X64: Implement RegExp natively.

Review URL: http://codereview.chromium.org/165443


git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2688 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
lrn@chromium.org 2009-08-14 11:24:32 +00:00
parent 7b05678316
commit 4254388c14
22 changed files with 2299 additions and 821 deletions

View File

@ -101,6 +101,9 @@ LIBRARY_FLAGS = {
'regexp:native': {
'arch:ia32' : {
'CPPDEFINES': ['V8_NATIVE_REGEXP']
},
'arch:x64' : {
'CPPDEFINES': ['V8_NATIVE_REGEXP']
}
}
},
@ -716,7 +719,11 @@ class BuildContext(object):
result = []
result += source.get('all', [])
for (name, value) in self.options.iteritems():
result += source.get(name + ':' + value, [])
source_value = source.get(name + ':' + value, [])
if type(source_value) == dict:
result += self.GetRelevantSources(source_value)
else:
result += source_value
return sorted(result)
def AppendFlags(self, options, added):

View File

@ -63,24 +63,32 @@ SOURCES = {
'arm/register-allocator-arm.cc', 'arm/stub-cache-arm.cc',
'arm/virtual-frame-arm.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'
],
'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'
]
},
'simulator:arm': ['arm/simulator-arm.cc'],
'os:freebsd': ['platform-freebsd.cc', 'platform-posix.cc'],
'os:linux': ['platform-linux.cc', 'platform-posix.cc'],

View File

