From 9230ad29ebd87ce99f87f431d84c8e98b0cca3b1 Mon Sep 17 00:00:00 2001 From: "lrn@chromium.org" Date: Mon, 31 Aug 2009 12:40:37 +0000 Subject: [PATCH] ARM native regexps. Review URL: http://codereview.chromium.org/173567 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2785 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- SConstruct | 5 - src/SConscript | 42 +- src/arm/assembler-arm-inl.h | 2 +- src/arm/assembler-arm.cc | 100 +- src/arm/assembler-arm.h | 17 +- src/arm/codegen-arm.cc | 4 +- src/arm/disasm-arm.cc | 64 +- src/arm/regexp-macro-assembler-arm.cc | 1201 ++++++++++++++++++++- src/arm/regexp-macro-assembler-arm.h | 227 ++++ src/arm/simulator-arm.cc | 172 ++- src/arm/simulator-arm.h | 27 +- src/assembler.cc | 42 + src/assembler.h | 13 + src/code-stubs.h | 1 + src/globals.h | 9 +- src/heap.cc | 14 + src/heap.h | 11 +- src/ia32/regexp-macro-assembler-ia32.cc | 41 +- src/ia32/regexp-macro-assembler-ia32.h | 23 +- src/ia32/simulator-ia32.h | 5 + src/jsregexp.cc | 50 +- src/regexp-macro-assembler-irregexp-inl.h | 2 + src/regexp-macro-assembler-irregexp.cc | 2 + src/regexp-macro-assembler-irregexp.h | 3 + src/regexp-macro-assembler-tracer.h | 2 +- src/regexp-macro-assembler.cc | 57 +- src/regexp-macro-assembler.h | 27 + src/serialize.cc | 24 + src/x64/regexp-macro-assembler-x64.cc | 54 +- src/x64/regexp-macro-assembler-x64.h | 27 +- src/x64/simulator-x64.h | 5 + test/cctest/test-assembler-arm.cc | 4 +- test/cctest/test-regexp.cc | 39 +- tools/gyp/v8.gyp | 16 +- 34 files changed, 2059 insertions(+), 273 deletions(-) diff --git a/SConstruct b/SConstruct index 4d1792fd9..71673c0f0 100644 --- a/SConstruct +++ b/SConstruct @@ -99,12 +99,7 @@ LIBRARY_FLAGS = { 'CPPDEFINES': ['ENABLE_LOGGING_AND_PROFILING'], 'CPPPATH': [join(root_dir, 'src')], 'regexp:native': { - 'arch:ia32' : { 'CPPDEFINES': ['V8_NATIVE_REGEXP'] - }, - 'arch:x64' : { - 'CPPDEFINES': ['V8_NATIVE_REGEXP'] - } }, 'mode:debug': { 'CPPDEFINES': ['V8_ENABLE_CHECKS'] diff --git a/src/SConscript b/src/SConscript index 6a38c1a79..fee3fab43 100755 --- a/src/SConscript +++ b/src/SConscript @@ -63,32 +63,22 @@ SOURCES = { 'arm/register-allocator-arm.cc', 'arm/stub-cache-arm.cc', 'arm/virtual-frame-arm.cc' ], - 'arch:ia32': { - 'all': [ - 'ia32/assembler-ia32.cc', 'ia32/builtins-ia32.cc', 'ia32/cfg-ia32.cc', - 'ia32/codegen-ia32.cc', 'ia32/cpu-ia32.cc', 'ia32/disasm-ia32.cc', - 'ia32/debug-ia32.cc', 'ia32/frames-ia32.cc', 'ia32/ic-ia32.cc', - 'ia32/jump-target-ia32.cc', 'ia32/macro-assembler-ia32.cc', - 'ia32/register-allocator-ia32.cc', 'ia32/stub-cache-ia32.cc', - 'ia32/virtual-frame-ia32.cc' - ], - 'regexp:native': [ - 'ia32/regexp-macro-assembler-ia32.cc', - ] - }, - 'arch:x64': { - 'all': [ - 'x64/assembler-x64.cc', 'x64/builtins-x64.cc', 'x64/cfg-x64.cc', - 'x64/codegen-x64.cc', 'x64/cpu-x64.cc', 'x64/disasm-x64.cc', - 'x64/debug-x64.cc', 'x64/frames-x64.cc', 'x64/ic-x64.cc', - 'x64/jump-target-x64.cc', 'x64/macro-assembler-x64.cc', - 'x64/register-allocator-x64.cc', - 'x64/stub-cache-x64.cc', 'x64/virtual-frame-x64.cc' - ], - 'regexp:native': [ - 'x64/regexp-macro-assembler-x64.cc' - ] - }, + 'arch:ia32': [ + 'ia32/assembler-ia32.cc', 'ia32/builtins-ia32.cc', 'ia32/cfg-ia32.cc', + 'ia32/codegen-ia32.cc', 'ia32/cpu-ia32.cc', 'ia32/disasm-ia32.cc', + 'ia32/debug-ia32.cc', 'ia32/frames-ia32.cc', 'ia32/ic-ia32.cc', + 'ia32/jump-target-ia32.cc', 'ia32/macro-assembler-ia32.cc', + 'ia32/regexp-macro-assembler-ia32.cc', 'ia32/register-allocator-ia32.cc', + 'ia32/stub-cache-ia32.cc', 'ia32/virtual-frame-ia32.cc' + ], + 'arch:x64': [ + 'x64/assembler-x64.cc', 'x64/builtins-x64.cc', 'x64/cfg-x64.cc', + 'x64/codegen-x64.cc', 'x64/cpu-x64.cc', 'x64/disasm-x64.cc', + 'x64/debug-x64.cc', 'x64/frames-x64.cc', 'x64/ic-x64.cc', + 'x64/jump-target-x64.cc', 'x64/macro-assembler-x64.cc', + 'x64/regexp-macro-assembler-x64.cc', 'x64/register-allocator-x64.cc', + 'x64/stub-cache-x64.cc', 'x64/virtual-frame-x64.cc' + ], 'simulator:arm': ['arm/simulator-arm.cc'], 'os:freebsd': ['platform-freebsd.cc', 'platform-posix.cc'], 'os:linux': ['platform-linux.cc', 'platform-posix.cc'], diff --git a/src/arm/assembler-arm-inl.h b/src/arm/assembler-arm-inl.h index 4dda7ec5b..cb5faa234 100644 --- a/src/arm/assembler-arm-inl.h +++ b/src/arm/assembler-arm-inl.h @@ -204,7 +204,7 @@ void Assembler::CheckBuffer() { if (buffer_space() <= kGap) { GrowBuffer(); } - if (pc_offset() > next_buffer_check_) { + if (pc_offset() >= next_buffer_check_) { CheckConstPool(false, true); } } diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc index 3ed99f9e1..8bd06dbfe 100644 --- a/src/arm/assembler-arm.cc +++ b/src/arm/assembler-arm.cc @@ -329,19 +329,30 @@ const int kEndOfChain = -4; int Assembler::target_at(int pos) { Instr instr = instr_at(pos); + if ((instr & ~Imm24Mask) == 0) { + // Emitted label constant, not part of a branch. + return instr - (Code::kHeaderSize - kHeapObjectTag); + } ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24 int imm26 = ((instr & Imm24Mask) << 8) >> 6; if ((instr & CondMask) == nv && (instr & B24) != 0) // blx uses bit 24 to encode bit 2 of imm26 imm26 += 2; - return pos + 8 + imm26; + return pos + kPcLoadDelta + imm26; } void Assembler::target_at_put(int pos, int target_pos) { - int imm26 = target_pos - pos - 8; Instr instr = instr_at(pos); + if ((instr & ~Imm24Mask) == 0) { + ASSERT(target_pos == kEndOfChain || target_pos >= 0); + // Emitted label constant, not part of a branch. + // Make label relative to Code* of generated Code object. + instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag)); + return; + } + int imm26 = target_pos - (pos + kPcLoadDelta); ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24 if ((instr & CondMask) == nv) { // blx uses bit 24 to encode bit 2 of imm26 @@ -368,41 +379,45 @@ void Assembler::print(Label* L) { while (l.is_linked()) { PrintF("@ %d ", l.pos()); Instr instr = instr_at(l.pos()); - ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx - int cond = instr & CondMask; - const char* b; - const char* c; - if (cond == nv) { - b = "blx"; - c = ""; + if ((instr & ~Imm24Mask) == 0) { + PrintF("value\n"); } else { - if ((instr & B24) != 0) - b = "bl"; - else - b = "b"; - - switch (cond) { - case eq: c = "eq"; break; - case ne: c = "ne"; break; - case hs: c = "hs"; break; - case lo: c = "lo"; break; - case mi: c = "mi"; break; - case pl: c = "pl"; break; - case vs: c = "vs"; break; - case vc: c = "vc"; break; - case hi: c = "hi"; break; - case ls: c = "ls"; break; - case ge: c = "ge"; break; - case lt: c = "lt"; break; - case gt: c = "gt"; break; - case le: c = "le"; break; - case al: c = ""; break; - default: - c = ""; - UNREACHABLE(); + ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx + int cond = instr & CondMask; + const char* b; + const char* c; + if (cond == nv) { + b = "blx"; + c = ""; + } else { + if ((instr & B24) != 0) + b = "bl"; + else + b = "b"; + + switch (cond) { + case eq: c = "eq"; break; + case ne: c = "ne"; break; + case hs: c = "hs"; break; + case lo: c = "lo"; break; + case mi: c = "mi"; break; + case pl: c = "pl"; break; + case vs: c = "vs"; break; + case vc: c = "vc"; break; + case hi: c = "hi"; break; + case ls: c = "ls"; break; + case ge: c = "ge"; break; + case lt: c = "lt"; break; + case gt: c = "gt"; break; + case le: c = "le"; break; + case al: c = ""; break; + default: + c = ""; + UNREACHABLE(); + } } + PrintF("%s%s\n", b, c); } - PrintF("%s%s\n", b, c); next(&l); } } else { @@ -670,8 +685,23 @@ int Assembler::branch_offset(Label* L, bool jump_elimination_allowed) { // Block the emission of the constant pool, since the branch instruction must // be emitted at the pc offset recorded by the label BlockConstPoolBefore(pc_offset() + kInstrSize); + return target_pos - (pc_offset() + kPcLoadDelta); +} - return target_pos - pc_offset() - 8; + +void Assembler::label_at_put(Label* L, int at_offset) { + int target_pos; + if (L->is_bound()) { + target_pos = L->pos(); + } else { + if (L->is_linked()) { + target_pos = L->pos(); // L's link + } else { + target_pos = kEndOfChain; + } + L->link_to(at_offset); + instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag)); + } } diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h index b3ebb8be8..63f04473e 100644 --- a/src/arm/assembler-arm.h +++ b/src/arm/assembler-arm.h @@ -39,7 +39,7 @@ #ifndef V8_ARM_ASSEMBLER_ARM_H_ #define V8_ARM_ASSEMBLER_ARM_H_ - +#include #include "assembler.h" namespace v8 { @@ -165,9 +165,10 @@ enum Coprocessor { enum Condition { eq = 0 << 28, // Z set equal. ne = 1 << 28, // Z clear not equal. - cs = 2 << 28, // C set unsigned higher or same. + nz = 1 << 28, // Z clear not zero. + cs = 2 << 28, // C set carry set. hs = 2 << 28, // C set unsigned higher or same. - cc = 3 << 28, // C clear unsigned lower. + cc = 3 << 28, // C clear carry clear. lo = 3 << 28, // C clear unsigned lower. mi = 4 << 28, // N set negative. pl = 5 << 28, // N clear positive or zero. @@ -420,6 +421,10 @@ class Assembler : public Malloced { // Manages the jump elimination optimization if the second parameter is true. int branch_offset(Label* L, bool jump_elimination_allowed); + // Puts a labels target address at the given position. + // The high 8 bits are set to zero. + void label_at_put(Label* L, int at_offset); + // Return the address in the constant pool of the code target address used by // the branch/call instruction at pc. INLINE(static Address target_address_address_at(Address pc)); @@ -435,6 +440,10 @@ class Assembler : public Malloced { // to jump to. static const int kPatchReturnSequenceAddressOffset = 1; + // Difference between address of current opcode and value read from pc + // register. + static const int kPcLoadDelta = 8; + // --------------------------------------------------------------------------- // Code generation @@ -784,6 +793,8 @@ class Assembler : public Malloced { // Record reloc info for current pc_ void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0); + + friend class RegExpMacroAssemblerARM; }; } } // namespace v8::internal diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc index ff8711a61..880507d06 100644 --- a/src/arm/codegen-arm.cc +++ b/src/arm/codegen-arm.cc @@ -5682,9 +5682,9 @@ void UnarySubStub::Generate(MacroAssembler* masm) { __ str(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); } else { AllocateHeapNumber(masm, &slow, r1, r2, r3); - __ ldr(r2, FieldMemOperand(r0, HeapNumber::kMantissaOffset)); - __ str(r2, FieldMemOperand(r1, HeapNumber::kMantissaOffset)); + __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset)); __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); + __ str(r3, FieldMemOperand(r1, HeapNumber::kMantissaOffset)); __ eor(r2, r2, Operand(HeapNumber::kSignMask)); // Flip sign. __ str(r2, FieldMemOperand(r1, HeapNumber::kExponentOffset)); __ mov(r0, Operand(r1)); diff --git a/src/arm/disasm-arm.cc b/src/arm/disasm-arm.cc index 0abe35b9e..2638409e8 100644 --- a/src/arm/disasm-arm.cc +++ b/src/arm/disasm-arm.cc @@ -119,6 +119,7 @@ class Decoder { void DecodeType5(Instr* instr); void DecodeType6(Instr* instr); void DecodeType7(Instr* instr); + void DecodeUnconditional(Instr* instr); const disasm::NameConverter& converter_; v8::internal::Vector out_buffer_; @@ -774,6 +775,67 @@ void Decoder::DecodeType7(Instr* instr) { } +void Decoder::DecodeUnconditional(Instr* instr) { + if (instr->Bits(7, 4) == 0xB && instr->Bits(27, 25) == 0 && instr->HasL()) { + Format(instr, "'memop'h'pu 'rd, "); + bool immediate = instr->HasB(); + switch (instr->PUField()) { + case 0: { + // Post index, negative. + if (instr->HasW()) { + Unknown(instr); + break; + } + if (immediate) { + Format(instr, "['rn], #-'imm12"); + } else { + Format(instr, "['rn], -'rm"); + } + break; + } + case 1: { + // Post index, positive. + if (instr->HasW()) { + Unknown(instr); + break; + } + if (immediate) { + Format(instr, "['rn], #+'imm12"); + } else { + Format(instr, "['rn], +'rm"); + } + break; + } + case 2: { + // Pre index or offset, negative. + if (immediate) { + Format(instr, "['rn, #-'imm12]'w"); + } else { + Format(instr, "['rn, -'rm]'w"); + } + break; + } + case 3: { + // Pre index or offset, positive. + if (immediate) { + Format(instr, "['rn, #+'imm12]'w"); + } else { + Format(instr, "['rn, +'rm]'w"); + } + break; + } + default: { + // The PU field is a 2-bit field. + UNREACHABLE(); + break; + } + } + return; + } + Format(instr, "break 'msg"); +} + + // Disassemble the instruction at *instr_ptr into the output buffer. int Decoder::InstructionDecode(byte* instr_ptr) { Instr* instr = Instr::At(instr_ptr); @@ -782,7 +844,7 @@ int Decoder::InstructionDecode(byte* instr_ptr) { "%08x ", instr->InstructionBits()); if (instr->ConditionField() == special_condition) { - Format(instr, "break 'msg"); + DecodeUnconditional(instr); return Instr::kInstrSize; } switch (instr->TypeField()) { diff --git a/src/arm/regexp-macro-assembler-arm.cc b/src/arm/regexp-macro-assembler-arm.cc index 78ebc7e80..63f47f67e 100644 --- a/src/arm/regexp-macro-assembler-arm.cc +++ b/src/arm/regexp-macro-assembler-arm.cc @@ -1,4 +1,4 @@ -// Copyright 2006-2008 the V8 project authors. All rights reserved. +// Copyright 2009 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -26,19 +26,1210 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "v8.h" +#include "unicode.h" +#include "log.h" #include "ast.h" +#include "regexp-stack.h" +#include "macro-assembler.h" #include "regexp-macro-assembler.h" +#include "arm/macro-assembler-arm.h" #include "arm/regexp-macro-assembler-arm.h" namespace v8 { namespace internal { -RegExpMacroAssemblerARM::RegExpMacroAssemblerARM() { - UNIMPLEMENTED(); +#ifdef V8_NATIVE_REGEXP +/* + * This assembler uses the following register assignment convention + * - r5 : Pointer to current code object (Code*) including heap object tag. + * - r6 : Current position in input, as negative offset from end of string. + * Please notice that this is the byte offset, not the character offset! + * - r7 : Currently loaded character. Must be loaded using + * LoadCurrentCharacter before using any of the dispatch methods. + * - r8 : points to tip of backtrack stack + * - r9 : Unused, might be used by C code and expected unchanged. + * - r10 : End of input (points to byte after last character in input). + * - r11 : Frame pointer. Used to access arguments, local variables and + * RegExp registers. + * - r12 : IP register, used by assembler. Very volatile. + * - r13/sp : points to tip of C stack. + * + * The remaining registers are free for computations. + * + * Each call to a public method should retain this convention. + * The stack will have the following structure: + * - stack_area_base (High end of the memory area to use as + * backtracking stack) + * - at_start (if 1, start at start of string, if 0, don't) + * --- sp when called --- + * - link address + * - backup of registers r4..r11 + * - int* capture_array (int[num_saved_registers_], for output). + * - end of input (Address of end of string) + * - start of input (Address of first character in string) + * --- frame pointer ---- + * - void* input_string (location of a handle containing the string) + * - Offset of location before start of input (effectively character + * position -1). Used to initialize capture registers to a non-position. + * - register 0 (Only positions must be stored in the first + * - register 1 num_saved_registers_ registers) + * - ... + * - register num_registers-1 + * --- sp --- + * + * The first num_saved_registers_ registers are initialized to point to + * "character -1" in the string (i.e., char_size() bytes before the first + * character of the string). The remaining registers start out as garbage. + * + * The data up to the return address must be placed there by the calling + * code, by calling the code entry as cast to a function with the signature: + * int (*match)(String* input_string, + * Address start, + * Address end, + * int* capture_output_array, + * bool at_start, + * byte* stack_area_base) + * The call is performed by NativeRegExpMacroAssembler::Execute() + * (in regexp-macro-assembler.cc). + */ + +#define __ ACCESS_MASM(masm_) + +RegExpMacroAssemblerARM::RegExpMacroAssemblerARM( + Mode mode, + int registers_to_save) + : masm_(new MacroAssembler(NULL, kRegExpCodeSize)), + mode_(mode), + num_registers_(registers_to_save), + num_saved_registers_(registers_to_save), + entry_label_(), + start_label_(), + success_label_(), + backtrack_label_(), + exit_label_() { + ASSERT_EQ(0, registers_to_save % 2); + __ jmp(&entry_label_); // We'll write the entry code later. + EmitBacktrackConstantPool(); + __ bind(&start_label_); // And then continue from here. } -RegExpMacroAssemblerARM::~RegExpMacroAssemblerARM() {} +RegExpMacroAssemblerARM::~RegExpMacroAssemblerARM() { + delete masm_; + // Unuse labels in case we throw away the assembler without calling GetCode. + entry_label_.Unuse(); + start_label_.Unuse(); + success_label_.Unuse(); + backtrack_label_.Unuse(); + exit_label_.Unuse(); + check_preempt_label_.Unuse(); + stack_overflow_label_.Unuse(); +} -}} // namespace v8::internal +int RegExpMacroAssemblerARM::stack_limit_slack() { + return RegExpStack::kStackLimitSlack; +} + + +bool RegExpMacroAssemblerARM::CanReadUnaligned() { +#if V8_TARGET_CAN_READ_UNALIGNED + return true; +#else + return false; +#endif +} + + +void RegExpMacroAssemblerARM::AdvanceCurrentPosition(int by) { + if (by != 0) { + Label inside_string; + __ add(current_input_offset(), + current_input_offset(), Operand(by * char_size())); + } +} + + +void RegExpMacroAssemblerARM::AdvanceRegister(int reg, int by) { + ASSERT(reg >= 0); + ASSERT(reg < num_registers_); + if (by != 0) { + __ ldr(r0, register_location(reg)); + __ add(r0, r0, Operand(by)); + __ str(r0, register_location(reg)); + } +} + + +void RegExpMacroAssemblerARM::Backtrack() { + CheckPreemption(); + // Pop Code* offset from backtrack stack, add Code* and jump to location. + Pop(r0); + __ add(pc, r0, Operand(r5)); +} + + +void RegExpMacroAssemblerARM::Bind(Label* label) { + __ bind(label); +} + + +void RegExpMacroAssemblerARM::CheckCharacter(uint32_t c, Label* on_equal) { + __ cmp(current_character(), Operand(c)); + BranchOrBacktrack(eq, on_equal); +} + + +void RegExpMacroAssemblerARM::CheckCharacterGT(uc16 limit, Label* on_greater) { + __ cmp(current_character(), Operand(limit)); + BranchOrBacktrack(gt, on_greater); +} + + +void RegExpMacroAssemblerARM::CheckAtStart(Label* on_at_start) { + Label not_at_start; + // Did we start the match at the start of the string at all? + __ ldr(r0, MemOperand(frame_pointer(), kAtStart)); + __ cmp(r0, Operand(0)); + BranchOrBacktrack(eq, ¬_at_start); + + // If we did, are we still at the start of the input? + __ ldr(r1, MemOperand(frame_pointer(), kInputStart)); + __ add(r0, end_of_input_address(), Operand(current_input_offset())); + __ cmp(r0, r1); + BranchOrBacktrack(eq, on_at_start); + __ bind(¬_at_start); +} + + +void RegExpMacroAssemblerARM::CheckNotAtStart(Label* on_not_at_start) { + // Did we start the match at the start of the string at all? + __ ldr(r0, MemOperand(frame_pointer(), kAtStart)); + __ cmp(r0, Operand(0)); + BranchOrBacktrack(eq, on_not_at_start); + // If we did, are we still at the start of the input? + __ ldr(r1, MemOperand(frame_pointer(), kInputStart)); + __ add(r0, end_of_input_address(), Operand(current_input_offset())); + __ cmp(r0, r1); + BranchOrBacktrack(ne, on_not_at_start); +} + + +void RegExpMacroAssemblerARM::CheckCharacterLT(uc16 limit, Label* on_less) { + __ cmp(current_character(), Operand(limit)); + BranchOrBacktrack(lt, on_less); +} + + +void RegExpMacroAssemblerARM::CheckCharacters(Vector str, + int cp_offset, + Label* on_failure, + bool check_end_of_string) { + int byte_length = str.length() * char_size(); + int byte_offset = cp_offset * char_size(); + if (check_end_of_string) { + // Check that there are at least str.length() characters left in the input. + __ cmp(end_of_input_address(), Operand(-(byte_offset + byte_length))); + BranchOrBacktrack(gt, on_failure); + } + + if (on_failure == NULL) { + // Instead of inlining a backtrack, (re)use the global backtrack target. + on_failure = &backtrack_label_; + } + + __ add(r0, end_of_input_address(), Operand(current_input_offset())); + int stored_high_byte = 0; + for (int i = 0; i < str.length(); i++) { + if (mode_ == ASCII) { + __ ldrb(r1, MemOperand(r0, char_size(), PostIndex)); + // str[i] is known to be an ASCII character. + __ cmp(r1, Operand(str[i])); + } else { + __ ldrh(r1, MemOperand(r0, char_size(), PostIndex)); + uc16 match_char = str[i]; + int match_high_byte = (match_char >> 8); + if (match_high_byte == 0) { + __ cmp(r1, Operand(str[i])); + } else { + if (match_high_byte != stored_high_byte) { + __ mov(r2, Operand(match_high_byte)); + stored_high_byte = match_high_byte; + } + __ add(r3, r2, Operand(match_char & 0xff)); + __ cmp(r1, r3); + } + } + BranchOrBacktrack(ne, on_failure); + } +} + + +void RegExpMacroAssemblerARM::CheckGreedyLoop(Label* on_equal) { + __ ldr(r0, MemOperand(backtrack_stackpointer(), 0)); + __ cmp(current_input_offset(), r0); + __ add(backtrack_stackpointer(), + backtrack_stackpointer(), Operand(kPointerSize), LeaveCC, eq); + BranchOrBacktrack(eq, on_equal); +} + + +void RegExpMacroAssemblerARM::CheckNotBackReferenceIgnoreCase( + int start_reg, + Label* on_no_match) { + Label fallthrough; + __ ldr(r0, register_location(start_reg)); // Index of start of capture + __ ldr(r1, register_location(start_reg + 1)); // Index of end of capture + __ sub(r1, r1, r0, SetCC); // Length of capture. + + // If length is zero, either the capture is empty or it is not participating. + // In either case succeed immediately. + __ b(eq, &fallthrough); + + // Check that there are enough characters left in the input. + __ cmn(r1, Operand(current_input_offset())); + BranchOrBacktrack(gt, on_no_match); + + if (mode_ == ASCII) { + Label success; + Label fail; + Label loop_check; + + // r0 - offset of start of capture + // r1 - length of capture + __ add(r0, r0, Operand(end_of_input_address())); + __ add(r2, end_of_input_address(), Operand(current_input_offset())); + __ add(r1, r0, Operand(r1)); + + // r0 - Address of start of capture. + // r1 - Address of end of capture + // r2 - Address of current input position. + + Label loop; + __ bind(&loop); + __ ldrb(r3, MemOperand(r0, char_size(), PostIndex)); + __ ldrb(r4, MemOperand(r2, char_size(), PostIndex)); + __ cmp(r4, r3); + __ b(eq, &loop_check); + + // Mismatch, try case-insensitive match (converting letters to lower-case). + __ orr(r3, r3, Operand(0x20)); // Convert capture character to lower-case. + __ orr(r4, r4, Operand(0x20)); // Also convert input character. + __ cmp(r4, r3); + __ b(ne, &fail); + __ sub(r3, r3, Operand('a')); + __ cmp(r3, Operand('z' - 'a')); // Is r3 a lowercase letter? + __ b(hi, &fail); + + + __ bind(&loop_check); + __ cmp(r0, r1); + __ b(lt, &loop); + __ jmp(&success); + + __ bind(&fail); + BranchOrBacktrack(al, on_no_match); + + __ bind(&success); + // Compute new value of character position after the matched part. + __ sub(current_input_offset(), r2, end_of_input_address()); + } else { + ASSERT(mode_ == UC16); + int argument_count = 3; + FrameAlign(argument_count, r2); + + // r0 - offset of start of capture + // r1 - length of capture + + // Put arguments into arguments registers. + // Parameters are + // r0: Address byte_offset1 - Address captured substring's start. + // r1: Address byte_offset2 - Address of current character position. + // r2: size_t byte_length - length of capture in bytes(!) + + // Address of start of capture. + __ add(r0, r0, Operand(end_of_input_address())); + // Length of capture. + __ mov(r2, Operand(r1)); + // Save length in callee-save register for use on return. + __ mov(r4, Operand(r1)); + // Address of current input position. + __ add(r1, current_input_offset(), Operand(end_of_input_address())); + + ExternalReference function = + ExternalReference::re_case_insensitive_compare_uc16(); + CallCFunction(function, argument_count); + + // Check if function returned non-zero for success or zero for failure. + __ cmp(r0, Operand(0)); + BranchOrBacktrack(eq, on_no_match); + // On success, increment position by length of capture. + __ add(current_input_offset(), current_input_offset(), Operand(r4)); + } + + __ bind(&fallthrough); +} + + +void RegExpMacroAssemblerARM::CheckNotBackReference( + int start_reg, + Label* on_no_match) { + Label fallthrough; + Label success; + + // Find length of back-referenced capture. + __ ldr(r0, register_location(start_reg)); + __ ldr(r1, register_location(start_reg + 1)); + __ sub(r1, r1, r0, SetCC); // Length to check. + // Succeed on empty capture (including no capture). + __ b(eq, &fallthrough); + + // Check that there are enough characters left in the input. + __ cmn(r1, Operand(current_input_offset())); + BranchOrBacktrack(gt, on_no_match); + + // Compute pointers to match string and capture string + __ add(r0, r0, Operand(end_of_input_address())); + __ add(r2, end_of_input_address(), Operand(current_input_offset())); + __ add(r1, r1, Operand(r0)); + + Label loop; + __ bind(&loop); + if (mode_ == ASCII) { + __ ldrb(r3, MemOperand(r0, char_size(), PostIndex)); + __ ldrb(r4, MemOperand(r2, char_size(), PostIndex)); + } else { + ASSERT(mode_ == UC16); + __ ldrh(r3, MemOperand(r0, char_size(), PostIndex)); + __ ldrh(r4, MemOperand(r2, char_size(), PostIndex)); + } + __ cmp(r3, r4); + BranchOrBacktrack(ne, on_no_match); + __ cmp(r0, r1); + __ b(lt, &loop); + + // Move current character position to position after match. + __ sub(current_input_offset(), r2, end_of_input_address()); + __ bind(&fallthrough); +} + + +void RegExpMacroAssemblerARM::CheckNotRegistersEqual(int reg1, + int reg2, + Label* on_not_equal) { + __ ldr(r0, register_location(reg1)); + __ ldr(r1, register_location(reg2)); + __ cmp(r0, r1); + BranchOrBacktrack(ne, on_not_equal); +} + + +void RegExpMacroAssemblerARM::CheckNotCharacter(uint32_t c, + Label* on_not_equal) { + __ cmp(current_character(), Operand(c)); + BranchOrBacktrack(ne, on_not_equal); +} + + +void RegExpMacroAssemblerARM::CheckCharacterAfterAnd(uint32_t c, + uint32_t mask, + Label* on_equal) { + __ and_(r0, current_character(), Operand(mask)); + __ cmp(r0, Operand(c)); + BranchOrBacktrack(eq, on_equal); +} + + +void RegExpMacroAssemblerARM::CheckNotCharacterAfterAnd(uint32_t c, + uint32_t mask, + Label* on_not_equal) { + __ and_(r0, current_character(), Operand(mask)); + __ cmp(r0, Operand(c)); + BranchOrBacktrack(ne, on_not_equal); +} + + +void RegExpMacroAssemblerARM::CheckNotCharacterAfterMinusAnd( + uc16 c, + uc16 minus, + uc16 mask, + Label* on_not_equal) { + ASSERT(minus < String::kMaxUC16CharCode); + __ sub(r0, current_character(), Operand(minus)); + __ and_(r0, r0, Operand(mask)); + __ cmp(r0, Operand(c)); + BranchOrBacktrack(ne, on_not_equal); +} + + +bool RegExpMacroAssemblerARM::CheckSpecialCharacterClass(uc16 type, + int cp_offset, + bool check_offset, + Label* on_no_match) { + // Range checks (c in min..max) are generally implemented by an unsigned + // (c - min) <= (max - min) check + switch (type) { + case 's': + // Match space-characters + if (mode_ == ASCII) { + // ASCII space characters are '\t'..'\r' and ' '. + if (check_offset) { + LoadCurrentCharacter(cp_offset, on_no_match); + } else { + LoadCurrentCharacterUnchecked(cp_offset, 1); + } + Label success; + __ cmp(current_character(), Operand(' ')); + __ b(eq, &success); + // Check range 0x09..0x0d + __ sub(r0, current_character(), Operand('\t')); + __ cmp(r0, Operand('\r' - '\t')); + BranchOrBacktrack(hi, on_no_match); + __ bind(&success); + return true; + } + return false; + case 'S': + // Match non-space characters. + if (check_offset) { + LoadCurrentCharacter(cp_offset, on_no_match, 1); + } else { + LoadCurrentCharacterUnchecked(cp_offset, 1); + } + if (mode_ == ASCII) { + // ASCII space characters are '\t'..'\r' and ' '. + __ cmp(current_character(), Operand(' ')); + BranchOrBacktrack(eq, on_no_match); + __ sub(r0, current_character(), Operand('\t')); + __ cmp(r0, Operand('\r' - '\t')); + BranchOrBacktrack(ls, on_no_match); + return true; + } + return false; + case 'd': + // Match ASCII digits ('0'..'9') + if (check_offset) { + LoadCurrentCharacter(cp_offset, on_no_match, 1); + } else { + LoadCurrentCharacterUnchecked(cp_offset, 1); + } + __ sub(r0, current_character(), Operand('0')); + __ cmp(current_character(), Operand('9' - '0')); + BranchOrBacktrack(hi, on_no_match); + return true; + case 'D': + // Match non ASCII-digits + if (check_offset) { + LoadCurrentCharacter(cp_offset, on_no_match, 1); + } else { + LoadCurrentCharacterUnchecked(cp_offset, 1); + } + __ sub(r0, current_character(), Operand('0')); + __ cmp(r0, Operand('9' - '0')); + BranchOrBacktrack(ls, on_no_match); + return true; + case '.': { + // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029) + if (check_offset) { + LoadCurrentCharacter(cp_offset, on_no_match, 1); + } else { + LoadCurrentCharacterUnchecked(cp_offset, 1); + } + __ eor(r0, current_character(), Operand(0x01)); + // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c + __ sub(r0, r0, Operand(0x0b)); + __ cmp(r0, Operand(0x0c - 0x0b)); + BranchOrBacktrack(ls, on_no_match); + if (mode_ == UC16) { + // Compare original value to 0x2028 and 0x2029, using the already + // computed (current_char ^ 0x01 - 0x0b). I.e., check for + // 0x201d (0x2028 - 0x0b) or 0x201e. + __ sub(r0, r0, Operand(0x2028 - 0x0b)); + __ cmp(r0, Operand(1)); + BranchOrBacktrack(ls, on_no_match); + } + return true; + } + case '*': + // Match any character. + if (check_offset) { + CheckPosition(cp_offset, on_no_match); + } + return true; + // No custom implementation (yet): w, W, s(UC16), S(UC16). + default: + return false; + } +} + + +void RegExpMacroAssemblerARM::Fail() { + __ mov(r0, Operand(FAILURE)); + __ jmp(&exit_label_); +} + + +Handle RegExpMacroAssemblerARM::GetCode(Handle source) { + // Finalize code - write the entry point code now we know how many + // registers we need. + + // Entry code: + __ bind(&entry_label_); + // Push Link register. + // Push arguments + // Save callee-save registers. + // Start new stack frame. + // Order here should correspond to order of offset constants in header file. + RegList registers_to_retain = r4.bit() | r5.bit() | r6.bit() | + r7.bit() | r8.bit() | r9.bit() | r10.bit() | fp.bit(); + RegList argument_registers = r0.bit() | r1.bit() | r2.bit() | r3.bit(); + __ stm(db_w, sp, argument_registers | registers_to_retain | lr.bit()); + // Set frame pointer just above the arguments. + __ add(frame_pointer(), sp, Operand(4 * kPointerSize)); + __ push(r0); // Make room for "position - 1" constant (value is irrelevant). + + // Check if we have space on the stack for registers. + Label stack_limit_hit; + Label stack_ok; + + ExternalReference stack_guard_limit = + ExternalReference::address_of_stack_guard_limit(); + __ mov(r0, Operand(stack_guard_limit)); + __ ldr(r0, MemOperand(r0)); + __ sub(r0, sp, r0, SetCC); + // Handle it if the stack pointer is already below the stack limit. + __ b(ls, &stack_limit_hit); + // Check if there is room for the variable number of registers above + // the stack limit. + __ cmp(r0, Operand(num_registers_ * kPointerSize)); + __ b(hs, &stack_ok); + // Exit with OutOfMemory exception. There is not enough space on the stack + // for our working registers. + __ mov(r0, Operand(EXCEPTION)); + __ jmp(&exit_label_); + + __ bind(&stack_limit_hit); + CallCheckStackGuardState(r0); + __ cmp(r0, Operand(0)); + // If returned value is non-zero, we exit with the returned value as result. + __ b(ne, &exit_label_); + + __ bind(&stack_ok); + + // Allocate space on stack for registers. + __ sub(sp, sp, Operand(num_registers_ * kPointerSize)); + // Load string end. + __ ldr(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd)); + // Load input start. + __ ldr(r0, MemOperand(frame_pointer(), kInputStart)); + // Find negative length (offset of start relative to end). + __ sub(current_input_offset(), r0, end_of_input_address()); + // Set r0 to address of char before start of input + // (effectively string position -1). + __ sub(r0, current_input_offset(), Operand(char_size())); + // Store this value in a local variable, for use when clearing + // position registers. + __ str(r0, MemOperand(frame_pointer(), kInputStartMinusOne)); + if (num_saved_registers_ > 0) { // Always is, if generated from a regexp. + // Fill saved registers with initial value = start offset - 1 + + // Address of register 0. + __ add(r1, frame_pointer(), Operand(kRegisterZero)); + __ mov(r2, Operand(num_saved_registers_)); + Label init_loop; + __ bind(&init_loop); + __ str(r0, MemOperand(r1, kPointerSize, NegPostIndex)); + __ sub(r2, r2, Operand(1), SetCC); + __ b(ne, &init_loop); + } + + // Initialize backtrack stack pointer. + __ ldr(backtrack_stackpointer(), MemOperand(frame_pointer(), kStackHighEnd)); + // Initialize code pointer register + __ mov(code_pointer(), Operand(masm_->CodeObject())); + // Load previous char as initial value of current character register. + Label at_start; + __ ldr(r0, MemOperand(frame_pointer(), kAtStart)); + __ cmp(r0, Operand(0)); + __ b(ne, &at_start); + LoadCurrentCharacterUnchecked(-1, 1); // Load previous char. + __ jmp(&start_label_); + __ bind(&at_start); + __ mov(current_character(), Operand('\n')); + __ jmp(&start_label_); + + + // Exit code: + if (success_label_.is_linked()) { + // Save captures when successful. + __ bind(&success_label_); + if (num_saved_registers_ > 0) { + // copy captures to output + __ ldr(r1, MemOperand(frame_pointer(), kInputStart)); + __ ldr(r0, MemOperand(frame_pointer(), kRegisterOutput)); + __ sub(r1, end_of_input_address(), r1); + // r1 is length of input in bytes. + if (mode_ == UC16) { + __ mov(r1, Operand(r1, LSR, 1)); + } + // r1 is length of input in characters. + + ASSERT_EQ(0, num_saved_registers_ % 2); + // Always an even number of capture registers. This allows us to + // unroll the loop once to add an operation between a load of a register + // and the following use of that register. + for (int i = 0; i < num_saved_registers_; i += 2) { + __ ldr(r2, register_location(i)); + __ ldr(r3, register_location(i + 1)); + if (mode_ == UC16) { + __ add(r2, r1, Operand(r2, ASR, 1)); + __ add(r3, r1, Operand(r3, ASR, 1)); + } else { + __ add(r2, r1, Operand(r2)); + __ add(r3, r1, Operand(r3)); + } + __ str(r2, MemOperand(r0, kPointerSize, PostIndex)); + __ str(r3, MemOperand(r0, kPointerSize, PostIndex)); + } + } + __ mov(r0, Operand(SUCCESS)); + } + // Exit and return r0 + __ bind(&exit_label_); + // Skip sp past regexp registers and local variables.. + __ mov(sp, frame_pointer()); + // Restore registers r4..r11 and return (restoring lr to pc). + __ ldm(ia_w, sp, registers_to_retain | pc.bit()); + + // Backtrack code (branch target for conditional backtracks). + if (backtrack_label_.is_linked()) { + __ bind(&backtrack_label_); + Backtrack(); + } + + Label exit_with_exception; + + // Preempt-code + if (check_preempt_label_.is_linked()) { + SafeCallTarget(&check_preempt_label_); + + CallCheckStackGuardState(r0); + __ cmp(r0, Operand(0)); + // If returning non-zero, we should end execution with the given + // result as return value. + __ b(ne, &exit_label_); + + // String might have moved: Reload end of string from frame. + __ ldr(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd)); + SafeReturn(); + } + + // Backtrack stack overflow code. + if (stack_overflow_label_.is_linked()) { + SafeCallTarget(&stack_overflow_label_); + // Reached if the backtrack-stack limit has been hit. + + Label grow_failed; + + // Call GrowStack(backtrack_stackpointer()) + int num_arguments = 2; + FrameAlign(num_arguments, r0); + __ mov(r0, backtrack_stackpointer()); + __ add(r1, frame_pointer(), Operand(kStackHighEnd)); + ExternalReference grow_stack = + ExternalReference::re_grow_stack(); + CallCFunction(grow_stack, num_arguments); + // If return NULL, we have failed to grow the stack, and + // must exit with a stack-overflow exception. + __ cmp(r0, Operand(0)); + __ b(eq, &exit_with_exception); + // Otherwise use return value as new stack pointer. + __ mov(backtrack_stackpointer(), r0); + // Restore saved registers and continue. + SafeReturn(); + } + + if (exit_with_exception.is_linked()) { + // If any of the code above needed to exit with an exception. + __ bind(&exit_with_exception); + // Exit with Result EXCEPTION(-1) to signal thrown exception. + __ mov(r0, Operand(EXCEPTION)); + __ jmp(&exit_label_); + } + + CodeDesc code_desc; + masm_->GetCode(&code_desc); + Handle code = Factory::NewCode(code_desc, + NULL, + Code::ComputeFlags(Code::REGEXP), + masm_->CodeObject()); + LOG(RegExpCodeCreateEvent(*code, *source)); + return Handle::cast(code); +} + + +void RegExpMacroAssemblerARM::GoTo(Label* to) { + BranchOrBacktrack(al, to); +} + + +void RegExpMacroAssemblerARM::IfRegisterGE(int reg, + int comparand, + Label* if_ge) { + __ ldr(r0, register_location(reg)); + __ cmp(r0, Operand(comparand)); + BranchOrBacktrack(ge, if_ge); +} + + +void RegExpMacroAssemblerARM::IfRegisterLT(int reg, + int comparand, + Label* if_lt) { + __ ldr(r0, register_location(reg)); + __ cmp(r0, Operand(comparand)); + BranchOrBacktrack(lt, if_lt); +} + + +void RegExpMacroAssemblerARM::IfRegisterEqPos(int reg, + Label* if_eq) { + __ ldr(r0, register_location(reg)); + __ cmp(r0, Operand(current_input_offset())); + BranchOrBacktrack(eq, if_eq); +} + + +RegExpMacroAssembler::IrregexpImplementation + RegExpMacroAssemblerARM::Implementation() { + return kARMImplementation; +} + + +void RegExpMacroAssemblerARM::LoadCurrentCharacter(int cp_offset, + Label* on_end_of_input, + bool check_bounds, + int characters) { + ASSERT(cp_offset >= -1); // ^ and \b can look behind one character. + ASSERT(cp_offset < (1<<30)); // Be sane! (And ensure negation works) + if (check_bounds) { + CheckPosition(cp_offset + characters - 1, on_end_of_input); + } + LoadCurrentCharacterUnchecked(cp_offset, characters); +} + + +void RegExpMacroAssemblerARM::PopCurrentPosition() { + Pop(current_input_offset()); +} + + +void RegExpMacroAssemblerARM::PopRegister(int register_index) { + Pop(r0); + __ str(r0, register_location(register_index)); +} + + +static bool is_valid_memory_offset(int value) { + if (value < 0) value = -value; + return value < (1<<12); +} + + +void RegExpMacroAssemblerARM::PushBacktrack(Label* label) { + if (label->is_bound()) { + int target = label->pos(); + __ mov(r0, Operand(target + Code::kHeaderSize - kHeapObjectTag)); + } else { + int constant_offset = GetBacktrackConstantPoolEntry(); + masm_->label_at_put(label, constant_offset); + // Reading pc-relative is based on the address 8 bytes ahead of + // the current opcode. + unsigned int offset_of_pc_register_read = + masm_->pc_offset() + Assembler::kPcLoadDelta; + int pc_offset_of_constant = + constant_offset - offset_of_pc_register_read; + ASSERT(pc_offset_of_constant < 0); + if (is_valid_memory_offset(pc_offset_of_constant)) { + masm_->BlockConstPoolBefore(masm_->pc_offset() + Assembler::kInstrSize); + __ ldr(r0, MemOperand(pc, pc_offset_of_constant)); + } else { + // Not a 12-bit offset, so it needs to be loaded from the constant + // pool. + masm_->BlockConstPoolBefore( + masm_->pc_offset() + 2 * Assembler::kInstrSize); + __ mov(r0, Operand(pc_offset_of_constant + Assembler::kInstrSize)); + __ ldr(r0, MemOperand(pc, r0)); + } + } + Push(r0); + CheckStackLimit(); +} + + +void RegExpMacroAssemblerARM::PushCurrentPosition() { + Push(current_input_offset()); +} + + +void RegExpMacroAssemblerARM::PushRegister(int register_index, + StackCheckFlag check_stack_limit) { + __ ldr(r0, register_location(register_index)); + Push(r0); + if (check_stack_limit) CheckStackLimit(); +} + + +void RegExpMacroAssemblerARM::ReadCurrentPositionFromRegister(int reg) { + __ ldr(current_input_offset(), register_location(reg)); +} + + +void RegExpMacroAssemblerARM::ReadStackPointerFromRegister(int reg) { + __ ldr(backtrack_stackpointer(), register_location(reg)); + __ ldr(r0, MemOperand(frame_pointer(), kStackHighEnd)); + __ add(backtrack_stackpointer(), backtrack_stackpointer(), Operand(r0)); +} + + +void RegExpMacroAssemblerARM::SetRegister(int register_index, int to) { + ASSERT(register_index >= num_saved_registers_); // Reserved for positions! + __ mov(r0, Operand(to)); + __ str(r0, register_location(register_index)); +} + + +void RegExpMacroAssemblerARM::Succeed() { + __ jmp(&success_label_); +} + + +void RegExpMacroAssemblerARM::WriteCurrentPositionToRegister(int reg, + int cp_offset) { + if (cp_offset == 0) { + __ str(current_input_offset(), register_location(reg)); + } else { + __ add(r0, current_input_offset(), Operand(cp_offset * char_size())); + __ str(r0, register_location(reg)); + } +} + + +void RegExpMacroAssemblerARM::ClearRegisters(int reg_from, int reg_to) { + ASSERT(reg_from <= reg_to); + __ ldr(r0, MemOperand(frame_pointer(), kInputStartMinusOne)); + for (int reg = reg_from; reg <= reg_to; reg++) { + __ str(r0, register_location(reg)); + } +} + + +void RegExpMacroAssemblerARM::WriteStackPointerToRegister(int reg) { + __ ldr(r1, MemOperand(frame_pointer(), kStackHighEnd)); + __ sub(r0, backtrack_stackpointer(), r1); + __ str(r0, register_location(reg)); +} + + +// Private methods: + +void RegExpMacroAssemblerARM::CallCheckStackGuardState(Register scratch) { + int num_arguments = 3; + FrameAlign(num_arguments, scratch); + // RegExp code frame pointer. + __ mov(r2, frame_pointer()); + // Code* of self. + __ mov(r1, Operand(masm_->CodeObject())); + // r0 becomes return address pointer. + ExternalReference stack_guard_check = + ExternalReference::re_check_stack_guard_state(); + CallCFunctionUsingStub(stack_guard_check, num_arguments); +} + + +// Helper function for reading a value out of a stack frame. +template +static T& frame_entry(Address re_frame, int frame_offset) { + return reinterpret_cast(Memory::int32_at(re_frame + frame_offset)); +} + + +int RegExpMacroAssemblerARM::CheckStackGuardState(Address* return_address, + Code* re_code, + Address re_frame) { + if (StackGuard::IsStackOverflow()) { + Top::StackOverflow(); + return EXCEPTION; + } + + // If not real stack overflow the stack guard was used to interrupt + // execution for another purpose. + + // Prepare for possible GC. + HandleScope handles; + Handle code_handle(re_code); + + Handle subject(frame_entry(re_frame, kInputString)); + // Current string. + bool is_ascii = subject->IsAsciiRepresentation(); + + ASSERT(re_code->instruction_start() <= *return_address); + ASSERT(*return_address <= + re_code->instruction_start() + re_code->instruction_size()); + + Object* result = Execution::HandleStackGuardInterrupt(); + + if (*code_handle != re_code) { // Return address no longer valid + int delta = *code_handle - re_code; + // Overwrite the return address on the stack. + *return_address += delta; + } + + if (result->IsException()) { + return EXCEPTION; + } + + // String might have changed. + if (subject->IsAsciiRepresentation() != is_ascii) { + // If we changed between an ASCII and an UC16 string, the specialized + // code cannot be used, and we need to restart regexp matching from + // scratch (including, potentially, compiling a new version of the code). + return RETRY; + } + + // Otherwise, the content of the string might have moved. It must still + // be a sequential or external string with the same content. + // Update the start and end pointers in the stack frame to the current + // location (whether it has actually moved or not). + ASSERT(StringShape(*subject).IsSequential() || + StringShape(*subject).IsExternal()); + + // The original start address of the characters to match. + const byte* start_address = frame_entry(re_frame, kInputStart); + + // Find the current start address of the same character at the current string + // position. + int start_index = frame_entry(re_frame, kStartIndex); + const byte* new_address = StringCharacterPosition(*subject, start_index); + + if (start_address != new_address) { + // If there is a difference, update the object pointer and start and end + // addresses in the RegExp stack frame to match the new value. + const byte* end_address = frame_entry(re_frame, kInputEnd); + int byte_length = end_address - start_address; + frame_entry(re_frame, kInputString) = *subject; + frame_entry(re_frame, kInputStart) = new_address; + frame_entry(re_frame, kInputEnd) = new_address + byte_length; + } + + return 0; +} + + +MemOperand RegExpMacroAssemblerARM::register_location(int register_index) { + ASSERT(register_index < (1<<30)); + if (num_registers_ <= register_index) { + num_registers_ = register_index + 1; + } + return MemOperand(frame_pointer(), + kRegisterZero - register_index * kPointerSize); +} + + +void RegExpMacroAssemblerARM::CheckPosition(int cp_offset, + Label* on_outside_input) { + __ cmp(current_input_offset(), Operand(-cp_offset * char_size())); + BranchOrBacktrack(ge, on_outside_input); +} + + +void RegExpMacroAssemblerARM::BranchOrBacktrack(Condition condition, + Label* to) { + if (condition == al) { // Unconditional. + if (to == NULL) { + Backtrack(); + return; + } + __ jmp(to); + return; + } + if (to == NULL) { + __ b(condition, &backtrack_label_); + return; + } + __ b(condition, to); +} + + +void RegExpMacroAssemblerARM::SafeCall(Label* to, Condition cond) { + __ bl(to, cond); +} + + +void RegExpMacroAssemblerARM::SafeReturn() { + __ pop(lr); + __ add(pc, lr, Operand(masm_->CodeObject())); +} + + +void RegExpMacroAssemblerARM::SafeCallTarget(Label* name) { + __ bind(name); + __ sub(lr, lr, Operand(masm_->CodeObject())); + __ push(lr); +} + + +void RegExpMacroAssemblerARM::Push(Register source) { + ASSERT(!source.is(backtrack_stackpointer())); + __ str(source, + MemOperand(backtrack_stackpointer(), kPointerSize, NegPreIndex)); +} + + +void RegExpMacroAssemblerARM::Pop(Register target) { + ASSERT(!target.is(backtrack_stackpointer())); + __ ldr(target, + MemOperand(backtrack_stackpointer(), kPointerSize, PostIndex)); +} + + +void RegExpMacroAssemblerARM::CheckPreemption() { + // Check for preemption. + ExternalReference stack_guard_limit = + ExternalReference::address_of_stack_guard_limit(); + __ mov(r0, Operand(stack_guard_limit)); + __ ldr(r0, MemOperand(r0)); + __ cmp(sp, r0); + SafeCall(&check_preempt_label_, ls); +} + + +void RegExpMacroAssemblerARM::CheckStackLimit() { + if (FLAG_check_stack) { + ExternalReference stack_limit = + ExternalReference::address_of_regexp_stack_limit(); + __ mov(r0, Operand(stack_limit)); + __ ldr(r0, MemOperand(r0)); + __ cmp(backtrack_stackpointer(), Operand(r0)); + SafeCall(&stack_overflow_label_, ls); + } +} + + +void RegExpMacroAssemblerARM::EmitBacktrackConstantPool() { + __ CheckConstPool(false, false); + __ BlockConstPoolBefore( + masm_->pc_offset() + kBacktrackConstantPoolSize * Assembler::kInstrSize); + backtrack_constant_pool_offset_ = masm_->pc_offset(); + for (int i = 0; i < kBacktrackConstantPoolSize; i++) { + __ emit(0); + } + + backtrack_constant_pool_capacity_ = kBacktrackConstantPoolSize; +} + + +int RegExpMacroAssemblerARM::GetBacktrackConstantPoolEntry() { + while (backtrack_constant_pool_capacity_ > 0) { + int offset = backtrack_constant_pool_offset_; + backtrack_constant_pool_offset_ += kPointerSize; + backtrack_constant_pool_capacity_--; + if (masm_->pc_offset() - offset < 2 * KB) { + return offset; + } + } + Label new_pool_skip; + __ jmp(&new_pool_skip); + EmitBacktrackConstantPool(); + __ bind(&new_pool_skip); + int offset = backtrack_constant_pool_offset_; + backtrack_constant_pool_offset_ += kPointerSize; + backtrack_constant_pool_capacity_--; + return offset; +} + + +void RegExpMacroAssemblerARM::FrameAlign(int num_arguments, Register scratch) { + int frameAlignment = OS::ActivationFrameAlignment(); + // Up to four simple arguments are passed in registers r0..r3. + int stack_passed_arguments = (num_arguments <= 4) ? 0 : num_arguments - 4; + if (frameAlignment != 0) { + // Make stack end at alignment and make room for num_arguments - 4 words + // and the original value of sp. + __ mov(scratch, sp); + __ sub(sp, sp, Operand((stack_passed_arguments + 1) * kPointerSize)); + ASSERT(IsPowerOf2(frameAlignment)); + __ and_(sp, sp, Operand(-frameAlignment)); + __ str(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize)); + } else { + __ sub(sp, sp, Operand(stack_passed_arguments * kPointerSize)); + } +} + + +void RegExpMacroAssemblerARM::CallCFunction(ExternalReference function, + int num_arguments) { + __ mov(r5, Operand(function)); + // Just call directly. The function called cannot cause a GC, or + // allow preemption, so the return address in the link register + // stays correct. + __ Call(r5); + int stack_passed_arguments = (num_arguments <= 4) ? 0 : num_arguments - 4; + if (OS::ActivationFrameAlignment() > kIntSize) { + __ ldr(sp, MemOperand(sp, stack_passed_arguments * kPointerSize)); + } else { + __ add(sp, sp, Operand(stack_passed_arguments * sizeof(kPointerSize))); + } + __ mov(code_pointer(), Operand(masm_->CodeObject())); +} + + +void RegExpMacroAssemblerARM::CallCFunctionUsingStub( + ExternalReference function, + int num_arguments) { + // Must pass all arguments in registers. The stub pushes on the stack. + ASSERT(num_arguments <= 4); + __ mov(r5, Operand(function)); + RegExpCEntryStub stub; + __ CallStub(&stub); + if (OS::ActivationFrameAlignment() != 0) { + __ ldr(sp, MemOperand(sp, 0)); + } + __ mov(code_pointer(), Operand(masm_->CodeObject())); +} + + +void RegExpMacroAssemblerARM::LoadCurrentCharacterUnchecked(int cp_offset, + int characters) { + Register offset = current_input_offset(); + if (cp_offset != 0) { + __ add(r0, current_input_offset(), Operand(cp_offset * char_size())); + offset = r0; + } + // We assume that we cannot do unaligned loads on ARM, so this function + // must only be used to load a single character at a time. + ASSERT(characters == 1); + if (mode_ == ASCII) { + __ ldrb(current_character(), MemOperand(end_of_input_address(), offset)); + } else { + ASSERT(mode_ == UC16); + __ ldrh(current_character(), MemOperand(end_of_input_address(), offset)); + } +} + + +void RegExpCEntryStub::Generate(MacroAssembler* masm_) { + int stack_alignment = OS::ActivationFrameAlignment(); + if (stack_alignment < kPointerSize) stack_alignment = kPointerSize; + // Stack is already aligned for call, so decrement by alignment + // to make room for storing the link register. + __ str(lr, MemOperand(sp, stack_alignment, NegPreIndex)); + __ mov(r0, sp); + __ Call(r5); + __ ldr(pc, MemOperand(sp, stack_alignment, PostIndex)); +} + +#undef __ + +#endif // V8_NATIVE_REGEXP + +}} // namespace v8::internal diff --git a/src/arm/regexp-macro-assembler-arm.h b/src/arm/regexp-macro-assembler-arm.h index de5518379..2d0bd442b 100644 --- a/src/arm/regexp-macro-assembler-arm.h +++ b/src/arm/regexp-macro-assembler-arm.h @@ -31,12 +31,239 @@ namespace v8 { namespace internal { + +#ifndef V8_NATIVE_REGEXP class RegExpMacroAssemblerARM: public RegExpMacroAssembler { public: RegExpMacroAssemblerARM(); virtual ~RegExpMacroAssemblerARM(); }; +#else +class RegExpMacroAssemblerARM: public NativeRegExpMacroAssembler { + public: + RegExpMacroAssemblerARM(Mode mode, int registers_to_save); + virtual ~RegExpMacroAssemblerARM(); + virtual int stack_limit_slack(); + virtual bool CanReadUnaligned(); + virtual void AdvanceCurrentPosition(int by); + virtual void AdvanceRegister(int reg, int by); + virtual void Backtrack(); + virtual void Bind(Label* label); + virtual void CheckAtStart(Label* on_at_start); + virtual void CheckCharacter(uint32_t c, Label* on_equal); + virtual void CheckCharacterAfterAnd(uint32_t c, + uint32_t mask, + Label* on_equal); + virtual void CheckCharacterGT(uc16 limit, Label* on_greater); + virtual void CheckCharacterLT(uc16 limit, Label* on_less); + virtual void CheckCharacters(Vector str, + int cp_offset, + Label* on_failure, + bool check_end_of_string); + // A "greedy loop" is a loop that is both greedy and with a simple + // body. It has a particularly simple implementation. + virtual void CheckGreedyLoop(Label* on_tos_equals_current_position); + virtual void CheckNotAtStart(Label* on_not_at_start); + virtual void CheckNotBackReference(int start_reg, Label* on_no_match); + virtual void CheckNotBackReferenceIgnoreCase(int start_reg, + Label* on_no_match); + virtual void CheckNotRegistersEqual(int reg1, int reg2, Label* on_not_equal); + virtual void CheckNotCharacter(uint32_t c, Label* on_not_equal); + virtual void CheckNotCharacterAfterAnd(uint32_t c, + uint32_t mask, + Label* on_not_equal); + virtual void CheckNotCharacterAfterMinusAnd(uc16 c, + uc16 minus, + uc16 mask, + Label* on_not_equal); + // Checks whether the given offset from the current position is before + // the end of the string. + virtual void CheckPosition(int cp_offset, Label* on_outside_input); + virtual bool CheckSpecialCharacterClass(uc16 type, + int cp_offset, + bool check_offset, + Label* on_no_match); + virtual void Fail(); + virtual Handle GetCode(Handle source); + virtual void GoTo(Label* label); + virtual void IfRegisterGE(int reg, int comparand, Label* if_ge); + virtual void IfRegisterLT(int reg, int comparand, Label* if_lt); + virtual void IfRegisterEqPos(int reg, Label* if_eq); + virtual IrregexpImplementation Implementation(); + virtual void LoadCurrentCharacter(int cp_offset, + Label* on_end_of_input, + bool check_bounds = true, + int characters = 1); + virtual void PopCurrentPosition(); + virtual void PopRegister(int register_index); + virtual void PushBacktrack(Label* label); + virtual void PushCurrentPosition(); + virtual void PushRegister(int register_index, + StackCheckFlag check_stack_limit); + virtual void ReadCurrentPositionFromRegister(int reg); + virtual void ReadStackPointerFromRegister(int reg); + virtual void SetRegister(int register_index, int to); + virtual void Succeed(); + virtual void WriteCurrentPositionToRegister(int reg, int cp_offset); + virtual void ClearRegisters(int reg_from, int reg_to); + virtual void WriteStackPointerToRegister(int reg); + + // Called from RegExp if the stack-guard is triggered. + // If the code object is relocated, the return address is fixed before + // returning. + static int CheckStackGuardState(Address* return_address, + Code* re_code, + Address re_frame); + private: + // Offsets from frame_pointer() of function parameters and stored registers. + static const int kFramePointer = 0; + + // Above the frame pointer - Stored registers and stack passed parameters. + // Register 4..11. + static const int kStoredRegisters = kFramePointer; + // Return address (stored from link register, read into pc on return). + static const int kReturnAddress = kStoredRegisters + 8 * kPointerSize; + // Stack parameters placed by caller. + static const int kRegisterOutput = kReturnAddress + kPointerSize; + static const int kAtStart = kRegisterOutput + kPointerSize; + static const int kStackHighEnd = kAtStart + kPointerSize; + + // Below the frame pointer. + // Register parameters stored by setup code. + static const int kInputEnd = kFramePointer - kPointerSize; + static const int kInputStart = kInputEnd - kPointerSize; + static const int kStartIndex = kInputStart - kPointerSize; + static const int kInputString = kStartIndex - kPointerSize; + // When adding local variables remember to push space for them in + // the frame in GetCode. + static const int kInputStartMinusOne = kInputString - kPointerSize; + // First register address. Following registers are below it on the stack. + static const int kRegisterZero = kInputStartMinusOne - kPointerSize; + + // Initial size of code buffer. + static const size_t kRegExpCodeSize = 1024; + + static const int kBacktrackConstantPoolSize = 4; + + // Load a number of characters at the given offset from the + // current position, into the current-character register. + void LoadCurrentCharacterUnchecked(int cp_offset, int character_count); + + // Check whether preemption has been requested. + void CheckPreemption(); + + // Check whether we are exceeding the stack limit on the backtrack stack. + void CheckStackLimit(); + + void EmitBacktrackConstantPool(); + int GetBacktrackConstantPoolEntry(); + + + // Generate a call to CheckStackGuardState. + void CallCheckStackGuardState(Register scratch); + + // The ebp-relative location of a regexp register. + MemOperand register_location(int register_index); + + // Register holding the current input position as negative offset from + // the end of the string. + inline Register current_input_offset() { return r6; } + + // The register containing the current character after LoadCurrentCharacter. + inline Register current_character() { return r7; } + + // Register holding address of the end of the input string. + inline Register end_of_input_address() { return r10; } + + // Register holding the frame address. Local variables, parameters and + // regexp registers are addressed relative to this. + inline Register frame_pointer() { return fp; } + + // The register containing the backtrack stack top. Provides a meaningful + // name to the register. + inline Register backtrack_stackpointer() { return r8; } + + // Register holding pointer to the current code object. + inline Register code_pointer() { return r5; } + + // Byte size of chars in the string to match (decided by the Mode argument) + inline int char_size() { return static_cast(mode_); } + + // Equivalent to a conditional branch to the label, unless the label + // is NULL, in which case it is a conditional Backtrack. + void BranchOrBacktrack(Condition condition, Label* to); + + // Call and return internally in the generated code in a way that + // is GC-safe (i.e., doesn't leave absolute code addresses on the stack) + inline void SafeCall(Label* to, Condition cond = al); + inline void SafeReturn(); + inline void SafeCallTarget(Label* name); + + // Pushes the value of a register on the backtrack stack. Decrements the + // stack pointer by a word size and stores the register's value there. + inline void Push(Register source); + + // Pops a value from the backtrack stack. Reads the word at the stack pointer + // and increments it by a word size. + inline void Pop(Register target); + + // Before calling a C-function from generated code, align arguments on stack. + // After aligning the frame, non-register arguments must be stored in + // sp[0], sp[4], etc., not pushed. The argument count assumes all arguments + // are word sized. + // Some compilers/platforms require the stack to be aligned when calling + // C++ code. + // Needs a scratch register to do some arithmetic. This register will be + // trashed. + inline void FrameAlign(int num_arguments, Register scratch); + + // Calls a C function and cleans up the space for arguments allocated + // by FrameAlign. The called function is not allowed to trigger a garbage + // collection. + inline void CallCFunction(ExternalReference function, + int num_arguments); + + // Calls a C function and cleans up the frame alignment done by + // by FrameAlign. The called function *is* allowed to trigger a garbage + // collection, but may not take more than four arguments (no arguments + // passed on the stack), and the first argument will be a pointer to the + // return address. + inline void CallCFunctionUsingStub(ExternalReference function, + int num_arguments); + + + MacroAssembler* masm_; + + // Which mode to generate code for (ASCII or UC16). + Mode mode_; + + // One greater than maximal register index actually used. + int num_registers_; + + // Number of registers to output at the end (the saved registers + // are always 0..num_saved_registers_-1) + int num_saved_registers_; + + // Manage a small pre-allocated pool for writing label targets + // to for pushing backtrack addresses. + int backtrack_constant_pool_offset_; + int backtrack_constant_pool_capacity_; + + // Labels used internally. + Label entry_label_; + Label start_label_; + Label success_label_; + Label backtrack_label_; + Label exit_label_; + Label check_preempt_label_; + Label stack_overflow_label_; +}; + + +#endif // V8_NATIVE_REGEXP + + }} // namespace v8::internal #endif // V8_ARM_REGEXP_MACRO_ASSEMBLER_ARM_H_ diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc index d12ddbfaa..e258e5a68 100644 --- a/src/arm/simulator-arm.cc +++ b/src/arm/simulator-arm.cc @@ -26,7 +26,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include - +#include #include "v8.h" #include "disasm.h" @@ -598,7 +598,7 @@ uint16_t Simulator::ReadHU(int32_t addr, Instr* instr) { uint16_t* ptr = reinterpret_cast(addr); return *ptr; } - PrintF("Unaligned read at %x, pc=%p\n", addr, instr); + PrintF("Unaligned unsigned halfword read at %x, pc=%p\n", addr, instr); UNIMPLEMENTED(); return 0; } @@ -609,7 +609,7 @@ int16_t Simulator::ReadH(int32_t addr, Instr* instr) { int16_t* ptr = reinterpret_cast(addr); return *ptr; } - PrintF("Unaligned read at %x\n", addr); + PrintF("Unaligned signed halfword read at %x\n", addr); UNIMPLEMENTED(); return 0; } @@ -621,7 +621,7 @@ void Simulator::WriteH(int32_t addr, uint16_t value, Instr* instr) { *ptr = value; return; } - PrintF("Unaligned write at %x, pc=%p\n", addr, instr); + PrintF("Unaligned unsigned halfword write at %x, pc=%p\n", addr, instr); UNIMPLEMENTED(); } @@ -632,7 +632,7 @@ void Simulator::WriteH(int32_t addr, int16_t value, Instr* instr) { *ptr = value; return; } - PrintF("Unaligned write at %x, pc=%p\n", addr, instr); + PrintF("Unaligned halfword write at %x, pc=%p\n", addr, instr); UNIMPLEMENTED(); } @@ -1416,8 +1416,12 @@ void Simulator::DecodeType01(Instr* instr) { case CMN: { if (instr->HasS()) { - Format(instr, "cmn'cond 'rn, 'shift_rm"); - Format(instr, "cmn'cond 'rn, 'imm"); + // Format(instr, "cmn'cond 'rn, 'shift_rm"); + // Format(instr, "cmn'cond 'rn, 'imm"); + alu_out = rn_val + shifter_operand; + SetNZFlags(alu_out); + SetCFlag(!CarryFrom(rn_val, shifter_operand)); + SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true)); } else { ASSERT(type == 0); int rm = instr->RmField(); @@ -1566,6 +1570,7 @@ void Simulator::DecodeType2(Instr* instr) { void Simulator::DecodeType3(Instr* instr) { + ASSERT(instr->Bit(4) == 0); int rd = instr->RdField(); int rn = instr->RnField(); int32_t rn_val = get_register(rn); @@ -1605,7 +1610,12 @@ void Simulator::DecodeType3(Instr* instr) { } } if (instr->HasB()) { - UNIMPLEMENTED(); + if (instr->HasL()) { + uint8_t byte = ReadB(addr); + set_register(rd, byte); + } else { + UNIMPLEMENTED(); + } } else { if (instr->HasL()) { set_register(rd, ReadW(addr, instr)); @@ -1630,12 +1640,13 @@ void Simulator::DecodeType4(Instr* instr) { void Simulator::DecodeType5(Instr* instr) { // Format(instr, "b'l'cond 'target"); - int off = (instr->SImmed24Field() << 2) + 8; - intptr_t pc = get_pc(); + int off = (instr->SImmed24Field() << 2); + intptr_t pc_address = get_pc(); if (instr->HasLink()) { - set_register(lr, pc + Instr::kInstrSize); + set_register(lr, pc_address + Instr::kInstrSize); } - set_pc(pc+off); + int pc_reg = get_register(pc); + set_pc(pc_reg + off); } @@ -1654,14 +1665,75 @@ void Simulator::DecodeType7(Instr* instr) { } +void Simulator::DecodeUnconditional(Instr* instr) { + if (instr->Bits(7, 4) == 0x0B && instr->Bits(27, 25) == 0 && instr->HasL()) { + // Load halfword instruction, either register or immediate offset. + int rd = instr->RdField(); + int rn = instr->RnField(); + int32_t rn_val = get_register(rn); + int32_t addr = 0; + int32_t offset; + if (instr->Bit(22) == 0) { + // Register offset. + int rm = instr->RmField(); + offset = get_register(rm); + } else { + // Immediate offset + offset = instr->Bits(3, 0) + (instr->Bits(11, 8) << 4); + } + switch (instr->PUField()) { + case 0: { + // Post index, negative. + ASSERT(!instr->HasW()); + addr = rn_val; + rn_val -= offset; + set_register(rn, rn_val); + break; + } + case 1: { + // Post index, positive. + ASSERT(!instr->HasW()); + addr = rn_val; + rn_val += offset; + set_register(rn, rn_val); + break; + } + case 2: { + // Pre index or offset, negative. + rn_val -= offset; + addr = rn_val; + if (instr->HasW()) { + set_register(rn, rn_val); + } + break; + } + case 3: { + // Pre index or offset, positive. + rn_val += offset; + addr = rn_val; + if (instr->HasW()) { + set_register(rn, rn_val); + } + break; + } + default: { + // The PU field is a 2-bit field. + UNREACHABLE(); + break; + } + } + // Not sign extending, so load as unsigned. + uint16_t halfword = ReadH(addr, instr); + set_register(rd, halfword); + } else { + UNIMPLEMENTED(); + } +} + + // Executes the current instruction. void Simulator::InstructionDecode(Instr* instr) { pc_modified_ = false; - if (instr->ConditionField() == special_condition) { - Debugger dbg(this); - dbg.Stop(instr); - return; - } if (::v8::internal::FLAG_trace_sim) { disasm::NameConverter converter; disasm::Disassembler dasm(converter); @@ -1671,7 +1743,9 @@ void Simulator::InstructionDecode(Instr* instr) { reinterpret_cast(instr)); PrintF(" 0x%x %s\n", instr, buffer.start()); } - if (ConditionallyExecute(instr)) { + if (instr->ConditionField() == special_condition) { + DecodeUnconditional(instr); + } else if (ConditionallyExecute(instr)) { switch (instr->TypeField()) { case 0: case 1: { @@ -1747,19 +1821,35 @@ void Simulator::Execute() { } -Object* Simulator::Call(int32_t entry, int32_t p0, int32_t p1, int32_t p2, - int32_t p3, int32_t p4) { - // Setup parameters - set_register(r0, p0); - set_register(r1, p1); - set_register(r2, p2); - set_register(r3, p3); - intptr_t* stack_pointer = reinterpret_cast(get_register(sp)); - *(--stack_pointer) = p4; - set_register(sp, reinterpret_cast(stack_pointer)); +int32_t Simulator::Call(byte* entry, int argument_count, ...) { + va_list parameters; + va_start(parameters, argument_count); + // Setup arguments + + // First four arguments passed in registers. + ASSERT(argument_count >= 4); + set_register(r0, va_arg(parameters, int32_t)); + set_register(r1, va_arg(parameters, int32_t)); + set_register(r2, va_arg(parameters, int32_t)); + set_register(r3, va_arg(parameters, int32_t)); + + // Remaining arguments passed on stack. + int original_stack = get_register(sp); + // Compute position of stack on entry to generated code. + int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t)); + if (OS::ActivationFrameAlignment() != 0) { + entry_stack &= -OS::ActivationFrameAlignment(); + } + // Store remaining arguments on stack, from low to high memory. + intptr_t* stack_argument = reinterpret_cast(entry_stack); + for (int i = 4; i < argument_count; i++) { + stack_argument[i - 4] = va_arg(parameters, int32_t); + } + va_end(parameters); + set_register(sp, entry_stack); // Prepare to execute the code at entry - set_register(pc, entry); + set_register(pc, reinterpret_cast(entry)); // Put down marker for end of simulation. The simulator will stop simulation // when the PC reaches this value. By saving the "end simulation" value into // the LR the simulation stops when returning to this call point. @@ -1793,14 +1883,14 @@ Object* Simulator::Call(int32_t entry, int32_t p0, int32_t p1, int32_t p2, Execute(); // Check that the callee-saved registers have been preserved. - CHECK_EQ(get_register(r4), callee_saved_value); - CHECK_EQ(get_register(r5), callee_saved_value); - CHECK_EQ(get_register(r6), callee_saved_value); - CHECK_EQ(get_register(r7), callee_saved_value); - CHECK_EQ(get_register(r8), callee_saved_value); - CHECK_EQ(get_register(r9), callee_saved_value); - CHECK_EQ(get_register(r10), callee_saved_value); - CHECK_EQ(get_register(r11), callee_saved_value); + CHECK_EQ(callee_saved_value, get_register(r4)); + CHECK_EQ(callee_saved_value, get_register(r5)); + CHECK_EQ(callee_saved_value, get_register(r6)); + CHECK_EQ(callee_saved_value, get_register(r7)); + CHECK_EQ(callee_saved_value, get_register(r8)); + CHECK_EQ(callee_saved_value, get_register(r9)); + CHECK_EQ(callee_saved_value, get_register(r10)); + CHECK_EQ(callee_saved_value, get_register(r11)); // Restore callee-saved registers with the original value. set_register(r4, r4_val); @@ -1812,8 +1902,12 @@ Object* Simulator::Call(int32_t entry, int32_t p0, int32_t p1, int32_t p2, set_register(r10, r10_val); set_register(r11, r11_val); - int result = get_register(r0); - return reinterpret_cast(result); + // Pop stack passed arguments. + CHECK_EQ(entry_stack, get_register(sp)); + set_register(sp, original_stack); + + int32_t result = get_register(r0); + return result; } } } // namespace assembler::arm diff --git a/src/arm/simulator-arm.h b/src/arm/simulator-arm.h index 15b92a5f8..3917d6a5a 100644 --- a/src/arm/simulator-arm.h +++ b/src/arm/simulator-arm.h @@ -40,7 +40,7 @@ // When running without a simulator we call the entry directly. #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \ - reinterpret_cast(entry(p0, p1, p2, p3, p4)) + (entry(p0, p1, p2, p3, p4)) // Calculated the stack limit beyond which we will throw stack overflow errors. // This macro must be called from a C++ method. It relies on being able to take @@ -49,13 +49,20 @@ #define GENERATED_CODE_STACK_LIMIT(limit) \ (reinterpret_cast(this) - limit) + +// Call the generated regexp code directly. The entry function pointer should +// expect seven int/pointer sized arguments and return an int. +#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \ + entry(p0, p1, p2, p3, p4, p5, p6) + #else // defined(__arm__) // When running with the simulator transition into simulated execution at this // point. #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \ - assembler::arm::Simulator::current()->Call((int32_t)entry, (int32_t)p0, \ - (int32_t)p1, (int32_t)p2, (int32_t)p3, (int32_t)p4) + reinterpret_cast( \ + assembler::arm::Simulator::current()->Call(FUNCTION_ADDR(entry), 5, \ + p0, p1, p2, p3, p4)) // The simulator has its own stack. Thus it has a different stack limit from // the C-based native code. @@ -63,6 +70,10 @@ (assembler::arm::Simulator::current()->StackLimit()) +#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \ + assembler::arm::Simulator::current()->Call( \ + FUNCTION_ADDR(entry), 7, p0, p1, p2, p3, p4, p5, p6) + #include "constants-arm.h" @@ -109,11 +120,10 @@ class Simulator { // Call on program start. static void Initialize(); - // V8 generally calls into generated code with 5 parameters. This is a - // convenience function, which sets up the simulator state and grabs the - // result on return. - v8::internal::Object* Call(int32_t entry, int32_t p0, int32_t p1, - int32_t p2, int32_t p3, int32_t p4); + // V8 generally calls into generated JS code with 5 parameters and into + // generated RegExp code with 7 parameters. This is a convenience function, + // which sets up the simulator state and grabs the result on return. + int32_t Call(byte* entry, int argument_count, ...); private: enum special_values { @@ -174,6 +184,7 @@ class Simulator { void DecodeType5(Instr* instr); void DecodeType6(Instr* instr); void DecodeType7(Instr* instr); + void DecodeUnconditional(Instr* instr); // Executes one instruction. void InstructionDecode(Instr* instr); diff --git a/src/assembler.cc b/src/assembler.cc index 546490ee3..3563ebd2e 100644 --- a/src/assembler.cc +++ b/src/assembler.cc @@ -42,6 +42,20 @@ #include "serialize.h" #include "stub-cache.h" #include "regexp-stack.h" +#include "ast.h" +#include "regexp-macro-assembler.h" +// Include native regexp-macro-assembler. +#ifdef V8_NATIVE_REGEXP +#if V8_TARGET_ARCH_IA32 +#include "ia32/regexp-macro-assembler-ia32.h" +#elif V8_TARGET_ARCH_X64 +#include "x64/regexp-macro-assembler-x64.h" +#elif V8_TARGET_ARCH_ARM +#include "arm/regexp-macro-assembler-arm.h" +#else // Unknown architecture. +#error "Unknown architecture." +#endif // Target architecture. +#endif // V8_NATIVE_REGEXP namespace v8 { namespace internal { @@ -597,6 +611,34 @@ ExternalReference ExternalReference::new_space_allocation_limit_address() { return ExternalReference(Heap::NewSpaceAllocationLimitAddress()); } +#ifdef V8_NATIVE_REGEXP + +ExternalReference ExternalReference::re_check_stack_guard_state() { + Address function; +#ifdef V8_TARGET_ARCH_X64 + function = FUNCTION_ADDR(RegExpMacroAssemblerX64::CheckStackGuardState); +#elif V8_TARGET_ARCH_IA32 + function = FUNCTION_ADDR(RegExpMacroAssemblerIA32::CheckStackGuardState); +#elif V8_TARGET_ARCH_ARM + function = FUNCTION_ADDR(RegExpMacroAssemblerARM::CheckStackGuardState); +#else + UNREACHABLE("Unexpected architecture"); +#endif + return ExternalReference(Redirect(function)); +} + +ExternalReference ExternalReference::re_grow_stack() { + return ExternalReference( + Redirect(FUNCTION_ADDR(NativeRegExpMacroAssembler::GrowStack))); +} + +ExternalReference ExternalReference::re_case_insensitive_compare_uc16() { + return ExternalReference(Redirect( + FUNCTION_ADDR(NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16))); +} + +#endif + static double add_two_doubles(double x, double y) { return x + y; diff --git a/src/assembler.h b/src/assembler.h index e217918ce..827389a1b 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -431,6 +431,19 @@ class ExternalReference BASE_EMBEDDED { static ExternalReference debug_step_in_fp_address(); #endif +#ifdef V8_NATIVE_REGEXP + // C functions called from RegExp generated code. + + // Function NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16() + static ExternalReference re_case_insensitive_compare_uc16(); + + // Function RegExpMacroAssembler*::CheckStackGuardState() + static ExternalReference re_check_stack_guard_state(); + + // Function NativeRegExpMacroAssembler::GrowStack() + static ExternalReference re_grow_stack(); +#endif + // This lets you register a function that rewrites all external references. // Used by the ARM simulator to catch calls to external references. static void set_redirector(ExternalReferenceRedirector* redirector) { diff --git a/src/code-stubs.h b/src/code-stubs.h index 76ec7870f..ae86c20ef 100644 --- a/src/code-stubs.h +++ b/src/code-stubs.h @@ -57,6 +57,7 @@ class CodeStub BASE_EMBEDDED { SetProperty, // ARM only InvokeBuiltin, // ARM only JSExit, // ARM only + RegExpCEntry, // ARM only NUMBER_OF_IDS }; diff --git a/src/globals.h b/src/globals.h index 3b8ee92ff..efe0127e0 100644 --- a/src/globals.h +++ b/src/globals.h @@ -47,7 +47,14 @@ namespace internal { #define V8_HOST_ARCH_ARM 1 #define V8_HOST_ARCH_32_BIT 1 #else -#error Your architecture was not detected as supported by v8 +#error Your host architecture was not detected as supported by v8 +#endif + +#if defined(V8_TARGET_ARCH_X64) || defined(V8_TARGET_ARCH_IA32) +#define V8_TARGET_CAN_READ_UNALIGNED 1 +#elif V8_TARGET_ARCH_ARM +#else +#error Your target architecture is not supported by v8 #endif // Support for alternative bool type. This is only enabled if the code is diff --git a/src/heap.cc b/src/heap.cc index 19eb42eed..c9128ae0b 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -39,6 +39,9 @@ #include "scanner.h" #include "scopeinfo.h" #include "v8threads.h" +#if V8_TARGET_ARCH_ARM && V8_NATIVE_REGEXP +#include "regexp-macro-assembler.h" +#endif namespace v8 { namespace internal { @@ -1320,6 +1323,14 @@ void Heap::CreateCEntryStub() { } +#if V8_TARGET_ARCH_ARM && V8_NATIVE_REGEXP +void Heap::CreateRegExpCEntryStub() { + RegExpCEntryStub stub; + set_re_c_entry_code(*stub.GetCode()); +} +#endif + + void Heap::CreateCEntryDebugBreakStub() { CEntryDebugBreakStub stub; set_c_entry_debug_break_code(*stub.GetCode()); @@ -1356,6 +1367,9 @@ void Heap::CreateFixedStubs() { Heap::CreateCEntryDebugBreakStub(); Heap::CreateJSEntryStub(); Heap::CreateJSConstructEntryStub(); +#if V8_TARGET_ARCH_ARM && V8_NATIVE_REGEXP + Heap::CreateRegExpCEntryStub(); +#endif } diff --git a/src/heap.h b/src/heap.h index 8b0919e93..fa4830672 100644 --- a/src/heap.h +++ b/src/heap.h @@ -34,7 +34,7 @@ namespace v8 { namespace internal { // Defines all the roots in Heap. -#define STRONG_ROOT_LIST(V) \ +#define UNCONDITIONAL_STRONG_ROOT_LIST(V) \ /* Cluster the most popular ones in a few cache lines here at the top. */ \ V(Smi, stack_limit, StackLimit) \ V(Object, undefined_value, UndefinedValue) \ @@ -136,6 +136,13 @@ namespace internal { V(FixedArray, natives_source_cache, NativesSourceCache) \ V(Object, last_script_id, LastScriptId) \ +#if V8_TARGET_ARCH_ARM && V8_NATIVE_REGEXP +#define STRONG_ROOT_LIST(V) \ + UNCONDITIONAL_STRONG_ROOT_LIST(V) \ + V(Code, re_c_entry_code, RegExpCEntryCode) +#else +#define STRONG_ROOT_LIST(V) UNCONDITIONAL_STRONG_ROOT_LIST(V) +#endif #define ROOT_LIST(V) \ STRONG_ROOT_LIST(V) \ @@ -1025,6 +1032,8 @@ class Heap : public AllStatic { static void CreateCEntryDebugBreakStub(); static void CreateJSEntryStub(); static void CreateJSConstructEntryStub(); + static void CreateRegExpCEntryStub(); + static void CreateFixedStubs(); static Object* CreateOddball(Map* map, diff --git a/src/ia32/regexp-macro-assembler-ia32.cc b/src/ia32/regexp-macro-assembler-ia32.cc index bc8107633..7af4e89e0 100644 --- a/src/ia32/regexp-macro-assembler-ia32.cc +++ b/src/ia32/regexp-macro-assembler-ia32.cc @@ -102,6 +102,7 @@ RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32( success_label_(), backtrack_label_(), exit_label_() { + ASSERT_EQ(0, registers_to_save % 2); __ jmp(&entry_label_); // We'll write the entry code later. __ bind(&start_label_); // And then continue from here. } @@ -337,8 +338,9 @@ void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase( __ add(edx, Operand(esi)); __ mov(Operand(esp, 0 * kPointerSize), edx); - Address function_address = FUNCTION_ADDR(&CaseInsensitiveCompareUC16); - CallCFunction(function_address, argument_count); + ExternalReference compare = + ExternalReference::re_case_insensitive_compare_uc16(); + CallCFunction(compare, argument_count); // Pop original values before reacting on result value. __ pop(ebx); __ pop(backtrack_stackpointer()); @@ -745,7 +747,8 @@ Handle RegExpMacroAssemblerIA32::GetCode(Handle source) { __ lea(eax, Operand(ebp, kStackHighEnd)); __ mov(Operand(esp, 1 * kPointerSize), eax); __ mov(Operand(esp, 0 * kPointerSize), backtrack_stackpointer()); - CallCFunction(FUNCTION_ADDR(&GrowStack), num_arguments); + ExternalReference grow_stack = ExternalReference::re_grow_stack(); + CallCFunction(grow_stack, num_arguments); // If return NULL, we have failed to grow the stack, and // must exit with a stack-overflow exception. __ or_(eax, Operand(eax)); @@ -817,7 +820,9 @@ void RegExpMacroAssemblerIA32::LoadCurrentCharacter(int cp_offset, int characters) { ASSERT(cp_offset >= -1); // ^ and \b can look behind one character. ASSERT(cp_offset < (1<<30)); // Be sane! (And ensure negation works) - CheckPosition(cp_offset + characters - 1, on_end_of_input); + if (check_bounds) { + CheckPosition(cp_offset + characters - 1, on_end_of_input); + } LoadCurrentCharacterUnchecked(cp_offset, characters); } @@ -913,7 +918,9 @@ void RegExpMacroAssemblerIA32::CallCheckStackGuardState(Register scratch) { // Next address on the stack (will be address of return address). __ lea(eax, Operand(esp, -kPointerSize)); __ mov(Operand(esp, 0 * kPointerSize), eax); - CallCFunction(FUNCTION_ADDR(&CheckStackGuardState), num_arguments); + ExternalReference check_stack_guard = + ExternalReference::re_check_stack_guard_state(); + CallCFunction(check_stack_guard, num_arguments); } @@ -996,22 +1003,6 @@ int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address, } -Address RegExpMacroAssemblerIA32::GrowStack(Address stack_pointer, - Address* stack_base) { - size_t size = RegExpStack::stack_capacity(); - Address old_stack_base = RegExpStack::stack_base(); - ASSERT(old_stack_base == *stack_base); - ASSERT(stack_pointer <= old_stack_base); - ASSERT(static_cast(old_stack_base - stack_pointer) <= size); - Address new_stack_base = RegExpStack::EnsureCapacity(size * 2); - if (new_stack_base == NULL) { - return NULL; - } - *stack_base = new_stack_base; - return new_stack_base - (old_stack_base - stack_pointer); -} - - Operand RegExpMacroAssemblerIA32::register_location(int register_index) { ASSERT(register_index < (1<<30)); if (num_registers_ <= register_index) { @@ -1135,9 +1126,9 @@ void RegExpMacroAssemblerIA32::FrameAlign(int num_arguments, Register scratch) { } -void RegExpMacroAssemblerIA32::CallCFunction(Address function_address, +void RegExpMacroAssemblerIA32::CallCFunction(ExternalReference function, int num_arguments) { - __ mov(Operand(eax), Immediate(reinterpret_cast(function_address))); + __ mov(Operand(eax), Immediate(function)); __ call(Operand(eax)); if (OS::ActivationFrameAlignment() != 0) { __ mov(esp, Operand(esp, num_arguments * kPointerSize)); @@ -1172,6 +1163,10 @@ void RegExpMacroAssemblerIA32::LoadCurrentCharacterUnchecked(int cp_offset, } +void RegExpCEntryStub::Generate(MacroAssembler* masm_) { + __ int3(); // Unused on ia32. +} + #undef __ #endif // V8_NATIVE_REGEXP diff --git a/src/ia32/regexp-macro-assembler-ia32.h b/src/ia32/regexp-macro-assembler-ia32.h index d11439299..5ffd46275 100644 --- a/src/ia32/regexp-macro-assembler-ia32.h +++ b/src/ia32/regexp-macro-assembler-ia32.h @@ -107,6 +107,13 @@ class RegExpMacroAssemblerIA32: public NativeRegExpMacroAssembler { virtual void ClearRegisters(int reg_from, int reg_to); virtual void WriteStackPointerToRegister(int reg); + // Called from RegExp if the stack-guard is triggered. + // If the code object is relocated, the return address is fixed before + // returning. + static int CheckStackGuardState(Address* return_address, + Code* re_code, + Address re_frame); + private: // Offsets from ebp of function parameters and stored registers. static const int kFramePointer = 0; @@ -144,23 +151,9 @@ class RegExpMacroAssemblerIA32: public NativeRegExpMacroAssembler { // Check whether we are exceeding the stack limit on the backtrack stack. void CheckStackLimit(); - // Called from RegExp if the stack-guard is triggered. - // If the code object is relocated, the return address is fixed before - // returning. - static int CheckStackGuardState(Address* return_address, - Code* re_code, - Address re_frame); - // Generate a call to CheckStackGuardState. void CallCheckStackGuardState(Register scratch); - // Called from RegExp if the backtrack stack limit is hit. - // Tries to expand the stack. Returns the new stack-pointer if - // successful, and updates the stack_top address, or returns 0 if unable - // to grow the stack. - // This function must not trigger a garbage collection. - static Address GrowStack(Address stack_pointer, Address* stack_top); - // The ebp-relative location of a regexp register. Operand register_location(int register_index); @@ -209,7 +202,7 @@ class RegExpMacroAssemblerIA32: public NativeRegExpMacroAssembler { // by FrameAlign. The called function is not allowed to trigger a garbage // collection, since that might move the code and invalidate the return // address (unless this is somehow accounted for). - inline void CallCFunction(Address function_address, int num_arguments); + inline void CallCFunction(ExternalReference function, int num_arguments); MacroAssembler* masm_; diff --git a/src/ia32/simulator-ia32.h b/src/ia32/simulator-ia32.h index 4d02c03ab..3bed2681f 100644 --- a/src/ia32/simulator-ia32.h +++ b/src/ia32/simulator-ia32.h @@ -44,4 +44,9 @@ (reinterpret_cast(this) >= limit ? \ reinterpret_cast(this) - limit : 0) +// Call the generated regexp code directly. The entry function pointer should +// expect seven int/pointer sized arguments and return an int. +#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \ + entry(p0, p1, p2, p3, p4, p5, p6) + #endif // V8_IA32_SIMULATOR_IA32_H_ diff --git a/src/jsregexp.cc b/src/jsregexp.cc index 06208aa50..40df777c8 100644 --- a/src/jsregexp.cc +++ b/src/jsregexp.cc @@ -51,6 +51,7 @@ #include "x64/macro-assembler-x64.h" #include "x64/regexp-macro-assembler-x64.h" #elif V8_TARGET_ARCH_ARM +#include "arm/macro-assembler-arm.h" #include "arm/regexp-macro-assembler-arm.h" #else #error Unsupported target architecture. @@ -419,9 +420,7 @@ Handle RegExpImpl::IrregexpExec(Handle jsregexp, Handle regexp(FixedArray::cast(jsregexp->data())); #ifdef V8_NATIVE_REGEXP -#ifdef V8_TARGET_ARCH_ARM - UNIMPLEMENTED(); -#else // Native regexp supported. + OffsetsVector captures(number_of_capture_registers); int* captures_vector = captures.vector(); NativeRegExpMacroAssembler::Result res; @@ -455,9 +454,9 @@ Handle RegExpImpl::IrregexpExec(Handle jsregexp, SetCapture(*array, i, captures_vector[i]); SetCapture(*array, i + 1, captures_vector[i + 1]); } -#endif // Native regexp supported. #else // ! V8_NATIVE_REGEXP + bool is_ascii = subject->IsAsciiRepresentation(); if (!EnsureCompiledIrregexp(jsregexp, is_ascii)) { return Handle::null(); @@ -487,6 +486,7 @@ Handle RegExpImpl::IrregexpExec(Handle jsregexp, SetCapture(*array, i, register_vector[i]); SetCapture(*array, i + 1, register_vector[i + 1]); } + #endif // V8_NATIVE_REGEXP SetLastCaptureCount(*array, number_of_capture_registers); @@ -1723,6 +1723,8 @@ bool RegExpNode::EmitQuickCheck(RegExpCompiler* compiler, GetQuickCheckDetails(details, compiler, 0, trace->at_start() == Trace::FALSE); if (details->cannot_match()) return false; if (!details->Rationalize(compiler->ascii())) return false; + if (details->characters() > 1 && + !compiler->macro_assembler()->CanReadUnaligned()) return false; uint32_t mask = details->mask(); uint32_t value = details->value(); @@ -2522,20 +2524,20 @@ void LoopChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) { int ChoiceNode::CalculatePreloadCharacters(RegExpCompiler* compiler) { int preload_characters = EatsAtLeast(4, 0); -#ifdef V8_HOST_CAN_READ_UNALIGNED - bool ascii = compiler->ascii(); - if (ascii) { - if (preload_characters > 4) preload_characters = 4; - // We can't preload 3 characters because there is no machine instruction - // to do that. We can't just load 4 because we could be reading - // beyond the end of the string, which could cause a memory fault. - if (preload_characters == 3) preload_characters = 2; + if (compiler->macro_assembler()->CanReadUnaligned()) { + bool ascii = compiler->ascii(); + if (ascii) { + if (preload_characters > 4) preload_characters = 4; + // We can't preload 3 characters because there is no machine instruction + // to do that. We can't just load 4 because we could be reading + // beyond the end of the string, which could cause a memory fault. + if (preload_characters == 3) preload_characters = 2; + } else { + if (preload_characters > 2) preload_characters = 2; + } } else { - if (preload_characters > 2) preload_characters = 2; + if (preload_characters > 1) preload_characters = 1; } -#else - if (preload_characters > 1) preload_characters = 1; -#endif return preload_characters; } @@ -4470,16 +4472,12 @@ RegExpEngine::CompilationResult RegExpEngine::Compile(RegExpCompileData* data, is_ascii ? NativeRegExpMacroAssembler::ASCII : NativeRegExpMacroAssembler::UC16; -#ifdef V8_TARGET_ARCH_IA32 - RegExpMacroAssemblerIA32 macro_assembler(mode, - (data->capture_count + 1) * 2); -#endif -#ifdef V8_TARGET_ARCH_X64 - RegExpMacroAssemblerX64 macro_assembler(mode, - (data->capture_count + 1) * 2); -#endif -#ifdef V8_TARGET_ARCH_ARM - UNIMPLEMENTED(); +#if V8_TARGET_ARCH_IA32 + RegExpMacroAssemblerIA32 macro_assembler(mode, (data->capture_count + 1) * 2); +#elif V8_TARGET_ARCH_X64 + RegExpMacroAssemblerX64 macro_assembler(mode, (data->capture_count + 1) * 2); +#elif V8_TARGET_ARCH_ARM + RegExpMacroAssemblerARM macro_assembler(mode, (data->capture_count + 1) * 2); #endif #else // ! V8_NATIVE_REGEXP diff --git a/src/regexp-macro-assembler-irregexp-inl.h b/src/regexp-macro-assembler-irregexp-inl.h index 5074f210a..b487468ef 100644 --- a/src/regexp-macro-assembler-irregexp-inl.h +++ b/src/regexp-macro-assembler-irregexp-inl.h @@ -38,6 +38,7 @@ namespace v8 { namespace internal { +#ifndef V8_NATIVE_REGEXP void RegExpMacroAssemblerIrregexp::Emit(uint32_t byte, uint32_t twenty_four_bits) { @@ -70,6 +71,7 @@ void RegExpMacroAssemblerIrregexp::Emit32(uint32_t word) { pc_ += 4; } +#endif // ! V8_NATIVE_REGEXP } } // namespace v8::internal diff --git a/src/regexp-macro-assembler-irregexp.cc b/src/regexp-macro-assembler-irregexp.cc index 21b622ef0..f9c7eeee0 100644 --- a/src/regexp-macro-assembler-irregexp.cc +++ b/src/regexp-macro-assembler-irregexp.cc @@ -36,6 +36,7 @@ namespace v8 { namespace internal { +#ifndef V8_NATIVE_REGEXP RegExpMacroAssemblerIrregexp::RegExpMacroAssemblerIrregexp(Vector buffer) : buffer_(buffer), @@ -458,5 +459,6 @@ void RegExpMacroAssemblerIrregexp::Expand() { } } +#endif // !V8_NATIVE_REGEXP } } // namespace v8::internal diff --git a/src/regexp-macro-assembler-irregexp.h b/src/regexp-macro-assembler-irregexp.h index dd64e7ae8..642a28390 100644 --- a/src/regexp-macro-assembler-irregexp.h +++ b/src/regexp-macro-assembler-irregexp.h @@ -31,6 +31,7 @@ namespace v8 { namespace internal { +#ifndef V8_NATIVE_REGEXP class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler { public: @@ -133,6 +134,8 @@ class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler { DISALLOW_IMPLICIT_CONSTRUCTORS(RegExpMacroAssemblerIrregexp); }; +#endif // !V8_NATIVE_REGEXP + } } // namespace v8::internal #endif // V8_REGEXP_MACRO_ASSEMBLER_IRREGEXP_H_ diff --git a/src/regexp-macro-assembler-tracer.h b/src/regexp-macro-assembler-tracer.h index 28434d7ca..28ca5f340 100644 --- a/src/regexp-macro-assembler-tracer.h +++ b/src/regexp-macro-assembler-tracer.h @@ -37,7 +37,7 @@ class RegExpMacroAssemblerTracer: public RegExpMacroAssembler { explicit RegExpMacroAssemblerTracer(RegExpMacroAssembler* assembler); virtual ~RegExpMacroAssemblerTracer(); virtual int stack_limit_slack() { return assembler_->stack_limit_slack(); } - + virtual bool CanReadUnaligned() { return assembler_->CanReadUnaligned(); } virtual void AdvanceCurrentPosition(int by); // Signed cp change. virtual void AdvanceRegister(int reg, int by); // r[reg] += by. virtual void Backtrack(); diff --git a/src/regexp-macro-assembler.cc b/src/regexp-macro-assembler.cc index 7f830fe48..0d00ceec3 100644 --- a/src/regexp-macro-assembler.cc +++ b/src/regexp-macro-assembler.cc @@ -30,6 +30,13 @@ #include "assembler.h" #include "regexp-stack.h" #include "regexp-macro-assembler.h" +#if V8_TARGET_ARCH_ARM +#include "arm/simulator-arm.h" +#elif V8_TARGET_ARCH_IA32 +#include "ia32/simulator-ia32.h" +#elif V8_TARGET_ARCH_X64 +#include "x64/simulator-x64.h" +#endif namespace v8 { namespace internal { @@ -42,6 +49,15 @@ RegExpMacroAssembler::~RegExpMacroAssembler() { } +bool RegExpMacroAssembler::CanReadUnaligned() { +#ifdef V8_HOST_CAN_READ_UNALIGNED + return true; +#else + return false; +#endif +} + + #ifdef V8_NATIVE_REGEXP // Avoid unused code, e.g., on ARM. NativeRegExpMacroAssembler::NativeRegExpMacroAssembler() { @@ -51,6 +67,15 @@ NativeRegExpMacroAssembler::NativeRegExpMacroAssembler() { NativeRegExpMacroAssembler::~NativeRegExpMacroAssembler() { } + +bool NativeRegExpMacroAssembler::CanReadUnaligned() { +#ifdef V8_TARGET_CAN_READ_UNALIGNED + return true; +#else + return false; +#endif +} + const byte* NativeRegExpMacroAssembler::StringCharacterPosition( String* subject, int start_index) { @@ -162,13 +187,14 @@ NativeRegExpMacroAssembler::Result NativeRegExpMacroAssembler::Execute( RegExpStack stack; Address stack_base = RegExpStack::stack_base(); - int result = matcher_func(input, - start_offset, - input_start, - input_end, - output, - at_start_val, - stack_base); + int result = CALL_GENERATED_REGEXP_CODE(matcher_func, + input, + start_offset, + input_start, + input_end, + output, + at_start_val, + stack_base); ASSERT(result <= SUCCESS); ASSERT(result >= RETRY); @@ -213,5 +239,22 @@ int NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16( return 1; } + +Address NativeRegExpMacroAssembler::GrowStack(Address stack_pointer, + Address* stack_base) { + size_t size = RegExpStack::stack_capacity(); + Address old_stack_base = RegExpStack::stack_base(); + ASSERT(old_stack_base == *stack_base); + ASSERT(stack_pointer <= old_stack_base); + ASSERT(static_cast(old_stack_base - stack_pointer) <= size); + Address new_stack_base = RegExpStack::EnsureCapacity(size * 2); + if (new_stack_base == NULL) { + return NULL; + } + *stack_base = new_stack_base; + intptr_t stack_content_size = old_stack_base - stack_pointer; + return new_stack_base - stack_content_size; +} + #endif // V8_NATIVE_REGEXP } } // namespace v8::internal diff --git a/src/regexp-macro-assembler.h b/src/regexp-macro-assembler.h index e59082768..26aab2c72 100644 --- a/src/regexp-macro-assembler.h +++ b/src/regexp-macro-assembler.h @@ -61,6 +61,7 @@ class RegExpMacroAssembler { // kCheckStackLimit flag to push operations (instead of kNoStackLimitCheck) // at least once for every stack_limit() pushes that are executed. virtual int stack_limit_slack() = 0; + virtual bool CanReadUnaligned(); virtual void AdvanceCurrentPosition(int by) = 0; // Signed cp change. virtual void AdvanceRegister(int reg, int by) = 0; // r[reg] += by. // Continues execution from the position pushed on the top of the backtrack @@ -182,6 +183,7 @@ class NativeRegExpMacroAssembler: public RegExpMacroAssembler { NativeRegExpMacroAssembler(); virtual ~NativeRegExpMacroAssembler(); + virtual bool CanReadUnaligned(); static Result Match(Handle regexp, Handle subject, @@ -195,6 +197,13 @@ class NativeRegExpMacroAssembler: public RegExpMacroAssembler { Address byte_offset2, size_t byte_length); + // Called from RegExp if the backtrack stack limit is hit. + // Tries to expand the stack. Returns the new stack-pointer if + // successful, and updates the stack_top address, or returns 0 if unable + // to grow the stack. + // This function must not trigger a garbage collection. + static Address GrowStack(Address stack_pointer, Address* stack_top); + static const byte* StringCharacterPosition(String* subject, int start_index); static Result Execute(Code* code, @@ -205,7 +214,25 @@ class NativeRegExpMacroAssembler: public RegExpMacroAssembler { int* output, bool at_start); }; + + +// Enter C code from generated RegExp code in a way that allows +// the C code to fix the return address in case of a GC. +// Currently only needed on ARM. +class RegExpCEntryStub: public CodeStub { + public: + RegExpCEntryStub() {} + virtual ~RegExpCEntryStub() {} + void Generate(MacroAssembler* masm); + + private: + Major MajorKey() { return RegExpCEntry; } + int MinorKey() { return 0; } + const char* GetName() { return "RegExpCEntryStub"; } +}; + #endif // V8_NATIVE_REGEXP + } } // namespace v8::internal #endif // V8_REGEXP_MACRO_ASSEMBLER_H_ diff --git a/src/serialize.cc b/src/serialize.cc index d2fd1e4fc..8b647da1c 100644 --- a/src/serialize.cc +++ b/src/serialize.cc @@ -734,6 +734,20 @@ void ExternalReferenceTable::PopulateTable() { UNCLASSIFIED, 17, "compare_doubles"); +#ifdef V8_NATIVE_REGEXP + Add(ExternalReference::re_case_insensitive_compare_uc16().address(), + UNCLASSIFIED, + 18, + "NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16()"); + Add(ExternalReference::re_check_stack_guard_state().address(), + UNCLASSIFIED, + 19, + "RegExpMacroAssembler*::CheckStackGuardState()"); + Add(ExternalReference::re_grow_stack().address(), + UNCLASSIFIED, + 20, + "NativeRegExpMacroAssembler::GrowStack()"); +#endif } @@ -1118,6 +1132,11 @@ void Serializer::PutHeader() { writer_->PutC(FLAG_debug_serialization ? '1' : '0'); #else writer_->PutC('0'); +#endif +#ifdef V8_NATIVE_REGEXP + writer_->PutC('N'); +#else // Interpreted regexp + writer_->PutC('I'); #endif // Write sizes of paged memory spaces. Allocate extra space for the old // and code spaces, because objects in new space will be promoted to them. @@ -1474,6 +1493,11 @@ void Deserializer::GetHeader() { // In release mode, don't attempt to read a snapshot containing // synchronization tags. if (reader_.GetC() != '0') FATAL("Snapshot contains synchronization tags."); +#endif +#ifdef V8_NATIVE_REGEXP + reader_.ExpectC('N'); +#else // Interpreted regexp. + reader_.ExpectC('I'); #endif // Ensure sufficient capacity in paged memory spaces to avoid growth // during deserialization. diff --git a/src/x64/regexp-macro-assembler-x64.cc b/src/x64/regexp-macro-assembler-x64.cc index 4c6a84d6e..373f35949 100644 --- a/src/x64/regexp-macro-assembler-x64.cc +++ b/src/x64/regexp-macro-assembler-x64.cc @@ -39,6 +39,8 @@ namespace v8 { namespace internal { +#ifdef V8_NATIVE_REGEXP + /* * This assembler uses the following register assignment convention * - rdx : currently loaded character(s) as ASCII or UC16. Must be loaded using @@ -110,6 +112,7 @@ RegExpMacroAssemblerX64::RegExpMacroAssemblerX64( success_label_(), backtrack_label_(), exit_label_() { + ASSERT_EQ(0, registers_to_save % 2); __ jmp(&entry_label_); // We'll write the entry code when we know more. __ bind(&start_label_); // And then continue from here. } @@ -350,8 +353,9 @@ void RegExpMacroAssemblerX64::CheckNotBackReferenceIgnoreCase( // Set byte_length. __ movq(rdx, rbx); #endif - Address function_address = FUNCTION_ADDR(&CaseInsensitiveCompareUC16); - CallCFunction(function_address, num_arguments); + ExternalReference compare = + ExternalReference::re_case_insensitive_compare_uc16(); + CallCFunction(compare, num_arguments); // Restore original values before reacting on result value. __ Move(code_object_pointer(), masm_->CodeObject()); @@ -808,11 +812,12 @@ Handle RegExpMacroAssemblerX64::GetCode(Handle source) { // First argument, backtrack stackpointer, is already in rcx. __ lea(rdx, Operand(rbp, kStackHighEnd)); // Second argument #else - // AMD64 ABI passes paremeters in rdi, rsi. + // AMD64 ABI passes parameters in rdi, rsi. __ movq(rdi, backtrack_stackpointer()); // First argument. __ lea(rsi, Operand(rbp, kStackHighEnd)); // Second argument. #endif - CallCFunction(FUNCTION_ADDR(&GrowStack), num_arguments); + ExternalReference grow_stack = ExternalReference::re_grow_stack(); + CallCFunction(grow_stack, num_arguments); // If return NULL, we have failed to grow the stack, and // must exit with a stack-overflow exception. __ testq(rax, rax); @@ -889,7 +894,9 @@ void RegExpMacroAssemblerX64::LoadCurrentCharacter(int cp_offset, int characters) { ASSERT(cp_offset >= -1); // ^ and \b can look behind one character. ASSERT(cp_offset < (1<<30)); // Be sane! (And ensure negation works) - CheckPosition(cp_offset + characters - 1, on_end_of_input); + if (check_bounds) { + CheckPosition(cp_offset + characters - 1, on_end_of_input); + } LoadCurrentCharacterUnchecked(cp_offset, characters); } @@ -997,7 +1004,9 @@ void RegExpMacroAssemblerX64::CallCheckStackGuardState() { // return address). __ lea(rdi, Operand(rsp, -kPointerSize)); #endif - CallCFunction(FUNCTION_ADDR(&CheckStackGuardState), num_arguments); + ExternalReference stack_check = + ExternalReference::re_check_stack_guard_state(); + CallCFunction(stack_check, num_arguments); } @@ -1080,23 +1089,6 @@ int RegExpMacroAssemblerX64::CheckStackGuardState(Address* return_address, } -Address RegExpMacroAssemblerX64::GrowStack(Address stack_pointer, - Address* stack_base) { - size_t size = RegExpStack::stack_capacity(); - Address old_stack_base = RegExpStack::stack_base(); - ASSERT(old_stack_base == *stack_base); - ASSERT(stack_pointer <= old_stack_base); - ASSERT(static_cast(old_stack_base - stack_pointer) <= size); - Address new_stack_base = RegExpStack::EnsureCapacity(size * 2); - if (new_stack_base == NULL) { - return NULL; - } - *stack_base = new_stack_base; - intptr_t stack_content_size = old_stack_base - stack_pointer; - return new_stack_base - stack_content_size; -} - - Operand RegExpMacroAssemblerX64::register_location(int register_index) { ASSERT(register_index < (1<<30)); if (num_registers_ <= register_index) { @@ -1256,17 +1248,16 @@ void RegExpMacroAssemblerX64::FrameAlign(int num_arguments) { } -void RegExpMacroAssemblerX64::CallCFunction(Address function_address, +void RegExpMacroAssemblerX64::CallCFunction(ExternalReference function, int num_arguments) { - // Don't compile regexps with serialization enabled. The addresses of the C++ - // function being called isn't relocatable. - ASSERT(!Serializer::enabled()); - __ movq(rax, reinterpret_cast(function_address), RelocInfo::NONE); + __ movq(rax, function); __ call(rax); ASSERT(OS::ActivationFrameAlignment() != 0); #ifdef _WIN64 __ movq(rsp, Operand(rsp, num_arguments * kPointerSize)); #else + // All arguments passed in registers. + ASSERT(num_arguments <= 6); __ pop(rsp); #endif } @@ -1297,5 +1288,12 @@ void RegExpMacroAssemblerX64::LoadCurrentCharacterUnchecked(int cp_offset, } +void RegExpCEntryStub::Generate(MacroAssembler* masm_) { + __ int3(); // Unused on x64. +} + #undef __ + +#endif // V8_NATIVE_REGEXP + }} // namespace v8::internal diff --git a/src/x64/regexp-macro-assembler-x64.h b/src/x64/regexp-macro-assembler-x64.h index a270bc186..ab9647704 100644 --- a/src/x64/regexp-macro-assembler-x64.h +++ b/src/x64/regexp-macro-assembler-x64.h @@ -31,6 +31,8 @@ namespace v8 { namespace internal { +#ifdef V8_NATIVE_REGEXP + class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler { public: RegExpMacroAssemblerX64(Mode mode, int registers_to_save); @@ -113,6 +115,13 @@ class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler { int* output, bool at_start); + // Called from RegExp if the stack-guard is triggered. + // If the code object is relocated, the return address is fixed before + // returning. + static int CheckStackGuardState(Address* return_address, + Code* re_code, + Address re_frame); + private: // Offsets from rbp of function parameters and stored registers. static const int kFramePointer = 0; @@ -181,23 +190,9 @@ class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler { // Check whether we are exceeding the stack limit on the backtrack stack. void CheckStackLimit(); - // Called from RegExp if the stack-guard is triggered. - // If the code object is relocated, the return address is fixed before - // returning. - static int CheckStackGuardState(Address* return_address, - Code* re_code, - Address re_frame); - // Generate a call to CheckStackGuardState. void CallCheckStackGuardState(); - // Called from RegExp if the backtrack stack limit is hit. - // Tries to expand the stack. Returns the new stack-pointer if - // successful, and updates the stack_top address, or returns 0 if unable - // to grow the stack. - // This function must not trigger a garbage collection. - static Address GrowStack(Address stack_pointer, Address* stack_top); - // The rbp-relative location of a regexp register. Operand register_location(int register_index); @@ -264,7 +259,7 @@ class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler { // by FrameAlign. The called function is not allowed to trigger a garbage // collection, since that might move the code and invalidate the return // address (unless this is somehow accounted for by the called function). - inline void CallCFunction(Address function_address, int num_arguments); + inline void CallCFunction(ExternalReference function, int num_arguments); MacroAssembler* masm_; @@ -290,6 +285,8 @@ class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler { Label stack_overflow_label_; }; +#endif // V8_NATIVE_REGEXP + }} // namespace v8::internal #endif // V8_X64_REGEXP_MACRO_ASSEMBLER_X64_H_ diff --git a/src/x64/simulator-x64.h b/src/x64/simulator-x64.h index 6b4d718f6..184c166bc 100644 --- a/src/x64/simulator-x64.h +++ b/src/x64/simulator-x64.h @@ -45,4 +45,9 @@ (reinterpret_cast(this) >= limit ? \ reinterpret_cast(this) - limit : 0) +// Call the generated regexp code directly. The entry function pointer should +// expect seven int/pointer sized arguments and return an int. +#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \ + entry(p0, p1, p2, p3, p4, p5, p6) + #endif // V8_X64_SIMULATOR_X64_H_ diff --git a/test/cctest/test-assembler-arm.cc b/test/cctest/test-assembler-arm.cc index fe1621c2a..34f16395e 100644 --- a/test/cctest/test-assembler-arm.cc +++ b/test/cctest/test-assembler-arm.cc @@ -185,7 +185,7 @@ TEST(3) { Label L, C; __ mov(ip, Operand(sp)); - __ stm(db_w, sp, r4.bit() | fp.bit() | sp.bit() | lr.bit()); + __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit()); __ sub(fp, ip, Operand(4)); __ mov(r4, Operand(r0)); __ ldr(r0, MemOperand(r4, OFFSET_OF(T, i))); @@ -199,7 +199,7 @@ TEST(3) { __ add(r0, r2, Operand(r0)); __ mov(r2, Operand(r2, ASR, 3)); __ strh(r2, MemOperand(r4, OFFSET_OF(T, s))); - __ ldm(ia, sp, r4.bit() | fp.bit() | sp.bit() | pc.bit()); + __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit()); CodeDesc desc; assm.GetCode(&desc); diff --git a/test/cctest/test-regexp.cc b/test/cctest/test-regexp.cc index 89c7868d8..81c220520 100644 --- a/test/cctest/test-regexp.cc +++ b/test/cctest/test-regexp.cc @@ -40,6 +40,7 @@ #include "regexp-macro-assembler-irregexp.h" #ifdef V8_NATIVE_REGEXP #ifdef V8_TARGET_ARCH_ARM +#include "arm/macro-assembler-arm.h" #include "arm/regexp-macro-assembler-arm.h" #endif #ifdef V8_TARGET_ARCH_X64 @@ -605,11 +606,12 @@ TEST(DispatchTableConstruction) { #ifdef V8_NATIVE_REGEXP -#ifdef V8_TARGET_ARCH_IA32 +#if V8_TARGET_ARCH_IA32 typedef RegExpMacroAssemblerIA32 ArchRegExpMacroAssembler; -#endif -#ifdef V8_TARGET_ARCH_X64 +#elif V8_TARGET_ARCH_X64 typedef RegExpMacroAssemblerX64 ArchRegExpMacroAssembler; +#elif V8_TARGET_ARCH_ARM +typedef RegExpMacroAssemblerARM ArchRegExpMacroAssembler; #endif class ContextInitializer { @@ -845,7 +847,7 @@ TEST(MacroAssemblerNativeBackReferenceASCII) { v8::V8::Initialize(); ContextInitializer initializer; - ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::ASCII, 3); + ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::ASCII, 4); m.WriteCurrentPositionToRegister(0, 0); m.AdvanceCurrentPosition(2); @@ -870,7 +872,7 @@ TEST(MacroAssemblerNativeBackReferenceASCII) { Handle seq_input = Handle::cast(input); Address start_adr = seq_input->GetCharsAddress(); - int output[3]; + int output[4]; NativeRegExpMacroAssembler::Result result = Execute(*code, *input, @@ -884,6 +886,7 @@ TEST(MacroAssemblerNativeBackReferenceASCII) { CHECK_EQ(0, output[0]); CHECK_EQ(2, output[1]); CHECK_EQ(6, output[2]); + CHECK_EQ(-1, output[3]); } @@ -891,7 +894,7 @@ TEST(MacroAssemblerNativeBackReferenceUC16) { v8::V8::Initialize(); ContextInitializer initializer; - ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::UC16, 3); + ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::UC16, 4); m.WriteCurrentPositionToRegister(0, 0); m.AdvanceCurrentPosition(2); @@ -918,7 +921,7 @@ TEST(MacroAssemblerNativeBackReferenceUC16) { Handle seq_input = Handle::cast(input); Address start_adr = seq_input->GetCharsAddress(); - int output[3]; + int output[4]; NativeRegExpMacroAssembler::Result result = Execute(*code, *input, @@ -932,6 +935,7 @@ TEST(MacroAssemblerNativeBackReferenceUC16) { CHECK_EQ(0, output[0]); CHECK_EQ(2, output[1]); CHECK_EQ(6, output[2]); + CHECK_EQ(-1, output[3]); } @@ -1055,12 +1059,12 @@ TEST(MacroAssemblerNativeRegisters) { v8::V8::Initialize(); ContextInitializer initializer; - ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::ASCII, 5); + ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::ASCII, 6); uc16 foo_chars[3] = {'f', 'o', 'o'}; Vector foo(foo_chars, 3); - enum registers { out1, out2, out3, out4, out5, sp, loop_cnt }; + enum registers { out1, out2, out3, out4, out5, out6, sp, loop_cnt }; Label fail; Label backtrack; m.WriteCurrentPositionToRegister(out1, 0); // Output: [0] @@ -1114,7 +1118,7 @@ TEST(MacroAssemblerNativeRegisters) { m.GoTo(&loop3); m.Bind(&exit_loop3); m.PopCurrentPosition(); - m.WriteCurrentPositionToRegister(out5, 0); // [0,3,6,9,9] + m.WriteCurrentPositionToRegister(out5, 0); // [0,3,6,9,9,-1] m.Succeed(); @@ -1132,15 +1136,15 @@ TEST(MacroAssemblerNativeRegisters) { Handle seq_input = Handle::cast(input); Address start_adr = seq_input->GetCharsAddress(); - int output[5]; + int output[6]; NativeRegExpMacroAssembler::Result result = Execute(*code, - *input, - 0, - start_adr, - start_adr + input->length(), - output, - true); + *input, + 0, + start_adr, + start_adr + input->length(), + output, + true); CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result); CHECK_EQ(0, output[0]); @@ -1148,6 +1152,7 @@ TEST(MacroAssemblerNativeRegisters) { CHECK_EQ(6, output[2]); CHECK_EQ(9, output[3]); CHECK_EQ(9, output[4]); + CHECK_EQ(-1, output[5]); } diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp index 037efa70c..1222ea9c9 100644 --- a/tools/gyp/v8.gyp +++ b/tools/gyp/v8.gyp @@ -433,18 +433,14 @@ '../../src/ia32/jump-target-ia32.cc', '../../src/ia32/macro-assembler-ia32.cc', '../../src/ia32/macro-assembler-ia32.h', + '../../src/ia32/regexp-macro-assembler-ia32.cc', + '../../src/ia32/regexp-macro-assembler-ia32.h', '../../src/ia32/register-allocator-ia32.cc', '../../src/ia32/stub-cache-ia32.cc', '../../src/ia32/virtual-frame-ia32.cc', '../../src/ia32/virtual-frame-ia32.h', ], }], - ['target_arch=="ia32" and v8_regexp=="native"', { - 'sources': [ - '../../src/ia32/regexp-macro-assembler-ia32.cc', - '../../src/ia32/regexp-macro-assembler-ia32.h', - ], - }], ['target_arch=="x64"', { 'include_dirs+': [ '../../src/x64', @@ -466,18 +462,14 @@ '../../src/x64/jump-target-x64.cc', '../../src/x64/macro-assembler-x64.cc', '../../src/x64/macro-assembler-x64.h', + '../../src/x64/regexp-macro-assembler-x64.cc', + '../../src/x64/regexp-macro-assembler-x64.h', '../../src/x64/register-allocator-x64.cc', '../../src/x64/stub-cache-x64.cc', '../../src/x64/virtual-frame-x64.cc', '../../src/x64/virtual-frame-x64.h', ], }], - ['target_arch=="x64" and v8_regexp=="native"', { - 'sources': [ - '../../src/x64/regexp-macro-assembler-x64.cc', - '../../src/x64/regexp-macro-assembler-x64.h', - ], - }], ['OS=="linux"', { 'link_settings': { 'libraries': [ -- 2.34.1