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:
lrn@chromium.org 2009-08-31 12:40:37 +00:00
parent fcf8293df2
commit 9230ad29eb
34 changed files with 2058 additions and 272 deletions

View File

@ -99,12 +99,7 @@ LIBRARY_FLAGS = {
'CPPDEFINES': ['ENABLE_LOGGING_AND_PROFILING'], 'CPPDEFINES': ['ENABLE_LOGGING_AND_PROFILING'],
'CPPPATH': [join(root_dir, 'src')], 'CPPPATH': [join(root_dir, 'src')],
'regexp:native': { 'regexp:native': {
'arch:ia32' : {
'CPPDEFINES': ['V8_NATIVE_REGEXP'] 'CPPDEFINES': ['V8_NATIVE_REGEXP']
},
'arch:x64' : {
'CPPDEFINES': ['V8_NATIVE_REGEXP']
}
}, },
'mode:debug': { 'mode:debug': {
'CPPDEFINES': ['V8_ENABLE_CHECKS'] 'CPPDEFINES': ['V8_ENABLE_CHECKS']

View File

@ -63,32 +63,22 @@ SOURCES = {
'arm/register-allocator-arm.cc', 'arm/stub-cache-arm.cc', 'arm/register-allocator-arm.cc', 'arm/stub-cache-arm.cc',
'arm/virtual-frame-arm.cc' 'arm/virtual-frame-arm.cc'
], ],
'arch:ia32': { 'arch:ia32': [
'all': [ 'ia32/assembler-ia32.cc', 'ia32/builtins-ia32.cc', 'ia32/cfg-ia32.cc',
'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/codegen-ia32.cc', 'ia32/cpu-ia32.cc', 'ia32/disasm-ia32.cc', 'ia32/debug-ia32.cc', 'ia32/frames-ia32.cc', 'ia32/ic-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/jump-target-ia32.cc', 'ia32/macro-assembler-ia32.cc', 'ia32/regexp-macro-assembler-ia32.cc', 'ia32/register-allocator-ia32.cc',
'ia32/register-allocator-ia32.cc', 'ia32/stub-cache-ia32.cc', 'ia32/stub-cache-ia32.cc', 'ia32/virtual-frame-ia32.cc'
'ia32/virtual-frame-ia32.cc' ],
], 'arch:x64': [
'regexp:native': [ 'x64/assembler-x64.cc', 'x64/builtins-x64.cc', 'x64/cfg-x64.cc',
'ia32/regexp-macro-assembler-ia32.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',
'arch:x64': { 'x64/regexp-macro-assembler-x64.cc', 'x64/register-allocator-x64.cc',
'all': [ 'x64/stub-cache-x64.cc', 'x64/virtual-frame-x64.cc'
'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'
]
},
'simulator:arm': ['arm/simulator-arm.cc'], 'simulator:arm': ['arm/simulator-arm.cc'],
'os:freebsd': ['platform-freebsd.cc', 'platform-posix.cc'], 'os:freebsd': ['platform-freebsd.cc', 'platform-posix.cc'],
'os:linux': ['platform-linux.cc', 'platform-posix.cc'], 'os:linux': ['platform-linux.cc', 'platform-posix.cc'],

View File

@ -204,7 +204,7 @@ void Assembler::CheckBuffer() {
if (buffer_space() <= kGap) { if (buffer_space() <= kGap) {
GrowBuffer(); GrowBuffer();
} }
if (pc_offset() > next_buffer_check_) { if (pc_offset() >= next_buffer_check_) {
CheckConstPool(false, true); CheckConstPool(false, true);
} }
} }

View File

@ -329,19 +329,30 @@ const int kEndOfChain = -4;
int Assembler::target_at(int pos) { int Assembler::target_at(int pos) {
Instr instr = instr_at(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 ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24
int imm26 = ((instr & Imm24Mask) << 8) >> 6; int imm26 = ((instr & Imm24Mask) << 8) >> 6;
if ((instr & CondMask) == nv && (instr & B24) != 0) if ((instr & CondMask) == nv && (instr & B24) != 0)
// blx uses bit 24 to encode bit 2 of imm26 // blx uses bit 24 to encode bit 2 of imm26
imm26 += 2; imm26 += 2;
return pos + 8 + imm26; return pos + kPcLoadDelta + imm26;
} }
void Assembler::target_at_put(int pos, int target_pos) { void Assembler::target_at_put(int pos, int target_pos) {
int imm26 = target_pos - pos - 8;
Instr instr = instr_at(pos); 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 ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24
if ((instr & CondMask) == nv) { if ((instr & CondMask) == nv) {
// blx uses bit 24 to encode bit 2 of imm26 // blx uses bit 24 to encode bit 2 of imm26
@ -368,41 +379,45 @@ void Assembler::print(Label* L) {
while (l.is_linked()) { while (l.is_linked()) {
PrintF("@ %d ", l.pos()); PrintF("@ %d ", l.pos());
Instr instr = instr_at(l.pos()); Instr instr = instr_at(l.pos());
ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx if ((instr & ~Imm24Mask) == 0) {
int cond = instr & CondMask; PrintF("value\n");
const char* b;
const char* c;
if (cond == nv) {
b = "blx";
c = "";
} else { } else {
if ((instr & B24) != 0) ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx
b = "bl"; int cond = instr & CondMask;
else const char* b;
b = "b"; const char* c;
if (cond == nv) {
b = "blx";
c = "";
} else {
if ((instr & B24) != 0)
b = "bl";
else
b = "b";
switch (cond) { switch (cond) {
case eq: c = "eq"; break; case eq: c = "eq"; break;
case ne: c = "ne"; break; case ne: c = "ne"; break;
case hs: c = "hs"; break; case hs: c = "hs"; break;
case lo: c = "lo"; break; case lo: c = "lo"; break;
case mi: c = "mi"; break; case mi: c = "mi"; break;
case pl: c = "pl"; break; case pl: c = "pl"; break;
case vs: c = "vs"; break; case vs: c = "vs"; break;
case vc: c = "vc"; break; case vc: c = "vc"; break;
case hi: c = "hi"; break; case hi: c = "hi"; break;
case ls: c = "ls"; break; case ls: c = "ls"; break;
case ge: c = "ge"; break; case ge: c = "ge"; break;
case lt: c = "lt"; break; case lt: c = "lt"; break;
case gt: c = "gt"; break; case gt: c = "gt"; break;
case le: c = "le"; break; case le: c = "le"; break;
case al: c = ""; break; case al: c = ""; break;
default: default:
c = ""; c = "";
UNREACHABLE(); UNREACHABLE();
}
} }
PrintF("%s%s\n", b, c);
} }
PrintF("%s%s\n", b, c);
next(&l); next(&l);
} }
} else { } 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 // Block the emission of the constant pool, since the branch instruction must
// be emitted at the pc offset recorded by the label // be emitted at the pc offset recorded by the label
BlockConstPoolBefore(pc_offset() + kInstrSize); 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));
}
} }

View File

@ -39,7 +39,7 @@
#ifndef V8_ARM_ASSEMBLER_ARM_H_ #ifndef V8_ARM_ASSEMBLER_ARM_H_
#define V8_ARM_ASSEMBLER_ARM_H_ #define V8_ARM_ASSEMBLER_ARM_H_
#include <stdio.h>
#include "assembler.h" #include "assembler.h"
namespace v8 { namespace v8 {
@ -165,9 +165,10 @@ enum Coprocessor {
enum Condition { enum Condition {
eq = 0 << 28, // Z set equal. eq = 0 << 28, // Z set equal.
ne = 1 << 28, // Z clear not 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. 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. lo = 3 << 28, // C clear unsigned lower.
mi = 4 << 28, // N set negative. mi = 4 << 28, // N set negative.
pl = 5 << 28, // N clear positive or zero. 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. // Manages the jump elimination optimization if the second parameter is true.
int branch_offset(Label* L, bool jump_elimination_allowed); 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 // Return the address in the constant pool of the code target address used by
// the branch/call instruction at pc. // the branch/call instruction at pc.
INLINE(static Address target_address_address_at(Address pc)); INLINE(static Address target_address_address_at(Address pc));
@ -435,6 +440,10 @@ class Assembler : public Malloced {
// to jump to. // to jump to.
static const int kPatchReturnSequenceAddressOffset = 1; static const int kPatchReturnSequenceAddressOffset = 1;
// Difference between address of current opcode and value read from pc
// register.
static const int kPcLoadDelta = 8;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Code generation // Code generation
@ -784,6 +793,8 @@ class Assembler : public Malloced {
// Record reloc info for current pc_ // Record reloc info for current pc_
void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0); void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
friend class RegExpMacroAssemblerARM;
}; };
} } // namespace v8::internal } } // namespace v8::internal

View File

@ -5682,9 +5682,9 @@ void UnarySubStub::Generate(MacroAssembler* masm) {
__ str(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); __ str(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
} else { } else {
AllocateHeapNumber(masm, &slow, r1, r2, r3); AllocateHeapNumber(masm, &slow, r1, r2, r3);
__ ldr(r2, FieldMemOperand(r0, HeapNumber::kMantissaOffset)); __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
__ str(r2, FieldMemOperand(r1, HeapNumber::kMantissaOffset));
__ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
__ str(r3, FieldMemOperand(r1, HeapNumber::kMantissaOffset));
__ eor(r2, r2, Operand(HeapNumber::kSignMask)); // Flip sign. __ eor(r2, r2, Operand(HeapNumber::kSignMask)); // Flip sign.
__ str(r2, FieldMemOperand(r1, HeapNumber::kExponentOffset)); __ str(r2, FieldMemOperand(r1, HeapNumber::kExponentOffset));
__ mov(r0, Operand(r1)); __ mov(r0, Operand(r1));

View File

@ -119,6 +119,7 @@ class Decoder {
void DecodeType5(Instr* instr); void DecodeType5(Instr* instr);
void DecodeType6(Instr* instr); void DecodeType6(Instr* instr);
void DecodeType7(Instr* instr); void DecodeType7(Instr* instr);
void DecodeUnconditional(Instr* instr);
const disasm::NameConverter& converter_; const disasm::NameConverter& converter_;
v8::internal::Vector<char> out_buffer_; 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. // Disassemble the instruction at *instr_ptr into the output buffer.
int Decoder::InstructionDecode(byte* instr_ptr) { int Decoder::InstructionDecode(byte* instr_ptr) {
Instr* instr = Instr::At(instr_ptr); Instr* instr = Instr::At(instr_ptr);
@ -782,7 +844,7 @@ int Decoder::InstructionDecode(byte* instr_ptr) {
"%08x ", "%08x ",
instr->InstructionBits()); instr->InstructionBits());
if (instr->ConditionField() == special_condition) { if (instr->ConditionField() == special_condition) {
Format(instr, "break 'msg"); DecodeUnconditional(instr);
return Instr::kInstrSize; return Instr::kInstrSize;
} }
switch (instr->TypeField()) { switch (instr->TypeField()) {

File diff suppressed because it is too large Load Diff

View File

@ -31,12 +31,239 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
#ifndef V8_NATIVE_REGEXP
class RegExpMacroAssemblerARM: public RegExpMacroAssembler { class RegExpMacroAssemblerARM: public RegExpMacroAssembler {
public: public:
RegExpMacroAssemblerARM(); RegExpMacroAssemblerARM();
virtual ~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 }} // namespace v8::internal
#endif // V8_ARM_REGEXP_MACRO_ASSEMBLER_ARM_H_ #endif // V8_ARM_REGEXP_MACRO_ASSEMBLER_ARM_H_

View File

@ -26,7 +26,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdlib.h> #include <stdlib.h>
#include <cstdarg>
#include "v8.h" #include "v8.h"
#include "disasm.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); uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
return *ptr; 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(); UNIMPLEMENTED();
return 0; return 0;
} }
@ -609,7 +609,7 @@ int16_t Simulator::ReadH(int32_t addr, Instr* instr) {
int16_t* ptr = reinterpret_cast<int16_t*>(addr); int16_t* ptr = reinterpret_cast<int16_t*>(addr);
return *ptr; return *ptr;
} }
PrintF("Unaligned read at %x\n", addr); PrintF("Unaligned signed halfword read at %x\n", addr);
UNIMPLEMENTED(); UNIMPLEMENTED();
return 0; return 0;
} }
@ -621,7 +621,7 @@ void Simulator::WriteH(int32_t addr, uint16_t value, Instr* instr) {
*ptr = value; *ptr = value;
return; return;
} }
PrintF("Unaligned write at %x, pc=%p\n", addr, instr); PrintF("Unaligned unsigned halfword write at %x, pc=%p\n", addr, instr);
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
@ -632,7 +632,7 @@ void Simulator::WriteH(int32_t addr, int16_t value, Instr* instr) {
*ptr = value; *ptr = value;
return; return;
} }
PrintF("Unaligned write at %x, pc=%p\n", addr, instr); PrintF("Unaligned halfword write at %x, pc=%p\n", addr, instr);
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
@ -1416,8 +1416,12 @@ void Simulator::DecodeType01(Instr* instr) {
case CMN: { case CMN: {
if (instr->HasS()) { if (instr->HasS()) {
Format(instr, "cmn'cond 'rn, 'shift_rm"); // Format(instr, "cmn'cond 'rn, 'shift_rm");
Format(instr, "cmn'cond 'rn, 'imm"); // 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 { } else {
ASSERT(type == 0); ASSERT(type == 0);
int rm = instr->RmField(); int rm = instr->RmField();
@ -1566,6 +1570,7 @@ void Simulator::DecodeType2(Instr* instr) {
void Simulator::DecodeType3(Instr* instr) { void Simulator::DecodeType3(Instr* instr) {
ASSERT(instr->Bit(4) == 0);
int rd = instr->RdField(); int rd = instr->RdField();
int rn = instr->RnField(); int rn = instr->RnField();
int32_t rn_val = get_register(rn); int32_t rn_val = get_register(rn);
@ -1605,7 +1610,12 @@ void Simulator::DecodeType3(Instr* instr) {
} }
} }
if (instr->HasB()) { if (instr->HasB()) {
UNIMPLEMENTED(); if (instr->HasL()) {
uint8_t byte = ReadB(addr);
set_register(rd, byte);
} else {
UNIMPLEMENTED();
}
} else { } else {
if (instr->HasL()) { if (instr->HasL()) {
set_register(rd, ReadW(addr, instr)); set_register(rd, ReadW(addr, instr));
@ -1630,12 +1640,13 @@ void Simulator::DecodeType4(Instr* instr) {
void Simulator::DecodeType5(Instr* instr) { void Simulator::DecodeType5(Instr* instr) {
// Format(instr, "b'l'cond 'target"); // Format(instr, "b'l'cond 'target");
int off = (instr->SImmed24Field() << 2) + 8; int off = (instr->SImmed24Field() << 2);
intptr_t pc = get_pc(); intptr_t pc_address = get_pc();
if (instr->HasLink()) { 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. // Executes the current instruction.
void Simulator::InstructionDecode(Instr* instr) { void Simulator::InstructionDecode(Instr* instr) {
pc_modified_ = false; pc_modified_ = false;
if (instr->ConditionField() == special_condition) {
Debugger dbg(this);
dbg.Stop(instr);
return;
}
if (::v8::internal::FLAG_trace_sim) { if (::v8::internal::FLAG_trace_sim) {
disasm::NameConverter converter; disasm::NameConverter converter;
disasm::Disassembler dasm(converter); disasm::Disassembler dasm(converter);
@ -1671,7 +1743,9 @@ void Simulator::InstructionDecode(Instr* instr) {
reinterpret_cast<byte*>(instr)); reinterpret_cast<byte*>(instr));
PrintF(" 0x%x %s\n", instr, buffer.start()); 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()) { switch (instr->TypeField()) {
case 0: case 0:
case 1: { 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 Simulator::Call(byte* entry, int argument_count, ...) {
int32_t p3, int32_t p4) { va_list parameters;
// Setup parameters va_start(parameters, argument_count);
set_register(r0, p0); // Setup arguments
set_register(r1, p1);
set_register(r2, p2); // First four arguments passed in registers.
set_register(r3, p3); ASSERT(argument_count >= 4);
intptr_t* stack_pointer = reinterpret_cast<intptr_t*>(get_register(sp)); set_register(r0, va_arg(parameters, int32_t));
*(--stack_pointer) = p4; set_register(r1, va_arg(parameters, int32_t));
set_register(sp, reinterpret_cast<int32_t>(stack_pointer)); 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 // 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 // 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 // when the PC reaches this value. By saving the "end simulation" value into
// the LR the simulation stops when returning to this call point. // 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(); Execute();
// Check that the callee-saved registers have been preserved. // Check that the callee-saved registers have been preserved.
CHECK_EQ(get_register(r4), callee_saved_value); CHECK_EQ(callee_saved_value, get_register(r4));
CHECK_EQ(get_register(r5), callee_saved_value); CHECK_EQ(callee_saved_value, get_register(r5));
CHECK_EQ(get_register(r6), callee_saved_value); CHECK_EQ(callee_saved_value, get_register(r6));
CHECK_EQ(get_register(r7), callee_saved_value); CHECK_EQ(callee_saved_value, get_register(r7));
CHECK_EQ(get_register(r8), callee_saved_value); CHECK_EQ(callee_saved_value, get_register(r8));
CHECK_EQ(get_register(r9), callee_saved_value); CHECK_EQ(callee_saved_value, get_register(r9));
CHECK_EQ(get_register(r10), callee_saved_value); CHECK_EQ(callee_saved_value, get_register(r10));
CHECK_EQ(get_register(r11), callee_saved_value); CHECK_EQ(callee_saved_value, get_register(r11));
// Restore callee-saved registers with the original value. // Restore callee-saved registers with the original value.
set_register(r4, r4_val); 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(r10, r10_val);
set_register(r11, r11_val); set_register(r11, r11_val);
int result = get_register(r0); // Pop stack passed arguments.
return reinterpret_cast<Object*>(result); CHECK_EQ(entry_stack, get_register(sp));
set_register(sp, original_stack);
int32_t result = get_register(r0);
return result;
} }
} } // namespace assembler::arm } } // namespace assembler::arm

View File

@ -40,7 +40,7 @@
// When running without a simulator we call the entry directly. // When running without a simulator we call the entry directly.
#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \ #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. // 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 // 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) \ #define GENERATED_CODE_STACK_LIMIT(limit) \
(reinterpret_cast<uintptr_t>(this) - 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__) #else // defined(__arm__)
// When running with the simulator transition into simulated execution at this // When running with the simulator transition into simulated execution at this
// point. // point.
#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \ #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
assembler::arm::Simulator::current()->Call((int32_t)entry, (int32_t)p0, \ reinterpret_cast<Object*>( \
(int32_t)p1, (int32_t)p2, (int32_t)p3, (int32_t)p4) 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 simulator has its own stack. Thus it has a different stack limit from
// the C-based native code. // the C-based native code.
@ -63,6 +70,10 @@
(assembler::arm::Simulator::current()->StackLimit()) (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" #include "constants-arm.h"
@ -109,11 +120,10 @@ class Simulator {
// Call on program start. // Call on program start.
static void Initialize(); static void Initialize();
// V8 generally calls into generated code with 5 parameters. This is a // V8 generally calls into generated JS code with 5 parameters and into
// convenience function, which sets up the simulator state and grabs the // generated RegExp code with 7 parameters. This is a convenience function,
// result on return. // 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 Call(byte* entry, int argument_count, ...);
int32_t p2, int32_t p3, int32_t p4);
private: private:
enum special_values { enum special_values {
@ -174,6 +184,7 @@ class Simulator {
void DecodeType5(Instr* instr); void DecodeType5(Instr* instr);
void DecodeType6(Instr* instr); void DecodeType6(Instr* instr);
void DecodeType7(Instr* instr); void DecodeType7(Instr* instr);
void DecodeUnconditional(Instr* instr);
// Executes one instruction. // Executes one instruction.
void InstructionDecode(Instr* instr); void InstructionDecode(Instr* instr);

View File

@ -42,6 +42,20 @@
#include "serialize.h" #include "serialize.h"
#include "stub-cache.h" #include "stub-cache.h"
#include "regexp-stack.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 v8 {
namespace internal { namespace internal {
@ -597,6 +611,34 @@ ExternalReference ExternalReference::new_space_allocation_limit_address() {
return ExternalReference(Heap::NewSpaceAllocationLimitAddress()); 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) { static double add_two_doubles(double x, double y) {
return x + y; return x + y;

View File

@ -431,6 +431,19 @@ class ExternalReference BASE_EMBEDDED {
static ExternalReference debug_step_in_fp_address(); static ExternalReference debug_step_in_fp_address();
#endif #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. // This lets you register a function that rewrites all external references.
// Used by the ARM simulator to catch calls to external references. // Used by the ARM simulator to catch calls to external references.
static void set_redirector(ExternalReferenceRedirector* redirector) { static void set_redirector(ExternalReferenceRedirector* redirector) {

View File

@ -57,6 +57,7 @@ class CodeStub BASE_EMBEDDED {
SetProperty, // ARM only SetProperty, // ARM only
InvokeBuiltin, // ARM only InvokeBuiltin, // ARM only
JSExit, // ARM only JSExit, // ARM only
RegExpCEntry, // ARM only
NUMBER_OF_IDS NUMBER_OF_IDS
}; };

View File

@ -47,7 +47,14 @@ namespace internal {
#define V8_HOST_ARCH_ARM 1 #define V8_HOST_ARCH_ARM 1
#define V8_HOST_ARCH_32_BIT 1 #define V8_HOST_ARCH_32_BIT 1
#else #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 #endif
// Support for alternative bool type. This is only enabled if the code is // Support for alternative bool type. This is only enabled if the code is

View File

@ -39,6 +39,9 @@
#include "scanner.h" #include "scanner.h"
#include "scopeinfo.h" #include "scopeinfo.h"
#include "v8threads.h" #include "v8threads.h"
#if V8_TARGET_ARCH_ARM && V8_NATIVE_REGEXP
#include "regexp-macro-assembler.h"
#endif
namespace v8 { namespace v8 {
namespace internal { 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() { void Heap::CreateCEntryDebugBreakStub() {
CEntryDebugBreakStub stub; CEntryDebugBreakStub stub;
set_c_entry_debug_break_code(*stub.GetCode()); set_c_entry_debug_break_code(*stub.GetCode());
@ -1356,6 +1367,9 @@ void Heap::CreateFixedStubs() {
Heap::CreateCEntryDebugBreakStub(); Heap::CreateCEntryDebugBreakStub();
Heap::CreateJSEntryStub(); Heap::CreateJSEntryStub();
Heap::CreateJSConstructEntryStub(); Heap::CreateJSConstructEntryStub();
#if V8_TARGET_ARCH_ARM && V8_NATIVE_REGEXP
Heap::CreateRegExpCEntryStub();
#endif
} }

View File

@ -34,7 +34,7 @@ namespace v8 {
namespace internal { namespace internal {
// Defines all the roots in Heap. // 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. */ \ /* Cluster the most popular ones in a few cache lines here at the top. */ \
V(Smi, stack_limit, StackLimit) \ V(Smi, stack_limit, StackLimit) \
V(Object, undefined_value, UndefinedValue) \ V(Object, undefined_value, UndefinedValue) \
@ -136,6 +136,13 @@ namespace internal {
V(FixedArray, natives_source_cache, NativesSourceCache) \ V(FixedArray, natives_source_cache, NativesSourceCache) \
V(Object, last_script_id, LastScriptId) \ 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) \ #define ROOT_LIST(V) \
STRONG_ROOT_LIST(V) \ STRONG_ROOT_LIST(V) \
@ -1025,6 +1032,8 @@ class Heap : public AllStatic {
static void CreateCEntryDebugBreakStub(); static void CreateCEntryDebugBreakStub();
static void CreateJSEntryStub(); static void CreateJSEntryStub();
static void CreateJSConstructEntryStub(); static void CreateJSConstructEntryStub();
static void CreateRegExpCEntryStub();
static void CreateFixedStubs(); static void CreateFixedStubs();
static Object* CreateOddball(Map* map, static Object* CreateOddball(Map* map,

View File

@ -102,6 +102,7 @@ RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32(
success_label_(), success_label_(),
backtrack_label_(), backtrack_label_(),
exit_label_() { exit_label_() {
ASSERT_EQ(0, registers_to_save % 2);
__ jmp(&entry_label_); // We'll write the entry code later. __ jmp(&entry_label_); // We'll write the entry code later.
__ bind(&start_label_); // And then continue from here. __ bind(&start_label_); // And then continue from here.
} }
@ -337,8 +338,9 @@ void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase(
__ add(edx, Operand(esi)); __ add(edx, Operand(esi));
__ mov(Operand(esp, 0 * kPointerSize), edx); __ mov(Operand(esp, 0 * kPointerSize), edx);
Address function_address = FUNCTION_ADDR(&CaseInsensitiveCompareUC16); ExternalReference compare =
CallCFunction(function_address, argument_count); ExternalReference::re_case_insensitive_compare_uc16();
CallCFunction(compare, argument_count);
// Pop original values before reacting on result value. // Pop original values before reacting on result value.
__ pop(ebx); __ pop(ebx);
__ pop(backtrack_stackpointer()); __ pop(backtrack_stackpointer());
@ -745,7 +747,8 @@ Handle<Object> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
__ lea(eax, Operand(ebp, kStackHighEnd)); __ lea(eax, Operand(ebp, kStackHighEnd));
__ mov(Operand(esp, 1 * kPointerSize), eax); __ mov(Operand(esp, 1 * kPointerSize), eax);
__ mov(Operand(esp, 0 * kPointerSize), backtrack_stackpointer()); __ 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 // If return NULL, we have failed to grow the stack, and
// must exit with a stack-overflow exception. // must exit with a stack-overflow exception.
__ or_(eax, Operand(eax)); __ or_(eax, Operand(eax));
@ -817,7 +820,9 @@ void RegExpMacroAssemblerIA32::LoadCurrentCharacter(int cp_offset,
int characters) { int characters) {
ASSERT(cp_offset >= -1); // ^ and \b can look behind one character. ASSERT(cp_offset >= -1); // ^ and \b can look behind one character.
ASSERT(cp_offset < (1<<30)); // Be sane! (And ensure negation works) 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); LoadCurrentCharacterUnchecked(cp_offset, characters);
} }
@ -913,7 +918,9 @@ void RegExpMacroAssemblerIA32::CallCheckStackGuardState(Register scratch) {
// Next address on the stack (will be address of return address). // Next address on the stack (will be address of return address).
__ lea(eax, Operand(esp, -kPointerSize)); __ lea(eax, Operand(esp, -kPointerSize));
__ mov(Operand(esp, 0 * kPointerSize), eax); __ 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) { Operand RegExpMacroAssemblerIA32::register_location(int register_index) {
ASSERT(register_index < (1<<30)); ASSERT(register_index < (1<<30));
if (num_registers_ <= register_index) { 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) { int num_arguments) {
__ mov(Operand(eax), Immediate(reinterpret_cast<int32_t>(function_address))); __ mov(Operand(eax), Immediate(function));
__ call(Operand(eax)); __ call(Operand(eax));
if (OS::ActivationFrameAlignment() != 0) { if (OS::ActivationFrameAlignment() != 0) {
__ mov(esp, Operand(esp, num_arguments * kPointerSize)); __ 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 __ #undef __
#endif // V8_NATIVE_REGEXP #endif // V8_NATIVE_REGEXP

View File

@ -107,6 +107,13 @@ class RegExpMacroAssemblerIA32: public NativeRegExpMacroAssembler {
virtual void ClearRegisters(int reg_from, int reg_to); virtual void ClearRegisters(int reg_from, int reg_to);
virtual void WriteStackPointerToRegister(int reg); 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: private:
// Offsets from ebp of function parameters and stored registers. // Offsets from ebp of function parameters and stored registers.
static const int kFramePointer = 0; 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. // Check whether we are exceeding the stack limit on the backtrack stack.
void CheckStackLimit(); 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. // Generate a call to CheckStackGuardState.
void CallCheckStackGuardState(Register scratch); 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. // The ebp-relative location of a regexp register.
Operand register_location(int register_index); 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 // by FrameAlign. The called function is not allowed to trigger a garbage
// collection, since that might move the code and invalidate the return // collection, since that might move the code and invalidate the return
// address (unless this is somehow accounted for). // 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_; MacroAssembler* masm_;

View File

@ -44,4 +44,9 @@
(reinterpret_cast<uintptr_t>(this) >= limit ? \ (reinterpret_cast<uintptr_t>(this) >= limit ? \
reinterpret_cast<uintptr_t>(this) - limit : 0) 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_ #endif // V8_IA32_SIMULATOR_IA32_H_

View File

@ -51,6 +51,7 @@
#include "x64/macro-assembler-x64.h" #include "x64/macro-assembler-x64.h"
#include "x64/regexp-macro-assembler-x64.h" #include "x64/regexp-macro-assembler-x64.h"
#elif V8_TARGET_ARCH_ARM #elif V8_TARGET_ARCH_ARM
#include "arm/macro-assembler-arm.h"
#include "arm/regexp-macro-assembler-arm.h" #include "arm/regexp-macro-assembler-arm.h"
#else #else
#error Unsupported target architecture. #error Unsupported target architecture.
@ -419,9 +420,7 @@ Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> jsregexp,
Handle<FixedArray> regexp(FixedArray::cast(jsregexp->data())); Handle<FixedArray> regexp(FixedArray::cast(jsregexp->data()));
#ifdef V8_NATIVE_REGEXP #ifdef V8_NATIVE_REGEXP
#ifdef V8_TARGET_ARCH_ARM
UNIMPLEMENTED();
#else // Native regexp supported.
OffsetsVector captures(number_of_capture_registers); OffsetsVector captures(number_of_capture_registers);
int* captures_vector = captures.vector(); int* captures_vector = captures.vector();
NativeRegExpMacroAssembler::Result res; NativeRegExpMacroAssembler::Result res;
@ -455,9 +454,9 @@ Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> jsregexp,
SetCapture(*array, i, captures_vector[i]); SetCapture(*array, i, captures_vector[i]);
SetCapture(*array, i + 1, captures_vector[i + 1]); SetCapture(*array, i + 1, captures_vector[i + 1]);
} }
#endif // Native regexp supported.
#else // ! V8_NATIVE_REGEXP #else // ! V8_NATIVE_REGEXP
bool is_ascii = subject->IsAsciiRepresentation(); bool is_ascii = subject->IsAsciiRepresentation();
if (!EnsureCompiledIrregexp(jsregexp, is_ascii)) { if (!EnsureCompiledIrregexp(jsregexp, is_ascii)) {
return Handle<Object>::null(); return Handle<Object>::null();
@ -487,6 +486,7 @@ Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> jsregexp,
SetCapture(*array, i, register_vector[i]); SetCapture(*array, i, register_vector[i]);
SetCapture(*array, i + 1, register_vector[i + 1]); SetCapture(*array, i + 1, register_vector[i + 1]);
} }
#endif // V8_NATIVE_REGEXP #endif // V8_NATIVE_REGEXP
SetLastCaptureCount(*array, number_of_capture_registers); SetLastCaptureCount(*array, number_of_capture_registers);
@ -1723,6 +1723,8 @@ bool RegExpNode::EmitQuickCheck(RegExpCompiler* compiler,
GetQuickCheckDetails(details, compiler, 0, trace->at_start() == Trace::FALSE); GetQuickCheckDetails(details, compiler, 0, trace->at_start() == Trace::FALSE);
if (details->cannot_match()) return false; if (details->cannot_match()) return false;
if (!details->Rationalize(compiler->ascii())) 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 mask = details->mask();
uint32_t value = details->value(); uint32_t value = details->value();
@ -2522,20 +2524,20 @@ void LoopChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace) {
int ChoiceNode::CalculatePreloadCharacters(RegExpCompiler* compiler) { int ChoiceNode::CalculatePreloadCharacters(RegExpCompiler* compiler) {
int preload_characters = EatsAtLeast(4, 0); int preload_characters = EatsAtLeast(4, 0);
#ifdef V8_HOST_CAN_READ_UNALIGNED if (compiler->macro_assembler()->CanReadUnaligned()) {
bool ascii = compiler->ascii(); bool ascii = compiler->ascii();
if (ascii) { if (ascii) {
if (preload_characters > 4) preload_characters = 4; if (preload_characters > 4) preload_characters = 4;
// We can't preload 3 characters because there is no machine instruction // 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 // 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. // beyond the end of the string, which could cause a memory fault.
if (preload_characters == 3) preload_characters = 2; if (preload_characters == 3) preload_characters = 2;
} else {
if (preload_characters > 2) preload_characters = 2;
}
} else { } 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; return preload_characters;
} }
@ -4470,16 +4472,12 @@ RegExpEngine::CompilationResult RegExpEngine::Compile(RegExpCompileData* data,
is_ascii ? NativeRegExpMacroAssembler::ASCII is_ascii ? NativeRegExpMacroAssembler::ASCII
: NativeRegExpMacroAssembler::UC16; : NativeRegExpMacroAssembler::UC16;
#ifdef V8_TARGET_ARCH_IA32 #if V8_TARGET_ARCH_IA32
RegExpMacroAssemblerIA32 macro_assembler(mode, RegExpMacroAssemblerIA32 macro_assembler(mode, (data->capture_count + 1) * 2);
(data->capture_count + 1) * 2); #elif V8_TARGET_ARCH_X64
#endif RegExpMacroAssemblerX64 macro_assembler(mode, (data->capture_count + 1) * 2);
#ifdef V8_TARGET_ARCH_X64 #elif V8_TARGET_ARCH_ARM
RegExpMacroAssemblerX64 macro_assembler(mode, RegExpMacroAssemblerARM macro_assembler(mode, (data->capture_count + 1) * 2);
(data->capture_count + 1) * 2);
#endif
#ifdef V8_TARGET_ARCH_ARM
UNIMPLEMENTED();
#endif #endif
#else // ! V8_NATIVE_REGEXP #else // ! V8_NATIVE_REGEXP

View File

@ -38,6 +38,7 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
#ifndef V8_NATIVE_REGEXP
void RegExpMacroAssemblerIrregexp::Emit(uint32_t byte, void RegExpMacroAssemblerIrregexp::Emit(uint32_t byte,
uint32_t twenty_four_bits) { uint32_t twenty_four_bits) {
@ -70,6 +71,7 @@ void RegExpMacroAssemblerIrregexp::Emit32(uint32_t word) {
pc_ += 4; pc_ += 4;
} }
#endif // ! V8_NATIVE_REGEXP
} } // namespace v8::internal } } // namespace v8::internal

View File

@ -36,6 +36,7 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
#ifndef V8_NATIVE_REGEXP
RegExpMacroAssemblerIrregexp::RegExpMacroAssemblerIrregexp(Vector<byte> buffer) RegExpMacroAssemblerIrregexp::RegExpMacroAssemblerIrregexp(Vector<byte> buffer)
: buffer_(buffer), : buffer_(buffer),
@ -458,5 +459,6 @@ void RegExpMacroAssemblerIrregexp::Expand() {
} }
} }
#endif // !V8_NATIVE_REGEXP
} } // namespace v8::internal } } // namespace v8::internal

View File

@ -31,6 +31,7 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
#ifndef V8_NATIVE_REGEXP
class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler { class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler {
public: public:
@ -133,6 +134,8 @@ class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler {
DISALLOW_IMPLICIT_CONSTRUCTORS(RegExpMacroAssemblerIrregexp); DISALLOW_IMPLICIT_CONSTRUCTORS(RegExpMacroAssemblerIrregexp);
}; };
#endif // !V8_NATIVE_REGEXP
} } // namespace v8::internal } } // namespace v8::internal
#endif // V8_REGEXP_MACRO_ASSEMBLER_IRREGEXP_H_ #endif // V8_REGEXP_MACRO_ASSEMBLER_IRREGEXP_H_

View File

@ -37,7 +37,7 @@ class RegExpMacroAssemblerTracer: public RegExpMacroAssembler {
explicit RegExpMacroAssemblerTracer(RegExpMacroAssembler* assembler); explicit RegExpMacroAssemblerTracer(RegExpMacroAssembler* assembler);
virtual ~RegExpMacroAssemblerTracer(); virtual ~RegExpMacroAssemblerTracer();
virtual int stack_limit_slack() { return assembler_->stack_limit_slack(); } 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 AdvanceCurrentPosition(int by); // Signed cp change.
virtual void AdvanceRegister(int reg, int by); // r[reg] += by. virtual void AdvanceRegister(int reg, int by); // r[reg] += by.
virtual void Backtrack(); virtual void Backtrack();

View File

@ -30,6 +30,13 @@
#include "assembler.h" #include "assembler.h"
#include "regexp-stack.h" #include "regexp-stack.h"
#include "regexp-macro-assembler.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 v8 {
namespace internal { 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. #ifdef V8_NATIVE_REGEXP // Avoid unused code, e.g., on ARM.
NativeRegExpMacroAssembler::NativeRegExpMacroAssembler() { NativeRegExpMacroAssembler::NativeRegExpMacroAssembler() {
@ -51,6 +67,15 @@ NativeRegExpMacroAssembler::NativeRegExpMacroAssembler() {
NativeRegExpMacroAssembler::~NativeRegExpMacroAssembler() { NativeRegExpMacroAssembler::~NativeRegExpMacroAssembler() {
} }
bool NativeRegExpMacroAssembler::CanReadUnaligned() {
#ifdef V8_TARGET_CAN_READ_UNALIGNED
return true;
#else
return false;
#endif
}
const byte* NativeRegExpMacroAssembler::StringCharacterPosition( const byte* NativeRegExpMacroAssembler::StringCharacterPosition(
String* subject, String* subject,
int start_index) { int start_index) {
@ -162,13 +187,14 @@ NativeRegExpMacroAssembler::Result NativeRegExpMacroAssembler::Execute(
RegExpStack stack; RegExpStack stack;
Address stack_base = RegExpStack::stack_base(); Address stack_base = RegExpStack::stack_base();
int result = matcher_func(input, int result = CALL_GENERATED_REGEXP_CODE(matcher_func,
start_offset, input,
input_start, start_offset,
input_end, input_start,
output, input_end,
at_start_val, output,
stack_base); at_start_val,
stack_base);
ASSERT(result <= SUCCESS); ASSERT(result <= SUCCESS);
ASSERT(result >= RETRY); ASSERT(result >= RETRY);
@ -213,5 +239,22 @@ int NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16(
return 1; 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 #endif // V8_NATIVE_REGEXP
} } // namespace v8::internal } } // namespace v8::internal

View File

@ -61,6 +61,7 @@ class RegExpMacroAssembler {
// kCheckStackLimit flag to push operations (instead of kNoStackLimitCheck) // kCheckStackLimit flag to push operations (instead of kNoStackLimitCheck)
// at least once for every stack_limit() pushes that are executed. // at least once for every stack_limit() pushes that are executed.
virtual int stack_limit_slack() = 0; virtual int stack_limit_slack() = 0;
virtual bool CanReadUnaligned();
virtual void AdvanceCurrentPosition(int by) = 0; // Signed cp change. virtual void AdvanceCurrentPosition(int by) = 0; // Signed cp change.
virtual void AdvanceRegister(int reg, int by) = 0; // r[reg] += by. virtual void AdvanceRegister(int reg, int by) = 0; // r[reg] += by.
// Continues execution from the position pushed on the top of the backtrack // Continues execution from the position pushed on the top of the backtrack
@ -182,6 +183,7 @@ class NativeRegExpMacroAssembler: public RegExpMacroAssembler {
NativeRegExpMacroAssembler(); NativeRegExpMacroAssembler();
virtual ~NativeRegExpMacroAssembler(); virtual ~NativeRegExpMacroAssembler();
virtual bool CanReadUnaligned();
static Result Match(Handle<Code> regexp, static Result Match(Handle<Code> regexp,
Handle<String> subject, Handle<String> subject,
@ -195,6 +197,13 @@ class NativeRegExpMacroAssembler: public RegExpMacroAssembler {
Address byte_offset2, Address byte_offset2,
size_t byte_length); 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 const byte* StringCharacterPosition(String* subject, int start_index);
static Result Execute(Code* code, static Result Execute(Code* code,
@ -205,7 +214,25 @@ class NativeRegExpMacroAssembler: public RegExpMacroAssembler {
int* output, int* output,
bool at_start); 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 #endif // V8_NATIVE_REGEXP
} } // namespace v8::internal } } // namespace v8::internal
#endif // V8_REGEXP_MACRO_ASSEMBLER_H_ #endif // V8_REGEXP_MACRO_ASSEMBLER_H_

View File

@ -734,6 +734,20 @@ void ExternalReferenceTable::PopulateTable() {
UNCLASSIFIED, UNCLASSIFIED,
17, 17,
"compare_doubles"); "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'); writer_->PutC(FLAG_debug_serialization ? '1' : '0');
#else #else
writer_->PutC('0'); writer_->PutC('0');
#endif
#ifdef V8_NATIVE_REGEXP
writer_->PutC('N');
#else // Interpreted regexp
writer_->PutC('I');
#endif #endif
// Write sizes of paged memory spaces. Allocate extra space for the old // 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. // 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 // In release mode, don't attempt to read a snapshot containing
// synchronization tags. // synchronization tags.
if (reader_.GetC() != '0') FATAL("Snapshot contains 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 #endif
// Ensure sufficient capacity in paged memory spaces to avoid growth // Ensure sufficient capacity in paged memory spaces to avoid growth
// during deserialization. // during deserialization.

View File

@ -39,6 +39,8 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
#ifdef V8_NATIVE_REGEXP
/* /*
* This assembler uses the following register assignment convention * This assembler uses the following register assignment convention
* - rdx : currently loaded character(s) as ASCII or UC16. Must be loaded using * - rdx : currently loaded character(s) as ASCII or UC16. Must be loaded using
@ -110,6 +112,7 @@ RegExpMacroAssemblerX64::RegExpMacroAssemblerX64(
success_label_(), success_label_(),
backtrack_label_(), backtrack_label_(),
exit_label_() { exit_label_() {
ASSERT_EQ(0, registers_to_save % 2);
__ jmp(&entry_label_); // We'll write the entry code when we know more. __ jmp(&entry_label_); // We'll write the entry code when we know more.
__ bind(&start_label_); // And then continue from here. __ bind(&start_label_); // And then continue from here.
} }
@ -350,8 +353,9 @@ void RegExpMacroAssemblerX64::CheckNotBackReferenceIgnoreCase(
// Set byte_length. // Set byte_length.
__ movq(rdx, rbx); __ movq(rdx, rbx);
#endif #endif
Address function_address = FUNCTION_ADDR(&CaseInsensitiveCompareUC16); ExternalReference compare =
CallCFunction(function_address, num_arguments); ExternalReference::re_case_insensitive_compare_uc16();
CallCFunction(compare, num_arguments);
// Restore original values before reacting on result value. // Restore original values before reacting on result value.
__ Move(code_object_pointer(), masm_->CodeObject()); __ 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. // First argument, backtrack stackpointer, is already in rcx.
__ lea(rdx, Operand(rbp, kStackHighEnd)); // Second argument __ lea(rdx, Operand(rbp, kStackHighEnd)); // Second argument
#else #else
// AMD64 ABI passes paremeters in rdi, rsi. // AMD64 ABI passes parameters in rdi, rsi.
__ movq(rdi, backtrack_stackpointer()); // First argument. __ movq(rdi, backtrack_stackpointer()); // First argument.
__ lea(rsi, Operand(rbp, kStackHighEnd)); // Second argument. __ lea(rsi, Operand(rbp, kStackHighEnd)); // Second argument.
#endif #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 // If return NULL, we have failed to grow the stack, and
// must exit with a stack-overflow exception. // must exit with a stack-overflow exception.
__ testq(rax, rax); __ testq(rax, rax);
@ -889,7 +894,9 @@ void RegExpMacroAssemblerX64::LoadCurrentCharacter(int cp_offset,
int characters) { int characters) {
ASSERT(cp_offset >= -1); // ^ and \b can look behind one character. ASSERT(cp_offset >= -1); // ^ and \b can look behind one character.
ASSERT(cp_offset < (1<<30)); // Be sane! (And ensure negation works) 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); LoadCurrentCharacterUnchecked(cp_offset, characters);
} }
@ -997,7 +1004,9 @@ void RegExpMacroAssemblerX64::CallCheckStackGuardState() {
// return address). // return address).
__ lea(rdi, Operand(rsp, -kPointerSize)); __ lea(rdi, Operand(rsp, -kPointerSize));
#endif #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) { Operand RegExpMacroAssemblerX64::register_location(int register_index) {
ASSERT(register_index < (1<<30)); ASSERT(register_index < (1<<30));
if (num_registers_ <= register_index) { 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) { int num_arguments) {
// Don't compile regexps with serialization enabled. The addresses of the C++ __ movq(rax, function);
// function being called isn't relocatable.
ASSERT(!Serializer::enabled());
__ movq(rax, reinterpret_cast<intptr_t>(function_address), RelocInfo::NONE);
__ call(rax); __ call(rax);
ASSERT(OS::ActivationFrameAlignment() != 0); ASSERT(OS::ActivationFrameAlignment() != 0);
#ifdef _WIN64 #ifdef _WIN64
__ movq(rsp, Operand(rsp, num_arguments * kPointerSize)); __ movq(rsp, Operand(rsp, num_arguments * kPointerSize));
#else #else
// All arguments passed in registers.
ASSERT(num_arguments <= 6);
__ pop(rsp); __ pop(rsp);
#endif #endif
} }
@ -1297,5 +1288,12 @@ void RegExpMacroAssemblerX64::LoadCurrentCharacterUnchecked(int cp_offset,
} }
void RegExpCEntryStub::Generate(MacroAssembler* masm_) {
__ int3(); // Unused on x64.
}
#undef __ #undef __
#endif // V8_NATIVE_REGEXP
}} // namespace v8::internal }} // namespace v8::internal

View File

@ -31,6 +31,8 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
#ifdef V8_NATIVE_REGEXP
class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler { class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler {
public: public:
RegExpMacroAssemblerX64(Mode mode, int registers_to_save); RegExpMacroAssemblerX64(Mode mode, int registers_to_save);
@ -113,6 +115,13 @@ class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler {
int* output, int* output,
bool at_start); 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: private:
// Offsets from rbp of function parameters and stored registers. // Offsets from rbp of function parameters and stored registers.
static const int kFramePointer = 0; 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. // Check whether we are exceeding the stack limit on the backtrack stack.
void CheckStackLimit(); 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. // Generate a call to CheckStackGuardState.
void CallCheckStackGuardState(); 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. // The rbp-relative location of a regexp register.
Operand register_location(int register_index); 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 // by FrameAlign. The called function is not allowed to trigger a garbage
// collection, since that might move the code and invalidate the return // collection, since that might move the code and invalidate the return
// address (unless this is somehow accounted for by the called function). // 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_; MacroAssembler* masm_;
@ -290,6 +285,8 @@ class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler {
Label stack_overflow_label_; Label stack_overflow_label_;
}; };
#endif // V8_NATIVE_REGEXP
}} // namespace v8::internal }} // namespace v8::internal
#endif // V8_X64_REGEXP_MACRO_ASSEMBLER_X64_H_ #endif // V8_X64_REGEXP_MACRO_ASSEMBLER_X64_H_

View File

@ -45,4 +45,9 @@
(reinterpret_cast<uintptr_t>(this) >= limit ? \ (reinterpret_cast<uintptr_t>(this) >= limit ? \
reinterpret_cast<uintptr_t>(this) - limit : 0) 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_ #endif // V8_X64_SIMULATOR_X64_H_

View File

@ -185,7 +185,7 @@ TEST(3) {
Label L, C; Label L, C;
__ mov(ip, Operand(sp)); __ 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)); __ sub(fp, ip, Operand(4));
__ mov(r4, Operand(r0)); __ mov(r4, Operand(r0));
__ ldr(r0, MemOperand(r4, OFFSET_OF(T, i))); __ ldr(r0, MemOperand(r4, OFFSET_OF(T, i)));
@ -199,7 +199,7 @@ TEST(3) {
__ add(r0, r2, Operand(r0)); __ add(r0, r2, Operand(r0));
__ mov(r2, Operand(r2, ASR, 3)); __ mov(r2, Operand(r2, ASR, 3));
__ strh(r2, MemOperand(r4, OFFSET_OF(T, s))); __ 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; CodeDesc desc;
assm.GetCode(&desc); assm.GetCode(&desc);

View File

@ -40,6 +40,7 @@
#include "regexp-macro-assembler-irregexp.h" #include "regexp-macro-assembler-irregexp.h"
#ifdef V8_NATIVE_REGEXP #ifdef V8_NATIVE_REGEXP
#ifdef V8_TARGET_ARCH_ARM #ifdef V8_TARGET_ARCH_ARM
#include "arm/macro-assembler-arm.h"
#include "arm/regexp-macro-assembler-arm.h" #include "arm/regexp-macro-assembler-arm.h"
#endif #endif
#ifdef V8_TARGET_ARCH_X64 #ifdef V8_TARGET_ARCH_X64
@ -605,11 +606,12 @@ TEST(DispatchTableConstruction) {
#ifdef V8_NATIVE_REGEXP #ifdef V8_NATIVE_REGEXP
#ifdef V8_TARGET_ARCH_IA32 #if V8_TARGET_ARCH_IA32
typedef RegExpMacroAssemblerIA32 ArchRegExpMacroAssembler; typedef RegExpMacroAssemblerIA32 ArchRegExpMacroAssembler;
#endif #elif V8_TARGET_ARCH_X64
#ifdef V8_TARGET_ARCH_X64
typedef RegExpMacroAssemblerX64 ArchRegExpMacroAssembler; typedef RegExpMacroAssemblerX64 ArchRegExpMacroAssembler;
#elif V8_TARGET_ARCH_ARM
typedef RegExpMacroAssemblerARM ArchRegExpMacroAssembler;
#endif #endif
class ContextInitializer { class ContextInitializer {
@ -845,7 +847,7 @@ TEST(MacroAssemblerNativeBackReferenceASCII) {
v8::V8::Initialize(); v8::V8::Initialize();
ContextInitializer initializer; ContextInitializer initializer;
ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::ASCII, 3); ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::ASCII, 4);
m.WriteCurrentPositionToRegister(0, 0); m.WriteCurrentPositionToRegister(0, 0);
m.AdvanceCurrentPosition(2); m.AdvanceCurrentPosition(2);
@ -870,7 +872,7 @@ TEST(MacroAssemblerNativeBackReferenceASCII) {
Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input); Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
Address start_adr = seq_input->GetCharsAddress(); Address start_adr = seq_input->GetCharsAddress();
int output[3]; int output[4];
NativeRegExpMacroAssembler::Result result = NativeRegExpMacroAssembler::Result result =
Execute(*code, Execute(*code,
*input, *input,
@ -884,6 +886,7 @@ TEST(MacroAssemblerNativeBackReferenceASCII) {
CHECK_EQ(0, output[0]); CHECK_EQ(0, output[0]);
CHECK_EQ(2, output[1]); CHECK_EQ(2, output[1]);
CHECK_EQ(6, output[2]); CHECK_EQ(6, output[2]);
CHECK_EQ(-1, output[3]);
} }
@ -891,7 +894,7 @@ TEST(MacroAssemblerNativeBackReferenceUC16) {
v8::V8::Initialize(); v8::V8::Initialize();
ContextInitializer initializer; ContextInitializer initializer;
ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::UC16, 3); ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::UC16, 4);
m.WriteCurrentPositionToRegister(0, 0); m.WriteCurrentPositionToRegister(0, 0);
m.AdvanceCurrentPosition(2); m.AdvanceCurrentPosition(2);
@ -918,7 +921,7 @@ TEST(MacroAssemblerNativeBackReferenceUC16) {
Handle<SeqTwoByteString> seq_input = Handle<SeqTwoByteString>::cast(input); Handle<SeqTwoByteString> seq_input = Handle<SeqTwoByteString>::cast(input);
Address start_adr = seq_input->GetCharsAddress(); Address start_adr = seq_input->GetCharsAddress();
int output[3]; int output[4];
NativeRegExpMacroAssembler::Result result = NativeRegExpMacroAssembler::Result result =
Execute(*code, Execute(*code,
*input, *input,
@ -932,6 +935,7 @@ TEST(MacroAssemblerNativeBackReferenceUC16) {
CHECK_EQ(0, output[0]); CHECK_EQ(0, output[0]);
CHECK_EQ(2, output[1]); CHECK_EQ(2, output[1]);
CHECK_EQ(6, output[2]); CHECK_EQ(6, output[2]);
CHECK_EQ(-1, output[3]);
} }
@ -1055,12 +1059,12 @@ TEST(MacroAssemblerNativeRegisters) {
v8::V8::Initialize(); v8::V8::Initialize();
ContextInitializer initializer; ContextInitializer initializer;
ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::ASCII, 5); ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::ASCII, 6);
uc16 foo_chars[3] = {'f', 'o', 'o'}; uc16 foo_chars[3] = {'f', 'o', 'o'};
Vector<const uc16> foo(foo_chars, 3); 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 fail;
Label backtrack; Label backtrack;
m.WriteCurrentPositionToRegister(out1, 0); // Output: [0] m.WriteCurrentPositionToRegister(out1, 0); // Output: [0]
@ -1114,7 +1118,7 @@ TEST(MacroAssemblerNativeRegisters) {
m.GoTo(&loop3); m.GoTo(&loop3);
m.Bind(&exit_loop3); m.Bind(&exit_loop3);
m.PopCurrentPosition(); m.PopCurrentPosition();
m.WriteCurrentPositionToRegister(out5, 0); // [0,3,6,9,9] m.WriteCurrentPositionToRegister(out5, 0); // [0,3,6,9,9,-1]
m.Succeed(); m.Succeed();
@ -1132,15 +1136,15 @@ TEST(MacroAssemblerNativeRegisters) {
Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input); Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
Address start_adr = seq_input->GetCharsAddress(); Address start_adr = seq_input->GetCharsAddress();
int output[5]; int output[6];
NativeRegExpMacroAssembler::Result result = NativeRegExpMacroAssembler::Result result =
Execute(*code, Execute(*code,
*input, *input,
0, 0,
start_adr, start_adr,
start_adr + input->length(), start_adr + input->length(),
output, output,
true); true);
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result); CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
CHECK_EQ(0, output[0]); CHECK_EQ(0, output[0]);
@ -1148,6 +1152,7 @@ TEST(MacroAssemblerNativeRegisters) {
CHECK_EQ(6, output[2]); CHECK_EQ(6, output[2]);
CHECK_EQ(9, output[3]); CHECK_EQ(9, output[3]);
CHECK_EQ(9, output[4]); CHECK_EQ(9, output[4]);
CHECK_EQ(-1, output[5]);
} }

View File

@ -433,18 +433,14 @@
'../../src/ia32/jump-target-ia32.cc', '../../src/ia32/jump-target-ia32.cc',
'../../src/ia32/macro-assembler-ia32.cc', '../../src/ia32/macro-assembler-ia32.cc',
'../../src/ia32/macro-assembler-ia32.h', '../../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/register-allocator-ia32.cc',
'../../src/ia32/stub-cache-ia32.cc', '../../src/ia32/stub-cache-ia32.cc',
'../../src/ia32/virtual-frame-ia32.cc', '../../src/ia32/virtual-frame-ia32.cc',
'../../src/ia32/virtual-frame-ia32.h', '../../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"', { ['target_arch=="x64"', {
'include_dirs+': [ 'include_dirs+': [
'../../src/x64', '../../src/x64',
@ -466,18 +462,14 @@
'../../src/x64/jump-target-x64.cc', '../../src/x64/jump-target-x64.cc',
'../../src/x64/macro-assembler-x64.cc', '../../src/x64/macro-assembler-x64.cc',
'../../src/x64/macro-assembler-x64.h', '../../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/register-allocator-x64.cc',
'../../src/x64/stub-cache-x64.cc', '../../src/x64/stub-cache-x64.cc',
'../../src/x64/virtual-frame-x64.cc', '../../src/x64/virtual-frame-x64.cc',
'../../src/x64/virtual-frame-x64.h', '../../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"', { ['OS=="linux"', {
'link_settings': { 'link_settings': {
'libraries': [ 'libraries': [