'CPPDEFINES': ['ENABLE_LOGGING_AND_PROFILING'],
'CPPPATH': [join(root_dir, 'src')],
'regexp:native': {
- 'arch:ia32' : {
'CPPDEFINES': ['V8_NATIVE_REGEXP']
- },
- 'arch:x64' : {
- 'CPPDEFINES': ['V8_NATIVE_REGEXP']
- }
},
'mode:debug': {
'CPPDEFINES': ['V8_ENABLE_CHECKS']
'arm/register-allocator-arm.cc', 'arm/stub-cache-arm.cc',
'arm/virtual-frame-arm.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'
- ]
- },
+ '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'
+ ],
'simulator:arm': ['arm/simulator-arm.cc'],
'os:freebsd': ['platform-freebsd.cc', 'platform-posix.cc'],
'os:linux': ['platform-linux.cc', 'platform-posix.cc'],
if (buffer_space() <= kGap) {
GrowBuffer();
}
- if (pc_offset() > next_buffer_check_) {
+ if (pc_offset() >= next_buffer_check_) {
CheckConstPool(false, true);
}
}
int Assembler::target_at(int pos) {
Instr instr = instr_at(pos);
+ if ((instr & ~Imm24Mask) == 0) {
+ // Emitted label constant, not part of a branch.
+ return instr - (Code::kHeaderSize - kHeapObjectTag);
+ }
ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24
int imm26 = ((instr & Imm24Mask) << 8) >> 6;
if ((instr & CondMask) == nv && (instr & B24) != 0)
// blx uses bit 24 to encode bit 2 of imm26
imm26 += 2;
- return pos + 8 + imm26;
+ return pos + kPcLoadDelta + imm26;
}
void Assembler::target_at_put(int pos, int target_pos) {
- int imm26 = target_pos - pos - 8;
Instr instr = instr_at(pos);
+ if ((instr & ~Imm24Mask) == 0) {
+ ASSERT(target_pos == kEndOfChain || target_pos >= 0);
+ // Emitted label constant, not part of a branch.
+ // Make label relative to Code* of generated Code object.
+ instr_at_put(pos, target_pos + (Code::kHeaderSize - kHeapObjectTag));
+ return;
+ }
+ int imm26 = target_pos - (pos + kPcLoadDelta);
ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx imm24
if ((instr & CondMask) == nv) {
// blx uses bit 24 to encode bit 2 of imm26
while (l.is_linked()) {
PrintF("@ %d ", l.pos());
Instr instr = instr_at(l.pos());
- ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx
- int cond = instr & CondMask;
- const char* b;
- const char* c;
- if (cond == nv) {
- b = "blx";
- c = "";
+ if ((instr & ~Imm24Mask) == 0) {
+ PrintF("value\n");
} else {
- if ((instr & B24) != 0)
- b = "bl";
- else
- b = "b";
-
- switch (cond) {
- case eq: c = "eq"; break;
- case ne: c = "ne"; break;
- case hs: c = "hs"; break;
- case lo: c = "lo"; break;
- case mi: c = "mi"; break;
- case pl: c = "pl"; break;
- case vs: c = "vs"; break;
- case vc: c = "vc"; break;
- case hi: c = "hi"; break;
- case ls: c = "ls"; break;
- case ge: c = "ge"; break;
- case lt: c = "lt"; break;
- case gt: c = "gt"; break;
- case le: c = "le"; break;
- case al: c = ""; break;
- default:
- c = "";
- UNREACHABLE();
+ ASSERT((instr & 7*B25) == 5*B25); // b, bl, or blx
+ int cond = instr & CondMask;
+ const char* b;
+ const char* c;
+ if (cond == nv) {
+ b = "blx";
+ c = "";
+ } else {
+ if ((instr & B24) != 0)
+ b = "bl";
+ else
+ b = "b";
+
+ switch (cond) {
+ case eq: c = "eq"; break;
+ case ne: c = "ne"; break;
+ case hs: c = "hs"; break;
+ case lo: c = "lo"; break;
+ case mi: c = "mi"; break;
+ case pl: c = "pl"; break;
+ case vs: c = "vs"; break;
+ case vc: c = "vc"; break;
+ case hi: c = "hi"; break;
+ case ls: c = "ls"; break;
+ case ge: c = "ge"; break;
+ case lt: c = "lt"; break;
+ case gt: c = "gt"; break;
+ case le: c = "le"; break;
+ case al: c = ""; break;
+ default:
+ c = "";
+ UNREACHABLE();
+ }
}
+ PrintF("%s%s\n", b, c);
}
- PrintF("%s%s\n", b, c);
next(&l);
}
} else {
// Block the emission of the constant pool, since the branch instruction must
// be emitted at the pc offset recorded by the label
BlockConstPoolBefore(pc_offset() + kInstrSize);
+ return target_pos - (pc_offset() + kPcLoadDelta);
+}
- return target_pos - pc_offset() - 8;
+
+void Assembler::label_at_put(Label* L, int at_offset) {
+ int target_pos;
+ if (L->is_bound()) {
+ target_pos = L->pos();
+ } else {
+ if (L->is_linked()) {
+ target_pos = L->pos(); // L's link
+ } else {
+ target_pos = kEndOfChain;
+ }
+ L->link_to(at_offset);
+ instr_at_put(at_offset, target_pos + (Code::kHeaderSize - kHeapObjectTag));
+ }
}
#ifndef V8_ARM_ASSEMBLER_ARM_H_
#define V8_ARM_ASSEMBLER_ARM_H_
-
+#include <stdio.h>
#include "assembler.h"
namespace v8 {
enum Condition {
eq = 0 << 28, // Z set equal.
ne = 1 << 28, // Z clear not equal.
- cs = 2 << 28, // C set unsigned higher or same.
+ nz = 1 << 28, // Z clear not zero.
+ cs = 2 << 28, // C set carry set.
hs = 2 << 28, // C set unsigned higher or same.
- cc = 3 << 28, // C clear unsigned lower.
+ cc = 3 << 28, // C clear carry clear.
lo = 3 << 28, // C clear unsigned lower.
mi = 4 << 28, // N set negative.
pl = 5 << 28, // N clear positive or zero.
// Manages the jump elimination optimization if the second parameter is true.
int branch_offset(Label* L, bool jump_elimination_allowed);
+ // Puts a labels target address at the given position.
+ // The high 8 bits are set to zero.
+ void label_at_put(Label* L, int at_offset);
+
// Return the address in the constant pool of the code target address used by
// the branch/call instruction at pc.
INLINE(static Address target_address_address_at(Address pc));
// to jump to.
static const int kPatchReturnSequenceAddressOffset = 1;
+ // Difference between address of current opcode and value read from pc
+ // register.
+ static const int kPcLoadDelta = 8;
+
// ---------------------------------------------------------------------------
// Code generation
// Record reloc info for current pc_
void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
+
+ friend class RegExpMacroAssemblerARM;
};
} } // namespace v8::internal
__ str(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
} else {
AllocateHeapNumber(masm, &slow, r1, r2, r3);
- __ ldr(r2, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
- __ str(r2, FieldMemOperand(r1, HeapNumber::kMantissaOffset));
+ __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
__ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
+ __ str(r3, FieldMemOperand(r1, HeapNumber::kMantissaOffset));
__ eor(r2, r2, Operand(HeapNumber::kSignMask)); // Flip sign.
__ str(r2, FieldMemOperand(r1, HeapNumber::kExponentOffset));
__ mov(r0, Operand(r1));
void DecodeType5(Instr* instr);
void DecodeType6(Instr* instr);
void DecodeType7(Instr* instr);
+ void DecodeUnconditional(Instr* instr);
const disasm::NameConverter& converter_;
v8::internal::Vector<char> out_buffer_;
}
+void Decoder::DecodeUnconditional(Instr* instr) {
+ if (instr->Bits(7, 4) == 0xB && instr->Bits(27, 25) == 0 && instr->HasL()) {
+ Format(instr, "'memop'h'pu 'rd, ");
+ bool immediate = instr->HasB();
+ switch (instr->PUField()) {
+ case 0: {
+ // Post index, negative.
+ if (instr->HasW()) {
+ Unknown(instr);
+ break;
+ }
+ if (immediate) {
+ Format(instr, "['rn], #-'imm12");
+ } else {
+ Format(instr, "['rn], -'rm");
+ }
+ break;
+ }
+ case 1: {
+ // Post index, positive.
+ if (instr->HasW()) {
+ Unknown(instr);
+ break;
+ }
+ if (immediate) {
+ Format(instr, "['rn], #+'imm12");
+ } else {
+ Format(instr, "['rn], +'rm");
+ }
+ break;
+ }
+ case 2: {
+ // Pre index or offset, negative.
+ if (immediate) {
+ Format(instr, "['rn, #-'imm12]'w");
+ } else {
+ Format(instr, "['rn, -'rm]'w");
+ }
+ break;
+ }
+ case 3: {
+ // Pre index or offset, positive.
+ if (immediate) {
+ Format(instr, "['rn, #+'imm12]'w");
+ } else {
+ Format(instr, "['rn, +'rm]'w");
+ }
+ break;
+ }
+ default: {
+ // The PU field is a 2-bit field.
+ UNREACHABLE();
+ break;
+ }
+ }
+ return;
+ }
+ Format(instr, "break 'msg");
+}
+
+
// Disassemble the instruction at *instr_ptr into the output buffer.
int Decoder::InstructionDecode(byte* instr_ptr) {
Instr* instr = Instr::At(instr_ptr);
"%08x ",
instr->InstructionBits());
if (instr->ConditionField() == special_condition) {
- Format(instr, "break 'msg");
+ DecodeUnconditional(instr);
return Instr::kInstrSize;
}
switch (instr->TypeField()) {
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Copyright 2009 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:
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "v8.h"
+#include "unicode.h"
+#include "log.h"
#include "ast.h"
+#include "regexp-stack.h"
+#include "macro-assembler.h"
#include "regexp-macro-assembler.h"
+#include "arm/macro-assembler-arm.h"
#include "arm/regexp-macro-assembler-arm.h"
namespace v8 {
namespace internal {
-RegExpMacroAssemblerARM::RegExpMacroAssemblerARM() {
- UNIMPLEMENTED();
+#ifdef V8_NATIVE_REGEXP
+/*
+ * This assembler uses the following register assignment convention
+ * - r5 : Pointer to current code object (Code*) including heap object tag.
+ * - r6 : Current position in input, as negative offset from end of string.
+ * Please notice that this is the byte offset, not the character offset!
+ * - r7 : Currently loaded character. Must be loaded using
+ * LoadCurrentCharacter before using any of the dispatch methods.
+ * - r8 : points to tip of backtrack stack
+ * - r9 : Unused, might be used by C code and expected unchanged.
+ * - r10 : End of input (points to byte after last character in input).
+ * - r11 : Frame pointer. Used to access arguments, local variables and
+ * RegExp registers.
+ * - r12 : IP register, used by assembler. Very volatile.
+ * - r13/sp : points to tip of C stack.
+ *
+ * The remaining registers are free for computations.
+ *
+ * Each call to a public method should retain this convention.
+ * The stack will have the following structure:
+ * - 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)
+ * --- sp when called ---
+ * - link address
+ * - backup of registers r4..r11
+ * - int* capture_array (int[num_saved_registers_], for output).
+ * - end of input (Address of end of string)
+ * - start of input (Address of first character in string)
+ * --- frame pointer ----
+ * - void* input_string (location of a handle containing the string)
+ * - Offset of location before start of input (effectively character
+ * position -1). Used to initialize capture registers to a non-position.
+ * - register 0 (Only positions must be stored in the first
+ * - register 1 num_saved_registers_ registers)
+ * - ...
+ * - register num_registers-1
+ * --- sp ---
+ *
+ * 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 start out as garbage.
+ *
+ * The data up to the return address must be placed there by the calling
+ * code, by calling the code entry as cast to a function with the signature:
+ * int (*match)(String* input_string,
+ * Address start,
+ * Address end,
+ * int* capture_output_array,
+ * bool at_start,
+ * byte* stack_area_base)
+ * The call is performed by NativeRegExpMacroAssembler::Execute()
+ * (in regexp-macro-assembler.cc).
+ */
+
+#define __ ACCESS_MASM(masm_)
+
+RegExpMacroAssemblerARM::RegExpMacroAssemblerARM(
+ Mode mode,
+ int registers_to_save)
+ : masm_(new MacroAssembler(NULL, kRegExpCodeSize)),
+ mode_(mode),
+ num_registers_(registers_to_save),
+ num_saved_registers_(registers_to_save),
+ entry_label_(),
+ start_label_(),
+ success_label_(),
+ backtrack_label_(),
+ exit_label_() {
+ ASSERT_EQ(0, registers_to_save % 2);
+ __ jmp(&entry_label_); // We'll write the entry code later.
+ EmitBacktrackConstantPool();
+ __ bind(&start_label_); // And then continue from here.
}
-RegExpMacroAssemblerARM::~RegExpMacroAssemblerARM() {}
+RegExpMacroAssemblerARM::~RegExpMacroAssemblerARM() {
+ delete masm_;
+ // Unuse labels in case we throw away the assembler without calling GetCode.
+ entry_label_.Unuse();
+ start_label_.Unuse();
+ success_label_.Unuse();
+ backtrack_label_.Unuse();
+ exit_label_.Unuse();
+ check_preempt_label_.Unuse();
+ stack_overflow_label_.Unuse();
+}
-}} // namespace v8::internal
+int RegExpMacroAssemblerARM::stack_limit_slack() {
+ return RegExpStack::kStackLimitSlack;
+}
+
+
+bool RegExpMacroAssemblerARM::CanReadUnaligned() {
+#if V8_TARGET_CAN_READ_UNALIGNED
+ return true;
+#else
+ return false;
+#endif
+}
+
+
+void RegExpMacroAssemblerARM::AdvanceCurrentPosition(int by) {
+ if (by != 0) {
+ Label inside_string;
+ __ add(current_input_offset(),
+ current_input_offset(), Operand(by * char_size()));
+ }
+}
+
+
+void RegExpMacroAssemblerARM::AdvanceRegister(int reg, int by) {
+ ASSERT(reg >= 0);
+ ASSERT(reg < num_registers_);
+ if (by != 0) {
+ __ ldr(r0, register_location(reg));
+ __ add(r0, r0, Operand(by));
+ __ str(r0, register_location(reg));
+ }
+}
+
+
+void RegExpMacroAssemblerARM::Backtrack() {
+ CheckPreemption();
+ // Pop Code* offset from backtrack stack, add Code* and jump to location.
+ Pop(r0);
+ __ add(pc, r0, Operand(r5));
+}
+
+
+void RegExpMacroAssemblerARM::Bind(Label* label) {
+ __ bind(label);
+}
+
+
+void RegExpMacroAssemblerARM::CheckCharacter(uint32_t c, Label* on_equal) {
+ __ cmp(current_character(), Operand(c));
+ BranchOrBacktrack(eq, on_equal);
+}
+
+
+void RegExpMacroAssemblerARM::CheckCharacterGT(uc16 limit, Label* on_greater) {
+ __ cmp(current_character(), Operand(limit));
+ BranchOrBacktrack(gt, on_greater);
+}
+
+
+void RegExpMacroAssemblerARM::CheckAtStart(Label* on_at_start) {
+ Label not_at_start;
+ // Did we start the match at the start of the string at all?
+ __ ldr(r0, MemOperand(frame_pointer(), kAtStart));
+ __ cmp(r0, Operand(0));
+ BranchOrBacktrack(eq, ¬_at_start);
+
+ // If we did, are we still at the start of the input?
+ __ ldr(r1, MemOperand(frame_pointer(), kInputStart));
+ __ add(r0, end_of_input_address(), Operand(current_input_offset()));
+ __ cmp(r0, r1);
+ BranchOrBacktrack(eq, on_at_start);
+ __ bind(¬_at_start);
+}
+
+
+void RegExpMacroAssemblerARM::CheckNotAtStart(Label* on_not_at_start) {
+ // Did we start the match at the start of the string at all?
+ __ ldr(r0, MemOperand(frame_pointer(), kAtStart));
+ __ cmp(r0, Operand(0));
+ BranchOrBacktrack(eq, on_not_at_start);
+ // If we did, are we still at the start of the input?
+ __ ldr(r1, MemOperand(frame_pointer(), kInputStart));
+ __ add(r0, end_of_input_address(), Operand(current_input_offset()));
+ __ cmp(r0, r1);
+ BranchOrBacktrack(ne, on_not_at_start);
+}
+
+
+void RegExpMacroAssemblerARM::CheckCharacterLT(uc16 limit, Label* on_less) {
+ __ cmp(current_character(), Operand(limit));
+ BranchOrBacktrack(lt, on_less);
+}
+
+
+void RegExpMacroAssemblerARM::CheckCharacters(Vector<const uc16> str,
+ int cp_offset,
+ Label* on_failure,
+ bool check_end_of_string) {
+ int byte_length = str.length() * char_size();
+ int byte_offset = cp_offset * char_size();
+ if (check_end_of_string) {
+ // Check that there are at least str.length() characters left in the input.
+ __ cmp(end_of_input_address(), Operand(-(byte_offset + byte_length)));
+ BranchOrBacktrack(gt, on_failure);
+ }
+
+ if (on_failure == NULL) {
+ // Instead of inlining a backtrack, (re)use the global backtrack target.
+ on_failure = &backtrack_label_;
+ }
+
+ __ add(r0, end_of_input_address(), Operand(current_input_offset()));
+ int stored_high_byte = 0;
+ for (int i = 0; i < str.length(); i++) {
+ if (mode_ == ASCII) {
+ __ ldrb(r1, MemOperand(r0, char_size(), PostIndex));
+ // str[i] is known to be an ASCII character.
+ __ cmp(r1, Operand(str[i]));
+ } else {
+ __ ldrh(r1, MemOperand(r0, char_size(), PostIndex));
+ uc16 match_char = str[i];
+ int match_high_byte = (match_char >> 8);
+ if (match_high_byte == 0) {
+ __ cmp(r1, Operand(str[i]));
+ } else {
+ if (match_high_byte != stored_high_byte) {
+ __ mov(r2, Operand(match_high_byte));
+ stored_high_byte = match_high_byte;
+ }
+ __ add(r3, r2, Operand(match_char & 0xff));
+ __ cmp(r1, r3);
+ }
+ }
+ BranchOrBacktrack(ne, on_failure);
+ }
+}
+
+
+void RegExpMacroAssemblerARM::CheckGreedyLoop(Label* on_equal) {
+ __ ldr(r0, MemOperand(backtrack_stackpointer(), 0));
+ __ cmp(current_input_offset(), r0);
+ __ add(backtrack_stackpointer(),
+ backtrack_stackpointer(), Operand(kPointerSize), LeaveCC, eq);
+ BranchOrBacktrack(eq, on_equal);
+}
+
+
+void RegExpMacroAssemblerARM::CheckNotBackReferenceIgnoreCase(
+ int start_reg,
+ Label* on_no_match) {
+ Label fallthrough;
+ __ ldr(r0, register_location(start_reg)); // Index of start of capture
+ __ ldr(r1, register_location(start_reg + 1)); // Index of end of capture
+ __ sub(r1, r1, r0, SetCC); // Length of capture.
+
+ // If length is zero, either the capture is empty or it is not participating.
+ // In either case succeed immediately.
+ __ b(eq, &fallthrough);
+
+ // Check that there are enough characters left in the input.
+ __ cmn(r1, Operand(current_input_offset()));
+ BranchOrBacktrack(gt, on_no_match);
+
+ if (mode_ == ASCII) {
+ Label success;
+ Label fail;
+ Label loop_check;
+
+ // r0 - offset of start of capture
+ // r1 - length of capture
+ __ add(r0, r0, Operand(end_of_input_address()));
+ __ add(r2, end_of_input_address(), Operand(current_input_offset()));
+ __ add(r1, r0, Operand(r1));
+
+ // r0 - Address of start of capture.
+ // r1 - Address of end of capture
+ // r2 - Address of current input position.
+
+ Label loop;
+ __ bind(&loop);
+ __ ldrb(r3, MemOperand(r0, char_size(), PostIndex));
+ __ ldrb(r4, MemOperand(r2, char_size(), PostIndex));
+ __ cmp(r4, r3);
+ __ b(eq, &loop_check);
+
+ // Mismatch, try case-insensitive match (converting letters to lower-case).
+ __ orr(r3, r3, Operand(0x20)); // Convert capture character to lower-case.
+ __ orr(r4, r4, Operand(0x20)); // Also convert input character.
+ __ cmp(r4, r3);
+ __ b(ne, &fail);
+ __ sub(r3, r3, Operand('a'));
+ __ cmp(r3, Operand('z' - 'a')); // Is r3 a lowercase letter?
+ __ b(hi, &fail);
+
+
+ __ bind(&loop_check);
+ __ cmp(r0, r1);
+ __ b(lt, &loop);
+ __ jmp(&success);
+
+ __ bind(&fail);
+ BranchOrBacktrack(al, on_no_match);
+
+ __ bind(&success);
+ // Compute new value of character position after the matched part.
+ __ sub(current_input_offset(), r2, end_of_input_address());
+ } else {
+ ASSERT(mode_ == UC16);
+ int argument_count = 3;
+ FrameAlign(argument_count, r2);
+
+ // r0 - offset of start of capture
+ // r1 - length of capture
+
+ // Put arguments into arguments registers.
+ // Parameters are
+ // r0: Address byte_offset1 - Address captured substring's start.
+ // r1: Address byte_offset2 - Address of current character position.
+ // r2: size_t byte_length - length of capture in bytes(!)
+
+ // Address of start of capture.
+ __ add(r0, r0, Operand(end_of_input_address()));
+ // Length of capture.
+ __ mov(r2, Operand(r1));
+ // Save length in callee-save register for use on return.
+ __ mov(r4, Operand(r1));
+ // Address of current input position.
+ __ add(r1, current_input_offset(), Operand(end_of_input_address()));
+
+ ExternalReference function =
+ ExternalReference::re_case_insensitive_compare_uc16();
+ CallCFunction(function, argument_count);
+
+ // Check if function returned non-zero for success or zero for failure.
+ __ cmp(r0, Operand(0));
+ BranchOrBacktrack(eq, on_no_match);
+ // On success, increment position by length of capture.
+ __ add(current_input_offset(), current_input_offset(), Operand(r4));
+ }
+
+ __ bind(&fallthrough);
+}
+
+
+void RegExpMacroAssemblerARM::CheckNotBackReference(
+ int start_reg,
+ Label* on_no_match) {
+ Label fallthrough;
+ Label success;
+
+ // Find length of back-referenced capture.
+ __ ldr(r0, register_location(start_reg));
+ __ ldr(r1, register_location(start_reg + 1));
+ __ sub(r1, r1, r0, SetCC); // Length to check.
+ // Succeed on empty capture (including no capture).
+ __ b(eq, &fallthrough);
+
+ // Check that there are enough characters left in the input.
+ __ cmn(r1, Operand(current_input_offset()));
+ BranchOrBacktrack(gt, on_no_match);
+
+ // Compute pointers to match string and capture string
+ __ add(r0, r0, Operand(end_of_input_address()));
+ __ add(r2, end_of_input_address(), Operand(current_input_offset()));
+ __ add(r1, r1, Operand(r0));
+
+ Label loop;
+ __ bind(&loop);
+ if (mode_ == ASCII) {
+ __ ldrb(r3, MemOperand(r0, char_size(), PostIndex));
+ __ ldrb(r4, MemOperand(r2, char_size(), PostIndex));
+ } else {
+ ASSERT(mode_ == UC16);
+ __ ldrh(r3, MemOperand(r0, char_size(), PostIndex));
+ __ ldrh(r4, MemOperand(r2, char_size(), PostIndex));
+ }
+ __ cmp(r3, r4);
+ BranchOrBacktrack(ne, on_no_match);
+ __ cmp(r0, r1);
+ __ b(lt, &loop);
+
+ // Move current character position to position after match.
+ __ sub(current_input_offset(), r2, end_of_input_address());
+ __ bind(&fallthrough);
+}
+
+
+void RegExpMacroAssemblerARM::CheckNotRegistersEqual(int reg1,
+ int reg2,
+ Label* on_not_equal) {
+ __ ldr(r0, register_location(reg1));
+ __ ldr(r1, register_location(reg2));
+ __ cmp(r0, r1);
+ BranchOrBacktrack(ne, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerARM::CheckNotCharacter(uint32_t c,
+ Label* on_not_equal) {
+ __ cmp(current_character(), Operand(c));
+ BranchOrBacktrack(ne, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerARM::CheckCharacterAfterAnd(uint32_t c,
+ uint32_t mask,
+ Label* on_equal) {
+ __ and_(r0, current_character(), Operand(mask));
+ __ cmp(r0, Operand(c));
+ BranchOrBacktrack(eq, on_equal);
+}
+
+
+void RegExpMacroAssemblerARM::CheckNotCharacterAfterAnd(uint32_t c,
+ uint32_t mask,
+ Label* on_not_equal) {
+ __ and_(r0, current_character(), Operand(mask));
+ __ cmp(r0, Operand(c));
+ BranchOrBacktrack(ne, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerARM::CheckNotCharacterAfterMinusAnd(
+ uc16 c,
+ uc16 minus,
+ uc16 mask,
+ Label* on_not_equal) {
+ ASSERT(minus < String::kMaxUC16CharCode);
+ __ sub(r0, current_character(), Operand(minus));
+ __ and_(r0, r0, Operand(mask));
+ __ cmp(r0, Operand(c));
+ BranchOrBacktrack(ne, on_not_equal);
+}
+
+
+bool RegExpMacroAssemblerARM::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(), Operand(' '));
+ __ b(eq, &success);
+ // Check range 0x09..0x0d
+ __ sub(r0, current_character(), Operand('\t'));
+ __ cmp(r0, Operand('\r' - '\t'));
+ BranchOrBacktrack(hi, 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(), Operand(' '));
+ BranchOrBacktrack(eq, on_no_match);
+ __ sub(r0, current_character(), Operand('\t'));
+ __ cmp(r0, Operand('\r' - '\t'));
+ BranchOrBacktrack(ls, 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(r0, current_character(), Operand('0'));
+ __ cmp(current_character(), Operand('9' - '0'));
+ BranchOrBacktrack(hi, 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(r0, current_character(), Operand('0'));
+ __ cmp(r0, Operand('9' - '0'));
+ BranchOrBacktrack(ls, 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);
+ }
+ __ eor(r0, current_character(), Operand(0x01));
+ // See if current character is '\n'^1 or '\r'^1, i.e., 0x0b or 0x0c
+ __ sub(r0, r0, Operand(0x0b));
+ __ cmp(r0, Operand(0x0c - 0x0b));
+ BranchOrBacktrack(ls, on_no_match);
+ if (mode_ == UC16) {
+ // Compare original value to 0x2028 and 0x2029, using the already
+ // computed (current_char ^ 0x01 - 0x0b). I.e., check for
+ // 0x201d (0x2028 - 0x0b) or 0x201e.
+ __ sub(r0, r0, Operand(0x2028 - 0x0b));
+ __ cmp(r0, Operand(1));
+ BranchOrBacktrack(ls, 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;
+ }
+}
+
+
+void RegExpMacroAssemblerARM::Fail() {
+ __ mov(r0, Operand(FAILURE));
+ __ jmp(&exit_label_);
+}
+
+
+Handle<Object> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
+ // Finalize code - write the entry point code now we know how many
+ // registers we need.
+
+ // Entry code:
+ __ bind(&entry_label_);
+ // Push Link register.
+ // Push arguments
+ // Save callee-save registers.
+ // Start new stack frame.
+ // Order here should correspond to order of offset constants in header file.
+ RegList registers_to_retain = r4.bit() | r5.bit() | r6.bit() |
+ r7.bit() | r8.bit() | r9.bit() | r10.bit() | fp.bit();
+ RegList argument_registers = r0.bit() | r1.bit() | r2.bit() | r3.bit();
+ __ stm(db_w, sp, argument_registers | registers_to_retain | lr.bit());
+ // Set frame pointer just above the arguments.
+ __ add(frame_pointer(), sp, Operand(4 * kPointerSize));
+ __ push(r0); // Make room for "position - 1" constant (value is irrelevant).
+
+ // Check if we have space on the stack for registers.
+ Label stack_limit_hit;
+ Label stack_ok;
+
+ ExternalReference stack_guard_limit =
+ ExternalReference::address_of_stack_guard_limit();
+ __ mov(r0, Operand(stack_guard_limit));
+ __ ldr(r0, MemOperand(r0));
+ __ sub(r0, sp, r0, SetCC);
+ // Handle it if the stack pointer is already below the stack limit.
+ __ b(ls, &stack_limit_hit);
+ // Check if there is room for the variable number of registers above
+ // the stack limit.
+ __ cmp(r0, Operand(num_registers_ * kPointerSize));
+ __ b(hs, &stack_ok);
+ // Exit with OutOfMemory exception. There is not enough space on the stack
+ // for our working registers.
+ __ mov(r0, Operand(EXCEPTION));
+ __ jmp(&exit_label_);
+
+ __ bind(&stack_limit_hit);
+ CallCheckStackGuardState(r0);
+ __ cmp(r0, Operand(0));
+ // If returned value is non-zero, we exit with the returned value as result.
+ __ b(ne, &exit_label_);
+
+ __ bind(&stack_ok);
+
+ // Allocate space on stack for registers.
+ __ sub(sp, sp, Operand(num_registers_ * kPointerSize));
+ // Load string end.
+ __ ldr(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
+ // Load input start.
+ __ ldr(r0, MemOperand(frame_pointer(), kInputStart));
+ // Find negative length (offset of start relative to end).
+ __ sub(current_input_offset(), r0, end_of_input_address());
+ // Set r0 to address of char before start of input
+ // (effectively string position -1).
+ __ sub(r0, current_input_offset(), Operand(char_size()));
+ // Store this value in a local variable, for use when clearing
+ // position registers.
+ __ str(r0, MemOperand(frame_pointer(), kInputStartMinusOne));
+ if (num_saved_registers_ > 0) { // Always is, if generated from a regexp.
+ // Fill saved registers with initial value = start offset - 1
+
+ // Address of register 0.
+ __ add(r1, frame_pointer(), Operand(kRegisterZero));
+ __ mov(r2, Operand(num_saved_registers_));
+ Label init_loop;
+ __ bind(&init_loop);
+ __ str(r0, MemOperand(r1, kPointerSize, NegPostIndex));
+ __ sub(r2, r2, Operand(1), SetCC);
+ __ b(ne, &init_loop);
+ }
+
+ // Initialize backtrack stack pointer.
+ __ ldr(backtrack_stackpointer(), MemOperand(frame_pointer(), kStackHighEnd));
+ // Initialize code pointer register
+ __ mov(code_pointer(), Operand(masm_->CodeObject()));
+ // Load previous char as initial value of current character register.
+ Label at_start;
+ __ ldr(r0, MemOperand(frame_pointer(), kAtStart));
+ __ cmp(r0, Operand(0));
+ __ b(ne, &at_start);
+ LoadCurrentCharacterUnchecked(-1, 1); // Load previous char.
+ __ jmp(&start_label_);
+ __ bind(&at_start);
+ __ mov(current_character(), Operand('\n'));
+ __ jmp(&start_label_);
+
+
+ // Exit code:
+ if (success_label_.is_linked()) {
+ // Save captures when successful.
+ __ bind(&success_label_);
+ if (num_saved_registers_ > 0) {
+ // copy captures to output
+ __ ldr(r1, MemOperand(frame_pointer(), kInputStart));
+ __ ldr(r0, MemOperand(frame_pointer(), kRegisterOutput));
+ __ sub(r1, end_of_input_address(), r1);
+ // r1 is length of input in bytes.
+ if (mode_ == UC16) {
+ __ mov(r1, Operand(r1, LSR, 1));
+ }
+ // r1 is length of input in characters.
+
+ ASSERT_EQ(0, num_saved_registers_ % 2);
+ // Always an even number of capture registers. This allows us to
+ // unroll the loop once to add an operation between a load of a register
+ // and the following use of that register.
+ for (int i = 0; i < num_saved_registers_; i += 2) {
+ __ ldr(r2, register_location(i));
+ __ ldr(r3, register_location(i + 1));
+ if (mode_ == UC16) {
+ __ add(r2, r1, Operand(r2, ASR, 1));
+ __ add(r3, r1, Operand(r3, ASR, 1));
+ } else {
+ __ add(r2, r1, Operand(r2));
+ __ add(r3, r1, Operand(r3));
+ }
+ __ str(r2, MemOperand(r0, kPointerSize, PostIndex));
+ __ str(r3, MemOperand(r0, kPointerSize, PostIndex));
+ }
+ }
+ __ mov(r0, Operand(SUCCESS));
+ }
+ // Exit and return r0
+ __ bind(&exit_label_);
+ // Skip sp past regexp registers and local variables..
+ __ mov(sp, frame_pointer());
+ // Restore registers r4..r11 and return (restoring lr to pc).
+ __ ldm(ia_w, sp, registers_to_retain | pc.bit());
+
+ // Backtrack code (branch target for conditional backtracks).
+ if (backtrack_label_.is_linked()) {
+ __ bind(&backtrack_label_);
+ Backtrack();
+ }
+
+ Label exit_with_exception;
+
+ // Preempt-code
+ if (check_preempt_label_.is_linked()) {
+ SafeCallTarget(&check_preempt_label_);
+
+ CallCheckStackGuardState(r0);
+ __ cmp(r0, Operand(0));
+ // If returning non-zero, we should end execution with the given
+ // result as return value.
+ __ b(ne, &exit_label_);
+
+ // String might have moved: Reload end of string from frame.
+ __ ldr(end_of_input_address(), MemOperand(frame_pointer(), kInputEnd));
+ SafeReturn();
+ }
+
+ // Backtrack stack overflow code.
+ if (stack_overflow_label_.is_linked()) {
+ SafeCallTarget(&stack_overflow_label_);
+ // Reached if the backtrack-stack limit has been hit.
+
+ Label grow_failed;
+
+ // Call GrowStack(backtrack_stackpointer())
+ int num_arguments = 2;
+ FrameAlign(num_arguments, r0);
+ __ mov(r0, backtrack_stackpointer());
+ __ add(r1, frame_pointer(), Operand(kStackHighEnd));
+ ExternalReference grow_stack =
+ ExternalReference::re_grow_stack();
+ CallCFunction(grow_stack, num_arguments);
+ // If return NULL, we have failed to grow the stack, and
+ // must exit with a stack-overflow exception.
+ __ cmp(r0, Operand(0));
+ __ b(eq, &exit_with_exception);
+ // Otherwise use return value as new stack pointer.
+ __ mov(backtrack_stackpointer(), r0);
+ // Restore saved registers and continue.
+ SafeReturn();
+ }
+
+ if (exit_with_exception.is_linked()) {
+ // If any of the code above needed to exit with an exception.
+ __ bind(&exit_with_exception);
+ // Exit with Result EXCEPTION(-1) to signal thrown exception.
+ __ mov(r0, Operand(EXCEPTION));
+ __ jmp(&exit_label_);
+ }
+
+ CodeDesc code_desc;
+ masm_->GetCode(&code_desc);
+ Handle<Code> code = Factory::NewCode(code_desc,
+ NULL,
+ Code::ComputeFlags(Code::REGEXP),
+ masm_->CodeObject());
+ LOG(RegExpCodeCreateEvent(*code, *source));
+ return Handle<Object>::cast(code);
+}
+
+
+void RegExpMacroAssemblerARM::GoTo(Label* to) {
+ BranchOrBacktrack(al, to);
+}
+
+
+void RegExpMacroAssemblerARM::IfRegisterGE(int reg,
+ int comparand,
+ Label* if_ge) {
+ __ ldr(r0, register_location(reg));
+ __ cmp(r0, Operand(comparand));
+ BranchOrBacktrack(ge, if_ge);
+}
+
+
+void RegExpMacroAssemblerARM::IfRegisterLT(int reg,
+ int comparand,
+ Label* if_lt) {
+ __ ldr(r0, register_location(reg));
+ __ cmp(r0, Operand(comparand));
+ BranchOrBacktrack(lt, if_lt);
+}
+
+
+void RegExpMacroAssemblerARM::IfRegisterEqPos(int reg,
+ Label* if_eq) {
+ __ ldr(r0, register_location(reg));
+ __ cmp(r0, Operand(current_input_offset()));
+ BranchOrBacktrack(eq, if_eq);
+}
+
+
+RegExpMacroAssembler::IrregexpImplementation
+ RegExpMacroAssemblerARM::Implementation() {
+ return kARMImplementation;
+}
+
+
+void RegExpMacroAssemblerARM::LoadCurrentCharacter(int cp_offset,
+ Label* on_end_of_input,
+ bool check_bounds,
+ int characters) {
+ ASSERT(cp_offset >= -1); // ^ and \b can look behind one character.
+ ASSERT(cp_offset < (1<<30)); // Be sane! (And ensure negation works)
+ if (check_bounds) {
+ CheckPosition(cp_offset + characters - 1, on_end_of_input);
+ }
+ LoadCurrentCharacterUnchecked(cp_offset, characters);
+}
+
+
+void RegExpMacroAssemblerARM::PopCurrentPosition() {
+ Pop(current_input_offset());
+}
+
+
+void RegExpMacroAssemblerARM::PopRegister(int register_index) {
+ Pop(r0);
+ __ str(r0, register_location(register_index));
+}
+
+
+static bool is_valid_memory_offset(int value) {
+ if (value < 0) value = -value;
+ return value < (1<<12);
+}
+
+
+void RegExpMacroAssemblerARM::PushBacktrack(Label* label) {
+ if (label->is_bound()) {
+ int target = label->pos();
+ __ mov(r0, Operand(target + Code::kHeaderSize - kHeapObjectTag));
+ } else {
+ int constant_offset = GetBacktrackConstantPoolEntry();
+ masm_->label_at_put(label, constant_offset);
+ // Reading pc-relative is based on the address 8 bytes ahead of
+ // the current opcode.
+ unsigned int offset_of_pc_register_read =
+ masm_->pc_offset() + Assembler::kPcLoadDelta;
+ int pc_offset_of_constant =
+ constant_offset - offset_of_pc_register_read;
+ ASSERT(pc_offset_of_constant < 0);
+ if (is_valid_memory_offset(pc_offset_of_constant)) {
+ masm_->BlockConstPoolBefore(masm_->pc_offset() + Assembler::kInstrSize);
+ __ ldr(r0, MemOperand(pc, pc_offset_of_constant));
+ } else {
+ // Not a 12-bit offset, so it needs to be loaded from the constant
+ // pool.
+ masm_->BlockConstPoolBefore(
+ masm_->pc_offset() + 2 * Assembler::kInstrSize);
+ __ mov(r0, Operand(pc_offset_of_constant + Assembler::kInstrSize));
+ __ ldr(r0, MemOperand(pc, r0));
+ }
+ }
+ Push(r0);
+ CheckStackLimit();
+}
+
+
+void RegExpMacroAssemblerARM::PushCurrentPosition() {
+ Push(current_input_offset());
+}
+
+
+void RegExpMacroAssemblerARM::PushRegister(int register_index,
+ StackCheckFlag check_stack_limit) {
+ __ ldr(r0, register_location(register_index));
+ Push(r0);
+ if (check_stack_limit) CheckStackLimit();
+}
+
+
+void RegExpMacroAssemblerARM::ReadCurrentPositionFromRegister(int reg) {
+ __ ldr(current_input_offset(), register_location(reg));
+}
+
+
+void RegExpMacroAssemblerARM::ReadStackPointerFromRegister(int reg) {
+ __ ldr(backtrack_stackpointer(), register_location(reg));
+ __ ldr(r0, MemOperand(frame_pointer(), kStackHighEnd));
+ __ add(backtrack_stackpointer(), backtrack_stackpointer(), Operand(r0));
+}
+
+
+void RegExpMacroAssemblerARM::SetRegister(int register_index, int to) {
+ ASSERT(register_index >= num_saved_registers_); // Reserved for positions!
+ __ mov(r0, Operand(to));
+ __ str(r0, register_location(register_index));
+}
+
+
+void RegExpMacroAssemblerARM::Succeed() {
+ __ jmp(&success_label_);
+}
+
+
+void RegExpMacroAssemblerARM::WriteCurrentPositionToRegister(int reg,
+ int cp_offset) {
+ if (cp_offset == 0) {
+ __ str(current_input_offset(), register_location(reg));
+ } else {
+ __ add(r0, current_input_offset(), Operand(cp_offset * char_size()));
+ __ str(r0, register_location(reg));
+ }
+}
+
+
+void RegExpMacroAssemblerARM::ClearRegisters(int reg_from, int reg_to) {
+ ASSERT(reg_from <= reg_to);
+ __ ldr(r0, MemOperand(frame_pointer(), kInputStartMinusOne));
+ for (int reg = reg_from; reg <= reg_to; reg++) {
+ __ str(r0, register_location(reg));
+ }
+}
+
+
+void RegExpMacroAssemblerARM::WriteStackPointerToRegister(int reg) {
+ __ ldr(r1, MemOperand(frame_pointer(), kStackHighEnd));
+ __ sub(r0, backtrack_stackpointer(), r1);
+ __ str(r0, register_location(reg));
+}
+
+
+// Private methods:
+
+void RegExpMacroAssemblerARM::CallCheckStackGuardState(Register scratch) {
+ int num_arguments = 3;
+ FrameAlign(num_arguments, scratch);
+ // RegExp code frame pointer.
+ __ mov(r2, frame_pointer());
+ // Code* of self.
+ __ mov(r1, Operand(masm_->CodeObject()));
+ // r0 becomes return address pointer.
+ ExternalReference stack_guard_check =
+ ExternalReference::re_check_stack_guard_state();
+ CallCFunctionUsingStub(stack_guard_check, num_arguments);
+}
+
+
+// Helper function for reading a value out of a stack frame.
+template <typename T>
+static T& frame_entry(Address re_frame, int frame_offset) {
+ return reinterpret_cast<T&>(Memory::int32_at(re_frame + frame_offset));
+}
+
+
+int RegExpMacroAssemblerARM::CheckStackGuardState(Address* return_address,
+ Code* re_code,
+ Address re_frame) {
+ if (StackGuard::IsStackOverflow()) {
+ Top::StackOverflow();
+ return EXCEPTION;
+ }
+
+ // If not real stack overflow the stack guard was used to interrupt
+ // execution for another purpose.
+
+ // Prepare for possible GC.
+ HandleScope handles;
+ Handle<Code> code_handle(re_code);
+
+ Handle<String> subject(frame_entry<String*>(re_frame, kInputString));
+ // Current string.
+ bool is_ascii = subject->IsAsciiRepresentation();
+
+ ASSERT(re_code->instruction_start() <= *return_address);
+ ASSERT(*return_address <=
+ re_code->instruction_start() + re_code->instruction_size());
+
+ Object* result = Execution::HandleStackGuardInterrupt();
+
+ if (*code_handle != re_code) { // Return address no longer valid
+ int delta = *code_handle - re_code;
+ // Overwrite the return address on the stack.
+ *return_address += delta;
+ }
+
+ if (result->IsException()) {
+ return EXCEPTION;
+ }
+
+ // String might have changed.
+ if (subject->IsAsciiRepresentation() != is_ascii) {
+ // If we changed between an ASCII and an UC16 string, the specialized
+ // code cannot be used, and we need to restart regexp matching from
+ // scratch (including, potentially, compiling a new version of the code).
+ return RETRY;
+ }
+
+ // Otherwise, the content of the string might have moved. It must still
+ // be a sequential or external string with the same content.
+ // Update the start and end pointers in the stack frame to the current
+ // location (whether it has actually moved or not).
+ ASSERT(StringShape(*subject).IsSequential() ||
+ StringShape(*subject).IsExternal());
+
+ // The original start address of the characters to match.
+ const byte* start_address = frame_entry<const byte*>(re_frame, kInputStart);
+
+ // Find the current start address of the same character at the current string
+ // position.
+ int start_index = frame_entry<int>(re_frame, kStartIndex);
+ const byte* new_address = StringCharacterPosition(*subject, start_index);
+
+ if (start_address != new_address) {
+ // If there is a difference, update the object pointer and start and end
+ // addresses in the RegExp stack frame to match the new value.
+ const byte* end_address = frame_entry<const byte* >(re_frame, kInputEnd);
+ int byte_length = end_address - start_address;
+ frame_entry<const String*>(re_frame, kInputString) = *subject;
+ frame_entry<const byte*>(re_frame, kInputStart) = new_address;
+ frame_entry<const byte*>(re_frame, kInputEnd) = new_address + byte_length;
+ }
+
+ return 0;
+}
+
+
+MemOperand RegExpMacroAssemblerARM::register_location(int register_index) {
+ ASSERT(register_index < (1<<30));
+ if (num_registers_ <= register_index) {
+ num_registers_ = register_index + 1;
+ }
+ return MemOperand(frame_pointer(),
+ kRegisterZero - register_index * kPointerSize);
+}
+
+
+void RegExpMacroAssemblerARM::CheckPosition(int cp_offset,
+ Label* on_outside_input) {
+ __ cmp(current_input_offset(), Operand(-cp_offset * char_size()));
+ BranchOrBacktrack(ge, on_outside_input);
+}
+
+
+void RegExpMacroAssemblerARM::BranchOrBacktrack(Condition condition,
+ Label* to) {
+ if (condition == al) { // Unconditional.
+ if (to == NULL) {
+ Backtrack();
+ return;
+ }
+ __ jmp(to);
+ return;
+ }
+ if (to == NULL) {
+ __ b(condition, &backtrack_label_);
+ return;
+ }
+ __ b(condition, to);
+}
+
+
+void RegExpMacroAssemblerARM::SafeCall(Label* to, Condition cond) {
+ __ bl(to, cond);
+}
+
+
+void RegExpMacroAssemblerARM::SafeReturn() {
+ __ pop(lr);
+ __ add(pc, lr, Operand(masm_->CodeObject()));
+}
+
+
+void RegExpMacroAssemblerARM::SafeCallTarget(Label* name) {
+ __ bind(name);
+ __ sub(lr, lr, Operand(masm_->CodeObject()));
+ __ push(lr);
+}
+
+
+void RegExpMacroAssemblerARM::Push(Register source) {
+ ASSERT(!source.is(backtrack_stackpointer()));
+ __ str(source,
+ MemOperand(backtrack_stackpointer(), kPointerSize, NegPreIndex));
+}
+
+
+void RegExpMacroAssemblerARM::Pop(Register target) {
+ ASSERT(!target.is(backtrack_stackpointer()));
+ __ ldr(target,
+ MemOperand(backtrack_stackpointer(), kPointerSize, PostIndex));
+}
+
+
+void RegExpMacroAssemblerARM::CheckPreemption() {
+ // Check for preemption.
+ ExternalReference stack_guard_limit =
+ ExternalReference::address_of_stack_guard_limit();
+ __ mov(r0, Operand(stack_guard_limit));
+ __ ldr(r0, MemOperand(r0));
+ __ cmp(sp, r0);
+ SafeCall(&check_preempt_label_, ls);
+}
+
+
+void RegExpMacroAssemblerARM::CheckStackLimit() {
+ if (FLAG_check_stack) {
+ ExternalReference stack_limit =
+ ExternalReference::address_of_regexp_stack_limit();
+ __ mov(r0, Operand(stack_limit));
+ __ ldr(r0, MemOperand(r0));
+ __ cmp(backtrack_stackpointer(), Operand(r0));
+ SafeCall(&stack_overflow_label_, ls);
+ }
+}
+
+
+void RegExpMacroAssemblerARM::EmitBacktrackConstantPool() {
+ __ CheckConstPool(false, false);
+ __ BlockConstPoolBefore(
+ masm_->pc_offset() + kBacktrackConstantPoolSize * Assembler::kInstrSize);
+ backtrack_constant_pool_offset_ = masm_->pc_offset();
+ for (int i = 0; i < kBacktrackConstantPoolSize; i++) {
+ __ emit(0);
+ }
+
+ backtrack_constant_pool_capacity_ = kBacktrackConstantPoolSize;
+}
+
+
+int RegExpMacroAssemblerARM::GetBacktrackConstantPoolEntry() {
+ while (backtrack_constant_pool_capacity_ > 0) {
+ int offset = backtrack_constant_pool_offset_;
+ backtrack_constant_pool_offset_ += kPointerSize;
+ backtrack_constant_pool_capacity_--;
+ if (masm_->pc_offset() - offset < 2 * KB) {
+ return offset;
+ }
+ }
+ Label new_pool_skip;
+ __ jmp(&new_pool_skip);
+ EmitBacktrackConstantPool();
+ __ bind(&new_pool_skip);
+ int offset = backtrack_constant_pool_offset_;
+ backtrack_constant_pool_offset_ += kPointerSize;
+ backtrack_constant_pool_capacity_--;
+ return offset;
+}
+
+
+void RegExpMacroAssemblerARM::FrameAlign(int num_arguments, Register scratch) {
+ int frameAlignment = OS::ActivationFrameAlignment();
+ // Up to four simple arguments are passed in registers r0..r3.
+ int stack_passed_arguments = (num_arguments <= 4) ? 0 : num_arguments - 4;
+ if (frameAlignment != 0) {
+ // Make stack end at alignment and make room for num_arguments - 4 words
+ // and the original value of sp.
+ __ mov(scratch, sp);
+ __ sub(sp, sp, Operand((stack_passed_arguments + 1) * kPointerSize));
+ ASSERT(IsPowerOf2(frameAlignment));
+ __ and_(sp, sp, Operand(-frameAlignment));
+ __ str(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize));
+ } else {
+ __ sub(sp, sp, Operand(stack_passed_arguments * kPointerSize));
+ }
+}
+
+
+void RegExpMacroAssemblerARM::CallCFunction(ExternalReference function,
+ int num_arguments) {
+ __ mov(r5, Operand(function));
+ // Just call directly. The function called cannot cause a GC, or
+ // allow preemption, so the return address in the link register
+ // stays correct.
+ __ Call(r5);
+ int stack_passed_arguments = (num_arguments <= 4) ? 0 : num_arguments - 4;
+ if (OS::ActivationFrameAlignment() > kIntSize) {
+ __ ldr(sp, MemOperand(sp, stack_passed_arguments * kPointerSize));
+ } else {
+ __ add(sp, sp, Operand(stack_passed_arguments * sizeof(kPointerSize)));
+ }
+ __ mov(code_pointer(), Operand(masm_->CodeObject()));
+}
+
+
+void RegExpMacroAssemblerARM::CallCFunctionUsingStub(
+ ExternalReference function,
+ int num_arguments) {
+ // Must pass all arguments in registers. The stub pushes on the stack.
+ ASSERT(num_arguments <= 4);
+ __ mov(r5, Operand(function));
+ RegExpCEntryStub stub;
+ __ CallStub(&stub);
+ if (OS::ActivationFrameAlignment() != 0) {
+ __ ldr(sp, MemOperand(sp, 0));
+ }
+ __ mov(code_pointer(), Operand(masm_->CodeObject()));
+}
+
+
+void RegExpMacroAssemblerARM::LoadCurrentCharacterUnchecked(int cp_offset,
+ int characters) {
+ Register offset = current_input_offset();
+ if (cp_offset != 0) {
+ __ add(r0, current_input_offset(), Operand(cp_offset * char_size()));
+ offset = r0;
+ }
+ // We assume that we cannot do unaligned loads on ARM, so this function
+ // must only be used to load a single character at a time.
+ ASSERT(characters == 1);
+ if (mode_ == ASCII) {
+ __ ldrb(current_character(), MemOperand(end_of_input_address(), offset));
+ } else {
+ ASSERT(mode_ == UC16);
+ __ ldrh(current_character(), MemOperand(end_of_input_address(), offset));
+ }
+}
+
+
+void RegExpCEntryStub::Generate(MacroAssembler* masm_) {
+ int stack_alignment = OS::ActivationFrameAlignment();
+ if (stack_alignment < kPointerSize) stack_alignment = kPointerSize;
+ // Stack is already aligned for call, so decrement by alignment
+ // to make room for storing the link register.
+ __ str(lr, MemOperand(sp, stack_alignment, NegPreIndex));
+ __ mov(r0, sp);
+ __ Call(r5);
+ __ ldr(pc, MemOperand(sp, stack_alignment, PostIndex));
+}
+
+#undef __
+
+#endif // V8_NATIVE_REGEXP
+
+}} // namespace v8::internal
namespace v8 {
namespace internal {
+
+#ifndef V8_NATIVE_REGEXP
class RegExpMacroAssemblerARM: public RegExpMacroAssembler {
public:
RegExpMacroAssemblerARM();
virtual ~RegExpMacroAssemblerARM();
};
+#else
+class RegExpMacroAssemblerARM: public NativeRegExpMacroAssembler {
+ public:
+ RegExpMacroAssemblerARM(Mode mode, int registers_to_save);
+ virtual ~RegExpMacroAssemblerARM();
+ virtual int stack_limit_slack();
+ virtual bool CanReadUnaligned();
+ 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);
+
+ // 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);
+ private:
+ // Offsets from frame_pointer() of function parameters and stored registers.
+ static const int kFramePointer = 0;
+
+ // Above the frame pointer - Stored registers and stack passed parameters.
+ // Register 4..11.
+ static const int kStoredRegisters = kFramePointer;
+ // Return address (stored from link register, read into pc on return).
+ static const int kReturnAddress = kStoredRegisters + 8 * kPointerSize;
+ // Stack parameters placed by caller.
+ static const int kRegisterOutput = kReturnAddress + kPointerSize;
+ static const int kAtStart = kRegisterOutput + kPointerSize;
+ static const int kStackHighEnd = kAtStart + kPointerSize;
+
+ // Below the frame pointer.
+ // Register parameters stored by setup code.
+ static const int kInputEnd = kFramePointer - kPointerSize;
+ static const int kInputStart = kInputEnd - kPointerSize;
+ static const int kStartIndex = kInputStart - kPointerSize;
+ static const int kInputString = kStartIndex - kPointerSize;
+ // When adding local variables remember to push space for them in
+ // the frame in GetCode.
+ static const int kInputStartMinusOne = kInputString - 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;
+
+ static const int kBacktrackConstantPoolSize = 4;
+
+ // 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();
+
+ void EmitBacktrackConstantPool();
+ int GetBacktrackConstantPoolEntry();
+
+
+ // Generate a call to CheckStackGuardState.
+ void CallCheckStackGuardState(Register scratch);
+
+ // The ebp-relative location of a regexp register.
+ MemOperand register_location(int register_index);
+
+ // Register holding the current input position as negative offset from
+ // the end of the string.
+ inline Register current_input_offset() { return r6; }
+
+ // The register containing the current character after LoadCurrentCharacter.
+ inline Register current_character() { return r7; }
+
+ // Register holding address of the end of the input string.
+ inline Register end_of_input_address() { return r10; }
+
+ // Register holding the frame address. Local variables, parameters and
+ // regexp registers are addressed relative to this.
+ inline Register frame_pointer() { return fp; }
+
+ // The register containing the backtrack stack top. Provides a meaningful
+ // name to the register.
+ inline Register backtrack_stackpointer() { return r8; }
+
+ // Register holding pointer to the current code object.
+ inline Register code_pointer() { return r5; }
+
+ // 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);
+
+ // 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, Condition cond = al);
+ inline void SafeReturn();
+ inline void SafeCallTarget(Label* name);
+
+ // Pushes the value of a register on the backtrack stack. Decrements the
+ // stack pointer by a word size and stores the register's value there.
+ inline void Push(Register source);
+
+ // Pops a value from the backtrack stack. Reads the word at the stack pointer
+ // and increments it by a word size.
+ inline void Pop(Register target);
+
+ // Before calling a C-function from generated code, align arguments on stack.
+ // After aligning the frame, non-register arguments must be stored in
+ // sp[0], sp[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, Register scratch);
+
+ // 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.
+ inline void CallCFunction(ExternalReference function,
+ int num_arguments);
+
+ // Calls a C function and cleans up the frame alignment done by
+ // by FrameAlign. The called function *is* allowed to trigger a garbage
+ // collection, but may not take more than four arguments (no arguments
+ // passed on the stack), and the first argument will be a pointer to the
+ // return address.
+ inline void CallCFunctionUsingStub(ExternalReference function,
+ int num_arguments);
+
+
+ MacroAssembler* masm_;
+
+ // 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_;
+
+ // Manage a small pre-allocated pool for writing label targets
+ // to for pushing backtrack addresses.
+ int backtrack_constant_pool_offset_;
+ int backtrack_constant_pool_capacity_;
+
+ // 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_;
+};
+
+
+#endif // V8_NATIVE_REGEXP
+
+
}} // namespace v8::internal
#endif // V8_ARM_REGEXP_MACRO_ASSEMBLER_ARM_H_
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stdlib.h>
-
+#include <cstdarg>
#include "v8.h"
#include "disasm.h"
uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
return *ptr;
}
- PrintF("Unaligned read at %x, pc=%p\n", addr, instr);
+ PrintF("Unaligned unsigned halfword read at %x, pc=%p\n", addr, instr);
UNIMPLEMENTED();
return 0;
}
int16_t* ptr = reinterpret_cast<int16_t*>(addr);
return *ptr;
}
- PrintF("Unaligned read at %x\n", addr);
+ PrintF("Unaligned signed halfword read at %x\n", addr);
UNIMPLEMENTED();
return 0;
}
*ptr = value;
return;
}
- PrintF("Unaligned write at %x, pc=%p\n", addr, instr);
+ PrintF("Unaligned unsigned halfword write at %x, pc=%p\n", addr, instr);
UNIMPLEMENTED();
}
*ptr = value;
return;
}
- PrintF("Unaligned write at %x, pc=%p\n", addr, instr);
+ PrintF("Unaligned halfword write at %x, pc=%p\n", addr, instr);
UNIMPLEMENTED();
}
case CMN: {
if (instr->HasS()) {
- Format(instr, "cmn'cond 'rn, 'shift_rm");
- Format(instr, "cmn'cond 'rn, 'imm");
+ // Format(instr, "cmn'cond 'rn, 'shift_rm");
+ // Format(instr, "cmn'cond 'rn, 'imm");
+ alu_out = rn_val + shifter_operand;
+ SetNZFlags(alu_out);
+ SetCFlag(!CarryFrom(rn_val, shifter_operand));
+ SetVFlag(OverflowFrom(alu_out, rn_val, shifter_operand, true));
} else {
ASSERT(type == 0);
int rm = instr->RmField();
void Simulator::DecodeType3(Instr* instr) {
+ ASSERT(instr->Bit(4) == 0);
int rd = instr->RdField();
int rn = instr->RnField();
int32_t rn_val = get_register(rn);
}
}
if (instr->HasB()) {
- UNIMPLEMENTED();
+ if (instr->HasL()) {
+ uint8_t byte = ReadB(addr);
+ set_register(rd, byte);
+ } else {
+ UNIMPLEMENTED();
+ }
} else {
if (instr->HasL()) {
set_register(rd, ReadW(addr, instr));
void Simulator::DecodeType5(Instr* instr) {
// Format(instr, "b'l'cond 'target");
- int off = (instr->SImmed24Field() << 2) + 8;
- intptr_t pc = get_pc();
+ int off = (instr->SImmed24Field() << 2);
+ intptr_t pc_address = get_pc();
if (instr->HasLink()) {
- set_register(lr, pc + Instr::kInstrSize);
+ set_register(lr, pc_address + Instr::kInstrSize);
}
- set_pc(pc+off);
+ int pc_reg = get_register(pc);
+ set_pc(pc_reg + off);
}
}
+void Simulator::DecodeUnconditional(Instr* instr) {
+ if (instr->Bits(7, 4) == 0x0B && instr->Bits(27, 25) == 0 && instr->HasL()) {
+ // Load halfword instruction, either register or immediate offset.
+ int rd = instr->RdField();
+ int rn = instr->RnField();
+ int32_t rn_val = get_register(rn);
+ int32_t addr = 0;
+ int32_t offset;
+ if (instr->Bit(22) == 0) {
+ // Register offset.
+ int rm = instr->RmField();
+ offset = get_register(rm);
+ } else {
+ // Immediate offset
+ offset = instr->Bits(3, 0) + (instr->Bits(11, 8) << 4);
+ }
+ switch (instr->PUField()) {
+ case 0: {
+ // Post index, negative.
+ ASSERT(!instr->HasW());
+ addr = rn_val;
+ rn_val -= offset;
+ set_register(rn, rn_val);
+ break;
+ }
+ case 1: {
+ // Post index, positive.
+ ASSERT(!instr->HasW());
+ addr = rn_val;
+ rn_val += offset;
+ set_register(rn, rn_val);
+ break;
+ }
+ case 2: {
+ // Pre index or offset, negative.
+ rn_val -= offset;
+ addr = rn_val;
+ if (instr->HasW()) {
+ set_register(rn, rn_val);
+ }
+ break;
+ }
+ case 3: {
+ // Pre index or offset, positive.
+ rn_val += offset;
+ addr = rn_val;
+ if (instr->HasW()) {
+ set_register(rn, rn_val);
+ }
+ break;
+ }
+ default: {
+ // The PU field is a 2-bit field.
+ UNREACHABLE();
+ break;
+ }
+ }
+ // Not sign extending, so load as unsigned.
+ uint16_t halfword = ReadH(addr, instr);
+ set_register(rd, halfword);
+ } else {
+ UNIMPLEMENTED();
+ }
+}
+
+
// Executes the current instruction.
void Simulator::InstructionDecode(Instr* instr) {
pc_modified_ = false;
- if (instr->ConditionField() == special_condition) {
- Debugger dbg(this);
- dbg.Stop(instr);
- return;
- }
if (::v8::internal::FLAG_trace_sim) {
disasm::NameConverter converter;
disasm::Disassembler dasm(converter);
reinterpret_cast<byte*>(instr));
PrintF(" 0x%x %s\n", instr, buffer.start());
}
- if (ConditionallyExecute(instr)) {
+ if (instr->ConditionField() == special_condition) {
+ DecodeUnconditional(instr);
+ } else if (ConditionallyExecute(instr)) {
switch (instr->TypeField()) {
case 0:
case 1: {
}
-Object* Simulator::Call(int32_t entry, int32_t p0, int32_t p1, int32_t p2,
- int32_t p3, int32_t p4) {
- // Setup parameters
- set_register(r0, p0);
- set_register(r1, p1);
- set_register(r2, p2);
- set_register(r3, p3);
- intptr_t* stack_pointer = reinterpret_cast<intptr_t*>(get_register(sp));
- *(--stack_pointer) = p4;
- set_register(sp, reinterpret_cast<int32_t>(stack_pointer));
+int32_t Simulator::Call(byte* entry, int argument_count, ...) {
+ va_list parameters;
+ va_start(parameters, argument_count);
+ // Setup arguments
+
+ // First four arguments passed in registers.
+ ASSERT(argument_count >= 4);
+ set_register(r0, va_arg(parameters, int32_t));
+ set_register(r1, va_arg(parameters, int32_t));
+ set_register(r2, va_arg(parameters, int32_t));
+ set_register(r3, va_arg(parameters, int32_t));
+
+ // Remaining arguments passed on stack.
+ int original_stack = get_register(sp);
+ // Compute position of stack on entry to generated code.
+ int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t));
+ if (OS::ActivationFrameAlignment() != 0) {
+ entry_stack &= -OS::ActivationFrameAlignment();
+ }
+ // Store remaining arguments on stack, from low to high memory.
+ intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
+ for (int i = 4; i < argument_count; i++) {
+ stack_argument[i - 4] = va_arg(parameters, int32_t);
+ }
+ va_end(parameters);
+ set_register(sp, entry_stack);
// Prepare to execute the code at entry
- set_register(pc, entry);
+ set_register(pc, reinterpret_cast<int32_t>(entry));
// Put down marker for end of simulation. The simulator will stop simulation
// when the PC reaches this value. By saving the "end simulation" value into
// the LR the simulation stops when returning to this call point.
Execute();
// Check that the callee-saved registers have been preserved.
- CHECK_EQ(get_register(r4), callee_saved_value);
- CHECK_EQ(get_register(r5), callee_saved_value);
- CHECK_EQ(get_register(r6), callee_saved_value);
- CHECK_EQ(get_register(r7), callee_saved_value);
- CHECK_EQ(get_register(r8), callee_saved_value);
- CHECK_EQ(get_register(r9), callee_saved_value);
- CHECK_EQ(get_register(r10), callee_saved_value);
- CHECK_EQ(get_register(r11), callee_saved_value);
+ CHECK_EQ(callee_saved_value, get_register(r4));
+ CHECK_EQ(callee_saved_value, get_register(r5));
+ CHECK_EQ(callee_saved_value, get_register(r6));
+ CHECK_EQ(callee_saved_value, get_register(r7));
+ CHECK_EQ(callee_saved_value, get_register(r8));
+ CHECK_EQ(callee_saved_value, get_register(r9));
+ CHECK_EQ(callee_saved_value, get_register(r10));
+ CHECK_EQ(callee_saved_value, get_register(r11));
// Restore callee-saved registers with the original value.
set_register(r4, r4_val);
set_register(r10, r10_val);
set_register(r11, r11_val);
- int result = get_register(r0);
- return reinterpret_cast<Object*>(result);
+ // Pop stack passed arguments.
+ CHECK_EQ(entry_stack, get_register(sp));
+ set_register(sp, original_stack);
+
+ int32_t result = get_register(r0);
+ return result;
}
} } // namespace assembler::arm
// When running without a simulator we call the entry directly.
#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
- reinterpret_cast<Object*>(entry(p0, p1, p2, p3, p4))
+ (entry(p0, p1, p2, p3, p4))
// Calculated the stack limit beyond which we will throw stack overflow errors.
// This macro must be called from a C++ method. It relies on being able to take
#define GENERATED_CODE_STACK_LIMIT(limit) \
(reinterpret_cast<uintptr_t>(this) - limit)
+
+// Call the generated regexp code directly. The entry function pointer should
+// expect seven int/pointer sized arguments and return an int.
+#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \
+ entry(p0, p1, p2, p3, p4, p5, p6)
+
#else // defined(__arm__)
// When running with the simulator transition into simulated execution at this
// point.
#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
- assembler::arm::Simulator::current()->Call((int32_t)entry, (int32_t)p0, \
- (int32_t)p1, (int32_t)p2, (int32_t)p3, (int32_t)p4)
+ reinterpret_cast<Object*>( \
+ assembler::arm::Simulator::current()->Call(FUNCTION_ADDR(entry), 5, \
+ p0, p1, p2, p3, p4))
// The simulator has its own stack. Thus it has a different stack limit from
// the C-based native code.
(assembler::arm::Simulator::current()->StackLimit())
+#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \
+ assembler::arm::Simulator::current()->Call( \
+ FUNCTION_ADDR(entry), 7, p0, p1, p2, p3, p4, p5, p6)
+
#include "constants-arm.h"
// Call on program start.
static void Initialize();
- // V8 generally calls into generated code with 5 parameters. This is a
- // convenience function, which sets up the simulator state and grabs the
- // result on return.
- v8::internal::Object* Call(int32_t entry, int32_t p0, int32_t p1,
- int32_t p2, int32_t p3, int32_t p4);
+ // V8 generally calls into generated JS code with 5 parameters and into
+ // generated RegExp code with 7 parameters. This is a convenience function,
+ // which sets up the simulator state and grabs the result on return.
+ int32_t Call(byte* entry, int argument_count, ...);
private:
enum special_values {
void DecodeType5(Instr* instr);
void DecodeType6(Instr* instr);
void DecodeType7(Instr* instr);
+ void DecodeUnconditional(Instr* instr);
// Executes one instruction.
void InstructionDecode(Instr* instr);
#include "serialize.h"
#include "stub-cache.h"
#include "regexp-stack.h"
+#include "ast.h"
+#include "regexp-macro-assembler.h"
+// Include native regexp-macro-assembler.
+#ifdef V8_NATIVE_REGEXP
+#if V8_TARGET_ARCH_IA32
+#include "ia32/regexp-macro-assembler-ia32.h"
+#elif V8_TARGET_ARCH_X64
+#include "x64/regexp-macro-assembler-x64.h"
+#elif V8_TARGET_ARCH_ARM
+#include "arm/regexp-macro-assembler-arm.h"
+#else // Unknown architecture.
+#error "Unknown architecture."
+#endif // Target architecture.
+#endif // V8_NATIVE_REGEXP
namespace v8 {
namespace internal {
return ExternalReference(Heap::NewSpaceAllocationLimitAddress());
}
+#ifdef V8_NATIVE_REGEXP
+
+ExternalReference ExternalReference::re_check_stack_guard_state() {
+ Address function;
+#ifdef V8_TARGET_ARCH_X64
+ function = FUNCTION_ADDR(RegExpMacroAssemblerX64::CheckStackGuardState);
+#elif V8_TARGET_ARCH_IA32
+ function = FUNCTION_ADDR(RegExpMacroAssemblerIA32::CheckStackGuardState);
+#elif V8_TARGET_ARCH_ARM
+ function = FUNCTION_ADDR(RegExpMacroAssemblerARM::CheckStackGuardState);
+#else
+ UNREACHABLE("Unexpected architecture");
+#endif
+ return ExternalReference(Redirect(function));
+}
+
+ExternalReference ExternalReference::re_grow_stack() {
+ return ExternalReference(
+ Redirect(FUNCTION_ADDR(NativeRegExpMacroAssembler::GrowStack)));
+}
+
+ExternalReference ExternalReference::re_case_insensitive_compare_uc16() {
+ return ExternalReference(Redirect(
+ FUNCTION_ADDR(NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16)));
+}
+
+#endif
+
static double add_two_doubles(double x, double y) {
return x + y;
static ExternalReference debug_step_in_fp_address();
#endif
+#ifdef V8_NATIVE_REGEXP
+ // C functions called from RegExp generated code.
+
+ // Function NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16()
+ static ExternalReference re_case_insensitive_compare_uc16();
+
+ // Function RegExpMacroAssembler*::CheckStackGuardState()
+ static ExternalReference re_check_stack_guard_state();
+
+ // Function NativeRegExpMacroAssembler::GrowStack()
+ static ExternalReference re_grow_stack();
+#endif
+
// This lets you register a function that rewrites all external references.
// Used by the ARM simulator to catch calls to external references.
static void set_redirector(ExternalReferenceRedirector* redirector) {
SetProperty, // ARM only
InvokeBuiltin, // ARM only
JSExit, // ARM only
+ RegExpCEntry, // ARM only
NUMBER_OF_IDS
};
#define V8_HOST_ARCH_ARM 1
#define V8_HOST_ARCH_32_BIT 1
#else
-#error Your architecture was not detected as supported by v8
+#error Your host architecture was not detected as supported by v8
+#endif
+
+#if defined(V8_TARGET_ARCH_X64) || defined(V8_TARGET_ARCH_IA32)
+#define V8_TARGET_CAN_READ_UNALIGNED 1
+#elif V8_TARGET_ARCH_ARM
+#else
+#error Your target architecture is not supported by v8
#endif
// Support for alternative bool type. This is only enabled if the code is
#include "scanner.h"
#include "scopeinfo.h"
#include "v8threads.h"
+#if V8_TARGET_ARCH_ARM && V8_NATIVE_REGEXP
+#include "regexp-macro-assembler.h"
+#endif
namespace v8 {
namespace internal {
}
+#if V8_TARGET_ARCH_ARM && V8_NATIVE_REGEXP
+void Heap::CreateRegExpCEntryStub() {
+ RegExpCEntryStub stub;
+ set_re_c_entry_code(*stub.GetCode());
+}
+#endif
+
+
void Heap::CreateCEntryDebugBreakStub() {
CEntryDebugBreakStub stub;
set_c_entry_debug_break_code(*stub.GetCode());
Heap::CreateCEntryDebugBreakStub();
Heap::CreateJSEntryStub();
Heap::CreateJSConstructEntryStub();
+#if V8_TARGET_ARCH_ARM && V8_NATIVE_REGEXP
+ Heap::CreateRegExpCEntryStub();
+#endif
}
namespace internal {
// Defines all the roots in Heap.
-#define STRONG_ROOT_LIST(V) \
+#define UNCONDITIONAL_STRONG_ROOT_LIST(V) \
/* Cluster the most popular ones in a few cache lines here at the top. */ \
V(Smi, stack_limit, StackLimit) \
V(Object, undefined_value, UndefinedValue) \
V(FixedArray, natives_source_cache, NativesSourceCache) \
V(Object, last_script_id, LastScriptId) \
+#if V8_TARGET_ARCH_ARM && V8_NATIVE_REGEXP
+#define STRONG_ROOT_LIST(V) \
+ UNCONDITIONAL_STRONG_ROOT_LIST(V) \
+ V(Code, re_c_entry_code, RegExpCEntryCode)
+#else
+#define STRONG_ROOT_LIST(V) UNCONDITIONAL_STRONG_ROOT_LIST(V)
+#endif
#define ROOT_LIST(V) \
STRONG_ROOT_LIST(V) \
static void CreateCEntryDebugBreakStub();
static void CreateJSEntryStub();
static void CreateJSConstructEntryStub();
+ static void CreateRegExpCEntryStub();
+
static void CreateFixedStubs();
static Object* CreateOddball(Map* map,
success_label_(),
backtrack_label_(),
exit_label_() {
+ ASSERT_EQ(0, registers_to_save % 2);
__ jmp(&entry_label_); // We'll write the entry code later.
__ bind(&start_label_); // And then continue from here.
}
__ add(edx, Operand(esi));
__ mov(Operand(esp, 0 * kPointerSize), edx);
- Address function_address = FUNCTION_ADDR(&CaseInsensitiveCompareUC16);
- CallCFunction(function_address, argument_count);
+ ExternalReference compare =
+ ExternalReference::re_case_insensitive_compare_uc16();
+ CallCFunction(compare, argument_count);
// Pop original values before reacting on result value.
__ pop(ebx);
__ pop(backtrack_stackpointer());
__ lea(eax, Operand(ebp, kStackHighEnd));
__ mov(Operand(esp, 1 * kPointerSize), eax);
__ mov(Operand(esp, 0 * kPointerSize), backtrack_stackpointer());
- CallCFunction(FUNCTION_ADDR(&GrowStack), num_arguments);
+ ExternalReference grow_stack = ExternalReference::re_grow_stack();
+ CallCFunction(grow_stack, num_arguments);
// If return NULL, we have failed to grow the stack, and
// must exit with a stack-overflow exception.
__ or_(eax, Operand(eax));
int characters) {
ASSERT(cp_offset >= -1); // ^ and \b can look behind one character.
ASSERT(cp_offset < (1<<30)); // Be sane! (And ensure negation works)
- CheckPosition(cp_offset + characters - 1, on_end_of_input);
+ if (check_bounds) {
+ CheckPosition(cp_offset + characters - 1, on_end_of_input);
+ }
LoadCurrentCharacterUnchecked(cp_offset, characters);
}
// Next address on the stack (will be address of return address).
__ lea(eax, Operand(esp, -kPointerSize));
__ mov(Operand(esp, 0 * kPointerSize), eax);
- CallCFunction(FUNCTION_ADDR(&CheckStackGuardState), num_arguments);
+ ExternalReference check_stack_guard =
+ ExternalReference::re_check_stack_guard_state();
+ CallCFunction(check_stack_guard, num_arguments);
}
}
-Address RegExpMacroAssemblerIA32::GrowStack(Address stack_pointer,
- Address* stack_base) {
- size_t size = RegExpStack::stack_capacity();
- 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_base = new_stack_base;
- return new_stack_base - (old_stack_base - stack_pointer);
-}
-
-
Operand RegExpMacroAssemblerIA32::register_location(int register_index) {
ASSERT(register_index < (1<<30));
if (num_registers_ <= register_index) {
}
-void RegExpMacroAssemblerIA32::CallCFunction(Address function_address,
+void RegExpMacroAssemblerIA32::CallCFunction(ExternalReference function,
int num_arguments) {
- __ mov(Operand(eax), Immediate(reinterpret_cast<int32_t>(function_address)));
+ __ mov(Operand(eax), Immediate(function));
__ call(Operand(eax));
if (OS::ActivationFrameAlignment() != 0) {
__ mov(esp, Operand(esp, num_arguments * kPointerSize));
}
+void RegExpCEntryStub::Generate(MacroAssembler* masm_) {
+ __ int3(); // Unused on ia32.
+}
+
#undef __
#endif // V8_NATIVE_REGEXP
virtual void ClearRegisters(int reg_from, int reg_to);
virtual void WriteStackPointerToRegister(int reg);
+ // 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);
+
private:
// Offsets from ebp of function parameters and stored registers.
static const int kFramePointer = 0;
// 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(Register scratch);
- // 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 ebp-relative location of a regexp register.
Operand register_location(int register_index);
// 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).
- inline void CallCFunction(Address function_address, int num_arguments);
+ inline void CallCFunction(ExternalReference function, int num_arguments);
MacroAssembler* masm_;
(reinterpret_cast<uintptr_t>(this) >= limit ? \
reinterpret_cast<uintptr_t>(this) - limit : 0)
+// Call the generated regexp code directly. The entry function pointer should
+// expect seven int/pointer sized arguments and return an int.
+#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \
+ entry(p0, p1, p2, p3, p4, p5, p6)
+
#endif // V8_IA32_SIMULATOR_IA32_H_
#include "x64/macro-assembler-x64.h"
#include "x64/regexp-macro-assembler-x64.h"
#elif V8_TARGET_ARCH_ARM
+#include "arm/macro-assembler-arm.h"
#include "arm/regexp-macro-assembler-arm.h"
#else
#error Unsupported target architecture.
Handle<FixedArray> regexp(FixedArray::cast(jsregexp->data()));
#ifdef V8_NATIVE_REGEXP
-#ifdef V8_TARGET_ARCH_ARM
- UNIMPLEMENTED();
-#else // Native regexp supported.
+
OffsetsVector captures(number_of_capture_registers);
int* captures_vector = captures.vector();
NativeRegExpMacroAssembler::Result res;
SetCapture(*array, i, captures_vector[i]);
SetCapture(*array, i + 1, captures_vector[i + 1]);
}
-#endif // Native regexp supported.
#else // ! V8_NATIVE_REGEXP
+
bool is_ascii = subject->IsAsciiRepresentation();
if (!EnsureCompiledIrregexp(jsregexp, is_ascii)) {
return Handle<Object>::null();
SetCapture(*array, i, register_vector[i]);
SetCapture(*array, i + 1, register_vector[i + 1]);
}
+
#endif // V8_NATIVE_REGEXP
SetLastCaptureCount(*array, number_of_capture_registers);
GetQuickCheckDetails(details, compiler, 0, trace->at_start() == Trace::FALSE);
if (details->cannot_match()) return false;
if (!details->Rationalize(compiler->ascii())) return false;
+ if (details->characters() > 1 &&
+ !compiler->macro_assembler()->CanReadUnaligned()) return false;
uint32_t mask = details->mask();
uint32_t value = details->value();
int ChoiceNode::CalculatePreloadCharacters(RegExpCompiler* compiler) {
int preload_characters = EatsAtLeast(4, 0);
-#ifdef V8_HOST_CAN_READ_UNALIGNED
- bool ascii = compiler->ascii();
- if (ascii) {
- if (preload_characters > 4) preload_characters = 4;
- // We can't preload 3 characters because there is no machine instruction
- // to do that. We can't just load 4 because we could be reading
- // beyond the end of the string, which could cause a memory fault.
- if (preload_characters == 3) preload_characters = 2;
+ if (compiler->macro_assembler()->CanReadUnaligned()) {
+ bool ascii = compiler->ascii();
+ if (ascii) {
+ if (preload_characters > 4) preload_characters = 4;
+ // We can't preload 3 characters because there is no machine instruction
+ // to do that. We can't just load 4 because we could be reading
+ // beyond the end of the string, which could cause a memory fault.
+ if (preload_characters == 3) preload_characters = 2;
+ } else {
+ if (preload_characters > 2) preload_characters = 2;
+ }
} else {
- if (preload_characters > 2) preload_characters = 2;
+ if (preload_characters > 1) preload_characters = 1;
}
-#else
- if (preload_characters > 1) preload_characters = 1;
-#endif
return preload_characters;
}
is_ascii ? NativeRegExpMacroAssembler::ASCII
: NativeRegExpMacroAssembler::UC16;
-#ifdef V8_TARGET_ARCH_IA32
- RegExpMacroAssemblerIA32 macro_assembler(mode,
- (data->capture_count + 1) * 2);
-#endif
-#ifdef V8_TARGET_ARCH_X64
- RegExpMacroAssemblerX64 macro_assembler(mode,
- (data->capture_count + 1) * 2);
-#endif
-#ifdef V8_TARGET_ARCH_ARM
- UNIMPLEMENTED();
+#if V8_TARGET_ARCH_IA32
+ RegExpMacroAssemblerIA32 macro_assembler(mode, (data->capture_count + 1) * 2);
+#elif V8_TARGET_ARCH_X64
+ RegExpMacroAssemblerX64 macro_assembler(mode, (data->capture_count + 1) * 2);
+#elif V8_TARGET_ARCH_ARM
+ RegExpMacroAssemblerARM macro_assembler(mode, (data->capture_count + 1) * 2);
#endif
#else // ! V8_NATIVE_REGEXP
namespace v8 {
namespace internal {
+#ifndef V8_NATIVE_REGEXP
void RegExpMacroAssemblerIrregexp::Emit(uint32_t byte,
uint32_t twenty_four_bits) {
pc_ += 4;
}
+#endif // ! V8_NATIVE_REGEXP
} } // namespace v8::internal
namespace v8 {
namespace internal {
+#ifndef V8_NATIVE_REGEXP
RegExpMacroAssemblerIrregexp::RegExpMacroAssemblerIrregexp(Vector<byte> buffer)
: buffer_(buffer),
}
}
+#endif // !V8_NATIVE_REGEXP
} } // namespace v8::internal
namespace v8 {
namespace internal {
+#ifndef V8_NATIVE_REGEXP
class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler {
public:
DISALLOW_IMPLICIT_CONSTRUCTORS(RegExpMacroAssemblerIrregexp);
};
+#endif // !V8_NATIVE_REGEXP
+
} } // namespace v8::internal
#endif // V8_REGEXP_MACRO_ASSEMBLER_IRREGEXP_H_
explicit RegExpMacroAssemblerTracer(RegExpMacroAssembler* assembler);
virtual ~RegExpMacroAssemblerTracer();
virtual int stack_limit_slack() { return assembler_->stack_limit_slack(); }
-
+ virtual bool CanReadUnaligned() { return assembler_->CanReadUnaligned(); }
virtual void AdvanceCurrentPosition(int by); // Signed cp change.
virtual void AdvanceRegister(int reg, int by); // r[reg] += by.
virtual void Backtrack();
#include "assembler.h"
#include "regexp-stack.h"
#include "regexp-macro-assembler.h"
+#if V8_TARGET_ARCH_ARM
+#include "arm/simulator-arm.h"
+#elif V8_TARGET_ARCH_IA32
+#include "ia32/simulator-ia32.h"
+#elif V8_TARGET_ARCH_X64
+#include "x64/simulator-x64.h"
+#endif
namespace v8 {
namespace internal {
}
+bool RegExpMacroAssembler::CanReadUnaligned() {
+#ifdef V8_HOST_CAN_READ_UNALIGNED
+ return true;
+#else
+ return false;
+#endif
+}
+
+
#ifdef V8_NATIVE_REGEXP // Avoid unused code, e.g., on ARM.
NativeRegExpMacroAssembler::NativeRegExpMacroAssembler() {
NativeRegExpMacroAssembler::~NativeRegExpMacroAssembler() {
}
+
+bool NativeRegExpMacroAssembler::CanReadUnaligned() {
+#ifdef V8_TARGET_CAN_READ_UNALIGNED
+ return true;
+#else
+ return false;
+#endif
+}
+
const byte* NativeRegExpMacroAssembler::StringCharacterPosition(
String* subject,
int start_index) {
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);
+ int result = CALL_GENERATED_REGEXP_CODE(matcher_func,
+ input,
+ start_offset,
+ input_start,
+ input_end,
+ output,
+ at_start_val,
+ stack_base);
ASSERT(result <= SUCCESS);
ASSERT(result >= RETRY);
return 1;
}
+
+Address NativeRegExpMacroAssembler::GrowStack(Address stack_pointer,
+ Address* stack_base) {
+ size_t size = RegExpStack::stack_capacity();
+ 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_base = new_stack_base;
+ intptr_t stack_content_size = old_stack_base - stack_pointer;
+ return new_stack_base - stack_content_size;
+}
+
#endif // V8_NATIVE_REGEXP
} } // namespace v8::internal
// kCheckStackLimit flag to push operations (instead of kNoStackLimitCheck)
// at least once for every stack_limit() pushes that are executed.
virtual int stack_limit_slack() = 0;
+ virtual bool CanReadUnaligned();
virtual void AdvanceCurrentPosition(int by) = 0; // Signed cp change.
virtual void AdvanceRegister(int reg, int by) = 0; // r[reg] += by.
// Continues execution from the position pushed on the top of the backtrack
NativeRegExpMacroAssembler();
virtual ~NativeRegExpMacroAssembler();
+ virtual bool CanReadUnaligned();
static Result Match(Handle<Code> regexp,
Handle<String> subject,
Address byte_offset2,
size_t byte_length);
+ // 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);
+
static const byte* StringCharacterPosition(String* subject, int start_index);
static Result Execute(Code* code,
int* output,
bool at_start);
};
+
+
+// Enter C code from generated RegExp code in a way that allows
+// the C code to fix the return address in case of a GC.
+// Currently only needed on ARM.
+class RegExpCEntryStub: public CodeStub {
+ public:
+ RegExpCEntryStub() {}
+ virtual ~RegExpCEntryStub() {}
+ void Generate(MacroAssembler* masm);
+
+ private:
+ Major MajorKey() { return RegExpCEntry; }
+ int MinorKey() { return 0; }
+ const char* GetName() { return "RegExpCEntryStub"; }
+};
+
#endif // V8_NATIVE_REGEXP
+
} } // namespace v8::internal
#endif // V8_REGEXP_MACRO_ASSEMBLER_H_
UNCLASSIFIED,
17,
"compare_doubles");
+#ifdef V8_NATIVE_REGEXP
+ Add(ExternalReference::re_case_insensitive_compare_uc16().address(),
+ UNCLASSIFIED,
+ 18,
+ "NativeRegExpMacroAssembler::CaseInsensitiveCompareUC16()");
+ Add(ExternalReference::re_check_stack_guard_state().address(),
+ UNCLASSIFIED,
+ 19,
+ "RegExpMacroAssembler*::CheckStackGuardState()");
+ Add(ExternalReference::re_grow_stack().address(),
+ UNCLASSIFIED,
+ 20,
+ "NativeRegExpMacroAssembler::GrowStack()");
+#endif
}
writer_->PutC(FLAG_debug_serialization ? '1' : '0');
#else
writer_->PutC('0');
+#endif
+#ifdef V8_NATIVE_REGEXP
+ writer_->PutC('N');
+#else // Interpreted regexp
+ writer_->PutC('I');
#endif
// Write sizes of paged memory spaces. Allocate extra space for the old
// and code spaces, because objects in new space will be promoted to them.
// In release mode, don't attempt to read a snapshot containing
// synchronization tags.
if (reader_.GetC() != '0') FATAL("Snapshot contains synchronization tags.");
+#endif
+#ifdef V8_NATIVE_REGEXP
+ reader_.ExpectC('N');
+#else // Interpreted regexp.
+ reader_.ExpectC('I');
#endif
// Ensure sufficient capacity in paged memory spaces to avoid growth
// during deserialization.
namespace v8 {
namespace internal {
+#ifdef V8_NATIVE_REGEXP
+
/*
* This assembler uses the following register assignment convention
* - rdx : currently loaded character(s) as ASCII or UC16. Must be loaded using
success_label_(),
backtrack_label_(),
exit_label_() {
+ ASSERT_EQ(0, registers_to_save % 2);
__ jmp(&entry_label_); // We'll write the entry code when we know more.
__ bind(&start_label_); // And then continue from here.
}
// Set byte_length.
__ movq(rdx, rbx);
#endif
- Address function_address = FUNCTION_ADDR(&CaseInsensitiveCompareUC16);
- CallCFunction(function_address, num_arguments);
+ ExternalReference compare =
+ ExternalReference::re_case_insensitive_compare_uc16();
+ CallCFunction(compare, num_arguments);
// Restore original values before reacting on result value.
__ Move(code_object_pointer(), masm_->CodeObject());
// First argument, backtrack stackpointer, is already in rcx.
__ lea(rdx, Operand(rbp, kStackHighEnd)); // Second argument
#else
- // AMD64 ABI passes paremeters in rdi, rsi.
+ // AMD64 ABI passes parameters in rdi, rsi.
__ movq(rdi, backtrack_stackpointer()); // First argument.
__ lea(rsi, Operand(rbp, kStackHighEnd)); // Second argument.
#endif
- CallCFunction(FUNCTION_ADDR(&GrowStack), num_arguments);
+ ExternalReference grow_stack = ExternalReference::re_grow_stack();
+ CallCFunction(grow_stack, num_arguments);
// If return NULL, we have failed to grow the stack, and
// must exit with a stack-overflow exception.
__ testq(rax, rax);
int characters) {
ASSERT(cp_offset >= -1); // ^ and \b can look behind one character.
ASSERT(cp_offset < (1<<30)); // Be sane! (And ensure negation works)
- CheckPosition(cp_offset + characters - 1, on_end_of_input);
+ if (check_bounds) {
+ CheckPosition(cp_offset + characters - 1, on_end_of_input);
+ }
LoadCurrentCharacterUnchecked(cp_offset, characters);
}
// return address).
__ lea(rdi, Operand(rsp, -kPointerSize));
#endif
- CallCFunction(FUNCTION_ADDR(&CheckStackGuardState), num_arguments);
+ ExternalReference stack_check =
+ ExternalReference::re_check_stack_guard_state();
+ CallCFunction(stack_check, num_arguments);
}
}
-Address RegExpMacroAssemblerX64::GrowStack(Address stack_pointer,
- Address* stack_base) {
- size_t size = RegExpStack::stack_capacity();
- 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_base = new_stack_base;
- intptr_t stack_content_size = old_stack_base - stack_pointer;
- return new_stack_base - stack_content_size;
-}
-
-
Operand RegExpMacroAssemblerX64::register_location(int register_index) {
ASSERT(register_index < (1<<30));
if (num_registers_ <= register_index) {
}
-void RegExpMacroAssemblerX64::CallCFunction(Address function_address,
+void RegExpMacroAssemblerX64::CallCFunction(ExternalReference function,
int num_arguments) {
- // Don't compile regexps with serialization enabled. The addresses of the C++
- // function being called isn't relocatable.
- ASSERT(!Serializer::enabled());
- __ movq(rax, reinterpret_cast<intptr_t>(function_address), RelocInfo::NONE);
+ __ movq(rax, function);
__ call(rax);
ASSERT(OS::ActivationFrameAlignment() != 0);
#ifdef _WIN64
__ movq(rsp, Operand(rsp, num_arguments * kPointerSize));
#else
+ // All arguments passed in registers.
+ ASSERT(num_arguments <= 6);
__ pop(rsp);
#endif
}
}
+void RegExpCEntryStub::Generate(MacroAssembler* masm_) {
+ __ int3(); // Unused on x64.
+}
+
#undef __
+
+#endif // V8_NATIVE_REGEXP
+
}} // namespace v8::internal
namespace v8 {
namespace internal {
+#ifdef V8_NATIVE_REGEXP
+
class RegExpMacroAssemblerX64: public NativeRegExpMacroAssembler {
public:
RegExpMacroAssemblerX64(Mode mode, int registers_to_save);
int* output,
bool at_start);
+ // 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);
+
private:
// Offsets from rbp of function parameters and stored registers.
static const int kFramePointer = 0;
// 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);
// 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);
+ inline void CallCFunction(ExternalReference function, int num_arguments);
MacroAssembler* masm_;
Label stack_overflow_label_;
};
+#endif // V8_NATIVE_REGEXP
+
}} // namespace v8::internal
#endif // V8_X64_REGEXP_MACRO_ASSEMBLER_X64_H_
(reinterpret_cast<uintptr_t>(this) >= limit ? \
reinterpret_cast<uintptr_t>(this) - limit : 0)
+// Call the generated regexp code directly. The entry function pointer should
+// expect seven int/pointer sized arguments and return an int.
+#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6) \
+ entry(p0, p1, p2, p3, p4, p5, p6)
+
#endif // V8_X64_SIMULATOR_X64_H_
Label L, C;
__ mov(ip, Operand(sp));
- __ stm(db_w, sp, r4.bit() | fp.bit() | sp.bit() | lr.bit());
+ __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit());
__ sub(fp, ip, Operand(4));
__ mov(r4, Operand(r0));
__ ldr(r0, MemOperand(r4, OFFSET_OF(T, i)));
__ add(r0, r2, Operand(r0));
__ mov(r2, Operand(r2, ASR, 3));
__ strh(r2, MemOperand(r4, OFFSET_OF(T, s)));
- __ ldm(ia, sp, r4.bit() | fp.bit() | sp.bit() | pc.bit());
+ __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit());
CodeDesc desc;
assm.GetCode(&desc);
#include "regexp-macro-assembler-irregexp.h"
#ifdef V8_NATIVE_REGEXP
#ifdef V8_TARGET_ARCH_ARM
+#include "arm/macro-assembler-arm.h"
#include "arm/regexp-macro-assembler-arm.h"
#endif
#ifdef V8_TARGET_ARCH_X64
#ifdef V8_NATIVE_REGEXP
-#ifdef V8_TARGET_ARCH_IA32
+#if V8_TARGET_ARCH_IA32
typedef RegExpMacroAssemblerIA32 ArchRegExpMacroAssembler;
-#endif
-#ifdef V8_TARGET_ARCH_X64
+#elif V8_TARGET_ARCH_X64
typedef RegExpMacroAssemblerX64 ArchRegExpMacroAssembler;
+#elif V8_TARGET_ARCH_ARM
+typedef RegExpMacroAssemblerARM ArchRegExpMacroAssembler;
#endif
class ContextInitializer {
v8::V8::Initialize();
ContextInitializer initializer;
- ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::ASCII, 3);
+ ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::ASCII, 4);
m.WriteCurrentPositionToRegister(0, 0);
m.AdvanceCurrentPosition(2);
Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
Address start_adr = seq_input->GetCharsAddress();
- int output[3];
+ int output[4];
NativeRegExpMacroAssembler::Result result =
Execute(*code,
*input,
CHECK_EQ(0, output[0]);
CHECK_EQ(2, output[1]);
CHECK_EQ(6, output[2]);
+ CHECK_EQ(-1, output[3]);
}
v8::V8::Initialize();
ContextInitializer initializer;
- ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::UC16, 3);
+ ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::UC16, 4);
m.WriteCurrentPositionToRegister(0, 0);
m.AdvanceCurrentPosition(2);
Handle<SeqTwoByteString> seq_input = Handle<SeqTwoByteString>::cast(input);
Address start_adr = seq_input->GetCharsAddress();
- int output[3];
+ int output[4];
NativeRegExpMacroAssembler::Result result =
Execute(*code,
*input,
CHECK_EQ(0, output[0]);
CHECK_EQ(2, output[1]);
CHECK_EQ(6, output[2]);
+ CHECK_EQ(-1, output[3]);
}
v8::V8::Initialize();
ContextInitializer initializer;
- ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::ASCII, 5);
+ ArchRegExpMacroAssembler m(NativeRegExpMacroAssembler::ASCII, 6);
uc16 foo_chars[3] = {'f', 'o', 'o'};
Vector<const uc16> foo(foo_chars, 3);
- enum registers { out1, out2, out3, out4, out5, sp, loop_cnt };
+ enum registers { out1, out2, out3, out4, out5, out6, sp, loop_cnt };
Label fail;
Label backtrack;
m.WriteCurrentPositionToRegister(out1, 0); // Output: [0]
m.GoTo(&loop3);
m.Bind(&exit_loop3);
m.PopCurrentPosition();
- m.WriteCurrentPositionToRegister(out5, 0); // [0,3,6,9,9]
+ m.WriteCurrentPositionToRegister(out5, 0); // [0,3,6,9,9,-1]
m.Succeed();
Handle<SeqAsciiString> seq_input = Handle<SeqAsciiString>::cast(input);
Address start_adr = seq_input->GetCharsAddress();
- int output[5];
+ int output[6];
NativeRegExpMacroAssembler::Result result =
Execute(*code,
- *input,
- 0,
- start_adr,
- start_adr + input->length(),
- output,
- true);
+ *input,
+ 0,
+ start_adr,
+ start_adr + input->length(),
+ output,
+ true);
CHECK_EQ(NativeRegExpMacroAssembler::SUCCESS, result);
CHECK_EQ(0, output[0]);
CHECK_EQ(6, output[2]);
CHECK_EQ(9, output[3]);
CHECK_EQ(9, output[4]);
+ CHECK_EQ(-1, output[5]);
}
'../../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=="ia32" 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',
'../../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': [