Merge regexp2000 back into bleeding_edge

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@832 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 112e9ebb
......@@ -35,15 +35,17 @@ Import('context')
SOURCES = {
'all': [
'accessors.cc', 'allocation.cc', 'api.cc', 'assembler.cc', 'ast.cc',
'bootstrapper.cc', 'builtins.cc', 'checks.cc', 'code-stubs.cc',
'codegen.cc', 'compilation-cache.cc', 'compiler.cc', 'contexts.cc',
'conversions.cc', 'counters.cc', 'dateparser.cc', 'debug.cc',
'disassembler.cc', 'execution.cc', 'factory.cc', 'flags.cc', 'frames.cc',
'global-handles.cc', 'handles.cc', 'hashmap.cc', 'heap.cc', 'ic.cc',
'jsregexp.cc', 'log.cc', 'mark-compact.cc', 'messages.cc', 'objects.cc',
'parser.cc', 'property.cc', 'rewriter.cc', 'runtime.cc', 'scanner.cc',
'scopeinfo.cc', 'scopes.cc', 'serialize.cc', 'snapshot-common.cc',
'accessors.cc', 'allocation.cc', 'api.cc', 'assembler.cc',
'assembler-irregexp.cc', 'ast.cc', 'bootstrapper.cc', 'builtins.cc',
'checks.cc', 'code-stubs.cc', 'codegen.cc', 'compilation-cache.cc',
'compiler.cc', 'contexts.cc', 'conversions.cc', 'counters.cc',
'dateparser.cc', 'debug.cc', 'disassembler.cc', 'execution.cc',
'factory.cc', 'flags.cc', 'frames.cc', 'global-handles.cc',
'handles.cc', 'hashmap.cc', 'heap.cc', 'ic.cc', 'interpreter-irregexp.cc',
'jsregexp.cc', 'log.cc', 'mark-compact.cc', 'messages.cc',
'objects.cc', 'parser.cc', 'property.cc', 'regexp-macro-assembler.cc',
'regexp-macro-assembler-irregexp.cc', 'rewriter.cc', 'runtime.cc', 'scanner.cc',
'scopeinfo.cc', 'scopes.cc', 'serialize.cc', 'snapshot-common.cc',
'spaces.cc', 'string-stream.cc', 'stub-cache.cc', 'token.cc', 'top.cc',
'unicode.cc', 'usage-analyzer.cc', 'utils.cc', 'v8-counters.cc',
'v8.cc', 'v8threads.cc', 'variables.cc', 'zone.cc'
......@@ -53,7 +55,8 @@ SOURCES = {
'macro-assembler-arm.cc', 'stub-cache-arm.cc'],
'arch:ia32': ['assembler-ia32.cc', 'builtins-ia32.cc', 'codegen-ia32.cc',
'cpu-ia32.cc', 'disasm-ia32.cc', 'frames-ia32.cc', 'ic-ia32.cc',
'macro-assembler-ia32.cc', 'stub-cache-ia32.cc'],
'macro-assembler-ia32.cc', 'regexp-macro-assembler-ia32.cc',
'stub-cache-ia32.cc'],
'simulator:arm': ['simulator-arm.cc'],
'os:freebsd': ['platform-freebsd.cc'],
'os:linux': ['platform-linux.cc'],
......
......@@ -205,6 +205,14 @@ void Assembler::emit(const Immediate& x) {
}
void Assembler::emit_w(const Immediate& x) {
ASSERT(x.rmode_ == RelocInfo::NONE);
uint16_t value = static_cast<uint16_t>(x.x_);
reinterpret_cast<uint16_t*>(pc_)[0] = value;
pc_ += sizeof(uint16_t);
}
Address Assembler::target_address_at(Address pc) {
return pc + sizeof(int32_t) + *reinterpret_cast<int32_t*>(pc);
}
......
......@@ -122,7 +122,8 @@ void CpuFeatures::Probe() {
#undef __
CodeDesc desc;
assm.GetCode(&desc);
Object* code = Heap::CreateCode(desc, NULL, Code::ComputeFlags(Code::STUB));
Object* code =
Heap::CreateCode(desc, NULL, Code::ComputeFlags(Code::STUB), NULL);
if (!code->IsCode()) return;
F0 f = FUNCTION_CAST<F0>(Code::cast(code)->entry());
uint32_t res = f();
......@@ -294,7 +295,6 @@ Assembler::Assembler(void* buffer, int buffer_size) {
}
buffer_size_ = buffer_size;
own_buffer_ = true;
} else {
// use externally provided buffer instead
ASSERT(buffer_size > 0);
......@@ -420,6 +420,29 @@ void Assembler::push(const Operand& src) {
}
void Assembler::push(Label* label, RelocInfo::Mode reloc_mode) {
ASSERT_NOT_NULL(label);
EnsureSpace ensure_space(this);
last_pc_ = pc_;
// If reloc_mode == NONE, the label is stored as buffer relative.
ASSERT(reloc_mode == RelocInfo::NONE);
if (label->is_bound()) {
// Index of position in Code object:
int pos = label->pos() + Code::kHeaderSize;
if (pos >= 0 && pos < 256) {
EMIT(0x6a);
EMIT(pos);
} else {
EMIT(0x68);
emit(pos);
}
} else {
EMIT(0x68);
emit_disp(label, Displacement::CODE_RELATIVE);
}
}
void Assembler::pop(Register dst) {
ASSERT(reloc_info_writer.last_pc() != NULL);
if (FLAG_push_pop_elimination && (reloc_info_writer.last_pc() <= last_pc_)) {
......@@ -546,6 +569,22 @@ void Assembler::pop(const Operand& dst) {
}
void Assembler::enter(const Immediate& size) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xC8);
emit_w(size);
EMIT(0);
}
void Assembler::leave() {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xC9);
}
void Assembler::mov_b(Register dst, const Operand& src) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
......@@ -830,6 +869,23 @@ void Assembler::cmp(const Operand& op, const Immediate& imm) {
}
void Assembler::rep_cmpsb() {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xFC); // CLD to ensure forward operation
EMIT(0xF3); // REP
EMIT(0xA6); // CMPSB
}
void Assembler::rep_cmpsw() {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xFC); // CLD to ensure forward operation
EMIT(0xF3); // REP
EMIT(0xA7); // CMPSW
}
void Assembler::dec_b(Register dst) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
......@@ -1074,6 +1130,14 @@ void Assembler::shr(Register dst) {
}
void Assembler::shr_cl(Register dst) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xD1);
EMIT(0xE8 | dst.code());
}
void Assembler::sub(const Operand& dst, const Immediate& x) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
......@@ -1171,6 +1235,15 @@ void Assembler::xor_(const Operand& dst, const Immediate& x) {
}
void Assembler::bt(const Operand& dst, Register src) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0x0F);
EMIT(0xA3);
emit_operand(src, dst);
}
void Assembler::bts(const Operand& dst, Register src) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
......@@ -1224,13 +1297,6 @@ void Assembler::ret(int imm16) {
}
void Assembler::leave() {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
EMIT(0xC9);
}
// Labels refer to positions in the (to be) generated code.
// There are bound, linked, and unused labels.
//
......@@ -1270,12 +1336,16 @@ void Assembler::bind_to(Label* L, int pos) {
while (L->is_linked()) {
Displacement disp = disp_at(L);
int fixup_pos = L->pos();
if (disp.type() == Displacement::UNCONDITIONAL_JUMP) {
ASSERT(byte_at(fixup_pos - 1) == 0xE9); // jmp expected
if (disp.type() == Displacement::CODE_RELATIVE) {
long_at_put(fixup_pos, pos + Code::kHeaderSize);
} else {
if (disp.type() == Displacement::UNCONDITIONAL_JUMP) {
ASSERT(byte_at(fixup_pos - 1) == 0xE9); // jmp expected
}
// relative address, relative to point after address
int imm32 = pos - (fixup_pos + sizeof(int32_t));
long_at_put(fixup_pos, imm32);
}
// relative address, relative to point after address
int imm32 = pos - (fixup_pos + sizeof(int32_t));
long_at_put(fixup_pos, imm32);
disp.next(L);
}
L->bind_to(pos);
......
......@@ -118,8 +118,8 @@ enum Condition {
not_equal = 5,
below_equal = 6,
above = 7,
sign = 8,
not_sign = 9,
negative = 8,
positive = 9,
parity_even = 10,
parity_odd = 11,
less = 12,
......@@ -128,10 +128,12 @@ enum Condition {
greater = 15,
// aliases
carry = below,
not_carry = above_equal,
zero = equal,
not_zero = not_equal,
negative = sign,
positive = not_sign
sign = negative,
not_sign = positive
};
......@@ -283,13 +285,14 @@ class Operand BASE_EMBEDDED {
//
// Displacement _data field layout
//
// |31.....1| ......0|
// |31.....2|1......0|
// [ next | type |
class Displacement BASE_EMBEDDED {
public:
enum Type {
UNCONDITIONAL_JUMP,
CODE_RELATIVE,
OTHER
};
......@@ -313,8 +316,8 @@ class Displacement BASE_EMBEDDED {
private:
int data_;
class TypeField: public BitField<Type, 0, 1> {};
class NextField: public BitField<int, 1, 32-1> {};
class TypeField: public BitField<Type, 0, 2> {};
class NextField: public BitField<int, 2, 32-2> {};
void init(Label* L, Type type);
};
......@@ -440,10 +443,14 @@ class Assembler : public Malloced {
void push(const Immediate& x);
void push(Register src);
void push(const Operand& src);
void push(Label* label, RelocInfo::Mode relocation_mode);
void pop(Register dst);
void pop(const Operand& dst);
void enter(const Immediate& size);
void leave();
// Moves
void mov_b(Register dst, const Operand& src);
void mov_b(const Operand& dst, int8_t imm8);
......@@ -491,6 +498,9 @@ class Assembler : public Malloced {
void cmp(Register reg, const Operand& op);
void cmp(const Operand& op, const Immediate& imm);
void rep_cmpsb();
void rep_cmpsw();
void dec_b(Register dst);
void dec(Register dst);
......@@ -535,6 +545,7 @@ class Assembler : public Malloced {
void shr(Register dst, uint8_t imm8);
void shr(Register dst);
void shr_cl(Register dst);
void sub(const Operand& dst, const Immediate& x);
void sub(Register dst, const Operand& src);
......@@ -550,6 +561,7 @@ class Assembler : public Malloced {
void xor_(const Operand& dst, const Immediate& x);
// Bit operations.
void bt(const Operand& dst, Register src);
void bts(const Operand& dst, Register src);
// Miscellaneous
......@@ -558,7 +570,6 @@ class Assembler : public Malloced {
void nop();
void rdtsc();
void ret(int imm16);
void leave();
// Label operations & relative jumps (PPUM Appendix D)
//
......@@ -748,6 +759,7 @@ class Assembler : public Malloced {
inline void emit(Handle<Object> handle);
inline void emit(uint32_t x, RelocInfo::Mode rmode);
inline void emit(const Immediate& x);
inline void emit_w(const Immediate& x);
// instruction generation
void emit_arith_b(int op1, int op2, Register dst, int imm8);
......
// Copyright 2008 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// A light-weight assembler for the Regexp2000 byte code.
#include "v8.h"
#include "ast.h"
#include "bytecodes-irregexp.h"
#include "assembler-irregexp.h"
namespace v8 { namespace internal {
void IrregexpAssembler::Emit(uint32_t byte) {
ASSERT(pc_ <= buffer_.length());
if (pc_ == buffer_.length()) {
Expand();
}
buffer_[pc_++] = byte;
}
void IrregexpAssembler::Emit16(uint32_t word) {
ASSERT(pc_ <= buffer_.length());
if (pc_ + 1 >= buffer_.length()) {
Expand();
}
Store16(buffer_.start() + pc_, word);
pc_ += 2;
}
void IrregexpAssembler::Emit32(uint32_t word) {
ASSERT(pc_ <= buffer_.length());
if (pc_ + 3 >= buffer_.length()) {
Expand();
}
Store32(buffer_.start() + pc_, word);
pc_ += 4;
}
void IrregexpAssembler::EmitOrLink(Label* l) {
if (l->is_bound()) {
Emit32(l->pos());
} else {
int pos = 0;
if (l->is_linked()) {
pos = l->pos();
}
l->link_to(pc_);
Emit32(pos);
}
}
} } // namespace v8::internal
// Copyright 2008 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// A light-weight assembler for the Irregexp byte code.
#include "v8.h"
#include "ast.h"
#include "bytecodes-irregexp.h"
#include "assembler-irregexp.h"
#include "assembler-irregexp-inl.h"
namespace v8 { namespace internal {
IrregexpAssembler::IrregexpAssembler(Vector<byte> buffer)
: buffer_(buffer),
pc_(0),
own_buffer_(false) {
}
IrregexpAssembler::~IrregexpAssembler() {
if (own_buffer_) {
buffer_.Dispose();
}
}
void IrregexpAssembler::PushCurrentPosition(int cp_offset) {
ASSERT(cp_offset >= 0);
Emit(BC_PUSH_CP);
Emit32(cp_offset);
}
void IrregexpAssembler::PushBacktrack(Label* l) {
Emit(BC_PUSH_BT);
EmitOrLink(l);
}
void IrregexpAssembler::PushRegister(int index) {
ASSERT(index >= 0);
Emit(BC_PUSH_REGISTER);
Emit(index);
}
void IrregexpAssembler::WriteCurrentPositionToRegister(int index,
int cp_offset) {
ASSERT(cp_offset >= 0);
ASSERT(index >= 0);
Emit(BC_SET_REGISTER_TO_CP);
Emit(index);
Emit32(cp_offset);
}
void IrregexpAssembler::ReadCurrentPositionFromRegister(int index) {
ASSERT(index >= 0);
Emit(BC_SET_CP_TO_REGISTER);
Emit(index);
}
void IrregexpAssembler::WriteStackPointerToRegister(int index) {
ASSERT(index >= 0);
Emit(BC_SET_REGISTER_TO_SP);
Emit(index);
}
void IrregexpAssembler::ReadStackPointerFromRegister(int index) {
ASSERT(index >= 0);
Emit(BC_SET_SP_TO_REGISTER);
Emit(index);
}
void IrregexpAssembler::SetRegister(int index, int value) {
ASSERT(index >= 0);
Emit(BC_SET_REGISTER);
Emit(index);
Emit32(value);
}
void IrregexpAssembler::AdvanceRegister(int index, int by) {
ASSERT(index >= 0);
Emit(BC_ADVANCE_REGISTER);
Emit(index);
Emit32(by);
}
void IrregexpAssembler::PopCurrentPosition() {
Emit(BC_POP_CP);
}
void IrregexpAssembler::PopBacktrack() {
Emit(BC_POP_BT);
}
void IrregexpAssembler::PopRegister(int index) {
Emit(BC_POP_REGISTER);
Emit(index);
}
void IrregexpAssembler::Fail() {
Emit(BC_FAIL);
}
void IrregexpAssembler::Break() {
Emit(BC_BREAK);
}
void IrregexpAssembler::Succeed() {
Emit(BC_SUCCEED);
}
void IrregexpAssembler::Bind(Label* l) {
ASSERT(!l->is_bound());
if (l->is_linked()) {
int pos = l->pos();
while (pos != 0) {
int fixup = pos;
pos = Load32(buffer_.start() + fixup);
Store32(buffer_.start() + fixup, pc_);
}
}
l->bind_to(pc_);
}
void IrregexpAssembler::AdvanceCP(int cp_offset) {
Emit(BC_ADVANCE_CP);
Emit32(cp_offset);
}
void IrregexpAssembler::GoTo(Label* l) {
Emit(BC_GOTO);
EmitOrLink(l);
}
void IrregexpAssembler::LoadCurrentChar(int cp_offset, Label* on_end) {
Emit(BC_LOAD_CURRENT_CHAR);
Emit32(cp_offset);
EmitOrLink(on_end);
}
void IrregexpAssembler::CheckCharacter(uc16 c, Label* on_match) {
Emit(BC_CHECK_CHAR);
Emit16(c);
EmitOrLink(on_match);
}
void IrregexpAssembler::CheckNotCharacter(uc16 c, Label* on_mismatch) {
Emit(BC_CHECK_NOT_CHAR);
Emit16(c);
EmitOrLink(on_mismatch);
}
void IrregexpAssembler::OrThenCheckNotCharacter(uc16 c,
uc16 mask,
Label* on_mismatch) {
Emit(BC_OR_CHECK_NOT_CHAR);
Emit16(c);
Emit16(mask);
EmitOrLink(on_mismatch);
}
void IrregexpAssembler::MinusOrThenCheckNotCharacter(uc16 c,
uc16 mask,
Label* on_mismatch) {
Emit(BC_MINUS_OR_CHECK_NOT_CHAR);
Emit16(c);
Emit16(mask);
EmitOrLink(on_mismatch);
}
void IrregexpAssembler::CheckCharacterLT(uc16 limit, Label* on_less) {
Emit(BC_CHECK_LT);
Emit16(limit);
EmitOrLink(on_less);
}
void IrregexpAssembler::CheckCharacterGT(uc16 limit, Label* on_greater) {
Emit(BC_CHECK_GT);
Emit16(limit);
EmitOrLink(on_greater);
}
void IrregexpAssembler::CheckNotBackReference(int capture_index,
Label* on_mismatch) {
Emit(BC_CHECK_NOT_BACK_REF);
Emit(capture_index);
EmitOrLink(on_mismatch);
}
void IrregexpAssembler::CheckRegister(int byte_code,
int reg_index,
uint16_t vs,
Label* on_true) {
Emit(byte_code);
Emit(reg_index);
Emit16(vs);
EmitOrLink(on_true);
}
void IrregexpAssembler::CheckRegisterLT(int reg_index,
uint16_t vs,
Label* on_less_than) {
CheckRegister(BC_CHECK_REGISTER_LT, reg_index, vs, on_less_than);
}
void IrregexpAssembler::CheckRegisterGE(int reg_index,
uint16_t vs,
Label* on_greater_than_equal) {
CheckRegister(BC_CHECK_REGISTER_GE, reg_index, vs, on_greater_than_equal);
}
void IrregexpAssembler::LookupMap1(uc16 start, Label* bit_map, Label* on_zero) {
Emit(BC_LOOKUP_MAP1);
Emit16(start);
EmitOrLink(bit_map);
EmitOrLink(on_zero);
}
void IrregexpAssembler::LookupMap2(uc16 start,
Label* half_nibble_map,
const Vector<Label*>& table) {
Emit(BC_LOOKUP_MAP2);
Emit16(start);
EmitOrLink(half_nibble_map);
ASSERT(table.length() > 0);
ASSERT(table.length() <= 4);
for (int i = 0; i < table.length(); i++) {
EmitOrLink(table[i]);
}
}
void IrregexpAssembler::LookupMap8(uc16 start,
Label* byte_map,
const Vector<Label*>& table) {
Emit(BC_LOOKUP_MAP8);
Emit16(start);
EmitOrLink(byte_map);
ASSERT(table.length() > 0);
ASSERT(table.length() <= 256);
for (int i = 0; i < table.length(); i++) {
EmitOrLink(table[i]);
}
}
void IrregexpAssembler::LookupHighMap8(byte start,
Label* byte_map,
const Vector<Label*>& table) {
Emit(BC_LOOKUP_HI_MAP8);
Emit(start);
EmitOrLink(byte_map);
ASSERT(table.length() > 0);
ASSERT(table.length() <= 256);
for (int i = 0; i < table.length(); i++) {
EmitOrLink(table[i]);
}
}
int IrregexpAssembler::length() {
return pc_;
}
void IrregexpAssembler::Copy(Address a) {
memcpy(a, buffer_.start(), length());
}
void IrregexpAssembler::Expand() {
bool old_buffer_was_our_own = own_buffer_;
Vector<byte> old_buffer = buffer_;
buffer_ = Vector<byte>::New(old_buffer.length() * 2);
own_buffer_ = true;
memcpy(buffer_.start(), old_buffer.start(), old_buffer.length());
if (old_buffer_was_our_own) {
old_buffer.Dispose();
}
}
} } // namespace v8::internal
// Copyright 2006-2008 the V8 project authors. All rights reserved.
// A light-weight assembler for the Irregexp byte code.
#ifndef V8_ASSEMBLER_IRREGEXP_H_
#define V8_ASSEMBLER_IRREGEXP_H_
namespace v8 { namespace internal {
class IrregexpAssembler {
public:
// Create an assembler. Instructions and relocation information are emitted
// into a buffer, with the instructions starting from the beginning and the
// relocation information starting from the end of the buffer. See CodeDesc
// for a detailed comment on the layout (globals.h).
//
// If the provided buffer is NULL, the assembler allocates and grows its own
// buffer, and buffer_size determines the initial buffer size. The buffer is
// owned by the assembler and deallocated upon destruction of the assembler.
//
// If the provided buffer is not NULL, the assembler uses the provided buffer
// for code generation and assumes its size to be buffer_size. If the buffer
// is too small, a fatal error occurs. No deallocation of the buffer is done
// upon destruction of the assembler.
explicit IrregexpAssembler(Vector<byte>);
~IrregexpAssembler();
// CP = current position in source.
// BT = backtrack label.
// Stack.
void PushCurrentPosition(int cp_offset = 0);
void PushBacktrack(Label* l);
void PushRegister(int index);
void WriteCurrentPositionToRegister(int index, int cp_offset = 0);
void ReadCurrentPositionFromRegister(int index);
void WriteStackPointerToRegister(int index);
void ReadStackPointerFromRegister(int index);
void SetRegister(int index, int value);
void AdvanceRegister(int index, int by);
void PopCurrentPosition();
void PopBacktrack();
void PopRegister(int index);
void Fail();
void Succeed();
void Break(); // This instruction will cause a fatal VM error if hit.
void Bind(Label* l); // Binds an unbound label L to the current code posn.
void AdvanceCP(int by);
void GoTo(Label* l);
// Loads current char into a machine register. Jumps to the label if we
// reached the end of the subject string. Fall through otherwise.
void LoadCurrentChar(int cp_offset, Label* on_end);
// Checks current char register against a singleton.
void CheckCharacter(uc16 c, Label* on_match);
void CheckNotCharacter(uc16 c, Label* on_mismatch);
void OrThenCheckNotCharacter(uc16 c, uc16 mask, Label* on_mismatch);
void MinusOrThenCheckNotCharacter(uc16 c, uc16 mask, Label* on_mismatch);
// Used to check current char register against a range.
void CheckCharacterLT(uc16 limit, Label* on_less);
void CheckCharacterGT(uc16 limit, Label* on_greater);
// Checks current position for a match against a
// previous capture. Advances current position by the length of the capture
// iff it matches. The capture is stored in a given register and the
// the register after. If a register contains -1 then the other register
// must always contain -1 and the on_mismatch label will never be called.
void CheckNotBackReference(int capture_index, Label* on_mismatch);
// Checks a register for strictly-less-than or greater-than-or-equal.
void CheckRegisterLT(int reg_index, uint16_t vs, Label* on_less_than);
void CheckRegisterGE(int reg_index, uint16_t vs, Label* on_greater_equal);
// Subtracts a 16 bit value from the current character, uses the result to
// look up in a bit array, uses the result of that decide whether to fall
// though (on 1) or jump to the on_zero label (on 0).
void LookupMap1(uc16 start, Label* bit_map, Label* on_zero);
// Subtracts a 16 bit value from the current character, uses the result to
// look up in a 2-bit array, uses the result of that to look up in a label
// table and jumps to the label.
void LookupMap2(uc16 start,
Label* half_nibble_map,
const Vector<Label*>& table);
// Subtracts a 16 bit value from the current character, uses the result to
// look up in a byte array, uses the result of that to look up in a label
// array and jumps to the label.
void LookupMap8(uc16 start, Label* byte_map, const Vector<Label*>& table);
// Takes the high byte of the current character, uses the result to
// look up in a byte array, uses the result of that to look up in a label
// array and jumps to the label.
void LookupHighMap8(byte start, Label* byte_map, const Vector<Label*>& table);
// Code and bitmap emission.
inline void Emit32(uint32_t x);
inline void Emit16(uint32_t x);
inline void Emit(uint32_t x);
// Bytecode buffer.
int length();
void Copy(Address a);
inline void EmitOrLink(Label* l);
private:
// Don't use this.
IrregexpAssembler() { UNREACHABLE(); }
// The buffer into which code and relocation info are generated.
Vector<byte> buffer_;
inline void CheckRegister(int byte_code,
int reg_index,
uint16_t vs,
Label* on_true);
// Code generation.
int pc_; // The program counter; moves forward.
// True if the assembler owns the buffer, false if buffer is external.
bool own_buffer_;
void Expand();
};
} } // namespace v8::internal
#endif // V8_ASSEMBLER_IRREGEXP_H_
......@@ -50,7 +50,8 @@ namespace v8 { namespace internal {
class Label : public ZoneObject { // LabelShadows are dynamically allocated.
public:
INLINE(Label()) { Unuse(); }
INLINE(Label())
{ Unuse(); }
INLINE(~Label()) { ASSERT(!is_linked()); }
INLINE(void Unuse()) { pos_ = 0; }
......@@ -82,8 +83,10 @@ class Label : public ZoneObject { // LabelShadows are dynamically allocated.
}
friend class Assembler;
friend class RegexpAssembler;
friend class Displacement;
friend class LabelShadow;
friend class IrregexpAssembler;
};
......
......@@ -29,6 +29,7 @@
#include "ast.h"
#include "scopes.h"
#include "string-stream.h"
namespace v8 { namespace internal {
......@@ -179,4 +180,204 @@ void Visitor::VisitExpressions(ZoneList<Expression*>* expressions) {
}
// ----------------------------------------------------------------------------
// Regular expressions
#define MAKE_ACCEPT(Name) \
void* RegExp##Name::Accept(RegExpVisitor* visitor, void* data) { \
return visitor->Visit##Name(this, data); \
}
FOR_EACH_REG_EXP_TREE_TYPE(MAKE_ACCEPT)
#undef MAKE_ACCEPT
#define MAKE_TYPE_CASE(Name) \
RegExp##Name* RegExpTree::As##Name() { \
return NULL; \
} \
bool RegExpTree::Is##Name() { return false; }
FOR_EACH_REG_EXP_TREE_TYPE(MAKE_TYPE_CASE)
#undef MAKE_TYPE_CASE
#define MAKE_TYPE_CASE(Name) \
RegExp##Name* RegExp##Name::As##Name() { \
return this; \
} \
bool RegExp##Name::Is##Name() { return true; }
FOR_EACH_REG_EXP_TREE_TYPE(MAKE_TYPE_CASE)
#undef MAKE_TYPE_CASE
RegExpEmpty RegExpEmpty::kInstance;
// Convert regular expression trees to a simple sexp representation.
// This representation should be different from the input grammar
// in as many cases as possible, to make it more difficult for incorrect
// parses to look as correct ones which is likely if the input and
// output formats are alike.
class RegExpUnparser: public RegExpVisitor {
public:
RegExpUnparser();
void VisitCharacterRange(CharacterRange that);
SmartPointer<const char> ToString() { return stream_.ToCString(); }
#define MAKE_CASE(Name) virtual void* Visit##Name(RegExp##Name*, void* data);
FOR_EACH_REG_EXP_TREE_TYPE(MAKE_CASE)
#undef MAKE_CASE
private:
StringStream* stream() { return &stream_; }
HeapStringAllocator alloc_;
StringStream stream_;
};
RegExpUnparser::RegExpUnparser() : stream_(&alloc_) {
}
void* RegExpUnparser::VisitDisjunction(RegExpDisjunction* that, void* data) {
stream()->Add("(|");
for (int i = 0; i < that->alternatives()->length(); i++) {
stream()->Add(" ");
that->alternatives()->at(i)->Accept(this, data);
}
stream()->Add(")");
return NULL;
}
void* RegExpUnparser::VisitAlternative(RegExpAlternative* that, void* data) {
stream()->Add("(:");
for (int i = 0; i < that->nodes()->length(); i++) {
stream()->Add(" ");
that->nodes()->at(i)->Accept(this, data);
}
stream()->Add(")");
return NULL;
}
void RegExpUnparser::VisitCharacterRange(CharacterRange that) {
stream()->Add("%k", that.from());
if (!that.IsSingleton()) {
stream()->Add("-%k", that.to());
}
}
void* RegExpUnparser::VisitCharacterClass(RegExpCharacterClass* that,
void* data) {
if (that->is_negated())
stream()->Add("^");
stream()->Add("[");
for (int i = 0; i < that->ranges()->length(); i++) {
if (i > 0) stream()->Add(" ");
VisitCharacterRange(that->ranges()->at(i));
}
stream()->Add("]");
return NULL;
}
void* RegExpUnparser::VisitAssertion(RegExpAssertion* that, void* data) {
switch (that->type()) {
case RegExpAssertion::START_OF_INPUT:
stream()->Add("@^i");
break;
case RegExpAssertion::END_OF_INPUT:
stream()->Add("@$i");
break;
case RegExpAssertion::START_OF_LINE:
stream()->Add("@^l");
break;
case RegExpAssertion::END_OF_LINE:
stream()->Add("@$l");
break;
case RegExpAssertion::BOUNDARY:
stream()->Add("@b");
break;
case RegExpAssertion::NON_BOUNDARY:
stream()->Add("@B");
break;
}
return NULL;
}
void* RegExpUnparser::VisitAtom(RegExpAtom* that, void* data) {
stream()->Add("'");
Vector<const uc16> chardata = that->data();
for (int i = 0; i < chardata.length(); i++) {
stream()->Add("%k", chardata[i]);
}
stream()->Add("'");
return NULL;
}
void* RegExpUnparser::VisitText(RegExpText* that, void* data) {
if (that->elements()->length() == 1) {
that->elements()->at(0).data.u_atom->Accept(this, data);
} else {
stream()->Add("(!");
for (int i = 0; i < that->elements()->length(); i++) {
stream()->Add(" ");
that->elements()->at(i).data.u_atom->Accept(this, data);
}
stream()->Add(")");
}
return NULL;
}
void* RegExpUnparser::VisitQuantifier(RegExpQuantifier* that, void* data) {
stream()->Add("(# %i ", that->min());
if (that->max() == RegExpQuantifier::kInfinity) {
stream()->Add("- ");
} else {
stream()->Add("%i ", that->max());
}
stream()->Add(that->is_greedy() ? "g " : "n ");
that->body()->Accept(this, data);
stream()->Add(")");
return NULL;
}
void* RegExpUnparser::VisitCapture(RegExpCapture* that, void* data) {
stream()->Add("(^ ");
that->body()->Accept(this, data);
stream()->Add(")");
return NULL;
}
void* RegExpUnparser::VisitLookahead(RegExpLookahead* that, void* data) {
stream()->Add("(-> ");
stream()->Add(that->is_positive() ? "+ " : "- ");
that->body()->Accept(this, data);
stream()->Add(")");
return NULL;
}
void* RegExpUnparser::VisitBackReference(RegExpBackReference* that,
void* data) {
stream()->Add("(<- %i)", that->index());
return NULL;
}
void* RegExpUnparser::VisitEmpty(RegExpEmpty* that, void* data) {
stream()->Put('%');
return NULL;
}
SmartPointer<const char> RegExpTree::ToString() {
RegExpUnparser unparser;
Accept(&unparser, NULL);
return unparser.ToString();
}
} } // namespace v8::internal
......@@ -34,6 +34,7 @@
#include "token.h"
#include "variables.h"
#include "macro-assembler.h"
#include "jsregexp.h"
namespace v8 { namespace internal {
......@@ -1191,6 +1192,268 @@ class ThisFunction: public Expression {
};
// ----------------------------------------------------------------------------
// Regular expressions
class RegExpTree: public ZoneObject {
public:
virtual ~RegExpTree() { }
virtual void* Accept(RegExpVisitor* visitor, void* data) = 0;
virtual RegExpNode* ToNode(RegExpCompiler* compiler,
RegExpNode* on_success,
RegExpNode* on_failure) = 0;
virtual bool IsTextElement() { return false; }
virtual void AppendToText(RegExpText* text);
SmartPointer<const char> ToString();
#define MAKE_ASTYPE(Name) \
virtual RegExp##Name* As##Name(); \
virtual bool Is##Name();
FOR_EACH_REG_EXP_TREE_TYPE(MAKE_ASTYPE)
#undef MAKE_ASTYPE
};
class RegExpDisjunction: public RegExpTree {
public:
explicit RegExpDisjunction(ZoneList<RegExpTree*>* alternatives)
: alternatives_(alternatives) { }
virtual void* Accept(RegExpVisitor* visitor, void* data);
virtual RegExpNode* ToNode(RegExpCompiler* compiler,
RegExpNode* on_success,
RegExpNode* on_failure);
virtual RegExpDisjunction* AsDisjunction();
virtual bool IsDisjunction();
ZoneList<RegExpTree*>* alternatives() { return alternatives_; }
private:
ZoneList<RegExpTree*>* alternatives_;
};
class RegExpAlternative: public RegExpTree {
public:
explicit RegExpAlternative(ZoneList<RegExpTree*>* nodes) : nodes_(nodes) { }
virtual void* Accept(RegExpVisitor* visitor, void* data);
virtual RegExpNode* ToNode(RegExpCompiler* compiler,
RegExpNode* on_success,
RegExpNode* on_failure);
virtual RegExpAlternative* AsAlternative();
virtual bool IsAlternative();
ZoneList<RegExpTree*>* nodes() { return nodes_; }
private:
ZoneList<RegExpTree*>* nodes_;
};
class RegExpText: public RegExpTree {
public:
RegExpText() : elements_(2) { }
virtual void* Accept(RegExpVisitor* visitor, void* data);
virtual RegExpNode* ToNode(RegExpCompiler* compiler,
RegExpNode* on_success,
RegExpNode* on_failure);
virtual RegExpText* AsText();
virtual bool IsText();
virtual bool IsTextElement() { return true; }
virtual void AppendToText(RegExpText* text);
void AddElement(TextElement elm) { elements_.Add(elm); }
ZoneList<TextElement>* elements() { return &elements_; }
private:
ZoneList<TextElement> elements_;
};
class RegExpAssertion: public RegExpTree {
public:
enum Type {
START_OF_LINE, START_OF_INPUT, END_OF_LINE, END_OF_INPUT,
BOUNDARY, NON_BOUNDARY
};
explicit RegExpAssertion(Type type) : type_(type) { }
virtual void* Accept(RegExpVisitor* visitor, void* data);
virtual RegExpNode* ToNode(RegExpCompiler* compiler,
RegExpNode* on_success,
RegExpNode* on_failure);
virtual RegExpAssertion* AsAssertion();
virtual bool IsAssertion();
Type type() { return type_; }
private:
Type type_;
};
class RegExpCharacterClass: public RegExpTree {
public:
RegExpCharacterClass(ZoneList<CharacterRange>* ranges, bool is_negated)
: ranges_(ranges),
is_negated_(is_negated) { }
explicit RegExpCharacterClass(uc16 type)
: ranges_(new ZoneList<CharacterRange>(2)),
is_negated_(false) {
CharacterRange::AddClassEscape(type, ranges_);
}
virtual void* Accept(RegExpVisitor* visitor, void* data);
virtual RegExpNode* ToNode(RegExpCompiler* compiler,
RegExpNode* on_success,
RegExpNode* on_failure);
virtual RegExpCharacterClass* AsCharacterClass();
virtual bool IsCharacterClass();
virtual bool IsTextElement() { return true; }
virtual void AppendToText(RegExpText* text);
ZoneList<CharacterRange>* ranges() { return ranges_; }
bool is_negated() { return is_negated_; }
private:
ZoneList<CharacterRange>* ranges_;
bool is_negated_;
};
class RegExpAtom: public RegExpTree {
public:
explicit RegExpAtom(Vector<const uc16> data) : data_(data) { }
virtual void* Accept(RegExpVisitor* visitor, void* data);
virtual RegExpNode* ToNode(RegExpCompiler* compiler,
RegExpNode* on_success,
RegExpNode* on_failure);
virtual RegExpAtom* AsAtom();
virtual bool IsAtom();
virtual bool IsTextElement() { return true; }
virtual void AppendToText(RegExpText* text);
Vector<const uc16> data() { return data_; }
private:
Vector<const uc16> data_;
};
class RegExpQuantifier: public RegExpTree {
public:
RegExpQuantifier(int min, int max, bool is_greedy, RegExpTree* body)
: min_(min),
max_(max),
is_greedy_(is_greedy),
body_(body) { }
virtual void* Accept(RegExpVisitor* visitor, void* data);
virtual RegExpNode* ToNode(RegExpCompiler* compiler,
RegExpNode* on_success,
RegExpNode* on_failure);
static RegExpNode* ToNode(int min,
int max,
bool is_greedy,
RegExpTree* body,
RegExpCompiler* compiler,
RegExpNode* on_success,
RegExpNode* on_failure);
virtual RegExpQuantifier* AsQuantifier();
virtual bool IsQuantifier();
int min() { return min_; }
int max() { return max_; }
bool is_greedy() { return is_greedy_; }
RegExpTree* body() { return body_; }
// We just use a very large integer value as infinity because 2^30
// is infinite in practice.
static const int kInfinity = (1 << 30);
private:
int min_;
int max_;
bool is_greedy_;
RegExpTree* body_;
};
enum CaptureAvailability {
CAPTURE_AVAILABLE, CAPTURE_UNREACHABLE, CAPTURE_PERMANENTLY_UNREACHABLE };
class RegExpCapture: public RegExpTree {
public:
explicit RegExpCapture(RegExpTree* body, int index)
: body_(body), index_(index), available_(CAPTURE_AVAILABLE) { }
virtual void* Accept(RegExpVisitor* visitor, void* data);
virtual RegExpNode* ToNode(RegExpCompiler* compiler,
RegExpNode* on_success,
RegExpNode* on_failure);
static RegExpNode* ToNode(RegExpTree* body,
int index,
RegExpCompiler* compiler,
RegExpNode* on_success,
RegExpNode* on_failure);
virtual RegExpCapture* AsCapture();
virtual bool IsCapture();
RegExpTree* body() { return body_; }
int index() { return index_; }
inline CaptureAvailability available() { return available_; }
inline void set_available(CaptureAvailability availability) {
available_ = availability;
}
static int StartRegister(int index) { return index * 2; }
static int EndRegister(int index) { return index * 2 + 1; }
private:
RegExpTree* body_;
int index_;
CaptureAvailability available_;
};
class RegExpLookahead: public RegExpTree {
public:
RegExpLookahead(RegExpTree* body, bool is_positive)
: body_(body),
is_positive_(is_positive) { }
virtual void* Accept(RegExpVisitor* visitor, void* data);
virtual RegExpNode* ToNode(RegExpCompiler* compiler,
RegExpNode* on_success,
RegExpNode* on_failure);
virtual RegExpLookahead* AsLookahead();
virtual bool IsLookahead();
RegExpTree* body() { return body_; }
bool is_positive() { return is_positive_; }
private:
RegExpTree* body_;
bool is_positive_;
};
class RegExpBackReference: public RegExpTree {
public:
explicit RegExpBackReference(RegExpCapture* capture)
: capture_(capture) { }
virtual void* Accept(RegExpVisitor* visitor, void* data);
virtual RegExpNode* ToNode(RegExpCompiler* compiler,
RegExpNode* on_success,
RegExpNode* on_failure);
virtual RegExpBackReference* AsBackReference();
virtual bool IsBackReference();
int index() { return capture_->index(); }
RegExpCapture* capture() { return capture_; }
private:
RegExpCapture* capture_;
};
class RegExpEmpty: public RegExpTree {
public:
RegExpEmpty() { }
virtual void* Accept(RegExpVisitor* visitor, void* data);
virtual RegExpNode* ToNode(RegExpCompiler* compiler,
RegExpNode* on_success,
RegExpNode* on_failure);
virtual RegExpEmpty* AsEmpty();
virtual bool IsEmpty();
static RegExpEmpty* GetInstance() { return &kInstance; }
private:
static RegExpEmpty kInstance;
};
class RegExpVisitor BASE_EMBEDDED {
public:
virtual ~RegExpVisitor() { }
#define MAKE_CASE(Name) \
virtual void* Visit##Name(RegExp##Name*, void* data) = 0;
FOR_EACH_REG_EXP_TREE_TYPE(MAKE_CASE)
#undef MAKE_CASE
};
// ----------------------------------------------------------------------------
// Basic visitor
// - leaf node visitors are abstract.
......
......@@ -647,7 +647,7 @@ void Builtins::Setup(bool create_heap_objects) {
// During startup it's OK to always allocate and defer GC to later.
// This simplifies things because we don't need to retry.
AlwaysAllocateScope __scope__;
code = Heap::CreateCode(desc, NULL, flags);
code = Heap::CreateCode(desc, NULL, flags, NULL);
if (code->IsFailure()) {
v8::internal::V8::FatalProcessOutOfMemory("CreateCode");
}
......
// Copyright 2008 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef V8_BYTECODES_IRREGEXP_H_
#define V8_BYTECODES_IRREGEXP_H_
namespace v8 { namespace internal {
#define BYTECODE_ITERATOR(V) \
V(BREAK, 0, 1) /* break */ \
V(PUSH_CP, 1, 5) /* push_cp offset32 */ \
V(PUSH_BT, 2, 5) /* push_bt addr32 */ \
V(PUSH_REGISTER, 3, 2) /* push_register register_index */ \
V(SET_REGISTER_TO_CP, 4, 6) /* set_register_to_cp register_index offset32 */ \
V(SET_CP_TO_REGISTER, 5, 2) /* set_cp_to_registger register_index */ \
V(SET_REGISTER_TO_SP, 6, 2) /* set_register_to_sp register_index */ \
V(SET_SP_TO_REGISTER, 7, 2) /* set_sp_to_registger register_index */ \
V(SET_REGISTER, 8, 6) /* set_register register_index value32 */ \
V(ADVANCE_REGISTER, 9, 6) /* advance_register register_index value32 */ \
V(POP_CP, 10, 1) /* pop_cp */ \
V(POP_BT, 11, 1) /* pop_bt */ \
V(POP_REGISTER, 12, 2) /* pop_register register_index */ \
V(FAIL, 13, 1) /* fail */ \
V(SUCCEED, 14, 1) /* succeed */ \
V(ADVANCE_CP, 15, 5) /* advance_cp offset32 */ \
V(GOTO, 16, 5) /* goto addr32 */ \
V(LOAD_CURRENT_CHAR, 17, 9) /* load offset32 addr32 */ \
V(CHECK_CHAR, 18, 7) /* check_char uc16 addr32 */ \
V(CHECK_NOT_CHAR, 19, 7) /* check_not_char uc16 addr32 */ \
V(OR_CHECK_NOT_CHAR, 20, 9) /* or_check_not_char uc16 uc16 addr32 */ \
V(MINUS_OR_CHECK_NOT_CHAR, 21, 9) /* minus_or_check_not_char uc16 uc16 ad...*/ \
V(CHECK_LT, 22, 7) /* check_lt uc16 addr32 */ \
V(CHECK_GT, 23, 7) /* check_gr uc16 addr32 */ \
V(CHECK_NOT_BACK_REF, 24, 6) /* check_not_back_ref capture_idx addr32 */ \
V(LOOKUP_MAP1, 25, 11) /* l_map1 start16 bit_map_addr32 addr32 */ \
V(LOOKUP_MAP2, 26, 99) /* l_map2 start16 half_nibble_map_addr32* */ \
V(LOOKUP_MAP8, 27, 99) /* l_map8 start16 byte_map addr32* */ \
V(LOOKUP_HI_MAP8, 28, 99) /* l_himap8 start8 byte_map_addr32 addr32* */ \
V(CHECK_REGISTER_LT, 29, 8) /* check_reg_lt register_index value16 addr32 */ \
V(CHECK_REGISTER_GE, 30, 8) /* check_reg_ge register_index value16 addr32 */ \
#define DECLARE_BYTECODES(name, code, length) \
static const int BC_##name = code;
BYTECODE_ITERATOR(DECLARE_BYTECODES)
#undef DECLARE_BYTECODES
#define DECLARE_BYTECODE_LENGTH(name, code, length) \
static const int BC_##name##_LENGTH = length;
BYTECODE_ITERATOR(DECLARE_BYTECODE_LENGTH)
#undef DECLARE_BYTECODE_LENGTH
} }
#endif // V8_BYTECODES_IRREGEXP_H_
......@@ -237,12 +237,14 @@ template <int> class StaticAssertionHelper { };
// The ASSERT macro is equivalent to CHECK except that it only
// generates code in debug builds. Ditto STATIC_ASSERT.
#ifdef DEBUG
#define ASSERT_RESULT(expr) CHECK(expr)
#define ASSERT(condition) CHECK(condition)
#define ASSERT_EQ(v1, v2) CHECK_EQ(v1, v2)
#define ASSERT_NE(v1, v2) CHECK_NE(v1, v2)
#define STATIC_ASSERT(test) STATIC_CHECK(test)
#define SLOW_ASSERT(condition) if (FLAG_enable_slow_asserts) CHECK(condition)
#else
#define ASSERT_RESULT(expr) (expr)
#define ASSERT(condition) ((void) 0)
#define ASSERT_EQ(v1, v2) ((void) 0)
#define ASSERT_NE(v1, v2) ((void) 0)
......@@ -256,4 +258,6 @@ template <int> class StaticAssertionHelper { };
#define ASSERT_SIZE_TAG_ALIGNED(size) ASSERT((size & kHeapObjectTagMask) == 0)
#define ASSERT_NOT_NULL(p) ASSERT_NE(NULL, p)
#endif // V8_CHECKS_H_
......@@ -120,7 +120,7 @@ typedef int32_t instr_t;
// bits.
//
// bool InstructionSetsConditionCodes(byte* ptr) {
// Instr *instr = Instr::At(ptr);
// Instr* instr = Instr::At(ptr);
// int type = instr->TypeField();
// return ((type == 0) || (type == 1)) && instr->HasS();
// }
......
......@@ -170,9 +170,9 @@ Handle<Proxy> Factory::NewProxy(const AccessorDescriptor* desc) {
}
Handle<ByteArray> Factory::NewByteArray(int length) {
Handle<ByteArray> Factory::NewByteArray(int length, PretenureFlag pretenure) {
ASSERT(0 <= length);
CALL_HEAP_FUNCTION(Heap::AllocateByteArray(length), ByteArray);
CALL_HEAP_FUNCTION(Heap::AllocateByteArray(length, pretenure), ByteArray);
}
......@@ -457,9 +457,15 @@ Handle<JSFunction> Factory::NewFunctionWithPrototype(Handle<String> name,
}
Handle<Code> Factory::NewCode(const CodeDesc& desc, ScopeInfo<>* sinfo,
Code::Flags flags, Handle<Object> self_ref) {
CALL_HEAP_FUNCTION(Heap::CreateCode(
desc, sinfo, flags, reinterpret_cast<Code**>(self_ref.location())), Code);
}
Handle<Code> Factory::NewCode(const CodeDesc& desc, ScopeInfo<>* sinfo,
Code::Flags flags) {
CALL_HEAP_FUNCTION(Heap::CreateCode(desc, sinfo, flags), Code);
CALL_HEAP_FUNCTION(Heap::CreateCode(desc, sinfo, flags, NULL), Code);
}
......@@ -706,8 +712,11 @@ Handle<JSFunction> Factory::CreateApiFunction(
ASSERT(type != INVALID_TYPE);
Handle<JSFunction> result =
Factory::NewFunction(Factory::empty_symbol(), type, instance_size,
code, true);
Factory::NewFunction(Factory::empty_symbol(),
type,
instance_size,
code,
true);
// Set class name.
Handle<Object> class_name = Handle<Object>(obj->class_name());
if (class_name->IsString()) {
......
......@@ -147,7 +147,8 @@ class Factory : public AllStatic {
// the old generation).
static Handle<Proxy> NewProxy(const AccessorDescriptor* proxy);
static Handle<ByteArray> NewByteArray(int length);
static Handle<ByteArray> NewByteArray(int length,
PretenureFlag pretenure = NOT_TENURED);
static Handle<Map> NewMap(InstanceType type, int instance_size);
......@@ -205,6 +206,9 @@ class Factory : public AllStatic {
Handle<JSFunction> boilerplate,
Handle<Context> context);
static Handle<Code> NewCode(const CodeDesc& desc, ScopeInfo<>* sinfo,
Code::Flags flags, Handle<Object> self_reference);
static Handle<Code> NewCode(const CodeDesc& desc, ScopeInfo<>* sinfo,
Code::Flags flags);
......
......@@ -289,6 +289,12 @@ DEFINE_bool(collect_heap_spill_statistics, false,
"report heap spill statistics along with heap_stats "
"(requires heap_stats)")
DEFINE_bool(irregexp, false, "new regular expression code")
DEFINE_bool(trace_regexps, false, "trace Irregexp execution")
DEFINE_bool(trace_regexp_bytecodes, false, "trace Irregexp bytecode executon")
DEFINE_bool(attempt_case_independent, false, "attempt to run Irregexp case independent")
DEFINE_bool(irregexp_native, false, "use native code Irregexp implementation (IA32 only)")
//
// Logging and profiling only flags
//
......
......@@ -178,10 +178,16 @@ class Map;
class MapSpace;
class MarkCompactCollector;
class NewSpace;
class NodeVisitor;
class Object;
class OldSpace;
class Property;
class Proxy;
class RegExpNode;
struct RegExpParseResult;
class RegExpTree;
class RegExpCompiler;
class RegExpVisitor;
class Scope;
template<class Allocator = FreeStoreAllocationPolicy> class ScopeInfo;
class Script;
......
......@@ -392,8 +392,7 @@ void Heap::PerformGarbageCollection(AllocationSpace space,
}
Counters::objs_since_last_young.Set(0);
// Process weak handles post gc.
GlobalHandles::PostGarbageCollectionProcessing();
PostGarbageCollectionProcessing();
if (collector == MARK_COMPACTOR) {
// Register the amount of external allocated memory.
......@@ -408,6 +407,14 @@ void Heap::PerformGarbageCollection(AllocationSpace space,
}
void Heap::PostGarbageCollectionProcessing() {
// Process weak handles post gc.
GlobalHandles::PostGarbageCollectionProcessing();
// Update flat string readers.
FlatStringReader::PostGarbageCollectionProcessing();
}
void Heap::MarkCompact(GCTracer* tracer) {
gc_state_ = MARK_COMPACT;
mc_count_++;
......@@ -1582,6 +1589,24 @@ Object* Heap::LookupSingleCharacterStringFromCode(uint16_t code) {
}
Object* Heap::AllocateByteArray(int length, PretenureFlag pretenure) {
if (pretenure == NOT_TENURED) {
return AllocateByteArray(length);
}
int size = ByteArray::SizeFor(length);
AllocationSpace space =
size > MaxHeapObjectSize() ? LO_SPACE : OLD_DATA_SPACE;
Object* result = AllocateRaw(size, space, OLD_DATA_SPACE);
if (result->IsFailure()) return result;
reinterpret_cast<Array*>(result)->set_map(byte_array_map());
reinterpret_cast<Array*>(result)->set_length(length);
return result;
}
Object* Heap::AllocateByteArray(int length) {
int size = ByteArray::SizeFor(length);
AllocationSpace space =
......@@ -1599,7 +1624,8 @@ Object* Heap::AllocateByteArray(int length) {
Object* Heap::CreateCode(const CodeDesc& desc,
ScopeInfo<>* sinfo,
Code::Flags flags) {
Code::Flags flags,
Code** self_reference) {
// Compute size
int body_size = RoundUp(desc.instr_size + desc.reloc_size, kObjectAlignment);
int sinfo_size = 0;
......@@ -1622,7 +1648,16 @@ Object* Heap::CreateCode(const CodeDesc& desc,
code->set_sinfo_size(sinfo_size);
code->set_flags(flags);
code->set_ic_flag(Code::IC_TARGET_IS_ADDRESS);
code->CopyFrom(desc); // migrate generated code
// Allow self references to created code object.
if (self_reference != NULL) {
*self_reference = code;
}
// Migrate generated code.
// The generated code can contain Object** values (typically from handles)
// that are dereferenced during the copy to point directly to the actual heap
// objects. These pointers can include references to the code object itself,
// through the self_reference parameter.
code->CopyFrom(desc);
if (sinfo != NULL) sinfo->Serialize(code); // write scope info
#ifdef DEBUG
......
......@@ -391,7 +391,13 @@ class Heap : public AllStatic {
// Allocate a byte array of the specified length
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please not this does not perform a garbage collection.
// Please note this does not perform a garbage collection.
static Object* AllocateByteArray(int length, PretenureFlag pretenure);
// Allocate a non-tenured byte array of the specified length
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
static Object* AllocateByteArray(int length);
// Allocates a fixed array initialized with undefined values
......@@ -549,11 +555,14 @@ class Heap : public AllStatic {
// Makes a new native code object
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// failed. On success, the pointer to the Code object is stored in the
// self_reference. This allows generated code to reference its own Code
// object by containing this pointer.
// Please note this function does not perform a garbage collection.
static Object* CreateCode(const CodeDesc& desc,
ScopeInfo<>* sinfo,
Code::Flags flags);
Code::Flags flags,
Code** self_reference = NULL);
static Object* CopyCode(Code* code);
// Finds the symbol for string in the symbol table.
......@@ -582,6 +591,9 @@ class Heap : public AllStatic {
static void GarbageCollectionPrologue();
static void GarbageCollectionEpilogue();
// Code that should be executed after the garbage collection proper.
static void PostGarbageCollectionProcessing();
// Performs garbage collection operation.
// Returns whether required_space bytes are available after the collection.
static bool CollectGarbage(int required_space, AllocationSpace space);
......
This diff is collapsed.
// Copyright 2008 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// A simple interpreter for the Regexp2000 byte code.
#ifndef V8_INTERPRETER_IRREGEXP_H_
#define V8_INTERPRETER_IRREGEXP_H_
namespace v8 { namespace internal {
class IrregexpInterpreter {
public:
static bool Match(Handle<ByteArray> code,
Handle<String> subject16,
int* captures,
int start_position);
};
} } // namespace v8::internal
#endif // V8_INTERPRETER_IRREGEXP_H_
// Copyright 2006-2008 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef V8_JSREGEXP_INL_H_
#define V8_JSREGEXP_INL_H_
#include "jsregexp.h"
#include "regexp-macro-assembler.h"
namespace v8 {
namespace internal {
template <typename C>
bool ZoneSplayTree<C>::Insert(const Key& key, Locator* locator) {
if (is_empty()) {
// If the tree is empty, insert the new node.
root_ = new Node(key, C::kNoValue);
} else {
// Splay on the key to move the last node on the search path
// for the key to the root of the tree.
Splay(key);
// Ignore repeated insertions with the same key.
int cmp = C::Compare(key, root_->key_);
if (cmp == 0) {
locator->bind(root_);
return false;
}
// Insert the new node.
Node* node = new Node(key, C::kNoValue);
if (cmp > 0) {
node->left_ = root_;
node->right_ = root_->right_;
root_->right_ = NULL;
} else {
node->right_ = root_;
node->left_ = root_->left_;
root_->left_ = NULL;
}
root_ = node;
}
locator->bind(root_);
return true;
}
template <typename C>
bool ZoneSplayTree<C>::Find(const Key& key, Locator* locator) {
if (is_empty())
return false;
Splay(key);
if (C::Compare(key, root_->key_) == 0) {
locator->bind(root_);
return true;
} else {
return false;
}
}
template <typename C>
bool ZoneSplayTree<C>::FindGreatestLessThan(const Key& key,
Locator* locator) {
if (is_empty())
return false;
// Splay on the key to move the node with the given key or the last
// node on the search path to the top of the tree.
Splay(key);
// Now the result is either the root node or the greatest node in
// the left subtree.
int cmp = C::Compare(root_->key_, key);
if (cmp <= 0) {
locator->bind(root_);
return true;
} else {
Node* temp = root_;
root_ = root_->left_;
bool result = FindGreatest(locator);
root_ = temp;
return result;
}
}
template <typename C>
bool ZoneSplayTree<C>::FindLeastGreaterThan(const Key& key,
Locator* locator) {
if (is_empty())
return false;
// Splay on the key to move the node with the given key or the last
// node on the search path to the top of the tree.
Splay(key);
// Now the result is either the root node or the least node in
// the right subtree.
int cmp = C::Compare(root_->key_, key);
if (cmp >= 0) {
locator->bind(root_);
return true;
} else {
Node* temp = root_;
root_ = root_->right_;
bool result = FindLeast(locator);
root_ = temp;
return result;
}
}
template <typename C>
bool ZoneSplayTree<C>::FindGreatest(Locator* locator) {
if (is_empty())
return false;
Node* current = root_;
while (current->right_ != NULL)
current = current->right_;
locator->bind(current);
return true;
}
template <typename C>
bool ZoneSplayTree<C>::FindLeast(Locator* locator) {
if (is_empty())
return false;
Node* current = root_;
while (current->left_ != NULL)
current = current->left_;
locator->bind(current);
return true;
}
template <typename C>
bool ZoneSplayTree<C>::Remove(const Key& key) {
// Bail if the tree is empty
if (is_empty())
return false;
// Splay on the key to move the node with the given key to the top.
Splay(key);
// Bail if the key is not in the tree
if (C::Compare(key, root_->key_) != 0)
return false;
if (root_->left_ == NULL) {
// No left child, so the new tree is just the right child.
root_ = root_->right_;
} else {
// Left child exists.
Node* right = root_->right_;
// Make the original left child the new root.
root_ = root_->left_;
// Splay to make sure that the new root has an empty right child.
Splay(key);
// Insert the original right child as the right child of the new
// root.
root_->right_ = right;
}
return true;
}
template <typename C>
void ZoneSplayTree<C>::Splay(const Key& key) {
if (is_empty())
return;
Node dummy_node(C::kNoKey, C::kNoValue);
// Create a dummy node. The use of the dummy node is a bit
// counter-intuitive: The right child of the dummy node will hold
// the L tree of the algorithm. The left child of the dummy node
// will hold the R tree of the algorithm. Using a dummy node, left
// and right will always be nodes and we avoid special cases.
Node* dummy = &dummy_node;
Node* left = dummy;
Node* right = dummy;
Node* current = root_;
while (true) {
int cmp = C::Compare(key, current->key_);
if (cmp < 0) {
if (current->left_ == NULL)
break;
if (C::Compare(key, current->left_->key_) < 0) {
// Rotate right.
Node* temp = current->left_;
current->left_ = temp->right_;
temp->right_ = current;
current = temp;
if (current->left_ == NULL)
break;
}
// Link right.
right->left_ = current;
right = current;
current = current->left_;
} else if (cmp > 0) {
if (current->right_ == NULL)
break;
if (C::Compare(key, current->right_->key_) > 0) {
// Rotate left.
Node* temp = current->right_;
current->right_ = temp->left_;
temp->left_ = current;
current = temp;
if (current->right_ == NULL)
break;
}
// Link left.
left->right_ = current;
left = current;
current = current->right_;
} else {
break;
}
}
// Assemble.
left->right_ = current->left_;
right->left_ = current->right_;
current->left_ = dummy->right_;
current->right_ = dummy->left_;
root_ = current;
}
template <typename Node, class Callback>
static void DoForEach(Node* node, Callback* callback) {
if (node == NULL) return;
DoForEach<Node, Callback>(node->left(), callback);
callback->Call(node->key(), node->value());
DoForEach<Node, Callback>(node->right(), callback);
}
void RegExpNode::Bind(RegExpMacroAssembler* macro) {
macro->Bind(&label_);
}
} // namespace internal
} // namespace v8
#endif // V8_JSREGEXP_INL_H_
This diff is collapsed.
This diff is collapsed.
......@@ -89,12 +89,19 @@ void List<T, P>::Iterate(void (*callback)(T* x)) {
}
template<typename T, class P>
bool List<T, P>::Contains(const T& elm) {
for (int i = 0; i < length_; i++) {
if (data_[i] == elm)
return true;
}
return false;
}
template<typename T, class P>
void List<T, P>::Sort(int (*cmp)(const T* x, const T* y)) {
qsort(data_,
length_,
sizeof(T),
reinterpret_cast<int (*)(const void*, const void*)>(cmp));
ToVector().Sort(cmp);
#ifdef DEBUG
for (int i = 1; i < length_; i++)
ASSERT(cmp(&data_[i - 1], &data_[i]) <= 0);
......@@ -102,6 +109,12 @@ void List<T, P>::Sort(int (*cmp)(const T* x, const T* y)) {
}
template<typename T, class P>
void List<T, P>::Sort() {
Sort(PointerSpaceship<T>);
}
template<typename T, class P>
void List<T, P>::Initialize(int capacity) {
ASSERT(capacity >= 0);
......
......@@ -46,6 +46,7 @@ namespace v8 { namespace internal {
template <typename T, class P>
class List {
public:
INLINE(explicit List(int capacity)) { Initialize(capacity); }
INLINE(~List()) { DeleteData(data_); }
......@@ -67,6 +68,8 @@ class List {
Vector<T> ToVector() { return Vector<T>(data_, length_); }
Vector<const T> ToConstVector() { return Vector<const T>(data_, length_); }
// Adds a copy of the given 'element' to the end of the list,
// expanding the list if necessary.
T& Add(const T& element);
......@@ -92,11 +95,14 @@ class List {
// Drops all but the first 'pos' elements from the list.
INLINE(void Rewind(int pos));
bool Contains(const T& elm);
// Iterate through all list entries, starting at index 0.
void Iterate(void (*callback)(T* x));
// Sort all list entries (using QuickSort)
void Sort(int (*cmp)(const T* x, const T* y));
void Sort();
INLINE(void Initialize(int capacity));
......
......@@ -670,7 +670,14 @@ void JSRegExp::JSRegExpVerify() {
}
case JSRegExp::JSCRE: {
FixedArray* arr = FixedArray::cast(data());
ASSERT(arr->get(JSRegExp::kJscreDataIndex)->IsFixedArray());
Object* jscre_data = arr->get(JSRegExp::kJscreDataIndex);
ASSERT(jscre_data->IsFixedArray() || jscre_data->IsUndefined());
break;
}
case JSRegExp::IRREGEXP: {
FixedArray* arr = FixedArray::cast(data());
Object* jscre_data = arr->get(JSRegExp::kJscreDataIndex);
ASSERT(jscre_data->IsFixedArray());
break;
}
default:
......
......@@ -279,6 +279,16 @@ bool StringShape::IsExternalTwoByte() {
}
uc32 FlatStringReader::Get(int index) {
ASSERT(0 <= index && index <= length_);
if (is_ascii_) {
return static_cast<const byte*>(start_)[index];
} else {
return static_cast<const uc16*>(start_)[index];
}
}
bool Object::IsNumber() {
return IsSmi() || IsHeapNumber();
}
......@@ -1142,6 +1152,13 @@ Object* FixedArray::get(int index) {
}
void FixedArray::set(int index, Smi* value) {
ASSERT(reinterpret_cast<Object*>(value)->IsSmi());
int offset = kHeaderSize + index * kPointerSize;
WRITE_FIELD(this, offset, value);
}
void FixedArray::set(int index, Object* value) {
ASSERT(index >= 0 && index < this->length());
int offset = kHeaderSize + index * kPointerSize;
......@@ -1747,6 +1764,7 @@ Code::Flags Code::flags() {
void Code::set_flags(Code::Flags flags) {
STATIC_ASSERT(Code::NUMBER_OF_KINDS <= (kFlagsKindMask >> kFlagsKindShift)+1);
// Make sure that all call stubs have an arguments count.
ASSERT(ExtractKindFromFlags(flags) != CALL_IC ||
ExtractArgumentsCountFromFlags(flags) >= 0);
......@@ -2213,6 +2231,22 @@ JSRegExp::Type JSRegExp::TypeTag() {
}
JSRegExp::Flags JSRegExp::GetFlags() {
ASSERT(this->data()->IsFixedArray());
Object* data = this->data();
Smi* smi = Smi::cast(FixedArray::cast(data)->get(kFlagsIndex));
return Flags(smi->value());
}
String* JSRegExp::Pattern() {
ASSERT(this->data()->IsFixedArray());
Object* data = this->data();
String* pattern= String::cast(FixedArray::cast(data)->get(kSourceIndex));
return pattern;
}
Object* JSRegExp::DataAt(int index) {
ASSERT(TypeTag() != NOT_COMPILED);
return FixedArray::cast(data())->get(index);
......
......@@ -3501,6 +3501,57 @@ const unibrow::byte* String::ReadBlock(String* input,
}
FlatStringReader* FlatStringReader::top_ = NULL;
FlatStringReader::FlatStringReader(Handle<String> str)
: str_(str.location()),
length_(str->length()),
prev_(top_) {
top_ = this;
RefreshState();
}
FlatStringReader::FlatStringReader(Vector<const char> input)
: str_(NULL),
is_ascii_(true),
length_(input.length()),
start_(input.start()),
prev_(top_) {
top_ = this;
}
FlatStringReader::~FlatStringReader() {
ASSERT_EQ(top_, this);
top_ = prev_;
}
void FlatStringReader::RefreshState() {
if (str_ == NULL) return;
Handle<String> str(str_);
StringShape shape(*str);
ASSERT(str->IsFlat(shape));
is_ascii_ = shape.IsAsciiRepresentation();
if (is_ascii_) {
start_ = str->ToAsciiVector().start();
} else {
start_ = str->ToUC16Vector().start();
}
}
void FlatStringReader::PostGarbageCollectionProcessing() {
FlatStringReader* current = top_;
while (current != NULL) {
current->RefreshState();
current = current->prev_;
}
}
void StringInputBuffer::Seek(unsigned pos) {
Reset(pos, input_);
}
......
......@@ -1498,9 +1498,12 @@ class FixedArray: public Array {
// Setter and getter for elements.
inline Object* get(int index);
// Setter that uses write barrier.
inline void set(int index, Object* value);
// Setter with barrier mode.
// Setter that doesn't need write barrier).
inline void set(int index, Smi* value);
// Setter with explicit barrier mode.
inline void set(int index, Object* value, WriteBarrierMode mode);
// Setters for frequently used oddballs located in old space.
......@@ -2114,14 +2117,17 @@ class Code: public HeapObject {
CALL_IC,
STORE_IC,
KEYED_STORE_IC,
// No more than eight kinds. The value currently encoded in three bits in
// Flags.
// Pseudo-kinds.
REGEXP = BUILTIN,
FIRST_IC_KIND = LOAD_IC,
LAST_IC_KIND = KEYED_STORE_IC
};
enum {
NUMBER_OF_KINDS = LAST_IC_KIND + 1
NUMBER_OF_KINDS = KEYED_STORE_IC + 1
};
// A state indicates that inline cache in this Code object contains
......@@ -2272,7 +2278,6 @@ class Code: public HeapObject {
static const int kFlagsTypeMask = 0x000001C0; // 111000000
static const int kFlagsArgumentsCountMask = 0xFFFFFE00;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(Code);
};
......@@ -2912,7 +2917,13 @@ class JSValue: public JSObject {
// Regular expressions
class JSRegExp: public JSObject {
public:
enum Type { NOT_COMPILED, JSCRE, ATOM };
// Meaning of Type:
// NOT_COMPILED: Initial value. No data has been stored in the JSRegExp yet.
// JSCRE: A complex RegExp for JSCRE
// ATOM: A simple string to match against using an indexOf operation.
// IRREGEXP: Compiled with Irregexp.
// IRREGEXP_NATIVE: Compiled to native code with Irregexp.
enum Type { NOT_COMPILED, JSCRE, ATOM, IRREGEXP, IRREGEXP_NATIVE };
enum Flag { NONE = 0, GLOBAL = 1, IGNORE_CASE = 2, MULTILINE = 4 };
class Flags {
......@@ -2929,6 +2940,8 @@ class JSRegExp: public JSObject {
DECL_ACCESSORS(data, Object)
inline Type TypeTag();
inline Flags GetFlags();
inline String* Pattern();
inline Object* DataAt(int index);
static inline JSRegExp* cast(Object* obj);
......@@ -2945,10 +2958,11 @@ class JSRegExp: public JSObject {
static const int kTagIndex = 0;
static const int kSourceIndex = kTagIndex + 1;
static const int kFlagsIndex = kSourceIndex + 1;
// These two are the same since the same entry is shared for
// These three are the same since the same entry is shared for
// different purposes in different types of regexps.
static const int kAtomPatternIndex = kFlagsIndex + 1;
static const int kJscreDataIndex = kFlagsIndex + 1;
static const int kIrregexpDataIndex = kFlagsIndex + 1;
static const int kDataSize = kAtomPatternIndex + 1;
};
......@@ -3578,6 +3592,28 @@ class ExternalTwoByteString: public ExternalString {
};
// A flat string reader provides random access to the contents of a
// string independent of the character width of the string. The handle
// must be valid as long as the reader is being used.
class FlatStringReader BASE_EMBEDDED {
public:
explicit FlatStringReader(Handle<String> str);
explicit FlatStringReader(Vector<const char> input);
~FlatStringReader();
void RefreshState();
inline uc32 Get(int index);
int length() { return length_; }
static void PostGarbageCollectionProcessing();
private:
String** str_;
bool is_ascii_;
int length_;
const void* start_;
FlatStringReader* prev_;
static FlatStringReader* top_;
};
// Note that StringInputBuffers are not valid across a GC! To fix this
// it would have to store a String Handle instead of a String* and
// AsciiStringReadBlock would have to be modified to use memcpy.
......
This diff is collapsed.
......@@ -145,6 +145,9 @@ ScriptDataImpl* PreParse(unibrow::CharacterStream* stream,
v8::Extension* extension);
bool ParseRegExp(FlatStringReader* input, RegExpParseResult* result);
// Support for doing lazy compilation. The script is the script containing full
// source of the script where the function is declared. The start_position and
// end_position specifies the part of the script source which has the source
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -288,7 +288,7 @@ static Object* Runtime_IsConstructCall(Arguments args) {
static Object* Runtime_RegExpCompile(Arguments args) {
HandleScope scope; // create a new handle scope
HandleScope scope;
ASSERT(args.length() == 3);
CONVERT_CHECKED(JSRegExp, raw_re, args[0]);
Handle<JSRegExp> re(raw_re);
......@@ -786,7 +786,9 @@ static Object* Runtime_RegExpExec(Arguments args) {
Handle<String> subject(raw_subject);
Handle<Object> index(args[2]);
ASSERT(index->IsNumber());
return *RegExpImpl::Exec(regexp, subject, index);
Handle<Object> result = RegExpImpl::Exec(regexp, subject, index);
if (result.is_null()) return Failure::Exception();
return *result;
}
......@@ -797,7 +799,9 @@ static Object* Runtime_RegExpExecGlobal(Arguments args) {
Handle<JSRegExp> regexp(raw_regexp);
CONVERT_CHECKED(String, raw_subject, args[1]);
Handle<String> subject(raw_subject);
return *RegExpImpl::ExecGlobal(regexp, subject);
Handle<Object> result = RegExpImpl::ExecGlobal(regexp, subject);
if (result.is_null()) return Failure::Exception();
return *result;
}
......@@ -2444,7 +2448,7 @@ static Object* ConvertCase(Arguments args,
// in the buffer
Access<StringInputBuffer> buffer(&string_input_buffer);
buffer->Reset(s);
unibrow::uchar chars[unibrow::kMaxCaseConvertedSize];
unibrow::uchar chars[Converter::kMaxWidth];
int i = 0;
// We can assume that the string is not empty
uc32 current = buffer->GetNext();
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment