Commit 429f3cf9 authored by sgjesse@chromium.org's avatar sgjesse@chromium.org

Direct call to native RegExp code from JavaScript.

Calls to RegExp no longer have to be via a call to the runtime system. A new stub have been added which can handle this call in generated code. The stub checks all the parameters and creates RegExp entry frame in the same way as it is created by the runtime system. Bailout to the runtime system is done whenever an uncommon situation is encountered or when the static data used is not initialized. After running the native RegExp code the last match info is updated like in the runtime system.

Currently only ASCII strings are handled.

Added another argument to the RegExp entry frame. It indicated whether the call is direct from JavaScript code or through the runtime system. This information is used when RegExp execution is interrupted. If an interruption happens when RegExp code is called directly a retry is issued causing the interruption to be handled via the runtime system. The reason for this is that the direct call to RegExp code does not support garbage collection.
Review URL: http://codereview.chromium.org/521028

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3542 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 8618b984
...@@ -3451,6 +3451,19 @@ void CodeGenerator::GenerateStringAdd(ZoneList<Expression*>* args) { ...@@ -3451,6 +3451,19 @@ void CodeGenerator::GenerateStringAdd(ZoneList<Expression*>* args) {
} }
void CodeGenerator::GenerateRegExpExec(ZoneList<Expression*>* args) {
ASSERT_EQ(4, args->length());
Load(args->at(0));
Load(args->at(1));
Load(args->at(2));
Load(args->at(3));
frame_->CallRuntime(Runtime::kRegExpExec, 4);
frame_->EmitPush(r0);
}
void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) {
VirtualFrame::SpilledScope spilled_scope; VirtualFrame::SpilledScope spilled_scope;
ASSERT(args->length() == 2); ASSERT(args->length() == 2);
......
...@@ -363,6 +363,9 @@ class CodeGenerator: public AstVisitor { ...@@ -363,6 +363,9 @@ class CodeGenerator: public AstVisitor {
// Fast support for StringAdd. // Fast support for StringAdd.
void GenerateStringAdd(ZoneList<Expression*>* args); void GenerateStringAdd(ZoneList<Expression*>* args);
// Support for direct calls from JavaScript to native RegExp code.
void GenerateRegExpExec(ZoneList<Expression*>* args);
// Simple condition analysis. // Simple condition analysis.
enum ConditionAnalysis { enum ConditionAnalysis {
ALWAYS_TRUE, ALWAYS_TRUE,
......
...@@ -59,15 +59,19 @@ namespace internal { ...@@ -59,15 +59,19 @@ namespace internal {
* *
* Each call to a public method should retain this convention. * Each call to a public method should retain this convention.
* The stack will have the following structure: * The stack will have the following structure:
* - direct_call (if 1, direct call from JavaScript code, if 0 call
* through the runtime system)
* - stack_area_base (High end of the memory area to use as * - stack_area_base (High end of the memory area to use as
* backtracking stack) * backtracking stack)
* - at_start (if 1, start at start of string, if 0, don't) * - at_start (if 1, we are starting at the start of the
* string, otherwise 0)
* - int* capture_array (int[num_saved_registers_], for output).
* --- sp when called --- * --- sp when called ---
* - link address * - link address
* - backup of registers r4..r11 * - backup of registers r4..r11
* - int* capture_array (int[num_saved_registers_], for output).
* - end of input (Address of end of string) * - end of input (Address of end of string)
* - start of input (Address of first character in string) * - start of input (Address of first character in string)
* - start index (character index of start)
* --- frame pointer ---- * --- frame pointer ----
* - void* input_string (location of a handle containing the string) * - void* input_string (location of a handle containing the string)
* - Offset of location before start of input (effectively character * - Offset of location before start of input (effectively character
...@@ -85,11 +89,13 @@ namespace internal { ...@@ -85,11 +89,13 @@ namespace internal {
* The data up to the return address must be placed there by the calling * The data up to the return address must be placed there by the calling
* code, by calling the code entry as cast to a function with the signature: * code, by calling the code entry as cast to a function with the signature:
* int (*match)(String* input_string, * int (*match)(String* input_string,
* int start_index,
* Address start, * Address start,
* Address end, * Address end,
* int* capture_output_array, * int* capture_output_array,
* bool at_start, * bool at_start,
* byte* stack_area_base) * byte* stack_area_base,
* bool direct_call)
* The call is performed by NativeRegExpMacroAssembler::Execute() * The call is performed by NativeRegExpMacroAssembler::Execute()
* (in regexp-macro-assembler.cc). * (in regexp-macro-assembler.cc).
*/ */
......
...@@ -127,6 +127,7 @@ class RegExpMacroAssemblerARM: public NativeRegExpMacroAssembler { ...@@ -127,6 +127,7 @@ class RegExpMacroAssemblerARM: public NativeRegExpMacroAssembler {
static const int kRegisterOutput = kReturnAddress + kPointerSize; static const int kRegisterOutput = kReturnAddress + kPointerSize;
static const int kAtStart = kRegisterOutput + kPointerSize; static const int kAtStart = kRegisterOutput + kPointerSize;
static const int kStackHighEnd = kAtStart + kPointerSize; static const int kStackHighEnd = kAtStart + kPointerSize;
static const int kDirectCall = kStackHighEnd + kPointerSize;
// Below the frame pointer. // Below the frame pointer.
// Register parameters stored by setup code. // Register parameters stored by setup code.
......
...@@ -62,9 +62,9 @@ class SimulatorStack : public v8::internal::AllStatic { ...@@ -62,9 +62,9 @@ class SimulatorStack : public v8::internal::AllStatic {
// Call the generated regexp code directly. The entry function pointer should // Call the generated regexp code directly. The entry function pointer should
// expect seven int/pointer sized arguments and return an int. // expect eight int/pointer sized arguments and return an int.
#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \ #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \
entry(p0, p1, p2, p3, p4, p5, p6) entry(p0, p1, p2, p3, p4, p5, p6, p7)
#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \ #define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
reinterpret_cast<TryCatch*>(try_catch_address) reinterpret_cast<TryCatch*>(try_catch_address)
...@@ -79,9 +79,9 @@ class SimulatorStack : public v8::internal::AllStatic { ...@@ -79,9 +79,9 @@ class SimulatorStack : public v8::internal::AllStatic {
assembler::arm::Simulator::current()->Call(FUNCTION_ADDR(entry), 5, \ assembler::arm::Simulator::current()->Call(FUNCTION_ADDR(entry), 5, \
p0, p1, p2, p3, p4)) p0, p1, p2, p3, p4))
#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \ #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \
assembler::arm::Simulator::current()->Call( \ assembler::arm::Simulator::current()->Call( \
FUNCTION_ADDR(entry), 7, p0, p1, p2, p3, p4, p5, p6) FUNCTION_ADDR(entry), 8, p0, p1, p2, p3, p4, p5, p6, p7)
#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \ #define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
try_catch_address == NULL ? \ try_catch_address == NULL ? \
......
...@@ -674,6 +674,19 @@ ExternalReference ExternalReference::re_case_insensitive_compare_uc16() { ...@@ -674,6 +674,19 @@ ExternalReference ExternalReference::re_case_insensitive_compare_uc16() {
FUNCTION_ADDR(NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16))); FUNCTION_ADDR(NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16)));
} }
ExternalReference ExternalReference::address_of_static_offsets_vector() {
return ExternalReference(OffsetsVector::static_offsets_vector_address());
}
ExternalReference ExternalReference::address_of_regexp_stack_memory_address() {
return ExternalReference(RegExpStack::memory_address());
}
ExternalReference ExternalReference::address_of_regexp_stack_memory_size() {
return ExternalReference(RegExpStack::memory_size_address());
}
#endif #endif
......
...@@ -420,6 +420,11 @@ class ExternalReference BASE_EMBEDDED { ...@@ -420,6 +420,11 @@ class ExternalReference BASE_EMBEDDED {
// Static variable RegExpStack::limit_address() // Static variable RegExpStack::limit_address()
static ExternalReference address_of_regexp_stack_limit(); static ExternalReference address_of_regexp_stack_limit();
// Static variables for RegExp.
static ExternalReference address_of_static_offsets_vector();
static ExternalReference address_of_regexp_stack_memory_address();
static ExternalReference address_of_regexp_stack_memory_size();
// Static variable Heap::NewSpaceStart() // Static variable Heap::NewSpaceStart()
static ExternalReference new_space_start(); static ExternalReference new_space_start();
static ExternalReference heap_always_allocate_scope_depth(); static ExternalReference heap_always_allocate_scope_depth();
......
...@@ -52,6 +52,7 @@ namespace internal { ...@@ -52,6 +52,7 @@ namespace internal {
V(Instanceof) \ V(Instanceof) \
V(CounterOp) \ V(CounterOp) \
V(ArgumentsAccess) \ V(ArgumentsAccess) \
V(RegExpExec) \
V(Runtime) \ V(Runtime) \
V(CEntry) \ V(CEntry) \
V(JSEntry) V(JSEntry)
......
...@@ -345,6 +345,7 @@ CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = { ...@@ -345,6 +345,7 @@ CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = {
{&CodeGenerator::GenerateIsObject, "_IsObject"}, {&CodeGenerator::GenerateIsObject, "_IsObject"},
{&CodeGenerator::GenerateIsFunction, "_IsFunction"}, {&CodeGenerator::GenerateIsFunction, "_IsFunction"},
{&CodeGenerator::GenerateStringAdd, "_StringAdd"}, {&CodeGenerator::GenerateStringAdd, "_StringAdd"},
{&CodeGenerator::GenerateRegExpExec, "_RegExpExec"},
}; };
......
...@@ -478,6 +478,26 @@ class ArgumentsAccessStub: public CodeStub { ...@@ -478,6 +478,26 @@ class ArgumentsAccessStub: public CodeStub {
}; };
class RegExpExecStub: public CodeStub {
public:
RegExpExecStub() { }
private:
Major MajorKey() { return RegExpExec; }
int MinorKey() { return 0; }
void Generate(MacroAssembler* masm);
const char* GetName() { return "RegExpExecStub"; }
#ifdef DEBUG
void Print() {
PrintF("RegExpExecStub\n");
}
#endif
};
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -231,6 +231,7 @@ DEFINE_bool(preemption, false, ...@@ -231,6 +231,7 @@ DEFINE_bool(preemption, false,
// Regexp // Regexp
DEFINE_bool(trace_regexps, false, "trace regexp execution") DEFINE_bool(trace_regexps, false, "trace regexp execution")
DEFINE_bool(regexp_optimization, true, "generate optimized regexp code") DEFINE_bool(regexp_optimization, true, "generate optimized regexp code")
DEFINE_bool(regexp_entry_native, true, "use native code to enter regexp")
// Testing flags test/cctest/test-{flags,api,serialization}.cc // Testing flags test/cctest/test-{flags,api,serialization}.cc
DEFINE_bool(testing_bool_flag, true, "testing_bool_flag") DEFINE_bool(testing_bool_flag, true, "testing_bool_flag")
......
This diff is collapsed.
...@@ -544,6 +544,9 @@ class CodeGenerator: public AstVisitor { ...@@ -544,6 +544,9 @@ class CodeGenerator: public AstVisitor {
// Fast support for StringAdd. // Fast support for StringAdd.
void GenerateStringAdd(ZoneList<Expression*>* args); void GenerateStringAdd(ZoneList<Expression*>* args);
// Support for direct calls from JavaScript to native RegExp code.
void GenerateRegExpExec(ZoneList<Expression*>* args);
// Simple condition analysis. // Simple condition analysis.
enum ConditionAnalysis { enum ConditionAnalysis {
ALWAYS_TRUE, ALWAYS_TRUE,
......
...@@ -325,6 +325,17 @@ void MacroAssembler::CmpInstanceType(Register map, InstanceType type) { ...@@ -325,6 +325,17 @@ void MacroAssembler::CmpInstanceType(Register map, InstanceType type) {
} }
Condition MacroAssembler::IsObjectStringType(Register heap_object,
Register map,
Register instance_type) {
mov(map, FieldOperand(heap_object, HeapObject::kMapOffset));
movzx_b(instance_type, FieldOperand(map, Map::kInstanceTypeOffset));
ASSERT(kNotStringTag != 0);
test(instance_type, Immediate(kIsNotStringMask));
return zero;
}
void MacroAssembler::FCmp() { void MacroAssembler::FCmp() {
if (CpuFeatures::IsSupported(CMOV)) { if (CpuFeatures::IsSupported(CMOV)) {
fucomip(); fucomip();
......
...@@ -141,6 +141,15 @@ class MacroAssembler: public Assembler { ...@@ -141,6 +141,15 @@ class MacroAssembler: public Assembler {
// Compare instance type for map. // Compare instance type for map.
void CmpInstanceType(Register map, InstanceType type); void CmpInstanceType(Register map, InstanceType type);
// Check if the object in register heap_object is a string. Afterwards the
// register map contains the object map and the register instance_type
// contains the instance_type. The registers map and instance_type can be the
// same in which case it contains the instance type afterwards. Either of the
// registers map and instance_type can be the same as heap_object.
Condition IsObjectStringType(Register heap_object,
Register map,
Register instance_type);
// FCmp is similar to integer cmp, but requires unsigned // FCmp is similar to integer cmp, but requires unsigned
// jcc instructions (je, ja, jae, jb, jbe, je, and jz). // jcc instructions (je, ja, jae, jb, jbe, je, and jz).
void FCmp(); void FCmp();
......
...@@ -55,13 +55,17 @@ namespace internal { ...@@ -55,13 +55,17 @@ namespace internal {
* *
* Each call to a public method should retain this convention. * Each call to a public method should retain this convention.
* The stack will have the following structure: * The stack will have the following structure:
* - stack_area_base (High end of the memory area to use as * - direct_call (if 1, direct call from JavaScript code, if 0
* backtracking stack) * call through the runtime system)
* - at_start (if 1, start at start of string, if 0, don't) * - stack_area_base (High end of the memory area to use as
* - int* capture_array (int[num_saved_registers_], for output). * backtracking stack)
* - end of input (Address of end of string) * - at_start (if 1, we are starting at the start of the
* - start of input (Address of first character in string) * string, otherwise 0)
* - void* input_string (location of a handle containing the string) * - int* capture_array (int[num_saved_registers_], for output).
* - end of input (Address of end of string)
* - start of input (Address of first character in string)
* - start index (character index of start)
* - String* input_string (location of a handle containing the string)
* --- frame alignment (if applicable) --- * --- frame alignment (if applicable) ---
* - return address * - return address
* ebp-> - old ebp * ebp-> - old ebp
...@@ -81,11 +85,13 @@ namespace internal { ...@@ -81,11 +85,13 @@ namespace internal {
* The data up to the return address must be placed there by the calling * The data up to the return address must be placed there by the calling
* code, by calling the code entry as cast to a function with the signature: * code, by calling the code entry as cast to a function with the signature:
* int (*match)(String* input_string, * int (*match)(String* input_string,
* int start_index,
* Address start, * Address start,
* Address end, * Address end,
* int* capture_output_array, * int* capture_output_array,
* bool at_start, * bool at_start,
* byte* stack_area_base) * byte* stack_area_base,
* bool direct_call)
*/ */
#define __ ACCESS_MASM(masm_) #define __ ACCESS_MASM(masm_)
...@@ -942,6 +948,12 @@ int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address, ...@@ -942,6 +948,12 @@ int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address,
// If not real stack overflow the stack guard was used to interrupt // If not real stack overflow the stack guard was used to interrupt
// execution for another purpose. // execution for another purpose.
// If this is a direct call from JavaScript retry the RegExp forcing the call
// through the runtime system. Currently the direct call cannot handle a GC.
if (frame_entry<int>(re_frame, kDirectCall) == 1) {
return RETRY;
}
// Prepare for possible GC. // Prepare for possible GC.
HandleScope handles; HandleScope handles;
Handle<Code> code_handle(re_code); Handle<Code> code_handle(re_code);
......
...@@ -128,6 +128,7 @@ class RegExpMacroAssemblerIA32: public NativeRegExpMacroAssembler { ...@@ -128,6 +128,7 @@ class RegExpMacroAssemblerIA32: public NativeRegExpMacroAssembler {
static const int kRegisterOutput = kInputEnd + kPointerSize; static const int kRegisterOutput = kInputEnd + kPointerSize;
static const int kAtStart = kRegisterOutput + kPointerSize; static const int kAtStart = kRegisterOutput + kPointerSize;
static const int kStackHighEnd = kAtStart + kPointerSize; static const int kStackHighEnd = kAtStart + kPointerSize;
static const int kDirectCall = kStackHighEnd + kPointerSize;
// Below the frame pointer - local stack variables. // Below the frame pointer - local stack variables.
// When adding local variables remember to push space for them in // When adding local variables remember to push space for them in
// the frame in GetCode. // the frame in GetCode.
......
...@@ -52,9 +52,9 @@ class SimulatorStack : public v8::internal::AllStatic { ...@@ -52,9 +52,9 @@ class SimulatorStack : public v8::internal::AllStatic {
}; };
// Call the generated regexp code directly. The entry function pointer should // Call the generated regexp code directly. The entry function pointer should
// expect seven int/pointer sized arguments and return an int. // expect eight int/pointer sized arguments and return an int.
#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \ #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \
entry(p0, p1, p2, p3, p4, p5, p6) entry(p0, p1, p2, p3, p4, p5, p6, p7)
#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \ #define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
reinterpret_cast<TryCatch*>(try_catch_address) reinterpret_cast<TryCatch*>(try_catch_address)
......
...@@ -112,37 +112,6 @@ static inline void ThrowRegExpException(Handle<JSRegExp> re, ...@@ -112,37 +112,6 @@ static inline void ThrowRegExpException(Handle<JSRegExp> re,
// Generic RegExp methods. Dispatches to implementation specific methods. // Generic RegExp methods. Dispatches to implementation specific methods.
class OffsetsVector {
public:
inline OffsetsVector(int num_registers)
: offsets_vector_length_(num_registers) {
if (offsets_vector_length_ > kStaticOffsetsVectorSize) {
vector_ = NewArray<int>(offsets_vector_length_);
} else {
vector_ = static_offsets_vector_;
}
}
inline ~OffsetsVector() {
if (offsets_vector_length_ > kStaticOffsetsVectorSize) {
DeleteArray(vector_);
vector_ = NULL;
}
}
inline int* vector() { return vector_; }
inline int length() { return offsets_vector_length_; }
private:
int* vector_;
int offsets_vector_length_;
static const int kStaticOffsetsVectorSize = 50;
static int static_offsets_vector_[kStaticOffsetsVectorSize];
};
int OffsetsVector::static_offsets_vector_[
OffsetsVector::kStaticOffsetsVectorSize];
Handle<Object> RegExpImpl::Compile(Handle<JSRegExp> re, Handle<Object> RegExpImpl::Compile(Handle<JSRegExp> re,
Handle<String> pattern, Handle<String> pattern,
Handle<String> flag_str) { Handle<String> flag_str) {
...@@ -448,6 +417,14 @@ Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> jsregexp, ...@@ -448,6 +417,14 @@ Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> jsregexp,
ASSERT(array->length() >= number_of_capture_registers + kLastMatchOverhead); ASSERT(array->length() >= number_of_capture_registers + kLastMatchOverhead);
// The captures come in (start, end+1) pairs. // The captures come in (start, end+1) pairs.
for (int i = 0; i < number_of_capture_registers; i += 2) { for (int i = 0; i < number_of_capture_registers; i += 2) {
// Capture values are relative to start_offset only.
// Convert them to be relative to start of string.
if (captures_vector[i] >= 0) {
captures_vector[i] += previous_index;
}
if (captures_vector[i + 1] >= 0) {
captures_vector[i + 1] += previous_index;
}
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]);
} }
...@@ -4606,4 +4583,8 @@ RegExpEngine::CompilationResult RegExpEngine::Compile(RegExpCompileData* data, ...@@ -4606,4 +4583,8 @@ RegExpEngine::CompilationResult RegExpEngine::Compile(RegExpCompileData* data,
pattern); pattern);
} }
int OffsetsVector::static_offsets_vector_[
OffsetsVector::kStaticOffsetsVectorSize];
}} // namespace v8::internal }} // namespace v8::internal
...@@ -101,13 +101,23 @@ class RegExpImpl { ...@@ -101,13 +101,23 @@ class RegExpImpl {
int index, int index,
Handle<JSArray> lastMatchInfo); Handle<JSArray> lastMatchInfo);
// Offsets in the lastMatchInfo array. // Array index in the lastMatchInfo array.
static const int kLastCaptureCount = 0; static const int kLastCaptureCount = 0;
static const int kLastSubject = 1; static const int kLastSubject = 1;
static const int kLastInput = 2; static const int kLastInput = 2;
static const int kFirstCapture = 3; static const int kFirstCapture = 3;
static const int kLastMatchOverhead = 3; static const int kLastMatchOverhead = 3;
// Direct offset into the lastMatchInfo array.
static const int kLastCaptureCountOffset =
FixedArray::kHeaderSize + kLastCaptureCount * kPointerSize;
static const int kLastSubjectOffset =
FixedArray::kHeaderSize + kLastSubject * kPointerSize;
static const int kLastInputOffset =
FixedArray::kHeaderSize + kLastInput * kPointerSize;
static const int kFirstCaptureOffset =
FixedArray::kHeaderSize + kFirstCapture * kPointerSize;
// Used to access the lastMatchInfo array. // Used to access the lastMatchInfo array.
static int GetCapture(FixedArray* array, int index) { static int GetCapture(FixedArray* array, int index) {
return Smi::cast(array->get(index + kFirstCapture))->value(); return Smi::cast(array->get(index + kFirstCapture))->value();
...@@ -1276,6 +1286,40 @@ class RegExpEngine: public AllStatic { ...@@ -1276,6 +1286,40 @@ class RegExpEngine: public AllStatic {
}; };
class OffsetsVector {
public:
inline OffsetsVector(int num_registers)
: offsets_vector_length_(num_registers) {
if (offsets_vector_length_ > kStaticOffsetsVectorSize) {
vector_ = NewArray<int>(offsets_vector_length_);
} else {
vector_ = static_offsets_vector_;
}
}
inline ~OffsetsVector() {
if (offsets_vector_length_ > kStaticOffsetsVectorSize) {
DeleteArray(vector_);
vector_ = NULL;
}
}
inline int* vector() { return vector_; }
inline int length() { return offsets_vector_length_; }
static const int kStaticOffsetsVectorSize = 50;
private:
static Address static_offsets_vector_address() {
return reinterpret_cast<Address>(&static_offsets_vector_);
}
int* vector_;
int offsets_vector_length_;
static int static_offsets_vector_[kStaticOffsetsVectorSize];
friend class ExternalReference;
};
} } // namespace v8::internal } } // namespace v8::internal
#endif // V8_JSREGEXP_H_ #endif // V8_JSREGEXP_H_
...@@ -3603,6 +3603,14 @@ class JSRegExp: public JSObject { ...@@ -3603,6 +3603,14 @@ class JSRegExp: public JSObject {
static const int kIrregexpCaptureCountIndex = kDataIndex + 3; static const int kIrregexpCaptureCountIndex = kDataIndex + 3;
static const int kIrregexpDataSize = kIrregexpCaptureCountIndex + 1; static const int kIrregexpDataSize = kIrregexpCaptureCountIndex + 1;
// Offsets directly into the data fixed array.
static const int kDataTagOffset =
FixedArray::kHeaderSize + kTagIndex * kPointerSize;
static const int kDataAsciiCodeOffset =
FixedArray::kHeaderSize + kIrregexpASCIICodeIndex * kPointerSize;
static const int kIrregexpCaptureCountOffset =
FixedArray::kHeaderSize + kIrregexpCaptureCountIndex * kPointerSize;
}; };
......
...@@ -136,7 +136,7 @@ function CompileRegExp(pattern, flags) { ...@@ -136,7 +136,7 @@ function CompileRegExp(pattern, flags) {
function DoRegExpExec(regexp, string, index) { function DoRegExpExec(regexp, string, index) {
return %RegExpExec(regexp, string, index, lastMatchInfo); return %_RegExpExec(regexp, string, index, lastMatchInfo);
} }
...@@ -164,7 +164,7 @@ function RegExpExec(string) { ...@@ -164,7 +164,7 @@ function RegExpExec(string) {
%_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]); %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]);
// matchIndices is either null or the lastMatchInfo array. // matchIndices is either null or the lastMatchInfo array.
var matchIndices = %RegExpExec(this, s, i, lastMatchInfo); var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo);
if (matchIndices == null) { if (matchIndices == null) {
if (this.global) this.lastIndex = 0; if (this.global) this.lastIndex = 0;
...@@ -221,7 +221,7 @@ function RegExpTest(string) { ...@@ -221,7 +221,7 @@ function RegExpTest(string) {
%_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]); %_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, s, lastIndex]);
// matchIndices is either null or the lastMatchInfo array. // matchIndices is either null or the lastMatchInfo array.
var matchIndices = %RegExpExec(this, s, i, lastMatchInfo); var matchIndices = %_RegExpExec(this, s, i, lastMatchInfo);
if (matchIndices == null) { if (matchIndices == null) {
if (this.global) this.lastIndex = 0; if (this.global) this.lastIndex = 0;
......
...@@ -143,17 +143,6 @@ NativeRegExpMacroAssembler::Result NativeRegExpMacroAssembler::Match( ...@@ -143,17 +143,6 @@ NativeRegExpMacroAssembler::Result NativeRegExpMacroAssembler::Match(
input_end, input_end,
offsets_vector, offsets_vector,
previous_index == 0); previous_index == 0);
if (res == SUCCESS) {
// Capture values are relative to start_offset only.
// Convert them to be relative to start of string.
for (int i = 0; i < offsets_vector_length; i++) {
if (offsets_vector[i] >= 0) {
offsets_vector[i] += previous_index;
}
}
}
return res; return res;
} }
...@@ -167,7 +156,7 @@ NativeRegExpMacroAssembler::Result NativeRegExpMacroAssembler::Execute( ...@@ -167,7 +156,7 @@ NativeRegExpMacroAssembler::Result NativeRegExpMacroAssembler::Execute(
int* output, int* output,
bool at_start) { bool at_start) {
typedef int (*matcher)(String*, int, const byte*, typedef int (*matcher)(String*, int, const byte*,
const byte*, int*, int, Address); const byte*, int*, int, Address, int);
matcher matcher_func = FUNCTION_CAST<matcher>(code->entry()); matcher matcher_func = FUNCTION_CAST<matcher>(code->entry());
int at_start_val = at_start ? 1 : 0; int at_start_val = at_start ? 1 : 0;
...@@ -176,6 +165,7 @@ NativeRegExpMacroAssembler::Result NativeRegExpMacroAssembler::Execute( ...@@ -176,6 +165,7 @@ NativeRegExpMacroAssembler::Result NativeRegExpMacroAssembler::Execute(
RegExpStack stack; RegExpStack stack;
Address stack_base = RegExpStack::stack_base(); Address stack_base = RegExpStack::stack_base();
int direct_call = 0;
int result = CALL_GENERATED_REGEXP_CODE(matcher_func, int result = CALL_GENERATED_REGEXP_CODE(matcher_func,
input, input,
start_offset, start_offset,
...@@ -183,7 +173,8 @@ NativeRegExpMacroAssembler::Result NativeRegExpMacroAssembler::Execute( ...@@ -183,7 +173,8 @@ NativeRegExpMacroAssembler::Result NativeRegExpMacroAssembler::Execute(
input_end, input_end,
output, output,
at_start_val, at_start_val,
stack_base); stack_base,
direct_call);
ASSERT(result <= SUCCESS); ASSERT(result <= SUCCESS);
ASSERT(result >= RETRY); ASSERT(result >= RETRY);
......
...@@ -98,12 +98,24 @@ class RegExpStack { ...@@ -98,12 +98,24 @@ class RegExpStack {
void Free(); void Free();
}; };
// Address of allocated memory.
static Address memory_address() {
return reinterpret_cast<Address>(&thread_local_.memory_);
}
// Address of size of allocated memory.
static Address memory_size_address() {
return reinterpret_cast<Address>(&thread_local_.memory_size_);
}
// Resets the buffer if it has grown beyond the default/minimum size. // Resets the buffer if it has grown beyond the default/minimum size.
// After this, the buffer is either the default size, or it is empty, so // After this, the buffer is either the default size, or it is empty, so
// you have to call EnsureCapacity before using it again. // you have to call EnsureCapacity before using it again.
static void Reset(); static void Reset();
static ThreadLocal thread_local_; static ThreadLocal thread_local_;
friend class ExternalReference;
}; };
}} // namespace v8::internal }} // namespace v8::internal
......
...@@ -153,7 +153,9 @@ namespace internal { ...@@ -153,7 +153,9 @@ namespace internal {
SC(generic_binary_stub_calls, V8.GenericBinaryStubCalls) \ SC(generic_binary_stub_calls, V8.GenericBinaryStubCalls) \
SC(generic_binary_stub_calls_regs, V8.GenericBinaryStubCallsRegs) \ SC(generic_binary_stub_calls_regs, V8.GenericBinaryStubCallsRegs) \
SC(string_add_runtime, V8.StringAddRuntime) \ SC(string_add_runtime, V8.StringAddRuntime) \
SC(string_add_native, V8.StringAddNative) SC(string_add_native, V8.StringAddNative) \
SC(regexp_entry_runtime, V8.RegExpEntryRuntime) \
SC(regexp_entry_native, V8.RegExpEntryNative)
// This file contains all the v8 counters that are in use. // This file contains all the v8 counters that are in use.
class Counters : AllStatic { class Counters : AllStatic {
......
...@@ -3876,6 +3876,19 @@ void CodeGenerator::GenerateRandomPositiveSmi(ZoneList<Expression*>* args) { ...@@ -3876,6 +3876,19 @@ void CodeGenerator::GenerateRandomPositiveSmi(ZoneList<Expression*>* args) {
} }
void CodeGenerator::GenerateRegExpExec(ZoneList<Expression*>* args) {
ASSERT_EQ(args->length(), 4);
// Load the arguments on the stack and call the runtime system.
Load(args->at(0));
Load(args->at(1));
Load(args->at(2));
Load(args->at(3));
Result result = frame_->CallRuntime(Runtime::kRegExpExec, 4);
frame_->Push(&result);
}
void CodeGenerator::GenerateStringAdd(ZoneList<Expression*>* args) { void CodeGenerator::GenerateStringAdd(ZoneList<Expression*>* args) {
ASSERT_EQ(2, args->length()); ASSERT_EQ(2, args->length());
......
...@@ -541,6 +541,9 @@ class CodeGenerator: public AstVisitor { ...@@ -541,6 +541,9 @@ class CodeGenerator: public AstVisitor {
// Fast support for StringAdd. // Fast support for StringAdd.
void GenerateStringAdd(ZoneList<Expression*>* args); void GenerateStringAdd(ZoneList<Expression*>* args);
// Support for direct calls from JavaScript to native RegExp code.
void GenerateRegExpExec(ZoneList<Expression*>* args);
// Simple condition analysis. // Simple condition analysis.
enum ConditionAnalysis { enum ConditionAnalysis {
ALWAYS_TRUE, ALWAYS_TRUE,
......
...@@ -67,13 +67,17 @@ namespace internal { ...@@ -67,13 +67,17 @@ namespace internal {
* *
* The stack will have the following content, in some order, indexable from the * The stack will have the following content, in some order, indexable from the
* frame pointer (see, e.g., kStackHighEnd): * frame pointer (see, e.g., kStackHighEnd):
* - stack_area_base (High end of the memory area to use as * - direct_call (if 1, direct call from JavaScript code, if 0 call
* backtracking stack) * through the runtime system)
* - at_start (if 1, start at start of string, if 0, don't) * - stack_area_base (High end of the memory area to use as
* - int* capture_array (int[num_saved_registers_], for output). * backtracking stack)
* - end of input (Address of end of string) * - at_start (if 1, we are starting at the start of the
* - start of input (Address of first character in string) * string, otherwise 0)
* - String** input_string (location of a handle containing the string) * - int* capture_array (int[num_saved_registers_], for output).
* - end of input (Address of end of string)
* - start of input (Address of first character in string)
* - start index (character index of start)
* - String* input_string (input string)
* - return address * - return address
* - backup of callee save registers (rbx, possibly rsi and rdi). * - backup of callee save registers (rbx, possibly rsi and rdi).
* - Offset of location before start of input (effectively character * - Offset of location before start of input (effectively character
...@@ -90,11 +94,13 @@ namespace internal { ...@@ -90,11 +94,13 @@ namespace internal {
* calling the code's entry address cast to a function pointer with the * calling the code's entry address cast to a function pointer with the
* following signature: * following signature:
* int (*match)(String* input_string, * int (*match)(String* input_string,
* int start_index,
* Address start, * Address start,
* Address end, * Address end,
* int* capture_output_array, * int* capture_output_array,
* bool at_start, * bool at_start,
* byte* stack_area_base) * byte* stack_area_base,
* bool direct_call)
*/ */
#define __ ACCESS_MASM(masm_) #define __ ACCESS_MASM(masm_)
......
...@@ -143,6 +143,8 @@ class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler { ...@@ -143,6 +143,8 @@ class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler {
// AtStart is passed as 32 bit int (values 0 or 1). // AtStart is passed as 32 bit int (values 0 or 1).
static const int kAtStart = kRegisterOutput + kPointerSize; static const int kAtStart = kRegisterOutput + kPointerSize;
static const int kStackHighEnd = kAtStart + kPointerSize; static const int kStackHighEnd = kAtStart + kPointerSize;
// DirectCall is passed as 32 bit int (values 0 or 1).
static const int kDirectCall = kStackHighEnd + kPointerSize;
#else #else
// In AMD64 ABI Calling Convention, the first six integer parameters // In AMD64 ABI Calling Convention, the first six integer parameters
// are passed as registers, and caller must allocate space on the stack // are passed as registers, and caller must allocate space on the stack
...@@ -154,6 +156,7 @@ class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler { ...@@ -154,6 +156,7 @@ class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler {
static const int kRegisterOutput = kInputEnd - kPointerSize; static const int kRegisterOutput = kInputEnd - kPointerSize;
static const int kAtStart = kRegisterOutput - kPointerSize; static const int kAtStart = kRegisterOutput - kPointerSize;
static const int kStackHighEnd = kFrameAlign; static const int kStackHighEnd = kFrameAlign;
static const int kDirectCall = kStackHighEnd + kPointerSize;
#endif #endif
#ifdef _WIN64 #ifdef _WIN64
......
...@@ -53,9 +53,9 @@ class SimulatorStack : public v8::internal::AllStatic { ...@@ -53,9 +53,9 @@ class SimulatorStack : public v8::internal::AllStatic {
}; };
// Call the generated regexp code directly. The entry function pointer should // Call the generated regexp code directly. The entry function pointer should
// expect seven int/pointer sized arguments and return an int. // expect eight int/pointer sized arguments and return an int.
#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \ #define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7) \
entry(p0, p1, p2, p3, p4, p5, p6) entry(p0, p1, p2, p3, p4, p5, p6, p7)
#define TRY_CATCH_FROM_ADDRESS(try_catch_address) \ #define TRY_CATCH_FROM_ADDRESS(try_catch_address) \
reinterpret_cast<TryCatch*>(try_catch_address) reinterpret_cast<TryCatch*>(try_catch_address)
......
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