Commit 9230ad29 authored by lrn@chromium.org's avatar lrn@chromium.org

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
parent fcf8293d
......@@ -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";
switch (cond) {
case eq: c = "eq"; break;
case ne: c = "ne"; break;
case hs: c = "hs"; break;
case lo: c = "lo"; break;
case mi: c = "mi"; break;
case pl: c = "pl"; break;
case vs: c = "vs"; break;
case vc: c = "vc"; break;
case hi: c = "hi"; break;
case ls: c = "ls"; break;
case ge: c = "ge"; break;
case lt: c = "lt"; break;
case gt: c = "gt"; break;
case le: c = "le"; break;
case al: c = ""; break;
default:
c = "";
UNREACHABLE();
ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx
int cond = instr & CondMask;
const char* b;
const char* c;
if (cond == nv) {
b = "blx";
c = "";
} else {
if ((instr & B24) != 0)
b = "bl";
else
b = "b";
switch (cond) {
case eq: c = "eq"; break;
case ne: c = "ne"; break;
case hs: c = "hs"; break;
case lo: c = "lo"; break;
case mi: c = "mi"; break;
case pl: c = "pl"; break;
case vs: c = "vs"; break;
case vc: c = "vc"; break;
case hi: c = "hi"; break;
case ls: c = "ls"; break;
case ge: c = "ge"; break;
case lt: c = "lt"; break;
case gt: c = "gt"; break;
case le: c = "le"; break;
case al: c = ""; break;
default:
c = "";
UNREACHABLE();
}
}
PrintF("%s%s\n", b, c);
}
PrintF("%s%s\n", b, c);
next(&l);
}
} else {
......@@ -670,8 +685,23 @@ int Assembler::branch_offset(Label* L, bool jump_elimination_allowed) {
// Block the emission of the constant pool, since the branch instruction must
// be emitted at the pc offset recorded by the label
BlockConstPoolBefore(pc_offset() + kInstrSize);
return target_pos - (pc_offset() + kPcLoadDelta);
}
return target_pos - pc_offset() - 8;
void Assembler::label_at_put(Label* L, int at_offset) {
int target_pos;
if (L->is_bound()) {
target_pos = L->pos();
} else {
if (L->is_linked()) {
target_pos = L->pos(); // L's link
} else {
target_pos = kEndOfChain;
}
L->link_to(at_offset);
instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag));
}
}
......
......@@ -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()) {
......
This diff is collapsed.
This diff is collapsed.
......@@ -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
......
......@@ -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
}
......
......@@ -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': [
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment