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
This commit is contained in:
parent
fcf8293df2
commit
9230ad29eb
@ -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']
|
||||
|
@ -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'],
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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";
|
||||
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();
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -39,7 +39,7 @@
|
||||
|
||||
#ifndef V8_ARM_ASSEMBLER_ARM_H_
|
||||
#define V8_ARM_ASSEMBLER_ARM_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#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
|
||||
|
@ -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));
|
||||
|
@ -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<char> 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()) {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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<const uc16> 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<Object> GetCode(Handle<String> 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<int>(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_
|
||||
|
@ -26,7 +26,7 @@
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <cstdarg>
|
||||
#include "v8.h"
|
||||
|
||||
#include "disasm.h"
|
||||
@ -598,7 +598,7 @@ uint16_t Simulator::ReadHU(int32_t addr, Instr* instr) {
|
||||
uint16_t* ptr = reinterpret_cast<uint16_t*>(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<int16_t*>(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<byte*>(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<intptr_t*>(get_register(sp));
|
||||
*(--stack_pointer) = p4;
|
||||
set_register(sp, reinterpret_cast<int32_t>(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<intptr_t*>(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<int32_t>(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<Object*>(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
|
||||
|
@ -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<Object*>(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<uintptr_t>(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<Object*>( \
|
||||
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);
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -57,6 +57,7 @@ class CodeStub BASE_EMBEDDED {
|
||||
SetProperty, // ARM only
|
||||
InvokeBuiltin, // ARM only
|
||||
JSExit, // ARM only
|
||||
RegExpCEntry, // ARM only
|
||||
NUMBER_OF_IDS
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
14
src/heap.cc
14
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
|
||||
}
|
||||
|
||||
|
||||
|
11
src/heap.h
11
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,
|
||||
|
@ -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<Object> RegExpMacroAssemblerIA32::GetCode(Handle<String> 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<size_t>(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<int32_t>(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
|
||||
|
@ -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_;
|
||||
|
||||
|
@ -44,4 +44,9 @@
|
||||
(reinterpret_cast<uintptr_t>(this) >= limit ? \
|
||||
reinterpret_cast<uintptr_t>(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_
|
||||
|
@ -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<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> jsregexp,
|
||||
Handle<FixedArray> 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<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> 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<Object>::null();
|
||||
@ -487,6 +486,7 @@ Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> 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
|
||||
|
@ -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
|
||||
|
||||
|
@ -36,6 +36,7 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
#ifndef V8_NATIVE_REGEXP
|
||||
|
||||
RegExpMacroAssemblerIrregexp::RegExpMacroAssemblerIrregexp(Vector<byte> buffer)
|
||||
: buffer_(buffer),
|
||||
@ -458,5 +459,6 @@ void RegExpMacroAssemblerIrregexp::Expand() {
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !V8_NATIVE_REGEXP
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
@ -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_
|
||||
|
@ -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();
|
||||
|
@ -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<size_t>(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
|
||||
|
@ -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<Code> regexp,
|
||||
Handle<String> 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_
|
||||
|
@ -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.
|
||||
|
@ -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<Object> RegExpMacroAssemblerX64::GetCode(Handle<String> 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<size_t>(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<intptr_t>(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
|
||||
|
@ -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_
|
||||
|
@ -45,4 +45,9 @@
|
||||
(reinterpret_cast<uintptr_t>(this) >= limit ? \
|
||||
reinterpret_cast<uintptr_t>(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_
|
||||
|
@ -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);
|
||||
|
@ -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<SeqAsciiString> seq_input = Handle<SeqAsciiString>::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<SeqTwoByteString> seq_input = Handle<SeqTwoByteString>::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<const uc16> 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<SeqAsciiString> seq_input = Handle<SeqAsciiString>::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]);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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': [
|
||||
|
Loading…
Reference in New Issue
Block a user