*
* Each call to a public method should retain this convention.
* The stack will have the following structure:
+ * - at_start (if 1, start at start of string, if 0, don't)
* - int* capture_array (int[num_saved_registers_], for output).
* - end of input (index of end of string, relative to *string_base)
* - start of input (index of first character in string, relative
* - return address
* - backup of esi
* - backup of edi
+ * - backup of ebx
* ebp-> - old ebp
* - register 0 ebp[-4] (Only positions must be stored in the first
* - register 1 ebp[-8] num_saved_registers_ registers)
* bool (*match)(String** string_base,
* int start_offset,
* int end_offset,
- * int* capture_output_array)
+ * int* capture_output_array,
+ * bool at_start)
*/
#define __ masm_->
Label* bitmap,
Label* on_zero) {
UNREACHABLE();
- ReadCurrentChar(eax);
+ __ mov(eax, current_character());
__ sub(Operand(eax), Immediate(start));
__ cmp(eax, 64); // FIXME: 64 = length_of_bitmap_in_bits.
BranchOrBacktrack(greater_equal, on_zero);
void RegExpMacroAssemblerIA32::CheckCharacter(uc16 c, Label* on_equal) {
- __ cmp(edx, c);
+ __ cmp(current_character(), c);
BranchOrBacktrack(equal, on_equal);
}
void RegExpMacroAssemblerIA32::CheckCharacterGT(uc16 limit, Label* on_greater) {
- __ cmp(edx, limit);
+ __ cmp(current_character(), limit);
BranchOrBacktrack(greater, on_greater);
}
void RegExpMacroAssemblerIA32::CheckNotAtStart(Label* on_not_at_start) {
- UNIMPLEMENTED();
+ __ cmp(Operand(ebp, kAtStart), Immediate(0));
+ BranchOrBacktrack(equal, on_not_at_start);
+ __ mov(eax, Operand(ebp, kInputEndOffset));
+ __ add(eax, Operand(edi));
+ __ cmp(eax, Operand(ebp, kInputStartOffset));
+ BranchOrBacktrack(not_equal, on_not_at_start);
}
void RegExpMacroAssemblerIA32::CheckCharacterLT(uc16 limit, Label* on_less) {
- __ cmp(edx, limit);
+ __ cmp(current_character(), limit);
BranchOrBacktrack(less, on_less);
}
Label* on_failure) {
int byte_length = str.length() * char_size();
int byte_offset = cp_offset * char_size();
- __ mov(ebx, edi);
- __ add(Operand(ebx), Immediate(byte_offset + byte_length));
- BranchOrBacktrack(greater_equal, on_failure);
+ __ cmp(Operand(edi), Immediate(-(byte_offset + byte_length)));
+ BranchOrBacktrack(greater, on_failure);
+
+ if (str.length() <= kMaxInlineStringTests) {
+ for (int i = 0; i < str.length(); i++) {
+ if (mode_ == ASCII) {
+ __ cmpb(Operand(esi, edi, times_1, byte_offset + i),
+ static_cast<int8_t>(str[i]));
+ } else {
+ ASSERT(mode_ == UC16);
+ __ cmpw(Operand(esi, edi, times_1, byte_offset + i * sizeof(uc16)),
+ Immediate(str[i]));
+ }
+ __ j(not_equal, on_failure);
+ }
+ return;
+ }
ArraySlice constant_buffer = constants_.GetBuffer(str.length(), char_size());
if (mode_ == ASCII) {
__ mov(ebx, esi);
__ lea(edi, Operand(esi, edi, times_1, byte_offset));
LoadConstantBufferAddress(esi, &constant_buffer);
- __ mov(ecx, str.length() * char_size());
- __ rep_cmpsb();
+ __ mov(ecx, str.length());
+ if (char_size() == 1) {
+ __ rep_cmpsb();
+ } else {
+ ASSERT(char_size() == 2);
+ __ rep_cmpsw();
+ }
__ mov(esi, ebx);
__ mov(edi, eax);
BranchOrBacktrack(not_equal, on_failure);
void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase(
int start_reg, Label* on_no_match) {
- UNIMPLEMENTED();
+ Label fallthrough;
+ __ mov(eax, register_location(start_reg));
+ __ mov(ecx, register_location(start_reg + 1));
+ __ sub(ecx, Operand(eax)); // Length to check.
+ __ j(less, on_no_match);
+ __ j(equal, &fallthrough);
+
+ UNIMPLEMENTED(); // TODO(lrn): Call runtime function to do test.
+
+ __ bind(&fallthrough);
}
__ mov(eax, register_location(start_reg));
__ mov(ecx, register_location(start_reg + 1));
__ sub(ecx, Operand(eax)); // Length to check.
- __ j(equal, &fallthrough); // Covers the case where it's not bound (-1,-1).
+ __ j(less, on_no_match);
+ __ j(equal, &fallthrough);
+ // check that there are sufficient characters left in the input
+ __ mov(ebx, edi);
+ __ add(ebx, Operand(ecx));
+ __ j(greater, on_no_match);
__ mov(ebx, Operand(edi));
__ push(esi);
__ add(edi, Operand(esi));
__ add(esi, Operand(eax));
- if (char_size() > 0) {
- ASSERT(char_size() == 2);
- __ add(ecx, Operand(ecx));
- }
__ rep_cmpsb();
__ pop(esi);
__ mov(edi, Operand(ebx));
int reg2,
Label* on_not_equal) {
__ mov(eax, register_location(reg1));
- __ mov(ecx, register_location(reg2));
- __ cmp(ecx, Operand(eax));
+ __ cmp(eax, register_location(reg2));
BranchOrBacktrack(not_equal, on_not_equal);
}
void RegExpMacroAssemblerIA32::CheckNotCharacter(uc16 c, Label* on_not_equal) {
- __ cmp(edx, c);
+ __ cmp(current_character(), c);
BranchOrBacktrack(not_equal, on_not_equal);
}
void RegExpMacroAssemblerIA32::CheckNotCharacterAfterOr(uc16 c,
uc16 mask,
Label* on_not_equal) {
- __ mov(eax, Operand(edx));
+ __ mov(eax, current_character());
__ or_(eax, mask);
__ cmp(eax, c);
BranchOrBacktrack(not_equal, on_not_equal);
uc16 c,
uc16 mask,
Label* on_not_equal) {
- __ lea(eax, Operand(edx, -mask));
+ __ lea(eax, Operand(current_character(), -mask));
__ or_(eax, mask);
__ cmp(eax, c);
BranchOrBacktrack(not_equal, on_not_equal);
uc16 start,
Label* half_nibble_map,
const Vector<Label*>& destinations) {
- ReadCurrentChar(eax);
+ UNIMPLEMENTED();
+ __ mov(eax, current_character());
__ sub(Operand(eax), Immediate(start));
__ mov(ecx, eax);
uc16 start,
Label* byte_map,
const Vector<Label*>& destinations) {
+ UNIMPLEMENTED();
+
Label fallthrough;
- ReadCurrentChar(eax);
+ __ mov(eax, current_character());
__ sub(Operand(eax), Immediate(start));
__ cmp(eax, 64); // FIXME: 64 = size of map. Found somehow??
__ j(greater_equal, &fallthrough);
byte start,
Label* byte_map,
const Vector<Label*>& destinations) {
- UNREACHABLE();
+ UNIMPLEMENTED();
Label fallthrough;
- ReadCurrentChar(eax);
+ __ mov(eax, current_character());
__ shr(eax, 8);
__ sub(Operand(eax), Immediate(start));
__ cmp(eax, destinations.length() - start);
void RegExpMacroAssemblerIA32::EmitOrLink(Label* label) {
- UNREACHABLE(); // Has no use.
+ UNIMPLEMENTED(); // Has no use.
}
__ inc(ecx);
__ j(not_equal, &init_loop);
}
+ // Load previous char as initial value of current-character.
+ Label at_start;
+ __ cmp(Operand(ebp, kAtStart), Immediate(0));
+ __ j(not_equal, &at_start);
+ LoadCurrentCharToRegister(-1); // Load previous char.
+ __ jmp(&start_label_);
+ __ bind(&at_start);
+ __ mov(current_character(), '\n');
__ jmp(&start_label_);
+
// Exit code:
+ // Success
__ bind(&success_label_);
if (num_saved_registers_ > 0) {
// copy captures to output
}
__ mov(eax, Immediate(1));
+ // Exit and return eax
__ bind(&exit_label_);
__ leave();
__ pop(ebx);
}
-
void RegExpMacroAssemblerIA32::IfRegisterGE(int reg,
int comparand,
Label* if_ge) {
}
-
void RegExpMacroAssemblerIA32::IfRegisterLT(int reg,
int comparand,
Label* if_lt) {
}
-
RegExpMacroAssembler::IrregexpImplementation
RegExpMacroAssemblerIA32::Implementation() {
return kIA32Implementation;
}
-
void RegExpMacroAssemblerIA32::LoadCurrentCharacter(int cp_offset,
Label* on_end_of_input) {
ASSERT(cp_offset >= 0);
ASSERT(cp_offset < (1<<30)); // Be sane! (And ensure negation works)
__ cmp(edi, -cp_offset * char_size());
BranchOrBacktrack(greater_equal, on_end_of_input);
- ReadChar(edx, cp_offset);
+ LoadCurrentCharToRegister(cp_offset);
}
void RegExpMacroAssemblerIA32::PopRegister(int register_index) {
- RecordRegister(register_index);
__ pop(register_location(register_index));
}
void RegExpMacroAssemblerIA32::SetRegister(int register_index, int to) {
ASSERT(register_index >= num_saved_registers_); // Reserved for positions!
- RecordRegister(register_index);
__ mov(register_location(register_index), Immediate(to));
}
}
-void RegExpMacroAssemblerIA32::WriteCurrentPositionToRegister(
- int register_index) {
- RecordRegister(register_index);
- __ mov(register_location(register_index), edi);
+void RegExpMacroAssemblerIA32::WriteCurrentPositionToRegister(int reg) {
+ __ mov(register_location(reg), edi);
}
void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) {
// Private methods:
-Operand RegExpMacroAssemblerIA32::register_location(
- int register_index) {
+Operand RegExpMacroAssemblerIA32::register_location(int register_index) {
ASSERT(register_index < (1<<30));
+ if (num_registers_ <= register_index) {
+ num_registers_ = register_index + 1;
+ }
return Operand(ebp, -(register_index + 1) * kPointerSize);
}
+Register RegExpMacroAssemblerIA32::current_character() {
+ return edx;
+}
+
+
size_t RegExpMacroAssemblerIA32::char_size() {
return static_cast<size_t>(mode_);
}
}
-void RegExpMacroAssemblerIA32::Canonicalize(Register reg) {
- if (mode_ == ASCII) {
- Label end;
- __ cmp(Operand(reg), Immediate('a'));
- __ j(below, &end);
- __ cmp(Operand(reg), Immediate('z'));
- __ j(above, &end);
- __ sub(Operand(reg), Immediate('a' - 'A'));
- __ bind(&end);
- return;
- }
- ASSERT(mode_ == UC16);
- // TODO(lrn): Use some tables.
-}
-
-
void RegExpMacroAssemblerIA32::CheckStackLimit() {
if (FLAG_check_stack) {
// Check for preemption first.
}
-void RegExpMacroAssemblerIA32::RecordRegister(int register_index) {
- if (register_index >= num_registers_) {
- num_registers_ = register_index + 1;
- }
-}
-
-
-void RegExpMacroAssemblerIA32::ReadChar(Register destination, int offset) {
+void RegExpMacroAssemblerIA32::LoadCurrentCharToRegister(int cp_offset) {
if (mode_ == ASCII) {
- __ movzx_b(destination, Operand(esi, edi, times_1, offset));
+ __ movzx_b(current_character(), Operand(esi, edi, times_1, cp_offset));
return;
}
ASSERT(mode_ == UC16);
- __ movzx_w(destination, Operand(esi, edi, times_1, offset * 2));
-}
-
-
-void RegExpMacroAssemblerIA32::ReadCurrentChar(Register destination) {
- __ mov(destination, edx);
+ __ movzx_w(current_character(),
+ Operand(esi, edi, times_1, cp_offset * sizeof(uc16)));
}
virtual void WriteCurrentPositionToRegister(int reg);
virtual void WriteStackPointerToRegister(int reg);
+ template <typename T>
+ static inline bool Execute(Code* code,
+ T** input,
+ int start_offset,
+ int end_offset,
+ int* output,
+ bool at_start) {
+ typedef bool (*matcher)(T**, int, int, int*, int);
+ matcher matcher_func = FUNCTION_CAST<matcher>(code->entry());
+ int at_start_val = at_start ? 1 : 0;
+ return matcher_func(input, start_offset, end_offset, output, at_start_val);
+ }
+
private:
// Offsets from ebp of arguments to function.
static const int kBackup_ebx = sizeof(uint32_t);
static const int kInputStartOffset = kInputBuffer + sizeof(uint32_t);
static const int kInputEndOffset = kInputStartOffset + sizeof(uint32_t);
static const int kRegisterOutput = kInputEndOffset + sizeof(uint32_t);
+ static const int kAtStart = kRegisterOutput + sizeof(uint32_t);
// Initial size of code buffer.
static const size_t kRegExpCodeSize = 1024;
// The ebp-relative location of a regexp register.
Operand register_location(int register_index);
+ // The register containing the current character after LoadCurrentCharacter.
+ Register current_character();
+
// Byte size of chars in the string to match (decided by the Mode argument)
size_t char_size();
- // Records that a register is used. At the end, we need the number of
- // registers used.
- void RecordRegister(int register_index);
-
// 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);
- // Generate code to perform case-canonicalization on the register.
- void Canonicalize(Register register);
-
// Read a character from input at the given offset from the current
// position.
- void ReadChar(Register destination, int offset);
+ void LoadCurrentCharToRegister(int cp_offset);
// 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);
- // Read the current character into the destination register.
- void ReadCurrentChar(Register destination);
-
// Adds code that checks whether preemption has been requested
// (and checks if we have hit the stack limit too).
void CheckStackLimit();
#ifndef ARM // IA32 only tests.
TEST(MacroAssemblerIA32Success) {
- typedef bool (*AsciiTest) (
- SeqAsciiString** base, int start_index, int end_index, int* captures);
-
V8::Initialize(NULL);
// regexp-macro-assembler-ia32 needs a handle scope to allocate
Handle<Object> code_object = m.GetCode();
Handle<Code> code = Handle<Code>::cast(code_object);
- AsciiTest test = FUNCTION_CAST<AsciiTest>(code->entry());
int captures[4] = {42, 37, 87, 117};
Handle<String> input = Factory::NewStringFromAscii(CStrVector("foofoo"));
int start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
int end_offset = start_offset + seq_input->length();
- bool success =
- test(seq_input.location(), start_offset, end_offset, captures);
+ bool success = RegExpMacroAssemblerIA32::Execute(*code,
+ seq_input.location(),
+ start_offset,
+ end_offset,
+ captures,
+ true);
CHECK(success);
CHECK_EQ(-1, captures[0]);
TEST(MacroAssemblerIA32Simple) {
- typedef bool (*AsciiTest) (
- SeqAsciiString** base, int start_index, int end_index, int* captures);
-
V8::Initialize(NULL);
// regexp-macro-assembler-ia32 needs a handle scope to allocate
Handle<Object> code_object = m.GetCode();
Handle<Code> code = Handle<Code>::cast(code_object);
- AsciiTest test = FUNCTION_CAST<AsciiTest>(code->entry());
int captures[4] = {42, 37, 87, 117};
Handle<String> input = Factory::NewStringFromAscii(CStrVector("foofoo"));
int start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
int end_offset = start_offset + seq_input->length();
- bool success =
- test(seq_input.location(), start_offset, end_offset, captures);
+ bool success = RegExpMacroAssemblerIA32::Execute(*code,
+ seq_input.location(),
+ start_offset,
+ end_offset,
+ captures,
+ true);
CHECK(success);
CHECK_EQ(0, captures[0]);
start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
end_offset = start_offset + seq_input->length();
- success = test(seq_input.location(), start_offset, end_offset, captures);
+ success = RegExpMacroAssemblerIA32::Execute(*code,
+ seq_input.location(),
+ start_offset,
+ end_offset,
+ captures,
+ true);
CHECK(!success);
}
TEST(MacroAssemblerIA32SimpleUC16) {
- typedef bool (*UC16Test) (
- SeqTwoByteString** base, int start_index, int end_index, int* captures);
-
V8::Initialize(NULL);
// regexp-macro-assembler-ia32 needs a handle scope to allocate
Handle<Object> code_object = m.GetCode();
Handle<Code> code = Handle<Code>::cast(code_object);
- UC16Test test = FUNCTION_CAST<UC16Test>(code->entry());
int captures[4] = {42, 37, 87, 117};
const uc16 input_data[6] = {'f', 'o', 'o', 'f', 'o', '\xa0'};
int start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
int end_offset = start_offset + seq_input->length() * sizeof(uc16);
- bool success =
- test(seq_input.location(), start_offset, end_offset, captures);
+ bool success = RegExpMacroAssemblerIA32::Execute(*code,
+ seq_input.location(),
+ start_offset,
+ end_offset,
+ captures,
+ true);
CHECK(success);
CHECK_EQ(0, captures[0]);
start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
end_offset = start_offset + seq_input->length() * sizeof(uc16);
- success = test(seq_input.location(), start_offset, end_offset, captures);
+ success = RegExpMacroAssemblerIA32::Execute(*code,
+ seq_input.location(),
+ start_offset,
+ end_offset,
+ captures,
+ true);
CHECK(!success);
}
TEST(MacroAssemblerIA32Backtrack) {
- typedef bool (*AsciiTest) (
- SeqAsciiString** base, int start_index, int end_index, int* captures);
-
V8::Initialize(NULL);
// regexp-macro-assembler-ia32 needs a handle scope to allocate
Handle<Object> code_object = m.GetCode();
Handle<Code> code = Handle<Code>::cast(code_object);
- AsciiTest test = FUNCTION_CAST<AsciiTest>(code->entry());
Handle<String> input = Factory::NewStringFromAscii(CStrVector("foofoo"));
Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
int start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
int end_offset = start_offset + seq_input->length();
- bool success =
- test(seq_input.location(), start_offset, end_offset, NULL);
+ bool success = RegExpMacroAssemblerIA32::Execute(*code,
+ seq_input.location(),
+ start_offset,
+ end_offset,
+ NULL,
+ true);
CHECK(!success);
}
+TEST(MacroAssemblerIA32AtStart) {
+ V8::Initialize(NULL);
+
+ // regexp-macro-assembler-ia32 needs a handle scope to allocate
+ // byte-arrays for constants.
+ v8::HandleScope scope;
-TEST(MacroAssemblerIA32Registers) {
- typedef bool (*AsciiTest) (
- SeqAsciiString** base, int start_index, int end_index, int* captures);
+ RegExpMacroAssemblerIA32 m(RegExpMacroAssemblerIA32::ASCII, 0);
+
+ uc16 foo_chars[3] = {'f', 'o', 'o'};
+ Vector<const uc16> foo(foo_chars, 3);
+
+ Label not_at_start, newline, fail;
+ m.CheckNotAtStart(¬_at_start);
+ // Check that prevchar = '\n' and current = 'f'.
+ m.CheckCharacter('\n', &newline);
+ m.Bind(&fail);
+ m.Fail();
+ m.Bind(&newline);
+ m.LoadCurrentCharacter(0, &fail);
+ m.CheckNotCharacter('f', &fail);
+ m.Succeed();
+ m.Bind(¬_at_start);
+ // Check that prevchar = 'o' and current = 'b'.
+ Label prevo;
+ m.CheckCharacter('o', &prevo);
+ m.Fail();
+ m.Bind(&prevo);
+ m.LoadCurrentCharacter(0, &fail);
+ m.CheckNotCharacter('b', &fail);
+ m.Succeed();
+
+ Handle<Object> code_object = m.GetCode();
+ Handle<Code> code = Handle<Code>::cast(code_object);
+
+ Handle<String> input = Factory::NewStringFromAscii(CStrVector("foobar"));
+ Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
+ Address start_adr = seq_input->GetCharsAddress();
+ int start_offset = start_adr - reinterpret_cast<Address>(*seq_input);
+ int end_offset = start_offset + seq_input->length();
+
+ bool success = RegExpMacroAssemblerIA32::Execute(*code,
+ seq_input.location(),
+ start_offset,
+ end_offset,
+ NULL,
+ true);
+
+ CHECK(success);
+
+ start_offset += 3;
+ success = RegExpMacroAssemblerIA32::Execute(*code,
+ seq_input.location(),
+ start_offset,
+ end_offset,
+ NULL,
+ false);
+
+ CHECK(success);
+}
+
+
+
+TEST(MacroAssemblerIA32Registers) {
V8::Initialize(NULL);
// regexp-macro-assembler-ia32 needs a handle scope to allocate
Handle<Object> code_object = m.GetCode();
Handle<Code> code = Handle<Code>::cast(code_object);
- AsciiTest test = FUNCTION_CAST<AsciiTest>(code->entry());
// String long enough for test (content doesn't matter).
Handle<String> input =
int end_offset = start_offset + seq_input->length();
int output[5];
- bool success =
- test(seq_input.location(), start_offset, end_offset, output);
+ bool success = RegExpMacroAssemblerIA32::Execute(*code,
+ seq_input.location(),
+ start_offset,
+ end_offset,
+ output,
+ true);
CHECK(success);
CHECK_EQ(0, output[0]);