Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(891)

Unified Diff: src/regexp-macro-assembler-ia32.cc

Issue 12427: Merge regexp2000 back into bleeding_edge (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 12 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/regexp-macro-assembler-ia32.cc
===================================================================
--- src/regexp-macro-assembler-ia32.cc (revision 0)
+++ src/regexp-macro-assembler-ia32.cc (revision 830)
@@ -0,0 +1,605 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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 "log.h"
+#include "ast.h"
+#include "macro-assembler.h"
+#include "regexp-macro-assembler-ia32.h"
+
+namespace v8 { namespace internal {
+/*
+ * This assembler uses the following register assignment convention
+ * - edx : current character, or kEndOfInput if current position is not
+ * inside string. The kEndOfInput value is greater than 0xffff,
+ * so any tests that don't check whether the current position
+ * is inside the correct range should retain bits above the
+ * 15th in their computations, and fail if the value is too
+ * great.
+ * - edi : current position in input, as negative offset from end of string.
+ * - esi : end of input (points to byte after last character in input).
+ * - ebp : points to the location above the registers on the stack,
+ * as if by the "enter <register_count>" opcode.
+ * - esp : points to tip of backtracking stack.
+ *
+ * The registers eax, ebx and ecx are free to use for computations.
+ *
+ * Each call to a public method should retain this convention.
+ * The stack will have the following structure:
+ * - 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
+ * to *string_base)
+ * - void** string_base (location of a handle containing the string)
+ * - return address
+ * - backup of esi
+ * - backup of edi
+ * ebp-> - old ebp
+ * - register 0 ebp[-4]
+ * - register 1 ebp[-8]
+ * - ...
+ *
+ * The data before ebp must be placed there by the calling code, e.g.,
+ * by calling the code as cast to:
+ * bool (*match)(String** string_base,
+ * int start_offset,
+ * int end_offset,
+ * int* capture_output_array)
+ */
+
+#define __ masm_->
+
+RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32(
+ Mode mode,
+ int registers_to_save,
+ bool ignore_case)
+ : masm_(new MacroAssembler(NULL, kRegExpCodeSize)),
Mads Ager (chromium) 2008/11/25 21:09:41 Guess what? :-)
+ constants_(kRegExpConstantsSize),
+ mode_(mode),
+ num_registers_(registers_to_save),
+ num_saved_registers_(registers_to_save),
+ ignore_case_(ignore_case),
+ entry_label_(),
+ start_label_(),
+ success_label_(),
+ exit_label_(),
+ self_(Heap::undefined_value()) {
+ __ jmp(&entry_label_); // We'll write the entry code later.
+ __ bind(&start_label_); // And then continue from here.
+}
+
+
+RegExpMacroAssemblerIA32::~RegExpMacroAssemblerIA32() {
+ delete masm_;
+ // Unuse labels in case we throw away the assembler without calling GetCode.
+ entry_label_.Unuse();
+ start_label_.Unuse();
+ success_label_.Unuse();
+ exit_label_.Unuse();
+}
+
+
+void RegExpMacroAssemblerIA32::AdvanceCurrentPosition(int by) {
+ ASSERT(by > 0);
+ Label inside_string;
+ __ add(Operand(edi), Immediate(by * char_size()));
+ __ j(below, &inside_string);
+ Backtrack();
+
+ __ bind(&inside_string);
+}
+
+
+void RegExpMacroAssemblerIA32::AdvanceRegister(int reg, int by) {
+ ASSERT(reg >= 0);
+ ASSERT(reg < num_registers_);
+ __ add(register_location(reg), Immediate(by));
+}
+
+
+void RegExpMacroAssemblerIA32::Backtrack() {
+ __ pop(ecx);
+ __ add(Operand(ecx), Immediate(self_));
+ __ jmp(Operand(ecx));
+}
+
+
+void RegExpMacroAssemblerIA32::Bind(Label* label) {
+ __ bind(label);
+}
+
+void RegExpMacroAssemblerIA32::CheckBitmap(uc16 start,
+ Label* bitmap,
+ Label* on_zero) {
+ ReadCurrentChar(eax);
+ __ sub(Operand(eax), Immediate(start));
+ __ cmp(eax, 64); // FIXME: 64 = length_of_bitmap_in_bits.
+ BranchOrBacktrack(greater_equal, on_zero);
+ __ mov(ebx, eax);
+ __ shr(ebx, 3);
+ // TODO(lrn): Where is the bitmap stored? Pass the bitmap as argument instead.
+ // __ mov(ecx, position_of_bitmap);
+ __ movzx_b(ebx, Operand(ecx, ebx, times_1, 0));
+ __ and_(eax, (1<<3)-1);
+ __ bt(Operand(ebx), eax);
+ __ j(carry, on_zero);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckCharacter(uc16 c, Label* on_equal) {
+ __ cmp(edx, c);
+ BranchOrBacktrack(equal, on_equal);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckCharacterGT(uc16 limit, Label* on_greater) {
+ __ cmp(edx, limit);
+ BranchOrBacktrack(greater, on_greater);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckCharacterLT(uc16 limit, Label* on_less) {
+ __ cmp(edx, limit);
+ BranchOrBacktrack(less, on_less);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckCharacters(Vector<const uc16> str,
+ int cp_offset,
+ Label* on_failure) {
+ int byte_length = str.length() * char_size();
+ int start_offset = cp_offset * char_size();
+ __ mov(ebx, edi);
+ __ add(Operand(ebx), Immediate(start_offset + byte_length));
+ BranchOrBacktrack(greater_equal, on_failure);
+
+ ArraySlice constant_buffer = constants_.GetBuffer(str.length(), char_size());
+ for (int i = 0; i < str.length(); i++) {
+ if (mode_ == ASCII) {
+ constant_buffer.at<char>(i) = static_cast<char>(str[i]);
+ } else {
+ memcpy(constant_buffer.location<void>(),
+ str.start(),
+ str.length() * sizeof(uc16));
+ }
+ }
+
+ __ mov(eax, edi);
+ __ mov(ebx, esi);
+ __ lea(edi, Operand(esi, edi, times_1, start_offset));
+ LoadConstantBufferAddress(esi, &constant_buffer);
+ __ mov(ecx, str.length());
+ if (mode_ == ASCII) {
+ __ rep_cmpsb();
+ } else {
+ ASSERT(mode_ == UC16);
+ __ rep_cmpsw();
+ }
+ __ mov(esi, ebx);
+ __ mov(edi, eax);
+ BranchOrBacktrack(not_equal, on_failure);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckCurrentPosition(int register_index,
+ Label* on_equal) {
+ __ cmp(edi, register_location(register_index));
+ BranchOrBacktrack(equal, on_equal);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckNotBackReference(
+ int start_reg, Label* on_no_match) {
+ if (ignore_case_) {
+ UNIMPLEMENTED();
+ }
+ Label 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).
+ __ mov(ebx, Operand(edi));
+ __ push(esi);
+ __ add(edi, Operand(esi));
+ __ add(esi, Operand(eax));
+ if (mode_ == ASCII) {
+ __ rep_cmpsb();
+ } else {
+ __ rep_cmpsw();
+ }
+ __ pop(esi);
+ __ mov(edi, Operand(ebx));
+ BranchOrBacktrack(not_equal, on_no_match);
+ __ bind(&fallthrough);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckNotCharacter(uc16 c, Label* on_not_equal) {
+ __ cmp(edx, c);
+ BranchOrBacktrack(not_equal, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckNotCharacterAfterOr(uc16 c,
+ uc16 mask,
+ Label* on_not_equal) {
+ __ mov(eax, Operand(edx));
+ __ or_(eax, mask);
+ __ cmp(eax, c);
+ BranchOrBacktrack(not_equal, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckNotCharacterAfterMinusOr(
+ uc16 c,
+ uc16 mask,
+ Label* on_not_equal) {
+ __ lea(eax, Operand(edx, -mask));
+ __ or_(eax, mask);
+ __ cmp(eax, c);
+ BranchOrBacktrack(not_equal, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerIA32::DispatchHalfNibbleMap(
+ uc16 start,
+ Label* half_nibble_map,
+ const Vector<Label*>& destinations) {
+ ReadCurrentChar(eax);
+ __ sub(Operand(eax), Immediate(start));
+
+ __ mov(ecx, eax);
+ __ shr(eax, 2);
+ // FIXME: ecx must hold address of map
+ __ movzx_b(eax, Operand(ecx, eax, times_1, 0));
+ __ and_(ecx, 0x03);
+ __ add(ecx, Operand(ecx));
+ __ shr(eax); // Shift right cl times
+
+ Label second_bit_set, case_3, case_1;
+ __ test(eax, Immediate(0x02));
+ __ j(not_zero, &second_bit_set);
+ __ test(eax, Immediate(0x01));
+ __ j(not_zero, &case_1);
+ // Case 0:
+ __ jmp(destinations[0]);
+ __ bind(&case_1);
+ // Case 1:
+ __ jmp(destinations[1]);
+ __ bind(&second_bit_set);
+ __ test(eax, Immediate(0x01));
+ __ j(not_zero, &case_3);
+ // Case 2
+ __ jmp(destinations[2]);
+ __ bind(&case_3);
+ // Case 3:
+ __ jmp(destinations[3]);
+}
+
+
+void RegExpMacroAssemblerIA32::DispatchByteMap(
+ uc16 start,
+ Label* byte_map,
+ const Vector<Label*>& destinations) {
+ Label fallthrough;
+ ReadCurrentChar(eax);
+ __ sub(Operand(eax), Immediate(start));
+ __ cmp(eax, 64); // FIXME: 64 = size of map. Found somehow??
+ __ j(greater_equal, &fallthrough);
+ // FIXME: ecx must hold address of map
+ __ movzx_b(eax, Operand(ecx, eax, times_1, 0));
+ // jump table: jump to destinations[eax];
+
+ __ bind(&fallthrough);
+}
+
+
+
+void RegExpMacroAssemblerIA32::DispatchHighByteMap(
+ byte start,
+ Label* byte_map,
+ const Vector<Label*>& destinations) {
+ Label fallthrough;
+ ReadCurrentChar(eax);
+ __ shr(eax, 8);
+ __ sub(Operand(eax), Immediate(start));
+ __ cmp(eax, destinations.length() - start);
+ __ j(greater_equal, &fallthrough);
+
+ // TODO(lrn) jumptable: jump to destinations[eax]
+ __ bind(&fallthrough);
+}
+
+
+void RegExpMacroAssemblerIA32::EmitOrLink(Label* label) {
+ UNREACHABLE(); // Has no use.
+}
+
+
+void RegExpMacroAssemblerIA32::Fail() {
+ __ mov(eax, 0);
+ __ jmp(&exit_label_);
+}
+
+
+Handle<Object> RegExpMacroAssemblerIA32::GetCode() {
+ // Finalize code - write the entry point code now we know how many
+ // registers we need.
+
+ // Entry code:
+ __ bind(&entry_label_);
+ __ push(esi);
+ __ push(edi);
+ __ enter(Immediate(num_registers_ * sizeof(uint32_t)));
+ __ mov(esi, Operand(ebp, kInputEndOffset));
+ __ mov(edi, Operand(ebp, kInputStartOffset));
+ __ sub(edi, Operand(esi));
+ __ mov(edx, Operand(ebp, kInputBuffer));
+ __ mov(edx, Operand(edx, 0));
+ __ add(esi, Operand(edx));
+ __ jmp(&start_label_);
+
+ // Exit code:
+ __ bind(&success_label_);
+ __ mov(ebx, Operand(ebp, kRegisterOutput));
+ __ mov(ecx, Operand(ebp, kInputEndOffset));
+ __ sub(ecx, Operand(ebp, kInputStartOffset));
+ for (int i = 0; i < num_saved_registers_; i++) {
+ __ mov(eax, register_location(i));
+ __ sub(eax, Operand(ecx)); // Convert to index from start, not end.
+ __ mov(Operand(ebx, i * sizeof(int32_t)), eax);
+ }
+ // copy captures to output
+ __ mov(eax, Immediate(1));
+
+ __ bind(&exit_label_);
+ __ leave();
+ __ pop(edi);
+ __ pop(esi);
+ __ ret(0);
+
+ CodeDesc code_desc;
+ masm_->GetCode(&code_desc);
+ Handle<Code> code = Factory::NewCode(code_desc,
+ NULL,
+ Code::ComputeFlags(Code::REGEXP),
+ self_);
+ LOG(CodeCreateEvent("RegExp", *code, "(Compiled RegExp)"));
+ return Handle<Object>::cast(code);
+}
+
+
+void RegExpMacroAssemblerIA32::GoTo(Label* to) {
+ __ jmp(to);
+}
+
+
+
+void RegExpMacroAssemblerIA32::IfRegisterGE(int reg,
+ int comparand,
+ Label* if_ge) {
+ __ cmp(register_location(reg), Immediate(comparand));
+ BranchOrBacktrack(greater_equal, if_ge);
+}
+
+
+
+void RegExpMacroAssemblerIA32::IfRegisterLT(int reg,
+ int comparand,
+ Label* if_lt) {
+ __ cmp(register_location(reg), Immediate(comparand));
+ BranchOrBacktrack(less, 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);
+ BranchOrBacktrack(less_equal, on_end_of_input);
+ ReadChar(edx, cp_offset);
+}
+
+
+void RegExpMacroAssemblerIA32::PopCurrentPosition() {
+ __ pop(edi);
+}
+
+
+void RegExpMacroAssemblerIA32::PopRegister(int register_index) {
+ RecordRegister(register_index);
+ __ pop(register_location(register_index));
+}
+
+
+void RegExpMacroAssemblerIA32::PushBacktrack(Label* label) {
+ // Check for preemption first.
+ Label no_preempt;
+ Label retry_preempt;
+ // Check for preemption.
+ ExternalReference stack_limit =
+ ExternalReference::address_of_stack_guard_limit();
+ __ cmp(esp, Operand::StaticVariable(stack_limit));
+ __ j(above, &no_preempt);
+
+ __ push(edi); // Current position.
+ __ push(edx); // Current character.
+ // Restore original edi, esi.
+ __ mov(edi, Operand(ebp, kBackup_edi));
+ __ mov(esi, Operand(ebp, kBackup_esi));
+
+ __ bind(&retry_preempt);
+ // simulate stack for Runtime call.
+ __ push(Immediate(0)); // Dummy receiver
+ __ CallRuntime(Runtime::kStackGuard, 0);
+ __ cmp(esp, Operand::StaticVariable(stack_limit));
+ __ j(below_equal, &retry_preempt);
+
+ __ pop(edx);
+ __ pop(edi);
+ __ mov(esi, Operand(ebp, kInputBuffer));
+ __ mov(esi, Operand(esi, 0));
+ __ add(esi, Operand(ebp, kInputEndOffset));
+
+ __ bind(&no_preempt);
+
+ Label cont;
+ __ push(label, RelocInfo::NONE);
+}
+
+
+void RegExpMacroAssemblerIA32::PushCurrentPosition() {
+ __ push(edi);
+}
+
+
+void RegExpMacroAssemblerIA32::PushRegister(int register_index) {
+ __ push(register_location(register_index));
+}
+
+
+void RegExpMacroAssemblerIA32::ReadCurrentPositionFromRegister(int reg) {
+ __ mov(edi, register_location(reg));
+}
+
+
+void RegExpMacroAssemblerIA32::ReadStackPointerFromRegister(int reg) {
+ __ mov(esp, register_location(reg));
+}
+
+
+void RegExpMacroAssemblerIA32::SetRegister(int register_index, int to) {
+ RecordRegister(register_index);
+ __ mov(register_location(register_index), Immediate(to));
+}
+
+
+void RegExpMacroAssemblerIA32::Succeed() {
+ __ jmp(&success_label_);
+}
+
+
+void RegExpMacroAssemblerIA32::WriteCurrentPositionToRegister(
+ int register_index) {
+ __ mov(register_location(register_index), edi);
+}
+
+void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) {
+ __ mov(register_location(reg), esp);
+}
+
+
+// Private methods:
+
+Operand RegExpMacroAssemblerIA32::register_location(
+ int register_index) {
+ ASSERT(register_index < (1<<30));
+ return Operand(ebp, -((register_index + 1) * sizeof(uint32_t)));
+}
+
+
+size_t RegExpMacroAssemblerIA32::char_size() {
+ return static_cast<size_t>(mode_);
+}
+
+
+void RegExpMacroAssemblerIA32::BranchOrBacktrack(Condition condition,
+ Label* to) {
+ if (condition < 0) { // No condition
+ if (to == NULL) {
+ Backtrack();
+ return;
+ }
+ __ jmp(to);
+ return;
+ } else if (to == NULL) {
+ Label skip;
+ __ j(NegateCondition(condition), &skip);
+ Backtrack();
+ __ bind(&skip);
+ return;
+ }
+ __ j(condition, to);
+}
+
+
+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::RecordRegister(int register_index) {
+ if (register_index >= num_registers_) {
+ num_registers_ = register_index + 1;
+ }
+}
+
+
+void RegExpMacroAssemblerIA32::ReadChar(Register destination, int offset) {
+ if (mode_ == ASCII) {
+ __ movzx_b(destination, Operand(esi, edi, times_1, offset));
+ return;
+ }
+ ASSERT(mode_ == UC16);
+ __ movzx_w(destination, Operand(esi, edi, times_1, offset * 2));
+}
+
+
+void RegExpMacroAssemblerIA32::ReadCurrentChar(Register destination) {
+ __ mov(destination, edx);
+}
+
+
+void RegExpMacroAssemblerIA32::LoadConstantBufferAddress(Register reg,
+ ArraySlice* buffer) {
+ __ mov(reg, buffer->array());
+ __ add(Operand(reg), Immediate(buffer->base_offset()));
+}
+
+#undef __
+}}

Powered by Google App Engine
This is Rietveld 408576698