@ -82,8 +82,8 @@ static void RecordWriteHelper(MacroAssembler* masm,
// page_start + kObjectStartOffset + objectSize
// where objectSize is FixedArray::kHeaderSize + kPointerSize * array_length.
// Add the delta between the end of the normal RSet and the start of the
// extra RSet to 'object', so that addressing the bit using 'pointer_offset'
// hits the extra RSet words.
// extra RSet to 'page_start', so that addressing the bit using
// 'pointer_offset' hits the extra RSet words.
masm->lea(page_start,
Operand(page_start, array_length, times_pointer_size,
Page::kObjectStartOffset + FixedArray::kHeaderSize

View File

@ -54,7 +54,7 @@ namespace internal {
*
* Each call to a public method should retain this convention.
* The stack will have the following structure:
* - stack_area_top (High end of the memory area to use as
* - stack_area_base (High end of the memory area to use as
* backtracking stack)
* - at_start (if 1, start at start of string, if 0, don't)
* - int* capture_array (int[num_saved_registers_], for output).
@ -78,13 +78,13 @@ namespace internal {
* character of the string). The remaining registers starts out as garbage.
*
* The data up to the return address must be placed there by the calling
* code, e.g., by calling the code entry as cast to:
* code, by calling the code entry as cast to a function with the signature:
* int (*match)(String* input_string,
* Address start,
* Address end,
* int* capture_output_array,
* bool at_start,
* byte* stack_area_top)
* byte* stack_area_base)
*/
#define __ ACCESS_MASM(masm_)
@ -93,7 +93,6 @@ RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32(
Mode mode,
int registers_to_save)
: masm_(new MacroAssembler(NULL, kRegExpCodeSize)),
constants_(kRegExpConstantsSize),
mode_(mode),
num_registers_(registers_to_save),
num_saved_registers_(registers_to_save),
@ -156,13 +155,6 @@ void RegExpMacroAssemblerIA32::Bind(Label* label) {
}
void RegExpMacroAssemblerIA32::CheckBitmap(uc16 start,
Label* bitmap,
Label* on_zero) {
UNIMPLEMENTED();
}
void RegExpMacroAssemblerIA32::CheckCharacter(uint32_t c, Label* on_equal) {
__ cmp(current_character(), c);
BranchOrBacktrack(equal, on_equal);
@ -217,15 +209,9 @@ void RegExpMacroAssemblerIA32::CheckCharacters(Vector<const uc16> str,
BranchOrBacktrack(greater, on_failure);
}
Label backtrack;
if (on_failure == NULL) {
// Avoid inlining the Backtrack macro for each test.
Label skip_backtrack;
__ jmp(&skip_backtrack);
__ bind(&backtrack);
Backtrack();
__ bind(&skip_backtrack);
on_failure = &backtrack;
// Instead of inlining a backtrack, (re)use the global backtrack target.
on_failure = &backtrack_label_;
}
for (int i = 0; i < str.length(); i++) {
@ -581,34 +567,6 @@ bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(uc16 type,
}
}
void RegExpMacroAssemblerIA32::DispatchHalfNibbleMap(
uc16 start,
Label* half_nibble_map,
const Vector<Label*>& destinations) {
UNIMPLEMENTED();
}
void RegExpMacroAssemblerIA32::DispatchByteMap(
uc16 start,
Label* byte_map,
const Vector<Label*>& destinations) {
UNIMPLEMENTED();
}
void RegExpMacroAssemblerIA32::DispatchHighByteMap(
byte start,
Label* byte_map,
const Vector<Label*>& destinations) {
UNIMPLEMENTED();
}
void RegExpMacroAssemblerIA32::EmitOrLink(Label* label) {
UNIMPLEMENTED(); // Has no use.
}
void RegExpMacroAssemblerIA32::Fail() {
ASSERT(FAILURE == 0); // Return value for failure is zero.
@ -668,17 +626,17 @@ Handle<Object> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
__ mov(edi, Operand(ebp, kInputStart));
// Set up edi to be negative offset from string end.
__ sub(edi, Operand(esi));
if (num_saved_registers_ > 0) {
// Set eax to address of char before start of input
// (effectively string position -1).
__ lea(eax, Operand(edi, -char_size()));
// Store this value in a local variable, for use when clearing
// position registers.
__ mov(Operand(ebp, kInputStartMinusOne), eax);
if (num_saved_registers_ > 0) { // Always is, if generated from a regexp.
// Fill saved registers with initial value = start offset - 1
// Fill in stack push order, to avoid accessing across an unwritten
// page (a problem on Windows).
__ mov(ecx, kRegisterZero);
// Set eax to address of char before start of input
// (effectively string position -1).
__ lea(eax, Operand(edi, -char_size()));
// Store this value in a local variable, for use when clearing
// position registers.
__ mov(Operand(ebp, kInputStartMinusOne), eax);
Label init_loop;
__ bind(&init_loop);
__ mov(Operand(ebp, ecx, times_1, +0), eax);
@ -942,139 +900,8 @@ void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) {
}
RegExpMacroAssemblerIA32::Result RegExpMacroAssemblerIA32::Match(
Handle<Code> regexp_code,
Handle<String> subject,
int* offsets_vector,
int offsets_vector_length,
int previous_index) {
ASSERT(subject->IsFlat());
ASSERT(previous_index >= 0);
ASSERT(previous_index <= subject->length());
// No allocations before calling the regexp, but we can't use
// AssertNoAllocation, since regexps might be preempted, and another thread
// might do allocation anyway.
String* subject_ptr = *subject;
// Character offsets into string.
int start_offset = previous_index;
int end_offset = subject_ptr->length();
bool is_ascii = subject->IsAsciiRepresentation();
if (StringShape(subject_ptr).IsCons()) {
subject_ptr = ConsString::cast(subject_ptr)->first();
} else if (StringShape(subject_ptr).IsSliced()) {
SlicedString* slice = SlicedString::cast(subject_ptr);
start_offset += slice->start();
end_offset += slice->start();
subject_ptr = slice->buffer();
}
// Ensure that an underlying string has the same ascii-ness.
ASSERT(subject_ptr->IsAsciiRepresentation() == is_ascii);
ASSERT(subject_ptr->IsExternalString() || subject_ptr->IsSeqString());
// String is now either Sequential or External
int char_size_shift = is_ascii ? 0 : 1;
int char_length = end_offset - start_offset;
const byte* input_start =
StringCharacterPosition(subject_ptr, start_offset);
int byte_length = char_length << char_size_shift;
const byte* input_end = input_start + byte_length;
RegExpMacroAssemblerIA32::Result res = Execute(*regexp_code,
subject_ptr,
start_offset,
input_start,
input_end,
offsets_vector,
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;
}
// Private methods:
static unibrow::Mapping<unibrow::Ecma262Canonicalize> canonicalize;
RegExpMacroAssemblerIA32::Result RegExpMacroAssemblerIA32::Execute(
Code* code,
String* input,
int start_offset,
const byte* input_start,
const byte* input_end,
int* output,
bool at_start) {
typedef int (*matcher)(String*, int, const byte*,
const byte*, int*, int, Address);
matcher matcher_func = FUNCTION_CAST<matcher>(code->entry());
int at_start_val = at_start ? 1 : 0;
// Ensure that the minimum stack has been allocated.
RegExpStack stack;
Address stack_top = RegExpStack::stack_top();
int result = matcher_func(input,
start_offset,
input_start,
input_end,
output,
at_start_val,
stack_top);
ASSERT(result <= SUCCESS);
ASSERT(result >= RETRY);
if (result == EXCEPTION && !Top::has_pending_exception()) {
// We detected a stack overflow (on the backtrack stack) in RegExp code,
// but haven't created the exception yet.
Top::StackOverflow();
}
return static_cast<Result>(result);
}
int RegExpMacroAssemblerIA32::CaseInsensitiveCompareUC16(Address byte_offset1,
Address byte_offset2,
size_t byte_length) {
// This function is not allowed to cause a garbage collection.
// A GC might move the calling generated code and invalidate the
// return address on the stack.
ASSERT(byte_length % 2 == 0);
uc16* substring1 = reinterpret_cast<uc16*>(byte_offset1);
uc16* substring2 = reinterpret_cast<uc16*>(byte_offset2);
size_t length = byte_length >> 1;
for (size_t i = 0; i < length; i++) {
unibrow::uchar c1 = substring1[i];
unibrow::uchar c2 = substring2[i];
if (c1 != c2) {
unibrow::uchar s1[1] = { c1 };
canonicalize.get(c1, '\0', s1);
if (s1[0] != c2) {
unibrow::uchar s2[1] = { c2 };
canonicalize.get(c2, '\0', s2);
if (s1[0] != s2[0]) {
return 0;
}
}
}
}
return 1;
}
void RegExpMacroAssemblerIA32::CallCheckStackGuardState(Register scratch) {
int num_arguments = 3;
FrameAlign(num_arguments, scratch);
@ -1096,35 +923,6 @@ static T& frame_entry(Address re_frame, int frame_offset) {
}
const byte* RegExpMacroAssemblerIA32::StringCharacterPosition(String* subject,
int start_index) {
// Not just flat, but ultra flat.
ASSERT(subject->IsExternalString() || subject->IsSeqString());
ASSERT(start_index >= 0);
ASSERT(start_index <= subject->length());
if (subject->IsAsciiRepresentation()) {
const byte* address;
if (StringShape(subject).IsExternal()) {
const char* data = ExternalAsciiString::cast(subject)->resource()->data();
address = reinterpret_cast<const byte*>(data);
} else {
ASSERT(subject->IsSeqAsciiString());
char* data = SeqAsciiString::cast(subject)->GetChars();
address = reinterpret_cast<const byte*>(data);
}
return address + start_index;
}
const uc16* data;
if (StringShape(subject).IsExternal()) {
data = ExternalTwoByteString::cast(subject)->resource()->data();
} else {
ASSERT(subject->IsSeqTwoByteString());
data = SeqTwoByteString::cast(subject)->GetChars();
}
return reinterpret_cast<const byte*>(data + start_index);
}
int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address,
Code* re_code,
Address re_frame) {
@ -1198,18 +996,18 @@ int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address,
Address RegExpMacroAssemblerIA32::GrowStack(Address stack_pointer,
Address* stack_top) {
Address* stack_base) {
size_t size = RegExpStack::stack_capacity();
Address old_stack_top = RegExpStack::stack_top();
ASSERT(old_stack_top == *stack_top);
ASSERT(stack_pointer <= old_stack_top);
ASSERT(static_cast<size_t>(old_stack_top - stack_pointer) <= size);
Address new_stack_top = RegExpStack::EnsureCapacity(size * 2);
if (new_stack_top == NULL) {
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_top = new_stack_top;
return new_stack_top - (old_stack_top - stack_pointer);
*stack_base = new_stack_base;
return new_stack_base - (old_stack_base - stack_pointer);
}
@ -1373,11 +1171,5 @@ void RegExpMacroAssemblerIA32::LoadCurrentCharacterUnchecked(int cp_offset,
}
void RegExpMacroAssemblerIA32::LoadConstantBufferAddress(Register reg,
ArraySlice* buffer) {
__ mov(reg, buffer->array());
__ add(Operand(reg), Immediate(buffer->base_offset()));
}
#undef __
}} // namespace v8::internal

View File

@ -31,21 +31,8 @@
namespace v8 {
namespace internal {
class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
class RegExpMacroAssemblerIA32: public NativeRegExpMacroAssembler {
public:
// Type of input string to generate code for.
enum Mode { ASCII = 1, UC16 = 2 };
// Result of calling the generated RegExp code:
// RETRY: Something significant changed during execution, and the matching
// should be retried from scratch.
// EXCEPTION: Something failed during execution. If no exception has been
// thrown, it's an internal out-of-memory, and the caller should
// throw the exception.
// FAILURE: Matching failed.
// SUCCESS: Matching succeeded, and the output array has been filled with
// capture positions.
enum Result { RETRY = -2, EXCEPTION = -1, FAILURE = 0, SUCCESS = 1 };
RegExpMacroAssemblerIA32(Mode mode, int registers_to_save);
virtual ~RegExpMacroAssemblerIA32();
virtual int stack_limit_slack();
@ -54,7 +41,6 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
virtual void Backtrack();
virtual void Bind(Label* label);
virtual void CheckAtStart(Label* on_at_start);
virtual void CheckBitmap(uc16 start, Label* bitmap, Label* on_zero);
virtual void CheckCharacter(uint32_t c, Label* on_equal);
virtual void CheckCharacterAfterAnd(uint32_t c,
uint32_t mask,
@ -88,16 +74,6 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
int cp_offset,
bool check_offset,
Label* on_no_match);
virtual void DispatchByteMap(uc16 start,
Label* byte_map,
const Vector<Label*>& destinations);
virtual void DispatchHalfNibbleMap(uc16 start,
Label* half_nibble_map,
const Vector<Label*>& destinations);
virtual void DispatchHighByteMap(byte start,
Label* byte_map,
const Vector<Label*>& destinations);
virtual void EmitOrLink(Label* label);
virtual void Fail();
virtual Handle<Object> GetCode(Handle<String> source);
virtual void GoTo(Label* label);
@ -123,20 +99,6 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
virtual void ClearRegisters(int reg_from, int reg_to);
virtual void WriteStackPointerToRegister(int reg);
static Result Match(Handle<Code> regexp,
Handle<String> subject,
int* offsets_vector,
int offsets_vector_length,
int previous_index);
static Result Execute(Code* code,
String* input,
int start_offset,
const byte* input_start,
const byte* input_end,
int* output,
bool at_start);
private:
// Offsets from ebp of function parameters and stored registers.
static const int kFramePointer = 0;
@ -163,16 +125,6 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
// Initial size of code buffer.
static const size_t kRegExpCodeSize = 1024;
// Initial size of constant buffers allocated during compilation.
static const int kRegExpConstantsSize = 256;
static const byte* StringCharacterPosition(String* subject, int start_index);
// Compares two-byte strings case insensitively.
// Called from generated RegExp code.
static int CaseInsensitiveCompareUC16(Address byte_offset1,
Address byte_offset2,
size_t byte_length);
// Load a number of characters at the given offset from the
// current position, into the current-character register.
@ -218,11 +170,6 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
// is NULL, in which case it is a conditional Backtrack.
void BranchOrBacktrack(Condition condition, Label* to, Hint hint = no_hint);
// Load the address of a "constant buffer" (a slice of a byte array)
// into a register. The address is computed from the ByteArray* address
// and an offset. Uses no extra registers.
void LoadConstantBufferAddress(Register reg, ArraySlice* buffer);
// 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);
@ -258,10 +205,6 @@ class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
MacroAssembler* masm_;
// Constant buffer provider. Allocates external storage for storing
// constants.
ByteArrayProvider constants_;
// Which mode to generate code for (ASCII or UC16).
Mode mode_;

View File

@ -43,6 +43,7 @@
#include "regexp-macro-assembler-irregexp.h"
#include "regexp-stack.h"
#ifdef V8_NATIVE_REGEXP
#if V8_TARGET_ARCH_IA32
#include "ia32/macro-assembler-ia32.h"
#include "ia32/regexp-macro-assembler-ia32.h"
@ -54,6 +55,7 @@
#else
#error Unsupported target architecture.
#endif
#endif
#include "interpreter-irregexp.h"
@ -270,10 +272,11 @@ Handle<Object> RegExpImpl::AtomExec(Handle<JSRegExp> re,
// If compilation fails, an exception is thrown and this function
// returns false.
bool RegExpImpl::EnsureCompiledIrregexp(Handle<JSRegExp> re, bool is_ascii) {
Object* compiled_code = re->DataAt(JSRegExp::code_index(is_ascii));
#ifdef V8_NATIVE_REGEXP
if (re->DataAt(JSRegExp::code_index(is_ascii))->IsCode()) return true;
if (compiled_code->IsCode()) return true;
#else // ! V8_NATIVE_REGEXP (RegExp interpreter code)
if (re->DataAt(JSRegExp::code_index(is_ascii))->IsByteArray()) return true;
if (compiled_code->IsByteArray()) return true;
#endif
return CompileIrregexp(re, is_ascii);
}
@ -414,33 +417,36 @@ Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> jsregexp,
// Dispatch to the correct RegExp implementation.
Handle<FixedArray> regexp(FixedArray::cast(jsregexp->data()));
#ifdef V8_NATIVE_REGEXP
#if V8_TARGET_ARCH_IA32
#ifdef V8_TARGET_ARCH_ARM
UNIMPLEMENTED();
#else // Native regexp supported.
OffsetsVector captures(number_of_capture_registers);
int* captures_vector = captures.vector();
RegExpMacroAssemblerIA32::Result res;
NativeRegExpMacroAssembler::Result res;
do {
bool is_ascii = subject->IsAsciiRepresentation();
if (!EnsureCompiledIrregexp(jsregexp, is_ascii)) {
return Handle<Object>::null();
}
Handle<Code> code(RegExpImpl::IrregexpNativeCode(*regexp, is_ascii));
res = RegExpMacroAssemblerIA32::Match(code,
subject,
captures_vector,
captures.length(),
previous_index);
res = NativeRegExpMacroAssembler::Match(code,
subject,
captures_vector,
captures.length(),
previous_index);
// If result is RETRY, the string have changed representation, and we
// must restart from scratch.
} while (res == RegExpMacroAssemblerIA32::RETRY);
if (res == RegExpMacroAssemblerIA32::EXCEPTION) {
} while (res == NativeRegExpMacroAssembler::RETRY);
if (res == NativeRegExpMacroAssembler::EXCEPTION) {
ASSERT(Top::has_pending_exception());
return Handle<Object>::null();
}
ASSERT(res == RegExpMacroAssemblerIA32::SUCCESS
|| res == RegExpMacroAssemblerIA32::FAILURE);
ASSERT(res == NativeRegExpMacroAssembler::SUCCESS
|| res == NativeRegExpMacroAssembler::FAILURE);
if (res != RegExpMacroAssemblerIA32::SUCCESS) return Factory::null_value();
if (res != NativeRegExpMacroAssembler::SUCCESS) return Factory::null_value();
array = Handle<FixedArray>(FixedArray::cast(last_match_info->elements()));
ASSERT(array->length() >= number_of_capture_registers + kLastMatchOverhead);
@ -449,10 +455,9 @@ Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> jsregexp,
SetCapture(*array, i, captures_vector[i]);
SetCapture(*array, i + 1, captures_vector[i + 1]);
}
#else // !V8_TARGET_ARCH_IA32
UNREACHABLE();
#endif // V8_TARGET_ARCH_IA32
#else // !V8_NATIVE_REGEXP
#endif // Native regexp supported.
#else // ! V8_NATIVE_REGEXP
bool is_ascii = subject->IsAsciiRepresentation();
if (!EnsureCompiledIrregexp(jsregexp, is_ascii)) {
return Handle<Object>::null();
@ -4457,38 +4462,36 @@ RegExpEngine::CompilationResult RegExpEngine::Compile(RegExpCompileData* data,
NodeInfo info = *node->info();
// Create the correct assembler for the architecture.
#ifdef V8_NATIVE_REGEXP
#ifdef V8_TARGET_ARCH_ARM
// ARM native regexp not implemented yet.
UNREACHABLE();
#endif
#ifdef V8_TARGET_ARCH_X64
// X64 native regexp not implemented yet.
UNREACHABLE();
#endif
// Native regexp implementation.
NativeRegExpMacroAssembler::Mode mode =
is_ascii ? NativeRegExpMacroAssembler::ASCII
: NativeRegExpMacroAssembler::UC16;
#ifdef V8_TARGET_ARCH_IA32
RegExpMacroAssemblerIA32::Mode mode;
if (is_ascii) {
mode = RegExpMacroAssemblerIA32::ASCII;
} else {
mode = RegExpMacroAssemblerIA32::UC16;
}
RegExpMacroAssemblerIA32 macro_assembler(mode,
(data->capture_count + 1) * 2);
return compiler.Assemble(&macro_assembler,
node,
data->capture_count,
pattern);
#endif
#ifdef V8_TARGET_ARCH_X64
RegExpMacroAssemblerX64 macro_assembler(mode,
(data->capture_count + 1) * 2);
#endif
#ifdef V8_TARGET_ARCH_ARM
UNIMPLEMENTED();
#endif
#else // ! V8_NATIVE_REGEXP
// Interpreted regexp.
// Interpreted regexp implementation.
EmbeddedVector<byte, 1024> codes;
RegExpMacroAssemblerIrregexp macro_assembler(codes);
#endif
return compiler.Assemble(&macro_assembler,
node,
data->capture_count,
pattern);
#endif // V8_NATIVE_REGEXP
}
}} // namespace v8::internal

View File

@ -375,37 +375,6 @@ void RegExpMacroAssemblerIrregexp::CheckNotRegistersEqual(int reg1,
}
void RegExpMacroAssemblerIrregexp::CheckBitmap(uc16 start,
Label* bitmap,
Label* on_zero) {
UNIMPLEMENTED();
}
void RegExpMacroAssemblerIrregexp::DispatchHalfNibbleMap(
uc16 start,
Label* half_nibble_map,
const Vector<Label*>& table) {
UNIMPLEMENTED();
}
void RegExpMacroAssemblerIrregexp::DispatchByteMap(
uc16 start,
Label* byte_map,
const Vector<Label*>& table) {
UNIMPLEMENTED();
}
void RegExpMacroAssemblerIrregexp::DispatchHighByteMap(
byte start,
Label* byte_map,
const Vector<Label*>& table) {
UNIMPLEMENTED();
}
void RegExpMacroAssemblerIrregexp::CheckCharacters(
Vector<const uc16> str,
int cp_offset,

View File

@ -52,7 +52,6 @@ class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler {
// The byte-code interpreter checks on each push anyway.
virtual int stack_limit_slack() { return 1; }
virtual void Bind(Label* label);
virtual void EmitOrLink(Label* label);
virtual void AdvanceCurrentPosition(int by); // Signed cp change.
virtual void PopCurrentPosition();
virtual void PushCurrentPosition();
@ -100,16 +99,6 @@ class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler {
int cp_offset,
Label* on_failure,
bool check_end_of_string);
virtual void CheckBitmap(uc16 start, Label* bitmap, Label* on_zero);
virtual void DispatchHalfNibbleMap(uc16 start,
Label* half_nibble_map,
const Vector<Label*>& destinations);
virtual void DispatchByteMap(uc16 start,
Label* byte_map,
const Vector<Label*>& destinations);
virtual void DispatchHighByteMap(byte start,
Label* byte_map,
const Vector<Label*>& destinations);
virtual void IfRegisterLT(int register_index, int comparand, Label* if_lt);
virtual void IfRegisterGE(int register_index, int comparand, Label* if_ge);
virtual void IfRegisterEqPos(int register_index, Label* if_eq);
@ -119,6 +108,7 @@ class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler {
private:
void Expand();
// Code and bitmap emission.
inline void EmitOrLink(Label* label);
inline void Emit32(uint32_t x);
inline void Emit16(uint32_t x);
inline void Emit(uint32_t bc, uint32_t arg);

View File

@ -53,12 +53,6 @@ void RegExpMacroAssemblerTracer::Bind(Label* label) {
}
void RegExpMacroAssemblerTracer::EmitOrLink(Label* label) {
PrintF(" EmitOrLink(label[%08x]);\n", label);
assembler_->EmitOrLink(label);
}
void RegExpMacroAssemblerTracer::AdvanceCurrentPosition(int by) {
PrintF(" AdvanceCurrentPosition(by=%d);\n", by);
assembler_->AdvanceCurrentPosition(by);
@ -311,13 +305,6 @@ void RegExpMacroAssemblerTracer::CheckCharacters(Vector<const uc16> str,
}
void RegExpMacroAssemblerTracer::CheckBitmap(uc16 start, Label* bitmap,
Label* on_zero) {
PrintF(" CheckBitmap(start=u%04x, <bitmap>, label[%08x]);\n", start, on_zero);
assembler_->CheckBitmap(start, bitmap, on_zero);
}
bool RegExpMacroAssemblerTracer::CheckSpecialCharacterClass(
uc16 type,
int cp_offset,
@ -338,51 +325,6 @@ bool RegExpMacroAssemblerTracer::CheckSpecialCharacterClass(
}
void RegExpMacroAssemblerTracer::DispatchHalfNibbleMap(
uc16 start,
Label* half_nibble_map,
const Vector<Label*>& destinations) {
PrintF(" DispatchHalfNibbleMap(start=u%04x, <half_nibble_map>, [", start);
for (int i = 0; i < destinations.length(); i++) {
if (i > 0)
PrintF(", ");
PrintF("label[%08x]", destinations[i]);
}
PrintF(");\n");
assembler_->DispatchHalfNibbleMap(start, half_nibble_map, destinations);
}
void RegExpMacroAssemblerTracer::DispatchByteMap(
uc16 start,
Label* byte_map,
const Vector<Label*>& destinations) {
PrintF(" DispatchByteMap(start=u%04x, <byte_map>, [", start);
for (int i = 0; i < destinations.length(); i++) {
if (i > 0)
PrintF(", ");
PrintF("label[%08x]", destinations[i]);
}
PrintF(");\n");
assembler_->DispatchByteMap(start, byte_map, destinations);
}
void RegExpMacroAssemblerTracer::DispatchHighByteMap(
byte start,
Label* byte_map,
const Vector<Label*>& destinations) {
PrintF(" DispatchHighByteMap(start=u%04x, <byte_map>, [", start);
for (int i = 0; i < destinations.length(); i++) {
if (i > 0)
PrintF(", ");
PrintF("label[%08x]", destinations[i]);
}
PrintF(");\n");
assembler_->DispatchHighByteMap(start, byte_map, destinations);
}
void RegExpMacroAssemblerTracer::IfRegisterLT(int register_index,
int comparand, Label* if_lt) {
PrintF(" IfRegisterLT(register=%d, number=%d, label[%08x]);\n",

View File

@ -43,7 +43,6 @@ class RegExpMacroAssemblerTracer: public RegExpMacroAssembler {
virtual void Backtrack();
virtual void Bind(Label* label);
virtual void CheckAtStart(Label* on_at_start);
virtual void CheckBitmap(uc16 start, Label* bitmap, Label* on_zero);
virtual void CheckCharacter(uint32_t c, Label* on_equal);
virtual void CheckCharacterAfterAnd(uint32_t c,
uint32_t and_with,
@ -73,19 +72,6 @@ class RegExpMacroAssemblerTracer: public RegExpMacroAssembler {
int cp_offset,
bool check_offset,
Label* on_no_match);
virtual void DispatchByteMap(
uc16 start,
Label* byte_map,
const Vector<Label*>& destinations);
virtual void DispatchHalfNibbleMap(
uc16 start,
Label* half_nibble_map,
const Vector<Label*>& destinations);
virtual void DispatchHighByteMap(
byte start,
Label* byte_map,
const Vector<Label*>& destinations);
virtual void EmitOrLink(Label* label);
virtual void Fail();
virtual Handle<Object> GetCode(Handle<String> source);
virtual void GoTo(Label* label);

View File

@ -25,10 +25,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <string.h>
#include "v8.h"
#include "ast.h"
#include "assembler.h"
#include "regexp-stack.h"
#include "regexp-macro-assembler.h"
namespace v8 {
@ -42,38 +42,176 @@ RegExpMacroAssembler::~RegExpMacroAssembler() {
}
ByteArrayProvider::ByteArrayProvider(unsigned int initial_size)
: byte_array_size_(initial_size),
current_byte_array_(),
current_byte_array_free_offset_(initial_size) {}
#ifdef V8_NATIVE_REGEXP // Avoid unused code, e.g., on ARM.
NativeRegExpMacroAssembler::NativeRegExpMacroAssembler() {
}
ArraySlice ByteArrayProvider::GetBuffer(unsigned int size,
unsigned int elem_size) {
ASSERT(size > 0);
size_t byte_size = size * elem_size;
int free_offset = current_byte_array_free_offset_;
// align elements
free_offset += elem_size - 1;
free_offset = free_offset - (free_offset % elem_size);
NativeRegExpMacroAssembler::~NativeRegExpMacroAssembler() {
}
if (free_offset + byte_size > byte_array_size_) {
if (byte_size > (byte_array_size_ / 2)) {
Handle<ByteArray> solo_buffer(Factory::NewByteArray(byte_size, TENURED));
return ArraySlice(solo_buffer, 0);
const byte* NativeRegExpMacroAssembler::StringCharacterPosition(
String* subject,
int start_index) {
// Not just flat, but ultra flat.
ASSERT(subject->IsExternalString() || subject->IsSeqString());
ASSERT(start_index >= 0);
ASSERT(start_index <= subject->length());
if (subject->IsAsciiRepresentation()) {
const byte* address;
if (StringShape(subject).IsExternal()) {
const char* data = ExternalAsciiString::cast(subject)->resource()->data();
address = reinterpret_cast<const byte*>(data);
} else {
ASSERT(subject->IsSeqAsciiString());
char* data = SeqAsciiString::cast(subject)->GetChars();
address = reinterpret_cast<const byte*>(data);
}
current_byte_array_ = Factory::NewByteArray(byte_array_size_, TENURED);
free_offset = 0;
return address + start_index;
}
current_byte_array_free_offset_ = free_offset + byte_size;
return ArraySlice(current_byte_array_, free_offset);
const uc16* data;
if (StringShape(subject).IsExternal()) {
data = ExternalTwoByteString::cast(subject)->resource()->data();
} else {
ASSERT(subject->IsSeqTwoByteString());
data = SeqTwoByteString::cast(subject)->GetChars();
}
return reinterpret_cast<const byte*>(data + start_index);
}
template <typename T>
ArraySlice ByteArrayProvider::GetBuffer(Vector<T> values) {
ArraySlice slice = GetBuffer(values.length(), sizeof(T));
memcpy(slice.location(), values.start(), values.length() * sizeof(T));
return slice;
NativeRegExpMacroAssembler::Result NativeRegExpMacroAssembler::Match(
Handle<Code> regexp_code,
Handle<String> subject,
int* offsets_vector,
int offsets_vector_length,
int previous_index) {
ASSERT(subject->IsFlat());
ASSERT(previous_index >= 0);
ASSERT(previous_index <= subject->length());
// No allocations before calling the regexp, but we can't use
// AssertNoAllocation, since regexps might be preempted, and another thread
// might do allocation anyway.
String* subject_ptr = *subject;
// Character offsets into string.
int start_offset = previous_index;
int end_offset = subject_ptr->length();
bool is_ascii = subject->IsAsciiRepresentation();
if (StringShape(subject_ptr).IsCons()) {
subject_ptr = ConsString::cast(subject_ptr)->first();
} else if (StringShape(subject_ptr).IsSliced()) {
SlicedString* slice = SlicedString::cast(subject_ptr);
start_offset += slice->start();
end_offset += slice->start();
subject_ptr = slice->buffer();
}
// Ensure that an underlying string has the same ascii-ness.
ASSERT(subject_ptr->IsAsciiRepresentation() == is_ascii);
ASSERT(subject_ptr->IsExternalString() || subject_ptr->IsSeqString());
// String is now either Sequential or External
int char_size_shift = is_ascii ? 0 : 1;
int char_length = end_offset - start_offset;
const byte* input_start =
StringCharacterPosition(subject_ptr, start_offset);
int byte_length = char_length << char_size_shift;
const byte* input_end = input_start + byte_length;
Result res = Execute(*regexp_code,
subject_ptr,
start_offset,
input_start,
input_end,
offsets_vector,
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;
}
NativeRegExpMacroAssembler::Result NativeRegExpMacroAssembler::Execute(
Code* code,
String* input,
int start_offset,
const byte* input_start,
const byte* input_end,
int* output,
bool at_start) {
typedef int (*matcher)(String*, int, const byte*,
const byte*, int*, int, Address);
matcher matcher_func = FUNCTION_CAST<matcher>(code->entry());
int at_start_val = at_start ? 1 : 0;
// Ensure that the minimum stack has been allocated.
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);
ASSERT(result <= SUCCESS);
ASSERT(result >= RETRY);
if (result == EXCEPTION && !Top::has_pending_exception()) {
// We detected a stack overflow (on the backtrack stack) in RegExp code,
// but haven't created the exception yet.
Top::StackOverflow();
}
return static_cast<Result>(result);
}
static unibrow::Mapping<unibrow::Ecma262Canonicalize> canonicalize;
int NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16(
Address byte_offset1,
Address byte_offset2,
size_t byte_length) {
// This function is not allowed to cause a garbage collection.
// A GC might move the calling generated code and invalidate the
// return address on the stack.
ASSERT(byte_length % 2 == 0);
uc16* substring1 = reinterpret_cast<uc16*>(byte_offset1);
uc16* substring2 = reinterpret_cast<uc16*>(byte_offset2);
size_t length = byte_length >> 1;
for (size_t i = 0; i < length; i++) {
unibrow::uchar c1 = substring1[i];
unibrow::uchar c2 = substring2[i];
if (c1 != c2) {
unibrow::uchar s1[1] = { c1 };
canonicalize.get(c1, '\0', s1);
if (s1[0] != c2) {
unibrow::uchar s2[1] = { c2 };
canonicalize.get(c2, '\0', s2);
if (s1[0] != s2[0]) {
return 0;
}
}
}
}
return 1;
}
#endif // V8_NATIVE_REGEXP
} } // namespace v8::internal

View File

@ -46,6 +46,7 @@ class RegExpMacroAssembler {
enum IrregexpImplementation {
kIA32Implementation,
kARMImplementation,
kX64Implementation,
kBytecodeImplementation
};
@ -67,12 +68,6 @@ class RegExpMacroAssembler {
virtual void Backtrack() = 0;
virtual void Bind(Label* label) = 0;
virtual void CheckAtStart(Label* on_at_start) = 0;
// Check the current character against a bitmap. The range of the current
// character must be from start to start + length_of_bitmap_in_bits.
virtual void CheckBitmap(
uc16 start, // The bitmap is indexed from this character.
Label* bitmap, // Where the bitmap is emitted.
Label* on_zero) = 0; // Where to go if the bit is 0. Fall through on 1.
// Dispatch after looking the current character up in a 2-bits-per-entry
// map. The destinations vector has up to 4 labels.
virtual void CheckCharacter(uint32_t c, Label* on_equal) = 0;
@ -132,23 +127,6 @@ class RegExpMacroAssembler {
Label* on_no_match) {
return false;
}
// Dispatch after looking the current character up in a byte map. The
// destinations vector has up to 256 labels.
virtual void DispatchByteMap(
uc16 start,
Label* byte_map,
const Vector<Label*>& destinations) = 0;
virtual void DispatchHalfNibbleMap(
uc16 start,
Label* half_nibble_map,
const Vector<Label*>& destinations) = 0;
// Dispatch after looking the high byte of the current character up in a byte
// map. The destinations vector has up to 256 labels.
virtual void DispatchHighByteMap(
byte start,
Label* byte_map,
const Vector<Label*>& destinations) = 0;
virtual void EmitOrLink(Label* label) = 0;
virtual void Fail() = 0;
virtual Handle<Object> GetCode(Handle<String> source) = 0;
virtual void GoTo(Label* label) = 0;
@ -181,51 +159,53 @@ class RegExpMacroAssembler {
virtual void WriteCurrentPositionToRegister(int reg, int cp_offset) = 0;
virtual void ClearRegisters(int reg_from, int reg_to) = 0;
virtual void WriteStackPointerToRegister(int reg) = 0;
private:
};
struct ArraySlice {
#ifdef V8_NATIVE_REGEXP // Avoid compiling unused code.
class NativeRegExpMacroAssembler: public RegExpMacroAssembler {
public:
ArraySlice(Handle<ByteArray> array, size_t offset)
: array_(array), offset_(offset) {}
Handle<ByteArray> array() { return array_; }
// Offset in the byte array data.
size_t offset() { return offset_; }
// Offset from the ByteArray pointer.
size_t base_offset() {
return ByteArray::kHeaderSize - kHeapObjectTag + offset_;
}
void* location() {
return reinterpret_cast<void*>(array_->GetDataStartAddress() + offset_);
}
template <typename T>
T& at(int idx) {
return reinterpret_cast<T*>(array_->GetDataStartAddress() + offset_)[idx];
}
private:
Handle<ByteArray> array_;
size_t offset_;
// Type of input string to generate code for.
enum Mode { ASCII = 1, UC16 = 2 };
// Result of calling generated native RegExp code.
// RETRY: Something significant changed during execution, and the matching
// should be retried from scratch.
// EXCEPTION: Something failed during execution. If no exception has been
// thrown, it's an internal out-of-memory, and the caller should
// throw the exception.
// FAILURE: Matching failed.
// SUCCESS: Matching succeeded, and the output array has been filled with
// capture positions.
enum Result { RETRY = -2, EXCEPTION = -1, FAILURE = 0, SUCCESS = 1 };
NativeRegExpMacroAssembler();
virtual ~NativeRegExpMacroAssembler();
static Result Match(Handle<Code> regexp,
Handle<String> subject,
int* offsets_vector,
int offsets_vector_length,
int previous_index);
// Compares two-byte strings case insensitively.
// Called from generated RegExp code.
static int CaseInsensitiveCompareUC16(Address byte_offset1,
Address byte_offset2,
size_t byte_length);
static const byte* StringCharacterPosition(String* subject, int start_index);
static Result Execute(Code* code,
String* input,
int start_offset,
const byte* input_start,
const byte* input_end,
int* output,
bool at_start);
};
class ByteArrayProvider {
public:
explicit ByteArrayProvider(unsigned int initial_size);
// Provides a place to put "size" elements of size "element_size".
// The information can be stored in the provided ByteArray at the "offset".
// The offset is aligned to the element size.
ArraySlice GetBuffer(unsigned int size,
unsigned int element_size);
template <typename T>
ArraySlice GetBuffer(Vector<T> values);
private:
size_t byte_array_size_;
Handle<ByteArray> current_byte_array_;
int current_byte_array_free_offset_;
};
#endif // V8_NATIVE_REGEXP
} } // namespace v8::internal
#endif // V8_REGEXP_MACRO_ASSEMBLER_H_

View File

@ -48,7 +48,7 @@ class RegExpStack {
~RegExpStack(); // Releases the stack if it has grown.
// Gives the top of the memory used as stack.
static Address stack_top() {
static Address stack_base() {
ASSERT(thread_local_.memory_size_ != 0);
return thread_local_.memory_ + thread_local_.memory_size_;
}
@ -74,7 +74,7 @@ class RegExpStack {
private:
// Artificial limit used when no memory has been allocated.
static const uint32_t kMemoryTop = 0xffffffff;
static const uintptr_t kMemoryTop = -1;
// Minimal size of allocated stack area.
static const size_t kMinimumStackSize = 1 * KB;

View File

@ -437,21 +437,43 @@ void Assembler::arithmetic_op(byte opcode, Register reg, const Operand& op) {
}
void Assembler::arithmetic_op(byte opcode, Register dst, Register src) {
void Assembler::arithmetic_op(byte opcode, Register reg, Register rm_reg) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
emit_rex_64(dst, src);
emit_rex_64(reg, rm_reg);
emit(opcode);
emit_modrm(dst, src);
emit_modrm(reg, rm_reg);
}
void Assembler::arithmetic_op_32(byte opcode, Register dst, Register src) {
void Assembler::arithmetic_op_16(byte opcode, Register reg, Register rm_reg) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
emit_optional_rex_32(dst, src);
emit(0x66);
emit_optional_rex_32(reg, rm_reg);
emit(opcode);
emit_modrm(dst, src);
emit_modrm(reg, rm_reg);
}
void Assembler::arithmetic_op_16(byte opcode,
Register reg,
const Operand& rm_reg) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
emit(0x66);
emit_optional_rex_32(reg, rm_reg);
emit(opcode);
emit_operand(reg, rm_reg);
}
void Assembler::arithmetic_op_32(byte opcode, Register reg, Register rm_reg) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
emit_optional_rex_32(reg, rm_reg);
emit(opcode);
emit_modrm(reg, rm_reg);
}
@ -504,6 +526,47 @@ void Assembler::immediate_arithmetic_op(byte subcode,
}
void Assembler::immediate_arithmetic_op_16(byte subcode,
Register dst,
Immediate src) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
emit(0x66); // Operand size override prefix.
emit_optional_rex_32(dst);
if (is_int8(src.value_)) {
emit(0x83);
emit_modrm(subcode, dst);
emit(src.value_);
} else if (dst.is(rax)) {
emit(0x05 | (subcode << 3));
emitl(src.value_);
} else {
emit(0x81);
emit_modrm(subcode, dst);
emitl(src.value_);
}
}
void Assembler::immediate_arithmetic_op_16(byte subcode,
const Operand& dst,
Immediate src) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
emit(0x66); // Operand size override prefix.
emit_optional_rex_32(dst);
if (is_int8(src.value_)) {
emit(0x83);
emit_operand(subcode, dst);
emit(src.value_);
} else {
emit(0x81);
emit_operand(subcode, dst);
emitl(src.value_);
}
}
void Assembler::immediate_arithmetic_op_32(byte subcode,
Register dst,
Immediate src) {
@ -744,6 +807,14 @@ void Assembler::cmovl(Condition cc, Register dst, const Operand& src) {
}
void Assembler::cmpb_al(Immediate imm8) {
ASSERT(is_int8(imm8.value_) || is_uint8(imm8.value_));
EnsureSpace ensure_space(this);
last_pc_ = pc_;
emit(0x3c);
emit(imm8.value_);
}
void Assembler::cpuid() {
ASSERT(CpuFeatures::IsEnabled(CpuFeatures::CPUID));
@ -1193,6 +1264,32 @@ void Assembler::movq(const Operand& dst, Immediate value) {
}
/*
* Loads the ip-relative location of the src label into the target
* location (as a 32-bit offset sign extended to 64-bit).
*/
void Assembler::movl(const Operand& dst, Label* src) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
emit_optional_rex_32(dst);
emit(0xC7);
emit_operand(0, dst);
if (src->is_bound()) {
int offset = src->pos() - pc_offset() - sizeof(int32_t);
ASSERT(offset <= 0);
emitl(offset);
} else if (src->is_linked()) {
emitl(src->pos());
src->link_to(pc_offset() - sizeof(int32_t));
} else {
ASSERT(src->is_unused());
int32_t current = pc_offset();
emitl(current);
src->link_to(current);
}
}
void Assembler::movq(Register dst, Handle<Object> value, RelocInfo::Mode mode) {
// If there is no relocation info, emit the value of the handle efficiently
// (possibly using less that 8 bytes for the value).

View File

@ -496,13 +496,17 @@ class Assembler : public Malloced {
// Load a 32-bit immediate value, zero-extended to 64 bits.
void movl(Register dst, Immediate imm32);
void movq(Register dst, const Operand& src);
// Sign extends immediate 32-bit value to 64 bits.
void movq(Register dst, Immediate x);
void movq(Register dst, Register src);
// Move 64 bit register value to 64-bit memory location.
void movq(const Operand& dst, Register src);
// Move 64 bit memory location to 64-bit register value.
void movq(Register dst, const Operand& src);
void movq(Register dst, Register src);
// Sign extends immediate 32-bit value to 64 bits.
void movq(Register dst, Immediate x);
// Move the offset of the label location relative to the current
// position (after the move) to the destination.
void movl(const Operand& dst, Label* src);
// Move sign extended immediate to memory location.
void movq(const Operand& dst, Immediate value);
// New x64 instructions to load a 64-bit immediate into a register.
@ -535,7 +539,11 @@ class Assembler : public Malloced {
// Arithmetics
void addl(Register dst, Register src) {
arithmetic_op_32(0x03, dst, src);
if (dst.low_bits() == 4) { // Forces SIB byte.
arithmetic_op_32(0x01, src, dst);
} else {
arithmetic_op_32(0x03, dst, src);
}
}
void addl(Register dst, Immediate src) {
@ -574,10 +582,44 @@ class Assembler : public Malloced {
immediate_arithmetic_op_8(0x7, dst, src);
}
void cmpb_al(Immediate src);
void cmpb(Register dst, Register src) {
arithmetic_op(0x3A, dst, src);
}
void cmpb(Register dst, const Operand& src) {
arithmetic_op(0x3A, dst, src);
}
void cmpb(const Operand& dst, Register src) {
arithmetic_op(0x38, src, dst);
}
void cmpb(const Operand& dst, Immediate src) {
immediate_arithmetic_op_8(0x7, dst, src);
}
void cmpw(const Operand& dst, Immediate src) {
immediate_arithmetic_op_16(0x7, dst, src);
}
void cmpw(Register dst, Immediate src) {
immediate_arithmetic_op_16(0x7, dst, src);
}
void cmpw(Register dst, const Operand& src) {
arithmetic_op_16(0x3B, dst, src);
}
void cmpw(Register dst, Register src) {
arithmetic_op_16(0x3B, dst, src);
}
void cmpw(const Operand& dst, Register src) {
arithmetic_op_16(0x39, src, dst);
}
void cmpl(Register dst, Register src) {
arithmetic_op_32(0x3B, dst, src);
}
@ -794,6 +836,10 @@ class Assembler : public Malloced {
immediate_arithmetic_op_32(0x5, dst, src);
}
void subb(Register dst, Immediate src) {
immediate_arithmetic_op_8(0x5, dst, src);
}
void testb(Register reg, Immediate mask);
void testb(const Operand& op, Immediate mask);
void testl(Register dst, Register src);
@ -1141,26 +1187,36 @@ class Assembler : public Malloced {
// AND, OR, XOR, or CMP. The encodings of these operations are all
// similar, differing just in the opcode or in the reg field of the
// ModR/M byte.
void arithmetic_op(byte opcode, Register dst, Register src);
void arithmetic_op_32(byte opcode, Register dst, Register src);
void arithmetic_op_16(byte opcode, Register reg, Register rm_reg);
void arithmetic_op_16(byte opcode, Register reg, const Operand& rm_reg);
void arithmetic_op_32(byte opcode, Register reg, Register rm_reg);
void arithmetic_op_32(byte opcode, Register reg, const Operand& rm_reg);
void arithmetic_op(byte opcode, Register reg, Register rm_reg);
void arithmetic_op(byte opcode, Register reg, const Operand& rm_reg);
void immediate_arithmetic_op(byte subcode, Register dst, Immediate src);
void immediate_arithmetic_op(byte subcode, const Operand& dst, Immediate src);
// Operate on a 32-bit word in memory or register.
void immediate_arithmetic_op_32(byte subcode,
const Operand& dst,
Immediate src);
void immediate_arithmetic_op_32(byte subcode,
Register dst,
Immediate src);
// Operate on a byte in memory or register.
void immediate_arithmetic_op_8(byte subcode,
const Operand& dst,
Immediate src);
void immediate_arithmetic_op_8(byte subcode,
Register dst,
Immediate src);
void immediate_arithmetic_op_8(byte subcode,
const Operand& dst,
Immediate src);
// Operate on a word in memory or register.
void immediate_arithmetic_op_16(byte subcode,
Register dst,
Immediate src);
void immediate_arithmetic_op_16(byte subcode,
const Operand& dst,
Immediate src);
// Operate on a 32-bit word in memory or register.
void immediate_arithmetic_op_32(byte subcode,
Register dst,
Immediate src);
void immediate_arithmetic_op_32(byte subcode,
const Operand& dst,
Immediate src);
// Emit machine code for a shift operation.
void shift(Register dst, Immediate shift_amount, int subcode);
void shift_32(Register dst, Immediate shift_amount, int subcode);
@ -1180,6 +1236,7 @@ class Assembler : public Malloced {
friend class CodePatcher;
friend class EnsureSpace;
friend class RegExpMacroAssemblerX64;
// Code buffer:
// The buffer into which code and relocation info are generated.

File diff suppressed because it is too large Load Diff

View File

@ -25,3 +25,271 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef V8_X64_REGEXP_MACRO_ASSEMBLER_X64_H_
#define V8_X64_REGEXP_MACRO_ASSEMBLER_X64_H_
namespace v8 {
namespace internal {
class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler {
public:
RegExpMacroAssemblerX64(Mode mode, int registers_to_save);
virtual ~RegExpMacroAssemblerX64();
virtual int stack_limit_slack();
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);
static Result Match(Handle<Code> regexp,
Handle<String> subject,
int* offsets_vector,
int offsets_vector_length,
int previous_index);
static Result Execute(Code* code,
String* input,
int start_offset,
const byte* input_start,
const byte* input_end,
int* output,
bool at_start);
private:
// Offsets from rbp of function parameters and stored registers.
static const int kFramePointer = 0;
// Above the frame pointer - function parameters and return address.
static const int kReturn_eip = kFramePointer + kPointerSize;
static const int kFrameAlign = kReturn_eip + kPointerSize;
#ifdef __MSVC__
// Parameters (first four passed as registers, but with room on stack).
// In Microsoft 64-bit Calling Convention, there is room on the callers
// stack (before the return address) to spill parameter registers. We
// use this space to store the register passed parameters.
static const int kInputString = kFrameAlign;
static const int kStartIndex = kInputString + kPointerSize;
static const int kInputStart = kStartIndex + kPointerSize;
static const int kInputEnd = kInputStart + kPointerSize;
static const int kRegisterOutput = kInputEnd + kPointerSize;
static const int kAtStart = kRegisterOutput + kPointerSize;
static const int kStackHighEnd = kAtStart + kPointerSize;
#else
// In AMD64 ABI Calling Convention, the first six integer parameters
// are passed as registers, and caller must allocate space on the stack
// if it wants them stored. We push the parameters after the frame pointer.
static const int kInputString = kFramePointer - kPointerSize;
static const int kStartIndex = kInputString - kPointerSize;
static const int kInputStart = kStartIndex - kPointerSize;
static const int kInputEnd = kInputStart - kPointerSize;
static const int kRegisterOutput = kInputEnd - kPointerSize;
static const int kAtStart = kRegisterOutput - kPointerSize;
static const int kStackHighEnd = kFrameAlign;
#endif
#ifdef __MSVC__
// Microsoft calling convention has three callee-saved registers
// (that we are using). We push these after the frame pointer.
static const int kBackup_rsi = kFramePointer - kPointerSize;
static const int kBackup_rdi = kBackup_rsi - kPointerSize;
static const int kBackup_rbx = kBackup_rdi - kPointerSize;
static const int kLastCalleeSaveRegister = kBackup_rbx;
#else
// AMD64 Calling Convention has only one callee-save register that
// we use. We push this after the frame pointer (and after the
// parameters).
static const int kBackup_rbx = kAtStart - kPointerSize;
static const int kLastCalleeSaveRegister = kBackup_rbx;
#endif
// When adding local variables remember to push space for them in
// the frame in GetCode.
static const int kInputStartMinusOne =
kLastCalleeSaveRegister - 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;
// 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();
// 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);
// The register containing the current character after LoadCurrentCharacter.
inline Register current_character() { return rdx; }
// The register containing the backtrack stack top. Provides a meaningful
// name to the register.
inline Register backtrack_stackpointer() { return rcx; }
// The registers containing a self pointer to this code's Code object.
inline Register code_object_pointer() { return r8; }
// 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);
void MarkPositionForCodeRelativeFixup() {
code_relative_fixup_positions_.Add(masm_->pc_offset());
}
void FixupCodeRelativePositions();
// 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);
inline void SafeCallTarget(Label* label);
inline void SafeReturn();
// Pushes the value of a register on the backtrack stack. Decrements the
// stack pointer (rcx) by a word size and stores the register's value there.
inline void Push(Register source);
// Pushes a value on the backtrack stack. Decrements the stack pointer (rcx)
// by a word size and stores the value there.
inline void Push(Immediate value);
// Pushes the Code object relative offset of a label on the backtrack stack
// (i.e., a backtrack target). Decrements the stack pointer (rcx)
// by a word size and stores the value there.
inline void Push(Label* label);
// Pops a value from the backtrack stack. Reads the word at the stack pointer
// (rcx) and increments it by a word size.
inline void Pop(Register target);
// Drops the top value from the backtrack stack without reading it.
// Increments the stack pointer (rcx) by a word size.
inline void Drop();
// Before calling a C-function from generated code, align arguments on stack.
// After aligning the frame, arguments must be stored in esp[0], esp[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);
// 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, 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);
MacroAssembler* masm_;
ZoneList<int> code_relative_fixup_positions_;
// 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_;
// 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_;
};
}} // namespace v8::internal
#endif // V8_X64_REGEXP_MACRO_ASSEMBLER_X64_H_

View File

@ -113,6 +113,7 @@ test-debug/DebuggerUnload: CRASH || FAIL
test-debug/DebuggerHostDispatch: CRASH || FAIL
test-debug/DebugBreakInMessageHandler: CRASH || FAIL
test-debug/NoDebugBreakInAfterCompileMessageHandler: CRASH || FAIL
test-debug/RegExpDebugBreak: FAIL
test-api/Threading: CRASH || FAIL
test-api/Threading2: PASS || TIMEOUT
test-api/TryCatchSourceInfo: CRASH || FAIL

View File

@ -38,18 +38,21 @@
#include "jsregexp.h"
#include "regexp-macro-assembler.h"
#include "regexp-macro-assembler-irregexp.h"
#ifdef V8_NATIVE_REGEXP
#ifdef V8_TARGET_ARCH_ARM
#include "arm/regexp-macro-assembler-arm.h"
#endif
#ifdef V8_TARGET_ARCH_X64
// No X64-implementation yet.
#include "x64/macro-assembler-x64.h"
#include "x64/regexp-macro-assembler-x64.h"
#endif
#ifdef V8_TARGET_ARCH_IA32
#include "ia32/macro-assembler-ia32.h"
#include "ia32/regexp-macro-assembler-ia32.h"
#endif
#else
#include "interpreter-irregexp.h"
#endif
using namespace v8::internal;
@ -599,75 +602,20 @@ TEST(DispatchTableConstruction) {
// Tests of interpreter.
TEST(MacroAssembler) {
V8::Initialize(NULL);
byte codes[1024];
RegExpMacroAssemblerIrregexp m(Vector<byte>(codes, 1024));
// ^f(o)o.
Label fail, fail2, start;
uc16 foo_chars[3];
foo_chars[0] = 'f';
foo_chars[1] = 'o';
foo_chars[2] = 'o';
Vector<const uc16> foo(foo_chars, 3);
m.SetRegister(4, 42);
m.PushRegister(4, RegExpMacroAssembler::kNoStackLimitCheck);
m.AdvanceRegister(4, 42);
m.GoTo(&start);
m.Fail();
m.Bind(&start);
m.PushBacktrack(&fail2);
m.CheckCharacters(foo, 0, &fail, true);
m.WriteCurrentPositionToRegister(0, 0);
m.PushCurrentPosition();
m.AdvanceCurrentPosition(3);
m.WriteCurrentPositionToRegister(1, 0);
m.PopCurrentPosition();
m.AdvanceCurrentPosition(1);
m.WriteCurrentPositionToRegister(2, 0);
m.AdvanceCurrentPosition(1);
m.WriteCurrentPositionToRegister(3, 0);
m.Succeed();
m.Bind(&fail);
m.Backtrack();
m.Succeed();
m.Bind(&fail2);
m.PopRegister(0);
m.Fail();
v8::HandleScope scope;
Handle<String> source = Factory::NewStringFromAscii(CStrVector("^f(o)o"));
Handle<ByteArray> array = Handle<ByteArray>::cast(m.GetCode(source));
int captures[5];
const uc16 str1[] = {'f', 'o', 'o', 'b', 'a', 'r'};
Handle<String> f1_16 =
Factory::NewStringFromTwoByte(Vector<const uc16>(str1, 6));
CHECK(IrregexpInterpreter::Match(array, f1_16, captures, 0));
CHECK_EQ(0, captures[0]);
CHECK_EQ(3, captures[1]);
CHECK_EQ(1, captures[2]);
CHECK_EQ(2, captures[3]);
CHECK_EQ(84, captures[4]);
const uc16 str2[] = {'b', 'a', 'r', 'f', 'o', 'o'};
Handle<String> f2_16 =
Factory::NewStringFromTwoByte(Vector<const uc16>(str2, 6));
CHECK(!IrregexpInterpreter::Match(array, f2_16, captures, 0));
CHECK_EQ(42, captures[0]);
}
#ifdef V8_TARGET_ARCH_IA32 // IA32 Native Regexp only tests.
#ifdef V8_NATIVE_REGEXP
#ifdef V8_TARGET_ARCH_IA32
typedef RegExpMacroAssemblerIA32 ArchRegExpMacroAssembler;
#endif
#ifdef V8_TARGET_ARCH_X64
typedef RegExpMacroAssemblerX64 ArchRegExpMacroAssembler;
#endif
class ContextInitializer {
public:
ContextInitializer() : env_(), scope_(), stack_guard_() {
ContextInitializer()
: env_(), scope_(), zone_(DELETE_ON_EXIT), stack_guard_() {
env_ = v8::Context::New();
env_->Enter();
}
@ -678,18 +626,19 @@ class ContextInitializer {
private:
v8::Persistent<v8::Context> env_;
v8::HandleScope scope_;
v8::internal::ZoneScope zone_;
v8::internal::StackGuard stack_guard_;
};
static RegExpMacroAssemblerIA32::Result ExecuteIA32(Code* code,
String* input,
int start_offset,
const byte* input_start,
const byte* input_end,
int* captures,
bool at_start) {
return RegExpMacroAssemblerIA32::Execute(
static ArchRegExpMacroAssembler::Result Execute(Code* code,
String* input,
int start_offset,
const byte* input_start,
const byte* input_end,
int* captures,
bool at_start) {
return NativeRegExpMacroAssembler::Execute(
code,
input,
start_offset,
@ -700,11 +649,11 @@ static RegExpMacroAssemblerIA32::Result ExecuteIA32(Code* code,
}
TEST(MacroAssemblerIA32Success) {
TEST(MacroAssemblerNativeSuccess) {
v8::V8::Initialize();
ContextInitializer initializer;
RegExpMacroAssemblerIA32 m(RegExpMacroAssemblerIA32::ASCII, 4);
ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::ASCII, 4);
m.Succeed();
@ -718,16 +667,16 @@ TEST(MacroAssemblerIA32Success) {
const byte* start_adr =
reinterpret_cast<const byte*>(seq_input->GetCharsAddress());
RegExpMacroAssemblerIA32::Result result =
ExecuteIA32(*code,
*input,
0,
start_adr,
start_adr + seq_input->length(),
captures,
true);
NativeRegExpMacroAssembler::Result result =
Execute(*code,
*input,
0,
start_adr,
start_adr + seq_input->length(),
captures,
true);
CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
CHECK_EQ(-1, captures[0]);
CHECK_EQ(-1, captures[1]);
CHECK_EQ(-1, captures[2]);
@ -735,11 +684,11 @@ TEST(MacroAssemblerIA32Success) {
}
TEST(MacroAssemblerIA32Simple) {
TEST(MacroAssemblerNativeSimple) {
v8::V8::Initialize();
ContextInitializer initializer;
RegExpMacroAssemblerIA32 m(RegExpMacroAssemblerIA32::ASCII, 4);
ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::ASCII, 4);
uc16 foo_chars[3] = {'f', 'o', 'o'};
Vector<const uc16> foo(foo_chars, 3);
@ -762,16 +711,16 @@ TEST(MacroAssemblerIA32Simple) {
Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
Address start_adr = seq_input->GetCharsAddress();
RegExpMacroAssemblerIA32::Result result =
ExecuteIA32(*code,
*input,
0,
start_adr,
start_adr + input->length(),
captures,
true);
NativeRegExpMacroAssembler::Result result =
Execute(*code,
*input,
0,
start_adr,
start_adr + input->length(),
captures,
true);
CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
CHECK_EQ(0, captures[0]);
CHECK_EQ(3, captures[1]);
CHECK_EQ(-1, captures[2]);
@ -781,23 +730,23 @@ TEST(MacroAssemblerIA32Simple) {
seq_input = Handle<SeqAsciiString>::cast(input);
start_adr = seq_input->GetCharsAddress();
result = ExecuteIA32(*code,
*input,
0,
start_adr,
start_adr + input->length(),
captures,
true);
result = Execute(*code,
*input,
0,
start_adr,
start_adr + input->length(),
captures,
true);
CHECK_EQ(RegExpMacroAssemblerIA32::FAILURE, result);
CHECK_EQ(NativeRegExpMacroAssembler::FAILURE, result);
}
TEST(MacroAssemblerIA32SimpleUC16) {
TEST(MacroAssemblerNativeSimpleUC16) {
v8::V8::Initialize();
ContextInitializer initializer;
RegExpMacroAssemblerIA32 m(RegExpMacroAssemblerIA32::UC16, 4);
ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::UC16, 4);
uc16 foo_chars[3] = {'f', 'o', 'o'};
Vector<const uc16> foo(foo_chars, 3);
@ -822,16 +771,16 @@ TEST(MacroAssemblerIA32SimpleUC16) {
Handle<SeqTwoByteString> seq_input = Handle<SeqTwoByteString>::cast(input);
Address start_adr = seq_input->GetCharsAddress();
RegExpMacroAssemblerIA32::Result result =
ExecuteIA32(*code,
*input,
0,
start_adr,
start_adr + input->length(),
captures,
true);
NativeRegExpMacroAssembler::Result result =
Execute(*code,
*input,
0,
start_adr,
start_adr + input->length(),
captures,
true);
CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
CHECK_EQ(0, captures[0]);
CHECK_EQ(3, captures[1]);
CHECK_EQ(-1, captures[2]);
@ -842,23 +791,23 @@ TEST(MacroAssemblerIA32SimpleUC16) {
seq_input = Handle<SeqTwoByteString>::cast(input);
start_adr = seq_input->GetCharsAddress();
result = ExecuteIA32(*code,
*input,
0,
start_adr,
start_adr + input->length() * 2,
captures,
true);
result = Execute(*code,
*input,
0,
start_adr,
start_adr + input->length() * 2,
captures,
true);
CHECK_EQ(RegExpMacroAssemblerIA32::FAILURE, result);
CHECK_EQ(NativeRegExpMacroAssembler::FAILURE, result);
}
TEST(MacroAssemblerIA32Backtrack) {
TEST(MacroAssemblerNativeBacktrack) {
v8::V8::Initialize();
ContextInitializer initializer;
RegExpMacroAssemblerIA32 m(RegExpMacroAssemblerIA32::ASCII, 0);
ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::ASCII, 0);
Label fail;
Label backtrack;
@ -879,24 +828,24 @@ TEST(MacroAssemblerIA32Backtrack) {
Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
Address start_adr = seq_input->GetCharsAddress();
RegExpMacroAssemblerIA32::Result result =
ExecuteIA32(*code,
*input,
0,
start_adr,
start_adr + input->length(),
NULL,
true);
NativeRegExpMacroAssembler::Result result =
Execute(*code,
*input,
0,
start_adr,
start_adr + input->length(),
NULL,
true);
CHECK_EQ(RegExpMacroAssemblerIA32::FAILURE, result);
CHECK_EQ(NativeRegExpMacroAssembler::FAILURE, result);
}
TEST(MacroAssemblerIA32BackReferenceASCII) {
TEST(MacroAssemblerNativeBackReferenceASCII) {
v8::V8::Initialize();
ContextInitializer initializer;
RegExpMacroAssemblerIA32 m(RegExpMacroAssemblerIA32::ASCII, 3);
ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::ASCII, 3);
m.WriteCurrentPositionToRegister(0, 0);
m.AdvanceCurrentPosition(2);
@ -922,27 +871,27 @@ TEST(MacroAssemblerIA32BackReferenceASCII) {
Address start_adr = seq_input->GetCharsAddress();
int output[3];
RegExpMacroAssemblerIA32::Result result =
ExecuteIA32(*code,
*input,
0,
start_adr,
start_adr + input->length(),
output,
true);
NativeRegExpMacroAssembler::Result result =
Execute(*code,
*input,
0,
start_adr,
start_adr + input->length(),
output,
true);
CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
CHECK_EQ(0, output[0]);
CHECK_EQ(2, output[1]);
CHECK_EQ(6, output[2]);
}
TEST(MacroAssemblerIA32BackReferenceUC16) {
TEST(MacroAssemblerNativeBackReferenceUC16) {
v8::V8::Initialize();
ContextInitializer initializer;
RegExpMacroAssemblerIA32 m(RegExpMacroAssemblerIA32::UC16, 3);
ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::UC16, 3);
m.WriteCurrentPositionToRegister(0, 0);
m.AdvanceCurrentPosition(2);
@ -970,8 +919,8 @@ TEST(MacroAssemblerIA32BackReferenceUC16) {
Address start_adr = seq_input->GetCharsAddress();
int output[3];
RegExpMacroAssemblerIA32::Result result =
ExecuteIA32(*code,
NativeRegExpMacroAssembler::Result result =
Execute(*code,
*input,
0,
start_adr,
@ -979,7 +928,7 @@ TEST(MacroAssemblerIA32BackReferenceUC16) {
output,
true);
CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
CHECK_EQ(0, output[0]);
CHECK_EQ(2, output[1]);
CHECK_EQ(6, output[2]);
@ -987,11 +936,11 @@ TEST(MacroAssemblerIA32BackReferenceUC16) {
TEST(MacroAssemblerIA32AtStart) {
TEST(MacroAssemblernativeAtStart) {
v8::V8::Initialize();
ContextInitializer initializer;
RegExpMacroAssemblerIA32 m(RegExpMacroAssemblerIA32::ASCII, 0);
ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::ASCII, 0);
Label not_at_start, newline, fail;
m.CheckNotAtStart(&not_at_start);
@ -1022,34 +971,34 @@ TEST(MacroAssemblerIA32AtStart) {
Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
Address start_adr = seq_input->GetCharsAddress();
RegExpMacroAssemblerIA32::Result result =
ExecuteIA32(*code,
*input,
0,
start_adr,
start_adr + input->length(),
NULL,
true);
NativeRegExpMacroAssembler::Result result =
Execute(*code,
*input,
0,
start_adr,
start_adr + input->length(),
NULL,
true);
CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
result = ExecuteIA32(*code,
*input,
3,
start_adr + 3,
start_adr + input->length(),
NULL,
false);
result = Execute(*code,
*input,
3,
start_adr + 3,
start_adr + input->length(),
NULL,
false);
CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
}
TEST(MacroAssemblerIA32BackRefNoCase) {
TEST(MacroAssemblerNativeBackRefNoCase) {
v8::V8::Initialize();
ContextInitializer initializer;
RegExpMacroAssemblerIA32 m(RegExpMacroAssemblerIA32::ASCII, 4);
ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::ASCII, 4);
Label fail, succ;
@ -1084,16 +1033,16 @@ TEST(MacroAssemblerIA32BackRefNoCase) {
Address start_adr = seq_input->GetCharsAddress();
int output[4];
RegExpMacroAssemblerIA32::Result result =
ExecuteIA32(*code,
*input,
0,
start_adr,
start_adr + input->length(),
output,
true);
NativeRegExpMacroAssembler::Result result =
Execute(*code,
*input,
0,
start_adr,
start_adr + input->length(),
output,
true);
CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
CHECK_EQ(0, output[0]);
CHECK_EQ(12, output[1]);
CHECK_EQ(0, output[2]);
@ -1102,11 +1051,11 @@ TEST(MacroAssemblerIA32BackRefNoCase) {
TEST(MacroAssemblerIA32Registers) {
TEST(MacroAssemblerNativeRegisters) {
v8::V8::Initialize();
ContextInitializer initializer;
RegExpMacroAssemblerIA32 m(RegExpMacroAssemblerIA32::ASCII, 5);
ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::ASCII, 5);
uc16 foo_chars[3] = {'f', 'o', 'o'};
Vector<const uc16> foo(foo_chars, 3);
@ -1184,8 +1133,8 @@ TEST(MacroAssemblerIA32Registers) {
Address start_adr = seq_input->GetCharsAddress();
int output[5];
RegExpMacroAssemblerIA32::Result result =
ExecuteIA32(*code,
NativeRegExpMacroAssembler::Result result =
Execute(*code,
*input,
0,
start_adr,
@ -1193,7 +1142,7 @@ TEST(MacroAssemblerIA32Registers) {
output,
true);
CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
CHECK_EQ(0, output[0]);
CHECK_EQ(3, output[1]);
CHECK_EQ(6, output[2]);
@ -1202,11 +1151,11 @@ TEST(MacroAssemblerIA32Registers) {
}
TEST(MacroAssemblerIA32StackOverflow) {
TEST(MacroAssemblerStackOverflow) {
v8::V8::Initialize();
ContextInitializer initializer;
RegExpMacroAssemblerIA32 m(RegExpMacroAssemblerIA32::ASCII, 0);
ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::ASCII, 0);
Label loop;
m.Bind(&loop);
@ -1224,26 +1173,26 @@ TEST(MacroAssemblerIA32StackOverflow) {
Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
Address start_adr = seq_input->GetCharsAddress();
RegExpMacroAssemblerIA32::Result result =
ExecuteIA32(*code,
*input,
0,
start_adr,
start_adr + input->length(),
NULL,
true);
NativeRegExpMacroAssembler::Result result =
Execute(*code,
*input,
0,
start_adr,
start_adr + input->length(),
NULL,
true);
CHECK_EQ(RegExpMacroAssemblerIA32::EXCEPTION, result);
CHECK_EQ(NativeRegExpMacroAssembler::EXCEPTION, result);
CHECK(Top::has_pending_exception());
Top::clear_pending_exception();
}
TEST(MacroAssemblerIA32LotsOfRegisters) {
TEST(MacroAssemblerNativeLotsOfRegisters) {
v8::V8::Initialize();
ContextInitializer initializer;
RegExpMacroAssemblerIA32 m(RegExpMacroAssemblerIA32::ASCII, 2);
ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::ASCII, 2);
// At least 2048, to ensure the allocated space for registers
// span one full page.
@ -1270,24 +1219,88 @@ TEST(MacroAssemblerIA32LotsOfRegisters) {
Address start_adr = seq_input->GetCharsAddress();
int captures[2];
RegExpMacroAssemblerIA32::Result result =
ExecuteIA32(*code,
*input,
0,
start_adr,
start_adr + input->length(),
captures,
true);
NativeRegExpMacroAssembler::Result result =
Execute(*code,
*input,
0,
start_adr,
start_adr + input->length(),
captures,
true);
CHECK_EQ(RegExpMacroAssemblerIA32::SUCCESS, result);
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
CHECK_EQ(0, captures[0]);
CHECK_EQ(42, captures[1]);
Top::clear_pending_exception();
}
#endif // V8_REGEXP_NATIVE
#endif // V8_TARGET_ARCH_IA32
#else // ! V8_REGEX_NATIVE
TEST(MacroAssembler) {
V8::Initialize(NULL);
byte codes[1024];
RegExpMacroAssemblerIrregexp m(Vector<byte>(codes, 1024));
// ^f(o)o.
Label fail, fail2, start;
uc16 foo_chars[3];
foo_chars[0] = 'f';
foo_chars[1] = 'o';
foo_chars[2] = 'o';
Vector<const uc16> foo(foo_chars, 3);
m.SetRegister(4, 42);
m.PushRegister(4, RegExpMacroAssembler::kNoStackLimitCheck);
m.AdvanceRegister(4, 42);
m.GoTo(&start);
m.Fail();
m.Bind(&start);
m.PushBacktrack(&fail2);
m.CheckCharacters(foo, 0, &fail, true);
m.WriteCurrentPositionToRegister(0, 0);
m.PushCurrentPosition();
m.AdvanceCurrentPosition(3);
m.WriteCurrentPositionToRegister(1, 0);
m.PopCurrentPosition();
m.AdvanceCurrentPosition(1);
m.WriteCurrentPositionToRegister(2, 0);
m.AdvanceCurrentPosition(1);
m.WriteCurrentPositionToRegister(3, 0);
m.Succeed();
m.Bind(&fail);
m.Backtrack();
m.Succeed();
m.Bind(&fail2);
m.PopRegister(0);
m.Fail();
v8::HandleScope scope;
Handle<String> source = Factory::NewStringFromAscii(CStrVector("^f(o)o"));
Handle<ByteArray> array = Handle<ByteArray>::cast(m.GetCode(source));
int captures[5];
const uc16 str1[] = {'f', 'o', 'o', 'b', 'a', 'r'};
Handle<String> f1_16 =
Factory::NewStringFromTwoByte(Vector<const uc16>(str1, 6));
CHECK(IrregexpInterpreter::Match(array, f1_16, captures, 0));
CHECK_EQ(0, captures[0]);
CHECK_EQ(3, captures[1]);
CHECK_EQ(1, captures[2]);
CHECK_EQ(2, captures[3]);
CHECK_EQ(84, captures[4]);
const uc16 str2[] = {'b', 'a', 'r', 'f', 'o', 'o'};
Handle<String> f2_16 =
Factory::NewStringFromTwoByte(Vector<const uc16>(str2, 6));
CHECK(!IrregexpInterpreter::Match(array, f2_16, captures, 0));
CHECK_EQ(42, captures[0]);
}
#endif // ! V8_REGEXP_NATIVE
TEST(AddInverseToTable) {

View File

@ -103,22 +103,24 @@ function testStrippedCustomError() {
// Utility function for testing that the expected strings occur
// in the stack trace produced when running the given function.
function testTrace(fun, expected, unexpected) {
function testTrace(name, fun, expected, unexpected) {
var threw = false;
try {
fun();
} catch (e) {
for (var i = 0; i < expected.length; i++) {
assertTrue(e.stack.indexOf(expected[i]) != -1);
assertTrue(e.stack.indexOf(expected[i]) != -1,
name + " doesn't contain expected[" + i + "]");
}
if (unexpected) {
for (var i = 0; i < unexpected.length; i++) {
assertEquals(e.stack.indexOf(unexpected[i]), -1);
assertEquals(e.stack.indexOf(unexpected[i]), -1,
name + " contains unexpected[" + i + "]");
}
}
threw = true;
}
assertTrue(threw);
assertTrue(threw, name + " didn't throw");
}
// Test that the error constructor is not shown in the trace
@ -127,10 +129,11 @@ function testCallerCensorship() {
try {
FAIL;
} catch (e) {
assertEquals(-1, e.stack.indexOf('at new ReferenceError'));
assertEquals(-1, e.stack.indexOf('at new ReferenceError'),
"CallerCensorship contained new ReferenceError");
threw = true;
}
assertTrue(threw);
assertTrue(threw, "CallerCensorship didn't throw");
}
// Test that the explicit constructor call is shown in the trace
@ -143,10 +146,11 @@ function testUnintendedCallerCensorship() {
}
});
} catch (e) {
assertTrue(e.stack.indexOf('at new ReferenceError') != -1);
assertTrue(e.stack.indexOf('at new ReferenceError') != -1,
"UnintendedCallerCensorship didn't contain new ReferenceError");
threw = true;
}
assertTrue(threw);
assertTrue(threw, "UnintendedCallerCensorship didn't throw");
}
// If an error occurs while the stack trace is being formatted it should
@ -161,9 +165,10 @@ function testErrorsDuringFormatting() {
n.foo();
} catch (e) {
threw = true;
assertTrue(e.stack.indexOf('<error: ReferenceError') != -1);
assertTrue(e.stack.indexOf('<error: ReferenceError') != -1,
"ErrorsDuringFormatting didn't contain error: ReferenceError");
}
assertTrue(threw);
assertTrue(threw, "ErrorsDuringFormatting didn't throw");
threw = false;
// Now we can't even format the message saying that we couldn't format
// the stack frame. Put that in your pipe and smoke it!
@ -172,26 +177,28 @@ function testErrorsDuringFormatting() {
n.foo();
} catch (e) {
threw = true;
assertTrue(e.stack.indexOf('<error>') != -1);
assertTrue(e.stack.indexOf('<error>') != -1,
"ErrorsDuringFormatting didn't contain <error>");
}
assertTrue(threw);
assertTrue(threw, "ErrorsDuringFormatting didnt' throw (2)");
}
testTrace(testArrayNative, ["Array.map (native)"]);
testTrace(testNested, ["at one", "at two", "at three"]);
testTrace(testMethodNameInference, ["at Foo.bar"]);
testTrace(testImplicitConversion, ["at Nirk.valueOf"]);
testTrace(testEval, ["at Doo (eval at testEval"]);
testTrace(testNestedEval, ["eval at Inner (eval at Outer"]);
testTrace(testValue, ["at Number.causeError"]);
testTrace(testConstructor, ["new Plonk"]);
testTrace(testRenamedMethod, ["Wookie.a$b$c$d [as d]"]);
testTrace(testAnonymousMethod, ["Array.<anonymous>"]);
testTrace(testDefaultCustomError, ["hep-hey", "new CustomError"],
["collectStackTrace"]);
testTrace(testStrippedCustomError, ["hep-hey"], ["new CustomError",
"collectStackTrace"]);
testTrace("testArrayNative", testArrayNative, ["Array.map (native)"]);
testTrace("testNested", testNested, ["at one", "at two", "at three"]);
testTrace("testMethodNameInference", testMethodNameInference, ["at Foo.bar"]);
testTrace("testImplicitConversion", testImplicitConversion, ["at Nirk.valueOf"]);
testTrace("testEval", testEval, ["at Doo (eval at testEval"]);
testTrace("testNestedEval", testNestedEval, ["eval at Inner (eval at Outer"]);
testTrace("testValue", testValue, ["at Number.causeError"]);
testTrace("testConstructor", testConstructor, ["new Plonk"]);
testTrace("testRenamedMethod", testRenamedMethod, ["Wookie.a$b$c$d [as d]"]);
testTrace("testAnonymousMethod", testAnonymousMethod, ["Array.<anonymous>"]);
testTrace("testDefaultCustomError", testDefaultCustomError,
["hep-hey", "new CustomError"],
["collectStackTrace"]);
testTrace("testStrippedCustomError", testStrippedCustomError, ["hep-hey"],
["new CustomError", "collectStackTrace"]);
testCallerCensorship();
testUnintendedCallerCensorship();
testErrorsDuringFormatting();

View File

@ -803,10 +803,3 @@ ecma/Expressions/11.7.3: SKIP
ecma/Expressions/11.10-3: SKIP
ecma/Expressions/11.7.1: SKIP
ecma_3/RegExp/regress-209067: SKIP
[ $ARCH == x64 ]
# Tests that fail on the 64-bit port. This section should be empty
# when the 64-bit port is fully debugged.
js1_2/regexp/regress-9141: FAIL

View File

@ -32,6 +32,7 @@
'gcc_version%': 'unknown',
'target_arch%': 'ia32',
'v8_use_snapshot%': 'true',
'v8_regexp%': 'native',
},
'includes': [
'../../../build/common.gypi',
@ -55,6 +56,7 @@
['target_arch=="x64"', {
'defines': [
'V8_TARGET_ARCH_X64',
'V8_NATIVE_REGEXP',
],
}],
],
@ -428,14 +430,18 @@
'../../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=="x32" 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',
@ -457,14 +463,18 @@
'../../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': [