2008-11-25 11:07:48 +00:00
|
|
|
// 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"
|
2008-12-05 09:18:55 +00:00
|
|
|
#include "unicode.h"
|
2008-11-25 11:07:48 +00:00
|
|
|
#include "log.h"
|
|
|
|
#include "ast.h"
|
|
|
|
#include "macro-assembler.h"
|
2008-11-26 13:54:08 +00:00
|
|
|
#include "regexp-macro-assembler.h"
|
|
|
|
#include "macro-assembler-ia32.h"
|
2008-11-25 11:07:48 +00:00
|
|
|
#include "regexp-macro-assembler-ia32.h"
|
|
|
|
|
|
|
|
namespace v8 { namespace internal {
|
2008-11-26 13:54:08 +00:00
|
|
|
|
2008-11-25 11:07:48 +00:00
|
|
|
/*
|
|
|
|
* This assembler uses the following register assignment convention
|
2008-11-25 13:13:02 +00:00
|
|
|
* - edx : current character. Must be loaded using LoadCurrentCharacter
|
|
|
|
* before using any of the dispatch methods.
|
2008-11-25 11:07:48 +00:00
|
|
|
* - edi : current position in input, as negative offset from end of string.
|
2008-11-25 13:13:02 +00:00
|
|
|
* Please notice that this is the byte offset, not the character offset!
|
2008-11-25 11:07:48 +00:00
|
|
|
* - 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:
|
2008-12-01 09:57:14 +00:00
|
|
|
* - at_start (if 1, start at start of string, if 0, don't)
|
2008-11-25 11:07:48 +00:00
|
|
|
* - 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
|
2008-12-01 09:57:14 +00:00
|
|
|
* - backup of ebx
|
2008-11-25 11:07:48 +00:00
|
|
|
* ebp-> - old ebp
|
2008-11-25 13:13:02 +00:00
|
|
|
* - register 0 ebp[-4] (Only positions must be stored in the first
|
|
|
|
* - register 1 ebp[-8] num_saved_registers_ registers)
|
2008-11-25 11:07:48 +00:00
|
|
|
* - ...
|
|
|
|
*
|
2008-11-25 13:13:02 +00:00
|
|
|
* The first num_saved_registers_ registers are initialized to point to
|
|
|
|
* "character -1" in the string (i.e., char_size() bytes before the first
|
|
|
|
* 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 as cast to:
|
2008-11-25 11:07:48 +00:00
|
|
|
* bool (*match)(String** string_base,
|
|
|
|
* int start_offset,
|
|
|
|
* int end_offset,
|
2008-12-01 09:57:14 +00:00
|
|
|
* int* capture_output_array,
|
|
|
|
* bool at_start)
|
2008-11-25 11:07:48 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#define __ masm_->
|
|
|
|
|
|
|
|
RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32(
|
|
|
|
Mode mode,
|
2008-11-25 13:13:02 +00:00
|
|
|
int registers_to_save)
|
2008-11-26 11:29:26 +00:00
|
|
|
: masm_(new MacroAssembler(NULL, kRegExpCodeSize)),
|
|
|
|
constants_(kRegExpConstantsSize),
|
|
|
|
mode_(mode),
|
|
|
|
num_registers_(registers_to_save),
|
|
|
|
num_saved_registers_(registers_to_save),
|
|
|
|
entry_label_(),
|
|
|
|
start_label_(),
|
|
|
|
success_label_(),
|
2008-12-19 12:08:29 +00:00
|
|
|
backtrack_label_(),
|
2008-11-26 11:29:26 +00:00
|
|
|
exit_label_(),
|
|
|
|
self_(Heap::undefined_value()) {
|
2008-11-25 11:07:48 +00:00
|
|
|
__ 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();
|
2008-12-19 12:08:29 +00:00
|
|
|
backtrack_label_.Unuse();
|
2008-11-25 11:07:48 +00:00
|
|
|
exit_label_.Unuse();
|
2008-12-12 10:49:00 +00:00
|
|
|
check_preempt_label_.Unuse();
|
2008-11-25 11:07:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RegExpMacroAssemblerIA32::AdvanceCurrentPosition(int by) {
|
2008-12-08 12:43:01 +00:00
|
|
|
if (by != 0) {
|
|
|
|
Label inside_string;
|
|
|
|
__ add(Operand(edi), Immediate(by * char_size()));
|
|
|
|
}
|
2008-11-25 11:07:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RegExpMacroAssemblerIA32::AdvanceRegister(int reg, int by) {
|
|
|
|
ASSERT(reg >= 0);
|
|
|
|
ASSERT(reg < num_registers_);
|
|
|
|
__ add(register_location(reg), Immediate(by));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RegExpMacroAssemblerIA32::Backtrack() {
|
2008-12-12 10:49:00 +00:00
|
|
|
SafeReturn();
|
2008-11-25 11:07:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RegExpMacroAssemblerIA32::Bind(Label* label) {
|
|
|
|
__ bind(label);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RegExpMacroAssemblerIA32::CheckBitmap(uc16 start,
|
|
|
|
Label* bitmap,
|
|
|
|
Label* on_zero) {
|
2008-12-08 12:43:01 +00:00
|
|
|
UNIMPLEMENTED();
|
2008-12-01 09:57:14 +00:00
|
|
|
__ mov(eax, current_character());
|
2008-11-25 11:07:48 +00:00
|
|
|
__ 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);
|
2008-12-08 10:33:10 +00:00
|
|
|
BranchOrBacktrack(carry, on_zero);
|
2008-11-25 11:07:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-19 12:02:34 +00:00
|
|
|
void RegExpMacroAssemblerIA32::CheckCharacter(uint32_t c, Label* on_equal) {
|
2008-12-01 09:57:14 +00:00
|
|
|
__ cmp(current_character(), c);
|
2008-11-25 11:07:48 +00:00
|
|
|
BranchOrBacktrack(equal, on_equal);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RegExpMacroAssemblerIA32::CheckCharacterGT(uc16 limit, Label* on_greater) {
|
2008-12-01 09:57:14 +00:00
|
|
|
__ cmp(current_character(), limit);
|
2008-11-25 11:07:48 +00:00
|
|
|
BranchOrBacktrack(greater, on_greater);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-11-28 11:48:22 +00:00
|
|
|
void RegExpMacroAssemblerIA32::CheckNotAtStart(Label* on_not_at_start) {
|
2008-12-01 09:57:14 +00:00
|
|
|
__ 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);
|
2008-11-28 11:48:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-11-25 11:07:48 +00:00
|
|
|
void RegExpMacroAssemblerIA32::CheckCharacterLT(uc16 limit, Label* on_less) {
|
2008-12-01 09:57:14 +00:00
|
|
|
__ cmp(current_character(), limit);
|
2008-11-25 11:07:48 +00:00
|
|
|
BranchOrBacktrack(less, on_less);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RegExpMacroAssemblerIA32::CheckCharacters(Vector<const uc16> str,
|
|
|
|
int cp_offset,
|
2008-12-08 09:22:12 +00:00
|
|
|
Label* on_failure,
|
|
|
|
bool check_end_of_string) {
|
2008-11-25 11:07:48 +00:00
|
|
|
int byte_length = str.length() * char_size();
|
2008-11-25 13:13:02 +00:00
|
|
|
int byte_offset = cp_offset * char_size();
|
2008-12-08 09:22:12 +00:00
|
|
|
if (check_end_of_string) {
|
|
|
|
__ cmp(Operand(edi), Immediate(-(byte_offset + byte_length)));
|
|
|
|
BranchOrBacktrack(greater, on_failure);
|
|
|
|
}
|
2008-12-01 09:57:14 +00:00
|
|
|
|
2008-12-16 14:21:00 +00:00
|
|
|
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;
|
2008-12-01 09:57:14 +00:00
|
|
|
}
|
2008-11-25 11:07:48 +00:00
|
|
|
|
2008-12-16 14:21:00 +00:00
|
|
|
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]));
|
2008-11-25 11:07:48 +00:00
|
|
|
}
|
2008-12-16 14:21:00 +00:00
|
|
|
BranchOrBacktrack(not_equal, on_failure);
|
2008-11-25 11:07:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-08 09:22:12 +00:00
|
|
|
void RegExpMacroAssemblerIA32::CheckGreedyLoop(Label* on_equal) {
|
|
|
|
Label fallthrough;
|
|
|
|
__ cmp(edi, Operand(esp, 0));
|
|
|
|
__ j(not_equal, &fallthrough);
|
|
|
|
__ add(Operand(esp), Immediate(4)); // Pop.
|
|
|
|
BranchOrBacktrack(no_condition, on_equal);
|
|
|
|
__ bind(&fallthrough);
|
2008-11-25 11:07:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-11-27 07:27:08 +00:00
|
|
|
void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase(
|
2008-12-05 09:18:55 +00:00
|
|
|
int start_reg,
|
|
|
|
Label* on_no_match) {
|
2008-12-01 09:57:14 +00:00
|
|
|
Label fallthrough;
|
2008-12-16 14:21:00 +00:00
|
|
|
__ mov(edx, register_location(start_reg));
|
2008-12-01 09:57:14 +00:00
|
|
|
__ mov(ecx, register_location(start_reg + 1));
|
2008-12-16 14:21:00 +00:00
|
|
|
__ sub(ecx, Operand(edx)); // Length to check.
|
2008-12-05 09:18:55 +00:00
|
|
|
BranchOrBacktrack(less, on_no_match);
|
2008-12-01 09:57:14 +00:00
|
|
|
__ j(equal, &fallthrough);
|
|
|
|
|
2008-12-05 09:18:55 +00:00
|
|
|
if (mode_ == ASCII) {
|
|
|
|
Label success;
|
|
|
|
Label fail;
|
2008-12-16 14:21:00 +00:00
|
|
|
Label loop_increment;
|
2008-12-05 09:18:55 +00:00
|
|
|
__ push(edi);
|
2008-12-16 14:21:00 +00:00
|
|
|
__ add(edx, Operand(esi));
|
2008-12-05 09:18:55 +00:00
|
|
|
__ add(edi, Operand(esi));
|
2008-12-16 14:21:00 +00:00
|
|
|
__ add(ecx, Operand(edi));
|
|
|
|
|
2008-12-05 09:18:55 +00:00
|
|
|
Label loop;
|
|
|
|
__ bind(&loop);
|
2008-12-16 14:21:00 +00:00
|
|
|
__ movzx_b(eax, Operand(edi, 0));
|
|
|
|
__ cmpb_al(Operand(edx, 0));
|
|
|
|
__ j(equal, &loop_increment);
|
|
|
|
|
2008-12-05 09:18:55 +00:00
|
|
|
// Compare lower-case if letters.
|
2008-12-16 14:21:00 +00:00
|
|
|
__ or_(eax, 0x20); // To lower-case.
|
2008-12-05 09:18:55 +00:00
|
|
|
__ lea(ebx, Operand(eax, -'a'));
|
|
|
|
__ cmp(ebx, static_cast<int32_t>('z' - 'a'));
|
|
|
|
__ j(above, &fail);
|
2008-12-16 14:21:00 +00:00
|
|
|
__ movzx_b(ebx, Operand(edx, 0));
|
2008-12-05 09:18:55 +00:00
|
|
|
__ or_(ebx, 0x20); // To-lower-case
|
|
|
|
__ cmp(eax, Operand(ebx));
|
|
|
|
__ j(not_equal, &fail);
|
2008-12-16 14:21:00 +00:00
|
|
|
|
|
|
|
__ bind(&loop_increment);
|
|
|
|
__ add(Operand(edx), Immediate(1));
|
|
|
|
__ add(Operand(edi), Immediate(1));
|
|
|
|
__ cmp(edi, Operand(ecx));
|
|
|
|
__ j(below, &loop, taken);
|
2008-12-05 09:18:55 +00:00
|
|
|
__ jmp(&success);
|
|
|
|
|
|
|
|
__ bind(&fail);
|
|
|
|
__ pop(edi);
|
|
|
|
BranchOrBacktrack(no_condition, on_no_match);
|
|
|
|
|
|
|
|
__ bind(&success);
|
|
|
|
__ pop(eax); // discard original value of edi
|
|
|
|
__ sub(edi, Operand(esi));
|
|
|
|
} else {
|
2008-12-12 10:49:00 +00:00
|
|
|
ASSERT(mode_ == UC16);
|
2008-12-05 09:18:55 +00:00
|
|
|
__ push(esi);
|
|
|
|
__ push(edi);
|
|
|
|
__ push(ecx);
|
2008-12-12 10:49:00 +00:00
|
|
|
const int four_arguments = 4;
|
|
|
|
FrameAlign(four_arguments);
|
2008-12-05 09:18:55 +00:00
|
|
|
// Put arguments on stack.
|
|
|
|
__ mov(Operand(esp, 3 * kPointerSize), ecx);
|
|
|
|
__ mov(ebx, Operand(ebp, kInputEndOffset));
|
|
|
|
__ add(edi, Operand(ebx));
|
|
|
|
__ mov(Operand(esp, 2 * kPointerSize), edi);
|
|
|
|
__ add(eax, Operand(ebx));
|
|
|
|
__ mov(Operand(esp, 1 * kPointerSize), eax);
|
|
|
|
__ mov(eax, Operand(ebp, kInputBuffer));
|
|
|
|
__ mov(Operand(esp, 0 * kPointerSize), eax);
|
|
|
|
Address function_address = FUNCTION_ADDR(&CaseInsensitiveCompareUC16);
|
2008-12-12 10:49:00 +00:00
|
|
|
CallCFunction(function_address, four_arguments);
|
2008-12-05 09:18:55 +00:00
|
|
|
__ pop(ecx);
|
|
|
|
__ pop(edi);
|
|
|
|
__ pop(esi);
|
2008-12-12 10:49:00 +00:00
|
|
|
|
2008-12-05 09:18:55 +00:00
|
|
|
__ or_(eax, Operand(eax));
|
|
|
|
BranchOrBacktrack(zero, on_no_match);
|
|
|
|
__ add(edi, Operand(ecx));
|
|
|
|
}
|
2008-12-01 09:57:14 +00:00
|
|
|
__ bind(&fallthrough);
|
2008-11-25 11:39:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-11-25 11:07:48 +00:00
|
|
|
void RegExpMacroAssemblerIA32::CheckNotBackReference(
|
2008-12-05 09:18:55 +00:00
|
|
|
int start_reg,
|
|
|
|
Label* on_no_match) {
|
2008-11-25 11:07:48 +00:00
|
|
|
Label fallthrough;
|
2008-12-16 14:21:00 +00:00
|
|
|
Label success;
|
|
|
|
Label fail;
|
|
|
|
__ mov(edx, register_location(start_reg));
|
2008-11-25 11:07:48 +00:00
|
|
|
__ mov(ecx, register_location(start_reg + 1));
|
2008-12-16 14:21:00 +00:00
|
|
|
__ sub(ecx, Operand(edx)); // Length to check.
|
2008-12-03 13:24:34 +00:00
|
|
|
BranchOrBacktrack(less, on_no_match);
|
2008-12-01 09:57:14 +00:00
|
|
|
__ j(equal, &fallthrough);
|
2008-12-03 13:24:34 +00:00
|
|
|
// Check that there are sufficient characters left in the input.
|
2008-12-16 14:21:00 +00:00
|
|
|
|
2008-12-01 09:57:14 +00:00
|
|
|
__ mov(ebx, edi);
|
|
|
|
__ add(ebx, Operand(ecx));
|
2008-12-03 13:24:34 +00:00
|
|
|
BranchOrBacktrack(greater, on_no_match);
|
|
|
|
|
|
|
|
__ mov(ebx, edi);
|
2008-11-25 11:07:48 +00:00
|
|
|
__ add(edi, Operand(esi));
|
2008-12-16 14:21:00 +00:00
|
|
|
__ add(edx, Operand(esi));
|
|
|
|
__ add(ecx, Operand(edi));
|
|
|
|
|
|
|
|
Label loop;
|
|
|
|
__ bind(&loop);
|
|
|
|
if (mode_ == ASCII) {
|
|
|
|
__ movzx_b(eax, Operand(edx, 0));
|
|
|
|
__ cmpb_al(Operand(edi, 0));
|
|
|
|
} else {
|
|
|
|
ASSERT(mode_ == UC16);
|
|
|
|
__ movzx_w(eax, Operand(edx, 0));
|
|
|
|
__ cmpw_ax(Operand(edi, 0));
|
|
|
|
}
|
|
|
|
__ j(not_equal, &fail);
|
|
|
|
__ add(Operand(edx), Immediate(char_size()));
|
|
|
|
__ add(Operand(edi), Immediate(char_size()));
|
|
|
|
__ cmp(edi, Operand(ecx));
|
|
|
|
__ j(below, &loop);
|
|
|
|
__ jmp(&success);
|
|
|
|
|
|
|
|
__ bind(&fail);
|
2008-12-03 13:24:34 +00:00
|
|
|
__ mov(edi, ebx);
|
|
|
|
BranchOrBacktrack(no_condition, on_no_match);
|
|
|
|
|
|
|
|
__ bind(&success);
|
|
|
|
__ sub(edi, Operand(esi));
|
2008-11-25 11:07:48 +00:00
|
|
|
__ bind(&fallthrough);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-11-28 08:53:53 +00:00
|
|
|
void RegExpMacroAssemblerIA32::CheckNotRegistersEqual(int reg1,
|
|
|
|
int reg2,
|
|
|
|
Label* on_not_equal) {
|
|
|
|
__ mov(eax, register_location(reg1));
|
2008-12-01 09:57:14 +00:00
|
|
|
__ cmp(eax, register_location(reg2));
|
2008-11-28 08:53:53 +00:00
|
|
|
BranchOrBacktrack(not_equal, on_not_equal);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-19 12:02:34 +00:00
|
|
|
void RegExpMacroAssemblerIA32::CheckNotCharacter(uint32_t c,
|
|
|
|
Label* on_not_equal) {
|
2008-12-01 09:57:14 +00:00
|
|
|
__ cmp(current_character(), c);
|
2008-11-25 11:07:48 +00:00
|
|
|
BranchOrBacktrack(not_equal, on_not_equal);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-19 12:02:34 +00:00
|
|
|
void RegExpMacroAssemblerIA32::CheckCharacterAfterAnd(uint32_t c,
|
|
|
|
uint32_t mask,
|
|
|
|
Label* on_equal) {
|
2008-12-01 09:57:14 +00:00
|
|
|
__ mov(eax, current_character());
|
2008-12-19 12:02:34 +00:00
|
|
|
__ and_(eax, mask);
|
|
|
|
__ cmp(eax, c);
|
|
|
|
BranchOrBacktrack(equal, on_equal);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RegExpMacroAssemblerIA32::CheckNotCharacterAfterAnd(uint32_t c,
|
|
|
|
uint32_t mask,
|
|
|
|
Label* on_not_equal) {
|
|
|
|
__ mov(eax, current_character());
|
|
|
|
__ and_(eax, mask);
|
2008-11-25 11:07:48 +00:00
|
|
|
__ cmp(eax, c);
|
|
|
|
BranchOrBacktrack(not_equal, on_not_equal);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-19 12:02:34 +00:00
|
|
|
void RegExpMacroAssemblerIA32::CheckNotCharacterAfterMinusAnd(
|
2008-11-25 11:07:48 +00:00
|
|
|
uc16 c,
|
2008-12-19 12:02:34 +00:00
|
|
|
uc16 minus,
|
2008-11-25 11:07:48 +00:00
|
|
|
uc16 mask,
|
|
|
|
Label* on_not_equal) {
|
2008-12-19 12:02:34 +00:00
|
|
|
ASSERT(minus < String::kMaxUC16CharCode);
|
|
|
|
__ lea(eax, Operand(current_character(), -minus));
|
|
|
|
__ and_(eax, mask);
|
2008-11-25 11:07:48 +00:00
|
|
|
__ cmp(eax, c);
|
|
|
|
BranchOrBacktrack(not_equal, on_not_equal);
|
|
|
|
}
|
|
|
|
|
2009-01-02 12:23:17 +00:00
|
|
|
bool RegExpMacroAssemblerIA32::CheckSpecialCharacterClass(uc16 type,
|
|
|
|
int cp_offset,
|
|
|
|
bool check_offset,
|
|
|
|
Label* on_no_match) {
|
|
|
|
// Range checks (c in min..max) are generally implemented by an unsigned
|
|
|
|
// (c - min) <= (max - min) check
|
|
|
|
switch (type) {
|
|
|
|
case 's':
|
|
|
|
// Match space-characters
|
|
|
|
if (mode_ == ASCII) {
|
|
|
|
// ASCII space characters are '\t'..'\r' and ' '.
|
|
|
|
if (check_offset) {
|
|
|
|
LoadCurrentCharacter(cp_offset, on_no_match);
|
|
|
|
} else {
|
|
|
|
LoadCurrentCharacterUnchecked(cp_offset, 1);
|
|
|
|
}
|
|
|
|
Label success;
|
|
|
|
__ cmp(current_character(), ' ');
|
|
|
|
__ j(equal, &success);
|
|
|
|
// Check range 0x09..0x0d
|
|
|
|
__ sub(Operand(current_character()), Immediate('\t'));
|
|
|
|
__ cmp(current_character(), '\r' - '\t');
|
|
|
|
BranchOrBacktrack(above_equal, on_no_match);
|
|
|
|
__ bind(&success);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
case 'S':
|
|
|
|
// Match non-space characters.
|
|
|
|
if (check_offset) {
|
|
|
|
LoadCurrentCharacter(cp_offset, on_no_match, 1);
|
|
|
|
} else {
|
|
|
|
LoadCurrentCharacterUnchecked(cp_offset, 1);
|
|
|
|
}
|
|
|
|
if (mode_ == ASCII) {
|
|
|
|
// ASCII space characters are '\t'..'\r' and ' '.
|
|
|
|
__ cmp(current_character(), ' ');
|
|
|
|
BranchOrBacktrack(equal, on_no_match);
|
|
|
|
__ sub(Operand(current_character()), Immediate('\t'));
|
|
|
|
__ cmp(current_character(), '\r' - '\t');
|
|
|
|
BranchOrBacktrack(below, on_no_match);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
case 'd':
|
|
|
|
// Match ASCII digits ('0'..'9')
|
|
|
|
if (check_offset) {
|
|
|
|
LoadCurrentCharacter(cp_offset, on_no_match, 1);
|
|
|
|
} else {
|
|
|
|
LoadCurrentCharacterUnchecked(cp_offset, 1);
|
|
|
|
}
|
|
|
|
__ sub(Operand(current_character()), Immediate('0'));
|
|
|
|
__ cmp(current_character(), '9' - '0');
|
|
|
|
BranchOrBacktrack(greater_equal, on_no_match);
|
|
|
|
return true;
|
|
|
|
case 'D':
|
|
|
|
// Match non ASCII-digits
|
|
|
|
if (check_offset) {
|
|
|
|
LoadCurrentCharacter(cp_offset, on_no_match, 1);
|
|
|
|
} else {
|
|
|
|
LoadCurrentCharacterUnchecked(cp_offset, 1);
|
|
|
|
}
|
|
|
|
__ sub(Operand(current_character()), Immediate('0'));
|
|
|
|
__ cmp(current_character(), '9' - '0');
|
|
|
|
BranchOrBacktrack(below, on_no_match);
|
|
|
|
return true;
|
|
|
|
case '.': {
|
|
|
|
// Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
|
|
|
|
if (check_offset) {
|
|
|
|
LoadCurrentCharacter(cp_offset, on_no_match, 1);
|
|
|
|
} else {
|
|
|
|
LoadCurrentCharacterUnchecked(cp_offset, 1);
|
|
|
|
}
|
|
|
|
// Compute hash value so exactly 0x0a and 0x0d become zero.
|
|
|
|
__ sub(Operand(current_character()), Immediate('\n'));
|
|
|
|
__ mov(eax, current_character());
|
|
|
|
__ and_(current_character(), 0x01);
|
|
|
|
__ shr(eax, 1);
|
|
|
|
__ xor_(current_character(), Operand(eax));
|
|
|
|
BranchOrBacktrack(equal, on_no_match);
|
|
|
|
if (mode_ == UC16) {
|
|
|
|
// Compare original value to 0x2028 and 0x2029, using the already
|
|
|
|
// computed ((current_char - '\n') >> 1) in eax.
|
|
|
|
__ cmp(eax, (0x2028 - '\n') >> 1);
|
|
|
|
BranchOrBacktrack(equal, on_no_match);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case '*':
|
|
|
|
// Match any character.
|
|
|
|
if (check_offset) {
|
|
|
|
CheckPosition(cp_offset, on_no_match);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
// No custom implementation (yet): w, W, s(UC16), S(UC16).
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2008-11-25 11:07:48 +00:00
|
|
|
|
|
|
|
void RegExpMacroAssemblerIA32::DispatchHalfNibbleMap(
|
|
|
|
uc16 start,
|
|
|
|
Label* half_nibble_map,
|
|
|
|
const Vector<Label*>& destinations) {
|
2008-12-01 09:57:14 +00:00
|
|
|
UNIMPLEMENTED();
|
|
|
|
__ mov(eax, current_character());
|
2008-11-25 11:07:48 +00:00
|
|
|
__ 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) {
|
2008-12-01 09:57:14 +00:00
|
|
|
UNIMPLEMENTED();
|
|
|
|
|
2008-11-25 11:07:48 +00:00
|
|
|
Label fallthrough;
|
2008-12-01 09:57:14 +00:00
|
|
|
__ mov(eax, current_character());
|
2008-11-25 11:07:48 +00:00
|
|
|
__ sub(Operand(eax), Immediate(start));
|
|
|
|
__ cmp(eax, 64); // FIXME: 64 = size of map. Found somehow??
|
|
|
|
__ j(greater_equal, &fallthrough);
|
2008-11-25 13:13:02 +00:00
|
|
|
// TODO(lrn): ecx must hold address of map
|
2008-11-25 11:07:48 +00:00
|
|
|
__ 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) {
|
2008-12-01 09:57:14 +00:00
|
|
|
UNIMPLEMENTED();
|
2008-11-25 13:13:02 +00:00
|
|
|
|
2008-11-25 11:07:48 +00:00
|
|
|
Label fallthrough;
|
2008-12-01 09:57:14 +00:00
|
|
|
__ mov(eax, current_character());
|
2008-11-25 11:07:48 +00:00
|
|
|
__ 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) {
|
2008-12-01 09:57:14 +00:00
|
|
|
UNIMPLEMENTED(); // Has no use.
|
2008-11-25 11:07:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RegExpMacroAssemblerIA32::Fail() {
|
2008-11-25 13:13:02 +00:00
|
|
|
__ xor_(eax, Operand(eax)); // zero eax.
|
2008-11-25 11:07:48 +00:00
|
|
|
__ jmp(&exit_label_);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-08 09:22:12 +00:00
|
|
|
Handle<Object> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
|
2008-11-25 11:07:48 +00:00
|
|
|
// Finalize code - write the entry point code now we know how many
|
|
|
|
// registers we need.
|
|
|
|
|
|
|
|
// Entry code:
|
|
|
|
__ bind(&entry_label_);
|
2008-11-27 09:27:30 +00:00
|
|
|
// Save callee-save registers. Order here should correspond to order of
|
|
|
|
// kBackup_ebx etc.
|
2008-11-25 11:07:48 +00:00
|
|
|
__ push(esi);
|
|
|
|
__ push(edi);
|
2008-11-27 09:27:30 +00:00
|
|
|
__ push(ebx); // Callee-save on MacOS.
|
2008-11-26 13:54:08 +00:00
|
|
|
__ enter(Immediate(num_registers_ * kPointerSize));
|
2008-11-27 09:27:30 +00:00
|
|
|
// Load string length.
|
2008-11-25 11:07:48 +00:00
|
|
|
__ mov(esi, Operand(ebp, kInputEndOffset));
|
2008-11-27 09:27:30 +00:00
|
|
|
// Load input position.
|
2008-11-25 11:07:48 +00:00
|
|
|
__ mov(edi, Operand(ebp, kInputStartOffset));
|
2008-11-27 09:27:30 +00:00
|
|
|
// Set up edi to be negative offset from string end.
|
2008-11-25 11:07:48 +00:00
|
|
|
__ sub(edi, Operand(esi));
|
2008-11-27 09:27:30 +00:00
|
|
|
// Set up esi to be end of string. First get location.
|
2008-11-25 11:07:48 +00:00
|
|
|
__ mov(edx, Operand(ebp, kInputBuffer));
|
2008-11-27 09:27:30 +00:00
|
|
|
// Dereference location to get string start.
|
2008-11-25 11:07:48 +00:00
|
|
|
__ mov(edx, Operand(edx, 0));
|
2008-11-27 09:27:30 +00:00
|
|
|
// Add start to length to complete esi setup.
|
2008-11-25 11:07:48 +00:00
|
|
|
__ add(esi, Operand(edx));
|
2008-11-25 13:13:02 +00:00
|
|
|
if (num_saved_registers_ > 0) {
|
|
|
|
// Fill saved registers with initial value = start offset - 1
|
|
|
|
__ mov(ecx, -num_saved_registers_);
|
|
|
|
__ mov(eax, Operand(edi));
|
|
|
|
__ sub(Operand(eax), Immediate(char_size()));
|
|
|
|
Label init_loop;
|
|
|
|
__ bind(&init_loop);
|
|
|
|
__ mov(Operand(ebp, ecx, times_4, +0), eax);
|
|
|
|
__ inc(ecx);
|
|
|
|
__ j(not_equal, &init_loop);
|
|
|
|
}
|
2008-12-01 09:57:14 +00:00
|
|
|
// Load previous char as initial value of current-character.
|
|
|
|
Label at_start;
|
|
|
|
__ cmp(Operand(ebp, kAtStart), Immediate(0));
|
|
|
|
__ j(not_equal, &at_start);
|
2008-12-19 12:02:34 +00:00
|
|
|
LoadCurrentCharacterUnchecked(-1, 1); // Load previous char.
|
2008-12-01 09:57:14 +00:00
|
|
|
__ jmp(&start_label_);
|
|
|
|
__ bind(&at_start);
|
|
|
|
__ mov(current_character(), '\n');
|
2008-11-25 11:07:48 +00:00
|
|
|
__ jmp(&start_label_);
|
|
|
|
|
2008-12-01 09:57:14 +00:00
|
|
|
|
2008-11-25 11:07:48 +00:00
|
|
|
// Exit code:
|
2008-12-12 10:49:00 +00:00
|
|
|
if (success_label_.is_linked()) {
|
|
|
|
// Success
|
|
|
|
__ bind(&success_label_);
|
|
|
|
if (num_saved_registers_ > 0) {
|
|
|
|
// copy captures to output
|
|
|
|
__ 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));
|
|
|
|
__ add(eax, Operand(ecx)); // Convert to index from start, not end.
|
|
|
|
if (mode_ == UC16) {
|
|
|
|
__ sar(eax, 1); // Convert byte index to character index.
|
|
|
|
}
|
|
|
|
__ mov(Operand(ebx, i * kPointerSize), eax);
|
2008-11-25 13:13:02 +00:00
|
|
|
}
|
|
|
|
}
|
2008-12-12 10:49:00 +00:00
|
|
|
__ mov(eax, Immediate(1));
|
2008-11-25 11:07:48 +00:00
|
|
|
}
|
2008-12-01 09:57:14 +00:00
|
|
|
// Exit and return eax
|
2008-11-25 11:07:48 +00:00
|
|
|
__ bind(&exit_label_);
|
|
|
|
__ leave();
|
2008-11-27 09:27:30 +00:00
|
|
|
__ pop(ebx);
|
2008-11-25 11:07:48 +00:00
|
|
|
__ pop(edi);
|
|
|
|
__ pop(esi);
|
|
|
|
__ ret(0);
|
|
|
|
|
2008-12-19 12:08:29 +00:00
|
|
|
// Backtrack code (branch target for conditional backtracks).
|
|
|
|
if (backtrack_label_.is_linked()) {
|
|
|
|
__ bind(&backtrack_label_);
|
|
|
|
Backtrack();
|
|
|
|
}
|
|
|
|
|
2008-12-12 10:49:00 +00:00
|
|
|
// Preempt-code
|
|
|
|
if (check_preempt_label_.is_linked()) {
|
|
|
|
__ bind(&check_preempt_label_);
|
|
|
|
// TODO(lrn): call C function to check the stack guard and return current
|
|
|
|
// stack state (0 = ok, positive = out of stack, negative = preempt).
|
|
|
|
// Then dispatch to an action depending on state, and loop.
|
|
|
|
__ push(edi);
|
|
|
|
|
|
|
|
Label retry;
|
|
|
|
Label stack_overflow;
|
|
|
|
|
|
|
|
__ bind(&retry);
|
|
|
|
int num_arguments = 2;
|
|
|
|
FrameAlign(num_arguments);
|
|
|
|
__ mov(Operand(esp, 1 * kPointerSize), Immediate(self_));
|
|
|
|
__ lea(eax, Operand(esp, -kPointerSize));
|
|
|
|
__ mov(Operand(esp, 0 * kPointerSize), eax);
|
|
|
|
CallCFunction(FUNCTION_ADDR(&CheckStackGuardState), num_arguments);
|
|
|
|
|
|
|
|
ExternalReference stack_guard_limit =
|
|
|
|
ExternalReference::address_of_stack_guard_limit();
|
|
|
|
|
|
|
|
__ or_(eax, Operand(eax));
|
|
|
|
__ j(not_equal, &stack_overflow);
|
|
|
|
|
|
|
|
__ cmp(esp, Operand::StaticVariable(stack_guard_limit));
|
|
|
|
__ j(below_equal, &retry);
|
|
|
|
|
|
|
|
__ pop(edi);
|
|
|
|
// String might have moved: Recompute esi from scratch.
|
|
|
|
__ mov(esi, Operand(esp, kInputBuffer));
|
|
|
|
__ mov(esi, Operand(esi, 0));
|
|
|
|
__ add(esi, Operand(esp, kInputEndOffset));
|
|
|
|
SafeReturn();
|
|
|
|
|
|
|
|
__ bind(&stack_overflow);
|
|
|
|
// Exit with result -1 to signal thrown exception.
|
|
|
|
__ mov(eax, -1);
|
|
|
|
__ jmp(&exit_label_);
|
|
|
|
}
|
|
|
|
|
2008-11-25 11:07:48 +00:00
|
|
|
CodeDesc code_desc;
|
|
|
|
masm_->GetCode(&code_desc);
|
|
|
|
Handle<Code> code = Factory::NewCode(code_desc,
|
|
|
|
NULL,
|
|
|
|
Code::ComputeFlags(Code::REGEXP),
|
|
|
|
self_);
|
2008-12-08 09:22:12 +00:00
|
|
|
LOG(CodeCreateEvent("RegExp", *code, *(source->ToCString())));
|
2008-11-25 11:07:48 +00:00
|
|
|
return Handle<Object>::cast(code);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RegExpMacroAssemblerIA32::GoTo(Label* to) {
|
2008-12-08 10:33:10 +00:00
|
|
|
BranchOrBacktrack(no_condition, to);
|
2008-11-25 11:07:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-08 12:40:47 +00:00
|
|
|
void RegExpMacroAssemblerIA32::IfRegisterEqPos(int reg,
|
|
|
|
Label* if_eq) {
|
|
|
|
__ cmp(edi, register_location(reg));
|
|
|
|
BranchOrBacktrack(equal, if_eq);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-11-25 11:07:48 +00:00
|
|
|
RegExpMacroAssembler::IrregexpImplementation
|
|
|
|
RegExpMacroAssemblerIA32::Implementation() {
|
|
|
|
return kIA32Implementation;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RegExpMacroAssemblerIA32::LoadCurrentCharacter(int cp_offset,
|
2008-12-19 12:02:34 +00:00
|
|
|
Label* on_end_of_input,
|
|
|
|
bool check_bounds,
|
|
|
|
int characters) {
|
2008-11-25 11:07:48 +00:00
|
|
|
ASSERT(cp_offset >= 0);
|
|
|
|
ASSERT(cp_offset < (1<<30)); // Be sane! (And ensure negation works)
|
2009-01-02 12:23:17 +00:00
|
|
|
CheckPosition(cp_offset + characters - 1, on_end_of_input);
|
2008-12-19 12:02:34 +00:00
|
|
|
LoadCurrentCharacterUnchecked(cp_offset, characters);
|
2008-11-25 11:07:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RegExpMacroAssemblerIA32::PopCurrentPosition() {
|
|
|
|
__ pop(edi);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RegExpMacroAssemblerIA32::PopRegister(int register_index) {
|
|
|
|
__ pop(register_location(register_index));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RegExpMacroAssemblerIA32::PushBacktrack(Label* label) {
|
2008-12-12 10:49:00 +00:00
|
|
|
__ push(Immediate::CodeRelativeOffset(label));
|
|
|
|
CheckStackLimit();
|
2008-11-25 11:07:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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) {
|
2008-11-25 13:13:02 +00:00
|
|
|
ASSERT(register_index >= num_saved_registers_); // Reserved for positions!
|
2008-11-25 11:07:48 +00:00
|
|
|
__ mov(register_location(register_index), Immediate(to));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RegExpMacroAssemblerIA32::Succeed() {
|
|
|
|
__ jmp(&success_label_);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-08 09:22:12 +00:00
|
|
|
void RegExpMacroAssemblerIA32::WriteCurrentPositionToRegister(int reg,
|
|
|
|
int cp_offset) {
|
|
|
|
if (cp_offset == 0) {
|
|
|
|
__ mov(register_location(reg), edi);
|
|
|
|
} else {
|
2008-12-08 10:33:10 +00:00
|
|
|
__ lea(eax, Operand(edi, cp_offset * char_size()));
|
2008-12-08 09:22:12 +00:00
|
|
|
__ mov(register_location(reg), eax);
|
|
|
|
}
|
2008-11-25 11:07:48 +00:00
|
|
|
}
|
|
|
|
|
2008-12-08 09:22:12 +00:00
|
|
|
|
2008-11-25 11:07:48 +00:00
|
|
|
void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) {
|
|
|
|
__ mov(register_location(reg), esp);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Private methods:
|
|
|
|
|
2008-12-05 09:18:55 +00:00
|
|
|
|
|
|
|
static unibrow::Mapping<unibrow::Ecma262Canonicalize> canonicalize;
|
|
|
|
|
|
|
|
|
|
|
|
int RegExpMacroAssemblerIA32::CaseInsensitiveCompareUC16(uc16** buffer,
|
|
|
|
int byte_offset1,
|
|
|
|
int byte_offset2,
|
|
|
|
size_t byte_length) {
|
2008-12-08 13:33:24 +00:00
|
|
|
// 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.
|
2008-12-05 09:18:55 +00:00
|
|
|
ASSERT(byte_length % 2 == 0);
|
|
|
|
Address buffer_address = reinterpret_cast<Address>(*buffer);
|
|
|
|
uc16* substring1 = reinterpret_cast<uc16*>(buffer_address + byte_offset1);
|
|
|
|
uc16* substring2 = reinterpret_cast<uc16*>(buffer_address + 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) {
|
|
|
|
canonicalize.get(c1, '\0', &c1);
|
|
|
|
if (c1 != c2) {
|
|
|
|
canonicalize.get(c2, '\0', &c2);
|
|
|
|
if (c1 != c2) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-12 10:49:00 +00:00
|
|
|
int RegExpMacroAssemblerIA32::CheckStackGuardState(Address return_address,
|
|
|
|
Code* re_code) {
|
|
|
|
if (StackGuard::IsStackOverflow()) {
|
|
|
|
Top::StackOverflow();
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If not real stack overflow the stack guard was used to interrupt
|
|
|
|
// execution for another purpose.
|
|
|
|
|
|
|
|
// Prepare for possible GC.
|
|
|
|
Handle<Code> code_handle(re_code);
|
|
|
|
#ifdef DEBUG
|
|
|
|
CHECK(re_code->instruction_start() <= return_address);
|
|
|
|
CHECK(return_address <=
|
|
|
|
re_code->instruction_start() + re_code->instruction_size());
|
|
|
|
#endif
|
|
|
|
|
|
|
|
Object* result = Execution::HandleStackGuardInterrupt();
|
|
|
|
|
|
|
|
if (*code_handle != re_code) { // Return address no longer valid
|
|
|
|
int delta = *code_handle - re_code;
|
|
|
|
*reinterpret_cast<int32_t*>(return_address) += delta;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result->IsException()) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-01 09:57:14 +00:00
|
|
|
Operand RegExpMacroAssemblerIA32::register_location(int register_index) {
|
2008-11-25 11:07:48 +00:00
|
|
|
ASSERT(register_index < (1<<30));
|
2008-12-01 09:57:14 +00:00
|
|
|
if (num_registers_ <= register_index) {
|
|
|
|
num_registers_ = register_index + 1;
|
|
|
|
}
|
2008-11-26 13:54:08 +00:00
|
|
|
return Operand(ebp, -(register_index + 1) * kPointerSize);
|
2008-11-25 11:07:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-01 09:57:14 +00:00
|
|
|
Register RegExpMacroAssemblerIA32::current_character() {
|
|
|
|
return edx;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-11-25 11:07:48 +00:00
|
|
|
size_t RegExpMacroAssemblerIA32::char_size() {
|
|
|
|
return static_cast<size_t>(mode_);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-02 12:23:17 +00:00
|
|
|
void RegExpMacroAssemblerIA32::CheckPosition(int cp_offset,
|
|
|
|
Label* on_outside_input) {
|
|
|
|
__ cmp(edi, -cp_offset * char_size());
|
|
|
|
BranchOrBacktrack(greater_equal, on_outside_input);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-11-25 11:07:48 +00:00
|
|
|
void RegExpMacroAssemblerIA32::BranchOrBacktrack(Condition condition,
|
|
|
|
Label* to) {
|
|
|
|
if (condition < 0) { // No condition
|
|
|
|
if (to == NULL) {
|
|
|
|
Backtrack();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
__ jmp(to);
|
|
|
|
return;
|
2008-11-25 13:13:02 +00:00
|
|
|
}
|
|
|
|
if (to == NULL) {
|
2008-12-19 12:08:29 +00:00
|
|
|
__ j(condition, &backtrack_label_);
|
2008-11-25 11:07:48 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
__ j(condition, to);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-12 10:49:00 +00:00
|
|
|
void RegExpMacroAssemblerIA32::SafeCall(Label* to) {
|
|
|
|
Label return_to;
|
|
|
|
__ push(Immediate::CodeRelativeOffset(&return_to));
|
|
|
|
__ jmp(to);
|
|
|
|
__ bind(&return_to);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RegExpMacroAssemblerIA32::SafeReturn() {
|
|
|
|
__ pop(ecx);
|
|
|
|
__ add(Operand(ecx), Immediate(self_));
|
|
|
|
__ jmp(Operand(ecx));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-11-25 13:13:02 +00:00
|
|
|
void RegExpMacroAssemblerIA32::CheckStackLimit() {
|
|
|
|
if (FLAG_check_stack) {
|
|
|
|
// Check for preemption first.
|
|
|
|
Label no_preempt;
|
|
|
|
// Check for preemption.
|
|
|
|
ExternalReference stack_guard_limit =
|
|
|
|
ExternalReference::address_of_stack_guard_limit();
|
|
|
|
__ cmp(esp, Operand::StaticVariable(stack_guard_limit));
|
|
|
|
__ j(above, &no_preempt, taken);
|
|
|
|
|
2008-12-12 10:49:00 +00:00
|
|
|
SafeCall(&check_preempt_label_);
|
2008-11-25 13:13:02 +00:00
|
|
|
|
|
|
|
__ bind(&no_preempt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-12 10:49:00 +00:00
|
|
|
void RegExpMacroAssemblerIA32::FrameAlign(int num_arguments) {
|
|
|
|
int frameAlignment = OS::ActivationFrameAlignment();
|
|
|
|
if (frameAlignment != 0) {
|
|
|
|
// Make stack end at alignment and make room for num_arguments words
|
|
|
|
// and the original value of esp.
|
|
|
|
__ mov(ebx, esp);
|
|
|
|
__ sub(Operand(esp), Immediate((num_arguments + 1) * kPointerSize));
|
|
|
|
ASSERT(IsPowerOf2(frameAlignment));
|
|
|
|
__ and_(esp, -frameAlignment);
|
|
|
|
__ mov(Operand(esp, num_arguments * kPointerSize), ebx);
|
|
|
|
} else {
|
|
|
|
__ sub(Operand(esp), Immediate(num_arguments * kPointerSize));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RegExpMacroAssemblerIA32::CallCFunction(Address function_address,
|
|
|
|
int num_arguments) {
|
|
|
|
__ mov(Operand(eax), Immediate(reinterpret_cast<int32_t>(function_address)));
|
|
|
|
__ call(Operand(eax));
|
|
|
|
if (OS::ActivationFrameAlignment() != 0) {
|
|
|
|
__ mov(esp, Operand(esp, num_arguments * kPointerSize));
|
|
|
|
} else {
|
|
|
|
__ add(Operand(esp), Immediate(num_arguments * sizeof(int32_t)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-12-19 12:02:34 +00:00
|
|
|
void RegExpMacroAssemblerIA32::LoadCurrentCharacterUnchecked(int cp_offset,
|
|
|
|
int characters) {
|
2008-11-25 11:07:48 +00:00
|
|
|
if (mode_ == ASCII) {
|
2008-12-19 12:02:34 +00:00
|
|
|
if (characters == 4) {
|
|
|
|
__ mov(current_character(), Operand(esi, edi, times_1, cp_offset));
|
|
|
|
} else if (characters == 2) {
|
|
|
|
__ movzx_w(current_character(), Operand(esi, edi, times_1, cp_offset));
|
|
|
|
} else {
|
|
|
|
ASSERT(characters == 1);
|
|
|
|
__ movzx_b(current_character(), Operand(esi, edi, times_1, cp_offset));
|
|
|
|
}
|
2008-12-12 10:49:00 +00:00
|
|
|
} else {
|
|
|
|
ASSERT(mode_ == UC16);
|
2008-12-19 12:02:34 +00:00
|
|
|
if (characters == 2) {
|
|
|
|
__ mov(current_character(),
|
|
|
|
Operand(esi, edi, times_1, cp_offset * sizeof(uc16)));
|
|
|
|
} else {
|
|
|
|
ASSERT(characters == 1);
|
|
|
|
__ movzx_w(current_character(),
|
|
|
|
Operand(esi, edi, times_1, cp_offset * sizeof(uc16)));
|
|
|
|
}
|
2008-11-25 11:07:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void RegExpMacroAssemblerIA32::LoadConstantBufferAddress(Register reg,
|
|
|
|
ArraySlice* buffer) {
|
|
|
|
__ mov(reg, buffer->array());
|
|
|
|
__ add(Operand(reg), Immediate(buffer->base_offset()));
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef __
|
2008-11-26 13:54:08 +00:00
|
|
|
}} // namespace v8::internal
|