Added experimental API support for allocating V8 symbols as external strings.
Fixed bugs in debugging support on ARM.
Changed eval implementation to correctly detect whether or not a call to eval is aliased.
Fixed bug caused by a combination of the compilation cache and dictionary probing in native code. The bug caused us to sometimes call functions that had not yet been compiled.
Added platform support for FreeBSD.
Added support for building V8 on Windows with either the shared or static version of MSVCRT
Added the v8::jscre namespace around the jscre functions to avoid link errors (duplicate symbols) when building Google Chrome.
Added support for calling a JavaScript function with the current debugger execution context as its argument to the debugger interface.
Changed the type of names of counters from wchar_t to char.
Changed the Windows system call used to compute daylight savings time. The system call that we used to use became four times slower on WinXP SP3.
Added support in the d8 developer shell for memory-mapped counters and added a stats-viewer tool.
Fixed bug in upper/lower case mappings (issue 149).
git-svn-id: http://v8.googlecode.com/svn/trunk@911 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/SConscript b/src/SConscript
index c1a6433..d985865 100644
--- a/src/SConscript
+++ b/src/SConscript
@@ -41,26 +41,33 @@
'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',
- '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'
+ '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'
],
'arch:arm': ['assembler-arm.cc', 'builtins-arm.cc', 'codegen-arm.cc',
'cpu-arm.cc', 'disasm-arm.cc', 'frames-arm.cc', 'ic-arm.cc',
- 'macro-assembler-arm.cc', 'stub-cache-arm.cc'],
+ 'macro-assembler-arm.cc', 'regexp-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:linux': ['platform-linux.cc'],
- 'os:macos': ['platform-macos.cc'],
- 'os:nullos': ['platform-nullos.cc'],
- 'os:win32': ['platform-win32.cc'],
+ 'os:freebsd': ['platform-freebsd.cc'],
+ 'os:linux': ['platform-linux.cc'],
+ 'os:macos': ['platform-macos.cc'],
+ 'os:nullos': ['platform-nullos.cc'],
+ 'os:win32': ['platform-win32.cc'],
'mode:release': [],
- 'mode:debug': ['objects-debug.cc', 'prettyprinter.cc']
+ 'mode:debug': [
+ 'objects-debug.cc', 'prettyprinter.cc', 'regexp-macro-assembler-tracer.cc'
+ ]
}
diff --git a/src/api.cc b/src/api.cc
index 0f53c72..885c683 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -2203,7 +2203,7 @@
const char* v8::V8::GetVersion() {
- return "0.4.4.1";
+ return "0.4.5";
}
@@ -2652,6 +2652,12 @@
}
+void V8::SetExternalSymbolCallback(ExternalSymbolCallback callback) {
+ if (IsDeadCheck("v8::V8::SetExternalSymbolCallback()")) return;
+ i::Heap::SetExternalSymbolCallback(callback);
+}
+
+
String::Utf8Value::Utf8Value(v8::Handle<v8::Value> obj) {
EnsureInitialized("v8::String::Utf8Value::Utf8Value()");
if (obj.IsEmpty()) {
@@ -2896,6 +2902,26 @@
}
+Handle<Value> Debug::Call(v8::Handle<v8::Function> fun,
+ v8::Handle<v8::Value> data) {
+ if (!i::V8::HasBeenSetup()) return Handle<Value>();
+ ON_BAILOUT("v8::Debug::Call()", return Handle<Value>());
+ i::Handle<i::Object> result;
+ EXCEPTION_PREAMBLE();
+ if (data.IsEmpty()) {
+ result = i::Debugger::Call(Utils::OpenHandle(*fun),
+ i::Factory::undefined_value(),
+ &has_pending_exception);
+ } else {
+ result = i::Debugger::Call(Utils::OpenHandle(*fun),
+ Utils::OpenHandle(*data),
+ &has_pending_exception);
+ }
+ EXCEPTION_BAILOUT_CHECK(Local<Value>());
+ return Utils::ToLocal(result);
+}
+
+
namespace internal {
diff --git a/src/assembler-arm.cc b/src/assembler-arm.cc
index 3307760..21cd225 100644
--- a/src/assembler-arm.cc
+++ b/src/assembler-arm.cc
@@ -554,7 +554,7 @@
// However, if the original instruction is a 'mov rd, x' (not setting the
// condition code), then replace it with a 'ldr rd, [pc]'
RecordRelocInfo(x.rmode_, x.imm32_);
- ASSERT(!rn.is(ip)); // rn should never be ip, or will be trashed
+ CHECK(!rn.is(ip)); // rn should never be ip, or will be trashed
Condition cond = static_cast<Condition>(instr & CondMask);
if ((instr & ~CondMask) == 13*B21) { // mov, S not set
ldr(rd, MemOperand(pc, 0), cond);
diff --git a/src/assembler-ia32-inl.h b/src/assembler-ia32-inl.h
index 9b3567a..534d57e 100644
--- a/src/assembler-ia32-inl.h
+++ b/src/assembler-ia32-inl.h
@@ -205,6 +205,14 @@
}
+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);
}
diff --git a/src/assembler-ia32.cc b/src/assembler-ia32.cc
index 264ef42..c7571e3 100644
--- a/src/assembler-ia32.cc
+++ b/src/assembler-ia32.cc
@@ -122,7 +122,8 @@
#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 @@
}
buffer_size_ = buffer_size;
own_buffer_ = true;
-
} else {
// use externally provided buffer instead
ASSERT(buffer_size > 0);
@@ -420,6 +420,29 @@
}
+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 relative to Code Object-pointer.
+ int rel_pos = label->pos() + Code::kHeaderSize - kHeapObjectTag;
+ if (rel_pos >= 0 && rel_pos < 256) {
+ EMIT(0x6a);
+ EMIT(rel_pos);
+ } else {
+ EMIT(0x68);
+ emit(rel_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::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_;
@@ -801,6 +840,26 @@
}
+void Assembler::cmpb(const Operand& op, int8_t imm8) {
+ EnsureSpace ensure_space(this);
+ last_pc_ = pc_;
+ EMIT(0x80);
+ emit_operand(edi, op); // edi == 7
+ EMIT(imm8);
+}
+
+
+void Assembler::cmpw(const Operand& op, Immediate imm16) {
+ ASSERT(imm16.is_int16());
+ EnsureSpace ensure_space(this);
+ last_pc_ = pc_;
+ EMIT(0x66);
+ EMIT(0x81);
+ emit_operand(edi, op);
+ emit_w(imm16);
+}
+
+
void Assembler::cmp(Register reg, int32_t imm32) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
@@ -830,6 +889,24 @@
}
+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(0x66); // Operand size overide.
+ EMIT(0xA7); // CMPS
+}
+
+
void Assembler::dec_b(Register dst) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
@@ -1074,6 +1151,14 @@
}
+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 +1256,15 @@
}
+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 +1318,6 @@
}
-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 +1357,17 @@
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) {
+ // Relative to Code* heap object pointer.
+ long_at_put(fixup_pos, pos + Code::kHeaderSize - kHeapObjectTag);
+ } 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);
diff --git a/src/assembler-ia32.h b/src/assembler-ia32.h
index 9647446..17c6b82 100644
--- a/src/assembler-ia32.h
+++ b/src/assembler-ia32.h
@@ -118,8 +118,8 @@
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 @@
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
};
@@ -187,6 +189,9 @@
bool is_int8() const {
return -128 <= x_ && x_ < 128 && rmode_ == RelocInfo::NONE;
}
+ bool is_int16() const {
+ return -32768 <= x_ && x_ < 32768 && rmode_ == RelocInfo::NONE;
+ }
private:
int x_;
@@ -283,13 +288,14 @@
//
// 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 +319,8 @@
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 +446,14 @@
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);
@@ -486,11 +496,16 @@
void and_(const Operand& src, Register dst);
void and_(const Operand& dst, const Immediate& x);
+ void cmpb(const Operand& op, int8_t imm8);
+ void cmpw(const Operand& op, Immediate imm16);
void cmp(Register reg, int32_t imm32);
void cmp(Register reg, Handle<Object> handle);
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 +550,7 @@
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 +566,7 @@
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 +575,6 @@
void nop();
void rdtsc();
void ret(int imm16);
- void leave();
// Label operations & relative jumps (PPUM Appendix D)
//
@@ -748,6 +764,7 @@
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);
diff --git a/src/assembler.h b/src/assembler.h
index 81c8056..971b950 100644
--- a/src/assembler.h
+++ b/src/assembler.h
@@ -82,8 +82,10 @@
}
friend class Assembler;
+ friend class RegexpAssembler;
friend class Displacement;
friend class LabelShadow;
+ friend class RegExpMacroAssemblerIrregexp;
};
diff --git a/src/ast.cc b/src/ast.cc
index 2f21d92..2ba4421 100644
--- a/src/ast.cc
+++ b/src/ast.cc
@@ -29,6 +29,7 @@
#include "ast.h"
#include "scopes.h"
+#include "string-stream.h"
namespace v8 { namespace internal {
@@ -37,14 +38,15 @@
VariableProxySentinel VariableProxySentinel::identifier_proxy_(false);
ValidLeftHandSideSentinel ValidLeftHandSideSentinel::instance_;
Property Property::this_property_(VariableProxySentinel::this_proxy(), NULL, 0);
-Call Call::sentinel_(NULL, NULL, false, 0);
+Call Call::sentinel_(NULL, NULL, 0);
+CallEval CallEval::sentinel_(NULL, NULL, 0);
// ----------------------------------------------------------------------------
// All the Accept member functions for each syntax tree node type.
#define DECL_ACCEPT(type) \
- void type::Accept(Visitor* v) { \
+ void type::Accept(AstVisitor* v) { \
if (v->CheckStackOverflow()) return; \
v->Visit##type(this); \
}
@@ -157,17 +159,17 @@
// ----------------------------------------------------------------------------
-// Implementation of Visitor
+// Implementation of AstVisitor
-void Visitor::VisitStatements(ZoneList<Statement*>* statements) {
+void AstVisitor::VisitStatements(ZoneList<Statement*>* statements) {
for (int i = 0; i < statements->length(); i++) {
Visit(statements->at(i));
}
}
-void Visitor::VisitExpressions(ZoneList<Expression*>* expressions) {
+void AstVisitor::VisitExpressions(ZoneList<Expression*>* expressions) {
for (int i = 0; i < expressions->length(); i++) {
// The variable statement visiting code may pass NULL expressions
// to this code. Maybe this should be handled by introducing an
@@ -179,4 +181,204 @@
}
+// ----------------------------------------------------------------------------
+// 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
diff --git a/src/ast.h b/src/ast.h
index b383f76..a301ab7 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -34,6 +34,7 @@
#include "token.h"
#include "variables.h"
#include "macro-assembler.h"
+#include "jsregexp.h"
namespace v8 { namespace internal {
@@ -80,6 +81,7 @@
V(Throw) \
V(Property) \
V(Call) \
+ V(CallEval) \
V(CallNew) \
V(CallRuntime) \
V(UnaryOperation) \
@@ -103,7 +105,7 @@
public:
Node(): statement_pos_(RelocInfo::kNoPosition) { }
virtual ~Node() { }
- virtual void Accept(Visitor* v) = 0;
+ virtual void Accept(AstVisitor* v) = 0;
// Type testing & conversion.
virtual Statement* AsStatement() { return NULL; }
@@ -167,7 +169,7 @@
class ValidLeftHandSideSentinel: public Expression {
public:
virtual bool IsValidLeftHandSide() { return true; }
- virtual void Accept(Visitor* v) { UNREACHABLE(); }
+ virtual void Accept(AstVisitor* v) { UNREACHABLE(); }
static ValidLeftHandSideSentinel* instance() { return &instance_; }
private:
static ValidLeftHandSideSentinel instance_;
@@ -220,7 +222,7 @@
statements_(capacity),
is_initializer_block_(is_initializer_block) { }
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
void AddStatement(Statement* statement) { statements_.Add(statement); }
@@ -236,15 +238,15 @@
class Declaration: public Node {
public:
Declaration(VariableProxy* proxy, Variable::Mode mode, FunctionLiteral* fun)
- : proxy_(proxy),
- mode_(mode),
- fun_(fun) {
+ : proxy_(proxy),
+ mode_(mode),
+ fun_(fun) {
ASSERT(mode == Variable::VAR || mode == Variable::CONST);
// At the moment there are no "const functions"'s in JavaScript...
ASSERT(fun == NULL || mode == Variable::VAR);
}
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
VariableProxy* proxy() const { return proxy_; }
Variable::Mode mode() const { return mode_; }
@@ -269,7 +271,7 @@
protected:
explicit IterationStatement(ZoneStringList* labels)
- : BreakableStatement(labels, TARGET_FOR_ANONYMOUS), body_(NULL) { }
+ : BreakableStatement(labels, TARGET_FOR_ANONYMOUS), body_(NULL) { }
void Initialize(Statement* body) {
body_ = body;
@@ -301,7 +303,7 @@
next_ = next;
}
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
Type type() const { return type_; }
Statement* init() const { return init_; }
@@ -323,7 +325,7 @@
class ForInStatement: public IterationStatement {
public:
explicit ForInStatement(ZoneStringList* labels)
- : IterationStatement(labels), each_(NULL), enumerable_(NULL) { }
+ : IterationStatement(labels), each_(NULL), enumerable_(NULL) { }
void Initialize(Expression* each, Expression* enumerable, Statement* body) {
IterationStatement::Initialize(body);
@@ -331,7 +333,7 @@
enumerable_ = enumerable;
}
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
Expression* each() const { return each_; }
Expression* enumerable() const { return enumerable_; }
@@ -347,7 +349,7 @@
explicit ExpressionStatement(Expression* expression)
: expression_(expression) { }
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
// Type testing & conversion.
virtual ExpressionStatement* AsExpressionStatement() { return this; }
@@ -365,7 +367,7 @@
explicit ContinueStatement(IterationStatement* target)
: target_(target) { }
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
IterationStatement* target() const { return target_; }
@@ -379,7 +381,7 @@
explicit BreakStatement(BreakableStatement* target)
: target_(target) { }
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
BreakableStatement* target() const { return target_; }
@@ -393,7 +395,7 @@
explicit ReturnStatement(Expression* expression)
: expression_(expression) { }
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
// Type testing & conversion.
virtual ReturnStatement* AsReturnStatement() { return this; }
@@ -410,7 +412,7 @@
explicit WithEnterStatement(Expression* expression)
: expression_(expression) { }
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
Expression* expression() const { return expression_; }
@@ -423,7 +425,7 @@
public:
WithExitStatement() { }
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
};
@@ -456,7 +458,7 @@
cases_ = cases;
}
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
Expression* tag() const { return tag_; }
ZoneList<CaseClause*>* cases() const { return cases_; }
@@ -481,7 +483,7 @@
then_statement_(then_statement),
else_statement_(else_statement) { }
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
bool HasThenStatement() const { return !then_statement()->IsEmpty(); }
bool HasElseStatement() const { return !else_statement()->IsEmpty(); }
@@ -509,7 +511,7 @@
void AddLabel(Label* label);
// Virtual behaviour. LabelCollectors are never part of the AST.
- virtual void Accept(Visitor* v) { UNREACHABLE(); }
+ virtual void Accept(AstVisitor* v) { UNREACHABLE(); }
virtual LabelCollector* AsLabelCollector() { return this; }
ZoneList<Label*>* labels() { return labels_; }
@@ -546,7 +548,7 @@
ASSERT(catch_var->AsVariableProxy() != NULL);
}
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
Expression* catch_var() const { return catch_var_; }
Block* catch_block() const { return catch_block_; }
@@ -563,7 +565,7 @@
: TryStatement(try_block),
finally_block_(finally_block) { }
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
Block* finally_block() const { return finally_block_; }
@@ -574,13 +576,13 @@
class DebuggerStatement: public Statement {
public:
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
};
class EmptyStatement: public Statement {
public:
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
// Type testing & conversion.
virtual EmptyStatement* AsEmptyStatement() { return this; }
@@ -591,7 +593,7 @@
public:
explicit Literal(Handle<Object> handle) : handle_(handle) { }
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
// Type testing & conversion.
virtual Literal* AsLiteral() { return this; }
@@ -664,7 +666,7 @@
properties_(properties) {
}
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
Handle<FixedArray> constant_properties() const {
return constant_properties_;
@@ -687,7 +689,7 @@
pattern_(pattern),
flags_(flags) {}
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
Handle<String> pattern() const { return pattern_; }
Handle<String> flags() const { return flags_; }
@@ -706,7 +708,7 @@
: literals_(literals), values_(values) {
}
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
Handle<FixedArray> literals() const { return literals_; }
ZoneList<Expression*>* values() const { return values_; }
@@ -719,7 +721,7 @@
class VariableProxy: public Expression {
public:
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
// Type testing & conversion
virtual Property* AsProperty() {
@@ -811,11 +813,11 @@
};
Slot(Variable* var, Type type, int index)
- : var_(var), type_(type), index_(index) {
+ : var_(var), type_(type), index_(index) {
ASSERT(var != NULL);
}
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
// Type testing & conversion
virtual Slot* AsSlot() { return this; }
@@ -837,7 +839,7 @@
Property(Expression* obj, Expression* key, int pos)
: obj_(obj), key_(key), pos_(pos) { }
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
// Type testing & conversion
virtual Property* AsProperty() { return this; }
@@ -866,21 +868,18 @@
public:
Call(Expression* expression,
ZoneList<Expression*>* arguments,
- bool is_eval,
int pos)
: expression_(expression),
arguments_(arguments),
- is_eval_(is_eval),
pos_(pos) { }
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
// Type testing and conversion.
virtual Call* AsCall() { return this; }
Expression* expression() const { return expression_; }
ZoneList<Expression*>* arguments() const { return arguments_; }
- bool is_eval() { return is_eval_; }
int position() { return pos_; }
static Call* sentinel() { return &sentinel_; }
@@ -888,7 +887,6 @@
private:
Expression* expression_;
ZoneList<Expression*>* arguments_;
- bool is_eval_;
int pos_;
static Call sentinel_;
@@ -898,9 +896,27 @@
class CallNew: public Call {
public:
CallNew(Expression* expression, ZoneList<Expression*>* arguments, int pos)
- : Call(expression, arguments, false, pos) { }
+ : Call(expression, arguments, pos) { }
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
+};
+
+
+// The CallEval class represents a call of the form 'eval(...)' where eval
+// cannot be seen to be overwritten at compile time. It is potentially a
+// direct (i.e. not aliased) eval call. The real nature of the call is
+// determined at runtime.
+class CallEval: public Call {
+ public:
+ CallEval(Expression* expression, ZoneList<Expression*>* arguments, int pos)
+ : Call(expression, arguments, pos) { }
+
+ virtual void Accept(AstVisitor* v);
+
+ static CallEval* sentinel() { return &sentinel_; }
+
+ private:
+ static CallEval sentinel_;
};
@@ -915,7 +931,7 @@
ZoneList<Expression*>* arguments)
: name_(name), function_(function), arguments_(arguments) { }
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
Handle<String> name() const { return name_; }
Runtime::Function* function() const { return function_; }
@@ -931,11 +947,11 @@
class UnaryOperation: public Expression {
public:
UnaryOperation(Token::Value op, Expression* expression)
- : op_(op), expression_(expression) {
+ : op_(op), expression_(expression) {
ASSERT(Token::IsUnaryOp(op));
}
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
// Type testing & conversion
virtual UnaryOperation* AsUnaryOperation() { return this; }
@@ -952,11 +968,11 @@
class BinaryOperation: public Expression {
public:
BinaryOperation(Token::Value op, Expression* left, Expression* right)
- : op_(op), left_(left), right_(right) {
+ : op_(op), left_(left), right_(right) {
ASSERT(Token::IsBinaryOp(op));
}
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
// Type testing & conversion
virtual BinaryOperation* AsBinaryOperation() { return this; }
@@ -1001,11 +1017,11 @@
class CountOperation: public Expression {
public:
CountOperation(bool is_prefix, Token::Value op, Expression* expression)
- : is_prefix_(is_prefix), op_(op), expression_(expression) {
+ : is_prefix_(is_prefix), op_(op), expression_(expression) {
ASSERT(Token::IsCountOp(op));
}
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
bool is_prefix() const { return is_prefix_; }
bool is_postfix() const { return !is_prefix_; }
@@ -1024,11 +1040,11 @@
class CompareOperation: public Expression {
public:
CompareOperation(Token::Value op, Expression* left, Expression* right)
- : op_(op), left_(left), right_(right) {
+ : op_(op), left_(left), right_(right) {
ASSERT(Token::IsCompareOp(op));
}
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
Token::Value op() const { return op_; }
Expression* left() const { return left_; }
@@ -1050,7 +1066,7 @@
then_expression_(then_expression),
else_expression_(else_expression) { }
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
Expression* condition() const { return condition_; }
Expression* then_expression() const { return then_expression_; }
@@ -1066,11 +1082,11 @@
class Assignment: public Expression {
public:
Assignment(Token::Value op, Expression* target, Expression* value, int pos)
- : op_(op), target_(target), value_(value), pos_(pos) {
+ : op_(op), target_(target), value_(value), pos_(pos) {
ASSERT(Token::IsAssignmentOp(op));
}
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
virtual Assignment* AsAssignment() { return this; }
Token::Value binary_op() const;
@@ -1093,7 +1109,7 @@
Throw(Expression* exception, int pos)
: exception_(exception), pos_(pos) {}
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
Expression* exception() const { return exception_; }
int position() const { return pos_; }
@@ -1129,7 +1145,7 @@
function_token_position_(RelocInfo::kNoPosition) {
}
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
// Type testing & conversion
virtual FunctionLiteral* AsFunctionLiteral() { return this; }
@@ -1178,7 +1194,7 @@
Handle<JSFunction> boilerplate() const { return boilerplate_; }
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
private:
Handle<JSFunction> boilerplate_;
@@ -1187,7 +1203,276 @@
class ThisFunction: public Expression {
public:
- virtual void Accept(Visitor* v);
+ virtual void Accept(AstVisitor* v);
+};
+
+
+// ----------------------------------------------------------------------------
+// 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
};
@@ -1195,10 +1480,10 @@
// Basic visitor
// - leaf node visitors are abstract.
-class Visitor BASE_EMBEDDED {
+class AstVisitor BASE_EMBEDDED {
public:
- Visitor() : stack_overflow_(false) { }
- virtual ~Visitor() { }
+ AstVisitor() : stack_overflow_(false) { }
+ virtual ~AstVisitor() { }
// Dispatch
void Visit(Node* node) { node->Accept(this); }
diff --git a/src/builtins-arm.cc b/src/builtins-arm.cc
index c1b654f..503a2d3 100644
--- a/src/builtins-arm.cc
+++ b/src/builtins-arm.cc
@@ -663,36 +663,7 @@
// they will have the correct value when returning from the debugger.
__ SaveRegistersToMemory(kJSCallerSaved);
- // This is a direct call from a debug breakpoint. To build a fake JS frame
- // with no parameters push a function and a receiver, keep the current
- // return address in lr, and set r0 to zero.
- __ mov(ip, Operand(ExternalReference::the_hole_value_location()));
- __ ldr(r3, MemOperand(ip));
- __ mov(r0, Operand(0)); // Null receiver and zero arguments.
- __ stm(db_w, sp, r0.bit() | r3.bit()); // push function and receiver
-
- // r0: number of arguments.
- // What follows is an inlined version of EnterJSFrame(0, 0).
- // It needs to be kept in sync if any calling conventions are changed.
-
- // Compute parameter pointer before making changes
- // ip = sp + kPointerSize*(args_len+1); // +1 for receiver, args_len == 0
- __ add(ip, sp, Operand(kPointerSize));
-
- __ mov(r3, Operand(0)); // args_len to be saved
- __ mov(r2, Operand(cp)); // context to be saved
-
- // push in reverse order: context (r2), args_len (r3), caller_pp, caller_fp,
- // sp_on_exit (ip == pp), return address
- __ stm(db_w, sp, r2.bit() | r3.bit() | pp.bit() | fp.bit() |
- ip.bit() | lr.bit());
- // Setup new frame pointer.
- __ add(fp, sp, Operand(-StandardFrameConstants::kContextOffset));
- __ mov(pp, Operand(ip)); // setup new parameter pointer
- // r0 is already set to 0 as spare slot to store caller code object during GC
- __ push(r0); // code pointer
-
- // Inlined EnterJSFrame ends here.
+ __ EnterInternalFrame();
// Store the registers containing object pointers on the expression stack to
// make sure that these are correctly updated during GC.
@@ -702,7 +673,7 @@
#ifdef DEBUG
__ RecordComment("// Calling from debug break to runtime - come in - over");
#endif
- // r0 is already 0, no arguments
+ __ mov(r0, Operand(0)); // no arguments
__ mov(r1, Operand(ExternalReference::debug_break()));
CEntryDebugBreakStub ceb;
@@ -713,14 +684,7 @@
// Use sp as base to pop.
__ CopyRegistersFromStackToMemory(sp, r3, pointer_regs);
- // What follows is an inlined version of ExitJSFrame(0).
- // It needs to be kept in sync if any calling conventions are changed.
- // NOTE: loading the return address to lr and discarding the (fake) function
- // is an addition to this inlined copy.
-
- __ mov(sp, Operand(fp)); // respect ABI stack constraint
- __ ldm(ia, sp, pp.bit() | fp.bit() | sp.bit() | lr.bit());
- __ pop(); // discard fake function
+ __ LeaveInternalFrame();
// Inlined ExitJSFrame ends here.
diff --git a/src/builtins.cc b/src/builtins.cc
index fdff2d2..c44b2e2 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -647,7 +647,7 @@
// 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");
}
diff --git a/src/bytecodes-irregexp.h b/src/bytecodes-irregexp.h
new file mode 100644
index 0000000..33a2f24
--- /dev/null
+++ b/src/bytecodes-irregexp.h
@@ -0,0 +1,81 @@
+// 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(CHECK_NOT_BACK_REF_NO_CASE, 25, 6) /* check_not_back_ref_no_case captu... */ \
+V(CHECK_NOT_REGS_EQUAL, 26, 7) /* check_not_regs_equal reg1 reg2 addr32 */ \
+V(LOOKUP_MAP1, 27, 11) /* l_map1 start16 bit_map_addr32 addr32 */ \
+V(LOOKUP_MAP2, 28, 99) /* l_map2 start16 half_nibble_map_addr32* */ \
+V(LOOKUP_MAP8, 29, 99) /* l_map8 start16 byte_map addr32* */ \
+V(LOOKUP_HI_MAP8, 30, 99) /* l_himap8 start8 byte_map_addr32 addr32* */ \
+V(CHECK_REGISTER_LT, 31, 8) /* check_reg_lt register_index value16 addr32 */ \
+V(CHECK_REGISTER_GE, 32, 8) /* check_reg_ge register_index value16 addr32 */ \
+V(CHECK_NOT_AT_START, 33, 5) /* check_not_at_start 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_
diff --git a/src/char-predicates-inl.h b/src/char-predicates-inl.h
index b575bdf..3ef2f91 100644
--- a/src/char-predicates-inl.h
+++ b/src/char-predicates-inl.h
@@ -59,6 +59,25 @@
}
+inline bool IsRegExpWord(uc16 c) {
+ return ('a' <= c && c <= 'z')
+ || ('A' <= c && c <= 'Z')
+ || ('0' <= c && c <= '9')
+ || (c == '_');
+}
+
+
+inline bool IsRegExpNewline(uc16 c) {
+ switch (c) {
+ // CR LF LS PS
+ case 0x000A: case 0x000D: case 0x2028: case 0x2029:
+ return false;
+ default:
+ return true;
+ }
+}
+
+
} } // namespace v8::internal
#endif // V8_CHAR_PREDICATES_INL_H_
diff --git a/src/char-predicates.h b/src/char-predicates.h
index 3fcaeb6..63e83b4 100644
--- a/src/char-predicates.h
+++ b/src/char-predicates.h
@@ -37,6 +37,8 @@
inline bool IsLineFeed(uc32 c);
inline bool IsDecimalDigit(uc32 c);
inline bool IsHexDigit(uc32 c);
+inline bool IsRegExpWord(uc32 c);
+inline bool IsRegExpNewline(uc32 c);
struct IdentifierStart {
static inline bool Is(uc32 c) {
diff --git a/src/checks.h b/src/checks.h
index 13075f8..77c43bc 100644
--- a/src/checks.h
+++ b/src/checks.h
@@ -237,12 +237,14 @@
// 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 @@
#define ASSERT_SIZE_TAG_ALIGNED(size) ASSERT((size & kHeapObjectTagMask) == 0)
+#define ASSERT_NOT_NULL(p) ASSERT_NE(NULL, p)
+
#endif // V8_CHECKS_H_
diff --git a/src/codegen-arm.cc b/src/codegen-arm.cc
index e5120ae..494257a 100644
--- a/src/codegen-arm.cc
+++ b/src/codegen-arm.cc
@@ -2303,7 +2303,7 @@
ZoneList<Expression*>* args = node->arguments();
- if (FLAG_debug_info) RecordStatementPosition(node);
+ RecordStatementPosition(node);
// Standard function call.
// Check if the function is a variable or a property.
@@ -2430,6 +2430,58 @@
}
+void CodeGenerator::VisitCallEval(CallEval* node) {
+ Comment cmnt(masm_, "[ CallEval");
+
+ // In a call to eval, we first call %ResolvePossiblyDirectEval to resolve
+ // the function we need to call and the receiver of the call.
+ // Then we call the resolved function using the given arguments.
+
+ ZoneList<Expression*>* args = node->arguments();
+ Expression* function = node->expression();
+
+ RecordStatementPosition(node);
+
+ // Prepare stack for call to resolved function.
+ Load(function);
+ __ mov(r2, Operand(Factory::undefined_value()));
+ __ push(r2); // Slot for receiver
+ for (int i = 0; i < args->length(); i++) {
+ Load(args->at(i));
+ }
+
+ // Prepare stack for call to ResolvePossiblyDirectEval.
+ __ ldr(r1, MemOperand(sp, args->length() * kPointerSize + kPointerSize));
+ __ push(r1);
+ if (args->length() > 0) {
+ __ ldr(r1, MemOperand(sp, args->length() * kPointerSize));
+ __ push(r1);
+ } else {
+ __ push(r2);
+ }
+
+ // Resolve the call.
+ __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 2);
+
+ // Touch up stack with the right values for the function and the receiver.
+ __ ldr(r1, FieldMemOperand(r0, FixedArray::kHeaderSize));
+ __ str(r1, MemOperand(sp, (args->length() + 1) * kPointerSize));
+ __ ldr(r1, FieldMemOperand(r0, FixedArray::kHeaderSize + kPointerSize));
+ __ str(r1, MemOperand(sp, args->length() * kPointerSize));
+
+ // Call the function.
+ __ RecordPosition(node->position());
+
+ CallFunctionStub call_function(args->length());
+ __ CallStub(&call_function);
+
+ __ ldr(cp, frame_->Context());
+ // Remove the function from the stack.
+ frame_->Pop();
+ frame_->Push(r0);
+}
+
+
void CodeGenerator::VisitCallNew(CallNew* node) {
Comment cmnt(masm_, "[ CallNew");
diff --git a/src/codegen-arm.h b/src/codegen-arm.h
index 2b889cd..904a3b7 100644
--- a/src/codegen-arm.h
+++ b/src/codegen-arm.h
@@ -187,7 +187,7 @@
// -------------------------------------------------------------------------
// CodeGenerator
-class CodeGenerator: public Visitor {
+class CodeGenerator: public AstVisitor {
public:
// Takes a function literal, generates code for it. This function should only
// be called by compiler.cc.
diff --git a/src/codegen-ia32.cc b/src/codegen-ia32.cc
index 230dc17..c5987a3 100644
--- a/src/codegen-ia32.cc
+++ b/src/codegen-ia32.cc
@@ -2836,6 +2836,54 @@
}
+void CodeGenerator::VisitCallEval(CallEval* node) {
+ Comment cmnt(masm_, "[ CallEval");
+
+ // In a call to eval, we first call %ResolvePossiblyDirectEval to resolve
+ // the function we need to call and the receiver of the call.
+ // Then we call the resolved function using the given arguments.
+
+ ZoneList<Expression*>* args = node->arguments();
+ Expression* function = node->expression();
+
+ RecordStatementPosition(node);
+
+ // Prepare stack for call to resolved function.
+ Load(function);
+ __ push(Immediate(Factory::undefined_value())); // Slot for receiver
+ for (int i = 0; i < args->length(); i++) {
+ Load(args->at(i));
+ }
+
+ // Prepare stack for call to ResolvePossiblyDirectEval.
+ __ push(Operand(esp, args->length() * kPointerSize + kPointerSize));
+ if (args->length() > 0) {
+ __ push(Operand(esp, args->length() * kPointerSize));
+ } else {
+ __ push(Immediate(Factory::undefined_value()));
+ }
+
+ // Resolve the call.
+ __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 2);
+
+ // Touch up stack with the right values for the function and the receiver.
+ __ mov(edx, FieldOperand(eax, FixedArray::kHeaderSize));
+ __ mov(Operand(esp, (args->length() + 1) * kPointerSize), edx);
+ __ mov(edx, FieldOperand(eax, FixedArray::kHeaderSize + kPointerSize));
+ __ mov(Operand(esp, args->length() * kPointerSize), edx);
+
+ // Call the function.
+ __ RecordPosition(node->position());
+
+ CallFunctionStub call_function(args->length());
+ __ CallStub(&call_function);
+
+ // Restore context and pop function from the stack.
+ __ mov(esi, frame_->Context());
+ __ mov(frame_->Top(), eax);
+}
+
+
void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Load(args->at(0));
diff --git a/src/codegen-ia32.h b/src/codegen-ia32.h
index ee6df47..a1525c7 100644
--- a/src/codegen-ia32.h
+++ b/src/codegen-ia32.h
@@ -193,7 +193,7 @@
// -------------------------------------------------------------------------
// CodeGenerator
-class CodeGenerator: public Visitor {
+class CodeGenerator: public AstVisitor {
public:
// Takes a function literal, generates code for it. This function should only
// be called by compiler.cc.
diff --git a/src/codegen.h b/src/codegen.h
index 6b543eb..71fe660 100644
--- a/src/codegen.h
+++ b/src/codegen.h
@@ -59,7 +59,7 @@
// CodeGenerator::FastCaseSwitchMinCaseCount
// CodeGenerator::FastCaseSwitchMaxOverheadFactor
-#if defined(ARM)
+#ifdef ARM
#include "codegen-arm.h"
#else
#include "codegen-ia32.h"
diff --git a/src/constants-arm.h b/src/constants-arm.h
index c74708b..46ddb15 100644
--- a/src/constants-arm.h
+++ b/src/constants-arm.h
@@ -120,7 +120,7 @@
// 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();
// }
diff --git a/src/contexts.cc b/src/contexts.cc
index 6aaa4cc..0f3f608 100644
--- a/src/contexts.cc
+++ b/src/contexts.cc
@@ -74,14 +74,6 @@
int* index_, PropertyAttributes* attributes) {
Handle<Context> context(this);
- // The context must be in frame slot 0 (if not debugging).
- if (kDebug && !Debug::InDebugger()) {
- StackFrameLocator locator;
- ASSERT(context->fcontext() ==
- Context::cast(
- locator.FindJavaScriptFrame(0)->context())->fcontext());
- }
-
bool follow_context_chain = (flags & FOLLOW_CONTEXT_CHAIN) != 0;
*index_ = -1;
*attributes = ABSENT;
diff --git a/src/counters.h b/src/counters.h
index 270c091..0e239c8 100644
--- a/src/counters.h
+++ b/src/counters.h
@@ -28,8 +28,6 @@
#ifndef V8_COUNTERS_H_
#define V8_COUNTERS_H_
-#include <wchar.h>
-
namespace v8 { namespace internal {
// StatsCounters is an interface for plugging into external
@@ -54,7 +52,7 @@
// may receive a different location to store it's counter.
// The return value must not be cached and re-used across
// threads, although a single thread is free to cache it.
- static int *FindLocation(const wchar_t* name) {
+ static int *FindLocation(const char* name) {
if (!lookup_function_) return NULL;
return lookup_function_(name);
}
@@ -74,9 +72,9 @@
//
// This class is designed to be POD initialized. It will be registered with
// the counter system on first use. For example:
-// StatsCounter c = { L"c:myctr", NULL, false };
+// StatsCounter c = { "c:myctr", NULL, false };
struct StatsCounter {
- const wchar_t* name_;
+ const char* name_;
int* ptr_;
bool lookup_done_;
diff --git a/src/d8.cc b/src/d8.cc
index 480d4ae..03a6ab6 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -26,6 +26,8 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include <stdlib.h>
+
#include "d8.h"
#include "debug.h"
#include "api.h"
@@ -77,11 +79,14 @@
char buffer[kBufferSize];
printf("%s", prompt);
char* str = fgets(buffer, kBufferSize, stdin);
- return i::SmartPointer<char>(str ? i::OS::StrDup(str) : str);
+ return i::SmartPointer<char>(str ? i::StrDup(str) : str);
}
Shell::CounterMap Shell::counter_map_;
+i::OS::MemoryMappedFile* Shell::counters_file_ = NULL;
+CounterCollection Shell::local_counters_;
+CounterCollection* Shell::counters_ = &local_counters_;
Persistent<Context> Shell::utility_context_;
Persistent<Context> Shell::evaluation_context_;
@@ -207,20 +212,59 @@
}
-int* Shell::LookupCounter(const wchar_t* name) {
+int32_t* Counter::Bind(const char* name) {
+ int i;
+ for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
+ name_[i] = static_cast<char>(name[i]);
+ name_[i] = '\0';
+ return &counter_;
+}
+
+
+CounterCollection::CounterCollection() {
+ magic_number_ = 0xDEADFACE;
+ max_counters_ = kMaxCounters;
+ max_name_size_ = Counter::kMaxNameSize;
+ counters_in_use_ = 0;
+}
+
+
+Counter* CounterCollection::GetNextCounter() {
+ if (counters_in_use_ == kMaxCounters) return NULL;
+ return &counters_[counters_in_use_++];
+}
+
+
+void Shell::MapCounters(const char* name) {
+ counters_file_ = i::OS::MemoryMappedFile::create(name,
+ sizeof(CounterCollection), &local_counters_);
+ void* memory = (counters_file_ == NULL) ?
+ NULL : counters_file_->memory();
+ if (memory == NULL) {
+ printf("Could not map counters file %s\n", name);
+ exit(1);
+ }
+ counters_ = static_cast<CounterCollection*>(memory);
+ V8::SetCounterFunction(LookupCounter);
+}
+
+
+int* Shell::LookupCounter(const char* name) {
CounterMap::iterator item = counter_map_.find(name);
if (item != counter_map_.end()) {
Counter* result = (*item).second;
- return result->GetValuePtr();
+ return result->ptr();
}
- Counter* result = new Counter(name);
- counter_map_[name] = result;
- return result->GetValuePtr();
+ Counter* result = counters_->GetNextCounter();
+ if (result == NULL) return NULL;
+ return result->Bind(name);
}
void Shell::Initialize() {
// Set up counters
+ if (i::FLAG_map_counters != NULL)
+ MapCounters(i::FLAG_map_counters);
if (i::FLAG_dump_counters)
V8::SetCounterFunction(LookupCounter);
// Initialize the global objects
@@ -250,7 +294,6 @@
// Install the debugger object in the utility scope
i::Debug::Load();
- i::Debug::debug_context()->set_security_token(i::Heap::undefined_value());
i::JSObject* debug = i::Debug::debug_context()->global();
utility_context_->Global()->Set(String::New("$debug"),
Utils::ToLocal(&debug));
@@ -270,6 +313,9 @@
// Create the evaluation context
evaluation_context_ = Context::New(NULL, global_template);
evaluation_context_->SetSecurityToken(Undefined());
+
+ // Set the security token of the debug context to allow access.
+ i::Debug::debug_context()->set_security_token(i::Heap::undefined_value());
}
@@ -282,10 +328,12 @@
i != counter_map_.end();
i++) {
Counter* counter = (*i).second;
- ::printf("| %-38ls | %8i |\n", counter->name(), counter->value());
+ ::printf("| %-38s | %8i |\n", (*i).first, counter->value());
}
::printf("+----------------------------------------+----------+\n");
}
+ if (counters_file_ != NULL)
+ delete counters_file_;
}
@@ -339,15 +387,32 @@
Context::Scope context_scope(evaluation_context_);
for (int i = 1; i < argc; i++) {
char* str = argv[i];
- HandleScope handle_scope;
- Handle<String> file_name = v8::String::New(str);
- Handle<String> source = ReadFile(str);
- if (source.IsEmpty()) {
- printf("Error reading '%s'\n", str);
- return 1;
+ if (strcmp(str, "-f") == 0) {
+ // Ignore any -f flags for compatibility with other stand-alone
+ // JavaScript engines.
+ continue;
+ } else if (strncmp(str, "--", 2) == 0) {
+ printf("Warning: unknown flag %s.\nTry --help for options\n", str);
+ } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
+ // Execute argument given to -e option directly.
+ v8::HandleScope handle_scope;
+ v8::Handle<v8::String> file_name = v8::String::New("unnamed");
+ v8::Handle<v8::String> source = v8::String::New(argv[i + 1]);
+ if (!ExecuteString(source, file_name, false, true))
+ return 1;
+ i++;
+ } else {
+ // Use all other arguments as names of files to load and run.
+ HandleScope handle_scope;
+ Handle<String> file_name = v8::String::New(str);
+ Handle<String> source = ReadFile(str);
+ if (source.IsEmpty()) {
+ printf("Error reading '%s'\n", str);
+ return 1;
+ }
+ if (!ExecuteString(source, file_name, false, true))
+ return 1;
}
- if (!ExecuteString(source, file_name, false, true))
- return 1;
}
if (run_shell)
RunShell();
diff --git a/src/d8.h b/src/d8.h
index 7e988c4..371e529 100644
--- a/src/d8.h
+++ b/src/d8.h
@@ -42,16 +42,33 @@
namespace i = v8::internal;
+// A single counter in a counter collection.
class Counter {
public:
- explicit Counter(const wchar_t* name)
- : name_(name), value_(0) { }
- int* GetValuePtr() { return &value_; }
- const wchar_t* name() { return name_; }
- int value() { return value_; }
+ static const int kMaxNameSize = 64;
+ int32_t* Bind(const char* name);
+ int32_t* ptr() { return &counter_; }
+ int32_t value() { return counter_; }
private:
- const wchar_t* name_;
- int value_;
+ int32_t counter_;
+ uint8_t name_[kMaxNameSize];
+};
+
+
+// A set of counters and associated information. An instance of this
+// class is stored directly in the memory-mapped counters file if
+// the --map-counters options is used
+class CounterCollection {
+ public:
+ CounterCollection();
+ Counter* GetNextCounter();
+ private:
+ static const unsigned kMaxCounters = 256;
+ uint32_t magic_number_;
+ uint32_t max_counters_;
+ uint32_t max_name_size_;
+ uint32_t counters_in_use_;
+ Counter counters_[kMaxCounters];
};
@@ -64,7 +81,8 @@
static void ReportException(TryCatch* try_catch);
static void Initialize();
static void OnExit();
- static int* LookupCounter(const wchar_t* name);
+ static int* LookupCounter(const char* name);
+ static void MapCounters(const char* name);
static Handle<String> ReadFile(const char* name);
static void RunShell();
static int Main(int argc, char* argv[]);
@@ -81,8 +99,13 @@
private:
static Persistent<Context> utility_context_;
static Persistent<Context> evaluation_context_;
- typedef std::map<const wchar_t*, Counter*> CounterMap;
+ typedef std::map<const char*, Counter*> CounterMap;
static CounterMap counter_map_;
+ // We statically allocate a set of local counters to be used if we
+ // don't want to store the stats in a memory-mapped file
+ static CounterCollection local_counters_;
+ static CounterCollection* counters_;
+ static i::OS::MemoryMappedFile* counters_file_;
};
diff --git a/src/date-delay.js b/src/date-delay.js
index c1b19e5..bef1fb4 100644
--- a/src/date-delay.js
+++ b/src/date-delay.js
@@ -111,24 +111,27 @@
// ECMA 262 - 15.9.1.9
function EquivalentYear(year) {
- // Returns an equivalent year in the range [1956-2000] matching
+ // Returns an equivalent year in the range [2008-2035] matching
// - leap year.
// - week day of first day.
var time = TimeFromYear(year);
- return (InLeapYear(time) == 0 ? 1967 : 1956) + (WeekDay(time) * 12) % 28;
+ var recent_year = (InLeapYear(time) == 0 ? 1967 : 1956) +
+ (WeekDay(time) * 12) % 28;
+ // Find the year in the range 2008..2037 that is equivalent mod 28.
+ // Add 3*28 to give a positive argument to the modulus operator.
+ return 2008 + (recent_year + 3*28 - 2008) % 28;
}
function EquivalentTime(t) {
// The issue here is that some library calls don't work right for dates
- // that cannot be represented using a signed 32 bit integer (measured in
- // whole seconds based on the 1970 epoch).
+ // that cannot be represented using a non-negative signed 32 bit integer
+ // (measured in whole seconds based on the 1970 epoch).
// We solve this by mapping the time to a year with same leap-year-ness
- // and same starting day for the year.
- // As an optimization we avoid finding an equivalent year in the common
- // case. We are measuring in ms here so the 32 bit signed integer range
- // is +-(1<<30)*1000 ie approximately +-2.1e20.
- if (t >= -2.1e12 && t <= 2.1e12) return t;
+ // and same starting day for the year. The ECMAscript specification says
+ // we must do this, but for compatability with other browsers, we use
+ // the actual year if it is in the range 1970..2037
+ if (t >= 0 && t <= 2.1e12) return t;
var day = MakeDay(EquivalentYear(YearFromTime(t)), MonthFromTime(t), DateFromTime(t));
return TimeClip(MakeDate(day, TimeWithinDay(t)));
}
diff --git a/src/debug-delay.js b/src/debug-delay.js
index 4d583b7..17b82b5 100644
--- a/src/debug-delay.js
+++ b/src/debug-delay.js
@@ -752,46 +752,6 @@
};
-BreakEvent.prototype.details = function() {
- // Build the break details.
- var details = '';
- if (this.breakPointsHit()) {
- details += 'breakpoint';
- if (this.breakPointsHit().length > 1) {
- details += 's';
- }
- details += ' ';
- for (var i = 0; i < this.breakPointsHit().length; i++) {
- if (i > 0) {
- details += ',';
- }
- details += this.breakPointsHit()[i].number();
- }
- } else {
- details += 'break';
- }
- details += ' in ';
- details += this.exec_state_.frame(0).invocationText();
- details += ' at ';
- details += this.exec_state_.frame(0).sourceAndPositionText();
- details += '\n'
- if (this.func().script()) {
- details += FrameSourceUnderline(this.exec_state_.frame(0));
- }
- return details;
-};
-
-
-BreakEvent.prototype.debugPrompt = function() {
- // Build the debug break prompt.
- if (this.breakPointsHit()) {
- return 'breakpoint';
- } else {
- return 'break';
- }
-};
-
-
BreakEvent.prototype.toJSONProtocol = function() {
var o = { seq: next_response_seq++,
type: "event",
@@ -869,32 +829,6 @@
};
-ExceptionEvent.prototype.details = function() {
- var details = "";
- if (this.uncaught_) {
- details += "Uncaught: ";
- } else {
- details += "Exception: ";
- }
-
- details += '"';
- details += MakeMirror(this.exception_).toText();
- details += '" at ';
- details += this.exec_state_.frame(0).sourceAndPositionText();
- details += '\n';
- details += FrameSourceUnderline(this.exec_state_.frame(0));
-
- return details;
-};
-
-ExceptionEvent.prototype.debugPrompt = function() {
- if (this.uncaught_) {
- return "uncaught exception";
- } else {
- return "exception";
- }
-};
-
ExceptionEvent.prototype.toJSONProtocol = function() {
var o = { seq: next_response_seq++,
type: "event",
@@ -920,399 +854,50 @@
return SimpleObjectToJSON_(o);
};
+
function MakeCompileEvent(script_source, script_name, script_function) {
return new CompileEvent(script_source, script_name, script_function);
}
+
function CompileEvent(script_source, script_name, script_function) {
this.scriptSource = script_source;
this.scriptName = script_name;
this.scriptFunction = script_function;
}
-CompileEvent.prototype.details = function() {
- var result = "";
- result = "Script added"
- if (this.scriptData) {
- result += ": '";
- result += this.scriptData;
- result += "'";
- }
- return result;
-};
-
-CompileEvent.prototype.debugPrompt = function() {
- var result = "source"
- if (this.scriptData) {
- result += " '";
- result += this.scriptData;
- result += "'";
- }
- if (this.func) {
- result += " added";
- } else {
- result += " compiled";
- }
- return result;
-};
function MakeNewFunctionEvent(func) {
return new NewFunctionEvent(func);
}
+
function NewFunctionEvent(func) {
this.func = func;
}
-NewFunctionEvent.prototype.details = function() {
- var result = "";
- result = "Function added: ";
- result += this.func.name;
- return result;
-};
-
-NewFunctionEvent.prototype.debugPrompt = function() {
- var result = "function";
- if (this.func.name) {
- result += " '";
- result += this.func.name;
- result += "'";
- }
- result += " added";
- return result;
-};
-
NewFunctionEvent.prototype.name = function() {
return this.func.name;
};
+
NewFunctionEvent.prototype.setBreakPoint = function(p) {
Debug.setBreakPoint(this.func, p || 0);
};
+
function DebugCommandProcessor(exec_state) {
this.exec_state_ = exec_state;
};
-// Convenience function for C debugger code to process a text command. This
-// function converts the text command to a JSON request, performs the request
-// and converts the request to a text result for display. The result is an
-// object containing the text result and the intermediate results.
-DebugCommandProcessor.prototype.processDebugCommand = function (command) {
- var request;
- var response;
- var text_result;
- var running;
-
- request = this.commandToJSONRequest(command);
- response = this.processDebugJSONRequest(request);
- text_result = this.responseToText(response);
- running = this.isRunning(response);
-
- return { "request" : request,
- "response" : response,
- "text_result" : text_result,
- "running" : running };
+DebugCommandProcessor.prototype.processDebugRequest = function (request) {
+ return this.processDebugJSONRequest(request);
}
-// Converts a text command to a JSON request.
-DebugCommandProcessor.prototype.commandToJSONRequest = function(cmd_line) {
- // If the wery first character is a { assume that a JSON request have been
- // entered as a command. Converting that to a JSON request is trivial.
- if (cmd_line && cmd_line.length > 0 && cmd_line.charAt(0) == '{') {
- return cmd_line;
- }
-
- // Trim string for leading and trailing whitespace.
- cmd_line = cmd_line.replace(/^\s+|\s+$/g, "");
-
- // Find the command.
- var pos = cmd_line.indexOf(" ");
- var cmd;
- var args;
- if (pos == -1) {
- cmd = cmd_line;
- args = "";
- } else {
- cmd = cmd_line.slice(0, pos);
- args = cmd_line.slice(pos).replace(/^\s+|\s+$/g, "");
- }
-
- // Switch on command.
- if (cmd == 'continue' || cmd == 'c') {
- return this.continueCommandToJSONRequest_(args);
- } else if (cmd == 'step' || cmd == 's') {
- return this.stepCommandToJSONRequest_(args);
- } else if (cmd == 'backtrace' || cmd == 'bt') {
- return this.backtraceCommandToJSONRequest_(args);
- } else if (cmd == 'frame' || cmd == 'f') {
- return this.frameCommandToJSONRequest_(args);
- } else if (cmd == 'print' || cmd == 'p') {
- return this.printCommandToJSONRequest_(args);
- } else if (cmd == 'source') {
- return this.sourceCommandToJSONRequest_(args);
- } else if (cmd == 'scripts') {
- return this.scriptsCommandToJSONRequest_(args);
- } else if (cmd[0] == '{') {
- return cmd_line;
- } else {
- throw new Error('Unknown command "' + cmd + '"');
- }
-};
-
-
-// Create a JSON request for the continue command.
-DebugCommandProcessor.prototype.continueCommandToJSONRequest_ = function(args) {
- var request = this.createRequest('continue');
- return request.toJSONProtocol();
-};
-
-
-// Create a JSON request for the step command.
-DebugCommandProcessor.prototype.stepCommandToJSONRequest_ = function(args) {
- // Requesting a step is through the continue command with additional
- // arguments.
- var request = this.createRequest('continue');
- request.arguments = {};
-
- // Process arguments if any.
- if (args && args.length > 0) {
- args = args.split(/\s*[ ]+\s*/g);
-
- if (args.length > 2) {
- throw new Error('Invalid step arguments.');
- }
-
- if (args.length > 0) {
- // Get step count argument if any.
- if (args.length == 2) {
- request.arguments.stepcount = %ToNumber(args[1]);
- }
-
- // Get the step action.
- if (args[0] == 'in' || args[0] == 'i') {
- request.arguments.stepaction = 'in';
- } else if (args[0] == 'min' || args[0] == 'm') {
- request.arguments.stepaction = 'min';
- } else if (args[0] == 'next' || args[0] == 'n') {
- request.arguments.stepaction = 'next';
- } else if (args[0] == 'out' || args[0] == 'o') {
- request.arguments.stepaction = 'out';
- } else {
- throw new Error('Invalid step argument "' + args[0] + '".');
- }
- }
- } else {
- // Default is step next.
- request.arguments.stepaction = 'next';
- }
-
- return request.toJSONProtocol();
-};
-
-
-// Create a JSON request for the backtrace command.
-DebugCommandProcessor.prototype.backtraceCommandToJSONRequest_ = function(args) {
- // Build a backtrace request from the text command.
- var request = this.createRequest('backtrace');
- args = args.split(/\s*[ ]+\s*/g);
- if (args.length == 2) {
- request.arguments = {};
- request.arguments.fromFrame = %ToNumber(args[0]);
- request.arguments.toFrame = %ToNumber(args[1]) + 1;
- }
- return request.toJSONProtocol();
-};
-
-
-// Create a JSON request for the frame command.
-DebugCommandProcessor.prototype.frameCommandToJSONRequest_ = function(args) {
- // Build a frame request from the text command.
- var request = this.createRequest('frame');
- args = args.split(/\s*[ ]+\s*/g);
- if (args.length > 0 && args[0].length > 0) {
- request.arguments = {};
- request.arguments.number = args[0];
- }
- return request.toJSONProtocol();
-};
-
-
-// Create a JSON request for the print command.
-DebugCommandProcessor.prototype.printCommandToJSONRequest_ = function(args) {
- // Build a evaluate request from the text command.
- var request = this.createRequest('evaluate');
- if (args.length == 0) {
- throw new Error('Missing expression.');
- }
-
- request.arguments = {};
- request.arguments.expression = args;
-
- return request.toJSONProtocol();
-};
-
-
-// Create a JSON request for the source command.
-DebugCommandProcessor.prototype.sourceCommandToJSONRequest_ = function(args) {
- // Build a evaluate request from the text command.
- var request = this.createRequest('source');
-
- // Default is one line before and two lines after current location.
- var before = 1;
- var after = 2;
-
- // Parse the arguments.
- args = args.split(/\s*[ ]+\s*/g);
- if (args.length > 1 && args[0].length > 0 && args[1].length > 0) {
- before = %ToNumber(args[0]);
- after = %ToNumber(args[1]);
- } else if (args.length > 0 && args[0].length > 0) {
- after = %ToNumber(args[0]);
- }
-
- // Request source arround current source location.
- request.arguments = {};
- request.arguments.fromLine = this.exec_state_.frame().sourceLine() - before;
- if (request.arguments.fromLine < 0) {
- request.arguments.fromLine = 0
- }
- request.arguments.toLine = this.exec_state_.frame().sourceLine() + after + 1;
-
- return request.toJSONProtocol();
-};
-
-
-// Create a JSON request for the scripts command.
-DebugCommandProcessor.prototype.scriptsCommandToJSONRequest_ = function(args) {
- // Build a evaluate request from the text command.
- var request = this.createRequest('scripts');
-
- // Process arguments if any.
- if (args && args.length > 0) {
- args = args.split(/\s*[ ]+\s*/g);
-
- if (args.length > 1) {
- throw new Error('Invalid scripts arguments.');
- }
-
- request.arguments = {};
- if (args[0] == 'natives') {
- request.arguments.types = ScriptTypeFlag(Debug.ScriptType.Native);
- } else if (args[0] == 'extensions') {
- request.arguments.types = ScriptTypeFlag(Debug.ScriptType.Extension);
- } else if (args[0] == 'all') {
- request.arguments.types =
- ScriptTypeFlag(Debug.ScriptType.Normal) |
- ScriptTypeFlag(Debug.ScriptType.Native) |
- ScriptTypeFlag(Debug.ScriptType.Extension);
- } else {
- throw new Error('Invalid argument "' + args[0] + '".');
- }
- }
-
- return request.toJSONProtocol();
-};
-
-
-// Convert a JSON response to text for display in a text based debugger.
-DebugCommandProcessor.prototype.responseToText = function(json_response) {
- try {
- // Convert the JSON string to an object.
- response = %CompileString('(' + json_response + ')', 0, false)();
-
- if (!response.success) {
- return response.message;
- }
-
- if (response.command == 'backtrace') {
- var body = response.body;
- var result = 'Frames #' + body.fromFrame + ' to #' +
- (body.toFrame - 1) + ' of ' + body.totalFrames + '\n';
- for (i = 0; i < body.frames.length; i++) {
- if (i != 0) result += '\n';
- result += body.frames[i].text;
- }
- return result;
- } else if (response.command == 'frame') {
- return SourceUnderline(response.body.sourceLineText,
- response.body.column);
- } else if (response.command == 'evaluate') {
- return response.body.text;
- } else if (response.command == 'source') {
- // Get the source from the response.
- var source = response.body.source;
-
- // Get rid of last line terminator.
- var remove_count = 0;
- if (source[source.length - 1] == '\n') remove_count++;
- if (source[source.length - 2] == '\r') remove_count++;
- if (remove_count > 0) source = source.substring(0, source.length - remove_count);
-
- return source;
- } else if (response.command == 'scripts') {
- var result = '';
- for (i = 0; i < response.body.length; i++) {
- if (i != 0) result += '\n';
- if (response.body[i].name) {
- result += response.body[i].name;
- } else {
- result += '[unnamed] ';
- var sourceStart = response.body[i].sourceStart;
- if (sourceStart.length > 40) {
- sourceStart = sourceStart.substring(0, 37) + '...';
- }
- result += sourceStart;
- }
- result += ' (lines: ';
- result += response.body[i].sourceLines;
- result += ', length: ';
- result += response.body[i].sourceLength;
- if (response.body[i].type == Debug.ScriptType.Native) {
- result += ', native';
- } else if (response.body[i].type == Debug.ScriptType.Extension) {
- result += ', extension';
- }
- result += ')';
- }
- return result;
- }
- } catch (e) {
- return 'Error: "' + %ToString(e) + '" formatting response';
- }
-};
-
-
-function SourceUnderline(source_text, position) {
- if (IS_UNDEFINED(source_text)) {
- return;
- }
-
- // Create an underline with a caret pointing to the source position. If the
- // source contains a tab character the underline will have a tab character in
- // the same place otherwise the underline will have a space character.
- var underline = '';
- for (var i = 0; i < position; i++) {
- if (source_text[i] == '\t') {
- underline += '\t';
- } else {
- underline += ' ';
- }
- }
- underline += '^';
-
- // Return the source line text with the underline beneath.
- return source_text + '\n' + underline;
-}
-
-
-function FrameSourceUnderline(frame) {
- var location = frame.sourceLocation();
- if (location) {
- return SourceUnderline(location.sourceText(), location.position - location.start);
- }
+DebugCommandProcessor.prototype.responseIsRunning = function (response) {
+ return this.isRunning(response);
}
@@ -1427,7 +1012,7 @@
try {
try {
// Convert the JSON string to an object.
- request = %CompileString('(' + json_request + ')', 0, false)();
+ request = %CompileString('(' + json_request + ')', 0)();
// Create an initial response.
response = this.createResponse(request);
@@ -1880,7 +1465,7 @@
DebugCommandProcessor.prototype.isRunning = function(json_response) {
try {
// Convert the JSON string to an object.
- response = %CompileString('(' + json_response + ')', 0, false)();
+ response = %CompileString('(' + json_response + ')', 0)();
// Return whether VM should be running after this request.
return response.running;
diff --git a/src/debug.cc b/src/debug.cc
index 7acc117..6952d8b 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -1650,6 +1650,30 @@
}
+Handle<Object> Debugger::Call(Handle<JSFunction> fun,
+ Handle<Object> data,
+ bool* pending_exception) {
+ // Enter the debugger.
+ EnterDebugger debugger;
+ if (debugger.FailedToEnter() || !debugger.HasJavaScriptFrames()) {
+ return Factory::undefined_value();
+ }
+
+ // Create the execution state.
+ bool caught_exception = false;
+ Handle<Object> exec_state = MakeExecutionState(&caught_exception);
+ if (caught_exception) {
+ return Factory::undefined_value();
+ }
+
+ static const int kArgc = 2;
+ Object** argv[kArgc] = { exec_state.location(), data.location() };
+ Handle<Object> result = Execution::Call(fun, Factory::undefined_value(),
+ kArgc, argv, pending_exception);
+ return result;
+}
+
+
DebugMessageThread::DebugMessageThread()
: host_running_(true),
command_queue_(kQueueInitialSize),
@@ -1769,10 +1793,10 @@
host_running_ = false;
SetEventJSONFromEvent(event_data);
- // Wait for commands from the debugger.
+ // Wait for requests from the debugger.
while (true) {
command_received_->Wait();
- Logger::DebugTag("Get command from command queue, in interactive loop.");
+ Logger::DebugTag("Got request from command queue, in interactive loop.");
Vector<uint16_t> command = command_queue_.Get();
ASSERT(!host_running_);
if (!Debugger::debugger_active()) {
@@ -1780,52 +1804,54 @@
return;
}
- // Invoke the JavaScript to convert the debug command line to a JSON
- // request, invoke the JSON request and convert the JSON response to a text
- // representation.
+ // Invoke the JavaScript to process the debug request.
v8::Local<v8::String> fun_name;
v8::Local<v8::Function> fun;
- v8::Local<v8::Value> args[1];
+ v8::Local<v8::Value> request;
v8::TryCatch try_catch;
- fun_name = v8::String::New("processDebugCommand");
+ fun_name = v8::String::New("processDebugRequest");
fun = v8::Function::Cast(*cmd_processor->Get(fun_name));
- args[0] = v8::String::New(reinterpret_cast<uint16_t*>(command.start()),
+ request = v8::String::New(reinterpret_cast<uint16_t*>(command.start()),
command.length());
- v8::Local<v8::Value> result_val = fun->Call(cmd_processor, 1, args);
+ static const int kArgc = 1;
+ v8::Handle<Value> argv[kArgc] = { request };
+ v8::Local<v8::Value> response_val = fun->Call(cmd_processor, kArgc, argv);
- // Get the result of the command.
- v8::Local<v8::String> result_string;
+ // Get the response.
+ v8::Local<v8::String> response;
bool running = false;
if (!try_catch.HasCaught()) {
- // Get the result as an object.
- v8::Local<v8::Object> result = v8::Object::Cast(*result_val);
+ // Get response string.
+ if (!response_val->IsUndefined()) {
+ response = v8::String::Cast(*response_val);
+ } else {
+ response = v8::String::New("");
+ }
// Log the JSON request/response.
if (FLAG_trace_debug_json) {
- PrintLn(result->Get(v8::String::New("request")));
- PrintLn(result->Get(v8::String::New("response")));
+ PrintLn(request);
+ PrintLn(response);
}
// Get the running state.
- running = result->Get(v8::String::New("running"))->ToBoolean()->Value();
-
- // Get result text.
- v8::Local<v8::Value> text_result =
- result->Get(v8::String::New("response"));
- if (!text_result->IsUndefined()) {
- result_string = text_result->ToString();
- } else {
- result_string = v8::String::New("");
+ fun_name = v8::String::New("isRunning");
+ fun = v8::Function::Cast(*cmd_processor->Get(fun_name));
+ static const int kArgc = 1;
+ v8::Handle<Value> argv[kArgc] = { response };
+ v8::Local<v8::Value> running_val = fun->Call(cmd_processor, kArgc, argv);
+ if (!try_catch.HasCaught()) {
+ running = running_val->ToBoolean()->Value();
}
} else {
// In case of failure the result text is the exception text.
- result_string = try_catch.Exception()->ToString();
+ response = try_catch.Exception()->ToString();
}
// Convert text result to C string.
- v8::String::Value val(result_string);
+ v8::String::Value val(response);
Vector<uint16_t> str(reinterpret_cast<uint16_t*>(*val),
- result_string->Length());
+ response->Length());
// Set host_running_ correctly for nested debugger evaluations.
host_running_ = running;
diff --git a/src/debug.h b/src/debug.h
index 6833982..629cebe 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -358,6 +358,10 @@
static void SendMessage(Vector<uint16_t> message);
static void ProcessCommand(Vector<const uint16_t> command);
static void UpdateActiveDebugger();
+ static Handle<Object> Call(Handle<JSFunction> fun,
+ Handle<Object> data,
+ bool* pending_exception);
+
inline static bool EventActive(v8::DebugEvent event) {
// Currently argument event is not used.
return !Debugger::compiling_natives_ && Debugger::debugger_active_;
@@ -504,6 +508,9 @@
// Check whether the debugger could be entered.
inline bool FailedToEnter() { return load_failed_; }
+ // Check whether there are any JavaScript frames on the stack.
+ inline bool HasJavaScriptFrames() { return set_; }
+
private:
JavaScriptFrameIterator it_;
const bool set_; // Was the break actually set?
diff --git a/src/dtoa-config.c b/src/dtoa-config.c
index cb73c17..eb2c955 100644
--- a/src/dtoa-config.c
+++ b/src/dtoa-config.c
@@ -37,7 +37,8 @@
* subtly wrong.
*/
-#if !(defined(__APPLE__) && defined(__MACH__)) && !defined(WIN32)
+#if !(defined(__APPLE__) && defined(__MACH__)) && \
+ !defined(WIN32) && !defined(__FreeBSD__)
#include <endian.h>
#endif
#include <math.h>
@@ -46,19 +47,31 @@
/* The floating point word order on ARM is big endian when floating point
* emulation is used, even if the byte order is little endian */
#if !(defined(__APPLE__) && defined(__MACH__)) && !defined(WIN32) && \
- __FLOAT_WORD_ORDER == __BIG_ENDIAN
+ !defined(__FreeBSD__) && __FLOAT_WORD_ORDER == __BIG_ENDIAN
#define IEEE_MC68k
#else
#define IEEE_8087
#endif
#define __MATH_H__
-#if defined(__APPLE__) && defined(__MACH__)
-/* stdlib.h on Apple's 10.5 and later SDKs will mangle the name of strtod.
- * If it's included after strtod is redefined as gay_strtod, it will mangle
- * the name of gay_strtod, which is unwanted. */
+#if defined(__APPLE__) && defined(__MACH__) || defined(__FreeBSD__)
+/* stdlib.h on FreeBSD and Apple's 10.5 and later SDKs will mangle the
+ * name of strtod. If it's included after strtod is redefined as
+ * gay_strtod, it will mangle the name of gay_strtod, which is
+ * unwanted. */
#include <stdlib.h>
+
#endif
+/* stdlib.h on Windows adds __declspec(dllimport) to all functions when using
+ * the DLL version of the CRT (compiling with /MD or /MDd). If stdlib.h is
+ * included after strtod is redefined as gay_strtod, it will add
+ * __declspec(dllimport) to gay_strtod, which causes the compilation of
+ * gay_strtod in dtoa.c to fail.
+*/
+#if defined(WIN32) && defined(_DLL)
+#include "stdlib.h"
+#endif
+
/* Make sure we use the David M. Gay version of strtod(). On Linux, we
* cannot use the same name (maybe the function does not have weak
* linkage?). */
diff --git a/src/execution.cc b/src/execution.cc
index 9f5bd83..996c58c 100644
--- a/src/execution.cc
+++ b/src/execution.cc
@@ -32,7 +32,7 @@
#include "api.h"
#include "codegen-inl.h"
-#if defined(ARM) || defined (__arm__) || defined(__thumb__)
+#ifdef ARM
#include "simulator-arm.h"
#else // ia32
#include "simulator-ia32.h"
diff --git a/src/factory.cc b/src/factory.cc
index 209cd4d..2c82b1d 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -170,9 +170,9 @@
}
-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);
}
@@ -458,8 +458,14 @@
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 @@
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()) {
diff --git a/src/factory.h b/src/factory.h
index 89e2d69..429c483 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -147,7 +147,8 @@
// 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);
@@ -206,6 +207,9 @@
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);
static Handle<Code> CopyCode(Handle<Code> code);
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 5c96429..0db2303 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -151,7 +151,7 @@
DEFINE_int(gc_interval, -1, "garbage collect after <n> allocations")
DEFINE_bool(trace_gc, false,
"print one trace line following each garbage collection")
-DEFINE_bool(collect_maps, true,
+DEFINE_bool(collect_maps, false,
"garbage collect maps from which no objects can be reached")
// ic.cc
@@ -199,6 +199,13 @@
DEFINE_bool(preemption, false,
"activate a 100ms timer that switches between V8 threads")
+// irregexp
+DEFINE_bool(irregexp, false, "new regular expression code")
+DEFINE_bool(trace_regexps, false, "trace Irregexp execution")
+DEFINE_bool(irregexp_native, false, "use native code Irregexp implementation (IA32 only)")
+DEFINE_bool(disable_jscre, false, "abort if JSCRE is used. Only useful with --irregexp")
+DEFINE_bool(attempt_multiline_irregexp, false, "attempt to use Irregexp for multiline regexps")
+
// Testing flags test/cctest/test-{flags,api,serialization}.cc
DEFINE_bool(testing_bool_flag, true, "testing_bool_flag")
DEFINE_int(testing_int_flag, 13, "testing_int_flag")
@@ -219,6 +226,7 @@
DEFINE_bool(help, false, "Print usage message, including flags, on console")
DEFINE_bool(dump_counters, false, "Dump counters on exit")
+DEFINE_string(map_counters, false, "Map counters to a file")
DEFINE_args(js_arguments, JSArguments(),
"Pass all remaining arguments to the script. Alias for \"--\".")
@@ -289,6 +297,11 @@
"report heap spill statistics along with heap_stats "
"(requires heap_stats)")
+// irregexp
+DEFINE_bool(trace_regexp_bytecodes, false, "trace Irregexp bytecode execution")
+DEFINE_bool(trace_regexp_assembler, false,
+ "trace Irregexp macro assembler calls.")
+
//
// Logging and profiling only flags
//
diff --git a/src/frames-inl.h b/src/frames-inl.h
index 2b50d55..b34a0ab 100644
--- a/src/frames-inl.h
+++ b/src/frames-inl.h
@@ -29,7 +29,7 @@
#define V8_FRAMES_INL_H_
#include "frames.h"
-#if defined(ARM) || defined (__arm__) || defined(__thumb__)
+#ifdef ARM
#include "frames-arm.h"
#else
#include "frames-ia32.h"
diff --git a/src/globals.h b/src/globals.h
index 387ed88..e2fb2a9 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -178,10 +178,16 @@
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;
@@ -191,7 +197,7 @@
class String;
class Struct;
class SwitchStatement;
-class Visitor;
+class AstVisitor;
class Variable;
class VariableProxy;
class RelocInfo;
diff --git a/src/heap-inl.h b/src/heap-inl.h
index 4fd9a4e..07d92c1 100644
--- a/src/heap-inl.h
+++ b/src/heap-inl.h
@@ -38,6 +38,18 @@
}
+Object* Heap::AllocateSymbol(Vector<const char> str,
+ int chars,
+ uint32_t length_field) {
+ if (global_external_symbol_callback_) {
+ return AllocateExternalSymbol(str, chars);
+ }
+ unibrow::Utf8InputBuffer<> buffer(str.start(),
+ static_cast<unsigned>(str.length()));
+ return AllocateInternalSymbol(&buffer, chars, length_field);
+}
+
+
Object* Heap::AllocateRaw(int size_in_bytes,
AllocationSpace space,
AllocationSpace retry_space) {
diff --git a/src/heap.cc b/src/heap.cc
index e62234f..53b0774 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -84,6 +84,8 @@
GCCallback Heap::global_gc_prologue_callback_ = NULL;
GCCallback Heap::global_gc_epilogue_callback_ = NULL;
+ExternalSymbolCallback Heap::global_external_symbol_callback_ = NULL;
+
// Variables set based on semispace_size_ and old_generation_size_ in
// ConfigureHeap.
int Heap::young_generation_size_ = 0; // Will be 2 * semispace_size_.
@@ -390,8 +392,7 @@
}
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.
@@ -406,6 +407,14 @@
}
+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_++;
@@ -1535,6 +1544,29 @@
}
+Object* Heap::AllocateExternalSymbolFromTwoByte(
+ ExternalTwoByteString::Resource* resource) {
+ Map* map;
+ int length = resource->length();
+ if (length <= String::kMaxShortStringSize) {
+ map = short_external_symbol_map();
+ } else if (length <= String::kMaxMediumStringSize) {
+ map = medium_external_symbol_map();
+ } else {
+ map = long_external_symbol_map();
+ }
+
+ Object* result = Allocate(map, OLD_DATA_SPACE);
+ if (result->IsFailure()) return result;
+
+ ExternalTwoByteString* external_string = ExternalTwoByteString::cast(result);
+ external_string->set_length(length);
+ external_string->set_resource(resource);
+
+ return result;
+}
+
+
Object* Heap::LookupSingleCharacterStringFromCode(uint16_t code) {
if (code <= String::kMaxAsciiCharCode) {
Object* value = Heap::single_character_string_cache()->get(code);
@@ -1557,6 +1589,24 @@
}
+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 =
@@ -1574,7 +1624,8 @@
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;
@@ -1597,7 +1648,16 @@
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
@@ -2028,9 +2088,9 @@
}
-Object* Heap::AllocateSymbol(unibrow::CharacterStream* buffer,
- int chars,
- uint32_t length_field) {
+Object* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer,
+ int chars,
+ uint32_t length_field) {
// Ensure the chars matches the number of characters in the buffer.
ASSERT(static_cast<unsigned>(chars) == buffer->Length());
// Determine whether the string is ascii.
@@ -2086,6 +2146,44 @@
}
+// External string resource that only contains a length field. These
+// are used temporarily when allocating external symbols.
+class DummyExternalStringResource
+ : public v8::String::ExternalStringResource {
+ public:
+ explicit DummyExternalStringResource(size_t length) : length_(length) { }
+
+ virtual const uint16_t* data() const {
+ UNREACHABLE();
+ return NULL;
+ }
+
+ virtual size_t length() const { return length_; }
+ private:
+ size_t length_;
+};
+
+
+Object* Heap::AllocateExternalSymbol(Vector<const char> string, int chars) {
+ // Attempt to allocate the resulting external string first. Use a
+ // dummy string resource that has the correct length so that we only
+ // have to patch the external string resource after the callback.
+ DummyExternalStringResource dummy_resource(chars);
+ Object* obj = AllocateExternalSymbolFromTwoByte(&dummy_resource);
+ if (obj->IsFailure()) return obj;
+ // Perform callback.
+ v8::String::ExternalStringResource* resource =
+ global_external_symbol_callback_(string.start(), string.length());
+ // Patch the resource pointer of the result.
+ ExternalTwoByteString* result = ExternalTwoByteString::cast(obj);
+ result->set_resource(resource);
+ // Force hash code to be computed.
+ result->Hash();
+ ASSERT(result->IsEqualTo(string));
+ return result;
+}
+
+
Object* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) {
AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
int size = SeqAsciiString::SizeFor(length);
diff --git a/src/heap.h b/src/heap.h
index d89caf9..f17a091 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -193,7 +193,8 @@
V(failure_symbol, "<failure>") \
V(space_symbol, " ") \
V(exec_symbol, "exec") \
- V(zero_symbol, "0")
+ V(zero_symbol, "0") \
+ V(global_eval_symbol, "GlobalEval")
// Forward declaration of the GCTracer class.
@@ -356,9 +357,17 @@
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this function does not perform a garbage collection.
- static Object* AllocateSymbol(unibrow::CharacterStream* buffer,
- int chars,
- uint32_t length_field);
+ static inline Object* AllocateSymbol(Vector<const char> str,
+ int chars,
+ uint32_t length_field);
+
+ static Object* AllocateInternalSymbol(unibrow::CharacterStream* buffer,
+ int chars,
+ uint32_t length_field);
+
+ static Object* AllocateExternalSymbol(Vector<const char> str,
+ int chars);
+
// Allocates and partially initializes a String. There are two String
// encodings: ASCII and two byte. These functions allocate a string of the
@@ -383,7 +392,13 @@
// 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
@@ -527,6 +542,8 @@
ExternalAsciiString::Resource* resource);
static Object* AllocateExternalStringFromTwoByte(
ExternalTwoByteString::Resource* resource);
+ static Object* AllocateExternalSymbolFromTwoByte(
+ ExternalTwoByteString::Resource* resource);
// Allocates an uninitialized object. The memory is non-executable if the
// hardware and OS allow.
@@ -539,11 +556,14 @@
// 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.
@@ -572,6 +592,9 @@
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);
@@ -595,6 +618,10 @@
global_gc_epilogue_callback_ = callback;
}
+ static void SetExternalSymbolCallback(ExternalSymbolCallback callback) {
+ global_external_symbol_callback_ = callback;
+ }
+
// Heap roots
#define ROOT_ACCESSOR(type, name) static type* name() { return name##_; }
ROOT_LIST(ROOT_ACCESSOR)
@@ -854,6 +881,9 @@
static GCCallback global_gc_prologue_callback_;
static GCCallback global_gc_epilogue_callback_;
+ // Callback function used for allocating external symbols.
+ static ExternalSymbolCallback global_external_symbol_callback_;
+
// Checks whether a global GC is necessary
static GarbageCollector SelectGarbageCollector(AllocationSpace space);
diff --git a/src/ic-arm.cc b/src/ic-arm.cc
index 92eb5d3..dc35256 100644
--- a/src/ic-arm.cc
+++ b/src/ic-arm.cc
@@ -125,6 +125,32 @@
}
+// Helper function used to check that a value is either not a function
+// or is loaded if it is a function.
+static void GenerateCheckNonFunctionOrLoaded(MacroAssembler* masm,
+ Label* miss,
+ Register value,
+ Register scratch) {
+ Label done;
+ // Check if the value is a Smi.
+ __ tst(value, Operand(kSmiTagMask));
+ __ b(eq, &done);
+ // Check if the value is a function.
+ __ ldr(scratch, FieldMemOperand(value, HeapObject::kMapOffset));
+ __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
+ __ cmp(scratch, Operand(JS_FUNCTION_TYPE));
+ __ b(ne, &done);
+ // Check if the function has been loaded.
+ __ ldr(scratch,
+ FieldMemOperand(value, JSFunction::kSharedFunctionInfoOffset));
+ __ ldr(scratch,
+ FieldMemOperand(scratch, SharedFunctionInfo::kLazyLoadDataOffset));
+ __ cmp(scratch, Operand(Factory::undefined_value()));
+ __ b(ne, miss);
+ __ bind(&done);
+}
+
+
void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r2 : name
@@ -142,62 +168,17 @@
}
-// Generate code to check if an object is a string. If the object is
-// a string, the map's instance type is left in the scratch1 register.
-static void GenerateStringCheck(MacroAssembler* masm,
- Register receiver,
- Register scratch1,
- Register scratch2,
- Label* smi,
- Label* non_string_object) {
- // Check that the receiver isn't a smi.
- __ tst(receiver, Operand(kSmiTagMask));
- __ b(eq, smi);
-
- // Check that the object is a string.
- __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
- __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
- __ and_(scratch2, scratch1, Operand(kIsNotStringMask));
- // The cast is to resolve the overload for the argument of 0x0.
- __ cmp(scratch2, Operand(static_cast<int32_t>(kStringTag)));
- __ b(ne, non_string_object);
-}
-
-
void LoadIC::GenerateStringLength(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- r2 : name
// -- lr : return address
// -- [sp] : receiver
// -----------------------------------
- Label miss, load_length, check_wrapper;
+ Label miss;
__ ldr(r0, MemOperand(sp, 0));
- // Check if the object is a string leaving the instance type in the
- // r1 register.
- GenerateStringCheck(masm, r0, r1, r3, &miss, &check_wrapper);
-
- // Load length directly from the string.
- __ bind(&load_length);
- __ and_(r1, r1, Operand(kStringSizeMask));
- __ add(r1, r1, Operand(String::kHashShift));
- __ ldr(r0, FieldMemOperand(r0, String::kLengthOffset));
- __ mov(r0, Operand(r0, LSR, r1));
- __ mov(r0, Operand(r0, LSL, kSmiTagSize));
- __ Ret();
-
- // Check if the object is a JSValue wrapper.
- __ bind(&check_wrapper);
- __ cmp(r1, Operand(JS_VALUE_TYPE));
- __ b(ne, &miss);
-
- // Check if the wrapped value is a string and load the length
- // directly if it is.
- __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset));
- GenerateStringCheck(masm, r0, r1, r3, &miss, &miss);
- __ b(&load_length);
-
+ StubCompiler::GenerateLoadStringLength2(masm, r0, r1, r3, &miss);
// Cache miss: Jump to runtime.
__ bind(&miss);
StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
@@ -300,6 +281,12 @@
__ cmp(r0, Operand(JS_FUNCTION_TYPE));
__ b(ne, miss);
+ // Check that the function has been loaded.
+ __ ldr(r0, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
+ __ ldr(r0, FieldMemOperand(r0, SharedFunctionInfo::kLazyLoadDataOffset));
+ __ cmp(r0, Operand(Factory::undefined_value()));
+ __ b(ne, miss);
+
// Patch the receiver with the global proxy if necessary.
if (is_global_object) {
__ ldr(r2, MemOperand(sp, argc * kPointerSize));
@@ -467,6 +454,7 @@
__ bind(&probe);
GenerateDictionaryLoad(masm, &miss, r1, r0);
+ GenerateCheckNonFunctionOrLoaded(masm, &miss, r0, r1);
__ Ret();
// Global object access: Check access rights.
@@ -500,7 +488,6 @@
}
-// TODO(1224671): ICs for keyed load/store is not completed on ARM.
Object* KeyedLoadIC_Miss(Arguments args);
@@ -521,14 +508,62 @@
}
-// TODO(1224671): implement the fast case.
void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
// ---------- S t a t e --------------
// -- lr : return address
// -- sp[0] : key
// -- sp[4] : receiver
+ Label slow, fast;
- KeyedLoadIC::Generate(masm, ExternalReference(Runtime::kKeyedGetProperty));
+ // Get the key and receiver object from the stack.
+ __ ldm(ia, sp, r0.bit() | r1.bit());
+ // Check that the key is a smi.
+ __ tst(r0, Operand(kSmiTagMask));
+ __ b(ne, &slow);
+ __ mov(r0, Operand(r0, ASR, kSmiTagSize));
+ // Check that the object isn't a smi.
+ __ tst(r1, Operand(kSmiTagMask));
+ __ b(eq, &slow);
+
+ // Check that the object is some kind of JS object EXCEPT JS Value type.
+ // In the case that the object is a value-wrapper object,
+ // we enter the runtime system to make sure that indexing into string
+ // objects work as intended.
+ ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
+ __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
+ __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
+ __ cmp(r2, Operand(JS_OBJECT_TYPE));
+ __ b(lt, &slow);
+
+ // Get the elements array of the object.
+ __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
+ // Check that the object is in fast mode (not dictionary).
+ __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
+ __ cmp(r3, Operand(Factory::hash_table_map()));
+ __ b(eq, &slow);
+ // Check that the key (index) is within bounds.
+ __ ldr(r3, FieldMemOperand(r1, Array::kLengthOffset));
+ __ cmp(r0, Operand(r3));
+ __ b(lo, &fast);
+
+ // Slow case: Push extra copies of the arguments (2).
+ __ bind(&slow);
+ __ IncrementCounter(&Counters::keyed_load_generic_slow, 1, r0, r1);
+ __ ldm(ia, sp, r0.bit() | r1.bit());
+ __ stm(db_w, sp, r0.bit() | r1.bit());
+ // Do tail-call to runtime routine.
+ __ TailCallRuntime(ExternalReference(Runtime::kGetProperty), 2);
+
+ // Fast case: Do the load.
+ __ bind(&fast);
+ __ add(r3, r1, Operand(Array::kHeaderSize - kHeapObjectTag));
+ __ ldr(r0, MemOperand(r3, r0, LSL, kPointerSizeLog2));
+ __ cmp(r0, Operand(Factory::the_hole_value()));
+ // In case the loaded value is the_hole we have to consult GetProperty
+ // to ensure the prototype chain is searched.
+ __ b(eq, &slow);
+
+ __ Ret();
}
@@ -547,15 +582,114 @@
}
-// TODO(1224671): implement the fast case.
void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
// ---------- S t a t e --------------
// -- r0 : value
// -- lr : return address
// -- sp[0] : key
// -- sp[1] : receiver
+ Label slow, fast, array, extra, exit;
+ // Get the key and the object from the stack.
+ __ ldm(ia, sp, r1.bit() | r3.bit()); // r1 = key, r3 = receiver
+ // Check that the key is a smi.
+ __ tst(r1, Operand(kSmiTagMask));
+ __ b(ne, &slow);
+ // Check that the object isn't a smi.
+ __ tst(r3, Operand(kSmiTagMask));
+ __ b(eq, &slow);
+ // Get the type of the object from its map.
+ __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
+ __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
+ // Check if the object is a JS array or not.
+ __ cmp(r2, Operand(JS_ARRAY_TYPE));
+ // r1 == key.
+ __ b(eq, &array);
+ // Check that the object is some kind of JS object.
+ __ cmp(r2, Operand(FIRST_JS_OBJECT_TYPE));
+ __ b(lt, &slow);
- KeyedStoreIC::Generate(masm, ExternalReference(Runtime::kSetProperty));
+
+ // Object case: Check key against length in the elements array.
+ __ ldr(r3, FieldMemOperand(r3, JSObject::kElementsOffset));
+ // Check that the object is in fast mode (not dictionary).
+ __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
+ __ cmp(r2, Operand(Factory::hash_table_map()));
+ __ b(eq, &slow);
+ // Untag the key (for checking against untagged length in the fixed array).
+ __ mov(r1, Operand(r1, ASR, kSmiTagSize));
+ // Compute address to store into and check array bounds.
+ __ add(r2, r3, Operand(Array::kHeaderSize - kHeapObjectTag));
+ __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2));
+ __ ldr(ip, FieldMemOperand(r3, Array::kLengthOffset));
+ __ cmp(r1, Operand(ip));
+ __ b(lo, &fast);
+
+
+ // Slow case: Push extra copies of the arguments (3).
+ __ bind(&slow);
+ __ ldm(ia, sp, r1.bit() | r3.bit()); // r0 == value, r1 == key, r3 == object
+ __ stm(db_w, sp, r0.bit() | r1.bit() | r3.bit());
+ // Do tail-call to runtime routine.
+ __ TailCallRuntime(ExternalReference(Runtime::kSetProperty), 3);
+
+ // Extra capacity case: Check if there is extra capacity to
+ // perform the store and update the length. Used for adding one
+ // element to the array by writing to array[array.length].
+ // r0 == value, r1 == key, r2 == elements, r3 == object
+ __ bind(&extra);
+ __ b(ne, &slow); // do not leave holes in the array
+ __ mov(r1, Operand(r1, ASR, kSmiTagSize)); // untag
+ __ ldr(ip, FieldMemOperand(r2, Array::kLengthOffset));
+ __ cmp(r1, Operand(ip));
+ __ b(hs, &slow);
+ __ mov(r1, Operand(r1, LSL, kSmiTagSize)); // restore tag
+ __ add(r1, r1, Operand(1 << kSmiTagSize)); // and increment
+ __ str(r1, FieldMemOperand(r3, JSArray::kLengthOffset));
+ __ mov(r3, Operand(r2));
+ // NOTE: Computing the address to store into must take the fact
+ // that the key has been incremented into account.
+ int displacement = Array::kHeaderSize - kHeapObjectTag -
+ ((1 << kSmiTagSize) * 2);
+ __ add(r2, r2, Operand(displacement));
+ __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize));
+ __ b(&fast);
+
+
+ // Array case: Get the length and the elements array from the JS
+ // array. Check that the array is in fast mode; if it is the
+ // length is always a smi.
+ // r0 == value, r3 == object
+ __ bind(&array);
+ __ ldr(r2, FieldMemOperand(r3, JSObject::kElementsOffset));
+ __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
+ __ cmp(r1, Operand(Factory::hash_table_map()));
+ __ b(eq, &slow);
+
+ // Check the key against the length in the array, compute the
+ // address to store into and fall through to fast case.
+ __ ldr(r1, MemOperand(sp)); // resotre key
+ // r0 == value, r1 == key, r2 == elements, r3 == object.
+ __ ldr(ip, FieldMemOperand(r3, JSArray::kLengthOffset));
+ __ cmp(r1, Operand(ip));
+ __ b(hs, &extra);
+ __ mov(r3, Operand(r2));
+ __ add(r2, r2, Operand(Array::kHeaderSize - kHeapObjectTag));
+ __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize));
+
+
+ // Fast case: Do the store.
+ // r0 == value, r2 == address to store into, r3 == elements
+ __ bind(&fast);
+ __ str(r0, MemOperand(r2));
+ // Skip write barrier if the written value is a smi.
+ __ tst(r0, Operand(kSmiTagMask));
+ __ b(eq, &exit);
+ // Update write barrier for the elements array address.
+ __ sub(r1, r2, Operand(r3));
+ __ RecordWrite(r3, r1, r2);
+
+ __ bind(&exit);
+ __ Ret();
}
diff --git a/src/ic-ia32.cc b/src/ic-ia32.cc
index 11e55a9..7ff47b9 100644
--- a/src/ic-ia32.cc
+++ b/src/ic-ia32.cc
@@ -41,7 +41,7 @@
#define __ masm->
-// Helper function used from LoadIC/CallIC GenerateNormal.
+// Helper function used to load a property from a dictionary backing storage.
static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label,
Register r0, Register r1, Register r2,
Register name) {
@@ -121,6 +121,29 @@
}
+// Helper function used to check that a value is either not a function
+// or is loaded if it is a function.
+static void GenerateCheckNonFunctionOrLoaded(MacroAssembler* masm, Label* miss,
+ Register value, Register scratch) {
+ Label done;
+ // Check if the value is a Smi.
+ __ test(value, Immediate(kSmiTagMask));
+ __ j(zero, &done, not_taken);
+ // Check if the value is a function.
+ __ mov(scratch, FieldOperand(value, HeapObject::kMapOffset));
+ __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
+ __ cmp(scratch, JS_FUNCTION_TYPE);
+ __ j(not_equal, &done, taken);
+ // Check if the function has been loaded.
+ __ mov(scratch, FieldOperand(value, JSFunction::kSharedFunctionInfoOffset));
+ __ mov(scratch,
+ FieldOperand(scratch, SharedFunctionInfo::kLazyLoadDataOffset));
+ __ cmp(scratch, Factory::undefined_value());
+ __ j(not_equal, miss, not_taken);
+ __ bind(&done);
+}
+
+
void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
// ----------- S t a t e -------------
// -- ecx : name
@@ -236,6 +259,7 @@
__ j(not_zero, &slow, not_taken);
// Probe the dictionary leaving result in ecx.
GenerateDictionaryLoad(masm, &slow, ebx, ecx, edx, eax);
+ GenerateCheckNonFunctionOrLoaded(masm, &slow, ecx, edx);
__ mov(eax, Operand(ecx));
__ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
__ ret(0);
@@ -456,6 +480,12 @@
__ cmp(edx, JS_FUNCTION_TYPE);
__ j(not_equal, miss, not_taken);
+ // Check that the function has been loaded.
+ __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
+ __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kLazyLoadDataOffset));
+ __ cmp(edx, Factory::undefined_value());
+ __ j(not_equal, miss, not_taken);
+
// Patch the receiver with the global proxy if necessary.
if (is_global_object) {
__ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
@@ -627,6 +657,7 @@
// Search the dictionary placing the result in eax.
__ bind(&probe);
GenerateDictionaryLoad(masm, &miss, edx, eax, ebx, ecx);
+ GenerateCheckNonFunctionOrLoaded(masm, &miss, eax, edx);
__ ret(0);
// Global object access: Check access rights.
diff --git a/src/interpreter-irregexp.cc b/src/interpreter-irregexp.cc
new file mode 100644
index 0000000..f76c135
--- /dev/null
+++ b/src/interpreter-irregexp.cc
@@ -0,0 +1,411 @@
+// 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 Irregexp byte code.
+
+
+#include "v8.h"
+#include "unicode.h"
+#include "utils.h"
+#include "ast.h"
+#include "bytecodes-irregexp.h"
+#include "interpreter-irregexp.h"
+
+
+namespace v8 { namespace internal {
+
+
+static unibrow::Mapping<unibrow::Ecma262Canonicalize> canonicalize;
+
+
+static bool BackRefMatchesNoCase(int from,
+ int current,
+ int len,
+ Vector<const uc16> subject) {
+ for (int i = 0; i < len; i++) {
+ unibrow::uchar old_char = subject[from++];
+ unibrow::uchar new_char = subject[current++];
+ if (old_char == new_char) continue;
+ canonicalize.get(old_char, '\0', &old_char);
+ canonicalize.get(new_char, '\0', &new_char);
+ if (old_char != new_char) {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+#ifdef DEBUG
+static void TraceInterpreter(const byte* code_base,
+ const byte* pc,
+ int stack_depth,
+ int current_position,
+ int bytecode_length,
+ const char* bytecode_name) {
+ if (FLAG_trace_regexp_bytecodes) {
+ PrintF("pc = %02x, sp = %d, current = %d, bc = %s",
+ pc - code_base,
+ stack_depth,
+ current_position,
+ bytecode_name);
+ for (int i = 1; i < bytecode_length; i++) {
+ printf(", %02x", pc[i]);
+ }
+ printf("\n");
+ }
+}
+
+
+#define BYTECODE(name) \
+ case BC_##name: \
+ TraceInterpreter(code_base, \
+ pc, \
+ backtrack_sp - backtrack_stack, \
+ current, \
+ BC_##name##_LENGTH, \
+ #name);
+#else
+#define BYTECODE(name) \
+ case BC_##name:
+#endif
+
+
+
+static bool RawMatch(const byte* code_base,
+ Vector<const uc16> subject,
+ int* registers,
+ int current,
+ int current_char) {
+ const byte* pc = code_base;
+ static const int kBacktrackStackSize = 10000;
+ int backtrack_stack[kBacktrackStackSize];
+ int backtrack_stack_space = kBacktrackStackSize;
+ int* backtrack_sp = backtrack_stack;
+#ifdef DEBUG
+ if (FLAG_trace_regexp_bytecodes) {
+ PrintF("\n\nStart bytecode interpreter\n\n");
+ }
+#endif
+ while (true) {
+ switch (*pc) {
+ BYTECODE(BREAK)
+ UNREACHABLE();
+ return false;
+ BYTECODE(PUSH_CP)
+ if (--backtrack_stack_space < 0) {
+ return false; // No match on backtrack stack overflow.
+ }
+ *backtrack_sp++ = current + Load32(pc + 1);
+ pc += BC_PUSH_CP_LENGTH;
+ break;
+ BYTECODE(PUSH_BT)
+ if (--backtrack_stack_space < 0) {
+ return false; // No match on backtrack stack overflow.
+ }
+ *backtrack_sp++ = Load32(pc + 1);
+ pc += BC_PUSH_BT_LENGTH;
+ break;
+ BYTECODE(PUSH_REGISTER)
+ if (--backtrack_stack_space < 0) {
+ return false; // No match on backtrack stack overflow.
+ }
+ *backtrack_sp++ = registers[pc[1]];
+ pc += BC_PUSH_REGISTER_LENGTH;
+ break;
+ BYTECODE(SET_REGISTER)
+ registers[pc[1]] = Load32(pc + 2);
+ pc += BC_SET_REGISTER_LENGTH;
+ break;
+ BYTECODE(ADVANCE_REGISTER)
+ registers[pc[1]] += Load32(pc + 2);
+ pc += BC_ADVANCE_REGISTER_LENGTH;
+ break;
+ BYTECODE(SET_REGISTER_TO_CP)
+ registers[pc[1]] = current + Load32(pc + 2);
+ pc += BC_SET_REGISTER_TO_CP_LENGTH;
+ break;
+ BYTECODE(SET_CP_TO_REGISTER)
+ current = registers[pc[1]];
+ pc += BC_SET_CP_TO_REGISTER_LENGTH;
+ break;
+ BYTECODE(SET_REGISTER_TO_SP)
+ registers[pc[1]] = backtrack_sp - backtrack_stack;
+ pc += BC_SET_REGISTER_TO_SP_LENGTH;
+ break;
+ BYTECODE(SET_SP_TO_REGISTER)
+ backtrack_sp = backtrack_stack + registers[pc[1]];
+ backtrack_stack_space = kBacktrackStackSize -
+ (backtrack_sp - backtrack_stack);
+ pc += BC_SET_SP_TO_REGISTER_LENGTH;
+ break;
+ BYTECODE(POP_CP)
+ backtrack_stack_space++;
+ --backtrack_sp;
+ current = *backtrack_sp;
+ pc += BC_POP_CP_LENGTH;
+ break;
+ BYTECODE(POP_BT)
+ backtrack_stack_space++;
+ --backtrack_sp;
+ pc = code_base + *backtrack_sp;
+ break;
+ BYTECODE(POP_REGISTER)
+ backtrack_stack_space++;
+ --backtrack_sp;
+ registers[pc[1]] = *backtrack_sp;
+ pc += BC_POP_REGISTER_LENGTH;
+ break;
+ BYTECODE(FAIL)
+ return false;
+ BYTECODE(SUCCEED)
+ return true;
+ BYTECODE(ADVANCE_CP)
+ current += Load32(pc + 1);
+ pc += BC_ADVANCE_CP_LENGTH;
+ break;
+ BYTECODE(GOTO)
+ pc = code_base + Load32(pc + 1);
+ break;
+ BYTECODE(LOAD_CURRENT_CHAR) {
+ int pos = current + Load32(pc + 1);
+ if (pos >= subject.length()) {
+ pc = code_base + Load32(pc + 5);
+ } else {
+ current_char = subject[pos];
+ pc += BC_LOAD_CURRENT_CHAR_LENGTH;
+ }
+ break;
+ }
+ BYTECODE(CHECK_CHAR) {
+ int c = Load16(pc + 1);
+ if (c == current_char) {
+ pc = code_base + Load32(pc + 3);
+ } else {
+ pc += BC_CHECK_CHAR_LENGTH;
+ }
+ break;
+ }
+ BYTECODE(CHECK_NOT_CHAR) {
+ int c = Load16(pc + 1);
+ if (c != current_char) {
+ pc = code_base + Load32(pc + 3);
+ } else {
+ pc += BC_CHECK_NOT_CHAR_LENGTH;
+ }
+ break;
+ }
+ BYTECODE(OR_CHECK_NOT_CHAR) {
+ int c = Load16(pc + 1);
+ if (c != (current_char | Load16(pc + 3))) {
+ pc = code_base + Load32(pc + 5);
+ } else {
+ pc += BC_OR_CHECK_NOT_CHAR_LENGTH;
+ }
+ break;
+ }
+ BYTECODE(MINUS_OR_CHECK_NOT_CHAR) {
+ int c = Load16(pc + 1);
+ int m = Load16(pc + 3);
+ if (c != ((current_char - m) | m)) {
+ pc = code_base + Load32(pc + 5);
+ } else {
+ pc += BC_MINUS_OR_CHECK_NOT_CHAR_LENGTH;
+ }
+ break;
+ }
+ BYTECODE(CHECK_LT) {
+ int limit = Load16(pc + 1);
+ if (current_char < limit) {
+ pc = code_base + Load32(pc + 3);
+ } else {
+ pc += BC_CHECK_LT_LENGTH;
+ }
+ break;
+ }
+ BYTECODE(CHECK_GT) {
+ int limit = Load16(pc + 1);
+ if (current_char > limit) {
+ pc = code_base + Load32(pc + 3);
+ } else {
+ pc += BC_CHECK_GT_LENGTH;
+ }
+ break;
+ }
+ BYTECODE(CHECK_REGISTER_LT)
+ if (registers[pc[1]] < Load16(pc + 2)) {
+ pc = code_base + Load32(pc + 4);
+ } else {
+ pc += BC_CHECK_REGISTER_LT_LENGTH;
+ }
+ break;
+ BYTECODE(CHECK_REGISTER_GE)
+ if (registers[pc[1]] >= Load16(pc + 2)) {
+ pc = code_base + Load32(pc + 4);
+ } else {
+ pc += BC_CHECK_REGISTER_GE_LENGTH;
+ }
+ break;
+ BYTECODE(LOOKUP_MAP1) {
+ // Look up character in a bitmap. If we find a 0, then jump to the
+ // location at pc + 7. Otherwise fall through!
+ int index = current_char - Load16(pc + 1);
+ byte map = code_base[Load32(pc + 3) + (index >> 3)];
+ map = ((map >> (index & 7)) & 1);
+ if (map == 0) {
+ pc = code_base + Load32(pc + 7);
+ } else {
+ pc += BC_LOOKUP_MAP1_LENGTH;
+ }
+ break;
+ }
+ BYTECODE(LOOKUP_MAP2) {
+ // Look up character in a half-nibble map. If we find 00, then jump to
+ // the location at pc + 7. If we find 01 then jump to location at
+ // pc + 11, etc.
+ int index = (current_char - Load16(pc + 1)) << 1;
+ byte map = code_base[Load32(pc + 3) + (index >> 3)];
+ map = ((map >> (index & 7)) & 3);
+ if (map < 2) {
+ if (map == 0) {
+ pc = code_base + Load32(pc + 7);
+ } else {
+ pc = code_base + Load32(pc + 11);
+ }
+ } else {
+ if (map == 2) {
+ pc = code_base + Load32(pc + 15);
+ } else {
+ pc = code_base + Load32(pc + 19);
+ }
+ }
+ break;
+ }
+ BYTECODE(LOOKUP_MAP8) {
+ // Look up character in a byte map. Use the byte as an index into a
+ // table that follows this instruction immediately.
+ int index = current_char - Load16(pc + 1);
+ byte map = code_base[Load32(pc + 3) + index];
+ const byte* new_pc = code_base + Load32(pc + 7) + (map << 2);
+ pc = code_base + Load32(new_pc);
+ break;
+ }
+ BYTECODE(LOOKUP_HI_MAP8) {
+ // Look up high byte of this character in a byte map. Use the byte as
+ // an index into a table that follows this instruction immediately.
+ int index = (current_char >> 8) - pc[1];
+ byte map = code_base[Load32(pc + 2) + index];
+ const byte* new_pc = code_base + Load32(pc + 6) + (map << 2);
+ pc = code_base + Load32(new_pc);
+ break;
+ }
+ BYTECODE(CHECK_NOT_REGS_EQUAL)
+ if (registers[pc[1]] == registers[pc[2]]) {
+ pc += BC_CHECK_NOT_REGS_EQUAL_LENGTH;
+ } else {
+ pc = code_base + Load32(pc + 3);
+ }
+ break;
+ BYTECODE(CHECK_NOT_BACK_REF) {
+ int from = registers[pc[1]];
+ int len = registers[pc[1] + 1] - from;
+ if (from < 0 || len <= 0) {
+ pc += BC_CHECK_NOT_BACK_REF_LENGTH;
+ break;
+ }
+ if (current + len > subject.length()) {
+ pc = code_base + Load32(pc + 2);
+ break;
+ } else {
+ int i;
+ for (i = 0; i < len; i++) {
+ if (subject[from + i] != subject[current + i]) {
+ pc = code_base + Load32(pc + 2);
+ break;
+ }
+ }
+ if (i < len) break;
+ current += len;
+ }
+ pc += BC_CHECK_NOT_BACK_REF_LENGTH;
+ break;
+ }
+ BYTECODE(CHECK_NOT_BACK_REF_NO_CASE) {
+ int from = registers[pc[1]];
+ int len = registers[pc[1] + 1] - from;
+ if (from < 0 || len <= 0) {
+ pc += BC_CHECK_NOT_BACK_REF_NO_CASE_LENGTH;
+ break;
+ }
+ if (current + len > subject.length()) {
+ pc = code_base + Load32(pc + 2);
+ break;
+ } else {
+ if (BackRefMatchesNoCase(from, current, len, subject)) {
+ pc += BC_CHECK_NOT_BACK_REF_NO_CASE_LENGTH;
+ } else {
+ pc = code_base + Load32(pc + 2);
+ }
+ }
+ break;
+ }
+ BYTECODE(CHECK_NOT_AT_START)
+ if (current == 0) {
+ pc += BC_CHECK_NOT_AT_START_LENGTH;
+ } else {
+ pc = code_base + Load32(pc + 1);
+ }
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+}
+
+
+bool IrregexpInterpreter::Match(Handle<ByteArray> code_array,
+ Handle<String> subject16,
+ int* registers,
+ int start_position) {
+ ASSERT(StringShape(*subject16).IsTwoByteRepresentation());
+ ASSERT(subject16->IsFlat(StringShape(*subject16)));
+
+ AssertNoAllocation a;
+ const byte* code_base = code_array->GetDataStartAddress();
+ uc16 previous_char = '\n';
+ Vector<const uc16> subject_vector =
+ Vector<const uc16>(subject16->GetTwoByteData(), subject16->length());
+ if (start_position != 0) previous_char = subject_vector[start_position - 1];
+ return RawMatch(code_base,
+ subject_vector,
+ registers,
+ start_position,
+ previous_char);
+}
+
+} } // namespace v8::internal
diff --git a/src/interpreter-irregexp.h b/src/interpreter-irregexp.h
new file mode 100644
index 0000000..2393d74
--- /dev/null
+++ b/src/interpreter-irregexp.h
@@ -0,0 +1,47 @@
+// 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 Irregexp 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_
diff --git a/src/jsregexp-inl.h b/src/jsregexp-inl.h
new file mode 100644
index 0000000..9371703
--- /dev/null
+++ b/src/jsregexp-inl.h
@@ -0,0 +1,264 @@
+// 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_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 v8::internal
+
+
+#endif // V8_JSREGEXP_INL_H_
diff --git a/src/jsregexp.cc b/src/jsregexp.cc
index 39dc0d1..3046b96 100644
--- a/src/jsregexp.cc
+++ b/src/jsregexp.cc
@@ -27,13 +27,28 @@
#include "v8.h"
+#include "ast.h"
#include "execution.h"
#include "factory.h"
-#include "jsregexp.h"
+#include "jsregexp-inl.h"
#include "platform.h"
#include "runtime.h"
#include "top.h"
#include "compilation-cache.h"
+#include "string-stream.h"
+#include "parser.h"
+#include "regexp-macro-assembler.h"
+#include "regexp-macro-assembler-tracer.h"
+#include "regexp-macro-assembler-irregexp.h"
+
+#ifdef ARM
+#include "regexp-macro-assembler-arm.h"
+#else // IA32
+#include "macro-assembler-ia32.h"
+#include "regexp-macro-assembler-ia32.h"
+#endif
+
+#include "interpreter-irregexp.h"
// Including pcre.h undefines DEBUG to avoid getting debug output from
// the JSCRE implementation. Make sure to redefine it in debug mode
@@ -45,12 +60,10 @@
#include "third_party/jscre/pcre.h"
#endif
+
namespace v8 { namespace internal {
-#define CAPTURE_INDEX 0
-#define INTERNAL_INDEX 1
-
static Failure* malloc_failure;
static void* JSREMalloc(size_t size) {
@@ -103,7 +116,7 @@
// Ensure that the constructor function has been loaded.
if (!constructor->IsLoaded()) {
LoadLazy(constructor, has_pending_exception);
- if (*has_pending_exception) return Handle<Object>(Failure::Exception());
+ if (*has_pending_exception) return Handle<Object>();
}
// Call the construct code with 2 arguments.
Object** argv[2] = { Handle<Object>::cast(pattern).location(),
@@ -176,7 +189,16 @@
}
-unibrow::Predicate<unibrow::RegExpSpecialChar, 128> is_reg_exp_special_char;
+static inline void ThrowRegExpException(Handle<JSRegExp> re,
+ Handle<String> pattern,
+ Handle<String> error_text,
+ const char* message) {
+ Handle<JSArray> array = Factory::NewJSArray(2);
+ SetElement(array, 0, pattern);
+ SetElement(array, 1, error_text);
+ Handle<Object> regexp_err = Factory::NewSyntaxError(message, array);
+ Top::Throw(*regexp_err);
+}
Handle<Object> RegExpImpl::Compile(Handle<JSRegExp> re,
@@ -185,21 +207,50 @@
JSRegExp::Flags flags = RegExpFlagsFromString(flag_str);
Handle<FixedArray> cached = CompilationCache::LookupRegExp(pattern, flags);
bool in_cache = !cached.is_null();
+ LOG(RegExpCompileEvent(re, in_cache));
+
Handle<Object> result;
- StringShape shape(*pattern);
if (in_cache) {
re->set_data(*cached);
result = re;
} else {
- bool is_atom = !flags.is_ignore_case();
- for (int i = 0; is_atom && i < pattern->length(shape); i++) {
- if (is_reg_exp_special_char.get(pattern->Get(shape, i)))
- is_atom = false;
+ FlattenString(pattern);
+ ZoneScope zone_scope(DELETE_ON_EXIT);
+ RegExpParseResult parse_result;
+ FlatStringReader reader(pattern);
+ if (!ParseRegExp(&reader, flags.is_multiline(), &parse_result)) {
+ // Throw an exception if we fail to parse the pattern.
+ ThrowRegExpException(re,
+ pattern,
+ parse_result.error,
+ "malformed_regexp");
+ return Handle<Object>();
}
- if (is_atom) {
- result = AtomCompile(re, pattern, flags);
+ RegExpAtom* atom = parse_result.tree->AsAtom();
+ if (atom != NULL && !flags.is_ignore_case()) {
+ if (parse_result.has_character_escapes) {
+ Vector<const uc16> atom_pattern = atom->data();
+ Handle<String> atom_string =
+ Factory::NewStringFromTwoByte(atom_pattern);
+ result = AtomCompile(re, pattern, flags, atom_string);
+ } else {
+ result = AtomCompile(re, pattern, flags, pattern);
+ }
} else {
- result = JsreCompile(re, pattern, flags);
+ RegExpNode* node = NULL;
+ Handle<FixedArray> irregexp_data =
+ RegExpEngine::Compile(&parse_result,
+ &node,
+ flags.is_ignore_case(),
+ flags.is_multiline());
+ if (irregexp_data.is_null()) {
+ if (FLAG_disable_jscre) {
+ UNIMPLEMENTED();
+ }
+ result = JscrePrepare(re, pattern, flags);
+ } else {
+ result = IrregexpPrepare(re, pattern, flags, irregexp_data);
+ }
}
Object* data = re->data();
if (data->IsFixedArray()) {
@@ -210,7 +261,6 @@
}
}
- LOG(RegExpCompileEvent(re, in_cache));
return result;
}
@@ -220,9 +270,14 @@
Handle<Object> index) {
switch (regexp->TypeTag()) {
case JSRegExp::JSCRE:
- return JsreExec(regexp, subject, index);
+ if (FLAG_disable_jscre) {
+ UNIMPLEMENTED();
+ }
+ return JscreExec(regexp, subject, index);
case JSRegExp::ATOM:
return AtomExec(regexp, subject, index);
+ case JSRegExp::IRREGEXP:
+ return IrregexpExec(regexp, subject, index);
default:
UNREACHABLE();
return Handle<Object>();
@@ -234,9 +289,14 @@
Handle<String> subject) {
switch (regexp->TypeTag()) {
case JSRegExp::JSCRE:
- return JsreExecGlobal(regexp, subject);
+ if (FLAG_disable_jscre) {
+ UNIMPLEMENTED();
+ }
+ return JscreExecGlobal(regexp, subject);
case JSRegExp::ATOM:
return AtomExecGlobal(regexp, subject);
+ case JSRegExp::IRREGEXP:
+ return IrregexpExecGlobal(regexp, subject);
default:
UNREACHABLE();
return Handle<Object>();
@@ -246,8 +306,9 @@
Handle<Object> RegExpImpl::AtomCompile(Handle<JSRegExp> re,
Handle<String> pattern,
- JSRegExp::Flags flags) {
- Factory::SetRegExpData(re, JSRegExp::ATOM, pattern, flags, pattern);
+ JSRegExp::Flags flags,
+ Handle<String> match_pattern) {
+ Factory::SetRegExpData(re, JSRegExp::ATOM, pattern, flags, match_pattern);
return re;
}
@@ -267,12 +328,8 @@
if (value == -1) return Factory::null_value();
Handle<FixedArray> array = Factory::NewFixedArray(2);
- array->set(0,
- Smi::FromInt(value),
- SKIP_WRITE_BARRIER);
- array->set(1,
- Smi::FromInt(value + needle->length()),
- SKIP_WRITE_BARRIER);
+ array->set(0, Smi::FromInt(value));
+ array->set(1, Smi::FromInt(value + needle->length()));
return Factory::NewJSArrayWithElements(array);
}
@@ -296,12 +353,8 @@
int end = value + needle_length;
Handle<FixedArray> array = Factory::NewFixedArray(2);
- array->set(0,
- Smi::FromInt(value),
- SKIP_WRITE_BARRIER);
- array->set(1,
- Smi::FromInt(end),
- SKIP_WRITE_BARRIER);
+ array->set(0, Smi::FromInt(value));
+ array->set(1, Smi::FromInt(end));
Handle<JSArray> pair = Factory::NewJSArrayWithElements(array);
SetElement(result, match_count, pair);
match_count++;
@@ -312,6 +365,24 @@
}
+Handle<Object>RegExpImpl::JscrePrepare(Handle<JSRegExp> re,
+ Handle<String> pattern,
+ JSRegExp::Flags flags) {
+ Handle<Object> value(Heap::undefined_value());
+ Factory::SetRegExpData(re, JSRegExp::JSCRE, pattern, flags, value);
+ return re;
+}
+
+
+Handle<Object>RegExpImpl::IrregexpPrepare(Handle<JSRegExp> re,
+ Handle<String> pattern,
+ JSRegExp::Flags flags,
+ Handle<FixedArray> irregexp_data) {
+ Factory::SetRegExpData(re, JSRegExp::IRREGEXP, pattern, flags, irregexp_data);
+ return re;
+}
+
+
static inline Object* DoCompile(String* pattern,
JSRegExp::Flags flags,
unsigned* number_of_captures,
@@ -358,9 +429,13 @@
}
-Handle<Object> RegExpImpl::JsreCompile(Handle<JSRegExp> re,
- Handle<String> pattern,
- JSRegExp::Flags flags) {
+Handle<Object> RegExpImpl::JscreCompile(Handle<JSRegExp> re) {
+ ASSERT_EQ(re->TypeTag(), JSRegExp::JSCRE);
+ ASSERT(re->DataAt(JSRegExp::kJscreDataIndex)->IsUndefined());
+
+ Handle<String> pattern(re->Pattern());
+ JSRegExp::Flags flags = re->GetFlags();
+
Handle<String> two_byte_pattern = StringToTwoByte(pattern);
unsigned number_of_captures;
@@ -391,26 +466,115 @@
Handle<ByteArray> internal(
ByteArray::FromDataStartAddress(reinterpret_cast<Address>(code)));
- Handle<FixedArray> value = Factory::NewFixedArray(2);
- value->set(CAPTURE_INDEX, Smi::FromInt(number_of_captures));
- value->set(INTERNAL_INDEX, *internal);
+ Handle<FixedArray> value = Factory::NewFixedArray(kJscreDataLength);
+ value->set(kJscreNumberOfCapturesIndex, Smi::FromInt(number_of_captures));
+ value->set(kJscreInternalIndex, *internal);
Factory::SetRegExpData(re, JSRegExp::JSCRE, pattern, flags, value);
return re;
}
-Handle<Object> RegExpImpl::JsreExecOnce(Handle<JSRegExp> regexp,
- int num_captures,
- Handle<String> subject,
- int previous_index,
- const uc16* two_byte_subject,
- int* offsets_vector,
- int offsets_vector_length) {
+Handle<Object> RegExpImpl::IrregexpExecOnce(Handle<JSRegExp> regexp,
+ int num_captures,
+ Handle<String> two_byte_subject,
+ int previous_index,
+ int* offsets_vector,
+ int offsets_vector_length) {
+#ifdef DEBUG
+ if (FLAG_trace_regexp_bytecodes) {
+ String* pattern = regexp->Pattern();
+ PrintF("\n\nRegexp match: /%s/\n\n", *(pattern->ToCString()));
+ PrintF("\n\nSubject string: '%s'\n\n", *(two_byte_subject->ToCString()));
+ }
+#endif
+ ASSERT(StringShape(*two_byte_subject).IsTwoByteRepresentation());
+ ASSERT(two_byte_subject->IsFlat(StringShape(*two_byte_subject)));
+ bool rc;
+
+ for (int i = (num_captures + 1) * 2 - 1; i >= 0; i--) {
+ offsets_vector[i] = -1;
+ }
+
+ LOG(RegExpExecEvent(regexp, previous_index, two_byte_subject));
+
+ FixedArray* irregexp =
+ FixedArray::cast(regexp->DataAt(JSRegExp::kIrregexpDataIndex));
+ int tag = Smi::cast(irregexp->get(kIrregexpImplementationIndex))->value();
+
+ switch (tag) {
+ case RegExpMacroAssembler::kIA32Implementation: {
+#ifndef ARM
+ Code* code = Code::cast(irregexp->get(kIrregexpCodeIndex));
+ Address start_addr =
+ Handle<SeqTwoByteString>::cast(two_byte_subject)->GetCharsAddress();
+ int string_offset =
+ start_addr - reinterpret_cast<Address>(*two_byte_subject);
+ int start_offset = string_offset + previous_index * sizeof(uc16);
+ int end_offset =
+ string_offset + two_byte_subject->length() * sizeof(uc16);
+ rc = RegExpMacroAssemblerIA32::Execute(code,
+ two_byte_subject.location(),
+ start_offset,
+ end_offset,
+ offsets_vector,
+ previous_index == 0);
+ if (rc) {
+ // Capture values are relative to start_offset only.
+ for (int i = 0; i < offsets_vector_length; i++) {
+ if (offsets_vector[i] >= 0) {
+ offsets_vector[i] += previous_index;
+ }
+ }
+ }
+ break;
+#else
+ UNIMPLEMENTED();
+ rc = false;
+ break;
+#endif
+ }
+ case RegExpMacroAssembler::kBytecodeImplementation: {
+ Handle<ByteArray> byte_codes = IrregexpCode(regexp);
+
+ rc = IrregexpInterpreter::Match(byte_codes,
+ two_byte_subject,
+ offsets_vector,
+ previous_index);
+ break;
+ }
+ case RegExpMacroAssembler::kARMImplementation:
+ default:
+ UNREACHABLE();
+ rc = false;
+ break;
+ }
+
+ if (!rc) {
+ return Factory::null_value();
+ }
+
+ Handle<FixedArray> array = Factory::NewFixedArray(2 * (num_captures+1));
+ // The captures come in (start, end+1) pairs.
+ for (int i = 0; i < 2 * (num_captures+1); i += 2) {
+ array->set(i, Smi::FromInt(offsets_vector[i]));
+ array->set(i+1, Smi::FromInt(offsets_vector[i+1]));
+ }
+ return Factory::NewJSArrayWithElements(array);
+}
+
+
+Handle<Object> RegExpImpl::JscreExecOnce(Handle<JSRegExp> regexp,
+ int num_captures,
+ Handle<String> subject,
+ int previous_index,
+ const uc16* two_byte_subject,
+ int* offsets_vector,
+ int offsets_vector_length) {
int rc;
{
AssertNoAllocation a;
- ByteArray* internal = JsreInternal(regexp);
+ ByteArray* internal = JscreInternal(regexp);
const v8::jscre::JscreRegExp* js_regexp =
reinterpret_cast<v8::jscre::JscreRegExp*>(
internal->GetDataStartAddress());
@@ -445,12 +609,8 @@
Handle<FixedArray> array = Factory::NewFixedArray(2 * (num_captures+1));
// The captures come in (start, end+1) pairs.
for (int i = 0; i < 2 * (num_captures+1); i += 2) {
- array->set(i,
- Smi::FromInt(offsets_vector[i]),
- SKIP_WRITE_BARRIER);
- array->set(i+1,
- Smi::FromInt(offsets_vector[i+1]),
- SKIP_WRITE_BARRIER);
+ array->set(i, Smi::FromInt(offsets_vector[i]));
+ array->set(i+1, Smi::FromInt(offsets_vector[i+1]));
}
return Factory::NewJSArrayWithElements(array);
}
@@ -458,8 +618,8 @@
class OffsetsVector {
public:
- inline OffsetsVector(int num_captures) {
- offsets_vector_length_ = (num_captures + 1) * 3;
+ inline OffsetsVector(int num_registers)
+ : offsets_vector_length_(num_registers) {
if (offsets_vector_length_ > kStaticOffsetsVectorSize) {
vector_ = NewArray<int>(offsets_vector_length_);
} else {
@@ -488,7 +648,7 @@
private:
int* vector_;
int offsets_vector_length_;
- static const int kStaticOffsetsVectorSize = 30;
+ static const int kStaticOffsetsVectorSize = 50;
static int static_offsets_vector_[kStaticOffsetsVectorSize];
};
@@ -497,33 +657,70 @@
OffsetsVector::kStaticOffsetsVectorSize];
-Handle<Object> RegExpImpl::JsreExec(Handle<JSRegExp> regexp,
- Handle<String> subject,
- Handle<Object> index) {
- // Prepare space for the return values.
- int num_captures = JsreCapture(regexp);
+Handle<Object> RegExpImpl::IrregexpExec(Handle<JSRegExp> regexp,
+ Handle<String> subject,
+ Handle<Object> index) {
+ ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
+ ASSERT(!regexp->DataAt(JSRegExp::kIrregexpDataIndex)->IsUndefined());
- OffsetsVector offsets(num_captures);
+ // Prepare space for the return values.
+ int number_of_registers = IrregexpNumberOfRegisters(regexp);
+ OffsetsVector offsets(number_of_registers);
+
+ int num_captures = IrregexpNumberOfCaptures(regexp);
int previous_index = static_cast<int>(DoubleToInteger(index->Number()));
Handle<String> subject16 = CachedStringToTwoByte(subject);
- Handle<Object> result(JsreExecOnce(regexp, num_captures, subject,
- previous_index,
- subject16->GetTwoByteData(),
- offsets.vector(), offsets.length()));
+ Handle<Object> result(IrregexpExecOnce(regexp,
+ num_captures,
+ subject16,
+ previous_index,
+ offsets.vector(),
+ offsets.length()));
+ return result;
+}
+
+
+Handle<Object> RegExpImpl::JscreExec(Handle<JSRegExp> regexp,
+ Handle<String> subject,
+ Handle<Object> index) {
+ ASSERT_EQ(regexp->TypeTag(), JSRegExp::JSCRE);
+ if (regexp->DataAt(JSRegExp::kJscreDataIndex)->IsUndefined()) {
+ Handle<Object> compile_result = JscreCompile(regexp);
+ if (compile_result.is_null()) return compile_result;
+ }
+ ASSERT(regexp->DataAt(JSRegExp::kJscreDataIndex)->IsFixedArray());
+
+ int num_captures = JscreNumberOfCaptures(regexp);
+
+ OffsetsVector offsets((num_captures + 1) * 3);
+
+ int previous_index = static_cast<int>(DoubleToInteger(index->Number()));
+
+ Handle<String> subject16 = CachedStringToTwoByte(subject);
+
+ Handle<Object> result(JscreExecOnce(regexp,
+ num_captures,
+ subject,
+ previous_index,
+ subject16->GetTwoByteData(),
+ offsets.vector(),
+ offsets.length()));
return result;
}
-Handle<Object> RegExpImpl::JsreExecGlobal(Handle<JSRegExp> regexp,
- Handle<String> subject) {
- // Prepare space for the return values.
- int num_captures = JsreCapture(regexp);
+Handle<Object> RegExpImpl::IrregexpExecGlobal(Handle<JSRegExp> regexp,
+ Handle<String> subject) {
+ ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
+ ASSERT(!regexp->DataAt(JSRegExp::kIrregexpDataIndex)->IsUndefined());
- OffsetsVector offsets(num_captures);
+ // Prepare space for the return values.
+ int number_of_registers = IrregexpNumberOfRegisters(regexp);
+ OffsetsVector offsets(number_of_registers);
int previous_index = 0;
@@ -539,9 +736,12 @@
// string length, there is no match.
matches = Factory::null_value();
} else {
- matches = JsreExecOnce(regexp, num_captures, subject, previous_index,
- subject16->GetTwoByteData(),
- offsets.vector(), offsets.length());
+ matches = IrregexpExecOnce(regexp,
+ IrregexpNumberOfCaptures(regexp),
+ subject16,
+ previous_index,
+ offsets.vector(),
+ offsets.length());
if (matches->IsJSArray()) {
SetElement(result, i, matches);
@@ -555,23 +755,2284 @@
} while (matches->IsJSArray());
// If we exited the loop with an exception, throw it.
- if (matches->IsNull()) { // Exited loop normally.
+ if (matches->IsNull()) {
+ // Exited loop normally.
return result;
- } else { // Exited loop with the exception in matches.
+ } else {
+ // Exited loop with the exception in matches.
return matches;
}
}
-int RegExpImpl::JsreCapture(Handle<JSRegExp> re) {
- FixedArray* value = FixedArray::cast(re->DataAt(JSRegExp::kJscreDataIndex));
- return Smi::cast(value->get(CAPTURE_INDEX))->value();
+Handle<Object> RegExpImpl::JscreExecGlobal(Handle<JSRegExp> regexp,
+ Handle<String> subject) {
+ ASSERT_EQ(regexp->TypeTag(), JSRegExp::JSCRE);
+ if (regexp->DataAt(JSRegExp::kJscreDataIndex)->IsUndefined()) {
+ Handle<Object> compile_result = JscreCompile(regexp);
+ if (compile_result.is_null()) return compile_result;
+ }
+ ASSERT(regexp->DataAt(JSRegExp::kJscreDataIndex)->IsFixedArray());
+
+ // Prepare space for the return values.
+ int num_captures = JscreNumberOfCaptures(regexp);
+
+ OffsetsVector offsets((num_captures + 1) * 3);
+
+ int previous_index = 0;
+
+ Handle<JSArray> result = Factory::NewJSArray(0);
+ int i = 0;
+ Handle<Object> matches;
+
+ Handle<String> subject16 = CachedStringToTwoByte(subject);
+
+ do {
+ if (previous_index > subject->length() || previous_index < 0) {
+ // Per ECMA-262 15.10.6.2, if the previous index is greater than the
+ // string length, there is no match.
+ matches = Factory::null_value();
+ } else {
+ matches = JscreExecOnce(regexp,
+ num_captures,
+ subject,
+ previous_index,
+ subject16->GetTwoByteData(),
+ offsets.vector(),
+ offsets.length());
+
+ if (matches->IsJSArray()) {
+ SetElement(result, i, matches);
+ i++;
+ previous_index = offsets.vector()[1];
+ if (offsets.vector()[0] == offsets.vector()[1]) {
+ previous_index++;
+ }
+ }
+ }
+ } while (matches->IsJSArray());
+
+ // If we exited the loop with an exception, throw it.
+ if (matches->IsNull()) {
+ // Exited loop normally.
+ return result;
+ } else {
+ // Exited loop with the exception in matches.
+ return matches;
+ }
}
-ByteArray* RegExpImpl::JsreInternal(Handle<JSRegExp> re) {
+int RegExpImpl::JscreNumberOfCaptures(Handle<JSRegExp> re) {
FixedArray* value = FixedArray::cast(re->DataAt(JSRegExp::kJscreDataIndex));
- return ByteArray::cast(value->get(INTERNAL_INDEX));
+ return Smi::cast(value->get(kJscreNumberOfCapturesIndex))->value();
}
+
+ByteArray* RegExpImpl::JscreInternal(Handle<JSRegExp> re) {
+ FixedArray* value = FixedArray::cast(re->DataAt(JSRegExp::kJscreDataIndex));
+ return ByteArray::cast(value->get(kJscreInternalIndex));
+}
+
+
+int RegExpImpl::IrregexpNumberOfCaptures(Handle<JSRegExp> re) {
+ FixedArray* value =
+ FixedArray::cast(re->DataAt(JSRegExp::kIrregexpDataIndex));
+ return Smi::cast(value->get(kIrregexpNumberOfCapturesIndex))->value();
+}
+
+
+int RegExpImpl::IrregexpNumberOfRegisters(Handle<JSRegExp> re) {
+ FixedArray* value =
+ FixedArray::cast(re->DataAt(JSRegExp::kIrregexpDataIndex));
+ return Smi::cast(value->get(kIrregexpNumberOfRegistersIndex))->value();
+}
+
+
+Handle<ByteArray> RegExpImpl::IrregexpCode(Handle<JSRegExp> re) {
+ FixedArray* value =
+ FixedArray::cast(re->DataAt(JSRegExp::kIrregexpDataIndex));
+ return Handle<ByteArray>(ByteArray::cast(value->get(kIrregexpCodeIndex)));
+}
+
+
+// -------------------------------------------------------------------
+// Implmentation of the Irregexp regular expression engine.
+
+
+void RegExpTree::AppendToText(RegExpText* text) {
+ UNREACHABLE();
+}
+
+
+void RegExpAtom::AppendToText(RegExpText* text) {
+ text->AddElement(TextElement::Atom(this));
+}
+
+
+void RegExpCharacterClass::AppendToText(RegExpText* text) {
+ text->AddElement(TextElement::CharClass(this));
+}
+
+
+void RegExpText::AppendToText(RegExpText* text) {
+ for (int i = 0; i < elements()->length(); i++)
+ text->AddElement(elements()->at(i));
+}
+
+
+TextElement TextElement::Atom(RegExpAtom* atom) {
+ TextElement result = TextElement(ATOM);
+ result.data.u_atom = atom;
+ return result;
+}
+
+
+TextElement TextElement::CharClass(
+ RegExpCharacterClass* char_class) {
+ TextElement result = TextElement(CHAR_CLASS);
+ result.data.u_char_class = char_class;
+ return result;
+}
+
+
+DispatchTable* ChoiceNode::GetTable(bool ignore_case) {
+ if (table_ == NULL) {
+ table_ = new DispatchTable();
+ DispatchTableConstructor cons(table_, ignore_case);
+ cons.BuildTable(this);
+ }
+ return table_;
+}
+
+
+class RegExpCompiler {
+ public:
+ RegExpCompiler(int capture_count, bool ignore_case);
+
+ int AllocateRegister() { return next_register_++; }
+
+ Handle<FixedArray> Assemble(RegExpMacroAssembler* assembler,
+ RegExpNode* start,
+ int capture_count);
+
+ inline void AddWork(RegExpNode* node) { work_list_->Add(node); }
+
+ static const int kImplementationOffset = 0;
+ static const int kNumberOfRegistersOffset = 0;
+ static const int kCodeOffset = 1;
+
+ RegExpMacroAssembler* macro_assembler() { return macro_assembler_; }
+ EndNode* accept() { return accept_; }
+ EndNode* backtrack() { return backtrack_; }
+
+ static const int kMaxRecursion = 100;
+ inline int recursion_depth() { return recursion_depth_; }
+ inline void IncrementRecursionDepth() { recursion_depth_++; }
+ inline void DecrementRecursionDepth() { recursion_depth_--; }
+
+ inline bool ignore_case() { return ignore_case_; }
+
+ private:
+ EndNode* accept_;
+ EndNode* backtrack_;
+ int next_register_;
+ List<RegExpNode*>* work_list_;
+ int recursion_depth_;
+ RegExpMacroAssembler* macro_assembler_;
+ bool ignore_case_;
+};
+
+
+// Attempts to compile the regexp using an Irregexp code generator. Returns
+// a fixed array or a null handle depending on whether it succeeded.
+RegExpCompiler::RegExpCompiler(int capture_count, bool ignore_case)
+ : next_register_(2 * (capture_count + 1)),
+ work_list_(NULL),
+ recursion_depth_(0),
+ ignore_case_(ignore_case) {
+ accept_ = new EndNode(EndNode::ACCEPT);
+ backtrack_ = new EndNode(EndNode::BACKTRACK);
+}
+
+
+Handle<FixedArray> RegExpCompiler::Assemble(
+ RegExpMacroAssembler* macro_assembler,
+ RegExpNode* start,
+ int capture_count) {
+#ifdef DEBUG
+ if (FLAG_trace_regexp_assembler)
+ macro_assembler_ = new RegExpMacroAssemblerTracer(macro_assembler);
+ else
+#endif
+ macro_assembler_ = macro_assembler;
+ List <RegExpNode*> work_list(0);
+ work_list_ = &work_list;
+ Label fail;
+ macro_assembler_->PushBacktrack(&fail);
+ if (!start->GoTo(this)) {
+ fail.Unuse();
+ return Handle<FixedArray>::null();
+ }
+ while (!work_list.is_empty()) {
+ if (!work_list.RemoveLast()->GoTo(this)) {
+ fail.Unuse();
+ return Handle<FixedArray>::null();
+ }
+ }
+ macro_assembler_->Bind(&fail);
+ macro_assembler_->Fail();
+ Handle<FixedArray> array =
+ Factory::NewFixedArray(RegExpImpl::kIrregexpDataLength);
+ array->set(RegExpImpl::kIrregexpImplementationIndex,
+ Smi::FromInt(macro_assembler_->Implementation()));
+ array->set(RegExpImpl::kIrregexpNumberOfRegistersIndex,
+ Smi::FromInt(next_register_));
+ array->set(RegExpImpl::kIrregexpNumberOfCapturesIndex,
+ Smi::FromInt(capture_count));
+ Handle<Object> code = macro_assembler_->GetCode();
+ array->set(RegExpImpl::kIrregexpCodeIndex, *code);
+ work_list_ = NULL;
+#ifdef DEBUG
+ if (FLAG_trace_regexp_assembler) {
+ delete macro_assembler_;
+ }
+#endif
+ return array;
+}
+
+
+bool RegExpNode::GoTo(RegExpCompiler* compiler) {
+ // TODO(erikcorry): Implement support.
+ if (info_.follows_word_interest ||
+ info_.follows_newline_interest ||
+ info_.follows_start_interest) {
+ return false;
+ }
+ if (label_.is_bound()) {
+ compiler->macro_assembler()->GoTo(&label_);
+ return true;
+ } else {
+ if (compiler->recursion_depth() > RegExpCompiler::kMaxRecursion) {
+ compiler->macro_assembler()->GoTo(&label_);
+ compiler->AddWork(this);
+ return true;
+ } else {
+ compiler->IncrementRecursionDepth();
+ bool how_it_went = Emit(compiler);
+ compiler->DecrementRecursionDepth();
+ return how_it_went;
+ }
+ }
+}
+
+
+// EndNodes are special. Because they can be very common and they are very
+// short we normally inline them. That is, if we are asked to emit a GoTo
+// we just emit the entire node. Since they don't have successors this
+// works.
+bool EndNode::GoTo(RegExpCompiler* compiler) {
+ if (info()->follows_word_interest ||
+ info()->follows_newline_interest ||
+ info()->follows_start_interest) {
+ return false;
+ }
+ return Emit(compiler);
+}
+
+
+Label* RegExpNode::label() {
+ return &label_;
+}
+
+
+bool EndNode::Emit(RegExpCompiler* compiler) {
+ RegExpMacroAssembler* macro = compiler->macro_assembler();
+ switch (action_) {
+ case ACCEPT:
+ if (!label()->is_bound()) Bind(macro);
+ if (info()->at_end) {
+ Label succeed;
+ // LoadCurrentCharacter will go to the label if we are at the end of the
+ // input string.
+ macro->LoadCurrentCharacter(0, &succeed);
+ macro->Backtrack();
+ macro->Bind(&succeed);
+ }
+ macro->Succeed();
+ return true;
+ case BACKTRACK:
+ if (!label()->is_bound()) Bind(macro);
+ ASSERT(!info()->at_end);
+ macro->Backtrack();
+ return true;
+ }
+ return false;
+}
+
+
+void GuardedAlternative::AddGuard(Guard* guard) {
+ if (guards_ == NULL)
+ guards_ = new ZoneList<Guard*>(1);
+ guards_->Add(guard);
+}
+
+
+ActionNode* ActionNode::StoreRegister(int reg,
+ int val,
+ RegExpNode* on_success) {
+ ActionNode* result = new ActionNode(STORE_REGISTER, on_success);
+ result->data_.u_store_register.reg = reg;
+ result->data_.u_store_register.value = val;
+ return result;
+}
+
+
+ActionNode* ActionNode::IncrementRegister(int reg, RegExpNode* on_success) {
+ ActionNode* result = new ActionNode(INCREMENT_REGISTER, on_success);
+ result->data_.u_increment_register.reg = reg;
+ return result;
+}
+
+
+ActionNode* ActionNode::StorePosition(int reg, RegExpNode* on_success) {
+ ActionNode* result = new ActionNode(STORE_POSITION, on_success);
+ result->data_.u_position_register.reg = reg;
+ return result;
+}
+
+
+ActionNode* ActionNode::RestorePosition(int reg, RegExpNode* on_success) {
+ ActionNode* result = new ActionNode(RESTORE_POSITION, on_success);
+ result->data_.u_position_register.reg = reg;
+ return result;
+}
+
+
+ActionNode* ActionNode::BeginSubmatch(int stack_reg,
+ int position_reg,
+ RegExpNode* on_success) {
+ ActionNode* result = new ActionNode(BEGIN_SUBMATCH, on_success);
+ result->data_.u_submatch.stack_pointer_register = stack_reg;
+ result->data_.u_submatch.current_position_register = position_reg;
+ return result;
+}
+
+
+ActionNode* ActionNode::EscapeSubmatch(int stack_reg,
+ bool restore_position,
+ int position_reg,
+ RegExpNode* on_success) {
+ ActionNode* result = new ActionNode(ESCAPE_SUBMATCH, on_success);
+ result->data_.u_submatch.stack_pointer_register = stack_reg;
+ if (restore_position) {
+ result->data_.u_submatch.current_position_register = position_reg;
+ } else {
+ result->data_.u_submatch.current_position_register = -1;
+ }
+ return result;
+}
+
+
+#define DEFINE_ACCEPT(Type) \
+ void Type##Node::Accept(NodeVisitor* visitor) { \
+ visitor->Visit##Type(this); \
+ }
+FOR_EACH_NODE_TYPE(DEFINE_ACCEPT)
+#undef DEFINE_ACCEPT
+
+
+// -------------------------------------------------------------------
+// Emit code.
+
+
+void ChoiceNode::GenerateGuard(RegExpMacroAssembler* macro_assembler,
+ Guard* guard,
+ Label* on_failure) {
+ switch (guard->op()) {
+ case Guard::LT:
+ macro_assembler->IfRegisterGE(guard->reg(), guard->value(), on_failure);
+ break;
+ case Guard::GEQ:
+ macro_assembler->IfRegisterLT(guard->reg(), guard->value(), on_failure);
+ break;
+ }
+}
+
+
+static unibrow::Mapping<unibrow::Ecma262UnCanonicalize> uncanonicalize;
+static unibrow::Mapping<unibrow::CanonicalizationRange> canonrange;
+
+
+static inline void EmitAtomNonLetters(
+ RegExpMacroAssembler* macro_assembler,
+ TextElement elm,
+ Vector<const uc16> quarks,
+ Label* on_failure,
+ int cp_offset) {
+ unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth];
+ for (int i = quarks.length() - 1; i >= 0; i--) {
+ uc16 c = quarks[i];
+ int length = uncanonicalize.get(c, '\0', chars);
+ if (length <= 1) {
+ macro_assembler->LoadCurrentCharacter(cp_offset + i, on_failure);
+ macro_assembler->CheckNotCharacter(c, on_failure);
+ }
+ }
+}
+
+
+static bool ShortCutEmitCharacterPair(RegExpMacroAssembler* macro_assembler,
+ uc16 c1,
+ uc16 c2,
+ Label* on_failure) {
+ uc16 exor = c1 ^ c2;
+ // Check whether exor has only one bit set.
+ if (((exor - 1) & exor) == 0) {
+ // If c1 and c2 differ only by one bit.
+ // Ecma262UnCanonicalize always gives the highest number last.
+ ASSERT(c2 > c1);
+ macro_assembler->CheckNotCharacterAfterOr(c2, exor, on_failure);
+ return true;
+ }
+ ASSERT(c2 > c1);
+ uc16 diff = c2 - c1;
+ if (((diff - 1) & diff) == 0 && c1 >= diff) {
+ // If the characters differ by 2^n but don't differ by one bit then
+ // subtract the difference from the found character, then do the or
+ // trick. We avoid the theoretical case where negative numbers are
+ // involved in order to simplify code generation.
+ macro_assembler->CheckNotCharacterAfterMinusOr(c2 - diff,
+ diff,
+ on_failure);
+ return true;
+ }
+ return false;
+}
+
+
+static inline void EmitAtomLetters(
+ RegExpMacroAssembler* macro_assembler,
+ TextElement elm,
+ Vector<const uc16> quarks,
+ Label* on_failure,
+ int cp_offset) {
+ unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth];
+ for (int i = quarks.length() - 1; i >= 0; i--) {
+ uc16 c = quarks[i];
+ int length = uncanonicalize.get(c, '\0', chars);
+ if (length <= 1) continue;
+ macro_assembler->LoadCurrentCharacter(cp_offset + i, on_failure);
+ Label ok;
+ ASSERT(unibrow::Ecma262UnCanonicalize::kMaxWidth == 4);
+ switch (length) {
+ case 2: {
+ if (ShortCutEmitCharacterPair(macro_assembler,
+ chars[0],
+ chars[1],
+ on_failure)) {
+ ok.Unuse();
+ } else {
+ macro_assembler->CheckCharacter(chars[0], &ok);
+ macro_assembler->CheckNotCharacter(chars[1], on_failure);
+ macro_assembler->Bind(&ok);
+ }
+ break;
+ }
+ case 4:
+ macro_assembler->CheckCharacter(chars[3], &ok);
+ // Fall through!
+ case 3:
+ macro_assembler->CheckCharacter(chars[0], &ok);
+ macro_assembler->CheckCharacter(chars[1], &ok);
+ macro_assembler->CheckNotCharacter(chars[2], on_failure);
+ macro_assembler->Bind(&ok);
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+}
+
+
+static void EmitCharClass(RegExpMacroAssembler* macro_assembler,
+ RegExpCharacterClass* cc,
+ int cp_offset,
+ Label* on_failure) {
+ macro_assembler->LoadCurrentCharacter(cp_offset, on_failure);
+ cp_offset++;
+
+ ZoneList<CharacterRange>* ranges = cc->ranges();
+
+ Label success;
+
+ Label* char_is_in_class =
+ cc->is_negated() ? on_failure : &success;
+
+ int range_count = ranges->length();
+
+ if (range_count == 0) {
+ if (!cc->is_negated()) {
+ macro_assembler->GoTo(on_failure);
+ }
+ return;
+ }
+
+ for (int i = 0; i < range_count - 1; i++) {
+ CharacterRange& range = ranges->at(i);
+ Label next_range;
+ uc16 from = range.from();
+ uc16 to = range.to();
+ if (to == from) {
+ macro_assembler->CheckCharacter(to, char_is_in_class);
+ } else {
+ if (from != 0) {
+ macro_assembler->CheckCharacterLT(from, &next_range);
+ }
+ if (to != 0xffff) {
+ macro_assembler->CheckCharacterLT(to + 1, char_is_in_class);
+ } else {
+ macro_assembler->GoTo(char_is_in_class);
+ }
+ }
+ macro_assembler->Bind(&next_range);
+ }
+
+ CharacterRange& range = ranges->at(range_count - 1);
+ uc16 from = range.from();
+ uc16 to = range.to();
+
+ if (to == from) {
+ if (cc->is_negated()) {
+ macro_assembler->CheckCharacter(to, on_failure);
+ } else {
+ macro_assembler->CheckNotCharacter(to, on_failure);
+ }
+ } else {
+ if (from != 0) {
+ if (cc->is_negated()) {
+ macro_assembler->CheckCharacterLT(from, &success);
+ } else {
+ macro_assembler->CheckCharacterLT(from, on_failure);
+ }
+ }
+ if (to != 0xffff) {
+ if (cc->is_negated()) {
+ macro_assembler->CheckCharacterLT(to + 1, on_failure);
+ } else {
+ macro_assembler->CheckCharacterGT(to, on_failure);
+ }
+ } else {
+ if (cc->is_negated()) {
+ macro_assembler->GoTo(on_failure);
+ }
+ }
+ }
+ macro_assembler->Bind(&success);
+}
+
+
+
+bool TextNode::Emit(RegExpCompiler* compiler) {
+ RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
+ Bind(macro_assembler);
+ int element_count = elms_->length();
+ ASSERT(element_count != 0);
+ int cp_offset = 0;
+ if (info()->at_end) {
+ macro_assembler->Backtrack();
+ return true;
+ }
+ // First, handle straight character matches.
+ for (int i = 0; i < element_count; i++) {
+ TextElement elm = elms_->at(i);
+ if (elm.type == TextElement::ATOM) {
+ Vector<const uc16> quarks = elm.data.u_atom->data();
+ if (compiler->ignore_case()) {
+ EmitAtomNonLetters(macro_assembler,
+ elm,
+ quarks,
+ on_failure_->label(),
+ cp_offset);
+ } else {
+ macro_assembler->CheckCharacters(quarks,
+ cp_offset,
+ on_failure_->label());
+ }
+ cp_offset += quarks.length();
+ } else {
+ ASSERT_EQ(elm.type, TextElement::CHAR_CLASS);
+ cp_offset++;
+ }
+ }
+ // Second, handle case independent letter matches if any.
+ if (compiler->ignore_case()) {
+ cp_offset = 0;
+ for (int i = 0; i < element_count; i++) {
+ TextElement elm = elms_->at(i);
+ if (elm.type == TextElement::ATOM) {
+ Vector<const uc16> quarks = elm.data.u_atom->data();
+ EmitAtomLetters(macro_assembler,
+ elm,
+ quarks,
+ on_failure_->label(),
+ cp_offset);
+ cp_offset += quarks.length();
+ } else {
+ cp_offset++;
+ }
+ }
+ }
+ // If the fast character matches passed then do the character classes.
+ cp_offset = 0;
+ for (int i = 0; i < element_count; i++) {
+ TextElement elm = elms_->at(i);
+ if (elm.type == TextElement::CHAR_CLASS) {
+ RegExpCharacterClass* cc = elm.data.u_char_class;
+ EmitCharClass(macro_assembler, cc, cp_offset, on_failure_->label());
+ cp_offset++;
+ } else {
+ cp_offset += elm.data.u_atom->data().length();
+ }
+ }
+
+ compiler->AddWork(on_failure_);
+ macro_assembler->AdvanceCurrentPosition(cp_offset);
+ return on_success()->GoTo(compiler);
+}
+
+
+void TextNode::MakeCaseIndependent() {
+ int element_count = elms_->length();
+ for (int i = 0; i < element_count; i++) {
+ TextElement elm = elms_->at(i);
+ if (elm.type == TextElement::CHAR_CLASS) {
+ RegExpCharacterClass* cc = elm.data.u_char_class;
+ ZoneList<CharacterRange>* ranges = cc->ranges();
+ int range_count = ranges->length();
+ for (int i = 0; i < range_count; i++) {
+ ranges->at(i).AddCaseEquivalents(ranges);
+ }
+ }
+ }
+}
+
+
+bool ChoiceNode::Emit(RegExpCompiler* compiler) {
+ int choice_count = alternatives_->length();
+ RegExpMacroAssembler* macro_assembler = compiler->macro_assembler();
+ Bind(macro_assembler);
+ // For now we just call all choices one after the other. The idea ultimately
+ // is to use the Dispatch table to try only the relevant ones.
+ for (int i = 0; i < choice_count - 1; i++) {
+ GuardedAlternative alternative = alternatives_->at(i);
+ Label after;
+ Label after_no_pop_cp;
+ ZoneList<Guard*>* guards = alternative.guards();
+ if (guards != NULL) {
+ int guard_count = guards->length();
+ for (int j = 0; j < guard_count; j++) {
+ GenerateGuard(macro_assembler, guards->at(j), &after_no_pop_cp);
+ }
+ }
+ macro_assembler->PushCurrentPosition();
+ macro_assembler->PushBacktrack(&after);
+ if (!alternative.node()->GoTo(compiler)) {
+ after.Unuse();
+ after_no_pop_cp.Unuse();
+ return false;
+ }
+ macro_assembler->Bind(&after);
+ macro_assembler->PopCurrentPosition();
+ macro_assembler->Bind(&after_no_pop_cp);
+ }
+ GuardedAlternative alternative = alternatives_->at(choice_count - 1);
+ ZoneList<Guard*>* guards = alternative.guards();
+ if (guards != NULL) {
+ int guard_count = guards->length();
+ for (int j = 0; j < guard_count; j++) {
+ GenerateGuard(macro_assembler, guards->at(j), on_failure_->label());
+ }
+ }
+ if (!on_failure_->IsBacktrack()) {
+ ASSERT_NOT_NULL(on_failure_ -> label());
+ macro_assembler->PushBacktrack(on_failure_->label());
+ compiler->AddWork(on_failure_);
+ }
+ if (!alternative.node()->GoTo(compiler)) {
+ return false;
+ }
+ return true;
+}
+
+
+bool ActionNode::Emit(RegExpCompiler* compiler) {
+ RegExpMacroAssembler* macro = compiler->macro_assembler();
+ Bind(macro);
+ switch (type_) {
+ case STORE_REGISTER:
+ macro->SetRegister(data_.u_store_register.reg,
+ data_.u_store_register.value);
+ break;
+ case INCREMENT_REGISTER: {
+ Label undo;
+ macro->PushBacktrack(&undo);
+ macro->AdvanceRegister(data_.u_increment_register.reg, 1);
+ bool ok = on_success()->GoTo(compiler);
+ if (!ok) {
+ undo.Unuse();
+ return false;
+ }
+ macro->Bind(&undo);
+ macro->AdvanceRegister(data_.u_increment_register.reg, -1);
+ macro->Backtrack();
+ break;
+ }
+ case STORE_POSITION: {
+ Label undo;
+ macro->PushRegister(data_.u_position_register.reg);
+ macro->PushBacktrack(&undo);
+ macro->WriteCurrentPositionToRegister(data_.u_position_register.reg);
+ bool ok = on_success()->GoTo(compiler);
+ if (!ok) {
+ undo.Unuse();
+ return false;
+ }
+ macro->Bind(&undo);
+ macro->PopRegister(data_.u_position_register.reg);
+ macro->Backtrack();
+ break;
+ }
+ case RESTORE_POSITION:
+ macro->ReadCurrentPositionFromRegister(
+ data_.u_position_register.reg);
+ break;
+ case BEGIN_SUBMATCH:
+ macro->WriteCurrentPositionToRegister(
+ data_.u_submatch.current_position_register);
+ macro->WriteStackPointerToRegister(
+ data_.u_submatch.stack_pointer_register);
+ break;
+ case ESCAPE_SUBMATCH:
+ if (info()->at_end) {
+ Label at_end;
+ // Load current character jumps to the label if we are beyond the string
+ // end.
+ macro->LoadCurrentCharacter(0, &at_end);
+ macro->Backtrack();
+ macro->Bind(&at_end);
+ }
+ if (data_.u_submatch.current_position_register != -1) {
+ macro->ReadCurrentPositionFromRegister(
+ data_.u_submatch.current_position_register);
+ }
+ macro->ReadStackPointerFromRegister(
+ data_.u_submatch.stack_pointer_register);
+ break;
+ default:
+ UNREACHABLE();
+ return false;
+ }
+ return on_success()->GoTo(compiler);
+}
+
+
+bool BackReferenceNode::Emit(RegExpCompiler* compiler) {
+ RegExpMacroAssembler* macro = compiler->macro_assembler();
+ Bind(macro);
+ ASSERT_EQ(start_reg_ + 1, end_reg_);
+ if (info()->at_end) {
+ // If we are constrained to match at the end of the input then succeed
+ // iff the back reference is empty.
+ macro->CheckNotRegistersEqual(start_reg_, end_reg_, on_failure_->label());
+ } else {
+ if (compiler->ignore_case()) {
+ macro->CheckNotBackReferenceIgnoreCase(start_reg_, on_failure_->label());
+ } else {
+ macro->CheckNotBackReference(start_reg_, on_failure_->label());
+ }
+ }
+ return on_success()->GoTo(compiler);
+}
+
+
+// -------------------------------------------------------------------
+// Dot/dotty output
+
+
+#ifdef DEBUG
+
+
+class DotPrinter: public NodeVisitor {
+ public:
+ explicit DotPrinter(bool ignore_case)
+ : ignore_case_(ignore_case),
+ stream_(&alloc_) { }
+ void PrintNode(const char* label, RegExpNode* node);
+ void Visit(RegExpNode* node);
+ void PrintOnFailure(RegExpNode* from, RegExpNode* on_failure);
+ void PrintAttributes(RegExpNode* from);
+ StringStream* stream() { return &stream_; }
+#define DECLARE_VISIT(Type) \
+ virtual void Visit##Type(Type##Node* that);
+FOR_EACH_NODE_TYPE(DECLARE_VISIT)
+#undef DECLARE_VISIT
+ private:
+ bool ignore_case_;
+ HeapStringAllocator alloc_;
+ StringStream stream_;
+};
+
+
+void DotPrinter::PrintNode(const char* label, RegExpNode* node) {
+ stream()->Add("digraph G {\n graph [label=\"");
+ for (int i = 0; label[i]; i++) {
+ switch (label[i]) {
+ case '\\':
+ stream()->Add("\\\\");
+ break;
+ case '"':
+ stream()->Add("\"");
+ break;
+ default:
+ stream()->Put(label[i]);
+ break;
+ }
+ }
+ stream()->Add("\"];\n");
+ Visit(node);
+ stream()->Add("}\n");
+ printf("%s", *(stream()->ToCString()));
+}
+
+
+void DotPrinter::Visit(RegExpNode* node) {
+ if (node->info()->visited) return;
+ node->info()->visited = true;
+ node->Accept(this);
+}
+
+
+void DotPrinter::PrintOnFailure(RegExpNode* from, RegExpNode* on_failure) {
+ if (on_failure->IsBacktrack()) return;
+ stream()->Add(" n%p -> n%p [style=dotted];\n", from, on_failure);
+ Visit(on_failure);
+}
+
+
+class TableEntryBodyPrinter {
+ public:
+ TableEntryBodyPrinter(StringStream* stream, ChoiceNode* choice)
+ : stream_(stream), choice_(choice) { }
+ void Call(uc16 from, DispatchTable::Entry entry) {
+ OutSet* out_set = entry.out_set();
+ for (unsigned i = 0; i < OutSet::kFirstLimit; i++) {
+ if (out_set->Get(i)) {
+ stream()->Add(" n%p:s%io%i -> n%p;\n",
+ choice(),
+ from,
+ i,
+ choice()->alternatives()->at(i).node());
+ }
+ }
+ }
+ private:
+ StringStream* stream() { return stream_; }
+ ChoiceNode* choice() { return choice_; }
+ StringStream* stream_;
+ ChoiceNode* choice_;
+};
+
+
+class TableEntryHeaderPrinter {
+ public:
+ explicit TableEntryHeaderPrinter(StringStream* stream)
+ : first_(true), stream_(stream) { }
+ void Call(uc16 from, DispatchTable::Entry entry) {
+ if (first_) {
+ first_ = false;
+ } else {
+ stream()->Add("|");
+ }
+ stream()->Add("{\\%k-\\%k|{", from, entry.to());
+ OutSet* out_set = entry.out_set();
+ int priority = 0;
+ for (unsigned i = 0; i < OutSet::kFirstLimit; i++) {
+ if (out_set->Get(i)) {
+ if (priority > 0) stream()->Add("|");
+ stream()->Add("<s%io%i> %i", from, i, priority);
+ priority++;
+ }
+ }
+ stream()->Add("}}");
+ }
+ private:
+ bool first_;
+ StringStream* stream() { return stream_; }
+ StringStream* stream_;
+};
+
+
+class AttributePrinter {
+ public:
+ explicit AttributePrinter(DotPrinter* out)
+ : out_(out), first_(true) { }
+ void PrintSeparator() {
+ if (first_) {
+ first_ = false;
+ } else {
+ out_->stream()->Add("|");
+ }
+ }
+ void PrintBit(const char* name, bool value) {
+ if (!value) return;
+ PrintSeparator();
+ out_->stream()->Add("{%s}", name);
+ }
+ void PrintPositive(const char* name, int value) {
+ if (value < 0) return;
+ PrintSeparator();
+ out_->stream()->Add("{%s|%x}", name, value);
+ }
+ private:
+ DotPrinter* out_;
+ bool first_;
+};
+
+
+void DotPrinter::PrintAttributes(RegExpNode* that) {
+ stream()->Add(" a%p [shape=Mrecord, color=grey, fontcolor=grey, "
+ "margin=0.1, fontsize=10, label=\"{",
+ that);
+ AttributePrinter printer(this);
+ NodeInfo* info = that->info();
+ printer.PrintBit("NI", info->follows_newline_interest);
+ printer.PrintBit("WI", info->follows_word_interest);
+ printer.PrintBit("SI", info->follows_start_interest);
+ printer.PrintBit("DN", info->determine_newline);
+ printer.PrintBit("DW", info->determine_word);
+ printer.PrintBit("DS", info->determine_start);
+ printer.PrintBit("DDN", info->does_determine_newline);
+ printer.PrintBit("DDW", info->does_determine_word);
+ printer.PrintBit("DDS", info->does_determine_start);
+ printer.PrintPositive("IW", info->is_word);
+ printer.PrintPositive("IN", info->is_newline);
+ printer.PrintPositive("FN", info->follows_newline);
+ printer.PrintPositive("FW", info->follows_word);
+ printer.PrintPositive("FS", info->follows_start);
+ Label* label = that->label();
+ if (label->is_bound())
+ printer.PrintPositive("@", label->pos());
+ stream()->Add("}\"];\n");
+ stream()->Add(" a%p -> n%p [style=dashed, color=grey, "
+ "arrowhead=none];\n", that, that);
+}
+
+
+static const bool kPrintDispatchTable = false;
+void DotPrinter::VisitChoice(ChoiceNode* that) {
+ if (kPrintDispatchTable) {
+ stream()->Add(" n%p [shape=Mrecord, label=\"", that);
+ TableEntryHeaderPrinter header_printer(stream());
+ that->GetTable(ignore_case_)->ForEach(&header_printer);
+ stream()->Add("\"]\n", that);
+ PrintAttributes(that);
+ TableEntryBodyPrinter body_printer(stream(), that);
+ that->GetTable(ignore_case_)->ForEach(&body_printer);
+ PrintOnFailure(that, that->on_failure());
+ } else {
+ stream()->Add(" n%p [shape=Mrecord, label=\"?\"];\n", that);
+ for (int i = 0; i < that->alternatives()->length(); i++) {
+ GuardedAlternative alt = that->alternatives()->at(i);
+ stream()->Add(" n%p -> n%p;\n", that, alt.node());
+ }
+ }
+ for (int i = 0; i < that->alternatives()->length(); i++) {
+ GuardedAlternative alt = that->alternatives()->at(i);
+ alt.node()->Accept(this);
+ }
+}
+
+
+void DotPrinter::VisitText(TextNode* that) {
+ stream()->Add(" n%p [label=\"", that);
+ for (int i = 0; i < that->elements()->length(); i++) {
+ if (i > 0) stream()->Add(" ");
+ TextElement elm = that->elements()->at(i);
+ switch (elm.type) {
+ case TextElement::ATOM: {
+ stream()->Add("'%w'", elm.data.u_atom->data());
+ break;
+ }
+ case TextElement::CHAR_CLASS: {
+ RegExpCharacterClass* node = elm.data.u_char_class;
+ stream()->Add("[");
+ if (node->is_negated())
+ stream()->Add("^");
+ for (int j = 0; j < node->ranges()->length(); j++) {
+ CharacterRange range = node->ranges()->at(j);
+ stream()->Add("%k-%k", range.from(), range.to());
+ }
+ stream()->Add("]");
+ break;
+ }
+ default:
+ UNREACHABLE();
+ }
+ }
+ stream()->Add("\", shape=box, peripheries=2];\n");
+ PrintAttributes(that);
+ stream()->Add(" n%p -> n%p;\n", that, that->on_success());
+ Visit(that->on_success());
+ PrintOnFailure(that, that->on_failure());
+}
+
+
+void DotPrinter::VisitBackReference(BackReferenceNode* that) {
+ stream()->Add(" n%p [label=\"$%i..$%i\", shape=doubleoctagon];\n",
+ that,
+ that->start_register(),
+ that->end_register());
+ PrintAttributes(that);
+ stream()->Add(" n%p -> n%p;\n", that, that->on_success());
+ Visit(that->on_success());
+ PrintOnFailure(that, that->on_failure());
+}
+
+
+void DotPrinter::VisitEnd(EndNode* that) {
+ stream()->Add(" n%p [style=bold, shape=point];\n", that);
+ PrintAttributes(that);
+}
+
+
+void DotPrinter::VisitAction(ActionNode* that) {
+ stream()->Add(" n%p [", that);
+ switch (that->type_) {
+ case ActionNode::STORE_REGISTER:
+ stream()->Add("label=\"$%i:=%i\", shape=octagon",
+ that->data_.u_store_register.reg,
+ that->data_.u_store_register.value);
+ break;
+ case ActionNode::INCREMENT_REGISTER:
+ stream()->Add("label=\"$%i++\", shape=octagon",
+ that->data_.u_increment_register.reg);
+ break;
+ case ActionNode::STORE_POSITION:
+ stream()->Add("label=\"$%i:=$pos\", shape=octagon",
+ that->data_.u_position_register.reg);
+ break;
+ case ActionNode::RESTORE_POSITION:
+ stream()->Add("label=\"$pos:=$%i\", shape=octagon",
+ that->data_.u_position_register.reg);
+ break;
+ case ActionNode::BEGIN_SUBMATCH:
+ stream()->Add("label=\"$%i:=$pos,begin\", shape=septagon",
+ that->data_.u_submatch.current_position_register);
+ break;
+ case ActionNode::ESCAPE_SUBMATCH:
+ stream()->Add("label=\"escape\", shape=septagon");
+ break;
+ }
+ stream()->Add("];\n");
+ PrintAttributes(that);
+ stream()->Add(" n%p -> n%p;\n", that, that->on_success());
+ Visit(that->on_success());
+}
+
+
+class DispatchTableDumper {
+ public:
+ explicit DispatchTableDumper(StringStream* stream) : stream_(stream) { }
+ void Call(uc16 key, DispatchTable::Entry entry);
+ StringStream* stream() { return stream_; }
+ private:
+ StringStream* stream_;
+};
+
+
+void DispatchTableDumper::Call(uc16 key, DispatchTable::Entry entry) {
+ stream()->Add("[%k-%k]: {", key, entry.to());
+ OutSet* set = entry.out_set();
+ bool first = true;
+ for (unsigned i = 0; i < OutSet::kFirstLimit; i++) {
+ if (set->Get(i)) {
+ if (first) {
+ first = false;
+ } else {
+ stream()->Add(", ");
+ }
+ stream()->Add("%i", i);
+ }
+ }
+ stream()->Add("}\n");
+}
+
+
+void DispatchTable::Dump() {
+ HeapStringAllocator alloc;
+ StringStream stream(&alloc);
+ DispatchTableDumper dumper(&stream);
+ tree()->ForEach(&dumper);
+ OS::PrintError("%s", *stream.ToCString());
+}
+
+
+void RegExpEngine::DotPrint(const char* label,
+ RegExpNode* node,
+ bool ignore_case) {
+ DotPrinter printer(ignore_case);
+ printer.PrintNode(label, node);
+}
+
+
+#endif // DEBUG
+
+
+// -------------------------------------------------------------------
+// Tree to graph conversion
+
+
+RegExpNode* RegExpAtom::ToNode(RegExpCompiler* compiler,
+ RegExpNode* on_success,
+ RegExpNode* on_failure) {
+ ZoneList<TextElement>* elms = new ZoneList<TextElement>(1);
+ elms->Add(TextElement::Atom(this));
+ return new TextNode(elms, on_success, on_failure);
+}
+
+
+RegExpNode* RegExpText::ToNode(RegExpCompiler* compiler,
+ RegExpNode* on_success,
+ RegExpNode* on_failure) {
+ return new TextNode(elements(), on_success, on_failure);
+}
+
+
+RegExpNode* RegExpCharacterClass::ToNode(RegExpCompiler* compiler,
+ RegExpNode* on_success,
+ RegExpNode* on_failure) {
+ ZoneList<TextElement>* elms = new ZoneList<TextElement>(1);
+ elms->Add(TextElement::CharClass(this));
+ return new TextNode(elms, on_success, on_failure);
+}
+
+
+RegExpNode* RegExpDisjunction::ToNode(RegExpCompiler* compiler,
+ RegExpNode* on_success,
+ RegExpNode* on_failure) {
+ ZoneList<RegExpTree*>* alternatives = this->alternatives();
+ int length = alternatives->length();
+ ChoiceNode* result = new ChoiceNode(length, on_failure);
+ for (int i = 0; i < length; i++) {
+ GuardedAlternative alternative(alternatives->at(i)->ToNode(compiler,
+ on_success,
+ on_failure));
+ result->AddAlternative(alternative);
+ }
+ return result;
+}
+
+
+RegExpNode* RegExpQuantifier::ToNode(RegExpCompiler* compiler,
+ RegExpNode* on_success,
+ RegExpNode* on_failure) {
+ return ToNode(min(),
+ max(),
+ is_greedy(),
+ body(),
+ compiler,
+ on_success,
+ on_failure);
+}
+
+
+RegExpNode* RegExpQuantifier::ToNode(int min,
+ int max,
+ bool is_greedy,
+ RegExpTree* body,
+ RegExpCompiler* compiler,
+ RegExpNode* on_success,
+ RegExpNode* on_failure) {
+ // x{f, t} becomes this:
+ //
+ // (r++)<-.
+ // | `
+ // | (x)
+ // v ^
+ // (r=0)-->(?)---/ [if r < t]
+ // |
+ // [if r >= f] \----> ...
+ //
+ //
+ // TODO(someone): clear captures on repetition and handle empty
+ // matches.
+ bool has_min = min > 0;
+ bool has_max = max < RegExpQuantifier::kInfinity;
+ bool needs_counter = has_min || has_max;
+ int reg_ctr = needs_counter ? compiler->AllocateRegister() : -1;
+ ChoiceNode* center = new ChoiceNode(2, on_failure);
+ RegExpNode* loop_return = needs_counter
+ ? static_cast<RegExpNode*>(ActionNode::IncrementRegister(reg_ctr, center))
+ : static_cast<RegExpNode*>(center);
+ RegExpNode* body_node = body->ToNode(compiler, loop_return, on_failure);
+ GuardedAlternative body_alt(body_node);
+ if (has_max) {
+ Guard* body_guard = new Guard(reg_ctr, Guard::LT, max);
+ body_alt.AddGuard(body_guard);
+ }
+ GuardedAlternative rest_alt(on_success);
+ if (has_min) {
+ Guard* rest_guard = new Guard(reg_ctr, Guard::GEQ, min);
+ rest_alt.AddGuard(rest_guard);
+ }
+ if (is_greedy) {
+ center->AddAlternative(body_alt);
+ center->AddAlternative(rest_alt);
+ } else {
+ center->AddAlternative(rest_alt);
+ center->AddAlternative(body_alt);
+ }
+ if (needs_counter) {
+ return ActionNode::StoreRegister(reg_ctr, 0, center);
+ } else {
+ return center;
+ }
+}
+
+
+RegExpNode* RegExpAssertion::ToNode(RegExpCompiler* compiler,
+ RegExpNode* on_success,
+ RegExpNode* on_failure) {
+ NodeInfo info;
+ switch (type()) {
+ case START_OF_LINE:
+ info.follows_newline_interest = true;
+ break;
+ case START_OF_INPUT:
+ info.follows_start_interest = true;
+ break;
+ case BOUNDARY: case NON_BOUNDARY:
+ info.follows_word_interest = true;
+ break;
+ case END_OF_INPUT:
+ info.at_end = true;
+ break;
+ case END_OF_LINE:
+ // This is wrong but has the effect of making the compiler abort.
+ info.at_end = true;
+ }
+ return on_success->PropagateForward(&info);
+}
+
+
+RegExpNode* RegExpBackReference::ToNode(RegExpCompiler* compiler,
+ RegExpNode* on_success,
+ RegExpNode* on_failure) {
+ return new BackReferenceNode(RegExpCapture::StartRegister(index()),
+ RegExpCapture::EndRegister(index()),
+ on_success,
+ on_failure);
+}
+
+
+RegExpNode* RegExpEmpty::ToNode(RegExpCompiler* compiler,
+ RegExpNode* on_success,
+ RegExpNode* on_failure) {
+ return on_success;
+}
+
+
+RegExpNode* RegExpLookahead::ToNode(RegExpCompiler* compiler,
+ RegExpNode* on_success,
+ RegExpNode* on_failure) {
+ int stack_pointer_register = compiler->AllocateRegister();
+ int position_register = compiler->AllocateRegister();
+ if (is_positive()) {
+ // begin submatch scope
+ // $reg = $pos
+ // if [body]
+ // then
+ // $pos = $reg
+ // escape submatch scope (drop all backtracks created in scope)
+ // succeed
+ // else
+ // end submatch scope (nothing to clean up, just exit the scope)
+ // fail
+ return ActionNode::BeginSubmatch(
+ stack_pointer_register,
+ position_register,
+ body()->ToNode(
+ compiler,
+ ActionNode::EscapeSubmatch(
+ stack_pointer_register,
+ true, // Also restore input position.
+ position_register,
+ on_success),
+ on_failure));
+ } else {
+ // begin submatch scope
+ // try
+ // first if (body)
+ // then
+ // escape submatch scope
+ // fail
+ // else
+ // backtrack
+ // second
+ // end submatch scope
+ // restore current position
+ // succeed
+ ChoiceNode* try_node =
+ new ChoiceNode(1, ActionNode::RestorePosition(position_register,
+ on_success));
+ RegExpNode* body_node = body()->ToNode(
+ compiler,
+ ActionNode::EscapeSubmatch(stack_pointer_register,
+ false, // Don't also restore position
+ 0, // Unused arguments.
+ on_failure),
+ compiler->backtrack());
+ GuardedAlternative body_alt(body_node);
+ try_node->AddAlternative(body_alt);
+ return ActionNode::BeginSubmatch(stack_pointer_register,
+ position_register,
+ try_node);
+ }
+}
+
+
+RegExpNode* RegExpCapture::ToNode(RegExpCompiler* compiler,
+ RegExpNode* on_success,
+ RegExpNode* on_failure) {
+ return ToNode(body(), index(), compiler, on_success, on_failure);
+}
+
+
+RegExpNode* RegExpCapture::ToNode(RegExpTree* body,
+ int index,
+ RegExpCompiler* compiler,
+ RegExpNode* on_success,
+ RegExpNode* on_failure) {
+ int start_reg = RegExpCapture::StartRegister(index);
+ int end_reg = RegExpCapture::EndRegister(index);
+ RegExpNode* store_end = ActionNode::StorePosition(end_reg, on_success);
+ RegExpNode* body_node = body->ToNode(compiler, store_end, on_failure);
+ return ActionNode::StorePosition(start_reg, body_node);
+}
+
+
+RegExpNode* RegExpAlternative::ToNode(RegExpCompiler* compiler,
+ RegExpNode* on_success,
+ RegExpNode* on_failure) {
+ ZoneList<RegExpTree*>* children = nodes();
+ RegExpNode* current = on_success;
+ for (int i = children->length() - 1; i >= 0; i--) {
+ current = children->at(i)->ToNode(compiler, current, on_failure);
+ }
+ return current;
+}
+
+
+static const int kSpaceRangeCount = 20;
+static const uc16 kSpaceRanges[kSpaceRangeCount] = {
+ 0x0009, 0x000D, 0x0020, 0x0020, 0x00A0, 0x00A0, 0x1680,
+ 0x1680, 0x180E, 0x180E, 0x2000, 0x200A, 0x2028, 0x2029,
+ 0x202F, 0x202F, 0x205F, 0x205F, 0x3000, 0x3000
+};
+
+
+static const int kWordRangeCount = 8;
+static const uc16 kWordRanges[kWordRangeCount] = {
+ '0', '9', 'A', 'Z', '_', '_', 'a', 'z'
+};
+
+
+static const int kDigitRangeCount = 2;
+static const uc16 kDigitRanges[kDigitRangeCount] = {
+ '0', '9'
+};
+
+
+static const int kLineTerminatorRangeCount = 6;
+static const uc16 kLineTerminatorRanges[kLineTerminatorRangeCount] = {
+ 0x000A, 0x000A, 0x000D, 0x000D, 0x2028, 0x2029
+};
+
+
+static void AddClass(const uc16* elmv,
+ int elmc,
+ ZoneList<CharacterRange>* ranges) {
+ for (int i = 0; i < elmc; i += 2) {
+ ASSERT(elmv[i] <= elmv[i + 1]);
+ ranges->Add(CharacterRange(elmv[i], elmv[i + 1]));
+ }
+}
+
+
+static void AddClassNegated(const uc16 *elmv,
+ int elmc,
+ ZoneList<CharacterRange>* ranges) {
+ ASSERT(elmv[0] != 0x0000);
+ ASSERT(elmv[elmc-1] != 0xFFFF);
+ uc16 last = 0x0000;
+ for (int i = 0; i < elmc; i += 2) {
+ ASSERT(last <= elmv[i] - 1);
+ ASSERT(elmv[i] <= elmv[i + 1]);
+ ranges->Add(CharacterRange(last, elmv[i] - 1));
+ last = elmv[i + 1] + 1;
+ }
+ ranges->Add(CharacterRange(last, 0xFFFF));
+}
+
+
+void CharacterRange::AddClassEscape(uc16 type,
+ ZoneList<CharacterRange>* ranges) {
+ switch (type) {
+ case 's':
+ AddClass(kSpaceRanges, kSpaceRangeCount, ranges);
+ break;
+ case 'S':
+ AddClassNegated(kSpaceRanges, kSpaceRangeCount, ranges);
+ break;
+ case 'w':
+ AddClass(kWordRanges, kWordRangeCount, ranges);
+ break;
+ case 'W':
+ AddClassNegated(kWordRanges, kWordRangeCount, ranges);
+ break;
+ case 'd':
+ AddClass(kDigitRanges, kDigitRangeCount, ranges);
+ break;
+ case 'D':
+ AddClassNegated(kDigitRanges, kDigitRangeCount, ranges);
+ break;
+ case '.':
+ AddClassNegated(kLineTerminatorRanges,
+ kLineTerminatorRangeCount,
+ ranges);
+ break;
+ // This is not a character range as defined by the spec but a
+ // convenient shorthand for a character class that matches any
+ // character.
+ case '*':
+ ranges->Add(CharacterRange::Everything());
+ break;
+ default:
+ UNREACHABLE();
+ }
+}
+
+
+Vector<const uc16> CharacterRange::GetWordBounds() {
+ return Vector<const uc16>(kWordRanges, kWordRangeCount);
+}
+
+
+class CharacterRangeSplitter {
+ public:
+ CharacterRangeSplitter(ZoneList<CharacterRange>** included,
+ ZoneList<CharacterRange>** excluded)
+ : included_(included),
+ excluded_(excluded) { }
+ void Call(uc16 from, DispatchTable::Entry entry);
+
+ static const int kInBase = 0;
+ static const int kInOverlay = 1;
+
+ private:
+ ZoneList<CharacterRange>** included_;
+ ZoneList<CharacterRange>** excluded_;
+};
+
+
+void CharacterRangeSplitter::Call(uc16 from, DispatchTable::Entry entry) {
+ if (!entry.out_set()->Get(kInBase)) return;
+ ZoneList<CharacterRange>** target = entry.out_set()->Get(kInOverlay)
+ ? included_
+ : excluded_;
+ if (*target == NULL) *target = new ZoneList<CharacterRange>(2);
+ (*target)->Add(CharacterRange(entry.from(), entry.to()));
+}
+
+
+void CharacterRange::Split(ZoneList<CharacterRange>* base,
+ Vector<const uc16> overlay,
+ ZoneList<CharacterRange>** included,
+ ZoneList<CharacterRange>** excluded) {
+ ASSERT_EQ(NULL, *included);
+ ASSERT_EQ(NULL, *excluded);
+ DispatchTable table;
+ for (int i = 0; i < base->length(); i++)
+ table.AddRange(base->at(i), CharacterRangeSplitter::kInBase);
+ for (int i = 0; i < overlay.length(); i += 2) {
+ table.AddRange(CharacterRange(overlay[i], overlay[i+1]),
+ CharacterRangeSplitter::kInOverlay);
+ }
+ CharacterRangeSplitter callback(included, excluded);
+ table.ForEach(&callback);
+}
+
+
+void CharacterRange::AddCaseEquivalents(ZoneList<CharacterRange>* ranges) {
+ unibrow::uchar chars[unibrow::Ecma262UnCanonicalize::kMaxWidth];
+ if (IsSingleton()) {
+ // If this is a singleton we just expand the one character.
+ int length = uncanonicalize.get(from(), '\0', chars);
+ for (int i = 0; i < length; i++) {
+ uc32 chr = chars[i];
+ if (chr != from()) {
+ ranges->Add(CharacterRange::Singleton(chars[i]));
+ }
+ }
+ } else if (from() <= kRangeCanonicalizeMax &&
+ to() <= kRangeCanonicalizeMax) {
+ // If this is a range we expand the characters block by block,
+ // expanding contiguous subranges (blocks) one at a time.
+ // The approach is as follows. For a given start character we
+ // look up the block that contains it, for instance 'a' if the
+ // start character is 'c'. A block is characterized by the property
+ // that all characters uncanonicalize in the same way as the first
+ // element, except that each entry in the result is incremented
+ // by the distance from the first element. So a-z is a block
+ // because 'a' uncanonicalizes to ['a', 'A'] and the k'th letter
+ // uncanonicalizes to ['a' + k, 'A' + k].
+ // Once we've found the start point we look up its uncanonicalization
+ // and produce a range for each element. For instance for [c-f]
+ // we look up ['a', 'A'] and produce [c-f] and [C-F]. We then only
+ // add a range if it is not already contained in the input, so [c-f]
+ // will be skipped but [C-F] will be added. If this range is not
+ // completely contained in a block we do this for all the blocks
+ // covered by the range.
+ unibrow::uchar range[unibrow::Ecma262UnCanonicalize::kMaxWidth];
+ // First, look up the block that contains the 'from' character.
+ int length = canonrange.get(from(), '\0', range);
+ if (length == 0) {
+ range[0] = from();
+ } else {
+ ASSERT_EQ(1, length);
+ }
+ int pos = from();
+ // The start of the current block. Note that except for the first
+ // iteration 'start' is always equal to 'pos'.
+ int start;
+ // If it is not the start point of a block the entry contains the
+ // offset of the character from the start point.
+ if ((range[0] & kStartMarker) == 0) {
+ start = pos - range[0];
+ } else {
+ start = pos;
+ }
+ // Then we add the ranges on at a time, incrementing the current
+ // position to be after the last block each time. The position
+ // always points to the start of a block.
+ while (pos < to()) {
+ length = canonrange.get(start, '\0', range);
+ if (length == 0) {
+ range[0] = start;
+ } else {
+ ASSERT_EQ(1, length);
+ }
+ ASSERT((range[0] & kStartMarker) != 0);
+ // The start point of a block contains the distance to the end
+ // of the range.
+ int block_end = start + (range[0] & kPayloadMask) - 1;
+ int end = (block_end > to()) ? to() : block_end;
+ length = uncanonicalize.get(start, '\0', range);
+ for (int i = 0; i < length; i++) {
+ uc32 c = range[i];
+ uc16 range_from = c + (pos - start);
+ uc16 range_to = c + (end - start);
+ if (!(from() <= range_from && range_to <= to())) {
+ ranges->Add(CharacterRange(range_from, range_to));
+ }
+ }
+ start = pos = block_end + 1;
+ }
+ } else {
+ // TODO(plesner) when we've fixed the 2^11 bug in unibrow.
+ }
+}
+
+
+// -------------------------------------------------------------------
+// Interest propagation
+
+
+RegExpNode* RegExpNode::TryGetSibling(NodeInfo* info) {
+ for (int i = 0; i < siblings_.length(); i++) {
+ RegExpNode* sibling = siblings_.Get(i);
+ if (sibling->info()->Matches(info))
+ return sibling;
+ }
+ return NULL;
+}
+
+
+RegExpNode* RegExpNode::EnsureSibling(NodeInfo* info, bool* cloned) {
+ ASSERT_EQ(false, *cloned);
+ ASSERT(!info->HasAssertions());
+ siblings_.Ensure(this);
+ RegExpNode* result = TryGetSibling(info);
+ if (result != NULL) return result;
+ result = this->Clone();
+ NodeInfo* new_info = result->info();
+ new_info->ResetCompilationState();
+ new_info->AddFromPreceding(info);
+ AddSibling(result);
+ *cloned = true;
+ return result;
+}
+
+
+template <class C>
+static RegExpNode* PropagateToEndpoint(C* node, NodeInfo* info) {
+ NodeInfo full_info(*node->info());
+ full_info.AddFromPreceding(info);
+ bool cloned = false;
+ return RegExpNode::EnsureSibling(node, &full_info, &cloned);
+}
+
+
+RegExpNode* ActionNode::PropagateForward(NodeInfo* info) {
+ NodeInfo full_info(*this->info());
+ full_info.AddFromPreceding(info);
+ bool cloned = false;
+ ActionNode* action = EnsureSibling(this, &full_info, &cloned);
+ if (cloned && type_ != ESCAPE_SUBMATCH) {
+ action->set_on_success(action->on_success()->PropagateForward(info));
+ }
+ return action;
+}
+
+
+RegExpNode* ChoiceNode::PropagateForward(NodeInfo* info) {
+ NodeInfo full_info(*this->info());
+ full_info.AddFromPreceding(info);
+ bool cloned = false;
+ ChoiceNode* choice = EnsureSibling(this, &full_info, &cloned);
+ if (cloned) {
+ ZoneList<GuardedAlternative>* old_alternatives = alternatives();
+ int count = old_alternatives->length();
+ choice->alternatives_ = new ZoneList<GuardedAlternative>(count);
+ for (int i = 0; i < count; i++) {
+ GuardedAlternative alternative = old_alternatives->at(i);
+ alternative.set_node(alternative.node()->PropagateForward(info));
+ choice->alternatives()->Add(alternative);
+ }
+ if (!choice->on_failure_->IsBacktrack()) {
+ choice->on_failure_ = choice->on_failure_->PropagateForward(info);
+ }
+ }
+ return choice;
+}
+
+
+RegExpNode* EndNode::PropagateForward(NodeInfo* info) {
+ return PropagateToEndpoint(this, info);
+}
+
+
+RegExpNode* BackReferenceNode::PropagateForward(NodeInfo* info) {
+ NodeInfo full_info(*this->info());
+ full_info.AddFromPreceding(info);
+ bool cloned = false;
+ BackReferenceNode* back_ref = EnsureSibling(this, &full_info, &cloned);
+ if (cloned) {
+ // TODO(erikcorry): A back reference has to have two successors (by default
+ // the same node). The first is used if the back reference matches a non-
+ // empty back reference, the second if it matches an empty one. This
+ // doesn't matter for at_end, which is the only one implemented right now,
+ // but it will matter for other pieces of info.
+ back_ref->set_on_success(back_ref->on_success()->PropagateForward(info));
+ }
+ return back_ref;
+}
+
+
+RegExpNode* TextNode::PropagateForward(NodeInfo* info) {
+ return PropagateToEndpoint(this, info);
+}
+
+
+// -------------------------------------------------------------------
+// Splay tree
+
+
+OutSet* OutSet::Extend(unsigned value) {
+ if (Get(value))
+ return this;
+ if (successors() != NULL) {
+ for (int i = 0; i < successors()->length(); i++) {
+ OutSet* successor = successors()->at(i);
+ if (successor->Get(value))
+ return successor;
+ }
+ } else {
+ successors_ = new ZoneList<OutSet*>(2);
+ }
+ OutSet* result = new OutSet(first_, remaining_);
+ result->Set(value);
+ successors()->Add(result);
+ return result;
+}
+
+
+void OutSet::Set(unsigned value) {
+ if (value < kFirstLimit) {
+ first_ |= (1 << value);
+ } else {
+ if (remaining_ == NULL)
+ remaining_ = new ZoneList<unsigned>(1);
+ if (remaining_->is_empty() || !remaining_->Contains(value))
+ remaining_->Add(value);
+ }
+}
+
+
+bool OutSet::Get(unsigned value) {
+ if (value < kFirstLimit) {
+ return (first_ & (1 << value)) != 0;
+ } else if (remaining_ == NULL) {
+ return false;
+ } else {
+ return remaining_->Contains(value);
+ }
+}
+
+
+const uc16 DispatchTable::Config::kNoKey = unibrow::Utf8::kBadChar;
+const DispatchTable::Entry DispatchTable::Config::kNoValue;
+
+
+void DispatchTable::AddRange(CharacterRange full_range, int value) {
+ CharacterRange current = full_range;
+ if (tree()->is_empty()) {
+ // If this is the first range we just insert into the table.
+ ZoneSplayTree<Config>::Locator loc;
+ ASSERT_RESULT(tree()->Insert(current.from(), &loc));
+ loc.set_value(Entry(current.from(), current.to(), empty()->Extend(value)));
+ return;
+ }
+ // First see if there is a range to the left of this one that
+ // overlaps.
+ ZoneSplayTree<Config>::Locator loc;
+ if (tree()->FindGreatestLessThan(current.from(), &loc)) {
+ Entry* entry = &loc.value();
+ // If we've found a range that overlaps with this one, and it
+ // starts strictly to the left of this one, we have to fix it
+ // because the following code only handles ranges that start on
+ // or after the start point of the range we're adding.
+ if (entry->from() < current.from() && entry->to() >= current.from()) {
+ // Snap the overlapping range in half around the start point of
+ // the range we're adding.
+ CharacterRange left(entry->from(), current.from() - 1);
+ CharacterRange right(current.from(), entry->to());
+ // The left part of the overlapping range doesn't overlap.
+ // Truncate the whole entry to be just the left part.
+ entry->set_to(left.to());
+ // The right part is the one that overlaps. We add this part
+ // to the map and let the next step deal with merging it with
+ // the range we're adding.
+ ZoneSplayTree<Config>::Locator loc;
+ ASSERT_RESULT(tree()->Insert(right.from(), &loc));
+ loc.set_value(Entry(right.from(),
+ right.to(),
+ entry->out_set()));
+ }
+ }
+ while (current.is_valid()) {
+ if (tree()->FindLeastGreaterThan(current.from(), &loc) &&
+ (loc.value().from() <= current.to()) &&
+ (loc.value().to() >= current.from())) {
+ Entry* entry = &loc.value();
+ // We have overlap. If there is space between the start point of
+ // the range we're adding and where the overlapping range starts
+ // then we have to add a range covering just that space.
+ if (current.from() < entry->from()) {
+ ZoneSplayTree<Config>::Locator ins;
+ ASSERT_RESULT(tree()->Insert(current.from(), &ins));
+ ins.set_value(Entry(current.from(),
+ entry->from() - 1,
+ empty()->Extend(value)));
+ current.set_from(entry->from());
+ }
+ ASSERT_EQ(current.from(), entry->from());
+ // If the overlapping range extends beyond the one we want to add
+ // we have to snap the right part off and add it separately.
+ if (entry->to() > current.to()) {
+ ZoneSplayTree<Config>::Locator ins;
+ ASSERT_RESULT(tree()->Insert(current.to() + 1, &ins));
+ ins.set_value(Entry(current.to() + 1,
+ entry->to(),
+ entry->out_set()));
+ entry->set_to(current.to());
+ }
+ ASSERT(entry->to() <= current.to());
+ // The overlapping range is now completely contained by the range
+ // we're adding so we can just update it and move the start point
+ // of the range we're adding just past it.
+ entry->AddValue(value);
+ // Bail out if the last interval ended at 0xFFFF since otherwise
+ // adding 1 will wrap around to 0.
+ if (entry->to() == 0xFFFF)
+ break;
+ ASSERT(entry->to() + 1 > current.from());
+ current.set_from(entry->to() + 1);
+ } else {
+ // There is no overlap so we can just add the range
+ ZoneSplayTree<Config>::Locator ins;
+ ASSERT_RESULT(tree()->Insert(current.from(), &ins));
+ ins.set_value(Entry(current.from(),
+ current.to(),
+ empty()->Extend(value)));
+ break;
+ }
+ }
+}
+
+
+OutSet* DispatchTable::Get(uc16 value) {
+ ZoneSplayTree<Config>::Locator loc;
+ if (!tree()->FindGreatestLessThan(value, &loc))
+ return empty();
+ Entry* entry = &loc.value();
+ if (value <= entry->to())
+ return entry->out_set();
+ else
+ return empty();
+}
+
+
+// -------------------------------------------------------------------
+// Analysis
+
+
+void Analysis::EnsureAnalyzed(RegExpNode* that) {
+ if (that->info()->been_analyzed || that->info()->being_analyzed)
+ return;
+ that->info()->being_analyzed = true;
+ that->Accept(this);
+ that->info()->being_analyzed = false;
+ that->info()->been_analyzed = true;
+}
+
+
+void Analysis::VisitEnd(EndNode* that) {
+ // nothing to do
+}
+
+
+void Analysis::VisitText(TextNode* that) {
+ if (ignore_case_) {
+ that->MakeCaseIndependent();
+ }
+ EnsureAnalyzed(that->on_success());
+ EnsureAnalyzed(that->on_failure());
+ NodeInfo* info = that->info();
+ NodeInfo* next_info = that->on_success()->info();
+ // If the following node is interested in what it follows then this
+ // node must determine it.
+ info->determine_newline = next_info->follows_newline_interest;
+ info->determine_word = next_info->follows_word_interest;
+ info->determine_start = next_info->follows_start_interest;
+}
+
+
+void Analysis::VisitAction(ActionNode* that) {
+ EnsureAnalyzed(that->on_success());
+ // If the next node is interested in what it follows then this node
+ // has to be interested too so it can pass the information on.
+ that->info()->AddFromFollowing(that->on_success()->info());
+}
+
+
+void Analysis::VisitChoice(ChoiceNode* that) {
+ NodeInfo* info = that->info();
+ for (int i = 0; i < that->alternatives()->length(); i++) {
+ RegExpNode* node = that->alternatives()->at(i).node();
+ EnsureAnalyzed(node);
+ // Anything the following nodes need to know has to be known by
+ // this node also, so it can pass it on.
+ info->AddFromFollowing(node->info());
+ }
+ EnsureAnalyzed(that->on_failure());
+}
+
+
+void Analysis::VisitBackReference(BackReferenceNode* that) {
+ EnsureAnalyzed(that->on_success());
+ EnsureAnalyzed(that->on_failure());
+}
+
+
+// -------------------------------------------------------------------
+// Assumption expansion
+
+
+RegExpNode* RegExpNode::EnsureExpanded(NodeInfo* info) {
+ siblings_.Ensure(this);
+ NodeInfo new_info = *this->info();
+ if (new_info.follows_word_interest)
+ new_info.follows_word = info->follows_word;
+ if (new_info.follows_newline_interest)
+ new_info.follows_newline = info->follows_newline;
+ // If the following node should determine something we need to get
+ // a sibling that determines it.
+ new_info.does_determine_newline = new_info.determine_newline;
+ new_info.does_determine_word = new_info.determine_word;
+ new_info.does_determine_start = new_info.determine_start;
+ RegExpNode* sibling = TryGetSibling(&new_info);
+ if (sibling == NULL) {
+ sibling = ExpandLocal(&new_info);
+ siblings_.Add(sibling);
+ sibling->info()->being_expanded = true;
+ sibling->ExpandChildren();
+ sibling->info()->being_expanded = false;
+ sibling->info()->been_expanded = true;
+ } else {
+ NodeInfo* sib_info = sibling->info();
+ if (!sib_info->been_expanded && !sib_info->being_expanded) {
+ sibling->info()->being_expanded = true;
+ sibling->ExpandChildren();
+ sibling->info()->being_expanded = false;
+ sibling->info()->been_expanded = true;
+ }
+ }
+ return sibling;
+}
+
+
+RegExpNode* ChoiceNode::ExpandLocal(NodeInfo* info) {
+ ChoiceNode* clone = this->Clone();
+ clone->info()->ResetCompilationState();
+ clone->info()->AddAssumptions(info);
+ return clone;
+}
+
+
+void ChoiceNode::ExpandChildren() {
+ ZoneList<GuardedAlternative>* alts = alternatives();
+ ZoneList<GuardedAlternative>* new_alts
+ = new ZoneList<GuardedAlternative>(alts->length());
+ for (int i = 0; i < alts->length(); i++) {
+ GuardedAlternative next = alts->at(i);
+ next.set_node(next.node()->EnsureExpanded(info()));
+ new_alts->Add(next);
+ }
+ alternatives_ = new_alts;
+}
+
+
+RegExpNode* TextNode::ExpandLocal(NodeInfo* info) {
+ TextElement last = elements()->last();
+ if (last.type == TextElement::CHAR_CLASS) {
+ RegExpCharacterClass* char_class = last.data.u_char_class;
+ if (info->does_determine_word) {
+ ZoneList<CharacterRange>* word = NULL;
+ ZoneList<CharacterRange>* non_word = NULL;
+ CharacterRange::Split(char_class->ranges(),
+ CharacterRange::GetWordBounds(),
+ &word,
+ &non_word);
+ if (non_word == NULL) {
+ // This node contains no non-word characters so it must be
+ // all word.
+ this->info()->is_word = NodeInfo::TRUE;
+ } else if (word == NULL) {
+ // Vice versa.
+ this->info()->is_word = NodeInfo::FALSE;
+ } else {
+ // If this character class contains both word and non-word
+ // characters we need to split it into two.
+ ChoiceNode* result = new ChoiceNode(2, on_failure());
+ // Welcome to the family, son!
+ result->set_siblings(this->siblings());
+ *result->info() = *this->info();
+ result->info()->ResetCompilationState();
+ result->info()->AddAssumptions(info);
+ RegExpNode* word_node
+ = new TextNode(new RegExpCharacterClass(word, false),
+ on_success(),
+ on_failure());
+ word_node->info()->determine_word = true;
+ word_node->info()->does_determine_word = true;
+ word_node->info()->is_word = NodeInfo::TRUE;
+ result->alternatives()->Add(GuardedAlternative(word_node));
+ RegExpNode* non_word_node
+ = new TextNode(new RegExpCharacterClass(non_word, false),
+ on_success(),
+ on_failure());
+ non_word_node->info()->determine_word = true;
+ non_word_node->info()->does_determine_word = true;
+ non_word_node->info()->is_word = NodeInfo::FALSE;
+ result->alternatives()->Add(GuardedAlternative(non_word_node));
+ return result;
+ }
+ }
+ }
+ TextNode* clone = this->Clone();
+ clone->info()->ResetCompilationState();
+ clone->info()->AddAssumptions(info);
+ return clone;
+}
+
+
+void TextNode::ExpandAtomChildren(RegExpAtom* that) {
+ NodeInfo new_info = *info();
+ uc16 last = that->data()[that->data().length() - 1];
+ if (info()->determine_word) {
+ new_info.follows_word = IsRegExpWord(last)
+ ? NodeInfo::TRUE : NodeInfo::FALSE;
+ } else {
+ new_info.follows_word = NodeInfo::UNKNOWN;
+ }
+ if (info()->determine_newline) {
+ new_info.follows_newline = IsRegExpNewline(last)
+ ? NodeInfo::TRUE : NodeInfo::FALSE;
+ } else {
+ new_info.follows_newline = NodeInfo::UNKNOWN;
+ }
+ if (info()->determine_start) {
+ new_info.follows_start = NodeInfo::FALSE;
+ } else {
+ new_info.follows_start = NodeInfo::UNKNOWN;
+ }
+ set_on_success(on_success()->EnsureExpanded(&new_info));
+}
+
+
+void TextNode::ExpandCharClassChildren(RegExpCharacterClass* that) {
+ if (info()->does_determine_word) {
+ // ASSERT(info()->is_word != NodeInfo::UNKNOWN);
+ NodeInfo next_info = *on_success()->info();
+ next_info.follows_word = info()->is_word;
+ set_on_success(on_success()->EnsureExpanded(&next_info));
+ } else {
+ set_on_success(on_success()->EnsureExpanded(info()));
+ }
+}
+
+
+void TextNode::ExpandChildren() {
+ TextElement last = elements()->last();
+ switch (last.type) {
+ case TextElement::ATOM:
+ ExpandAtomChildren(last.data.u_atom);
+ break;
+ case TextElement::CHAR_CLASS:
+ ExpandCharClassChildren(last.data.u_char_class);
+ break;
+ default:
+ UNREACHABLE();
+ }
+}
+
+
+RegExpNode* ActionNode::ExpandLocal(NodeInfo* info) {
+ ActionNode* clone = this->Clone();
+ clone->info()->ResetCompilationState();
+ clone->info()->AddAssumptions(info);
+ return clone;
+}
+
+
+void ActionNode::ExpandChildren() {
+ set_on_success(on_success()->EnsureExpanded(info()));
+}
+
+
+RegExpNode* BackReferenceNode::ExpandLocal(NodeInfo* info) {
+ BackReferenceNode* clone = this->Clone();
+ clone->info()->ResetCompilationState();
+ clone->info()->AddAssumptions(info);
+ return clone;
+}
+
+
+void BackReferenceNode::ExpandChildren() {
+ set_on_success(on_success()->EnsureExpanded(info()));
+}
+
+
+RegExpNode* EndNode::ExpandLocal(NodeInfo* info) {
+ EndNode* clone = this->Clone();
+ clone->info()->ResetCompilationState();
+ clone->info()->AddAssumptions(info);
+ return clone;
+}
+
+
+void EndNode::ExpandChildren() {
+ // nothing to do
+}
+
+
+// -------------------------------------------------------------------
+// Dispatch table construction
+
+
+void DispatchTableConstructor::VisitEnd(EndNode* that) {
+ AddRange(CharacterRange::Everything());
+}
+
+
+void DispatchTableConstructor::BuildTable(ChoiceNode* node) {
+ node->set_being_calculated(true);
+ ZoneList<GuardedAlternative>* alternatives = node->alternatives();
+ for (int i = 0; i < alternatives->length(); i++) {
+ set_choice_index(i);
+ alternatives->at(i).node()->Accept(this);
+ }
+ node->set_being_calculated(false);
+}
+
+
+class AddDispatchRange {
+ public:
+ explicit AddDispatchRange(DispatchTableConstructor* constructor)
+ : constructor_(constructor) { }
+ void Call(uc32 from, DispatchTable::Entry entry);
+ private:
+ DispatchTableConstructor* constructor_;
+};
+
+
+void AddDispatchRange::Call(uc32 from, DispatchTable::Entry entry) {
+ CharacterRange range(from, entry.to());
+ constructor_->AddRange(range);
+}
+
+
+void DispatchTableConstructor::VisitChoice(ChoiceNode* node) {
+ if (node->being_calculated())
+ return;
+ DispatchTable* table = node->GetTable(ignore_case_);
+ AddDispatchRange adder(this);
+ table->ForEach(&adder);
+}
+
+
+void DispatchTableConstructor::VisitBackReference(BackReferenceNode* that) {
+ // TODO(160): Find the node that we refer back to and propagate its start
+ // set back to here. For now we just accept anything.
+ AddRange(CharacterRange::Everything());
+}
+
+
+
+static int CompareRangeByFrom(const CharacterRange* a,
+ const CharacterRange* b) {
+ return Compare<uc16>(a->from(), b->from());
+}
+
+
+void DispatchTableConstructor::AddInverse(ZoneList<CharacterRange>* ranges) {
+ ranges->Sort(CompareRangeByFrom);
+ uc16 last = 0;
+ for (int i = 0; i < ranges->length(); i++) {
+ CharacterRange range = ranges->at(i);
+ if (last < range.from())
+ AddRange(CharacterRange(last, range.from() - 1));
+ if (range.to() >= last) {
+ if (range.to() == 0xFFFF) {
+ return;
+ } else {
+ last = range.to() + 1;
+ }
+ }
+ }
+ AddRange(CharacterRange(last, 0xFFFF));
+}
+
+
+void DispatchTableConstructor::VisitText(TextNode* that) {
+ TextElement elm = that->elements()->at(0);
+ switch (elm.type) {
+ case TextElement::ATOM: {
+ uc16 c = elm.data.u_atom->data()[0];
+ AddRange(CharacterRange(c, c));
+ break;
+ }
+ case TextElement::CHAR_CLASS: {
+ RegExpCharacterClass* tree = elm.data.u_char_class;
+ ZoneList<CharacterRange>* ranges = tree->ranges();
+ if (tree->is_negated()) {
+ AddInverse(ranges);
+ } else {
+ for (int i = 0; i < ranges->length(); i++)
+ AddRange(ranges->at(i));
+ }
+ break;
+ }
+ default: {
+ UNIMPLEMENTED();
+ }
+ }
+}
+
+
+void DispatchTableConstructor::VisitAction(ActionNode* that) {
+ that->on_success()->Accept(this);
+}
+
+
+Handle<FixedArray> RegExpEngine::Compile(RegExpParseResult* input,
+ RegExpNode** node_return,
+ bool ignore_case,
+ bool is_multiline) {
+ RegExpCompiler compiler(input->capture_count, ignore_case);
+ // Wrap the body of the regexp in capture #0.
+ RegExpNode* captured_body = RegExpCapture::ToNode(input->tree,
+ 0,
+ &compiler,
+ compiler.accept(),
+ compiler.backtrack());
+ // Add a .*? at the beginning, outside the body capture.
+ // Note: We could choose to not add this if the regexp is anchored at
+ // the start of the input but I'm not sure how best to do that and
+ // since we don't even handle ^ yet I'm saving that optimization for
+ // later.
+ RegExpNode* node = RegExpQuantifier::ToNode(0,
+ RegExpQuantifier::kInfinity,
+ false,
+ new RegExpCharacterClass('*'),
+ &compiler,
+ captured_body,
+ compiler.backtrack());
+ if (node_return != NULL) *node_return = node;
+ Analysis analysis(ignore_case);
+ analysis.EnsureAnalyzed(node);
+
+ NodeInfo info = *node->info();
+ node = node->EnsureExpanded(&info);
+
+ if (!FLAG_irregexp) {
+ return Handle<FixedArray>::null();
+ }
+
+ if (is_multiline && !FLAG_attempt_multiline_irregexp) {
+ return Handle<FixedArray>::null();
+ }
+
+ if (FLAG_irregexp_native) {
+#ifdef ARM
+ // Unimplemented, fall-through to bytecode implementation.
+#else // IA32
+ RegExpMacroAssemblerIA32 macro_assembler(RegExpMacroAssemblerIA32::UC16,
+ (input->capture_count + 1) * 2);
+ return compiler.Assemble(¯o_assembler,
+ node,
+ input->capture_count);
+#endif
+ }
+ EmbeddedVector<byte, 1024> codes;
+ RegExpMacroAssemblerIrregexp macro_assembler(codes);
+ return compiler.Assemble(¯o_assembler,
+ node,
+ input->capture_count);
+}
+
+
}} // namespace v8::internal
diff --git a/src/jsregexp.h b/src/jsregexp.h
index c05380d..3ab6651 100644
--- a/src/jsregexp.h
+++ b/src/jsregexp.h
@@ -30,6 +30,10 @@
namespace v8 { namespace internal {
+
+class RegExpMacroAssembler;
+
+
class RegExpImpl {
public:
// Creates a regular expression literal in the old space.
@@ -61,10 +65,28 @@
static Handle<Object> ExecGlobal(Handle<JSRegExp> regexp,
Handle<String> subject);
+ // Stores an uncompiled RegExp pattern in the JSRegExp object.
+ // It will be compiled by JSCRE when first executed.
+ static Handle<Object> JscrePrepare(Handle<JSRegExp> re,
+ Handle<String> pattern,
+ JSRegExp::Flags flags);
+
+ // Stores a compiled RegExp pattern in the JSRegExp object.
+ // The pattern is compiled by Irregexp.
+ static Handle<Object> IrregexpPrepare(Handle<JSRegExp> re,
+ Handle<String> pattern,
+ JSRegExp::Flags flags,
+ Handle<FixedArray> irregexp_data);
+
+
+ // Compile the pattern using JSCRE and store the result in the
+ // JSRegExp object.
+ static Handle<Object> JscreCompile(Handle<JSRegExp> re);
+
static Handle<Object> AtomCompile(Handle<JSRegExp> re,
Handle<String> pattern,
- JSRegExp::Flags flags);
-
+ JSRegExp::Flags flags,
+ Handle<String> match_pattern);
static Handle<Object> AtomExec(Handle<JSRegExp> regexp,
Handle<String> subject,
Handle<Object> index);
@@ -72,47 +94,78 @@
static Handle<Object> AtomExecGlobal(Handle<JSRegExp> regexp,
Handle<String> subject);
- static Handle<Object> JsreCompile(Handle<JSRegExp> re,
- Handle<String> pattern,
- JSRegExp::Flags flags);
+ static Handle<Object> JscreCompile(Handle<JSRegExp> re,
+ Handle<String> pattern,
+ JSRegExp::Flags flags);
- static Handle<Object> JsreExec(Handle<JSRegExp> regexp,
- Handle<String> subject,
- Handle<Object> index);
+ // Execute a compiled JSCRE pattern.
+ static Handle<Object> JscreExec(Handle<JSRegExp> regexp,
+ Handle<String> subject,
+ Handle<Object> index);
- static Handle<Object> JsreExecGlobal(Handle<JSRegExp> regexp,
- Handle<String> subject);
+ // Execute an Irregexp bytecode pattern.
+ static Handle<Object> IrregexpExec(Handle<JSRegExp> regexp,
+ Handle<String> subject,
+ Handle<Object> index);
+
+ static Handle<Object> JscreExecGlobal(Handle<JSRegExp> regexp,
+ Handle<String> subject);
+
+ static Handle<Object> IrregexpExecGlobal(Handle<JSRegExp> regexp,
+ Handle<String> subject);
static void NewSpaceCollectionPrologue();
static void OldSpaceCollectionPrologue();
- private:
// Converts a source string to a 16 bit flat string. The string
// will be either sequential or it will be a SlicedString backed
// by a flat string.
static Handle<String> StringToTwoByte(Handle<String> pattern);
static Handle<String> CachedStringToTwoByte(Handle<String> pattern);
+ static const int kIrregexpImplementationIndex = 0;
+ static const int kIrregexpNumberOfCapturesIndex = 1;
+ static const int kIrregexpNumberOfRegistersIndex = 2;
+ static const int kIrregexpCodeIndex = 3;
+ static const int kIrregexpDataLength = 4;
+
+ static const int kJscreNumberOfCapturesIndex = 0;
+ static const int kJscreInternalIndex = 1;
+ static const int kJscreDataLength = 2;
+
+ private:
static String* last_ascii_string_;
static String* two_byte_cached_string_;
- // Returns the caputure from the re.
- static int JsreCapture(Handle<JSRegExp> re);
- static ByteArray* JsreInternal(Handle<JSRegExp> re);
+ static int JscreNumberOfCaptures(Handle<JSRegExp> re);
+ static ByteArray* JscreInternal(Handle<JSRegExp> re);
+
+ static int IrregexpNumberOfCaptures(Handle<JSRegExp> re);
+ static int IrregexpNumberOfRegisters(Handle<JSRegExp> re);
+ static Handle<ByteArray> IrregexpCode(Handle<JSRegExp> re);
// Call jsRegExpExecute once
- static Handle<Object> JsreExecOnce(Handle<JSRegExp> regexp,
- int num_captures,
- Handle<String> subject,
- int previous_index,
- const uc16* utf8_subject,
- int* ovector,
- int ovector_length);
+ static Handle<Object> JscreExecOnce(Handle<JSRegExp> regexp,
+ int num_captures,
+ Handle<String> subject,
+ int previous_index,
+ const uc16* utf8_subject,
+ int* ovector,
+ int ovector_length);
+
+ static Handle<Object> IrregexpExecOnce(Handle<JSRegExp> regexp,
+ int num_captures,
+ Handle<String> subject16,
+ int previous_index,
+ int* ovector,
+ int ovector_length);
// Set the subject cache. The previous string buffer is not deleted, so the
// caller should ensure that it doesn't leak.
- static void SetSubjectCache(String* subject, char* utf8_subject,
- int uft8_length, int character_position,
+ static void SetSubjectCache(String* subject,
+ char* utf8_subject,
+ int uft8_length,
+ int character_position,
int utf8_position);
// A one element cache of the last utf8_subject string and its length. The
@@ -125,6 +178,789 @@
};
+class CharacterRange {
+ public:
+ CharacterRange() : from_(0), to_(0) { }
+ // For compatibility with the CHECK_OK macro
+ CharacterRange(void* null) { ASSERT_EQ(NULL, null); } //NOLINT
+ CharacterRange(uc16 from, uc16 to) : from_(from), to_(to) { }
+ static void AddClassEscape(uc16 type, ZoneList<CharacterRange>* ranges);
+ static Vector<const uc16> GetWordBounds();
+ static inline CharacterRange Singleton(uc16 value) {
+ return CharacterRange(value, value);
+ }
+ static inline CharacterRange Range(uc16 from, uc16 to) {
+ ASSERT(from <= to);
+ return CharacterRange(from, to);
+ }
+ static inline CharacterRange Everything() {
+ return CharacterRange(0, 0xFFFF);
+ }
+ bool Contains(uc16 i) { return from_ <= i && i <= to_; }
+ uc16 from() const { return from_; }
+ void set_from(uc16 value) { from_ = value; }
+ uc16 to() const { return to_; }
+ void set_to(uc16 value) { to_ = value; }
+ bool is_valid() { return from_ <= to_; }
+ bool IsSingleton() { return (from_ == to_); }
+ void AddCaseEquivalents(ZoneList<CharacterRange>* ranges);
+ static void Split(ZoneList<CharacterRange>* base,
+ Vector<const uc16> overlay,
+ ZoneList<CharacterRange>** included,
+ ZoneList<CharacterRange>** excluded);
+
+ static const int kRangeCanonicalizeMax = 0x346;
+ static const int kStartMarker = (1 << 24);
+ static const int kPayloadMask = (1 << 24) - 1;
+
+ private:
+ uc16 from_;
+ uc16 to_;
+};
+
+
+template <typename Node, class Callback>
+static void DoForEach(Node* node, Callback* callback);
+
+
+// A zone splay tree. The config type parameter encapsulates the
+// different configurations of a concrete splay tree:
+//
+// typedef Key: the key type
+// typedef Value: the value type
+// static const kNoKey: the dummy key used when no key is set
+// static const kNoValue: the dummy value used to initialize nodes
+// int (Compare)(Key& a, Key& b) -> {-1, 0, 1}: comparison function
+//
+template <typename Config>
+class ZoneSplayTree : public ZoneObject {
+ public:
+ typedef typename Config::Key Key;
+ typedef typename Config::Value Value;
+
+ class Locator;
+
+ ZoneSplayTree() : root_(NULL) { }
+
+ // Inserts the given key in this tree with the given value. Returns
+ // true if a node was inserted, otherwise false. If found the locator
+ // is enabled and provides access to the mapping for the key.
+ bool Insert(const Key& key, Locator* locator);
+
+ // Looks up the key in this tree and returns true if it was found,
+ // otherwise false. If the node is found the locator is enabled and
+ // provides access to the mapping for the key.
+ bool Find(const Key& key, Locator* locator);
+
+ // Finds the mapping with the greatest key less than or equal to the
+ // given key.
+ bool FindGreatestLessThan(const Key& key, Locator* locator);
+
+ // Find the mapping with the greatest key in this tree.
+ bool FindGreatest(Locator* locator);
+
+ // Finds the mapping with the least key greater than or equal to the
+ // given key.
+ bool FindLeastGreaterThan(const Key& key, Locator* locator);
+
+ // Find the mapping with the least key in this tree.
+ bool FindLeast(Locator* locator);
+
+ // Remove the node with the given key from the tree.
+ bool Remove(const Key& key);
+
+ bool is_empty() { return root_ == NULL; }
+
+ // Perform the splay operation for the given key. Moves the node with
+ // the given key to the top of the tree. If no node has the given
+ // key, the last node on the search path is moved to the top of the
+ // tree.
+ void Splay(const Key& key);
+
+ class Node : public ZoneObject {
+ public:
+ Node(const Key& key, const Value& value)
+ : key_(key),
+ value_(value),
+ left_(NULL),
+ right_(NULL) { }
+ Key key() { return key_; }
+ Value value() { return value_; }
+ Node* left() { return left_; }
+ Node* right() { return right_; }
+ private:
+ friend class ZoneSplayTree;
+ friend class Locator;
+ Key key_;
+ Value value_;
+ Node* left_;
+ Node* right_;
+ };
+
+ // A locator provides access to a node in the tree without actually
+ // exposing the node.
+ class Locator {
+ public:
+ explicit Locator(Node* node) : node_(node) { }
+ Locator() : node_(NULL) { }
+ const Key& key() { return node_->key_; }
+ Value& value() { return node_->value_; }
+ void set_value(const Value& value) { node_->value_ = value; }
+ inline void bind(Node* node) { node_ = node; }
+ private:
+ Node* node_;
+ };
+
+ template <class Callback>
+ void ForEach(Callback* c) {
+ DoForEach<typename ZoneSplayTree<Config>::Node, Callback>(root_, c);
+ }
+
+ private:
+ Node* root_;
+};
+
+
+// A set of unsigned integers that behaves especially well on small
+// integers (< 32). May do zone-allocation.
+class OutSet: public ZoneObject {
+ public:
+ OutSet() : first_(0), remaining_(NULL), successors_(NULL) { }
+ OutSet* Extend(unsigned value);
+ bool Get(unsigned value);
+ static const unsigned kFirstLimit = 32;
+
+ private:
+ // Destructively set a value in this set. In most cases you want
+ // to use Extend instead to ensure that only one instance exists
+ // that contains the same values.
+ void Set(unsigned value);
+
+ // The successors are a list of sets that contain the same values
+ // as this set and the one more value that is not present in this
+ // set.
+ ZoneList<OutSet*>* successors() { return successors_; }
+
+ OutSet(uint32_t first, ZoneList<unsigned>* remaining)
+ : first_(first), remaining_(remaining), successors_(NULL) { }
+ uint32_t first_;
+ ZoneList<unsigned>* remaining_;
+ ZoneList<OutSet*>* successors_;
+};
+
+
+// A mapping from integers, specified as ranges, to a set of integers.
+// Used for mapping character ranges to choices.
+class DispatchTable : public ZoneObject {
+ public:
+ class Entry {
+ public:
+ Entry() : from_(0), to_(0), out_set_(NULL) { }
+ Entry(uc16 from, uc16 to, OutSet* out_set)
+ : from_(from), to_(to), out_set_(out_set) { }
+ uc16 from() { return from_; }
+ uc16 to() { return to_; }
+ void set_to(uc16 value) { to_ = value; }
+ void AddValue(int value) { out_set_ = out_set_->Extend(value); }
+ OutSet* out_set() { return out_set_; }
+ private:
+ uc16 from_;
+ uc16 to_;
+ OutSet* out_set_;
+ };
+
+ class Config {
+ public:
+ typedef uc16 Key;
+ typedef Entry Value;
+ static const uc16 kNoKey;
+ static const Entry kNoValue;
+ static inline int Compare(uc16 a, uc16 b) {
+ if (a == b)
+ return 0;
+ else if (a < b)
+ return -1;
+ else
+ return 1;
+ }
+ };
+
+ void AddRange(CharacterRange range, int value);
+ OutSet* Get(uc16 value);
+ void Dump();
+
+ template <typename Callback>
+ void ForEach(Callback* callback) { return tree()->ForEach(callback); }
+ private:
+ // There can't be a static empty set since it allocates its
+ // successors in a zone and caches them.
+ OutSet* empty() { return &empty_; }
+ OutSet empty_;
+ ZoneSplayTree<Config>* tree() { return &tree_; }
+ ZoneSplayTree<Config> tree_;
+};
+
+
+#define FOR_EACH_NODE_TYPE(VISIT) \
+ VISIT(End) \
+ VISIT(Action) \
+ VISIT(Choice) \
+ VISIT(BackReference) \
+ VISIT(Text)
+
+
+#define FOR_EACH_REG_EXP_TREE_TYPE(VISIT) \
+ VISIT(Disjunction) \
+ VISIT(Alternative) \
+ VISIT(Assertion) \
+ VISIT(CharacterClass) \
+ VISIT(Atom) \
+ VISIT(Quantifier) \
+ VISIT(Capture) \
+ VISIT(Lookahead) \
+ VISIT(BackReference) \
+ VISIT(Empty) \
+ VISIT(Text)
+
+
+#define FORWARD_DECLARE(Name) class RegExp##Name;
+FOR_EACH_REG_EXP_TREE_TYPE(FORWARD_DECLARE)
+#undef FORWARD_DECLARE
+
+
+class TextElement {
+ public:
+ enum Type {UNINITIALIZED, ATOM, CHAR_CLASS};
+ TextElement() : type(UNINITIALIZED) { }
+ explicit TextElement(Type t) : type(t) { }
+ static TextElement Atom(RegExpAtom* atom);
+ static TextElement CharClass(RegExpCharacterClass* char_class);
+ Type type;
+ union {
+ RegExpAtom* u_atom;
+ RegExpCharacterClass* u_char_class;
+ } data;
+};
+
+
+struct NodeInfo {
+ enum TriBool {
+ UNKNOWN = -1, FALSE = 0, TRUE = 1
+ };
+
+ NodeInfo()
+ : being_analyzed(false),
+ been_analyzed(false),
+ being_expanded(false),
+ been_expanded(false),
+ determine_word(false),
+ determine_newline(false),
+ determine_start(false),
+ does_determine_word(false),
+ does_determine_newline(false),
+ does_determine_start(false),
+ follows_word_interest(false),
+ follows_newline_interest(false),
+ follows_start_interest(false),
+ is_word(UNKNOWN),
+ is_newline(UNKNOWN),
+ at_end(false),
+ follows_word(UNKNOWN),
+ follows_newline(UNKNOWN),
+ follows_start(UNKNOWN),
+ visited(false) { }
+
+ // Returns true if the interests and assumptions of this node
+ // matches the given one.
+ bool Matches(NodeInfo* that) {
+ return (at_end == that->at_end) &&
+ (follows_word_interest == that->follows_word_interest) &&
+ (follows_newline_interest == that->follows_newline_interest) &&
+ (follows_start_interest == that->follows_start_interest) &&
+ (follows_word == that->follows_word) &&
+ (follows_newline == that->follows_newline) &&
+ (follows_start == that->follows_start) &&
+ (does_determine_word == that->does_determine_word) &&
+ (does_determine_newline == that->does_determine_newline) &&
+ (does_determine_start == that->does_determine_start);
+ }
+
+ bool HasAssertions() {
+ return (follows_word != UNKNOWN) ||
+ (follows_newline != UNKNOWN) ||
+ (follows_start != UNKNOWN);
+ }
+
+ // Updates the interests of this node given the interests of the
+ // node preceding it.
+ void AddFromPreceding(NodeInfo* that) {
+ at_end |= that->at_end;
+ follows_word_interest |= that->follows_word_interest;
+ follows_newline_interest |= that->follows_newline_interest;
+ follows_start_interest |= that->follows_start_interest;
+ }
+
+ void AddAssumptions(NodeInfo* that) {
+ if (that->follows_word != UNKNOWN) {
+ ASSERT(follows_word == UNKNOWN || follows_word == that->follows_word);
+ follows_word = that->follows_word;
+ }
+ if (that->follows_newline != UNKNOWN) {
+ ASSERT(follows_newline == UNKNOWN ||
+ follows_newline == that->follows_newline);
+ follows_newline = that->follows_newline;
+ }
+ if (that->follows_start != UNKNOWN) {
+ ASSERT(follows_start == UNKNOWN ||
+ follows_start == that->follows_start);
+ follows_start = that->follows_start;
+ }
+ does_determine_word = that->does_determine_word;
+ does_determine_newline = that->does_determine_newline;
+ does_determine_start = that->does_determine_start;
+ }
+
+ // Sets the interests of this node to include the interests of the
+ // following node.
+ void AddFromFollowing(NodeInfo* that) {
+ follows_word_interest |= that->follows_word_interest;
+ follows_newline_interest |= that->follows_newline_interest;
+ follows_start_interest |= that->follows_start_interest;
+ }
+
+ void ResetCompilationState() {
+ being_analyzed = false;
+ been_analyzed = false;
+ being_expanded = false;
+ been_expanded = false;
+ }
+
+ bool being_analyzed: 1;
+ bool been_analyzed: 1;
+ bool being_expanded: 1;
+ bool been_expanded: 1;
+
+ // These bits are set if this node must propagate forward information
+ // about the last character it consumed (or, in the case of 'start',
+ // if it is at the start of the input).
+ bool determine_word: 1;
+ bool determine_newline: 1;
+ bool determine_start: 1;
+
+ bool does_determine_word: 1;
+ bool does_determine_newline: 1;
+ bool does_determine_start: 1;
+
+ // These bits are set of this node has to know what the preceding
+ // character was.
+ bool follows_word_interest: 1;
+ bool follows_newline_interest: 1;
+ bool follows_start_interest: 1;
+
+ TriBool is_word: 2;
+ TriBool is_newline: 2;
+
+ bool at_end: 1;
+
+ // These bits are set if the node can make assumptions about what
+ // the previous character was.
+ TriBool follows_word: 2;
+ TriBool follows_newline: 2;
+ TriBool follows_start: 2;
+
+ bool visited: 1;
+};
+
+
+class ExpansionGuard {
+ public:
+ explicit inline ExpansionGuard(NodeInfo* info) : info_(info) {
+ ASSERT(!info->being_expanded);
+ info->being_expanded = true;
+ }
+ inline ~ExpansionGuard() {
+ info_->being_expanded = false;
+ }
+ private:
+ NodeInfo* info_;
+};
+
+
+class SiblingList {
+ public:
+ SiblingList() : list_(NULL) { }
+ int length() {
+ return list_ == NULL ? 0 : list_->length();
+ }
+ void Ensure(RegExpNode* parent) {
+ if (list_ == NULL) {
+ list_ = new ZoneList<RegExpNode*>(2);
+ list_->Add(parent);
+ }
+ }
+ void Add(RegExpNode* node) { list_->Add(node); }
+ RegExpNode* Get(int index) { return list_->at(index); }
+ private:
+ ZoneList<RegExpNode*>* list_;
+};
+
+
+class RegExpNode: public ZoneObject {
+ public:
+ virtual ~RegExpNode() { }
+ virtual void Accept(NodeVisitor* visitor) = 0;
+ // Generates a goto to this node or actually generates the code at this point.
+ // Until the implementation is complete we will return true for success and
+ // false for failure.
+ virtual bool GoTo(RegExpCompiler* compiler);
+ Label* label();
+
+ // Until the implementation is complete we will return true for success and
+ // false for failure.
+ virtual bool Emit(RegExpCompiler* compiler) = 0;
+
+ RegExpNode* EnsureExpanded(NodeInfo* info);
+ virtual RegExpNode* ExpandLocal(NodeInfo* info) = 0;
+ virtual void ExpandChildren() = 0;
+
+ // Propagates the given interest information forward. When seeing
+ // \bfoo for instance, the \b is implemented by propagating forward
+ // to the 'foo' string that it should only succeed if its first
+ // character is a letter xor the previous character was a letter.
+ virtual RegExpNode* PropagateForward(NodeInfo* info) = 0;
+
+ NodeInfo* info() { return &info_; }
+ virtual bool IsBacktrack() { return false; }
+
+ void AddSibling(RegExpNode* node) { siblings_.Add(node); }
+
+ // Static version of EnsureSibling that expresses the fact that the
+ // result has the same type as the input.
+ template <class C>
+ static C* EnsureSibling(C* node, NodeInfo* info, bool* cloned) {
+ return static_cast<C*>(node->EnsureSibling(info, cloned));
+ }
+
+ SiblingList* siblings() { return &siblings_; }
+ void set_siblings(SiblingList* other) { siblings_ = *other; }
+
+ protected:
+
+ // Returns a sibling of this node whose interests and assumptions
+ // match the ones in the given node info. If no sibling exists NULL
+ // is returned.
+ RegExpNode* TryGetSibling(NodeInfo* info);
+
+ // Returns a sibling of this node whose interests match the ones in
+ // the given node info. The info must not contain any assertions.
+ // If no node exists a new one will be created by cloning the current
+ // node. The result will always be an instance of the same concrete
+ // class as this node.
+ RegExpNode* EnsureSibling(NodeInfo* info, bool* cloned);
+
+ // Returns a clone of this node initialized using the copy constructor
+ // of its concrete class. Note that the node may have to be pre-
+ // processed before it is on a useable state.
+ virtual RegExpNode* Clone() = 0;
+
+ inline void Bind(RegExpMacroAssembler* macro);
+
+ private:
+ Label label_;
+ NodeInfo info_;
+ SiblingList siblings_;
+};
+
+
+class SeqRegExpNode: public RegExpNode {
+ public:
+ explicit SeqRegExpNode(RegExpNode* on_success)
+ : on_success_(on_success) { }
+ RegExpNode* on_success() { return on_success_; }
+ void set_on_success(RegExpNode* node) { on_success_ = node; }
+ virtual bool Emit(RegExpCompiler* compiler) { return false; }
+ private:
+ RegExpNode* on_success_;
+};
+
+
+class ActionNode: public SeqRegExpNode {
+ public:
+ enum Type {
+ STORE_REGISTER,
+ INCREMENT_REGISTER,
+ STORE_POSITION,
+ RESTORE_POSITION,
+ BEGIN_SUBMATCH,
+ ESCAPE_SUBMATCH
+ };
+ static ActionNode* StoreRegister(int reg, int val, RegExpNode* on_success);
+ static ActionNode* IncrementRegister(int reg, RegExpNode* on_success);
+ static ActionNode* StorePosition(int reg, RegExpNode* on_success);
+ static ActionNode* RestorePosition(int reg, RegExpNode* on_success);
+ static ActionNode* BeginSubmatch(int stack_pointer_reg,
+ int position_reg,
+ RegExpNode* on_success);
+ static ActionNode* EscapeSubmatch(int stack_pointer_reg,
+ bool and_restore_position,
+ int restore_reg,
+ RegExpNode* on_success);
+ virtual void Accept(NodeVisitor* visitor);
+ virtual bool Emit(RegExpCompiler* compiler);
+ virtual RegExpNode* ExpandLocal(NodeInfo* info);
+ virtual void ExpandChildren();
+ virtual RegExpNode* PropagateForward(NodeInfo* info);
+ virtual ActionNode* Clone() { return new ActionNode(*this); }
+
+ private:
+ union {
+ struct {
+ int reg;
+ int value;
+ } u_store_register;
+ struct {
+ int reg;
+ } u_increment_register;
+ struct {
+ int reg;
+ } u_position_register;
+ struct {
+ int stack_pointer_register;
+ int current_position_register;
+ } u_submatch;
+ } data_;
+ ActionNode(Type type, RegExpNode* on_success)
+ : SeqRegExpNode(on_success),
+ type_(type) { }
+ Type type_;
+ friend class DotPrinter;
+};
+
+
+class TextNode: public SeqRegExpNode {
+ public:
+ TextNode(ZoneList<TextElement>* elms,
+ RegExpNode* on_success,
+ RegExpNode* on_failure)
+ : SeqRegExpNode(on_success),
+ on_failure_(on_failure),
+ elms_(elms) { }
+ TextNode(RegExpCharacterClass* that,
+ RegExpNode* on_success,
+ RegExpNode* on_failure)
+ : SeqRegExpNode(on_success),
+ on_failure_(on_failure),
+ elms_(new ZoneList<TextElement>(1)) {
+ elms_->Add(TextElement::CharClass(that));
+ }
+ virtual void Accept(NodeVisitor* visitor);
+ virtual RegExpNode* PropagateForward(NodeInfo* info);
+ virtual RegExpNode* ExpandLocal(NodeInfo* info);
+ virtual void ExpandChildren();
+ RegExpNode* on_failure() { return on_failure_; }
+ virtual bool Emit(RegExpCompiler* compiler);
+ ZoneList<TextElement>* elements() { return elms_; }
+ void MakeCaseIndependent();
+ virtual TextNode* Clone() { return new TextNode(*this); }
+
+ private:
+ void ExpandAtomChildren(RegExpAtom* that);
+ void ExpandCharClassChildren(RegExpCharacterClass* that);
+
+ RegExpNode* on_failure_;
+ ZoneList<TextElement>* elms_;
+};
+
+
+class BackReferenceNode: public SeqRegExpNode {
+ public:
+ BackReferenceNode(int start_reg,
+ int end_reg,
+ RegExpNode* on_success,
+ RegExpNode* on_failure)
+ : SeqRegExpNode(on_success),
+ on_failure_(on_failure),
+ start_reg_(start_reg),
+ end_reg_(end_reg) { }
+ virtual void Accept(NodeVisitor* visitor);
+ RegExpNode* on_failure() { return on_failure_; }
+ int start_register() { return start_reg_; }
+ int end_register() { return end_reg_; }
+ virtual bool Emit(RegExpCompiler* compiler);
+ virtual RegExpNode* PropagateForward(NodeInfo* info);
+ virtual RegExpNode* ExpandLocal(NodeInfo* info);
+ virtual void ExpandChildren();
+ virtual BackReferenceNode* Clone() { return new BackReferenceNode(*this); }
+
+ private:
+ RegExpNode* on_failure_;
+ int start_reg_;
+ int end_reg_;
+};
+
+
+class EndNode: public RegExpNode {
+ public:
+ enum Action { ACCEPT, BACKTRACK };
+ explicit EndNode(Action action) : action_(action) { }
+ virtual void Accept(NodeVisitor* visitor);
+ virtual bool Emit(RegExpCompiler* compiler);
+ virtual RegExpNode* PropagateForward(NodeInfo* info);
+ virtual RegExpNode* ExpandLocal(NodeInfo* info);
+ virtual void ExpandChildren();
+ virtual bool IsBacktrack() { return action_ == BACKTRACK; }
+ virtual bool GoTo(RegExpCompiler* compiler);
+ virtual EndNode* Clone() { return new EndNode(*this); }
+
+ private:
+ Action action_;
+};
+
+
+class Guard: public ZoneObject {
+ public:
+ enum Relation { LT, GEQ };
+ Guard(int reg, Relation op, int value)
+ : reg_(reg),
+ op_(op),
+ value_(value) { }
+ int reg() { return reg_; }
+ Relation op() { return op_; }
+ int value() { return value_; }
+
+ private:
+ int reg_;
+ Relation op_;
+ int value_;
+};
+
+
+class GuardedAlternative {
+ public:
+ explicit GuardedAlternative(RegExpNode* node) : node_(node), guards_(NULL) { }
+ void AddGuard(Guard* guard);
+ RegExpNode* node() { return node_; }
+ void set_node(RegExpNode* node) { node_ = node; }
+ ZoneList<Guard*>* guards() { return guards_; }
+
+ private:
+ RegExpNode* node_;
+ ZoneList<Guard*>* guards_;
+};
+
+
+class ChoiceNode: public RegExpNode {
+ public:
+ explicit ChoiceNode(int expected_size, RegExpNode* on_failure)
+ : on_failure_(on_failure),
+ alternatives_(new ZoneList<GuardedAlternative>(expected_size)),
+ table_(NULL),
+ being_calculated_(false) { }
+ virtual void Accept(NodeVisitor* visitor);
+ void AddAlternative(GuardedAlternative node) { alternatives()->Add(node); }
+ ZoneList<GuardedAlternative>* alternatives() { return alternatives_; }
+ DispatchTable* GetTable(bool ignore_case);
+ RegExpNode* on_failure() { return on_failure_; }
+ virtual bool Emit(RegExpCompiler* compiler);
+ virtual RegExpNode* PropagateForward(NodeInfo* info);
+ virtual RegExpNode* ExpandLocal(NodeInfo* info);
+ virtual void ExpandChildren();
+ virtual ChoiceNode* Clone() { return new ChoiceNode(*this); }
+
+ bool being_calculated() { return being_calculated_; }
+ void set_being_calculated(bool b) { being_calculated_ = b; }
+
+ private:
+ friend class DispatchTableConstructor;
+ friend class Analysis;
+ void GenerateGuard(RegExpMacroAssembler* macro_assembler,
+ Guard *guard,
+ Label* on_failure);
+ RegExpNode* on_failure_;
+ ZoneList<GuardedAlternative>* alternatives_;
+ DispatchTable* table_;
+ bool being_calculated_;
+};
+
+
+class NodeVisitor {
+ public:
+ virtual ~NodeVisitor() { }
+#define DECLARE_VISIT(Type) \
+ virtual void Visit##Type(Type##Node* that) = 0;
+FOR_EACH_NODE_TYPE(DECLARE_VISIT)
+#undef DECLARE_VISIT
+};
+
+
+// Node visitor used to add the start set of the alternatives to the
+// dispatch table of a choice node.
+class DispatchTableConstructor: public NodeVisitor {
+ public:
+ DispatchTableConstructor(DispatchTable* table, bool ignore_case)
+ : table_(table),
+ choice_index_(-1),
+ ignore_case_(ignore_case) { }
+
+ void BuildTable(ChoiceNode* node);
+
+ void AddRange(CharacterRange range) {
+ table()->AddRange(range, choice_index_);
+ }
+
+ void AddInverse(ZoneList<CharacterRange>* ranges);
+
+#define DECLARE_VISIT(Type) \
+ virtual void Visit##Type(Type##Node* that);
+FOR_EACH_NODE_TYPE(DECLARE_VISIT)
+#undef DECLARE_VISIT
+
+ DispatchTable* table() { return table_; }
+ void set_choice_index(int value) { choice_index_ = value; }
+
+ protected:
+ DispatchTable *table_;
+ int choice_index_;
+ bool ignore_case_;
+};
+
+
+class Analysis: public NodeVisitor {
+ public:
+ explicit Analysis(bool ignore_case)
+ : ignore_case_(ignore_case) { }
+ void EnsureAnalyzed(RegExpNode* node);
+
+#define DECLARE_VISIT(Type) \
+ virtual void Visit##Type(Type##Node* that);
+FOR_EACH_NODE_TYPE(DECLARE_VISIT)
+#undef DECLARE_VISIT
+
+ private:
+ bool ignore_case_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(Analysis);
+};
+
+
+struct RegExpParseResult {
+ RegExpTree* tree;
+ bool has_character_escapes;
+ Handle<String> error;
+ int capture_count;
+};
+
+
+class RegExpEngine: public AllStatic {
+ public:
+ static Handle<FixedArray> Compile(RegExpParseResult* input,
+ RegExpNode** node_return,
+ bool ignore_case,
+ bool multiline);
+ static void DotPrint(const char* label, RegExpNode* node, bool ignore_case);
+};
+
+
} } // namespace v8::internal
#endif // V8_JSREGEXP_H_
diff --git a/src/list-inl.h b/src/list-inl.h
index a185af3..790bdd8 100644
--- a/src/list-inl.h
+++ b/src/list-inl.h
@@ -90,11 +90,18 @@
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);
@@ -103,6 +110,12 @@
template<typename T, class P>
+void List<T, P>::Sort() {
+ Sort(PointerValueCompare<T>);
+}
+
+
+template<typename T, class P>
void List<T, P>::Initialize(int capacity) {
ASSERT(capacity >= 0);
data_ = (capacity > 0) ? NewData(capacity) : NULL;
diff --git a/src/list.h b/src/list.h
index 34b18fb..2f8aa90 100644
--- a/src/list.h
+++ b/src/list.h
@@ -46,6 +46,7 @@
template <typename T, class P>
class List {
public:
+
INLINE(explicit List(int capacity)) { Initialize(capacity); }
INLINE(~List()) { DeleteData(data_); }
@@ -67,6 +68,8 @@
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 @@
// 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));
diff --git a/src/log.cc b/src/log.cc
index 803dfe8..d145480 100644
--- a/src/log.cc
+++ b/src/log.cc
@@ -356,12 +356,14 @@
len = 256;
for (int i = 0; i < len; i++) {
uc32 c = str->Get(shape, i);
- if (c < 32 || (c > 126 && c <= 255)) {
- fprintf(logfile_, "\\x%02x", c);
- } else if (c > 255) {
+ if (c > 0xff) {
fprintf(logfile_, "\\u%04x", c);
+ } else if (c < 32 || c > 126) {
+ fprintf(logfile_, "\\x%02x", c);
} else if (c == ',') {
fprintf(logfile_, "\\,");
+ } else if (c == '\\') {
+ fprintf(logfile_, "\\\\");
} else {
fprintf(logfile_, "%lc", c);
}
diff --git a/src/macro-assembler-arm.cc b/src/macro-assembler-arm.cc
index 616a9bf..7016145 100644
--- a/src/macro-assembler-arm.cc
+++ b/src/macro-assembler-arm.cc
@@ -846,6 +846,40 @@
}
+void MacroAssembler::SetCounter(StatsCounter* counter, int value,
+ Register scratch1, Register scratch2) {
+ if (FLAG_native_code_counters && counter->Enabled()) {
+ mov(scratch1, Operand(value));
+ mov(scratch2, Operand(ExternalReference(counter)));
+ str(scratch1, MemOperand(scratch2));
+ }
+}
+
+
+void MacroAssembler::IncrementCounter(StatsCounter* counter, int value,
+ Register scratch1, Register scratch2) {
+ ASSERT(value > 0);
+ if (FLAG_native_code_counters && counter->Enabled()) {
+ mov(scratch2, Operand(ExternalReference(counter)));
+ ldr(scratch1, MemOperand(scratch2));
+ add(scratch1, scratch1, Operand(value));
+ str(scratch1, MemOperand(scratch2));
+ }
+}
+
+
+void MacroAssembler::DecrementCounter(StatsCounter* counter, int value,
+ Register scratch1, Register scratch2) {
+ ASSERT(value > 0);
+ if (FLAG_native_code_counters && counter->Enabled()) {
+ mov(scratch2, Operand(ExternalReference(counter)));
+ ldr(scratch1, MemOperand(scratch2));
+ sub(scratch1, scratch1, Operand(value));
+ str(scratch1, MemOperand(scratch2));
+ }
+}
+
+
void MacroAssembler::Assert(Condition cc, const char* msg) {
if (FLAG_debug_code)
Check(cc, msg);
diff --git a/src/macro-assembler-arm.h b/src/macro-assembler-arm.h
index 956cd71..7cc843f 100644
--- a/src/macro-assembler-arm.h
+++ b/src/macro-assembler-arm.h
@@ -231,6 +231,17 @@
// ---------------------------------------------------------------------------
+ // StatsCounter support
+
+ void SetCounter(StatsCounter* counter, int value,
+ Register scratch1, Register scratch2);
+ void IncrementCounter(StatsCounter* counter, int value,
+ Register scratch1, Register scratch2);
+ void DecrementCounter(StatsCounter* counter, int value,
+ Register scratch1, Register scratch2);
+
+
+ // ---------------------------------------------------------------------------
// Debugging
// Calls Abort(msg) if the condition cc is not satisfied.
diff --git a/src/macro-assembler.h b/src/macro-assembler.h
index f289346..84a1eef 100644
--- a/src/macro-assembler.h
+++ b/src/macro-assembler.h
@@ -28,7 +28,7 @@
#ifndef V8_MACRO_ASSEMBLER_H_
#define V8_MACRO_ASSEMBLER_H_
-#if defined(ARM) || defined (__arm__) || defined(__thumb__)
+#ifdef ARM
#include "constants-arm.h"
#include "assembler.h"
diff --git a/src/messages.js b/src/messages.js
index 531c710..8aa2914 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -112,6 +112,7 @@
illegal_continue: "Illegal continue statement",
illegal_return: "Illegal return statement",
error_loading_debugger: "Error loading debugger %0",
+ no_input_to_regexp: "No input to %0",
};
diff --git a/src/mksnapshot.cc b/src/mksnapshot.cc
index 7fb4490..441ae18 100644
--- a/src/mksnapshot.cc
+++ b/src/mksnapshot.cc
@@ -48,10 +48,10 @@
class Counter {
public:
static const int kMaxNameSize = 64;
- int32_t* Bind(const wchar_t* name) {
+ int32_t* Bind(const char* name) {
int i;
for (i = 0; i < kMaxNameSize - 1 && name[i]; i++) {
- name_[i] = static_cast<char>(name[i]);
+ name_[i] = name[i];
}
name_[i] = '\0';
return &counter_;
@@ -92,13 +92,13 @@
static CounterCollection* counters = &local_counters;
-typedef std::map<std::wstring, int*> CounterMap;
-typedef std::map<std::wstring, int*>::iterator CounterMapIterator;
+typedef std::map<std::string, int*> CounterMap;
+typedef std::map<std::string, int*>::iterator CounterMapIterator;
static CounterMap counter_table_;
// Callback receiver when v8 has a counter to track.
-static int* counter_callback(const wchar_t* name) {
- std::wstring counter = name;
+static int* counter_callback(const char* name) {
+ std::string counter = name;
// See if this counter name is already known.
if (counter_table_.find(counter) != counter_table_.end())
return counter_table_[counter];
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index f2dd3b5..1c1ffed 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -670,7 +670,14 @@
}
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:
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 97c6819..e8c4e91 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -279,6 +279,16 @@
}
+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 @@
}
+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 @@
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::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);
diff --git a/src/objects.cc b/src/objects.cc
index 511f9f7..6068898 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -3501,6 +3501,57 @@
}
+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_);
}
@@ -5745,8 +5796,8 @@
class RegExpKey : public HashTableKey {
public:
RegExpKey(String* string, JSRegExp::Flags flags)
- : string_(string),
- flags_(Smi::FromInt(flags.value())) { }
+ : string_(string),
+ flags_(Smi::FromInt(flags.value())) { }
bool IsMatch(Object* obj) {
FixedArray* val = FixedArray::cast(obj);
@@ -5806,9 +5857,7 @@
Object* GetObject() {
if (length_field_ == 0) Hash();
- unibrow::Utf8InputBuffer<> buffer(string_.start(),
- static_cast<unsigned>(string_.length()));
- return Heap::AllocateSymbol(&buffer, chars_, length_field_);
+ return Heap::AllocateSymbol(string_, chars_, length_field_);
}
static uint32_t StringHash(Object* obj) {
@@ -5857,9 +5906,9 @@
}
// Otherwise allocate a new symbol.
StringInputBuffer buffer(string_);
- return Heap::AllocateSymbol(&buffer,
- string_->length(),
- string_->length_field());
+ return Heap::AllocateInternalSymbol(&buffer,
+ string_->length(),
+ string_->length_field());
}
static uint32_t StringHash(Object* obj) {
@@ -6139,7 +6188,7 @@
class MapNameKey : public HashTableKey {
public:
MapNameKey(Map* map, String* name)
- : map_(map), name_(name) { }
+ : map_(map), name_(name) { }
bool IsMatch(Object* other) {
if (!other->IsFixedArray()) return false;
diff --git a/src/objects.h b/src/objects.h
index 82edc53..f6feca8 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -1498,9 +1498,12 @@
// 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 @@
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 @@
static const int kFlagsTypeMask = 0x000001C0; // 111000000
static const int kFlagsArgumentsCountMask = 0xFFFFFE00;
-
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(Code);
};
@@ -2912,7 +2917,13 @@
// 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 @@
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 @@
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 @@
};
+// 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.
diff --git a/src/parser.cc b/src/parser.cc
index bcc439f..8217315 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -34,6 +34,7 @@
#include "runtime.h"
#include "parser.h"
#include "scopes.h"
+#include "string-stream.h"
namespace v8 { namespace internal {
@@ -227,6 +228,335 @@
};
+template <typename T, int initial_size>
+class BufferedZoneList {
+ public:
+
+ BufferedZoneList() :
+ list_(NULL), last_(NULL) {}
+
+ // Adds element at end of list. This element is buffered and can
+ // be read using last() or removed using RemoveLast until a new Add or until
+ // RemoveLast or GetList has been called.
+ void Add(T* value) {
+ if (last_ != NULL) {
+ if (list_ == NULL) {
+ list_ = new ZoneList<T*>(initial_size);
+ }
+ list_->Add(last_);
+ }
+ last_ = value;
+ }
+
+ T* last() {
+ ASSERT(last_ != NULL);
+ return last_;
+ }
+
+ T* RemoveLast() {
+ ASSERT(last_ != NULL);
+ T* result = last_;
+ if (list_ != NULL && list_->length() > 0)
+ last_ = list_->RemoveLast();
+ else
+ last_ = NULL;
+ return result;
+ }
+
+ T* Get(int i) {
+ ASSERT(0 <= i && i < length());
+ if (list_ == NULL) {
+ ASSERT_EQ(0, i);
+ return last_;
+ } else {
+ if (i == list_->length()) {
+ ASSERT(last_ != NULL);
+ return last_;
+ } else {
+ return list_->at(i);
+ }
+ }
+ }
+
+ void Clear() {
+ list_ = NULL;
+ last_ = NULL;
+ }
+
+ int length() {
+ int length = (list_ == NULL) ? 0 : list_->length();
+ return length + ((last_ == NULL) ? 0 : 1);
+ }
+
+ ZoneList<T*>* GetList() {
+ if (list_ == NULL) {
+ list_ = new ZoneList<T*>(initial_size);
+ }
+ if (last_ != NULL) {
+ list_->Add(last_);
+ last_ = NULL;
+ }
+ return list_;
+ }
+
+ private:
+ ZoneList<T*>* list_;
+ T* last_;
+};
+
+// Accumulates RegExp atoms and assertions into lists of terms and alternatives.
+class RegExpBuilder {
+ public:
+ RegExpBuilder();
+ void AddCharacter(uc16 character);
+ // "Adds" an empty expression. Does nothing except consume a
+ // following quantifier
+ void AddEmpty();
+ void AddAtom(RegExpTree* tree);
+ void AddAssertion(RegExpTree* tree);
+ void NewAlternative(); // '|'
+ void AddQuantifierToAtom(int min, int max, bool is_greedy);
+ RegExpTree* ToRegExp();
+ private:
+ void FlushCharacters();
+ void FlushText();
+ void FlushTerms();
+ bool pending_empty_;
+ ZoneList<uc16>* characters_;
+ BufferedZoneList<RegExpTree, 2> terms_;
+ BufferedZoneList<RegExpTree, 2> text_;
+ BufferedZoneList<RegExpTree, 2> alternatives_;
+#ifdef DEBUG
+ enum {ADD_NONE, ADD_CHAR, ADD_TERM, ADD_ASSERT, ADD_ATOM} last_added_;
+#define LAST(x) last_added_ = x;
+#else
+#define LAST(x)
+#endif
+};
+
+
+RegExpBuilder::RegExpBuilder()
+ : pending_empty_(false), characters_(NULL), terms_(), alternatives_()
+#ifdef DEBUG
+ , last_added_(ADD_NONE)
+#endif
+ {}
+
+
+void RegExpBuilder::FlushCharacters() {
+ pending_empty_ = false;
+ if (characters_ != NULL) {
+ RegExpTree* atom = new RegExpAtom(characters_->ToConstVector());
+ characters_ = NULL;
+ text_.Add(atom);
+ LAST(ADD_ATOM);
+ }
+}
+
+
+void RegExpBuilder::FlushText() {
+ FlushCharacters();
+ int num_text = text_.length();
+ if (num_text == 0) {
+ return;
+ } else if (num_text == 1) {
+ terms_.Add(text_.last());
+ } else {
+ RegExpText* text = new RegExpText();
+ for (int i = 0; i < num_text; i++)
+ text_.Get(i)->AppendToText(text);
+ terms_.Add(text);
+ }
+ text_.Clear();
+}
+
+
+void RegExpBuilder::AddCharacter(uc16 c) {
+ pending_empty_ = false;
+ if (characters_ == NULL) {
+ characters_ = new ZoneList<uc16>(4);
+ }
+ characters_->Add(c);
+ LAST(ADD_CHAR);
+}
+
+
+void RegExpBuilder::AddEmpty() {
+ pending_empty_ = true;
+}
+
+
+void RegExpBuilder::AddAtom(RegExpTree* term) {
+ if (term->IsEmpty()) {
+ AddEmpty();
+ return;
+ }
+ if (term->IsTextElement()) {
+ FlushCharacters();
+ text_.Add(term);
+ } else {
+ FlushText();
+ terms_.Add(term);
+ }
+ LAST(ADD_ATOM);
+}
+
+
+void RegExpBuilder::AddAssertion(RegExpTree* assert) {
+ FlushText();
+ terms_.Add(assert);
+ LAST(ADD_ASSERT);
+}
+
+
+void RegExpBuilder::NewAlternative() {
+ FlushTerms();
+}
+
+
+void RegExpBuilder::FlushTerms() {
+ FlushText();
+ int num_terms = terms_.length();
+ RegExpTree* alternative;
+ if (num_terms == 0) {
+ alternative = RegExpEmpty::GetInstance();
+ } else if (num_terms == 1) {
+ alternative = terms_.last();
+ } else {
+ alternative = new RegExpAlternative(terms_.GetList());
+ }
+ alternatives_.Add(alternative);
+ terms_.Clear();
+ LAST(ADD_NONE);
+}
+
+
+RegExpTree* RegExpBuilder::ToRegExp() {
+ FlushTerms();
+ int num_alternatives = alternatives_.length();
+ if (num_alternatives == 0) {
+ return RegExpEmpty::GetInstance();
+ }
+ if (num_alternatives == 1) {
+ return alternatives_.last();
+ }
+ return new RegExpDisjunction(alternatives_.GetList());
+}
+
+
+void RegExpBuilder::AddQuantifierToAtom(int min, int max, bool is_greedy) {
+ if (pending_empty_) {
+ pending_empty_ = false;
+ return;
+ }
+ RegExpTree* atom;
+ if (characters_ != NULL) {
+ ASSERT(last_added_ == ADD_CHAR);
+ // Last atom was character.
+ Vector<const uc16> char_vector = characters_->ToConstVector();
+ int num_chars = char_vector.length();
+ if (num_chars > 1) {
+ Vector<const uc16> prefix = char_vector.SubVector(0, num_chars - 1);
+ text_.Add(new RegExpAtom(prefix));
+ char_vector = char_vector.SubVector(num_chars - 1, num_chars);
+ }
+ characters_ = NULL;
+ atom = new RegExpAtom(char_vector);
+ FlushText();
+ } else if (text_.length() > 0) {
+ ASSERT(last_added_ == ADD_ATOM);
+ atom = text_.RemoveLast();
+ FlushText();
+ } else if (terms_.length() > 0) {
+ ASSERT(last_added_ == ADD_ATOM);
+ atom = terms_.RemoveLast();
+ if (atom->IsLookahead() || atom->IsAssertion()) {
+ // Guaranteed not to match a non-empty string.
+ // Assertion as an atom can happen as, e.g., (?:\b)
+ LAST(ADD_TERM);
+ if (min == 0) {
+ return;
+ }
+ terms_.Add(atom);
+ return;
+ }
+ } else {
+ // Only call immediately after adding an atom or character!
+ UNREACHABLE();
+ return;
+ }
+ terms_.Add(new RegExpQuantifier(min, max, is_greedy, atom));
+ LAST(ADD_TERM);
+}
+
+
+class RegExpParser {
+ public:
+ RegExpParser(FlatStringReader* in,
+ Handle<String>* error,
+ bool multiline_mode);
+ RegExpTree* ParsePattern();
+ RegExpTree* ParseDisjunction();
+ RegExpTree* ParseGroup();
+ RegExpTree* ParseCharacterClass();
+
+ // Parses a {...,...} quantifier and stores the range in the given
+ // out parameters.
+ bool ParseIntervalQuantifier(int* min_out, int* max_out);
+
+ // Parses and returns a single escaped character. The character
+ // must not be 'b' or 'B' since they are usually handle specially.
+ uc32 ParseClassCharacterEscape();
+
+ // Checks whether the following is a length-digit hexadecimal number,
+ // and sets the value if it is.
+ bool ParseHexEscape(int length, uc32* value);
+
+ uc32 ParseControlLetterEscape();
+ uc32 ParseOctalLiteral();
+
+ // Tries to parse the input as a back reference. If successful it
+ // stores the result in the output parameter and returns true. If
+ // it fails it will push back the characters read so the same characters
+ // can be reparsed.
+ bool ParseBackReferenceIndex(int* index_out);
+
+ CharacterRange ParseClassAtom(uc16* char_class);
+ RegExpTree* ReportError(Vector<const char> message);
+ void Advance();
+ void Advance(int dist);
+ void Reset(int pos);
+
+ bool HasCharacterEscapes();
+
+ int captures_started() { return captures_ == NULL ? 0 : captures_->length(); }
+ int position() { return next_pos_ - 1; }
+ bool failed() { return failed_; }
+
+ static const uc32 kEndMarker = (1 << 21);
+ private:
+ uc32 current() { return current_; }
+ bool has_more() { return has_more_; }
+ bool has_next() { return next_pos_ < in()->length(); }
+ uc32 Next();
+ FlatStringReader* in() { return in_; }
+ void ScanForCaptures();
+ bool CaptureAvailable(int index);
+ uc32 current_;
+ bool has_more_;
+ bool multiline_;
+ int next_pos_;
+ FlatStringReader* in_;
+ Handle<String>* error_;
+ bool has_character_escapes_;
+ ZoneList<RegExpCapture*>* captures_;
+ bool is_scanned_for_captures_;
+ // The capture count is only valid after we have scanned for captures.
+ int capture_count_;
+ bool failed_;
+};
+
+
// A temporary scope stores information during parsing, just like
// a plain scope. However, temporary scopes are not kept around
// after parsing or referenced by syntax trees so they can be stack-
@@ -337,10 +667,16 @@
virtual Expression* NewCall(Expression* expression,
ZoneList<Expression*>* arguments,
- bool is_eval, int pos) {
+ int pos) {
return Call::sentinel();
}
+ virtual Expression* NewCallEval(Expression* expression,
+ ZoneList<Expression*>* arguments,
+ int pos) {
+ return CallEval::sentinel();
+ }
+
virtual Statement* EmptyStatement() {
return NULL;
}
@@ -387,8 +723,14 @@
virtual Expression* NewCall(Expression* expression,
ZoneList<Expression*>* arguments,
- bool is_eval, int pos) {
- return new Call(expression, arguments, is_eval, pos);
+ int pos) {
+ return new Call(expression, arguments, pos);
+ }
+
+ virtual Expression* NewCallEval(Expression* expression,
+ ZoneList<Expression*>* arguments,
+ int pos) {
+ return new CallEval(expression, arguments, pos);
}
virtual Statement* EmptyStatement() {
@@ -686,6 +1028,11 @@
#define DUMMY ) // to make indentation work
#undef DUMMY
+#define CHECK_FAILED /**/); \
+ if (failed_) return NULL; \
+ ((void)0
+#define DUMMY ) // to make indentation work
+#undef DUMMY
// ----------------------------------------------------------------------------
// Implementation of Parser
@@ -1013,7 +1360,7 @@
// to the calling function context.
if (top_scope_->is_function_scope()) {
// Declare the variable in the function scope.
- var = top_scope_->Lookup(name);
+ var = top_scope_->LookupLocal(name);
if (var == NULL) {
// Declare the name.
var = top_scope_->Declare(name, mode);
@@ -2294,55 +2641,34 @@
ZoneList<Expression*>* args = ParseArguments(CHECK_OK);
// Keep track of eval() calls since they disable all local variable
- // optimizations. We can ignore locally declared variables with
- // name 'eval' since they override the global 'eval' function. We
- // only need to look at unresolved variables (VariableProxies).
+ // optimizations.
+ // The calls that need special treatment are the
+ // direct (i.e. not aliased) eval calls. These calls are all of the
+ // form eval(...) with no explicit receiver object where eval is not
+ // declared in the current scope chain. These calls are marked as
+ // potentially direct eval calls. Whether they are actually direct calls
+ // to eval is determined at run time.
+ bool is_potentially_direct_eval = false;
if (!is_pre_parsing_) {
- // We assume that only a function called 'eval' can be used
- // to invoke the global eval() implementation. This permits
- // for massive optimizations.
VariableProxy* callee = result->AsVariableProxy();
if (callee != NULL && callee->IsVariable(Factory::eval_symbol())) {
- // We do not allow direct calls to 'eval' in our internal
- // JS files. Use builtin functions instead.
- ASSERT(!Bootstrapper::IsActive());
- top_scope_->RecordEvalCall();
- } else {
- // This is rather convoluted code to check if we're calling
- // a function named 'eval' through a property access. If so,
- // we mark it as a possible eval call (we don't know if the
- // receiver will resolve to the global object or not), but
- // we do not treat the call as an eval() call - we let the
- // call get through to the JavaScript eval code defined in
- // v8natives.js.
- Property* property = result->AsProperty();
- if (property != NULL) {
- Literal* key = property->key()->AsLiteral();
- if (key != NULL &&
- key->handle().is_identical_to(Factory::eval_symbol())) {
- // We do not allow direct calls to 'eval' in our
- // internal JS files. Use builtin functions instead.
- ASSERT(!Bootstrapper::IsActive());
- top_scope_->RecordEvalCall();
- }
+ Handle<String> name = callee->name();
+ Variable* var = top_scope_->Lookup(name);
+ if (var == NULL) {
+ // We do not allow direct calls to 'eval' in our internal
+ // JS files. Use builtin functions instead.
+ ASSERT(!Bootstrapper::IsActive());
+ top_scope_->RecordEvalCall();
+ is_potentially_direct_eval = true;
}
}
}
- // Optimize the eval() case w/o arguments so we
- // don't need to handle it every time at runtime.
- //
- // Note: For now we don't do static eval analysis
- // as it appears that we need to be able to call
- // eval() via alias names. We leave the code as
- // is, in case we want to enable this again in the
- // future.
- const bool is_eval = false;
- if (is_eval && args->length() == 0) {
- result = NEW(Literal(Factory::undefined_value()));
+ if (is_potentially_direct_eval) {
+ result = factory()->NewCallEval(result, args, pos);
} else {
- result = factory()->NewCall(result, args, is_eval, pos);
+ result = factory()->NewCall(result, args, pos);
}
break;
}
@@ -3164,6 +3490,769 @@
// ----------------------------------------------------------------------------
+// Regular expressions
+
+
+RegExpParser::RegExpParser(FlatStringReader* in,
+ Handle<String>* error,
+ bool multiline)
+ : current_(kEndMarker),
+ has_more_(true),
+ multiline_(multiline),
+ next_pos_(0),
+ in_(in),
+ error_(error),
+ has_character_escapes_(false),
+ captures_(NULL),
+ is_scanned_for_captures_(false),
+ capture_count_(0),
+ failed_(false) {
+ Advance(1);
+}
+
+
+uc32 RegExpParser::Next() {
+ if (has_next()) {
+ return in()->Get(next_pos_);
+ } else {
+ return kEndMarker;
+ }
+}
+
+
+void RegExpParser::Advance() {
+ if (next_pos_ < in()->length()) {
+ StackLimitCheck check;
+ if (check.HasOverflowed()) {
+ ReportError(CStrVector(Top::kStackOverflowMessage));
+ } else if (Zone::excess_allocation()) {
+ ReportError(CStrVector("Regular expression too large"));
+ } else {
+ current_ = in()->Get(next_pos_);
+ next_pos_++;
+ }
+ } else {
+ current_ = kEndMarker;
+ has_more_ = false;
+ }
+}
+
+
+void RegExpParser::Reset(int pos) {
+ next_pos_ = pos;
+ Advance();
+}
+
+
+void RegExpParser::Advance(int dist) {
+ for (int i = 0; i < dist; i++)
+ Advance();
+}
+
+
+// Reports whether the parsed string atoms contain any characters that were
+// escaped in the original pattern. If not, all atoms are proper substrings
+// of the original pattern.
+bool RegExpParser::HasCharacterEscapes() {
+ return has_character_escapes_;
+}
+
+RegExpTree* RegExpParser::ReportError(Vector<const char> message) {
+ failed_ = true;
+ *error_ = Factory::NewStringFromAscii(message, NOT_TENURED);
+ // Zip to the end to make sure the no more input is read.
+ current_ = kEndMarker;
+ next_pos_ = in()->length();
+ return NULL;
+}
+
+
+// Pattern ::
+// Disjunction
+RegExpTree* RegExpParser::ParsePattern() {
+ RegExpTree* result = ParseDisjunction(CHECK_FAILED);
+ if (has_more()) {
+ ReportError(CStrVector("Unmatched ')'") CHECK_FAILED);
+ }
+ return result;
+}
+
+
+bool RegExpParser::CaptureAvailable(int index) {
+ if (captures_ == NULL) return false;
+ if (index >= captures_->length()) return false;
+ RegExpCapture* capture = captures_->at(index);
+ return capture != NULL && capture->available() == CAPTURE_AVAILABLE;
+}
+
+
+// Disjunction ::
+// Alternative
+// Alternative | Disjunction
+// Alternative ::
+// [empty]
+// Term Alternative
+// Term ::
+// Assertion
+// Atom
+// Atom Quantifier
+RegExpTree* RegExpParser::ParseDisjunction() {
+ RegExpBuilder builder;
+ int capture_start_index = captures_started();
+ while (true) {
+ switch (current()) {
+ case kEndMarker:
+ case ')':
+ return builder.ToRegExp();
+ case '|': {
+ Advance();
+ builder.NewAlternative();
+ int capture_new_alt_start_index = captures_started();
+ for (int i = capture_start_index; i < capture_new_alt_start_index; i++) {
+ RegExpCapture* capture = captures_->at(i);
+ if (capture->available() == CAPTURE_AVAILABLE) {
+ capture->set_available(CAPTURE_UNREACHABLE);
+ }
+ }
+ capture_start_index = capture_new_alt_start_index;
+ continue;
+ }
+ case '*':
+ case '+':
+ case '?':
+ ReportError(CStrVector("Nothing to repeat") CHECK_FAILED);
+ case '^': {
+ Advance();
+ RegExpAssertion::Type type =
+ multiline_ ? RegExpAssertion::START_OF_LINE :
+ RegExpAssertion::START_OF_INPUT;
+ builder.AddAssertion(new RegExpAssertion(type));
+ continue;
+ }
+ case '$': {
+ Advance();
+ RegExpAssertion::Type type =
+ multiline_ ? RegExpAssertion::END_OF_LINE :
+ RegExpAssertion::END_OF_INPUT;
+ builder.AddAssertion(new RegExpAssertion(type));
+ continue;
+ }
+ case '.': {
+ Advance();
+ // everything except \x0a, \x0d, \u2028 and \u2029
+ ZoneList<CharacterRange>* ranges = new ZoneList<CharacterRange>(2);
+ CharacterRange::AddClassEscape('.', ranges);
+ RegExpTree* atom = new RegExpCharacterClass(ranges, false);
+ builder.AddAtom(atom);
+ break;
+ }
+ case '(': {
+ RegExpTree* atom = ParseGroup(CHECK_FAILED);
+ builder.AddAtom(atom);
+ break;
+ }
+ case '[': {
+ RegExpTree* atom = ParseCharacterClass(CHECK_FAILED);
+ builder.AddAtom(atom);
+ break;
+ }
+ // Atom ::
+ // \ AtomEscape
+ case '\\':
+ switch (Next()) {
+ case kEndMarker:
+ ReportError(CStrVector("\\ at end of pattern") CHECK_FAILED);
+ case 'b':
+ Advance(2);
+ builder.AddAssertion(
+ new RegExpAssertion(RegExpAssertion::BOUNDARY));
+ continue;
+ case 'B':
+ Advance(2);
+ builder.AddAssertion(
+ new RegExpAssertion(RegExpAssertion::NON_BOUNDARY));
+ continue;
+ // AtomEscape ::
+ // CharacterClassEscape
+ //
+ // CharacterClassEscape :: one of
+ // d D s S w W
+ case 'd': case 'D': case 's': case 'S': case 'w': case 'W': {
+ uc32 c = Next();
+ Advance(2);
+ ZoneList<CharacterRange>* ranges = new ZoneList<CharacterRange>(2);
+ CharacterRange::AddClassEscape(c, ranges);
+ RegExpTree* atom = new RegExpCharacterClass(ranges, false);
+ builder.AddAtom(atom);
+ goto has_read_atom; // Avoid setting has_character_escapes_.
+ }
+ case '1': case '2': case '3': case '4': case '5': case '6':
+ case '7': case '8': case '9': {
+ int index = 0;
+ if (ParseBackReferenceIndex(&index)) {
+ if (!CaptureAvailable(index - 1)) {
+ // Prepare to ignore a following quantifier
+ builder.AddEmpty();
+ goto has_read_atom;
+ }
+ RegExpCapture* capture = captures_->at(index - 1);
+ RegExpTree* atom = new RegExpBackReference(capture);
+ builder.AddAtom(atom);
+ goto has_read_atom; // Avoid setting has_character_escapes_.
+ }
+ uc32 first_digit = Next();
+ if (first_digit == '8' || first_digit == '9') {
+ // Treat as identity escape
+ builder.AddCharacter(first_digit);
+ Advance(2);
+ break;
+ }
+ }
+ // FALLTHROUGH
+ case '0': {
+ Advance();
+ uc32 octal = ParseOctalLiteral();
+ builder.AddCharacter(octal);
+ break;
+ }
+ // ControlEscape :: one of
+ // f n r t v
+ case 'f':
+ Advance(2);
+ builder.AddCharacter('\f');
+ break;
+ case 'n':
+ Advance(2);
+ builder.AddCharacter('\n');
+ break;
+ case 'r':
+ Advance(2);
+ builder.AddCharacter('\r');
+ break;
+ case 't':
+ Advance(2);
+ builder.AddCharacter('\t');
+ break;
+ case 'v':
+ Advance(2);
+ builder.AddCharacter('\v');
+ break;
+ case 'c': {
+ Advance(2);
+ uc32 control = ParseControlLetterEscape();
+ builder.AddCharacter(control);
+ break;
+ }
+ case 'x': {
+ Advance(2);
+ uc32 value;
+ if (ParseHexEscape(2, &value)) {
+ builder.AddCharacter(value);
+ } else {
+ builder.AddCharacter('x');
+ }
+ break;
+ }
+ case 'u': {
+ Advance(2);
+ uc32 value;
+ if (ParseHexEscape(4, &value)) {
+ builder.AddCharacter(value);
+ } else {
+ builder.AddCharacter('u');
+ }
+ break;
+ }
+ default:
+ // Identity escape.
+ builder.AddCharacter(Next());
+ Advance(2);
+ break;
+ }
+ has_character_escapes_ = true;
+ break;
+ case '{': {
+ int dummy;
+ if (ParseIntervalQuantifier(&dummy, &dummy)) {
+ ReportError(CStrVector("Nothing to repeat") CHECK_FAILED);
+ }
+ // fallthrough
+ }
+ default:
+ builder.AddCharacter(current());
+ Advance();
+ break;
+ } // end switch(current())
+
+ has_read_atom:
+ int min;
+ int max;
+ switch (current()) {
+ // QuantifierPrefix ::
+ // *
+ // +
+ // ?
+ // {
+ case '*':
+ min = 0;
+ max = RegExpQuantifier::kInfinity;
+ Advance();
+ break;
+ case '+':
+ min = 1;
+ max = RegExpQuantifier::kInfinity;
+ Advance();
+ break;
+ case '?':
+ min = 0;
+ max = 1;
+ Advance();
+ break;
+ case '{':
+ if (ParseIntervalQuantifier(&min, &max)) {
+ break;
+ } else {
+ continue;
+ }
+ default:
+ continue;
+ }
+ bool is_greedy = true;
+ if (current() == '?') {
+ is_greedy = false;
+ Advance();
+ }
+ builder.AddQuantifierToAtom(min, max, is_greedy);
+ }
+}
+
+class SourceCharacter {
+ public:
+ static bool Is(uc32 c) {
+ switch (c) {
+ // case ']': case '}':
+ // In spidermonkey and jsc these are treated as source characters
+ // so we do too.
+ case '^': case '$': case '\\': case '.': case '*': case '+':
+ case '?': case '(': case ')': case '[': case '{': case '|':
+ case RegExpParser::kEndMarker:
+ return false;
+ default:
+ return true;
+ }
+ }
+};
+
+
+static unibrow::Predicate<SourceCharacter> source_character;
+
+
+static inline bool IsSourceCharacter(uc32 c) {
+ return source_character.get(c);
+}
+
+#ifdef DEBUG
+// Currently only used in an ASSERT.
+static bool IsSpecialClassEscape(uc32 c) {
+ switch (c) {
+ case 'd': case 'D':
+ case 's': case 'S':
+ case 'w': case 'W':
+ return true;
+ default:
+ return false;
+ }
+}
+#endif
+
+
+// In order to know whether an escape is a backreference or not we have to scan
+// the entire regexp and find the number of capturing parentheses. However we
+// don't want to scan the regexp twice unless it is necessary. This mini-parser
+// is called when needed. It can see the difference between capturing and
+// noncapturing parentheses and can skip character classes and backslash-escaped
+// characters.
+void RegExpParser::ScanForCaptures() {
+ // Start with captures started previous to current position
+ int capture_count = captures_started();
+ // Add count of captures after this position.
+ int n;
+ while ((n = current()) != kEndMarker) {
+ Advance();
+ switch (n) {
+ case '\\':
+ Advance();
+ break;
+ case '[': {
+ int c;
+ while ((c = current()) != kEndMarker) {
+ Advance();
+ if (c == '\\') {
+ Advance();
+ } else {
+ if (c == ']') break;
+ }
+ }
+ break;
+ }
+ case '(':
+ if (current() != '?') capture_count++;
+ break;
+ }
+ }
+ capture_count_ = capture_count;
+ is_scanned_for_captures_ = true;
+}
+
+
+bool RegExpParser::ParseBackReferenceIndex(int* index_out) {
+ ASSERT_EQ('\\', current());
+ ASSERT('1' <= Next() && Next() <= '9');
+ // Try to parse a decimal literal that is no greater than the number
+ // of previously encountered left capturing parentheses.
+ // This is a not according the the ECMAScript specification. According to
+ // that, one must accept values up to the total number of left capturing
+ // parentheses in the entire input, even if they are meaningless.
+ int start = position();
+ int value = Next() - '0';
+ Advance(2);
+ while (true) {
+ uc32 c = current();
+ if (IsDecimalDigit(c)) {
+ value = 10 * value + (c - '0');
+ Advance();
+ } else {
+ break;
+ }
+ }
+ if (value > captures_started()) {
+ if (!is_scanned_for_captures_) {
+ int saved_position = position();
+ ScanForCaptures();
+ Reset(saved_position);
+ }
+ if (value > capture_count_) {
+ Reset(start);
+ return false;
+ }
+ }
+ *index_out = value;
+ return true;
+}
+
+
+// QuantifierPrefix ::
+// { DecimalDigits }
+// { DecimalDigits , }
+// { DecimalDigits , DecimalDigits }
+bool RegExpParser::ParseIntervalQuantifier(int* min_out, int* max_out) {
+ ASSERT_EQ(current(), '{');
+ int start = position();
+ Advance();
+ int min = 0;
+ if (!IsDecimalDigit(current())) {
+ Reset(start);
+ return false;
+ }
+ while (IsDecimalDigit(current())) {
+ min = 10 * min + (current() - '0');
+ Advance();
+ }
+ int max = 0;
+ if (current() == '}') {
+ max = min;
+ Advance();
+ } else if (current() == ',') {
+ Advance();
+ if (current() == '}') {
+ max = RegExpQuantifier::kInfinity;
+ Advance();
+ } else {
+ while (IsDecimalDigit(current())) {
+ max = 10 * max + (current() - '0');
+ Advance();
+ }
+ if (current() != '}') {
+ Reset(start);
+ return false;
+ }
+ Advance();
+ }
+ } else {
+ Reset(start);
+ return false;
+ }
+ *min_out = min;
+ *max_out = max;
+ return true;
+}
+
+
+// Upper and lower case letters differ by one bit.
+STATIC_CHECK(('a' ^ 'A') == 0x20);
+
+uc32 RegExpParser::ParseControlLetterEscape() {
+ if (!has_more()) {
+ ReportError(CStrVector("\\c at end of pattern"));
+ return '\0';
+ }
+ uc32 letter = current() & ~(0x20); // Collapse upper and lower case letters.
+ if (letter < 'A' || 'Z' < letter) {
+ // Non-spec error-correction: "\c" followed by non-control letter is
+ // interpreted as an IdentityEscape of 'c'.
+ return 'c';
+ }
+ Advance();
+ return letter & 0x1f; // Remainder modulo 32, per specification.
+}
+
+
+uc32 RegExpParser::ParseOctalLiteral() {
+ ASSERT('0' <= current() && current() <= '7');
+ // For compatibility with some other browsers (not all), we parse
+ // up to three octal digits with a value below 256.
+ uc32 value = current() - '0';
+ Advance();
+ if ('0' <= current() && current() <= '7') {
+ value = value * 8 + current() - '0';
+ Advance();
+ if (value < 32 && '0' <= current() && current() <= '7') {
+ value = value * 8 + current() - '0';
+ Advance();
+ }
+ }
+ return value;
+}
+
+
+bool RegExpParser::ParseHexEscape(int length, uc32 *value) {
+ int start = position();
+ uc32 val = 0;
+ bool done = false;
+ for (int i = 0; !done; i++) {
+ uc32 c = current();
+ int d = HexValue(c);
+ if (d < 0) {
+ Reset(start);
+ return false;
+ }
+ val = val * 16 + d;
+ Advance();
+ if (i == length - 1) {
+ done = true;
+ }
+ }
+ *value = val;
+ return true;
+}
+
+
+uc32 RegExpParser::ParseClassCharacterEscape() {
+ ASSERT(current() == '\\');
+ ASSERT(has_next() && !IsSpecialClassEscape(Next()));
+ Advance();
+ switch (current()) {
+ case 'b':
+ Advance();
+ return '\b';
+ // ControlEscape :: one of
+ // f n r t v
+ case 'f':
+ Advance();
+ return '\f';
+ case 'n':
+ Advance();
+ return '\n';
+ case 'r':
+ Advance();
+ return '\r';
+ case 't':
+ Advance();
+ return '\t';
+ case 'v':
+ Advance();
+ return '\v';
+ case 'c':
+ return ParseControlLetterEscape();
+ case '0': case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7':
+ // For compatibility, we interpret a decimal escape that isn't
+ // a back reference (and therefore either \0 or not valid according
+ // to the specification) as a 1..3 digit octal character code.
+ return ParseOctalLiteral();
+ case 'x': {
+ Advance();
+ uc32 value;
+ if (ParseHexEscape(2, &value)) {
+ return value;
+ }
+ // If \x is not followed by a two-digit hexadecimal, treat it
+ // as an identity escape.
+ return 'x';
+ }
+ case 'u': {
+ Advance();
+ uc32 value;
+ if (ParseHexEscape(4, &value)) {
+ return value;
+ }
+ // If \u is not followed by a four-digit hexadecimal, treat it
+ // as an identity escape.
+ return 'u';
+ }
+ default: {
+ // Extended identity escape. We accept any character that hasn't
+ // been matched by a more specific case, not just the subset required
+ // by the ECMAScript specification.
+ uc32 result = current();
+ Advance();
+ return result;
+ }
+ }
+ return 0;
+}
+
+
+RegExpTree* RegExpParser::ParseGroup() {
+ ASSERT_EQ(current(), '(');
+ char type = '(';
+ Advance();
+ if (current() == '?') {
+ switch (Next()) {
+ case ':': case '=': case '!':
+ type = Next();
+ Advance(2);
+ break;
+ default:
+ ReportError(CStrVector("Invalid group") CHECK_FAILED);
+ break;
+ }
+ } else {
+ if (captures_ == NULL) {
+ captures_ = new ZoneList<RegExpCapture*>(2);
+ }
+ captures_->Add(NULL);
+ }
+ int capture_index = captures_started();
+ RegExpTree* body = ParseDisjunction(CHECK_FAILED);
+ if (current() != ')') {
+ ReportError(CStrVector("Unterminated group") CHECK_FAILED);
+ }
+ Advance();
+
+ int end_capture_index = captures_started();
+ if (type == '!') {
+ // Captures inside a negative lookahead are never available outside it.
+ for (int i = capture_index; i < end_capture_index; i++) {
+ RegExpCapture* capture = captures_->at(i);
+ ASSERT(capture != NULL);
+ capture->set_available(CAPTURE_PERMANENTLY_UNREACHABLE);
+ }
+ } else {
+ // Captures temporarily unavailable because they are in different
+ // alternatives are all available after the disjunction.
+ for (int i = capture_index; i < end_capture_index; i++) {
+ RegExpCapture* capture = captures_->at(i);
+ ASSERT(capture != NULL);
+ if (capture->available() == CAPTURE_UNREACHABLE) {
+ capture->set_available(CAPTURE_AVAILABLE);
+ }
+ }
+ }
+
+ if (type == '(') {
+ RegExpCapture* capture = new RegExpCapture(body, capture_index);
+ captures_->at(capture_index - 1) = capture;
+ return capture;
+ } else if (type == ':') {
+ return body;
+ } else {
+ ASSERT(type == '=' || type == '!');
+ bool is_positive = (type == '=');
+ return new RegExpLookahead(body, is_positive);
+ }
+}
+
+
+CharacterRange RegExpParser::ParseClassAtom(uc16* char_class) {
+ ASSERT_EQ(0, *char_class);
+ uc32 first = current();
+ if (first == '\\') {
+ switch (Next()) {
+ case 'w': case 'W': case 'd': case 'D': case 's': case 'S': {
+ *char_class = Next();
+ Advance(2);
+ return CharacterRange::Singleton(0); // Return dummy value.
+ }
+ default:
+ uc32 c = ParseClassCharacterEscape(CHECK_FAILED);
+ return CharacterRange::Singleton(c);
+ }
+ } else {
+ Advance();
+ return CharacterRange::Singleton(first);
+ }
+}
+
+
+RegExpTree* RegExpParser::ParseCharacterClass() {
+ static const char* kUnterminated = "Unterminated character class";
+ static const char* kRangeOutOfOrder = "Range out of order in character class";
+
+ ASSERT_EQ(current(), '[');
+ Advance();
+ bool is_negated = false;
+ if (current() == '^') {
+ is_negated = true;
+ Advance();
+ }
+ ZoneList<CharacterRange>* ranges = new ZoneList<CharacterRange>(2);
+ while (has_more() && current() != ']') {
+ uc16 char_class = 0;
+ CharacterRange first = ParseClassAtom(&char_class CHECK_FAILED);
+ if (char_class) {
+ CharacterRange::AddClassEscape(char_class, ranges);
+ continue;
+ }
+ if (current() == '-') {
+ Advance();
+ if (current() == kEndMarker) {
+ // If we reach the end we break out of the loop and let the
+ // following code report an error.
+ break;
+ } else if (current() == ']') {
+ ranges->Add(first);
+ ranges->Add(CharacterRange::Singleton('-'));
+ break;
+ }
+ CharacterRange next = ParseClassAtom(&char_class CHECK_FAILED);
+ if (char_class) {
+ ranges->Add(first);
+ ranges->Add(CharacterRange::Singleton('-'));
+ CharacterRange::AddClassEscape(char_class, ranges);
+ continue;
+ }
+ if (first.from() > next.to()) {
+ return ReportError(CStrVector(kRangeOutOfOrder) CHECK_FAILED);
+ }
+ ranges->Add(CharacterRange::Range(first.from(), next.to()));
+ } else {
+ ranges->Add(first);
+ }
+ }
+ if (!has_more()) {
+ return ReportError(CStrVector(kUnterminated) CHECK_FAILED);
+ }
+ Advance();
+ if (ranges->length() == 0) {
+ ranges->Add(CharacterRange::Everything());
+ is_negated = !is_negated;
+ }
+ return new RegExpCharacterClass(ranges, is_negated);
+}
+
+
+// ----------------------------------------------------------------------------
// The Parser interface.
// MakeAST() is just a wrapper for the corresponding Parser calls
@@ -3211,6 +4300,27 @@
}
+bool ParseRegExp(FlatStringReader* input,
+ bool multiline,
+ RegExpParseResult* result) {
+ ASSERT(result != NULL);
+ // Make sure we have a stack guard.
+ StackGuard guard;
+ RegExpParser parser(input, &result->error, multiline);
+ result->tree = parser.ParsePattern();
+ if (parser.failed()) {
+ ASSERT(result->tree == NULL);
+ ASSERT(!result->error.is_null());
+ } else {
+ ASSERT(result->tree != NULL);
+ ASSERT(result->error.is_null());
+ result->has_character_escapes = parser.HasCharacterEscapes();
+ result->capture_count = parser.captures_started();
+ }
+ return !parser.failed();
+}
+
+
FunctionLiteral* MakeAST(bool compile_in_global_context,
Handle<Script> script,
v8::Extension* extension,
diff --git a/src/parser.h b/src/parser.h
index d331d73..0ebef74 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -145,6 +145,11 @@
v8::Extension* extension);
+bool ParseRegExp(FlatStringReader* input,
+ bool multiline,
+ 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
diff --git a/src/platform-freebsd.cc b/src/platform-freebsd.cc
new file mode 100644
index 0000000..75140c9
--- /dev/null
+++ b/src/platform-freebsd.cc
@@ -0,0 +1,698 @@
+// 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.
+
+// Platform specific code for FreeBSD goes here
+
+#include <pthread.h>
+#include <semaphore.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/ucontext.h>
+#include <stdlib.h>
+
+#include <sys/types.h> // mmap & munmap
+#include <sys/mman.h> // mmap & munmap
+#include <sys/stat.h> // open
+#include <sys/fcntl.h> // open
+#include <unistd.h> // getpagesize
+#include <execinfo.h> // backtrace, backtrace_symbols
+#include <strings.h> // index
+#include <errno.h>
+#include <stdarg.h>
+#include <limits.h>
+
+#undef MAP_TYPE
+
+#include "v8.h"
+
+#include "platform.h"
+
+
+namespace v8 { namespace internal {
+
+// 0 is never a valid thread id on FreeBSD since tids and pids share a
+// name space and pid 0 is used to kill the group (see man 2 kill).
+static const pthread_t kNoThread = (pthread_t) 0;
+
+
+double ceiling(double x) {
+ // Correct as on OS X
+ if (-1.0 < x && x < 0.0) {
+ return -0.0;
+ } else {
+ return ceil(x);
+ }
+}
+
+
+void OS::Setup() {
+ // Seed the random number generator.
+ // Convert the current time to a 64-bit integer first, before converting it
+ // to an unsigned. Going directly can cause an overflow and the seed to be
+ // set to all ones. The seed will be identical for different instances that
+ // call this setup code within the same millisecond.
+ uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis());
+ srandom(static_cast<unsigned int>(seed));
+}
+
+
+int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) {
+ struct rusage usage;
+
+ if (getrusage(RUSAGE_SELF, &usage) < 0) return -1;
+ *secs = usage.ru_utime.tv_sec;
+ *usecs = usage.ru_utime.tv_usec;
+ return 0;
+}
+
+
+double OS::TimeCurrentMillis() {
+ struct timeval tv;
+ if (gettimeofday(&tv, NULL) < 0) return 0.0;
+ return (static_cast<double>(tv.tv_sec) * 1000) +
+ (static_cast<double>(tv.tv_usec) / 1000);
+}
+
+
+int64_t OS::Ticks() {
+ // FreeBSD's gettimeofday has microsecond resolution.
+ struct timeval tv;
+ if (gettimeofday(&tv, NULL) < 0)
+ return 0;
+ return (static_cast<int64_t>(tv.tv_sec) * 1000000) + tv.tv_usec;
+}
+
+
+char* OS::LocalTimezone(double time) {
+ time_t tv = static_cast<time_t>(floor(time/msPerSecond));
+ struct tm* t = localtime(&tv);
+ return const_cast<char*>(t->tm_zone);
+}
+
+
+double OS::DaylightSavingsOffset(double time) {
+ time_t tv = static_cast<time_t>(floor(time/msPerSecond));
+ struct tm* t = localtime(&tv);
+ return t->tm_isdst > 0 ? 3600 * msPerSecond : 0;
+}
+
+
+double OS::LocalTimeOffset() {
+ time_t tv = time(NULL);
+ struct tm* t = localtime(&tv);
+ // tm_gmtoff includes any daylight savings offset, so subtract it.
+ return static_cast<double>(t->tm_gmtoff * msPerSecond -
+ (t->tm_isdst > 0 ? 3600 * msPerSecond : 0));
+}
+
+
+FILE* OS::FOpen(const char* path, const char* mode) {
+ return fopen(path, mode);
+}
+
+
+void OS::Print(const char* format, ...) {
+ va_list args;
+ va_start(args, format);
+ VPrint(format, args);
+ va_end(args);
+}
+
+
+void OS::VPrint(const char* format, va_list args) {
+ vprintf(format, args);
+}
+
+
+void OS::PrintError(const char* format, ...) {
+ va_list args;
+ va_start(args, format);
+ VPrintError(format, args);
+ va_end(args);
+}
+
+
+void OS::VPrintError(const char* format, va_list args) {
+ vfprintf(stderr, format, args);
+}
+
+
+int OS::SNPrintF(Vector<char> str, const char* format, ...) {
+ va_list args;
+ va_start(args, format);
+ int result = VSNPrintF(str, format, args);
+ va_end(args);
+ return result;
+}
+
+
+int OS::VSNPrintF(Vector<char> str,
+ const char* format,
+ va_list args) {
+ int n = vsnprintf(str.start(), str.length(), format, args);
+ if (n < 0 || n >= str.length()) {
+ str[str.length() - 1] = '\0';
+ return -1;
+ } else {
+ return n;
+ }
+}
+
+
+void OS::StrNCpy(Vector<char> dest, const char* src, size_t n) {
+ strncpy(dest.start(), src, n);
+}
+
+
+char *OS::StrDup(const char* str) {
+ return strdup(str);
+}
+
+
+double OS::nan_value() {
+ return NAN;
+}
+
+
+int OS::ActivationFrameAlignment() {
+ // 16 byte alignment on FreeBSD
+ return 16;
+}
+
+
+// We keep the lowest and highest addresses mapped as a quick way of
+// determining that pointers are outside the heap (used mostly in assertions
+// and verification). The estimate is conservative, ie, not all addresses in
+// 'allocated' space are actually allocated to our heap. The range is
+// [lowest, highest), inclusive on the low and and exclusive on the high end.
+static void* lowest_ever_allocated = reinterpret_cast<void*>(-1);
+static void* highest_ever_allocated = reinterpret_cast<void*>(0);
+
+
+static void UpdateAllocatedSpaceLimits(void* address, int size) {
+ lowest_ever_allocated = Min(lowest_ever_allocated, address);
+ highest_ever_allocated =
+ Max(highest_ever_allocated,
+ reinterpret_cast<void*>(reinterpret_cast<char*>(address) + size));
+}
+
+
+bool OS::IsOutsideAllocatedSpace(void* address) {
+ return address < lowest_ever_allocated || address >= highest_ever_allocated;
+}
+
+
+size_t OS::AllocateAlignment() {
+ return getpagesize();
+}
+
+
+void* OS::Allocate(const size_t requested,
+ size_t* allocated,
+ bool executable) {
+ const size_t msize = RoundUp(requested, getpagesize());
+ int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
+ void* mbase = mmap(NULL, msize, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
+
+ if (mbase == MAP_FAILED) {
+ LOG(StringEvent("OS::Allocate", "mmap failed"));
+ return NULL;
+ }
+ *allocated = msize;
+ UpdateAllocatedSpaceLimits(mbase, msize);
+ return mbase;
+}
+
+
+void OS::Free(void* buf, const size_t length) {
+ // TODO(1240712): munmap has a return value which is ignored here.
+ munmap(buf, length);
+}
+
+
+void OS::Sleep(int milliseconds) {
+ unsigned int ms = static_cast<unsigned int>(milliseconds);
+ usleep(1000 * ms);
+}
+
+
+void OS::Abort() {
+ // Redirect to std abort to signal abnormal program termination.
+ abort();
+}
+
+
+void OS::DebugBreak() {
+#if defined (__arm__) || defined(__thumb__)
+ asm("bkpt 0");
+#else
+ asm("int $3");
+#endif
+}
+
+
+class PosixMemoryMappedFile : public OS::MemoryMappedFile {
+ public:
+ PosixMemoryMappedFile(FILE* file, void* memory, int size)
+ : file_(file), memory_(memory), size_(size) { }
+ virtual ~PosixMemoryMappedFile();
+ virtual void* memory() { return memory_; }
+ private:
+ FILE* file_;
+ void* memory_;
+ int size_;
+};
+
+
+OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, int size,
+ void* initial) {
+ FILE* file = fopen(name, "w+");
+ if (file == NULL) return NULL;
+ int result = fwrite(initial, size, 1, file);
+ if (result < 1) {
+ fclose(file);
+ return NULL;
+ }
+ void* memory =
+ mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(file), 0);
+ return new PosixMemoryMappedFile(file, memory, size);
+}
+
+
+PosixMemoryMappedFile::~PosixMemoryMappedFile() {
+ if (memory_) munmap(memory_, size_);
+ fclose(file_);
+}
+
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+static unsigned StringToLong(char* buffer) {
+ return static_cast<unsigned>(strtol(buffer, NULL, 16)); // NOLINT
+}
+#endif
+
+
+void OS::LogSharedLibraryAddresses() {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ static const int MAP_LENGTH = 1024;
+ int fd = open("/proc/self/maps", O_RDONLY);
+ if (fd < 0) return;
+ while (true) {
+ char addr_buffer[11];
+ addr_buffer[0] = '0';
+ addr_buffer[1] = 'x';
+ addr_buffer[10] = 0;
+ int result = read(fd, addr_buffer + 2, 8);
+ if (result < 8) break;
+ unsigned start = StringToLong(addr_buffer);
+ result = read(fd, addr_buffer + 2, 1);
+ if (result < 1) break;
+ if (addr_buffer[2] != '-') break;
+ result = read(fd, addr_buffer + 2, 8);
+ if (result < 8) break;
+ unsigned end = StringToLong(addr_buffer);
+ char buffer[MAP_LENGTH];
+ int bytes_read = -1;
+ do {
+ bytes_read++;
+ if (bytes_read >= MAP_LENGTH - 1)
+ break;
+ result = read(fd, buffer + bytes_read, 1);
+ if (result < 1) break;
+ } while (buffer[bytes_read] != '\n');
+ buffer[bytes_read] = 0;
+ // Ignore mappings that are not executable.
+ if (buffer[3] != 'x') continue;
+ char* start_of_path = index(buffer, '/');
+ // There may be no filename in this line. Skip to next.
+ if (start_of_path == NULL) continue;
+ buffer[bytes_read] = 0;
+ LOG(SharedLibraryEvent(start_of_path, start, end));
+ }
+ close(fd);
+#endif
+}
+
+
+int OS::StackWalk(OS::StackFrame* frames, int frames_size) {
+ void** addresses = NewArray<void*>(frames_size);
+
+ int frames_count = backtrace(addresses, frames_size);
+
+ char** symbols;
+ symbols = backtrace_symbols(addresses, frames_count);
+ if (symbols == NULL) {
+ DeleteArray(addresses);
+ return kStackWalkError;
+ }
+
+ for (int i = 0; i < frames_count; i++) {
+ frames[i].address = addresses[i];
+ // Format a text representation of the frame based on the information
+ // available.
+ SNPrintF(MutableCStrVector(frames[i].text, kStackWalkMaxTextLen),
+ "%s",
+ symbols[i]);
+ // Make sure line termination is in place.
+ frames[i].text[kStackWalkMaxTextLen - 1] = '\0';
+ }
+
+ DeleteArray(addresses);
+ free(symbols);
+
+ return frames_count;
+}
+
+
+// Constants used for mmap.
+static const int kMmapFd = -1;
+static const int kMmapFdOffset = 0;
+
+
+VirtualMemory::VirtualMemory(size_t size) {
+ address_ = mmap(NULL, size, PROT_NONE,
+ MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
+ kMmapFd, kMmapFdOffset);
+ size_ = size;
+}
+
+
+VirtualMemory::~VirtualMemory() {
+ if (IsReserved()) {
+ if (0 == munmap(address(), size())) address_ = MAP_FAILED;
+ }
+}
+
+
+bool VirtualMemory::IsReserved() {
+ return address_ != MAP_FAILED;
+}
+
+
+bool VirtualMemory::Commit(void* address, size_t size, bool executable) {
+ int prot = PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0);
+ if (MAP_FAILED == mmap(address, size, prot,
+ MAP_PRIVATE | MAP_ANON | MAP_FIXED,
+ kMmapFd, kMmapFdOffset)) {
+ return false;
+ }
+
+ UpdateAllocatedSpaceLimits(address, size);
+ return true;
+}
+
+
+bool VirtualMemory::Uncommit(void* address, size_t size) {
+ return mmap(address, size, PROT_NONE,
+ MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
+ kMmapFd, kMmapFdOffset) != MAP_FAILED;
+}
+
+
+class ThreadHandle::PlatformData : public Malloced {
+ public:
+ explicit PlatformData(ThreadHandle::Kind kind) {
+ Initialize(kind);
+ }
+
+ void Initialize(ThreadHandle::Kind kind) {
+ switch (kind) {
+ case ThreadHandle::SELF: thread_ = pthread_self(); break;
+ case ThreadHandle::INVALID: thread_ = kNoThread; break;
+ }
+ }
+ pthread_t thread_; // Thread handle for pthread.
+};
+
+
+ThreadHandle::ThreadHandle(Kind kind) {
+ data_ = new PlatformData(kind);
+}
+
+
+void ThreadHandle::Initialize(ThreadHandle::Kind kind) {
+ data_->Initialize(kind);
+}
+
+
+ThreadHandle::~ThreadHandle() {
+ delete data_;
+}
+
+
+bool ThreadHandle::IsSelf() const {
+ return pthread_equal(data_->thread_, pthread_self());
+}
+
+
+bool ThreadHandle::IsValid() const {
+ return data_->thread_ != kNoThread;
+}
+
+
+Thread::Thread() : ThreadHandle(ThreadHandle::INVALID) {
+}
+
+
+Thread::~Thread() {
+}
+
+
+static void* ThreadEntry(void* arg) {
+ Thread* thread = reinterpret_cast<Thread*>(arg);
+ // This is also initialized by the first argument to pthread_create() but we
+ // don't know which thread will run first (the original thread or the new
+ // one) so we initialize it here too.
+ thread->thread_handle_data()->thread_ = pthread_self();
+ ASSERT(thread->IsValid());
+ thread->Run();
+ return NULL;
+}
+
+
+void Thread::Start() {
+ pthread_create(&thread_handle_data()->thread_, NULL, ThreadEntry, this);
+ ASSERT(IsValid());
+}
+
+
+void Thread::Join() {
+ pthread_join(thread_handle_data()->thread_, NULL);
+}
+
+
+Thread::LocalStorageKey Thread::CreateThreadLocalKey() {
+ pthread_key_t key;
+ int result = pthread_key_create(&key, NULL);
+ USE(result);
+ ASSERT(result == 0);
+ return static_cast<LocalStorageKey>(key);
+}
+
+
+void Thread::DeleteThreadLocalKey(LocalStorageKey key) {
+ pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
+ int result = pthread_key_delete(pthread_key);
+ USE(result);
+ ASSERT(result == 0);
+}
+
+
+void* Thread::GetThreadLocal(LocalStorageKey key) {
+ pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
+ return pthread_getspecific(pthread_key);
+}
+
+
+void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
+ pthread_key_t pthread_key = static_cast<pthread_key_t>(key);
+ pthread_setspecific(pthread_key, value);
+}
+
+
+void Thread::YieldCPU() {
+ sched_yield();
+}
+
+
+class FreeBSDMutex : public Mutex {
+ public:
+
+ FreeBSDMutex() {
+ pthread_mutexattr_t attrs;
+ int result = pthread_mutexattr_init(&attrs);
+ ASSERT(result == 0);
+ result = pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_RECURSIVE);
+ ASSERT(result == 0);
+ result = pthread_mutex_init(&mutex_, &attrs);
+ ASSERT(result == 0);
+ }
+
+ virtual ~FreeBSDMutex() { pthread_mutex_destroy(&mutex_); }
+
+ virtual int Lock() {
+ int result = pthread_mutex_lock(&mutex_);
+ return result;
+ }
+
+ virtual int Unlock() {
+ int result = pthread_mutex_unlock(&mutex_);
+ return result;
+ }
+
+ private:
+ pthread_mutex_t mutex_; // Pthread mutex for POSIX platforms.
+};
+
+
+Mutex* OS::CreateMutex() {
+ return new FreeBSDMutex();
+}
+
+
+class FreeBSDSemaphore : public Semaphore {
+ public:
+ explicit FreeBSDSemaphore(int count) { sem_init(&sem_, 0, count); }
+ virtual ~FreeBSDSemaphore() { sem_destroy(&sem_); }
+
+ virtual void Wait();
+ virtual void Signal() { sem_post(&sem_); }
+ private:
+ sem_t sem_;
+};
+
+void FreeBSDSemaphore::Wait() {
+ while (true) {
+ int result = sem_wait(&sem_);
+ if (result == 0) return; // Successfully got semaphore.
+ CHECK(result == -1 && errno == EINTR); // Signal caused spurious wakeup.
+ }
+}
+
+Semaphore* OS::CreateSemaphore(int count) {
+ return new FreeBSDSemaphore(count);
+}
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+
+static Sampler* active_sampler_ = NULL;
+
+static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
+ USE(info);
+ if (signal != SIGPROF) return;
+ if (active_sampler_ == NULL) return;
+
+ TickSample sample;
+
+ // If profiling, we extract the current pc and sp.
+ if (active_sampler_->IsProfiling()) {
+ // Extracting the sample from the context is extremely machine dependent.
+ ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
+ mcontext_t& mcontext = ucontext->uc_mcontext;
+#if defined (__arm__) || defined(__thumb__)
+ sample.pc = mcontext.mc_r15;
+ sample.sp = mcontext.mc_r13;
+#else
+ sample.pc = mcontext.mc_eip;
+ sample.sp = mcontext.mc_esp;
+#endif
+ }
+
+ // We always sample the VM state.
+ sample.state = Logger::state();
+
+ active_sampler_->Tick(&sample);
+}
+
+
+class Sampler::PlatformData : public Malloced {
+ public:
+ PlatformData() {
+ signal_handler_installed_ = false;
+ }
+
+ bool signal_handler_installed_;
+ struct sigaction old_signal_handler_;
+ struct itimerval old_timer_value_;
+};
+
+
+Sampler::Sampler(int interval, bool profiling)
+ : interval_(interval), profiling_(profiling), active_(false) {
+ data_ = new PlatformData();
+}
+
+
+Sampler::~Sampler() {
+ delete data_;
+}
+
+
+void Sampler::Start() {
+ // There can only be one active sampler at the time on POSIX
+ // platforms.
+ if (active_sampler_ != NULL) return;
+
+ // Request profiling signals.
+ struct sigaction sa;
+ sa.sa_sigaction = ProfilerSignalHandler;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_SIGINFO;
+ if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return;
+ data_->signal_handler_installed_ = true;
+
+ // Set the itimer to generate a tick for each interval.
+ itimerval itimer;
+ itimer.it_interval.tv_sec = interval_ / 1000;
+ itimer.it_interval.tv_usec = (interval_ % 1000) * 1000;
+ itimer.it_value.tv_sec = itimer.it_interval.tv_sec;
+ itimer.it_value.tv_usec = itimer.it_interval.tv_usec;
+ setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_);
+
+ // Set this sampler as the active sampler.
+ active_sampler_ = this;
+ active_ = true;
+}
+
+
+void Sampler::Stop() {
+ // Restore old signal handler
+ if (data_->signal_handler_installed_) {
+ setitimer(ITIMER_PROF, &data_->old_timer_value_, NULL);
+ sigaction(SIGPROF, &data_->old_signal_handler_, 0);
+ data_->signal_handler_installed_ = false;
+ }
+
+ // This sampler is no longer the active sampler.
+ active_sampler_ = NULL;
+ active_ = false;
+}
+
+#endif // ENABLE_LOGGING_AND_PROFILING
+
+} } // namespace v8::internal
diff --git a/src/platform-linux.cc b/src/platform-linux.cc
index 46ca7dc..2bb9665 100644
--- a/src/platform-linux.cc
+++ b/src/platform-linux.cc
@@ -185,11 +185,6 @@
}
-void OS::WcsCpy(Vector<wchar_t> dest, const wchar_t* src) {
- wcscpy(dest.start(), src);
-}
-
-
char *OS::StrDup(const char* str) {
return strdup(str);
}
@@ -309,13 +304,14 @@
fclose(file_);
}
-#ifdef ENABLE_LOGGING_AND_PROFILING
-static unsigned StringToLongLong(char* buffer) {
- return static_cast<unsigned>(strtoll(buffer, NULL, 16)); // NOLINT
-}
+#ifdef ENABLE_LOGGING_AND_PROFILING
+static unsigned StringToLong(char* buffer) {
+ return static_cast<unsigned>(strtol(buffer, NULL, 16)); // NOLINT
+}
#endif
+
void OS::LogSharedLibraryAddresses() {
#ifdef ENABLE_LOGGING_AND_PROFILING
static const int MAP_LENGTH = 1024;
@@ -328,13 +324,13 @@
addr_buffer[10] = 0;
int result = read(fd, addr_buffer + 2, 8);
if (result < 8) break;
- unsigned start = StringToLongLong(addr_buffer);
+ unsigned start = StringToLong(addr_buffer);
result = read(fd, addr_buffer + 2, 1);
if (result < 1) break;
if (addr_buffer[2] != '-') break;
result = read(fd, addr_buffer + 2, 8);
if (result < 8) break;
- unsigned end = StringToLongLong(addr_buffer);
+ unsigned end = StringToLong(addr_buffer);
char buffer[MAP_LENGTH];
int bytes_read = -1;
do {
diff --git a/src/platform-macos.cc b/src/platform-macos.cc
index e57f79d..f08d64d 100644
--- a/src/platform-macos.cc
+++ b/src/platform-macos.cc
@@ -190,11 +190,6 @@
}
-void OS::WcsCpy(Vector<wchar_t> dest, const wchar_t* src) {
- wcscpy(dest.start(), src);
-}
-
-
char *OS::StrDup(const char* str) {
return strdup(str);
}
diff --git a/src/platform-win32.cc b/src/platform-win32.cc
index 055008e..bd65dde 100644
--- a/src/platform-win32.cc
+++ b/src/platform-win32.cc
@@ -48,9 +48,15 @@
#ifndef NOMCX
#define NOMCX
#endif
+// Require Windows 2000 or higher (this is required for the IsDebuggerPresent
+// function to be present).
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x500
+#endif
#include <windows.h>
+#include <time.h> // For LocalOffset() implementation.
#include <mmsystem.h> // For timeGetTime().
#include <dbghelp.h> // For SymLoadModule64 and al.
#include <tlhelp32.h> // For Module32First and al.
@@ -318,6 +324,8 @@
// Just return if timezone information has already been initialized.
if (tz_initialized_) return;
+ // Initialize POSIX time zone data.
+ _tzset();
// Obtain timezone information from operating system.
memset(&tzinfo_, 0, sizeof(tzinfo_));
if (GetTimeZoneInformation(&tzinfo_) == TIME_ZONE_ID_INVALID) {
@@ -391,9 +399,9 @@
static bool initialized = false;
static TimeStamp init_time;
static DWORD init_ticks;
- static const int kHundredNanosecondsPerSecond = 10000;
- static const int kMaxClockElapsedTime =
- 60*60*24*kHundredNanosecondsPerSecond; // 1 day
+ static const int64_t kHundredNanosecondsPerSecond = 10000000;
+ static const int64_t kMaxClockElapsedTime =
+ 60*kHundredNanosecondsPerSecond; // 1 minute
// If we are uninitialized, we need to resync the clock.
bool needs_resync = !initialized;
@@ -424,30 +432,37 @@
// Return the local timezone offset in milliseconds east of UTC. This
// takes into account whether daylight saving is in effect at the time.
+// Only times in the 32-bit Unix range may be passed to this function.
+// Also, adding the time-zone offset to the input must not overflow.
+// The function EquivalentTime() in date-delay.js guarantees this.
int64_t Time::LocalOffset() {
// Initialize timezone information, if needed.
TzSet();
- // Convert timestamp to date/time components. These are now in UTC
- // format. NB: Please do not replace the following three calls with one
- // call to FileTimeToLocalFileTime(), because it does not handle
- // daylight saving correctly.
- SYSTEMTIME utc;
- FileTimeToSystemTime(&ft(), &utc);
+ Time rounded_to_second(*this);
+ rounded_to_second.t() = rounded_to_second.t() / 1000 / kTimeScaler *
+ 1000 * kTimeScaler;
+ // Convert to local time using POSIX localtime function.
+ // Windows XP Service Pack 3 made SystemTimeToTzSpecificLocalTime()
+ // very slow. Other browsers use localtime().
- // Convert to local time, using timezone information.
- SYSTEMTIME local;
- SystemTimeToTzSpecificLocalTime(&tzinfo_, &utc, &local);
+ // Convert from JavaScript milliseconds past 1/1/1970 0:00:00 to
+ // POSIX seconds past 1/1/1970 0:00:00.
+ double unchecked_posix_time = rounded_to_second.ToJSTime() / 1000;
+ if (unchecked_posix_time > INT_MAX || unchecked_posix_time < 0) {
+ return 0;
+ }
+ // Because _USE_32BIT_TIME_T is defined, time_t is a 32-bit int.
+ time_t posix_time = static_cast<time_t>(unchecked_posix_time);
- // Convert local time back to a timestamp. This timestamp now
- // has a bias similar to the local timezone bias in effect
- // at the time of the original timestamp.
- Time localtime;
- SystemTimeToFileTime(&local, &localtime.ft());
+ // Convert to local time, as struct with fields for day, hour, year, etc.
+ tm posix_local_time_struct;
+ if (localtime_s(&posix_local_time_struct, &posix_time)) return 0;
+ // Convert local time in struct to POSIX time as if it were a UTC time.
+ time_t local_posix_time = _mkgmtime(&posix_local_time_struct);
+ Time localtime(1000.0 * local_posix_time);
- // The difference between the new local timestamp and the original
- // timestamp and is the local timezone offset.
- return localtime.Diff(this);
+ return localtime.Diff(&rounded_to_second);
}
@@ -680,13 +695,6 @@
}
-void OS::WcsCpy(Vector<wchar_t> dest, const wchar_t* src) {
- int result = wcscpy_s(dest.start(), dest.length(), src);
- USE(result);
- ASSERT(result == 0);
-}
-
-
char *OS::StrDup(const char* str) {
return _strdup(str);
}
@@ -781,10 +789,14 @@
void OS::Abort() {
- // Make the MSVCRT do a silent abort.
- _set_abort_behavior(0, _WRITE_ABORT_MSG);
- _set_abort_behavior(0, _CALL_REPORTFAULT);
- abort();
+ if (!IsDebuggerPresent()) {
+ // Make the MSVCRT do a silent abort.
+ _set_abort_behavior(0, _WRITE_ABORT_MSG);
+ _set_abort_behavior(0, _CALL_REPORTFAULT);
+ abort();
+ } else {
+ DebugBreak();
+ }
}
diff --git a/src/platform.h b/src/platform.h
index 7238d70..cc44718 100644
--- a/src/platform.h
+++ b/src/platform.h
@@ -205,7 +205,6 @@
va_list args);
static void StrNCpy(Vector<char> dest, const char* src, size_t n);
- static void WcsCpy(Vector<wchar_t> dest, const wchar_t* src);
static char* StrDup(const char* str);
// Support for profiler. Can do nothing, in which case ticks
diff --git a/src/prettyprinter.cc b/src/prettyprinter.cc
index 39af187..a914383 100644
--- a/src/prettyprinter.cc
+++ b/src/prettyprinter.cc
@@ -348,6 +348,11 @@
}
+void PrettyPrinter::VisitCallEval(CallEval* node) {
+ VisitCall(node);
+}
+
+
void PrettyPrinter::VisitCallNew(CallNew* node) {
Print("new (");
Visit(node->expression());
@@ -1016,6 +1021,11 @@
}
+void AstPrinter::VisitCallEval(CallEval* node) {
+ VisitCall(node);
+}
+
+
void AstPrinter::VisitCallNew(CallNew* node) {
IndentedScope indent("CALL NEW");
Visit(node->expression());
diff --git a/src/prettyprinter.h b/src/prettyprinter.h
index 58cac51..1c94635 100644
--- a/src/prettyprinter.h
+++ b/src/prettyprinter.h
@@ -34,7 +34,7 @@
#ifdef DEBUG
-class PrettyPrinter: public Visitor {
+class PrettyPrinter: public AstVisitor {
public:
PrettyPrinter();
virtual ~PrettyPrinter();
diff --git a/src/regexp-delay.js b/src/regexp-delay.js
index e15240a..4baa9cd 100644
--- a/src/regexp-delay.js
+++ b/src/regexp-delay.js
@@ -163,6 +163,9 @@
function RegExpExec(string) {
if (%_ArgumentsLength() == 0) {
+ if (IS_UNDEFINED(regExpInput)) {
+ throw MakeError('no_input_to_regexp', [this]);
+ }
string = regExpInput;
}
var s = ToString(string);
@@ -283,7 +286,7 @@
// the last successful match.
var regExpCaptures = [0, 0];
var regExpSubject = '';
-var regExpInput = "";
+var regExpInput;
// -------------------------------------------------------------------
@@ -308,13 +311,11 @@
%FunctionSetLength($RegExp.prototype.compile, 1);
// The properties input, $input, and $_ are aliases for each other. When this
- // value is set in SpiderMonkey, the value it is set to is coerced to a
- // string. We mimic that behavior with a slight difference: in SpiderMonkey
- // the value of the expression 'RegExp.input = null' (for instance) is the
- // string "null" (ie, the value after coercion), while in V8 it is the value
- // null (ie, the value before coercion).
+ // value is set the value it is set to is coerced to a string.
// Getter and setter for the input.
- function RegExpGetInput() { return regExpInput; }
+ function RegExpGetInput() {
+ return IS_UNDEFINED(regExpInput) ? "" : regExpInput;
+ }
function RegExpSetInput(string) { regExpInput = ToString(string); }
%DefineAccessor($RegExp, 'input', GETTER, RegExpGetInput, DONT_DELETE);
diff --git a/src/regexp-macro-assembler-arm.cc b/src/regexp-macro-assembler-arm.cc
new file mode 100644
index 0000000..bcfddf6
--- /dev/null
+++ b/src/regexp-macro-assembler-arm.cc
@@ -0,0 +1,43 @@
+// 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.
+
+#include "v8.h"
+#include "ast.h"
+#include "regexp-macro-assembler.h"
+#include "regexp-macro-assembler-arm.h"
+
+namespace v8 { namespace internal {
+
+RegExpMacroAssemblerARM::RegExpMacroAssemblerARM() {
+ UNIMPLEMENTED();
+}
+
+
+RegExpMacroAssemblerARM::~RegExpMacroAssemblerARM() {}
+
+}} // namespace v8::internal
+
diff --git a/src/regexp-macro-assembler-arm.h b/src/regexp-macro-assembler-arm.h
new file mode 100644
index 0000000..51352bc
--- /dev/null
+++ b/src/regexp-macro-assembler-arm.h
@@ -0,0 +1,41 @@
+// 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 REGEXP_MACRO_ASSEMBLER_ARM_H_
+#define REGEXP_MACRO_ASSEMBLER_ARM_H_
+
+namespace v8 { namespace internal {
+
+class RegExpMacroAssemblerARM: public RegExpMacroAssembler {
+ public:
+ RegExpMacroAssemblerARM();
+ virtual ~RegExpMacroAssemblerARM();
+};
+
+}} // namespace v8::internal
+
+#endif /* REGEXP_MACRO_ASSEMBLER_ARM_H_ */
diff --git a/src/regexp-macro-assembler-ia32.cc b/src/regexp-macro-assembler-ia32.cc
new file mode 100644
index 0000000..76b4bcf
--- /dev/null
+++ b/src/regexp-macro-assembler-ia32.cc
@@ -0,0 +1,684 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <string.h>
+#include "v8.h"
+#include "log.h"
+#include "ast.h"
+#include "macro-assembler.h"
+#include "regexp-macro-assembler.h"
+#include "macro-assembler-ia32.h"
+#include "regexp-macro-assembler-ia32.h"
+
+namespace v8 { namespace internal {
+
+/*
+ * This assembler uses the following register assignment convention
+ * - edx : current character. Must be loaded using LoadCurrentCharacter
+ * before using any of the dispatch methods.
+ * - edi : current position in input, as negative offset from end of string.
+ * Please notice that this is the byte offset, not the character offset!
+ * - esi : end of input (points to byte after last character in input).
+ * - ebp : points to the location above the registers on the stack,
+ * as if by the "enter <register_count>" opcode.
+ * - esp : points to tip of backtracking stack.
+ *
+ * The registers eax, ebx and ecx are free to use for computations.
+ *
+ * Each call to a public method should retain this convention.
+ * The stack will have the following structure:
+ * - at_start (if 1, start at start of string, if 0, don't)
+ * - int* capture_array (int[num_saved_registers_], for output).
+ * - end of input (index of end of string, relative to *string_base)
+ * - start of input (index of first character in string, relative
+ * to *string_base)
+ * - void** string_base (location of a handle containing the string)
+ * - return address
+ * - backup of esi
+ * - backup of edi
+ * - backup of ebx
+ * ebp-> - old ebp
+ * - register 0 ebp[-4] (Only positions must be stored in the first
+ * - register 1 ebp[-8] num_saved_registers_ registers)
+ * - ...
+ *
+ * The first num_saved_registers_ registers are initialized to point to
+ * "character -1" in the string (i.e., char_size() bytes before the first
+ * character of the string). The remaining registers starts out as garbage.
+ *
+ * The data up to the return address must be placed there by the calling
+ * code, e.g., by calling the code as cast to:
+ * bool (*match)(String** string_base,
+ * int start_offset,
+ * int end_offset,
+ * int* capture_output_array,
+ * bool at_start)
+ */
+
+#define __ masm_->
+
+RegExpMacroAssemblerIA32::RegExpMacroAssemblerIA32(
+ Mode mode,
+ int registers_to_save)
+ : masm_(new MacroAssembler(NULL, kRegExpCodeSize)),
+ constants_(kRegExpConstantsSize),
+ mode_(mode),
+ num_registers_(registers_to_save),
+ num_saved_registers_(registers_to_save),
+ entry_label_(),
+ start_label_(),
+ success_label_(),
+ exit_label_(),
+ self_(Heap::undefined_value()) {
+ __ jmp(&entry_label_); // We'll write the entry code later.
+ __ bind(&start_label_); // And then continue from here.
+}
+
+
+RegExpMacroAssemblerIA32::~RegExpMacroAssemblerIA32() {
+ delete masm_;
+ // Unuse labels in case we throw away the assembler without calling GetCode.
+ entry_label_.Unuse();
+ start_label_.Unuse();
+ success_label_.Unuse();
+ exit_label_.Unuse();
+}
+
+
+void RegExpMacroAssemblerIA32::AdvanceCurrentPosition(int by) {
+ ASSERT(by > 0);
+ Label inside_string;
+ __ add(Operand(edi), Immediate(by * char_size()));
+}
+
+
+void RegExpMacroAssemblerIA32::AdvanceRegister(int reg, int by) {
+ ASSERT(reg >= 0);
+ ASSERT(reg < num_registers_);
+ __ add(register_location(reg), Immediate(by));
+}
+
+
+void RegExpMacroAssemblerIA32::Backtrack() {
+ __ pop(ecx);
+ __ add(Operand(ecx), Immediate(self_));
+ __ jmp(Operand(ecx));
+}
+
+
+void RegExpMacroAssemblerIA32::Bind(Label* label) {
+ __ bind(label);
+}
+
+void RegExpMacroAssemblerIA32::CheckBitmap(uc16 start,
+ Label* bitmap,
+ Label* on_zero) {
+ UNREACHABLE();
+ __ mov(eax, current_character());
+ __ sub(Operand(eax), Immediate(start));
+ __ cmp(eax, 64); // FIXME: 64 = length_of_bitmap_in_bits.
+ BranchOrBacktrack(greater_equal, on_zero);
+ __ mov(ebx, eax);
+ __ shr(ebx, 3);
+ // TODO(lrn): Where is the bitmap stored? Pass the bitmap as argument instead.
+ // __ mov(ecx, position_of_bitmap);
+ __ movzx_b(ebx, Operand(ecx, ebx, times_1, 0));
+ __ and_(eax, (1<<3)-1);
+ __ bt(Operand(ebx), eax);
+ __ j(carry, on_zero);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckCharacter(uc16 c, Label* on_equal) {
+ __ cmp(current_character(), c);
+ BranchOrBacktrack(equal, on_equal);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckCharacterGT(uc16 limit, Label* on_greater) {
+ __ cmp(current_character(), limit);
+ BranchOrBacktrack(greater, on_greater);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckNotAtStart(Label* on_not_at_start) {
+ __ cmp(Operand(ebp, kAtStart), Immediate(0));
+ BranchOrBacktrack(equal, on_not_at_start);
+ __ mov(eax, Operand(ebp, kInputEndOffset));
+ __ add(eax, Operand(edi));
+ __ cmp(eax, Operand(ebp, kInputStartOffset));
+ BranchOrBacktrack(not_equal, on_not_at_start);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckCharacterLT(uc16 limit, Label* on_less) {
+ __ cmp(current_character(), limit);
+ BranchOrBacktrack(less, on_less);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckCharacters(Vector<const uc16> str,
+ int cp_offset,
+ Label* on_failure) {
+ int byte_length = str.length() * char_size();
+ int byte_offset = cp_offset * char_size();
+ __ cmp(Operand(edi), Immediate(-(byte_offset + byte_length)));
+ BranchOrBacktrack(greater, on_failure);
+
+ if (str.length() <= kMaxInlineStringTests) {
+ for (int i = 0; i < str.length(); i++) {
+ if (mode_ == ASCII) {
+ __ cmpb(Operand(esi, edi, times_1, byte_offset + i),
+ static_cast<int8_t>(str[i]));
+ } else {
+ ASSERT(mode_ == UC16);
+ __ cmpw(Operand(esi, edi, times_1, byte_offset + i * sizeof(uc16)),
+ Immediate(str[i]));
+ }
+ __ j(not_equal, on_failure);
+ }
+ return;
+ }
+
+ ArraySlice constant_buffer = constants_.GetBuffer(str.length(), char_size());
+ if (mode_ == ASCII) {
+ for (int i = 0; i < str.length(); i++) {
+ constant_buffer.at<char>(i) = static_cast<char>(str[i]);
+ }
+ } else {
+ memcpy(constant_buffer.location(),
+ str.start(),
+ str.length() * sizeof(uc16));
+ }
+
+ __ mov(eax, edi);
+ __ mov(ebx, esi);
+ __ lea(edi, Operand(esi, edi, times_1, byte_offset));
+ LoadConstantBufferAddress(esi, &constant_buffer);
+ __ mov(ecx, str.length());
+ if (char_size() == 1) {
+ __ rep_cmpsb();
+ } else {
+ ASSERT(char_size() == 2);
+ __ rep_cmpsw();
+ }
+ __ mov(esi, ebx);
+ __ mov(edi, eax);
+ BranchOrBacktrack(not_equal, on_failure);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckCurrentPosition(int register_index,
+ Label* on_equal) {
+ __ cmp(edi, register_location(register_index));
+ BranchOrBacktrack(equal, on_equal);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckNotBackReferenceIgnoreCase(
+ int start_reg, Label* on_no_match) {
+ Label fallthrough;
+ __ mov(eax, register_location(start_reg));
+ __ mov(ecx, register_location(start_reg + 1));
+ __ sub(ecx, Operand(eax)); // Length to check.
+ __ j(less, on_no_match);
+ __ j(equal, &fallthrough);
+
+ UNIMPLEMENTED(); // TODO(lrn): Call runtime function to do test.
+
+ __ bind(&fallthrough);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckNotBackReference(
+ int start_reg, Label* on_no_match) {
+ Label fallthrough;
+ __ mov(eax, register_location(start_reg));
+ __ mov(ecx, register_location(start_reg + 1));
+ __ sub(ecx, Operand(eax)); // Length to check.
+ BranchOrBacktrack(less, on_no_match);
+ __ j(equal, &fallthrough);
+ // Check that there are sufficient characters left in the input.
+ __ mov(ebx, edi);
+ __ add(ebx, Operand(ecx));
+ BranchOrBacktrack(greater, on_no_match);
+
+ __ mov(ebx, edi);
+ __ mov(edx, esi);
+ __ add(edi, Operand(esi));
+ __ add(esi, Operand(eax));
+ __ rep_cmpsb();
+ __ mov(esi, edx);
+ Label success;
+ __ j(equal, &success);
+ __ mov(edi, ebx);
+ BranchOrBacktrack(no_condition, on_no_match);
+
+ __ bind(&success);
+ __ sub(edi, Operand(esi));
+
+ __ bind(&fallthrough);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckNotRegistersEqual(int reg1,
+ int reg2,
+ Label* on_not_equal) {
+ __ mov(eax, register_location(reg1));
+ __ cmp(eax, register_location(reg2));
+ BranchOrBacktrack(not_equal, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckNotCharacter(uc16 c, Label* on_not_equal) {
+ __ cmp(current_character(), c);
+ BranchOrBacktrack(not_equal, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckNotCharacterAfterOr(uc16 c,
+ uc16 mask,
+ Label* on_not_equal) {
+ __ mov(eax, current_character());
+ __ or_(eax, mask);
+ __ cmp(eax, c);
+ BranchOrBacktrack(not_equal, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckNotCharacterAfterMinusOr(
+ uc16 c,
+ uc16 mask,
+ Label* on_not_equal) {
+ __ lea(eax, Operand(current_character(), -mask));
+ __ or_(eax, mask);
+ __ cmp(eax, c);
+ BranchOrBacktrack(not_equal, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerIA32::DispatchHalfNibbleMap(
+ uc16 start,
+ Label* half_nibble_map,
+ const Vector<Label*>& destinations) {
+ UNIMPLEMENTED();
+ __ mov(eax, current_character());
+ __ sub(Operand(eax), Immediate(start));
+
+ __ mov(ecx, eax);
+ __ shr(eax, 2);
+ // FIXME: ecx must hold address of map
+ __ movzx_b(eax, Operand(ecx, eax, times_1, 0));
+ __ and_(ecx, 0x03);
+ __ add(ecx, Operand(ecx));
+ __ shr(eax); // Shift right cl times
+
+ Label second_bit_set, case_3, case_1;
+ __ test(eax, Immediate(0x02));
+ __ j(not_zero, &second_bit_set);
+ __ test(eax, Immediate(0x01));
+ __ j(not_zero, &case_1);
+ // Case 0:
+ __ jmp(destinations[0]);
+ __ bind(&case_1);
+ // Case 1:
+ __ jmp(destinations[1]);
+ __ bind(&second_bit_set);
+ __ test(eax, Immediate(0x01));
+ __ j(not_zero, &case_3);
+ // Case 2
+ __ jmp(destinations[2]);
+ __ bind(&case_3);
+ // Case 3:
+ __ jmp(destinations[3]);
+}
+
+
+void RegExpMacroAssemblerIA32::DispatchByteMap(
+ uc16 start,
+ Label* byte_map,
+ const Vector<Label*>& destinations) {
+ UNIMPLEMENTED();
+
+ Label fallthrough;
+ __ mov(eax, current_character());
+ __ sub(Operand(eax), Immediate(start));
+ __ cmp(eax, 64); // FIXME: 64 = size of map. Found somehow??
+ __ j(greater_equal, &fallthrough);
+ // TODO(lrn): ecx must hold address of map
+ __ movzx_b(eax, Operand(ecx, eax, times_1, 0));
+ // jump table: jump to destinations[eax];
+
+ __ bind(&fallthrough);
+}
+
+
+void RegExpMacroAssemblerIA32::DispatchHighByteMap(
+ byte start,
+ Label* byte_map,
+ const Vector<Label*>& destinations) {
+ UNIMPLEMENTED();
+
+ Label fallthrough;
+ __ mov(eax, current_character());
+ __ shr(eax, 8);
+ __ sub(Operand(eax), Immediate(start));
+ __ cmp(eax, destinations.length() - start);
+ __ j(greater_equal, &fallthrough);
+
+ // TODO(lrn) jumptable: jump to destinations[eax]
+ __ bind(&fallthrough);
+}
+
+
+void RegExpMacroAssemblerIA32::EmitOrLink(Label* label) {
+ UNIMPLEMENTED(); // Has no use.
+}
+
+
+void RegExpMacroAssemblerIA32::Fail() {
+ __ xor_(eax, Operand(eax)); // zero eax.
+ __ jmp(&exit_label_);
+}
+
+
+Handle<Object> RegExpMacroAssemblerIA32::GetCode() {
+ // Finalize code - write the entry point code now we know how many
+ // registers we need.
+
+ // Entry code:
+ __ bind(&entry_label_);
+ // Save callee-save registers. Order here should correspond to order of
+ // kBackup_ebx etc.
+ __ push(esi);
+ __ push(edi);
+ __ push(ebx); // Callee-save on MacOS.
+ __ enter(Immediate(num_registers_ * kPointerSize));
+ // Load string length.
+ __ mov(esi, Operand(ebp, kInputEndOffset));
+ // Load input position.
+ __ mov(edi, Operand(ebp, kInputStartOffset));
+ // Set up edi to be negative offset from string end.
+ __ sub(edi, Operand(esi));
+ // Set up esi to be end of string. First get location.
+ __ mov(edx, Operand(ebp, kInputBuffer));
+ // Dereference location to get string start.
+ __ mov(edx, Operand(edx, 0));
+ // Add start to length to complete esi setup.
+ __ add(esi, Operand(edx));
+ if (num_saved_registers_ > 0) {
+ // Fill saved registers with initial value = start offset - 1
+ __ mov(ecx, -num_saved_registers_);
+ __ mov(eax, Operand(edi));
+ __ sub(Operand(eax), Immediate(char_size()));
+ Label init_loop;
+ __ bind(&init_loop);
+ __ mov(Operand(ebp, ecx, times_4, +0), eax);
+ __ inc(ecx);
+ __ j(not_equal, &init_loop);
+ }
+ // Load previous char as initial value of current-character.
+ Label at_start;
+ __ cmp(Operand(ebp, kAtStart), Immediate(0));
+ __ j(not_equal, &at_start);
+ LoadCurrentCharToRegister(-1); // Load previous char.
+ __ jmp(&start_label_);
+ __ bind(&at_start);
+ __ mov(current_character(), '\n');
+ __ jmp(&start_label_);
+
+
+ // Exit code:
+ // Success
+ __ bind(&success_label_);
+ if (num_saved_registers_ > 0) {
+ // copy captures to output
+ __ mov(ebx, Operand(ebp, kRegisterOutput));
+ __ mov(ecx, Operand(ebp, kInputEndOffset));
+ __ sub(ecx, Operand(ebp, kInputStartOffset));
+ for (int i = 0; i < num_saved_registers_; i++) {
+ __ mov(eax, register_location(i));
+ __ add(eax, Operand(ecx)); // Convert to index from start, not end.
+ if (char_size() > 1) {
+ ASSERT(char_size() == 2);
+ __ sar(eax, 1); // Convert to character index, not byte.
+ }
+ __ mov(Operand(ebx, i * kPointerSize), eax);
+ }
+ }
+ __ mov(eax, Immediate(1));
+
+ // Exit and return eax
+ __ bind(&exit_label_);
+ __ leave();
+ __ pop(ebx);
+ __ pop(edi);
+ __ pop(esi);
+ __ ret(0);
+
+ CodeDesc code_desc;
+ masm_->GetCode(&code_desc);
+ Handle<Code> code = Factory::NewCode(code_desc,
+ NULL,
+ Code::ComputeFlags(Code::REGEXP),
+ self_);
+ LOG(CodeCreateEvent("RegExp", *code, "(Compiled RegExp)"));
+ return Handle<Object>::cast(code);
+}
+
+
+void RegExpMacroAssemblerIA32::GoTo(Label* to) {
+ __ jmp(to);
+}
+
+
+void RegExpMacroAssemblerIA32::IfRegisterGE(int reg,
+ int comparand,
+ Label* if_ge) {
+ __ cmp(register_location(reg), Immediate(comparand));
+ BranchOrBacktrack(greater_equal, if_ge);
+}
+
+
+void RegExpMacroAssemblerIA32::IfRegisterLT(int reg,
+ int comparand,
+ Label* if_lt) {
+ __ cmp(register_location(reg), Immediate(comparand));
+ BranchOrBacktrack(less, if_lt);
+}
+
+
+RegExpMacroAssembler::IrregexpImplementation
+ RegExpMacroAssemblerIA32::Implementation() {
+ return kIA32Implementation;
+}
+
+
+void RegExpMacroAssemblerIA32::LoadCurrentCharacter(int cp_offset,
+ Label* on_end_of_input) {
+ ASSERT(cp_offset >= 0);
+ ASSERT(cp_offset < (1<<30)); // Be sane! (And ensure negation works)
+ __ cmp(edi, -cp_offset * char_size());
+ BranchOrBacktrack(greater_equal, on_end_of_input);
+ LoadCurrentCharToRegister(cp_offset);
+}
+
+
+void RegExpMacroAssemblerIA32::PopCurrentPosition() {
+ __ pop(edi);
+}
+
+
+void RegExpMacroAssemblerIA32::PopRegister(int register_index) {
+ __ pop(register_location(register_index));
+}
+
+
+void RegExpMacroAssemblerIA32::PushBacktrack(Label* label) {
+ // CheckStackLimit(); // Not ready yet.
+ __ push(label, RelocInfo::NONE);
+}
+
+
+void RegExpMacroAssemblerIA32::PushCurrentPosition() {
+ __ push(edi);
+}
+
+
+void RegExpMacroAssemblerIA32::PushRegister(int register_index) {
+ __ push(register_location(register_index));
+}
+
+
+void RegExpMacroAssemblerIA32::ReadCurrentPositionFromRegister(int reg) {
+ __ mov(edi, register_location(reg));
+}
+
+
+void RegExpMacroAssemblerIA32::ReadStackPointerFromRegister(int reg) {
+ __ mov(esp, register_location(reg));
+}
+
+
+void RegExpMacroAssemblerIA32::SetRegister(int register_index, int to) {
+ ASSERT(register_index >= num_saved_registers_); // Reserved for positions!
+ __ mov(register_location(register_index), Immediate(to));
+}
+
+
+void RegExpMacroAssemblerIA32::Succeed() {
+ __ jmp(&success_label_);
+}
+
+
+void RegExpMacroAssemblerIA32::WriteCurrentPositionToRegister(int reg) {
+ __ mov(register_location(reg), edi);
+}
+
+void RegExpMacroAssemblerIA32::WriteStackPointerToRegister(int reg) {
+ __ mov(register_location(reg), esp);
+}
+
+
+// Private methods:
+
+Operand RegExpMacroAssemblerIA32::register_location(int register_index) {
+ ASSERT(register_index < (1<<30));
+ if (num_registers_ <= register_index) {
+ num_registers_ = register_index + 1;
+ }
+ return Operand(ebp, -(register_index + 1) * kPointerSize);
+}
+
+
+Register RegExpMacroAssemblerIA32::current_character() {
+ return edx;
+}
+
+
+size_t RegExpMacroAssemblerIA32::char_size() {
+ return static_cast<size_t>(mode_);
+}
+
+
+void RegExpMacroAssemblerIA32::BranchOrBacktrack(Condition condition,
+ Label* to) {
+ if (condition < 0) { // No condition
+ if (to == NULL) {
+ Backtrack();
+ return;
+ }
+ __ jmp(to);
+ return;
+ }
+ if (to == NULL) {
+ Label skip;
+ __ j(NegateCondition(condition), &skip);
+ Backtrack();
+ __ bind(&skip);
+ return;
+ }
+ __ j(condition, to);
+}
+
+
+void RegExpMacroAssemblerIA32::CheckStackLimit() {
+ if (FLAG_check_stack) {
+ // Check for preemption first.
+ Label no_preempt;
+ Label retry_preempt;
+ // Check for preemption.
+ ExternalReference stack_guard_limit =
+ ExternalReference::address_of_stack_guard_limit();
+ __ cmp(esp, Operand::StaticVariable(stack_guard_limit));
+ __ j(above, &no_preempt, taken);
+ __ push(edi); // Current position.
+ __ push(edx); // Current character.
+ // Restore original edi, esi.
+ __ mov(edi, Operand(ebp, kBackup_edi));
+ __ mov(esi, Operand(ebp, kBackup_esi));
+
+ __ bind(&retry_preempt);
+ // simulate stack for Runtime call.
+ __ push(eax);
+ __ push(Immediate(Smi::FromInt(0))); // Dummy receiver
+ __ CallRuntime(Runtime::kStackGuard, 1);
+ __ pop(eax);
+
+ __ cmp(esp, Operand::StaticVariable(stack_guard_limit));
+ __ j(below_equal, &retry_preempt);
+
+ __ pop(edx);
+ __ pop(edi);
+ __ mov(esi, Operand(ebp, kInputBuffer));
+ __ mov(esi, Operand(esi, 0));
+ __ add(esi, Operand(ebp, kInputEndOffset));
+
+ __ bind(&no_preempt);
+ }
+}
+
+
+void RegExpMacroAssemblerIA32::LoadCurrentCharToRegister(int cp_offset) {
+ if (mode_ == ASCII) {
+ __ movzx_b(current_character(), Operand(esi, edi, times_1, cp_offset));
+ return;
+ }
+ ASSERT(mode_ == UC16);
+ __ movzx_w(current_character(),
+ Operand(esi, edi, times_1, cp_offset * sizeof(uc16)));
+}
+
+
+void RegExpMacroAssemblerIA32::LoadConstantBufferAddress(Register reg,
+ ArraySlice* buffer) {
+ __ mov(reg, buffer->array());
+ __ add(Operand(reg), Immediate(buffer->base_offset()));
+}
+
+#undef __
+}} // namespace v8::internal
diff --git a/src/regexp-macro-assembler-ia32.h b/src/regexp-macro-assembler-ia32.h
new file mode 100644
index 0000000..d303910
--- /dev/null
+++ b/src/regexp-macro-assembler-ia32.h
@@ -0,0 +1,173 @@
+// 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 REGEXP_MACRO_ASSEMBLER_IA32_H_
+#define REGEXP_MACRO_ASSEMBLER_IA32_H_
+
+namespace v8 { namespace internal {
+
+class RegExpMacroAssemblerIA32: public RegExpMacroAssembler {
+ public:
+ // Type of input string to generate code for.
+ enum Mode {ASCII = 1, UC16 = 2};
+
+ RegExpMacroAssemblerIA32(Mode mode, int registers_to_save);
+ virtual ~RegExpMacroAssemblerIA32();
+ virtual void AdvanceCurrentPosition(int by);
+ virtual void AdvanceRegister(int reg, int by);
+ virtual void Backtrack();
+ virtual void Bind(Label* label);
+ virtual void CheckBitmap(uc16 start, Label* bitmap, Label* on_zero);
+ virtual void CheckCharacter(uc16 c, 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);
+ virtual void CheckCurrentPosition(int register_index, Label* on_equal);
+ 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(uc16 c, Label* on_not_equal);
+ virtual void CheckNotCharacterAfterOr(uc16 c, uc16 mask, Label* on_not_equal);
+ virtual void CheckNotCharacterAfterMinusOr(uc16 c,
+ uc16 mask,
+ Label* on_not_equal);
+ virtual void DispatchByteMap(uc16 start,
+ Label* byte_map,
+ const Vector<Label*>& destinations);
+ virtual void DispatchHalfNibbleMap(uc16 start,
+ Label* half_nibble_map,
+ const Vector<Label*>& destinations);
+ virtual void DispatchHighByteMap(byte start,
+ Label* byte_map,
+ const Vector<Label*>& destinations);
+ virtual void EmitOrLink(Label* label);
+ virtual void Fail();
+ virtual Handle<Object> GetCode();
+ 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 IrregexpImplementation Implementation();
+ virtual void LoadCurrentCharacter(int cp_offset, Label* on_end_of_input);
+ virtual void PopCurrentPosition();
+ virtual void PopRegister(int register_index);
+ virtual void PushBacktrack(Label* label);
+ virtual void PushCurrentPosition();
+ virtual void PushRegister(int register_index);
+ 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);
+ virtual void WriteStackPointerToRegister(int reg);
+
+ template <typename T>
+ static inline bool Execute(Code* code,
+ T** input,
+ int start_offset,
+ int end_offset,
+ int* output,
+ bool at_start) {
+ typedef bool (*matcher)(T**, int, int, int*, int);
+ matcher matcher_func = FUNCTION_CAST<matcher>(code->entry());
+ int at_start_val = at_start ? 1 : 0;
+ return matcher_func(input, start_offset, end_offset, output, at_start_val);
+ }
+
+ private:
+ // Offsets from ebp of arguments to function.
+ static const int kBackup_ebx = sizeof(uint32_t);
+ static const int kBackup_edi = kBackup_ebx + sizeof(uint32_t);
+ static const int kBackup_esi = kBackup_edi + sizeof(uint32_t);
+ static const int kReturn_eip = kBackup_esi + sizeof(uint32_t);
+ static const int kInputBuffer = kReturn_eip + sizeof(uint32_t);
+ static const int kInputStartOffset = kInputBuffer + sizeof(uint32_t);
+ static const int kInputEndOffset = kInputStartOffset + sizeof(uint32_t);
+ static const int kRegisterOutput = kInputEndOffset + sizeof(uint32_t);
+ static const int kAtStart = kRegisterOutput + sizeof(uint32_t);
+
+ // Initial size of code buffer.
+ static const size_t kRegExpCodeSize = 1024;
+ // Initial size of constant buffers allocated during compilation.
+ static const int kRegExpConstantsSize = 256;
+ // Only unroll loops up to this length.
+ static const int kMaxInlineStringTests = 8;
+ // Special "character" marking end of input.
+ static const uint32_t kEndOfInput = ~0;
+
+ // The ebp-relative location of a regexp register.
+ Operand register_location(int register_index);
+
+ // The register containing the current character after LoadCurrentCharacter.
+ Register current_character();
+
+ // Byte size of chars in the string to match (decided by the Mode argument)
+ size_t char_size();
+
+ // 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);
+
+ // Read a character from input at the given offset from the current
+ // position.
+ void LoadCurrentCharToRegister(int cp_offset);
+
+ // Load the address of a "constant buffer" (a slice of a byte array)
+ // into a register. The address is computed from the ByteArray* address
+ // and an offset. Uses no extra registers.
+ void LoadConstantBufferAddress(Register reg, ArraySlice* buffer);
+
+ // Adds code that checks whether preemption has been requested
+ // (and checks if we have hit the stack limit too).
+ void CheckStackLimit();
+
+ MacroAssembler* masm_;
+ // Constant buffer provider. Allocates external storage for storing
+ // constants.
+ ByteArrayProvider constants_;
+ // Which mode to generate code for (ASCII or UTF16).
+ 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_;
+ // Labels used internally.
+ Label entry_label_;
+ Label start_label_;
+ Label success_label_;
+ Label exit_label_;
+ // Handle used to represent the generated code object itself.
+ Handle<Object> self_;
+};
+
+}} // namespace v8::internal
+
+#endif /* REGEXP_MACRO_ASSEMBLER_IA32_H_ */
diff --git a/src/regexp-macro-assembler-irregexp-inl.h b/src/regexp-macro-assembler-irregexp-inl.h
new file mode 100644
index 0000000..faf12da
--- /dev/null
+++ b/src/regexp-macro-assembler-irregexp-inl.h
@@ -0,0 +1,68 @@
+// 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"
+
+
+namespace v8 { namespace internal {
+
+
+void RegExpMacroAssemblerIrregexp::Emit(uint32_t byte) {
+ ASSERT(pc_ <= buffer_.length());
+ if (pc_ == buffer_.length()) {
+ Expand();
+ }
+ buffer_[pc_++] = byte;
+}
+
+
+void RegExpMacroAssemblerIrregexp::Emit16(uint32_t word) {
+ ASSERT(pc_ <= buffer_.length());
+ if (pc_ + 1 >= buffer_.length()) {
+ Expand();
+ }
+ Store16(buffer_.start() + pc_, word);
+ pc_ += 2;
+}
+
+
+void RegExpMacroAssemblerIrregexp::Emit32(uint32_t word) {
+ ASSERT(pc_ <= buffer_.length());
+ if (pc_ + 3 >= buffer_.length()) {
+ Expand();
+ }
+ Store32(buffer_.start() + pc_, word);
+ pc_ += 4;
+}
+
+
+} } // namespace v8::internal
diff --git a/src/regexp-macro-assembler-irregexp.cc b/src/regexp-macro-assembler-irregexp.cc
new file mode 100644
index 0000000..b821788
--- /dev/null
+++ b/src/regexp-macro-assembler-irregexp.cc
@@ -0,0 +1,389 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+#include "ast.h"
+#include "bytecodes-irregexp.h"
+#include "regexp-macro-assembler.h"
+#include "regexp-macro-assembler-irregexp.h"
+#include "regexp-macro-assembler-irregexp-inl.h"
+
+
+namespace v8 { namespace internal {
+
+
+RegExpMacroAssemblerIrregexp::RegExpMacroAssemblerIrregexp(Vector<byte> buffer)
+ : buffer_(buffer),
+ pc_(0),
+ own_buffer_(false) {
+}
+
+
+RegExpMacroAssemblerIrregexp::~RegExpMacroAssemblerIrregexp() {
+}
+
+
+RegExpMacroAssemblerIrregexp::IrregexpImplementation
+RegExpMacroAssemblerIrregexp::Implementation() {
+ return kBytecodeImplementation;
+}
+
+
+void RegExpMacroAssemblerIrregexp::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 RegExpMacroAssemblerIrregexp::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);
+ }
+}
+
+
+void RegExpMacroAssemblerIrregexp::PopRegister(int register_index) {
+ Emit(BC_POP_REGISTER);
+ Emit(register_index);
+}
+
+
+void RegExpMacroAssemblerIrregexp::PushRegister(int register_index) {
+ ASSERT(register_index >= 0);
+ Emit(BC_PUSH_REGISTER);
+ Emit(register_index);
+}
+
+
+void RegExpMacroAssemblerIrregexp::WriteCurrentPositionToRegister(
+ int register_index) {
+ ASSERT(register_index >= 0);
+ Emit(BC_SET_REGISTER_TO_CP);
+ Emit(register_index);
+ Emit32(0); // Current position offset.
+}
+
+
+void RegExpMacroAssemblerIrregexp::ReadCurrentPositionFromRegister(
+ int register_index) {
+ ASSERT(register_index >= 0);
+ Emit(BC_SET_CP_TO_REGISTER);
+ Emit(register_index);
+}
+
+
+void RegExpMacroAssemblerIrregexp::WriteStackPointerToRegister(
+ int register_index) {
+ ASSERT(register_index >= 0);
+ Emit(BC_SET_REGISTER_TO_SP);
+ Emit(register_index);
+}
+
+
+void RegExpMacroAssemblerIrregexp::ReadStackPointerFromRegister(
+ int register_index) {
+ ASSERT(register_index >= 0);
+ Emit(BC_SET_SP_TO_REGISTER);
+ Emit(register_index);
+}
+
+
+void RegExpMacroAssemblerIrregexp::SetRegister(int register_index, int to) {
+ ASSERT(register_index >= 0);
+ Emit(BC_SET_REGISTER);
+ Emit(register_index);
+ Emit32(to);
+}
+
+
+void RegExpMacroAssemblerIrregexp::AdvanceRegister(int register_index, int by) {
+ ASSERT(register_index >= 0);
+ Emit(BC_ADVANCE_REGISTER);
+ Emit(register_index);
+ Emit32(by);
+}
+
+
+void RegExpMacroAssemblerIrregexp::PopCurrentPosition() {
+ Emit(BC_POP_CP);
+}
+
+
+void RegExpMacroAssemblerIrregexp::PushCurrentPosition() {
+ Emit(BC_PUSH_CP);
+ Emit32(0); // Current position offset.
+}
+
+
+void RegExpMacroAssemblerIrregexp::Backtrack() {
+ Emit(BC_POP_BT);
+}
+
+
+void RegExpMacroAssemblerIrregexp::GoTo(Label* l) {
+ Emit(BC_GOTO);
+ EmitOrLink(l);
+}
+
+
+void RegExpMacroAssemblerIrregexp::PushBacktrack(Label* l) {
+ Emit(BC_PUSH_BT);
+ EmitOrLink(l);
+}
+
+
+void RegExpMacroAssemblerIrregexp::Succeed() {
+ Emit(BC_SUCCEED);
+}
+
+
+void RegExpMacroAssemblerIrregexp::Fail() {
+ Emit(BC_FAIL);
+}
+
+
+void RegExpMacroAssemblerIrregexp::AdvanceCurrentPosition(int by) {
+ Emit(BC_ADVANCE_CP);
+ Emit32(by);
+}
+
+
+void RegExpMacroAssemblerIrregexp::CheckCurrentPosition(
+ int register_index,
+ Label* on_equal) {
+ // TODO(erikcorry): Implement.
+ UNIMPLEMENTED();
+}
+
+
+void RegExpMacroAssemblerIrregexp::LoadCurrentCharacter(int cp_offset,
+ Label* on_failure) {
+ Emit(BC_LOAD_CURRENT_CHAR);
+ Emit32(cp_offset);
+ EmitOrLink(on_failure);
+}
+
+
+void RegExpMacroAssemblerIrregexp::CheckCharacterLT(uc16 limit,
+ Label* on_less) {
+ Emit(BC_CHECK_LT);
+ Emit16(limit);
+ EmitOrLink(on_less);
+}
+
+
+void RegExpMacroAssemblerIrregexp::CheckCharacterGT(uc16 limit,
+ Label* on_greater) {
+ Emit(BC_CHECK_GT);
+ Emit16(limit);
+ EmitOrLink(on_greater);
+}
+
+
+void RegExpMacroAssemblerIrregexp::CheckCharacter(uc16 c, Label* on_equal) {
+ Emit(BC_CHECK_CHAR);
+ Emit16(c);
+ EmitOrLink(on_equal);
+}
+
+
+void RegExpMacroAssemblerIrregexp::CheckNotAtStart(Label* on_not_at_start) {
+ Emit(BC_CHECK_NOT_AT_START);
+ EmitOrLink(on_not_at_start);
+}
+
+
+void RegExpMacroAssemblerIrregexp::CheckNotCharacter(uc16 c,
+ Label* on_not_equal) {
+ Emit(BC_CHECK_NOT_CHAR);
+ Emit16(c);
+ EmitOrLink(on_not_equal);
+}
+
+
+void RegExpMacroAssemblerIrregexp::CheckNotCharacterAfterOr(
+ uc16 c,
+ uc16 mask,
+ Label* on_not_equal) {
+ Emit(BC_OR_CHECK_NOT_CHAR);
+ Emit16(c);
+ Emit16(mask);
+ EmitOrLink(on_not_equal);
+}
+
+
+void RegExpMacroAssemblerIrregexp::CheckNotCharacterAfterMinusOr(
+ uc16 c,
+ uc16 mask,
+ Label* on_not_equal) {
+ Emit(BC_MINUS_OR_CHECK_NOT_CHAR);
+ Emit16(c);
+ Emit16(mask);
+ EmitOrLink(on_not_equal);
+}
+
+
+void RegExpMacroAssemblerIrregexp::CheckNotBackReference(int start_reg,
+ Label* on_not_equal) {
+ Emit(BC_CHECK_NOT_BACK_REF);
+ Emit(start_reg);
+ EmitOrLink(on_not_equal);
+}
+
+
+void RegExpMacroAssemblerIrregexp::CheckNotBackReferenceIgnoreCase(
+ int start_reg,
+ Label* on_not_equal) {
+ Emit(BC_CHECK_NOT_BACK_REF_NO_CASE);
+ Emit(start_reg);
+ EmitOrLink(on_not_equal);
+}
+
+
+void RegExpMacroAssemblerIrregexp::CheckNotRegistersEqual(int reg1,
+ int reg2,
+ Label* on_not_equal) {
+ Emit(BC_CHECK_NOT_REGS_EQUAL);
+ Emit(reg1);
+ Emit(reg2);
+ EmitOrLink(on_not_equal);
+}
+
+
+void RegExpMacroAssemblerIrregexp::CheckBitmap(uc16 start,
+ Label* bitmap,
+ Label* on_zero) {
+ UNIMPLEMENTED();
+}
+
+
+void RegExpMacroAssemblerIrregexp::DispatchHalfNibbleMap(
+ uc16 start,
+ Label* half_nibble_map,
+ const Vector<Label*>& table) {
+ UNIMPLEMENTED();
+}
+
+
+void RegExpMacroAssemblerIrregexp::DispatchByteMap(
+ uc16 start,
+ Label* byte_map,
+ const Vector<Label*>& table) {
+ UNIMPLEMENTED();
+}
+
+
+void RegExpMacroAssemblerIrregexp::DispatchHighByteMap(
+ byte start,
+ Label* byte_map,
+ const Vector<Label*>& table) {
+ UNIMPLEMENTED();
+}
+
+
+void RegExpMacroAssemblerIrregexp::CheckCharacters(
+ Vector<const uc16> str,
+ int cp_offset,
+ Label* on_failure) {
+ for (int i = str.length() - 1; i >= 0; i--) {
+ Emit(BC_LOAD_CURRENT_CHAR);
+ Emit32(cp_offset + i);
+ EmitOrLink(on_failure);
+ Emit(BC_CHECK_NOT_CHAR);
+ Emit16(str[i]);
+ EmitOrLink(on_failure);
+ }
+}
+
+
+void RegExpMacroAssemblerIrregexp::IfRegisterLT(int register_index,
+ int comparand,
+ Label* on_less_than) {
+ ASSERT(comparand >= 0 && comparand <= 65535);
+ Emit(BC_CHECK_REGISTER_LT);
+ Emit(register_index);
+ Emit16(comparand);
+ EmitOrLink(on_less_than);
+}
+
+
+void RegExpMacroAssemblerIrregexp::IfRegisterGE(int register_index,
+ int comparand,
+ Label* on_greater_or_equal) {
+ ASSERT(comparand >= 0 && comparand <= 65535);
+ Emit(BC_CHECK_REGISTER_GE);
+ Emit(register_index);
+ Emit16(comparand);
+ EmitOrLink(on_greater_or_equal);
+}
+
+
+Handle<Object> RegExpMacroAssemblerIrregexp::GetCode() {
+ Handle<ByteArray> array = Factory::NewByteArray(length());
+ Copy(array->GetDataStartAddress());
+ return array;
+}
+
+
+int RegExpMacroAssemblerIrregexp::length() {
+ return pc_;
+}
+
+
+void RegExpMacroAssemblerIrregexp::Copy(Address a) {
+ memcpy(a, buffer_.start(), length());
+}
+
+
+void RegExpMacroAssemblerIrregexp::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
diff --git a/src/regexp-macro-assembler-irregexp.h b/src/regexp-macro-assembler-irregexp.h
new file mode 100644
index 0000000..77d18e1
--- /dev/null
+++ b/src/regexp-macro-assembler-irregexp.h
@@ -0,0 +1,126 @@
+// 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_REGEXP_MACRO_ASSEMBLER_IRREGEXP_H_
+#define V8_REGEXP_MACRO_ASSEMBLER_IRREGEXP_H_
+
+namespace v8 { namespace internal {
+
+
+class RegExpMacroAssemblerIrregexp: public RegExpMacroAssembler {
+ 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 RegExpMacroAssemblerIrregexp(Vector<byte>);
+ virtual ~RegExpMacroAssemblerIrregexp();
+ virtual void Bind(Label* label);
+ virtual void EmitOrLink(Label* label);
+ virtual void AdvanceCurrentPosition(int by); // Signed cp change.
+ virtual void PopCurrentPosition();
+ virtual void PushCurrentPosition();
+ virtual void Backtrack();
+ virtual void GoTo(Label* label);
+ virtual void PushBacktrack(Label* label);
+ virtual void Succeed();
+ virtual void Fail();
+ virtual void PopRegister(int register_index);
+ virtual void PushRegister(int register_index);
+ virtual void AdvanceRegister(int reg, int by); // r[reg] += by.
+ virtual void SetRegister(int register_index, int to);
+ virtual void WriteCurrentPositionToRegister(int reg);
+ virtual void ReadCurrentPositionFromRegister(int reg);
+ virtual void WriteStackPointerToRegister(int reg);
+ virtual void ReadStackPointerFromRegister(int reg);
+ virtual void LoadCurrentCharacter(int cp_offset, Label* on_end_of_input);
+ virtual void CheckCharacterLT(uc16 limit, Label* on_less);
+ virtual void CheckCharacterGT(uc16 limit, Label* on_greater);
+ virtual void CheckCharacter(uc16 c, Label* on_equal);
+ virtual void CheckNotAtStart(Label* on_not_at_start);
+ virtual void CheckNotCharacter(uc16 c, Label* on_not_equal);
+ virtual void CheckNotCharacterAfterOr(uc16 c, uc16 mask, Label* on_not_equal);
+ virtual void CheckNotCharacterAfterMinusOr(uc16 c,
+ uc16 mask,
+ Label* on_not_equal);
+ 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 CheckCharacters(Vector<const uc16> str,
+ int cp_offset,
+ Label* on_failure);
+ virtual void CheckCurrentPosition(int register_index, Label* on_equal);
+ virtual void CheckBitmap(uc16 start, Label* bitmap, Label* on_zero);
+ virtual void DispatchHalfNibbleMap(uc16 start,
+ Label* half_nibble_map,
+ const Vector<Label*>& destinations);
+ virtual void DispatchByteMap(uc16 start,
+ Label* byte_map,
+ const Vector<Label*>& destinations);
+ virtual void DispatchHighByteMap(byte start,
+ Label* byte_map,
+ const Vector<Label*>& destinations);
+ virtual void IfRegisterLT(int register_index, int comparand, Label* if_lt);
+ virtual void IfRegisterGE(int register_index, int comparand, Label* if_ge);
+
+ virtual IrregexpImplementation Implementation();
+ virtual Handle<Object> GetCode();
+ private:
+ void Expand();
+ // 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);
+
+
+
+ // The buffer into which code and relocation info are generated.
+ Vector<byte> buffer_;
+ // The program counter.
+ int pc_;
+ // True if the assembler owns the buffer, false if buffer is external.
+ bool own_buffer_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(RegExpMacroAssemblerIrregexp);
+};
+
+} } // namespace v8::internal
+
+#endif // V8_REGEXP_MACRO_ASSEMBLER_IRREGEXP_H_
diff --git a/src/regexp-macro-assembler-tracer.cc b/src/regexp-macro-assembler-tracer.cc
new file mode 100644
index 0000000..80dff25
--- /dev/null
+++ b/src/regexp-macro-assembler-tracer.cc
@@ -0,0 +1,342 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+#include "ast.h"
+#include "regexp-macro-assembler.h"
+#include "regexp-macro-assembler-tracer.h"
+
+namespace v8 { namespace internal {
+
+RegExpMacroAssemblerTracer::RegExpMacroAssemblerTracer(
+ RegExpMacroAssembler* assembler) :
+ assembler_(assembler) {
+ unsigned int type = assembler->Implementation();
+ ASSERT(type < 3);
+ const char* impl_names[3] = {"IA32", "ARM", "Bytecode"};
+ PrintF("RegExpMacroAssembler%s();\n", impl_names[type]);
+}
+
+
+RegExpMacroAssemblerTracer::~RegExpMacroAssemblerTracer() {
+}
+
+
+void RegExpMacroAssemblerTracer::Bind(Label* label) {
+ PrintF("label[%08x]: (Bind)\n", label, label);
+ assembler_->Bind(label);
+}
+
+
+void RegExpMacroAssemblerTracer::EmitOrLink(Label* label) {
+ PrintF(" EmitOrLink(label[%08x]);\n", label);
+ assembler_->EmitOrLink(label);
+}
+
+
+void RegExpMacroAssemblerTracer::AdvanceCurrentPosition(int by) {
+ PrintF(" AdvanceCurrentPosition(by=%d);\n", by);
+ assembler_->AdvanceCurrentPosition(by);
+}
+
+
+void RegExpMacroAssemblerTracer::PopCurrentPosition() {
+ PrintF(" PopCurrentPosition();\n");
+ assembler_->PopCurrentPosition();
+}
+
+
+void RegExpMacroAssemblerTracer::PushCurrentPosition() {
+ PrintF(" PushCurrentPosition();\n");
+ assembler_->PushCurrentPosition();
+}
+
+
+void RegExpMacroAssemblerTracer::Backtrack() {
+ PrintF(" Backtrack();\n");
+ assembler_->Backtrack();
+}
+
+
+void RegExpMacroAssemblerTracer::GoTo(Label* label) {
+ PrintF(" GoTo(label[%08x]);\n\n", label);
+ assembler_->GoTo(label);
+}
+
+
+void RegExpMacroAssemblerTracer::PushBacktrack(Label* label) {
+ PrintF(" PushBacktrack(label[%08x]);\n", label);
+ assembler_->PushBacktrack(label);
+}
+
+
+void RegExpMacroAssemblerTracer::Succeed() {
+ PrintF(" Succeed();\n");
+ assembler_->Succeed();
+}
+
+
+void RegExpMacroAssemblerTracer::Fail() {
+ PrintF(" Fail();\n");
+ assembler_->Fail();
+}
+
+
+void RegExpMacroAssemblerTracer::PopRegister(int register_index) {
+ PrintF(" PopRegister(register=%d);\n", register_index);
+ assembler_->PopRegister(register_index);
+}
+
+
+void RegExpMacroAssemblerTracer::PushRegister(int register_index) {
+ PrintF(" PushRegister(register=%d);\n", register_index);
+ assembler_->PushRegister(register_index);
+}
+
+
+void RegExpMacroAssemblerTracer::AdvanceRegister(int reg, int by) {
+ PrintF(" AdvanceRegister(register=%d, by=%d);\n", reg, by);
+ assembler_->AdvanceRegister(reg, by);
+}
+
+
+void RegExpMacroAssemblerTracer::SetRegister(int register_index, int to) {
+ PrintF(" SetRegister(register=%d, to=%d);\n", register_index, to);
+ assembler_->SetRegister(register_index, to);
+}
+
+
+void RegExpMacroAssemblerTracer::WriteCurrentPositionToRegister(int reg) {
+ PrintF(" WriteCurrentPositionToRegister(register=%d);\n", reg);
+ assembler_->WriteCurrentPositionToRegister(reg);
+}
+
+
+void RegExpMacroAssemblerTracer::ReadCurrentPositionFromRegister(int reg) {
+ PrintF(" ReadCurrentPositionFromRegister(register=%d);\n", reg);
+ assembler_->ReadCurrentPositionFromRegister(reg);
+}
+
+
+void RegExpMacroAssemblerTracer::WriteStackPointerToRegister(int reg) {
+ PrintF(" WriteStackPointerToRegister(register=%d);\n", reg);
+ assembler_->WriteStackPointerToRegister(reg);
+}
+
+
+void RegExpMacroAssemblerTracer::ReadStackPointerFromRegister(int reg) {
+ PrintF(" ReadStackPointerFromRegister(register=%d);\n", reg);
+ assembler_->ReadStackPointerFromRegister(reg);
+}
+
+
+void RegExpMacroAssemblerTracer::LoadCurrentCharacter(int cp_offset,
+ Label* on_end_of_input) {
+ PrintF(" LoadCurrentCharacter(cp_offset=%d, label[%08x]);\n", cp_offset,
+ on_end_of_input);
+ assembler_->LoadCurrentCharacter(cp_offset, on_end_of_input);
+}
+
+
+void RegExpMacroAssemblerTracer::CheckCharacterLT(uc16 limit, Label* on_less) {
+ PrintF(" CheckCharacterLT(c='u%04x', label[%08x]);\n", limit, on_less);
+ assembler_->CheckCharacterLT(limit, on_less);
+}
+
+
+void RegExpMacroAssemblerTracer::CheckCharacterGT(uc16 limit,
+ Label* on_greater) {
+ PrintF(" CheckCharacterGT(c='u%04x', label[%08x]);\n", limit, on_greater);
+ assembler_->CheckCharacterGT(limit, on_greater);
+}
+
+
+void RegExpMacroAssemblerTracer::CheckCharacter(uc16 c, Label* on_equal) {
+ PrintF(" CheckCharacter(c='u%04x', label[%08x]);\n", c, on_equal);
+ assembler_->CheckCharacter(c, on_equal);
+}
+
+
+void RegExpMacroAssemblerTracer::CheckNotAtStart(Label* on_not_at_start) {
+ PrintF(" CheckNotAtStart(label[%08x]);\n", on_not_at_start);
+ assembler_->CheckNotAtStart(on_not_at_start);
+}
+
+
+void RegExpMacroAssemblerTracer::CheckNotCharacter(uc16 c,
+ Label* on_not_equal) {
+ PrintF(" CheckNotCharacter(c='u%04x', label[%08x]);\n", c, on_not_equal);
+ assembler_->CheckNotCharacter(c, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerTracer::CheckNotCharacterAfterOr(uc16 c, uc16 mask,
+ Label* on_not_equal) {
+ PrintF(" CheckNotCharacterAfterOr(c='u%04x', mask=0x%04x, label[%08x]);\n", c,
+ mask, on_not_equal);
+ assembler_->CheckNotCharacterAfterOr(c, mask, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerTracer::CheckNotCharacterAfterMinusOr(
+ uc16 c,
+ uc16 mask,
+ Label* on_not_equal) {
+ PrintF(" CheckNotCharacterAfterMinusOr(c='u%04x', mask=0x%04x, "
+ "label[%08x]);\n", c, mask, on_not_equal);
+ assembler_->CheckNotCharacterAfterMinusOr(c, mask, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerTracer::CheckNotBackReference(int start_reg,
+ Label* on_no_match) {
+ PrintF(" CheckNotBackReference(register=%d, label[%08x]);\n", start_reg,
+ on_no_match);
+ assembler_->CheckNotBackReference(start_reg, on_no_match);
+}
+
+
+void RegExpMacroAssemblerTracer::CheckNotBackReferenceIgnoreCase(
+ int start_reg,
+ Label* on_no_match) {
+ PrintF(" CheckNotBackReferenceIgnoreCase(register=%d, label[%08x]);\n",
+ start_reg, on_no_match);
+ assembler_->CheckNotBackReferenceIgnoreCase(start_reg, on_no_match);
+}
+
+
+void RegExpMacroAssemblerTracer::CheckNotRegistersEqual(int reg1,
+ int reg2,
+ Label* on_not_equal) {
+ PrintF(" CheckNotRegistersEqual(reg1=%d, reg2=%d, label[%08x]);\n",
+ reg1,
+ reg2,
+ on_not_equal);
+ assembler_->CheckNotRegistersEqual(reg1, reg2, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerTracer::CheckCharacters(Vector<const uc16> str,
+ int cp_offset,
+ Label* on_failure) {
+ PrintF(" CheckCharacters(str=\"");
+ for (int i = 0; i < str.length(); i++) {
+ PrintF("u%04x", str[i]);
+ }
+ PrintF("\", cp_offset=%d, label[%08x])\n", cp_offset, on_failure);
+ assembler_->CheckCharacters(str, cp_offset, on_failure);
+}
+
+
+void RegExpMacroAssemblerTracer::CheckCurrentPosition(int register_index,
+ Label* on_equal) {
+ PrintF(" CheckCurrentPosition(register=%d, label[%08x]);\n", register_index,
+ on_equal);
+ assembler_->CheckCurrentPosition(register_index, on_equal);
+}
+
+
+void RegExpMacroAssemblerTracer::CheckBitmap(uc16 start, Label* bitmap,
+ Label* on_zero) {
+ PrintF(" CheckBitmap(start=u$04x, <bitmap>, label[%08x]);\n", start, on_zero);
+ assembler_->CheckBitmap(start, bitmap, on_zero);
+}
+
+
+void RegExpMacroAssemblerTracer::DispatchHalfNibbleMap(
+ uc16 start,
+ Label* half_nibble_map,
+ const Vector<Label*>& destinations) {
+ PrintF(" DispatchHalfNibbleMap(start=u$04x, <half_nibble_map>, [", start);
+ for (int i = 0; i < destinations.length(); i++) {
+ if (i > 0)
+ PrintF(", ");
+ PrintF("label[%08x]", destinations[i]);
+ }
+ PrintF(");\n");
+ assembler_->DispatchHalfNibbleMap(start, half_nibble_map, destinations);
+}
+
+
+void RegExpMacroAssemblerTracer::DispatchByteMap(
+ uc16 start,
+ Label* byte_map,
+ const Vector<Label*>& destinations) {
+ PrintF(" DispatchByteMap(start=u$04x, <byte_map>, [", start);
+ for (int i = 0; i < destinations.length(); i++) {
+ if (i > 0)
+ PrintF(", ");
+ PrintF("label[%08x]", destinations[i]);
+ }
+ PrintF(");\n");
+ assembler_->DispatchByteMap(start, byte_map, destinations);
+}
+
+
+void RegExpMacroAssemblerTracer::DispatchHighByteMap(
+ byte start,
+ Label* byte_map,
+ const Vector<Label*>& destinations) {
+ PrintF(" DispatchHighByteMap(start=u$04x, <byte_map>, [", start);
+ for (int i = 0; i < destinations.length(); i++) {
+ if (i > 0)
+ PrintF(", ");
+ PrintF("label[%08x]", destinations[i]);
+ }
+ PrintF(");\n");
+ assembler_->DispatchHighByteMap(start, byte_map, destinations);
+}
+
+
+void RegExpMacroAssemblerTracer::IfRegisterLT(int register_index,
+ int comparand, Label* if_lt) {
+ PrintF(" IfRegisterLT(register=%d, number=%d, label[%08x]);\n",
+ register_index, comparand, if_lt);
+ assembler_->IfRegisterLT(register_index, comparand, if_lt);
+}
+
+
+void RegExpMacroAssemblerTracer::IfRegisterGE(int register_index,
+ int comparand, Label* if_ge) {
+ PrintF(" IfRegisterGE(register=%d, number=%d, label[%08x]);\n",
+ register_index, comparand, if_ge);
+ assembler_->IfRegisterGE(register_index, comparand, if_ge);
+}
+
+
+RegExpMacroAssembler::IrregexpImplementation
+ RegExpMacroAssemblerTracer::Implementation() {
+ return assembler_->Implementation();
+}
+
+
+Handle<Object> RegExpMacroAssemblerTracer::GetCode() {
+ PrintF(" GetCode();\n");
+ return assembler_->GetCode();
+}
+
+}} // namespace v8::internal
diff --git a/src/regexp-macro-assembler-tracer.h b/src/regexp-macro-assembler-tracer.h
new file mode 100644
index 0000000..3488082
--- /dev/null
+++ b/src/regexp-macro-assembler-tracer.h
@@ -0,0 +1,103 @@
+// 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 REGEXP_MACRO_ASSEMBLER_TRACER_H_
+#define REGEXP_MACRO_ASSEMBLER_TRACER_H_
+
+namespace v8 { namespace internal {
+
+// Decorator on a RegExpMacroAssembler that write all calls.
+class RegExpMacroAssemblerTracer: public RegExpMacroAssembler {
+ public:
+ explicit RegExpMacroAssemblerTracer(RegExpMacroAssembler* assembler);
+ virtual ~RegExpMacroAssemblerTracer();
+
+ virtual void AdvanceCurrentPosition(int by); // Signed cp change.
+ virtual void AdvanceRegister(int reg, int by); // r[reg] += by.
+ virtual void Backtrack();
+ virtual void Bind(Label* label);
+ virtual void CheckBitmap(uc16 start, Label* bitmap, Label* on_zero);
+ virtual void CheckCharacter(uc16 c, 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);
+ virtual void CheckCurrentPosition(
+ int register_index,
+ Label* on_equal);
+ 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(uc16 c, Label* on_not_equal);
+ virtual void CheckNotCharacterAfterOr(uc16 c,
+ uc16 or_with,
+ Label* on_not_equal);
+ virtual void CheckNotCharacterAfterMinusOr(uc16 c,
+ uc16 minus_then_or_with,
+ Label* on_not_equal);
+ virtual void DispatchByteMap(
+ uc16 start,
+ Label* byte_map,
+ const Vector<Label*>& destinations);
+ virtual void DispatchHalfNibbleMap(
+ uc16 start,
+ Label* half_nibble_map,
+ const Vector<Label*>& destinations);
+ virtual void DispatchHighByteMap(
+ byte start,
+ Label* byte_map,
+ const Vector<Label*>& destinations);
+ virtual void EmitOrLink(Label* label);
+ virtual void Fail();
+ virtual Handle<Object> GetCode();
+ 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 IrregexpImplementation Implementation();
+ virtual void LoadCurrentCharacter(int cp_offset, Label* on_end_of_input);
+ virtual void PopCurrentPosition();
+ virtual void PopRegister(int register_index);
+ virtual void PushBacktrack(Label* label);
+ virtual void PushCurrentPosition();
+ virtual void PushRegister(int register_index);
+ 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);
+ virtual void WriteStackPointerToRegister(int reg);
+ private:
+ RegExpMacroAssembler* assembler_;
+};
+
+}} // namespace v8::internal
+
+#endif // REGEXP_MACRO_ASSEMBLER_TRACER_H_
diff --git a/src/regexp-macro-assembler.cc b/src/regexp-macro-assembler.cc
new file mode 100644
index 0000000..27bf9e2
--- /dev/null
+++ b/src/regexp-macro-assembler.cc
@@ -0,0 +1,77 @@
+// Copyright 2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <string.h>
+#include "v8.h"
+#include "ast.h"
+#include "assembler.h"
+#include "regexp-macro-assembler.h"
+
+namespace v8 { namespace internal {
+
+RegExpMacroAssembler::RegExpMacroAssembler() {
+}
+
+
+RegExpMacroAssembler::~RegExpMacroAssembler() {
+}
+
+
+ByteArrayProvider::ByteArrayProvider(unsigned int initial_size)
+ : byte_array_size_(initial_size),
+ current_byte_array_(),
+ current_byte_array_free_offset_(initial_size) {}
+
+
+ArraySlice ByteArrayProvider::GetBuffer(unsigned int size,
+ unsigned int elem_size) {
+ ASSERT(size > 0);
+ size_t byte_size = size * elem_size;
+ int free_offset = current_byte_array_free_offset_;
+ // align elements
+ free_offset += elem_size - 1;
+ free_offset = free_offset - (free_offset % elem_size);
+
+ if (free_offset + byte_size > byte_array_size_) {
+ if (byte_size > (byte_array_size_ / 2)) {
+ Handle<ByteArray> solo_buffer(Factory::NewByteArray(byte_size, TENURED));
+ return ArraySlice(solo_buffer, 0);
+ }
+ current_byte_array_ = Factory::NewByteArray(byte_array_size_, TENURED);
+ free_offset = 0;
+ }
+ current_byte_array_free_offset_ = free_offset + size;
+ return ArraySlice(current_byte_array_, free_offset);
+}
+
+template <typename T>
+ArraySlice ByteArrayProvider::GetBuffer(Vector<T> values) {
+ ArraySlice slice = GetBuffer(values.length(), sizeof(T));
+ memcpy(slice.location(), values.start(), values.length() * sizeof(T));
+ return slice;
+}
+} }
diff --git a/src/regexp-macro-assembler.h b/src/regexp-macro-assembler.h
new file mode 100644
index 0000000..8cbd274
--- /dev/null
+++ b/src/regexp-macro-assembler.h
@@ -0,0 +1,186 @@
+// 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_REGEXP_MACRO_ASSEMBLER_H_
+#define V8_REGEXP_MACRO_ASSEMBLER_H_
+
+namespace v8 { namespace internal {
+
+
+struct DisjunctDecisionRow {
+ RegExpCharacterClass cc;
+ Label* on_match;
+};
+
+
+class RegExpMacroAssembler {
+ public:
+ enum IrregexpImplementation {
+ kIA32Implementation,
+ kARMImplementation,
+ kBytecodeImplementation};
+
+ RegExpMacroAssembler();
+ virtual ~RegExpMacroAssembler();
+ virtual void AdvanceCurrentPosition(int by) = 0; // Signed cp change.
+ virtual void AdvanceRegister(int reg, int by) = 0; // r[reg] += by.
+ virtual void Backtrack() = 0;
+ virtual void Bind(Label* label) = 0;
+ // Check the current character against a bitmap. The range of the current
+ // character must be from start to start + length_of_bitmap_in_bits.
+ virtual void CheckBitmap(
+ uc16 start, // The bitmap is indexed from this character.
+ Label* bitmap, // Where the bitmap is emitted.
+ Label* on_zero) = 0; // Where to go if the bit is 0. Fall through on 1.
+ // Dispatch after looking the current character up in a 2-bits-per-entry
+ // map. The destinations vector has up to 4 labels.
+ virtual void CheckCharacter(uc16 c, Label* on_equal) = 0;
+ virtual void CheckCharacterGT(uc16 limit, Label* on_greater) = 0;
+ virtual void CheckCharacterLT(uc16 limit, Label* on_less) = 0;
+ // Check the current character for a match with a literal string. If we
+ // fail to match then goto the on_failure label. End of input always
+ // matches. If the label is NULL then we should pop a backtrack address off
+ // the stack abnd go to that.
+ virtual void CheckCharacters(
+ Vector<const uc16> str,
+ int cp_offset,
+ Label* on_failure) = 0;
+ // Check the current input position against a register. If the register is
+ // equal to the current position then go to the label. If the label is NULL
+ // then backtrack instead.
+ virtual void CheckCurrentPosition(
+ int register_index,
+ Label* on_equal) = 0;
+ virtual void CheckNotAtStart(Label* on_not_at_start) = 0;
+ virtual void CheckNotBackReference(int start_reg, Label* on_no_match) = 0;
+ virtual void CheckNotBackReferenceIgnoreCase(int start_reg,
+ Label* on_no_match) = 0;
+ // Check the current character for a match with a literal character. If we
+ // fail to match then goto the on_failure label. End of input always
+ // matches. If the label is NULL then we should pop a backtrack address off
+ // the stack and go to that.
+ virtual void CheckNotCharacter(uc16 c, Label* on_not_equal) = 0;
+ // Bitwise or the current character with the given constant and then
+ // check for a match with c.
+ virtual void CheckNotCharacterAfterOr(uc16 c,
+ uc16 or_with,
+ Label* on_not_equal) = 0;
+ // Subtract a constant from the current character, then or with the given
+ // constant and then check for a match with c.
+ virtual void CheckNotCharacterAfterMinusOr(uc16 c,
+ uc16 minus_then_or_with,
+ Label* on_not_equal) = 0;
+ virtual void CheckNotRegistersEqual(int reg1,
+ int reg2,
+ Label* on_not_equal) = 0;
+ // Dispatch after looking the current character up in a byte map. The
+ // destinations vector has up to 256 labels.
+ virtual void DispatchByteMap(
+ uc16 start,
+ Label* byte_map,
+ const Vector<Label*>& destinations) = 0;
+ virtual void DispatchHalfNibbleMap(
+ uc16 start,
+ Label* half_nibble_map,
+ const Vector<Label*>& destinations) = 0;
+ // Dispatch after looking the high byte of the current character up in a byte
+ // map. The destinations vector has up to 256 labels.
+ virtual void DispatchHighByteMap(
+ byte start,
+ Label* byte_map,
+ const Vector<Label*>& destinations) = 0;
+ virtual void EmitOrLink(Label* label) = 0;
+ virtual void Fail() = 0;
+ virtual Handle<Object> GetCode() = 0;
+ virtual void GoTo(Label* label) = 0;
+ // Check whether a register is >= a given constant and go to a label if it
+ // is. Backtracks instead if the label is NULL.
+ virtual void IfRegisterGE(int reg, int comparand, Label* if_ge) = 0;
+ // Check whether a register is < a given constant and go to a label if it is.
+ // Backtracks instead if the label is NULL.
+ virtual void IfRegisterLT(int reg, int comparand, Label* if_lt) = 0;
+ virtual IrregexpImplementation Implementation() = 0;
+ virtual void LoadCurrentCharacter(int cp_offset, Label* on_end_of_input) = 0;
+ virtual void PopCurrentPosition() = 0;
+ virtual void PopRegister(int register_index) = 0;
+ virtual void PushBacktrack(Label* label) = 0;
+ virtual void PushCurrentPosition() = 0;
+ virtual void PushRegister(int register_index) = 0;
+ virtual void ReadCurrentPositionFromRegister(int reg) = 0;
+ virtual void ReadStackPointerFromRegister(int reg) = 0;
+ virtual void SetRegister(int register_index, int to) = 0;
+ virtual void Succeed() = 0;
+ virtual void WriteCurrentPositionToRegister(int reg) = 0;
+ virtual void WriteStackPointerToRegister(int reg) = 0;
+
+ private:
+};
+
+
+struct ArraySlice {
+ public:
+ ArraySlice(Handle<ByteArray> array, size_t offset)
+ : array_(array), offset_(offset) {}
+ Handle<ByteArray> array() { return array_; }
+ // Offset in the byte array data.
+ size_t offset() { return offset_; }
+ // Offset from the ByteArray pointer.
+ size_t base_offset() {
+ return ByteArray::kHeaderSize - kHeapObjectTag + offset_;
+ }
+ void* location() {
+ return reinterpret_cast<void*>(array_->GetDataStartAddress() + offset_);
+ }
+ template <typename T>
+ T& at(int idx) {
+ return reinterpret_cast<T*>(array_->GetDataStartAddress() + offset_)[idx];
+ }
+ private:
+ Handle<ByteArray> array_;
+ size_t offset_;
+};
+
+
+class ByteArrayProvider {
+ public:
+ explicit ByteArrayProvider(unsigned int initial_size);
+ // Provides a place to put "size" elements of size "element_size".
+ // The information can be stored in the provided ByteArray at the "offset".
+ // The offset is aligned to the element size.
+ ArraySlice GetBuffer(unsigned int size,
+ unsigned int element_size);
+ template <typename T>
+ ArraySlice GetBuffer(Vector<T> values);
+ private:
+ size_t byte_array_size_;
+ Handle<ByteArray> current_byte_array_;
+ int current_byte_array_free_offset_;
+};
+
+} } // namespace v8::internal
+
+#endif // V8_REGEXP_MACRO_ASSEMBLER_H_
diff --git a/src/rewriter.cc b/src/rewriter.cc
index c5ca7cd..f0d53b8 100644
--- a/src/rewriter.cc
+++ b/src/rewriter.cc
@@ -34,7 +34,7 @@
namespace v8 { namespace internal {
-class AstOptimizer: public Visitor {
+class AstOptimizer: public AstVisitor {
public:
explicit AstOptimizer() {
}
@@ -344,6 +344,12 @@
}
+void AstOptimizer::VisitCallEval(CallEval* node) {
+ Visit(node->expression());
+ OptimizeArguments(node->arguments());
+}
+
+
void AstOptimizer::VisitCallNew(CallNew* node) {
Visit(node->expression());
OptimizeArguments(node->arguments());
@@ -469,7 +475,7 @@
}
-class Processor: public Visitor {
+class Processor: public AstVisitor {
public:
explicit Processor(VariableProxy* result)
: result_(result),
@@ -702,6 +708,12 @@
}
+void Processor::VisitCallEval(CallEval* node) {
+ USE(node);
+ UNREACHABLE();
+}
+
+
void Processor::VisitCallNew(CallNew* node) {
USE(node);
UNREACHABLE();
diff --git a/src/runtime.cc b/src/runtime.cc
index 1d40e4c..749bee0 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -288,7 +288,7 @@
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 @@
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 @@
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;
}
@@ -1237,11 +1241,8 @@
template <typename schar>
static int SingleCharIndexOf(Vector<const schar> string,
- uc16 pattern_char,
+ schar pattern_char,
int start_index) {
- if (sizeof(schar) == 1 && pattern_char > String::kMaxAsciiCharCode) {
- return -1;
- }
for (int i = start_index, n = string.length(); i < n; i++) {
if (pattern_char == string[i]) {
return i;
@@ -1376,9 +1377,20 @@
if (pattern_length == 1) {
AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
if (sub_shape.IsAsciiRepresentation()) {
- return SingleCharIndexOf(sub->ToAsciiVector(),
- pat->Get(pat_shape, 0),
- start_index);
+ uc16 pchar = pat->Get(pat_shape, 0);
+ if (pchar > String::kMaxAsciiCharCode) {
+ return -1;
+ }
+ Vector<const char> ascii_vector =
+ sub->ToAsciiVector().SubVector(start_index, subject_length);
+ const void* pos = memchr(ascii_vector.start(),
+ static_cast<const char>(pchar),
+ static_cast<size_t>(ascii_vector.length()));
+ if (pos == NULL) {
+ return -1;
+ }
+ return reinterpret_cast<const char*>(pos) - ascii_vector.start()
+ + start_index;
}
return SingleCharIndexOf(sub->ToUC16Vector(),
pat->Get(pat_shape, 0),
@@ -2444,7 +2456,7 @@
// 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();
@@ -3163,9 +3175,9 @@
// double in the range [0, RAND_MAX + 1) obtained by adding the
// high-order bits in the range [0, RAND_MAX] with the low-order
// bits in the range [0, 1).
- double lo = static_cast<double>(random()) / (RAND_MAX + 1.0);
+ double lo = static_cast<double>(random()) * (1.0 / (RAND_MAX + 1.0));
double hi = static_cast<double>(random());
- double result = (hi + lo) / (RAND_MAX + 1.0);
+ double result = (hi + lo) * (1.0 / (RAND_MAX + 1.0));
ASSERT(result >= 0 && result < 1);
return Heap::AllocateHeapNumber(result);
}
@@ -3930,58 +3942,6 @@
}
-static Object* EvalContext() {
- // The topmost JS frame belongs to the eval function which called
- // the CompileString runtime function. We need to unwind one level
- // to get to the caller of eval.
- StackFrameLocator locator;
- JavaScriptFrame* frame = locator.FindJavaScriptFrame(1);
-
- // TODO(900055): Right now we check if the caller of eval() supports
- // eval to determine if it's an aliased eval or not. This may not be
- // entirely correct in the unlikely case where a function uses both
- // aliased and direct eval calls.
- HandleScope scope;
- if (!ScopeInfo<>::SupportsEval(frame->FindCode())) {
- // Aliased eval: Evaluate in the global context of the eval
- // function to support aliased, cross environment evals.
- return *Top::global_context();
- }
-
- // Fetch the caller context from the frame.
- Handle<Context> caller(Context::cast(frame->context()));
-
- // Check for eval() invocations that cross environments. Use the
- // context from the stack if evaluating in current environment.
- Handle<Context> target = Top::global_context();
- if (caller->global_context() == *target) return *caller;
-
- // Compute a function closure that captures the calling context. We
- // need a function that has trivial scope info, since it is only
- // used to hold the context chain together.
- Handle<JSFunction> closure = Factory::NewFunction(Factory::empty_symbol(),
- Factory::undefined_value());
- closure->set_context(*caller);
-
- // Create a new adaptor context that has the target environment as
- // the extension object. This enables the evaluated code to see both
- // the current context with locals and everything and to see global
- // variables declared in the target global object. Furthermore, any
- // properties introduced with 'var' will be added to the target
- // global object because it is the extension object.
- Handle<Context> adaptor =
- Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, closure);
- adaptor->set_extension(target->global());
- return *adaptor;
-}
-
-
-static Object* Runtime_EvalReceiver(Arguments args) {
- StackFrameLocator locator;
- return locator.FindJavaScriptFrame(1)->receiver();
-}
-
-
static Object* Runtime_GlobalReceiver(Arguments args) {
ASSERT(args.length() == 1);
Object* global = args[0];
@@ -3992,37 +3952,112 @@
static Object* Runtime_CompileString(Arguments args) {
HandleScope scope;
- ASSERT(args.length() == 3);
+ ASSERT(args.length() == 2);
CONVERT_ARG_CHECKED(String, source, 0);
CONVERT_ARG_CHECKED(Smi, line_offset, 1);
- bool contextual = args[2]->IsTrue();
- RUNTIME_ASSERT(contextual || args[2]->IsFalse());
-
- // Compute the eval context.
- Handle<Context> context;
- if (contextual) {
- // Get eval context. May not be available if we are calling eval
- // through an alias, and the corresponding frame doesn't have a
- // proper eval context set up.
- Object* eval_context = EvalContext();
- if (eval_context->IsFailure()) return eval_context;
- context = Handle<Context>(Context::cast(eval_context));
- } else {
- context = Handle<Context>(Top::context()->global_context());
- }
-
// Compile source string.
- bool is_global = context->IsGlobalContext();
Handle<JSFunction> boilerplate =
- Compiler::CompileEval(source, line_offset->value(), is_global);
+ Compiler::CompileEval(source, line_offset->value(), true);
if (boilerplate.is_null()) return Failure::Exception();
+ Handle<Context> context(Top::context()->global_context());
Handle<JSFunction> fun =
Factory::NewFunctionFromBoilerplate(boilerplate, context);
return *fun;
}
+static Handle<JSFunction> GetBuiltinFunction(String* name) {
+ LookupResult result;
+ Top::global_context()->builtins()->LocalLookup(name, &result);
+ return Handle<JSFunction>(JSFunction::cast(result.GetValue()));
+}
+
+
+static Object* CompileDirectEval(Handle<String> source) {
+ // Compute the eval context.
+ HandleScope scope;
+ StackFrameLocator locator;
+ JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
+ Handle<Context> context(Context::cast(frame->context()));
+ bool is_global = context->IsGlobalContext();
+
+ // Compile source string.
+ Handle<JSFunction> boilerplate = Compiler::CompileEval(source, 0, is_global);
+ if (boilerplate.is_null()) return Failure::Exception();
+ Handle<JSFunction> fun =
+ Factory::NewFunctionFromBoilerplate(boilerplate, context);
+ return *fun;
+}
+
+
+static Object* Runtime_ResolvePossiblyDirectEval(Arguments args) {
+ ASSERT(args.length() == 2);
+
+ HandleScope scope;
+
+ CONVERT_ARG_CHECKED(JSFunction, callee, 0);
+
+ Handle<Object> receiver;
+
+ // Find where the 'eval' symbol is bound. It is unaliased only if
+ // it is bound in the global context.
+ StackFrameLocator locator;
+ JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
+ Handle<Context> context(Context::cast(frame->context()));
+ int index;
+ PropertyAttributes attributes;
+ while (!context.is_null()) {
+ receiver = context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN,
+ &index, &attributes);
+ if (attributes != ABSENT) break;
+ if (context->is_function_context()) {
+ context = Handle<Context>(Context::cast(context->closure()->context()));
+ } else {
+ context = Handle<Context>(context->previous());
+ }
+ }
+
+ if (context->IsGlobalContext()) {
+ // 'eval' is bound in the global context, but it may have been overwritten.
+ // Compare it to the builtin 'GlobalEval' function to make sure.
+ Handle<JSFunction> global_eval =
+ GetBuiltinFunction(Heap::global_eval_symbol());
+ if (global_eval.is_identical_to(callee)) {
+ // A direct eval call.
+ if (args[1]->IsString()) {
+ CONVERT_ARG_CHECKED(String, source, 1);
+ // A normal eval call on a string. Compile it and return the
+ // compiled function bound in the local context.
+ Object* compiled_source = CompileDirectEval(source);
+ if (compiled_source->IsFailure()) return compiled_source;
+ receiver = Handle<Object>(frame->receiver());
+ callee = Handle<JSFunction>(JSFunction::cast(compiled_source));
+ } else {
+ // An eval call that is not called on a string. Global eval
+ // deals better with this.
+ receiver = Handle<Object>(Top::global_context()->global());
+ }
+ } else {
+ // 'eval' is overwritten. Just call the function with the given arguments.
+ receiver = Handle<Object>(Top::global_context()->global());
+ }
+ } else {
+ // 'eval' is not bound in the global context. Just call the function
+ // with the given arguments. This is not necessarily the global eval.
+ if (receiver->IsContext()) {
+ context = Handle<Context>::cast(receiver);
+ receiver = Handle<Object>(context->get(index));
+ }
+ }
+
+ Handle<FixedArray> call = Factory::NewFixedArray(2);
+ call->set(0, *callee);
+ call->set(1, *receiver);
+ return *call;
+}
+
+
static Object* Runtime_CompileScript(Arguments args) {
HandleScope scope;
ASSERT(args.length() == 4);
@@ -4797,9 +4832,10 @@
// Traverse the saved contexts chain to find the active context for the
// selected frame.
SaveContext* save = Top::save_context();
- while (save != NULL && reinterpret_cast<Address>(save) < it.frame()->sp()) {
+ while (save != NULL && !save->below(it.frame())) {
save = save->prev();
}
+ ASSERT(save != NULL);
// Get the frame id.
Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
@@ -5299,7 +5335,7 @@
// Traverse the saved contexts chain to find the active context for the
// selected frame.
SaveContext* save = Top::save_context();
- while (save != NULL && reinterpret_cast<Address>(save) < frame->sp()) {
+ while (save != NULL && !save->below(frame)) {
save = save->prev();
}
ASSERT(save != NULL);
diff --git a/src/runtime.h b/src/runtime.h
index 36a7180..98559d4 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -190,13 +190,13 @@
F(NumberIsFinite, 1) \
\
/* Globals */ \
- F(CompileString, 3) \
+ F(CompileString, 2) \
F(CompileScript, 4) \
F(GlobalPrint, 1) \
\
/* Eval */ \
- F(EvalReceiver, 1) \
F(GlobalReceiver, 1) \
+ F(ResolvePossiblyDirectEval, 2) \
\
F(SetProperty, -1 /* 3 or 4 */) \
F(IgnoreAttributesAndSetProperty, -1 /* 3 or 4 */) \
diff --git a/src/scopes.cc b/src/scopes.cc
index 4f84bbb..fcdc577 100644
--- a/src/scopes.cc
+++ b/src/scopes.cc
@@ -184,11 +184,22 @@
-Variable* Scope::Lookup(Handle<String> name) {
+Variable* Scope::LookupLocal(Handle<String> name) {
return locals_.Lookup(name);
}
+Variable* Scope::Lookup(Handle<String> name) {
+ for (Scope* scope = this;
+ scope != NULL;
+ scope = scope->outer_scope()) {
+ Variable* var = scope->LookupLocal(name);
+ if (var != NULL) return var;
+ }
+ return NULL;
+}
+
+
Variable* Scope::DeclareFunctionVar(Handle<String> name) {
ASSERT(is_function_scope() && function_ == NULL);
function_ = new Variable(this, name, Variable::CONST, true, false);
@@ -207,7 +218,7 @@
void Scope::AddParameter(Variable* var) {
ASSERT(is_function_scope());
- ASSERT(Lookup(var->name()) == var);
+ ASSERT(LookupLocal(var->name()) == var);
params_.Add(var);
}
@@ -258,7 +269,7 @@
}
-void Scope::VisitIllegalRedeclaration(Visitor* visitor) {
+void Scope::VisitIllegalRedeclaration(AstVisitor* visitor) {
ASSERT(HasIllegalRedeclaration());
illegal_redecl_->Accept(visitor);
}
@@ -513,7 +524,7 @@
bool guess = scope_calls_eval_;
// Try to find the variable in this scope.
- Variable* var = Lookup(name);
+ Variable* var = LookupLocal(name);
if (var != NULL) {
// We found a variable. If this is not an inner lookup, we are done.
@@ -707,7 +718,7 @@
void Scope::AllocateParameterLocals() {
ASSERT(is_function_scope());
- Variable* arguments = Lookup(Factory::arguments_symbol());
+ Variable* arguments = LookupLocal(Factory::arguments_symbol());
ASSERT(arguments != NULL); // functions have 'arguments' declared implicitly
if (MustAllocate(arguments) && !HasArgumentsParameter()) {
// 'arguments' is used. Unless there is also a parameter called
diff --git a/src/scopes.h b/src/scopes.h
index 05e462b..1eee225 100644
--- a/src/scopes.h
+++ b/src/scopes.h
@@ -88,6 +88,10 @@
// Declarations
// Lookup a variable in this scope. Returns the variable or NULL if not found.
+ virtual Variable* LookupLocal(Handle<String> name);
+
+ // Lookup a variable in this scope or outer scopes.
+ // Returns the variable or NULL if not found.
virtual Variable* Lookup(Handle<String> name);
// Declare the function variable for a function literal. This variable
@@ -138,7 +142,7 @@
// Visit the illegal redeclaration expression. Do not call if the
// scope doesn't have an illegal redeclaration node.
- void VisitIllegalRedeclaration(Visitor* visitor);
+ void VisitIllegalRedeclaration(AstVisitor* visitor);
// Check if the scope has (at least) one illegal redeclaration.
bool HasIllegalRedeclaration() const { return illegal_redecl_ != NULL; }
diff --git a/src/string-stream.cc b/src/string-stream.cc
index 6a3737b..f311e20 100644
--- a/src/string-stream.cc
+++ b/src/string-stream.cc
@@ -93,13 +93,13 @@
}
-void StringStream::Add(const char* format, Vector<FmtElm> elms) {
+void StringStream::Add(Vector<const char> format, Vector<FmtElm> elms) {
// If we already ran out of space then return immediately.
if (space() == 0)
return;
int offset = 0;
int elm = 0;
- while (format[offset] != '\0') {
+ while (offset < format.length()) {
if (format[offset] != '%' || elm == elms.length()) {
Put(format[offset]);
offset++;
@@ -111,12 +111,11 @@
// Skip over the whole control character sequence until the
// format element type
temp[format_length++] = format[offset++];
- // '\0' is not a control character so we don't have to
- // explicitly check for the end of the string
- while (IsControlChar(format[offset]))
+ while (offset < format.length() && IsControlChar(format[offset]))
temp[format_length++] = format[offset++];
+ if (offset >= format.length())
+ return;
char type = format[offset];
- if (type == '\0') return;
temp[format_length++] = type;
temp[format_length] = '\0';
offset++;
@@ -128,17 +127,36 @@
Add(value);
break;
}
+ case 'w': {
+ ASSERT_EQ(FmtElm::LC_STR, current.type_);
+ Vector<const uc16> value = *current.data_.u_lc_str_;
+ for (int i = 0; i < value.length(); i++)
+ Put(static_cast<char>(value[i]));
+ break;
+ }
case 'o': {
ASSERT_EQ(FmtElm::OBJ, current.type_);
Object* obj = current.data_.u_obj_;
PrintObject(obj);
break;
}
- case 'i': case 'd': case 'u': case 'x': case 'c': case 'p': {
+ case 'k': {
+ ASSERT_EQ(FmtElm::INT, current.type_);
+ int value = current.data_.u_int_;
+ if (0x20 <= value && value <= 0x7F) {
+ Put(value);
+ } else if (value <= 0xff) {
+ Add("\\x%02x", value);
+ } else {
+ Add("\\u%04x", value);
+ }
+ break;
+ }
+ case 'i': case 'd': case 'u': case 'x': case 'c': case 'p': case 'X': {
int value = current.data_.u_int_;
EmbeddedVector<char, 24> formatted;
- OS::SNPrintF(formatted, temp.start(), value);
- Add(formatted.start());
+ int length = OS::SNPrintF(formatted, temp.start(), value);
+ Add(Vector<const char>(formatted.start(), length));
break;
}
case 'f': case 'g': case 'G': case 'e': case 'E': {
@@ -154,10 +172,8 @@
}
}
- // Verify that the buffer is 0-terminated and doesn't contain any
- // other 0-characters.
+ // Verify that the buffer is 0-terminated
ASSERT(buffer_[length_] == '\0');
- ASSERT(strlen(buffer_) == length_);
}
@@ -188,6 +204,11 @@
void StringStream::Add(const char* format) {
+ Add(CStrVector(format));
+}
+
+
+void StringStream::Add(Vector<const char> format) {
Add(format, Vector<FmtElm>::empty());
}
@@ -195,14 +216,14 @@
void StringStream::Add(const char* format, FmtElm arg0) {
const char argc = 1;
FmtElm argv[argc] = { arg0 };
- Add(format, Vector<FmtElm>(argv, argc));
+ Add(CStrVector(format), Vector<FmtElm>(argv, argc));
}
void StringStream::Add(const char* format, FmtElm arg0, FmtElm arg1) {
const char argc = 2;
FmtElm argv[argc] = { arg0, arg1 };
- Add(format, Vector<FmtElm>(argv, argc));
+ Add(CStrVector(format), Vector<FmtElm>(argv, argc));
}
@@ -210,7 +231,15 @@
FmtElm arg2) {
const char argc = 3;
FmtElm argv[argc] = { arg0, arg1, arg2 };
- Add(format, Vector<FmtElm>(argv, argc));
+ Add(CStrVector(format), Vector<FmtElm>(argv, argc));
+}
+
+
+void StringStream::Add(const char* format, FmtElm arg0, FmtElm arg1,
+ FmtElm arg2, FmtElm arg3) {
+ const char argc = 4;
+ FmtElm argv[argc] = { arg0, arg1, arg2, arg3 };
+ Add(CStrVector(format), Vector<FmtElm>(argv, argc));
}
diff --git a/src/string-stream.h b/src/string-stream.h
index 2fb29af..37ae93e 100644
--- a/src/string-stream.h
+++ b/src/string-stream.h
@@ -75,17 +75,19 @@
FmtElm(int value) : type_(INT) { data_.u_int_ = value; } // NOLINT
explicit FmtElm(double value) : type_(DOUBLE) { data_.u_double_ = value; } // NOLINT
FmtElm(const char* value) : type_(C_STR) { data_.u_c_str_ = value; } // NOLINT
+ FmtElm(const Vector<const uc16>& value) : type_(LC_STR) { data_.u_lc_str_ = &value; } // NOLINT
FmtElm(Object* value) : type_(OBJ) { data_.u_obj_ = value; } // NOLINT
FmtElm(Handle<Object> value) : type_(HANDLE) { data_.u_handle_ = value.location(); } // NOLINT
FmtElm(void* value) : type_(INT) { data_.u_int_ = reinterpret_cast<int>(value); } // NOLINT
private:
friend class StringStream;
- enum Type { INT, DOUBLE, C_STR, OBJ, HANDLE };
+ enum Type { INT, DOUBLE, C_STR, LC_STR, OBJ, HANDLE };
Type type_;
union {
int u_int_;
double u_double_;
const char* u_c_str_;
+ const Vector<const uc16>* u_lc_str_;
Object* u_obj_;
Object** u_handle_;
} data_;
@@ -108,11 +110,17 @@
bool Put(char c);
bool Put(String* str);
bool Put(String* str, int start, int end);
- void Add(const char* format, Vector<FmtElm> elms);
+ void Add(Vector<const char> format, Vector<FmtElm> elms);
void Add(const char* format);
+ void Add(Vector<const char> format);
void Add(const char* format, FmtElm arg0);
void Add(const char* format, FmtElm arg0, FmtElm arg1);
void Add(const char* format, FmtElm arg0, FmtElm arg1, FmtElm arg2);
+ void Add(const char* format,
+ FmtElm arg0,
+ FmtElm arg1,
+ FmtElm arg2,
+ FmtElm arg3);
// Getting the message out.
void OutputToStdOut();
diff --git a/src/stub-cache-arm.cc b/src/stub-cache-arm.cc
index e7fe0b9..3584a4e 100644
--- a/src/stub-cache-arm.cc
+++ b/src/stub-cache-arm.cc
@@ -290,6 +290,155 @@
}
+// Generate code to check if an object is a string. If the object is
+// a string, the map's instance type is left in the scratch1 register.
+static void GenerateStringCheck(MacroAssembler* masm,
+ Register receiver,
+ Register scratch1,
+ Register scratch2,
+ Label* smi,
+ Label* non_string_object) {
+ // Check that the receiver isn't a smi.
+ __ tst(receiver, Operand(kSmiTagMask));
+ __ b(eq, smi);
+
+ // Check that the object is a string.
+ __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
+ __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
+ __ and_(scratch2, scratch1, Operand(kIsNotStringMask));
+ // The cast is to resolve the overload for the argument of 0x0.
+ __ cmp(scratch2, Operand(static_cast<int32_t>(kStringTag)));
+ __ b(ne, non_string_object);
+}
+
+
+void StubCompiler::GenerateLoadStringLength2(MacroAssembler* masm,
+ Register receiver,
+ Register scratch1,
+ Register scratch2,
+ Label* miss) {
+ Label load_length, check_wrapper;
+
+ // Check if the object is a string leaving the instance type in the
+ // scratch1 register.
+ GenerateStringCheck(masm, receiver, scratch1, scratch2,
+ miss, &check_wrapper);
+
+ // Load length directly from the string.
+ __ bind(&load_length);
+ __ and_(scratch1, scratch1, Operand(kStringSizeMask));
+ __ add(scratch1, scratch1, Operand(String::kHashShift));
+ __ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset));
+ __ mov(r0, Operand(r0, LSR, scratch1));
+ __ mov(r0, Operand(r0, LSL, kSmiTagSize));
+ __ Ret();
+
+ // Check if the object is a JSValue wrapper.
+ __ bind(&check_wrapper);
+ __ cmp(scratch1, Operand(JS_VALUE_TYPE));
+ __ b(ne, miss);
+
+ // Check if the wrapped value is a string and load the length
+ // directly if it is.
+ __ ldr(r0, FieldMemOperand(receiver, JSValue::kValueOffset));
+ GenerateStringCheck(masm, receiver, scratch1, scratch1, miss, miss);
+ __ b(&load_length);
+}
+
+
+// Generate StoreField code, value is passed in r0 register.
+// After executing generated code, the receiver_reg and name_reg
+// may be clobbered.
+void StubCompiler::GenerateStoreField(MacroAssembler* masm,
+ Builtins::Name storage_extend,
+ JSObject* object,
+ int index,
+ Map* transition,
+ Register receiver_reg,
+ Register name_reg,
+ Register scratch,
+ Label* miss_label) {
+ // r0 : value
+ Label exit;
+
+ // Check that the receiver isn't a smi.
+ __ tst(receiver_reg, Operand(kSmiTagMask));
+ __ b(eq, miss_label);
+
+ // Check that the map of the receiver hasn't changed.
+ __ ldr(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
+ __ cmp(scratch, Operand(Handle<Map>(object->map())));
+ __ b(ne, miss_label);
+
+ // Perform global security token check if needed.
+ if (object->IsJSGlobalProxy()) {
+ __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
+ }
+
+ // Stub never generated for non-global objects that require access
+ // checks.
+ ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
+
+ // Perform map transition for the receiver if necessary.
+ if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
+ // The properties must be extended before we can store the value.
+ // We jump to a runtime call that extends the propeties array.
+ __ mov(r2, Operand(Handle<Map>(transition)));
+ // Please note, if we implement keyed store for arm we need
+ // to call the Builtins::KeyedStoreIC_ExtendStorage.
+ Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_ExtendStorage));
+ __ Jump(ic, RelocInfo::CODE_TARGET);
+ return;
+ }
+
+ if (transition != NULL) {
+ // Update the map of the object; no write barrier updating is
+ // needed because the map is never in new space.
+ __ mov(ip, Operand(Handle<Map>(transition)));
+ __ str(ip, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
+ }
+
+ // Adjust for the number of properties stored in the object. Even in the
+ // face of a transition we can use the old map here because the size of the
+ // object and the number of in-object properties is not going to change.
+ index -= object->map()->inobject_properties();
+
+ if (index < 0) {
+ // Set the property straight into the object.
+ int offset = object->map()->instance_size() + (index * kPointerSize);
+ __ str(r0, FieldMemOperand(receiver_reg, offset));
+
+ // Skip updating write barrier if storing a smi.
+ __ tst(r0, Operand(kSmiTagMask));
+ __ b(eq, &exit);
+
+ // Update the write barrier for the array address.
+ // Pass the value being stored in the now unused name_reg.
+ __ mov(name_reg, Operand(offset));
+ __ RecordWrite(receiver_reg, name_reg, scratch);
+ } else {
+ // Write to the properties array.
+ int offset = index * kPointerSize + Array::kHeaderSize;
+ // Get the properties array
+ __ ldr(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset));
+ __ str(r0, FieldMemOperand(scratch, offset));
+
+ // Skip updating write barrier if storing a smi.
+ __ tst(r0, Operand(kSmiTagMask));
+ __ b(eq, &exit);
+
+ // Update the write barrier for the array address.
+ // Ok to clobber receiver_reg and name_reg, since we return.
+ __ mov(name_reg, Operand(offset));
+ __ RecordWrite(scratch, name_reg, receiver_reg);
+ }
+
+ // Return the value (register r0).
+ __ bind(&exit);
+ __ Ret();
+}
+
+
void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) {
ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC);
Code* code = NULL;
@@ -552,87 +701,19 @@
// -----------------------------------
HandleScope scope;
- Label miss, exit;
+ Label miss;
// Get the receiver from the stack.
__ ldr(r3, MemOperand(sp, 0 * kPointerSize));
- // Check that the receiver isn't a smi.
- __ tst(r3, Operand(kSmiTagMask));
- __ b(eq, &miss);
-
- // Check that the map of the receiver hasn't changed.
- __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset));
- __ cmp(r1, Operand(Handle<Map>(object->map())));
- __ b(ne, &miss);
-
- // Perform global security token check if needed.
- if (object->IsJSGlobalProxy()) {
- __ CheckAccessGlobalProxy(r3, r1, &miss);
- }
-
- // Stub never generated for non-global objects that require access
- // checks.
- ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
-
- // Perform map transition for the receiver if necessary.
- if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
- // The properties must be extended before we can store the value.
- // We jump to a runtime call that extends the propeties array.
- __ mov(r2, Operand(Handle<Map>(transition)));
- // Please note, if we implement keyed store for arm we need
- // to call the Builtins::KeyedStoreIC_ExtendStorage.
- Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_ExtendStorage));
- __ Jump(ic, RelocInfo::CODE_TARGET);
- } else {
- // Adjust for the number of properties stored in the object. Even in the
- // face of a transition we can use the old map here because the size of the
- // object and the number of in-object properties is not going to change.
- index -= object->map()->inobject_properties();
-
- if (index >= 0) {
- // Get the properties array
- __ ldr(r1, FieldMemOperand(r3, JSObject::kPropertiesOffset));
- }
-
- if (transition != NULL) {
- // Update the map of the object; no write barrier updating is
- // needed because the map is never in new space.
- __ mov(ip, Operand(Handle<Map>(transition)));
- __ str(ip, FieldMemOperand(r3, HeapObject::kMapOffset));
- }
-
- if (index < 0) {
- // Set the property straight into the object.
- int offset = object->map()->instance_size() + (index * kPointerSize);
- __ str(r0, FieldMemOperand(r3, offset));
-
- // Skip updating write barrier if storing a smi.
- __ tst(r0, Operand(kSmiTagMask));
- __ b(eq, &exit);
-
- // Update the write barrier for the array address.
- __ mov(r1, Operand(offset));
- __ RecordWrite(r3, r1, r2);
- } else {
- // Write to the properties array.
- int offset = index * kPointerSize + Array::kHeaderSize;
- __ str(r0, FieldMemOperand(r1, offset));
-
- // Skip updating write barrier if storing a smi.
- __ tst(r0, Operand(kSmiTagMask));
- __ b(eq, &exit);
-
- // Update the write barrier for the array address.
- __ mov(r3, Operand(offset));
- __ RecordWrite(r1, r3, r2); // OK to clobber r2, since we return
- }
-
- // Return the value (register r0).
- __ bind(&exit);
- __ Ret();
- }
- // Handle store cache miss.
+ // name register might be clobbered.
+ GenerateStoreField(masm(),
+ Builtins::StoreIC_ExtendStorage,
+ object,
+ index,
+ transition,
+ r3, r2, r1,
+ &miss);
__ bind(&miss);
__ mov(r2, Operand(Handle<String>(name))); // restore name
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
@@ -978,7 +1059,6 @@
}
-// TODO(1224671): implement the fast case.
Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) {
// ----------- S t a t e -------------
// -- lr : return address
@@ -986,6 +1066,20 @@
// -- sp[4] : receiver
// -----------------------------------
HandleScope scope;
+
+ Label miss;
+ __ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
+
+ __ ldr(r2, MemOperand(sp));
+ __ ldr(r0, MemOperand(sp, kPointerSize)); // receiver
+
+ __ cmp(r2, Operand(Handle<String>(name)));
+ __ b(ne, &miss);
+
+ GenerateLoadStringLength2(masm(), r0, r1, r3, &miss);
+ __ bind(&miss);
+ __ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
+
GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
return GetCode(CALLBACKS);
@@ -1006,7 +1100,6 @@
}
-// TODO(1224671): implement the fast case.
Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
int index,
Map* transition,
@@ -1018,6 +1111,28 @@
// -- [sp] : receiver
// -----------------------------------
HandleScope scope;
+ Label miss;
+
+ __ IncrementCounter(&Counters::keyed_store_field, 1, r1, r3);
+
+ // Check that the name has not changed.
+ __ cmp(r2, Operand(Handle<String>(name)));
+ __ b(ne, &miss);
+
+ // Load receiver from the stack.
+ __ ldr(r3, MemOperand(sp));
+ // r1 is used as scratch register, r3 and r2 might be clobbered.
+ GenerateStoreField(masm(),
+ Builtins::StoreIC_ExtendStorage,
+ object,
+ index,
+ transition,
+ r3, r2, r1,
+ &miss);
+ __ bind(&miss);
+
+ __ DecrementCounter(&Counters::keyed_store_field, 1, r1, r3);
+ __ mov(r2, Operand(Handle<String>(name))); // restore name register.
Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss));
__ Jump(ic, RelocInfo::CODE_TARGET);
diff --git a/src/stub-cache-ia32.cc b/src/stub-cache-ia32.cc
index d15b19d..c2be65d 100644
--- a/src/stub-cache-ia32.cc
+++ b/src/stub-cache-ia32.cc
@@ -401,16 +401,6 @@
return;
}
- // Adjust for the number of properties stored in the object. Even in the
- // face of a transition we can use the old map here because the size of the
- // object and the number of in-object properties is not going to change.
- index -= object->map()->inobject_properties();
-
- if (index >= 0) {
- // Get the properties array (optimistically).
- __ mov(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
- }
-
if (transition != NULL) {
// Update the map of the object; no write barrier updating is
// needed because the map is never in new space.
@@ -418,6 +408,11 @@
Immediate(Handle<Map>(transition)));
}
+ // Adjust for the number of properties stored in the object. Even in the
+ // face of a transition we can use the old map here because the size of the
+ // object and the number of in-object properties is not going to change.
+ index -= object->map()->inobject_properties();
+
if (index < 0) {
// Set the property straight into the object.
int offset = object->map()->instance_size() + (index * kPointerSize);
@@ -430,6 +425,8 @@
} else {
// Write to the properties array.
int offset = index * kPointerSize + Array::kHeaderSize;
+ // Get the properties array (optimistically).
+ __ mov(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
__ mov(FieldOperand(scratch, offset), eax);
// Update the write barrier for the array address.
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index 3ee1b9e..f5f00ae 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -892,7 +892,7 @@
Object* StubCompiler::GetCodeWithFlags(Code::Flags flags) {
CodeDesc desc;
masm_.GetCode(&desc);
- Object* result = Heap::CreateCode(desc, NULL, flags);
+ Object* result = Heap::CreateCode(desc, NULL, flags, NULL);
#ifdef DEBUG
if (FLAG_print_code_stubs && !result->IsFailure()) {
Code::cast(result)->Print();
diff --git a/src/stub-cache.h b/src/stub-cache.h
index 66d03fe..498a695 100644
--- a/src/stub-cache.h
+++ b/src/stub-cache.h
@@ -340,6 +340,11 @@
Register receiver,
Register scratch,
Label* miss_label);
+ static void GenerateLoadStringLength2(MacroAssembler* masm,
+ Register receiver,
+ Register scratch1,
+ Register scratch2,
+ Label* miss_label);
static void GenerateLoadFunctionPrototype(MacroAssembler* masm,
Register receiver,
Register scratch1,
diff --git a/src/top.cc b/src/top.cc
index ace79a9..7e239ec 100644
--- a/src/top.cc
+++ b/src/top.cc
@@ -603,6 +603,10 @@
}
+const char* Top::kStackOverflowMessage =
+ "Uncaught RangeError: Maximum call stack size exceeded";
+
+
Failure* Top::StackOverflow() {
HandleScope scope;
Handle<String> key = Factory::stack_overflow_symbol();
@@ -616,9 +620,7 @@
// doesn't use ReportUncaughtException to determine the location
// from where the exception occurred. It should probably be
// reworked.
- static const char* kMessage =
- "Uncaught RangeError: Maximum call stack size exceeded";
- DoThrow(*exception, NULL, kMessage);
+ DoThrow(*exception, NULL, kStackOverflowMessage);
return Failure::Exception();
}
diff --git a/src/top.h b/src/top.h
index 866487c..29d46b5 100644
--- a/src/top.h
+++ b/src/top.h
@@ -271,6 +271,8 @@
static char* ArchiveThread(char* to);
static char* RestoreThread(char* from);
+ static const char* kStackOverflowMessage;
+
private:
// The context that initiated this JS execution.
static ThreadLocalTop thread_local_;
@@ -312,6 +314,10 @@
#endif
prev_(Top::save_context()) {
Top::set_save_context(this);
+
+ // If there is no JS frame under the current C frame, use the value 0.
+ JavaScriptFrameIterator it;
+ js_sp_ = it.done() ? 0 : it.frame()->sp();
}
~SaveContext() {
@@ -322,12 +328,18 @@
Handle<Context> context() { return context_; }
SaveContext* prev() { return prev_; }
+ // Returns true if this save context is below a given JavaScript frame.
+ bool below(JavaScriptFrame* frame) {
+ return (js_sp_ == 0) || (frame->sp() < js_sp_);
+ }
+
private:
Handle<Context> context_;
#if __GNUC_VERSION__ >= 40100 && __GNUC_VERSION__ < 40300
Handle<Context> dummy_;
#endif
SaveContext* prev_;
+ Address js_sp_; // The top JS frame's sp when saving context.
};
diff --git a/src/unicode.cc b/src/unicode.cc
index 2f70bd3..8b06dba 100644
--- a/src/unicode.cc
+++ b/src/unicode.cc
@@ -25,7 +25,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
-// This file was generated at 2008-10-01 18:05:45.480436
+// This file was generated at 2008-11-25 16:02:40.592795
#include "unicode-inl.h"
#include <cstdlib>
@@ -33,6 +33,9 @@
namespace unibrow {
+static const int kStartBit = (1 << 30);
+static const int kChunkBits = (1 << 15);
+
/**
* \file
* Implementations of functions for working with unicode.
@@ -40,19 +43,20 @@
typedef signed short int16_t; // NOLINT
typedef unsigned short uint16_t; // NOLINT
+typedef int int32_t; // NOLINT
// All access to the character table should go through this function.
template <int D>
-static inline uchar TableGet(const uint16_t* table, int index) {
+static inline uchar TableGet(const int32_t* table, int index) {
return table[D * index];
}
-static inline uchar GetEntry(uint16_t entry) {
- return entry & 0x7fff;
+static inline uchar GetEntry(int32_t entry) {
+ return entry & (kStartBit - 1);
}
-static inline bool IsStart(uint16_t entry) {
- return (entry & (1 << 15)) != 0;
+static inline bool IsStart(int32_t entry) {
+ return (entry & kStartBit) != 0;
}
/**
@@ -65,9 +69,9 @@
* about a character is around 10, slightly higher if there is no
* information available about the character.
*/
-static bool LookupPredicate(const uint16_t* table, uint16_t size, uchar chr) {
+static bool LookupPredicate(const int32_t* table, uint16_t size, uchar chr) {
static const int kEntryDist = 1;
- uint16_t value = chr & 0x7fff;
+ uint16_t value = chr & (kChunkBits - 1);
unsigned int low = 0;
unsigned int high = size - 1;
while (high != low) {
@@ -89,14 +93,17 @@
high = mid - 1;
}
}
- uint16_t field = TableGet<kEntryDist>(table, low);
- return (GetEntry(field) == value) ||
- (GetEntry(field) < value && IsStart(field));
+ int32_t field = TableGet<kEntryDist>(table, low);
+ uchar entry = GetEntry(field);
+ bool is_start = IsStart(field);
+ return (entry == value) ||
+ (entry < value && is_start);
}
+template <int kW>
struct MultiCharacterSpecialCase {
uint16_t length;
- uchar chars[kMaxCaseConvertedSize];
+ uchar chars[kW];
};
// Look up the mapping for the given character in the specified table,
@@ -107,11 +114,16 @@
// if the allow_caching_ptr is non-null then false will be stored in
// it if the result contains multiple characters or depends on the
// context.
-static int LookupMapping(const uint16_t* table, uint16_t size,
- const MultiCharacterSpecialCase* multi_chars, uchar chr, uchar next,
- uchar* result, bool* allow_caching_ptr) {
+template <int kW>
+static int LookupMapping(const int32_t* table,
+ uint16_t size,
+ const MultiCharacterSpecialCase<kW>* multi_chars,
+ uchar chr,
+ uchar next,
+ uchar* result,
+ bool* allow_caching_ptr) {
static const int kEntryDist = 2;
- uint16_t value = chr & 0x7fff;
+ uint16_t value = chr & (kChunkBits - 1);
unsigned int low = 0;
unsigned int high = size - 1;
while (high != low) {
@@ -133,11 +145,12 @@
high = mid - 1;
}
}
- uint16_t field = TableGet<kEntryDist>(table, low);
- bool found = (GetEntry(field) == value) ||
- (GetEntry(field) < value && IsStart(field));
+ int32_t field = TableGet<kEntryDist>(table, low);
+ uchar entry = GetEntry(field);
+ bool is_start = IsStart(field);
+ bool found = (entry == value) || (entry < value && is_start);
if (found) {
- int16_t value = table[2 * low + 1];
+ int32_t value = table[2 * low + 1];
if (value == 0) {
// 0 means not present
return 0;
@@ -148,7 +161,7 @@
} else if ((value & 3) == 1) {
// Low bits 1 means a special case mapping
if (allow_caching_ptr) *allow_caching_ptr = false;
- const MultiCharacterSpecialCase& mapping = multi_chars[value >> 2];
+ const MultiCharacterSpecialCase<kW>& mapping = multi_chars[value >> 2];
for (int i = 0; i < mapping.length; i++)
result[i] = mapping.chars[i];
return mapping.length;
@@ -323,13 +336,13 @@
// Uppercase: point.category == 'Lu'
static const uint16_t kUppercaseTable0Size = 509;
-static const uint16_t kUppercaseTable0[509] = { 32833, 90, 32960, 214, 32984, 222, 256, 258, 260, 262, 264, 266, 268, 270, 272, 274, 276, 278, 280, 282, 284, 286, 288, 290, 292, 294, 296, 298, 300, 302, 304, 306, 308, 310, 313, 315, 317, 319, 321, 323, 325, 327, 330, 332, 334, 336, 338, 340, 342, 344, 346, 348, 350, 352, 354, 356, 358, 360, 362, 364, 366, 368, 370, 372, 374, 33144, 377, 379, 381, 33153, 386, 388, 33158, 391, 33161, 395, 33166, 401, 33171, 404, 33174, 408, 33180, 413, 33183, 416, 418, 420, 33190, 423, 425, 428, 33198, 431, 33201, 435, 437, 33207, 440, 444, 452, 455, 458, 461, 463, 465, 467, 469, 471, 473, 475, 478, 480, 482, 484, 486, 488, 490, 492, 494, 497, 500, 33270, 504, 506, 508, 510, 512, 514, 516, 518, 520, 522, 524, 526, 528, 530, 532, 534, 536, 538, 540, 542, 544, 546, 548, 550, 552, 554, 556, 558, 560, 562, 33338, 571, 33341, 574, 577, 33347, 582, 584, 586, 588, 590, 902, 33672, 906, 908, 33678, 911, 33681, 929, 33699, 939, 33746, 980, 984, 986, 988, 990, 992, 994, 996, 998, 1000, 1002, 1004, 1006, 1012, 1015, 33785, 1018, 33789, 1071, 1120, 1122, 1124, 1126, 1128, 1130, 1132, 1134, 1136, 1138, 1140, 1142, 1144, 1146, 1148, 1150, 1152, 1162, 1164, 1166, 1168, 1170, 1172, 1174, 1176, 1178, 1180, 1182, 1184, 1186, 1188, 1190, 1192, 1194, 1196, 1198, 1200, 1202, 1204, 1206, 1208, 1210, 1212, 1214, 33984, 1217, 1219, 1221, 1223, 1225, 1227, 1229, 1232, 1234, 1236, 1238, 1240, 1242, 1244, 1246, 1248, 1250, 1252, 1254, 1256, 1258, 1260, 1262, 1264, 1266, 1268, 1270, 1272, 1274, 1276, 1278, 1280, 1282, 1284, 1286, 1288, 1290, 1292, 1294, 1296, 1298, 34097, 1366, 37024, 4293, 7680, 7682, 7684, 7686, 7688, 7690, 7692, 7694, 7696, 7698, 7700, 7702, 7704, 7706, 7708, 7710, 7712, 7714, 7716, 7718, 7720, 7722, 7724, 7726, 7728, 7730, 7732, 7734, 7736, 7738, 7740, 7742, 7744, 7746, 7748, 7750, 7752, 7754, 7756, 7758, 7760, 7762, 7764, 7766, 7768, 7770, 7772, 7774, 7776, 7778, 7780, 7782, 7784, 7786, 7788, 7790, 7792, 7794, 7796, 7798, 7800, 7802, 7804, 7806, 7808, 7810, 7812, 7814, 7816, 7818, 7820, 7822, 7824, 7826, 7828, 7840, 7842, 7844, 7846, 7848, 7850, 7852, 7854, 7856, 7858, 7860, 7862, 7864, 7866, 7868, 7870, 7872, 7874, 7876, 7878, 7880, 7882, 7884, 7886, 7888, 7890, 7892, 7894, 7896, 7898, 7900, 7902, 7904, 7906, 7908, 7910, 7912, 7914, 7916, 7918, 7920, 7922, 7924, 7926, 7928, 40712, 7951, 40728, 7965, 40744, 7983, 40760, 7999, 40776, 8013, 8025, 8027, 8029, 8031, 40808, 8047, 40888, 8123, 40904, 8139, 40920, 8155, 40936, 8172, 40952, 8187, 8450, 8455, 41227, 8461, 41232, 8466, 8469, 41241, 8477, 8484, 8486, 8488, 41258, 8493, 41264, 8499, 41278, 8511, 8517, 8579, 44032, 11310, 11360, 44130, 11364, 11367, 11369, 11371, 11381, 11392, 11394, 11396, 11398, 11400, 11402, 11404, 11406, 11408, 11410, 11412, 11414, 11416, 11418, 11420, 11422, 11424, 11426, 11428, 11430, 11432, 11434, 11436, 11438, 11440, 11442, 11444, 11446, 11448, 11450, 11452, 11454, 11456, 11458, 11460, 11462, 11464, 11466, 11468, 11470, 11472, 11474, 11476, 11478, 11480, 11482, 11484, 11486, 11488, 11490 }; // NOLINT
+static const int32_t kUppercaseTable0[509] = { 1073741889, 90, 1073742016, 214, 1073742040, 222, 256, 258, 260, 262, 264, 266, 268, 270, 272, 274, 276, 278, 280, 282, 284, 286, 288, 290, 292, 294, 296, 298, 300, 302, 304, 306, 308, 310, 313, 315, 317, 319, 321, 323, 325, 327, 330, 332, 334, 336, 338, 340, 342, 344, 346, 348, 350, 352, 354, 356, 358, 360, 362, 364, 366, 368, 370, 372, 374, 1073742200, 377, 379, 381, 1073742209, 386, 388, 1073742214, 391, 1073742217, 395, 1073742222, 401, 1073742227, 404, 1073742230, 408, 1073742236, 413, 1073742239, 416, 418, 420, 1073742246, 423, 425, 428, 1073742254, 431, 1073742257, 435, 437, 1073742263, 440, 444, 452, 455, 458, 461, 463, 465, 467, 469, 471, 473, 475, 478, 480, 482, 484, 486, 488, 490, 492, 494, 497, 500, 1073742326, 504, 506, 508, 510, 512, 514, 516, 518, 520, 522, 524, 526, 528, 530, 532, 534, 536, 538, 540, 542, 544, 546, 548, 550, 552, 554, 556, 558, 560, 562, 1073742394, 571, 1073742397, 574, 577, 1073742403, 582, 584, 586, 588, 590, 902, 1073742728, 906, 908, 1073742734, 911, 1073742737, 929, 1073742755, 939, 1073742802, 980, 984, 986, 988, 990, 992, 994, 996, 998, 1000, 1002, 1004, 1006, 1012, 1015, 1073742841, 1018, 1073742845, 1071, 1120, 1122, 1124, 1126, 1128, 1130, 1132, 1134, 1136, 1138, 1140, 1142, 1144, 1146, 1148, 1150, 1152, 1162, 1164, 1166, 1168, 1170, 1172, 1174, 1176, 1178, 1180, 1182, 1184, 1186, 1188, 1190, 1192, 1194, 1196, 1198, 1200, 1202, 1204, 1206, 1208, 1210, 1212, 1214, 1073743040, 1217, 1219, 1221, 1223, 1225, 1227, 1229, 1232, 1234, 1236, 1238, 1240, 1242, 1244, 1246, 1248, 1250, 1252, 1254, 1256, 1258, 1260, 1262, 1264, 1266, 1268, 1270, 1272, 1274, 1276, 1278, 1280, 1282, 1284, 1286, 1288, 1290, 1292, 1294, 1296, 1298, 1073743153, 1366, 1073746080, 4293, 7680, 7682, 7684, 7686, 7688, 7690, 7692, 7694, 7696, 7698, 7700, 7702, 7704, 7706, 7708, 7710, 7712, 7714, 7716, 7718, 7720, 7722, 7724, 7726, 7728, 7730, 7732, 7734, 7736, 7738, 7740, 7742, 7744, 7746, 7748, 7750, 7752, 7754, 7756, 7758, 7760, 7762, 7764, 7766, 7768, 7770, 7772, 7774, 7776, 7778, 7780, 7782, 7784, 7786, 7788, 7790, 7792, 7794, 7796, 7798, 7800, 7802, 7804, 7806, 7808, 7810, 7812, 7814, 7816, 7818, 7820, 7822, 7824, 7826, 7828, 7840, 7842, 7844, 7846, 7848, 7850, 7852, 7854, 7856, 7858, 7860, 7862, 7864, 7866, 7868, 7870, 7872, 7874, 7876, 7878, 7880, 7882, 7884, 7886, 7888, 7890, 7892, 7894, 7896, 7898, 7900, 7902, 7904, 7906, 7908, 7910, 7912, 7914, 7916, 7918, 7920, 7922, 7924, 7926, 7928, 1073749768, 7951, 1073749784, 7965, 1073749800, 7983, 1073749816, 7999, 1073749832, 8013, 8025, 8027, 8029, 8031, 1073749864, 8047, 1073749944, 8123, 1073749960, 8139, 1073749976, 8155, 1073749992, 8172, 1073750008, 8187, 8450, 8455, 1073750283, 8461, 1073750288, 8466, 8469, 1073750297, 8477, 8484, 8486, 8488, 1073750314, 8493, 1073750320, 8499, 1073750334, 8511, 8517, 8579, 1073753088, 11310, 11360, 1073753186, 11364, 11367, 11369, 11371, 11381, 11392, 11394, 11396, 11398, 11400, 11402, 11404, 11406, 11408, 11410, 11412, 11414, 11416, 11418, 11420, 11422, 11424, 11426, 11428, 11430, 11432, 11434, 11436, 11438, 11440, 11442, 11444, 11446, 11448, 11450, 11452, 11454, 11456, 11458, 11460, 11462, 11464, 11466, 11468, 11470, 11472, 11474, 11476, 11478, 11480, 11482, 11484, 11486, 11488, 11490 }; // NOLINT
static const uint16_t kUppercaseTable1Size = 2;
-static const uint16_t kUppercaseTable1[2] = { 65313, 32570 }; // NOLINT
+static const int32_t kUppercaseTable1[2] = { 1073774369, 32570 }; // NOLINT
static const uint16_t kUppercaseTable2Size = 2;
-static const uint16_t kUppercaseTable2[2] = { 33792, 1063 }; // NOLINT
+static const int32_t kUppercaseTable2[2] = { 1073742848, 1063 }; // NOLINT
static const uint16_t kUppercaseTable3Size = 58;
-static const uint16_t kUppercaseTable3[58] = { 54272, 21529, 54324, 21581, 54376, 21633, 21660, 54430, 21663, 21666, 54437, 21670, 54441, 21676, 54446, 21685, 54480, 21737, 54532, 21765, 54535, 21770, 54541, 21780, 54550, 21788, 54584, 21817, 54587, 21822, 54592, 21828, 21830, 54602, 21840, 54636, 21893, 54688, 21945, 54740, 21997, 54792, 22049, 54844, 22101, 54896, 22153, 54952, 22208, 55010, 22266, 55068, 22324, 55126, 22382, 55184, 22440, 22474 }; // NOLINT
+static const int32_t kUppercaseTable3[58] = { 1073763328, 21529, 1073763380, 21581, 1073763432, 21633, 21660, 1073763486, 21663, 21666, 1073763493, 21670, 1073763497, 21676, 1073763502, 21685, 1073763536, 21737, 1073763588, 21765, 1073763591, 21770, 1073763597, 21780, 1073763606, 21788, 1073763640, 21817, 1073763643, 21822, 1073763648, 21828, 21830, 1073763658, 21840, 1073763692, 21893, 1073763744, 21945, 1073763796, 21997, 1073763848, 22049, 1073763900, 22101, 1073763952, 22153, 1073764008, 22208, 1073764066, 22266, 1073764124, 22324, 1073764182, 22382, 1073764240, 22440, 22474 }; // NOLINT
bool Uppercase::Is(uchar c) {
int chunk_index = c >> 15;
switch (chunk_index) {
@@ -352,13 +365,13 @@
// Lowercase: point.category == 'Ll'
static const uint16_t kLowercaseTable0Size = 528;
-static const uint16_t kLowercaseTable0[528] = { 32865, 122, 170, 181, 186, 32991, 246, 33016, 255, 257, 259, 261, 263, 265, 267, 269, 271, 273, 275, 277, 279, 281, 283, 285, 287, 289, 291, 293, 295, 297, 299, 301, 303, 305, 307, 309, 33079, 312, 314, 316, 318, 320, 322, 324, 326, 33096, 329, 331, 333, 335, 337, 339, 341, 343, 345, 347, 349, 351, 353, 355, 357, 359, 361, 363, 365, 367, 369, 371, 373, 375, 378, 380, 33150, 384, 387, 389, 392, 33164, 397, 402, 405, 33177, 411, 414, 417, 419, 421, 424, 33194, 427, 429, 432, 436, 438, 33209, 442, 33213, 447, 454, 457, 460, 462, 464, 466, 468, 470, 472, 474, 33244, 477, 479, 481, 483, 485, 487, 489, 491, 493, 33263, 496, 499, 501, 505, 507, 509, 511, 513, 515, 517, 519, 521, 523, 525, 527, 529, 531, 533, 535, 537, 539, 541, 543, 545, 547, 549, 551, 553, 555, 557, 559, 561, 33331, 569, 572, 33343, 576, 578, 583, 585, 587, 589, 33359, 659, 33429, 687, 33659, 893, 912, 33708, 974, 33744, 977, 33749, 983, 985, 987, 989, 991, 993, 995, 997, 999, 1001, 1003, 1005, 33775, 1011, 1013, 1016, 33787, 1020, 33840, 1119, 1121, 1123, 1125, 1127, 1129, 1131, 1133, 1135, 1137, 1139, 1141, 1143, 1145, 1147, 1149, 1151, 1153, 1163, 1165, 1167, 1169, 1171, 1173, 1175, 1177, 1179, 1181, 1183, 1185, 1187, 1189, 1191, 1193, 1195, 1197, 1199, 1201, 1203, 1205, 1207, 1209, 1211, 1213, 1215, 1218, 1220, 1222, 1224, 1226, 1228, 33998, 1231, 1233, 1235, 1237, 1239, 1241, 1243, 1245, 1247, 1249, 1251, 1253, 1255, 1257, 1259, 1261, 1263, 1265, 1267, 1269, 1271, 1273, 1275, 1277, 1279, 1281, 1283, 1285, 1287, 1289, 1291, 1293, 1295, 1297, 1299, 34145, 1415, 40192, 7467, 40290, 7543, 40313, 7578, 7681, 7683, 7685, 7687, 7689, 7691, 7693, 7695, 7697, 7699, 7701, 7703, 7705, 7707, 7709, 7711, 7713, 7715, 7717, 7719, 7721, 7723, 7725, 7727, 7729, 7731, 7733, 7735, 7737, 7739, 7741, 7743, 7745, 7747, 7749, 7751, 7753, 7755, 7757, 7759, 7761, 7763, 7765, 7767, 7769, 7771, 7773, 7775, 7777, 7779, 7781, 7783, 7785, 7787, 7789, 7791, 7793, 7795, 7797, 7799, 7801, 7803, 7805, 7807, 7809, 7811, 7813, 7815, 7817, 7819, 7821, 7823, 7825, 7827, 40597, 7835, 7841, 7843, 7845, 7847, 7849, 7851, 7853, 7855, 7857, 7859, 7861, 7863, 7865, 7867, 7869, 7871, 7873, 7875, 7877, 7879, 7881, 7883, 7885, 7887, 7889, 7891, 7893, 7895, 7897, 7899, 7901, 7903, 7905, 7907, 7909, 7911, 7913, 7915, 7917, 7919, 7921, 7923, 7925, 7927, 7929, 40704, 7943, 40720, 7957, 40736, 7975, 40752, 7991, 40768, 8005, 40784, 8023, 40800, 8039, 40816, 8061, 40832, 8071, 40848, 8087, 40864, 8103, 40880, 8116, 40886, 8119, 8126, 40898, 8132, 40902, 8135, 40912, 8147, 40918, 8151, 40928, 8167, 40946, 8180, 40950, 8183, 8305, 8319, 8458, 41230, 8463, 8467, 8495, 8500, 8505, 41276, 8509, 41286, 8521, 8526, 8580, 44080, 11358, 11361, 44133, 11366, 11368, 11370, 11372, 11380, 44150, 11383, 11393, 11395, 11397, 11399, 11401, 11403, 11405, 11407, 11409, 11411, 11413, 11415, 11417, 11419, 11421, 11423, 11425, 11427, 11429, 11431, 11433, 11435, 11437, 11439, 11441, 11443, 11445, 11447, 11449, 11451, 11453, 11455, 11457, 11459, 11461, 11463, 11465, 11467, 11469, 11471, 11473, 11475, 11477, 11479, 11481, 11483, 11485, 11487, 11489, 44259, 11492, 44288, 11557 }; // NOLINT
+static const int32_t kLowercaseTable0[528] = { 1073741921, 122, 170, 181, 186, 1073742047, 246, 1073742072, 255, 257, 259, 261, 263, 265, 267, 269, 271, 273, 275, 277, 279, 281, 283, 285, 287, 289, 291, 293, 295, 297, 299, 301, 303, 305, 307, 309, 1073742135, 312, 314, 316, 318, 320, 322, 324, 326, 1073742152, 329, 331, 333, 335, 337, 339, 341, 343, 345, 347, 349, 351, 353, 355, 357, 359, 361, 363, 365, 367, 369, 371, 373, 375, 378, 380, 1073742206, 384, 387, 389, 392, 1073742220, 397, 402, 405, 1073742233, 411, 414, 417, 419, 421, 424, 1073742250, 427, 429, 432, 436, 438, 1073742265, 442, 1073742269, 447, 454, 457, 460, 462, 464, 466, 468, 470, 472, 474, 1073742300, 477, 479, 481, 483, 485, 487, 489, 491, 493, 1073742319, 496, 499, 501, 505, 507, 509, 511, 513, 515, 517, 519, 521, 523, 525, 527, 529, 531, 533, 535, 537, 539, 541, 543, 545, 547, 549, 551, 553, 555, 557, 559, 561, 1073742387, 569, 572, 1073742399, 576, 578, 583, 585, 587, 589, 1073742415, 659, 1073742485, 687, 1073742715, 893, 912, 1073742764, 974, 1073742800, 977, 1073742805, 983, 985, 987, 989, 991, 993, 995, 997, 999, 1001, 1003, 1005, 1073742831, 1011, 1013, 1016, 1073742843, 1020, 1073742896, 1119, 1121, 1123, 1125, 1127, 1129, 1131, 1133, 1135, 1137, 1139, 1141, 1143, 1145, 1147, 1149, 1151, 1153, 1163, 1165, 1167, 1169, 1171, 1173, 1175, 1177, 1179, 1181, 1183, 1185, 1187, 1189, 1191, 1193, 1195, 1197, 1199, 1201, 1203, 1205, 1207, 1209, 1211, 1213, 1215, 1218, 1220, 1222, 1224, 1226, 1228, 1073743054, 1231, 1233, 1235, 1237, 1239, 1241, 1243, 1245, 1247, 1249, 1251, 1253, 1255, 1257, 1259, 1261, 1263, 1265, 1267, 1269, 1271, 1273, 1275, 1277, 1279, 1281, 1283, 1285, 1287, 1289, 1291, 1293, 1295, 1297, 1299, 1073743201, 1415, 1073749248, 7467, 1073749346, 7543, 1073749369, 7578, 7681, 7683, 7685, 7687, 7689, 7691, 7693, 7695, 7697, 7699, 7701, 7703, 7705, 7707, 7709, 7711, 7713, 7715, 7717, 7719, 7721, 7723, 7725, 7727, 7729, 7731, 7733, 7735, 7737, 7739, 7741, 7743, 7745, 7747, 7749, 7751, 7753, 7755, 7757, 7759, 7761, 7763, 7765, 7767, 7769, 7771, 7773, 7775, 7777, 7779, 7781, 7783, 7785, 7787, 7789, 7791, 7793, 7795, 7797, 7799, 7801, 7803, 7805, 7807, 7809, 7811, 7813, 7815, 7817, 7819, 7821, 7823, 7825, 7827, 1073749653, 7835, 7841, 7843, 7845, 7847, 7849, 7851, 7853, 7855, 7857, 7859, 7861, 7863, 7865, 7867, 7869, 7871, 7873, 7875, 7877, 7879, 7881, 7883, 7885, 7887, 7889, 7891, 7893, 7895, 7897, 7899, 7901, 7903, 7905, 7907, 7909, 7911, 7913, 7915, 7917, 7919, 7921, 7923, 7925, 7927, 7929, 1073749760, 7943, 1073749776, 7957, 1073749792, 7975, 1073749808, 7991, 1073749824, 8005, 1073749840, 8023, 1073749856, 8039, 1073749872, 8061, 1073749888, 8071, 1073749904, 8087, 1073749920, 8103, 1073749936, 8116, 1073749942, 8119, 8126, 1073749954, 8132, 1073749958, 8135, 1073749968, 8147, 1073749974, 8151, 1073749984, 8167, 1073750002, 8180, 1073750006, 8183, 8305, 8319, 8458, 1073750286, 8463, 8467, 8495, 8500, 8505, 1073750332, 8509, 1073750342, 8521, 8526, 8580, 1073753136, 11358, 11361, 1073753189, 11366, 11368, 11370, 11372, 11380, 1073753206, 11383, 11393, 11395, 11397, 11399, 11401, 11403, 11405, 11407, 11409, 11411, 11413, 11415, 11417, 11419, 11421, 11423, 11425, 11427, 11429, 11431, 11433, 11435, 11437, 11439, 11441, 11443, 11445, 11447, 11449, 11451, 11453, 11455, 11457, 11459, 11461, 11463, 11465, 11467, 11469, 11471, 11473, 11475, 11477, 11479, 11481, 11483, 11485, 11487, 11489, 1073753315, 11492, 1073753344, 11557 }; // NOLINT
static const uint16_t kLowercaseTable1Size = 6;
-static const uint16_t kLowercaseTable1[6] = { 64256, 31494, 64275, 31511, 65345, 32602 }; // NOLINT
+static const int32_t kLowercaseTable1[6] = { 1073773312, 31494, 1073773331, 31511, 1073774401, 32602 }; // NOLINT
static const uint16_t kLowercaseTable2Size = 2;
-static const uint16_t kLowercaseTable2[2] = { 33832, 1103 }; // NOLINT
+static const int32_t kLowercaseTable2[2] = { 1073742888, 1103 }; // NOLINT
static const uint16_t kLowercaseTable3Size = 54;
-static const uint16_t kLowercaseTable3[54] = { 54298, 21555, 54350, 21588, 54358, 21607, 54402, 21659, 54454, 21689, 21691, 54461, 21699, 54469, 21711, 54506, 21763, 54558, 21815, 54610, 21867, 54662, 21919, 54714, 21971, 54766, 22023, 54818, 22075, 54870, 22127, 54922, 22181, 54978, 22234, 55004, 22241, 55036, 22292, 55062, 22299, 55094, 22350, 55120, 22357, 55152, 22408, 55178, 22415, 55210, 22466, 55236, 22473, 22475 }; // NOLINT
+static const int32_t kLowercaseTable3[54] = { 1073763354, 21555, 1073763406, 21588, 1073763414, 21607, 1073763458, 21659, 1073763510, 21689, 21691, 1073763517, 21699, 1073763525, 21711, 1073763562, 21763, 1073763614, 21815, 1073763666, 21867, 1073763718, 21919, 1073763770, 21971, 1073763822, 22023, 1073763874, 22075, 1073763926, 22127, 1073763978, 22181, 1073764034, 22234, 1073764060, 22241, 1073764092, 22292, 1073764118, 22299, 1073764150, 22350, 1073764176, 22357, 1073764208, 22408, 1073764234, 22415, 1073764266, 22466, 1073764292, 22473, 22475 }; // NOLINT
bool Lowercase::Is(uchar c) {
int chunk_index = c >> 15;
switch (chunk_index) {
@@ -381,17 +394,17 @@
// Letter: point.category in ['Lu', 'Ll', 'Lt', 'Lm', 'Lo' ]
static const uint16_t kLetterTable0Size = 476;
-static const uint16_t kLetterTable0[476] = { 32833, 90, 32865, 122, 170, 181, 186, 32960, 214, 32984, 246, 33016, 705, 33478, 721, 33504, 740, 750, 33658, 893, 902, 33672, 906, 908, 33678, 929, 33699, 974, 33744, 1013, 33783, 1153, 33930, 1299, 34097, 1366, 1369, 34145, 1415, 34256, 1514, 34288, 1522, 34337, 1594, 34368, 1610, 34414, 1647, 34417, 1747, 1749, 34533, 1766, 34542, 1775, 34554, 1788, 1791, 1808, 34578, 1839, 34637, 1901, 34688, 1957, 1969, 34762, 2026, 34804, 2037, 2042, 35076, 2361, 2365, 2384, 35160, 2401, 35195, 2431, 35205, 2444, 35215, 2448, 35219, 2472, 35242, 2480, 2482, 35254, 2489, 2493, 2510, 35292, 2525, 35295, 2529, 35312, 2545, 35333, 2570, 35343, 2576, 35347, 2600, 35370, 2608, 35378, 2611, 35381, 2614, 35384, 2617, 35417, 2652, 2654, 35442, 2676, 35461, 2701, 35471, 2705, 35475, 2728, 35498, 2736, 35506, 2739, 35509, 2745, 2749, 2768, 35552, 2785, 35589, 2828, 35599, 2832, 35603, 2856, 35626, 2864, 35634, 2867, 35637, 2873, 2877, 35676, 2909, 35679, 2913, 2929, 2947, 35717, 2954, 35726, 2960, 35730, 2965, 35737, 2970, 2972, 35742, 2975, 35747, 2980, 35752, 2986, 35758, 3001, 35845, 3084, 35854, 3088, 35858, 3112, 35882, 3123, 35893, 3129, 35936, 3169, 35973, 3212, 35982, 3216, 35986, 3240, 36010, 3251, 36021, 3257, 3261, 3294, 36064, 3297, 36101, 3340, 36110, 3344, 36114, 3368, 36138, 3385, 36192, 3425, 36229, 3478, 36250, 3505, 36275, 3515, 3517, 36288, 3526, 36353, 3632, 36402, 3635, 36416, 3654, 36481, 3714, 3716, 36487, 3720, 3722, 3725, 36500, 3735, 36505, 3743, 36513, 3747, 3749, 3751, 36522, 3755, 36525, 3760, 36530, 3763, 3773, 36544, 3780, 3782, 36572, 3805, 3840, 36672, 3911, 36681, 3946, 36744, 3979, 36864, 4129, 36899, 4135, 36905, 4138, 36944, 4181, 37024, 4293, 37072, 4346, 4348, 37120, 4441, 37215, 4514, 37288, 4601, 37376, 4680, 37450, 4685, 37456, 4694, 4696, 37466, 4701, 37472, 4744, 37514, 4749, 37520, 4784, 37554, 4789, 37560, 4798, 4800, 37570, 4805, 37576, 4822, 37592, 4880, 37650, 4885, 37656, 4954, 37760, 5007, 37792, 5108, 37889, 5740, 38511, 5750, 38529, 5786, 38560, 5866, 38656, 5900, 38670, 5905, 38688, 5937, 38720, 5969, 38752, 5996, 38766, 6000, 38784, 6067, 6103, 6108, 38944, 6263, 39040, 6312, 39168, 6428, 39248, 6509, 39280, 6516, 39296, 6569, 39361, 6599, 39424, 6678, 39685, 6963, 39749, 6987, 40192, 7615, 40448, 7835, 40608, 7929, 40704, 7957, 40728, 7965, 40736, 8005, 40776, 8013, 40784, 8023, 8025, 8027, 8029, 40799, 8061, 40832, 8116, 40886, 8124, 8126, 40898, 8132, 40902, 8140, 40912, 8147, 40918, 8155, 40928, 8172, 40946, 8180, 40950, 8188, 8305, 8319, 41104, 8340, 8450, 8455, 41226, 8467, 8469, 41241, 8477, 8484, 8486, 8488, 41258, 8493, 41263, 8505, 41276, 8511, 41285, 8521, 8526, 41347, 8580, 44032, 11310, 44080, 11358, 44128, 11372, 44148, 11383, 44160, 11492, 44288, 11557, 44336, 11621, 11631, 44416, 11670, 44448, 11686, 44456, 11694, 44464, 11702, 44472, 11710, 44480, 11718, 44488, 11726, 44496, 11734, 44504, 11742, 45061, 12294, 45105, 12341, 45115, 12348, 45121, 12438, 45213, 12447, 45217, 12538, 45308, 12543, 45317, 12588, 45361, 12686, 45472, 12727, 45552, 12799, 46080, 19893, 52736, 32767 }; // NOLINT
+static const int32_t kLetterTable0[476] = { 1073741889, 90, 1073741921, 122, 170, 181, 186, 1073742016, 214, 1073742040, 246, 1073742072, 705, 1073742534, 721, 1073742560, 740, 750, 1073742714, 893, 902, 1073742728, 906, 908, 1073742734, 929, 1073742755, 974, 1073742800, 1013, 1073742839, 1153, 1073742986, 1299, 1073743153, 1366, 1369, 1073743201, 1415, 1073743312, 1514, 1073743344, 1522, 1073743393, 1594, 1073743424, 1610, 1073743470, 1647, 1073743473, 1747, 1749, 1073743589, 1766, 1073743598, 1775, 1073743610, 1788, 1791, 1808, 1073743634, 1839, 1073743693, 1901, 1073743744, 1957, 1969, 1073743818, 2026, 1073743860, 2037, 2042, 1073744132, 2361, 2365, 2384, 1073744216, 2401, 1073744251, 2431, 1073744261, 2444, 1073744271, 2448, 1073744275, 2472, 1073744298, 2480, 2482, 1073744310, 2489, 2493, 2510, 1073744348, 2525, 1073744351, 2529, 1073744368, 2545, 1073744389, 2570, 1073744399, 2576, 1073744403, 2600, 1073744426, 2608, 1073744434, 2611, 1073744437, 2614, 1073744440, 2617, 1073744473, 2652, 2654, 1073744498, 2676, 1073744517, 2701, 1073744527, 2705, 1073744531, 2728, 1073744554, 2736, 1073744562, 2739, 1073744565, 2745, 2749, 2768, 1073744608, 2785, 1073744645, 2828, 1073744655, 2832, 1073744659, 2856, 1073744682, 2864, 1073744690, 2867, 1073744693, 2873, 2877, 1073744732, 2909, 1073744735, 2913, 2929, 2947, 1073744773, 2954, 1073744782, 2960, 1073744786, 2965, 1073744793, 2970, 2972, 1073744798, 2975, 1073744803, 2980, 1073744808, 2986, 1073744814, 3001, 1073744901, 3084, 1073744910, 3088, 1073744914, 3112, 1073744938, 3123, 1073744949, 3129, 1073744992, 3169, 1073745029, 3212, 1073745038, 3216, 1073745042, 3240, 1073745066, 3251, 1073745077, 3257, 3261, 3294, 1073745120, 3297, 1073745157, 3340, 1073745166, 3344, 1073745170, 3368, 1073745194, 3385, 1073745248, 3425, 1073745285, 3478, 1073745306, 3505, 1073745331, 3515, 3517, 1073745344, 3526, 1073745409, 3632, 1073745458, 3635, 1073745472, 3654, 1073745537, 3714, 3716, 1073745543, 3720, 3722, 3725, 1073745556, 3735, 1073745561, 3743, 1073745569, 3747, 3749, 3751, 1073745578, 3755, 1073745581, 3760, 1073745586, 3763, 3773, 1073745600, 3780, 3782, 1073745628, 3805, 3840, 1073745728, 3911, 1073745737, 3946, 1073745800, 3979, 1073745920, 4129, 1073745955, 4135, 1073745961, 4138, 1073746000, 4181, 1073746080, 4293, 1073746128, 4346, 4348, 1073746176, 4441, 1073746271, 4514, 1073746344, 4601, 1073746432, 4680, 1073746506, 4685, 1073746512, 4694, 4696, 1073746522, 4701, 1073746528, 4744, 1073746570, 4749, 1073746576, 4784, 1073746610, 4789, 1073746616, 4798, 4800, 1073746626, 4805, 1073746632, 4822, 1073746648, 4880, 1073746706, 4885, 1073746712, 4954, 1073746816, 5007, 1073746848, 5108, 1073746945, 5740, 1073747567, 5750, 1073747585, 5786, 1073747616, 5866, 1073747712, 5900, 1073747726, 5905, 1073747744, 5937, 1073747776, 5969, 1073747808, 5996, 1073747822, 6000, 1073747840, 6067, 6103, 6108, 1073748000, 6263, 1073748096, 6312, 1073748224, 6428, 1073748304, 6509, 1073748336, 6516, 1073748352, 6569, 1073748417, 6599, 1073748480, 6678, 1073748741, 6963, 1073748805, 6987, 1073749248, 7615, 1073749504, 7835, 1073749664, 7929, 1073749760, 7957, 1073749784, 7965, 1073749792, 8005, 1073749832, 8013, 1073749840, 8023, 8025, 8027, 8029, 1073749855, 8061, 1073749888, 8116, 1073749942, 8124, 8126, 1073749954, 8132, 1073749958, 8140, 1073749968, 8147, 1073749974, 8155, 1073749984, 8172, 1073750002, 8180, 1073750006, 8188, 8305, 8319, 1073750160, 8340, 8450, 8455, 1073750282, 8467, 8469, 1073750297, 8477, 8484, 8486, 8488, 1073750314, 8493, 1073750319, 8505, 1073750332, 8511, 1073750341, 8521, 8526, 1073750403, 8580, 1073753088, 11310, 1073753136, 11358, 1073753184, 11372, 1073753204, 11383, 1073753216, 11492, 1073753344, 11557, 1073753392, 11621, 11631, 1073753472, 11670, 1073753504, 11686, 1073753512, 11694, 1073753520, 11702, 1073753528, 11710, 1073753536, 11718, 1073753544, 11726, 1073753552, 11734, 1073753560, 11742, 1073754117, 12294, 1073754161, 12341, 1073754171, 12348, 1073754177, 12438, 1073754269, 12447, 1073754273, 12538, 1073754364, 12543, 1073754373, 12588, 1073754417, 12686, 1073754528, 12727, 1073754608, 12799, 1073755136, 19893, 1073761792, 32767 }; // NOLINT
static const uint16_t kLetterTable1Size = 68;
-static const uint16_t kLetterTable1[68] = { 32768, 8123, 40960, 9356, 42775, 10010, 43008, 10241, 43011, 10245, 43015, 10250, 43020, 10274, 43072, 10355, 44032, 22435, 63744, 31277, 64048, 31338, 64112, 31449, 64256, 31494, 64275, 31511, 31517, 64287, 31528, 64298, 31542, 64312, 31548, 31550, 64320, 31553, 64323, 31556, 64326, 31665, 64467, 32061, 64848, 32143, 64914, 32199, 65008, 32251, 65136, 32372, 65142, 32508, 65313, 32570, 65345, 32602, 65382, 32702, 65474, 32711, 65482, 32719, 65490, 32727, 65498, 32732 }; // NOLINT
+static const int32_t kLetterTable1[68] = { 1073741824, 8123, 1073750016, 9356, 1073751831, 10010, 1073752064, 10241, 1073752067, 10245, 1073752071, 10250, 1073752076, 10274, 1073752128, 10355, 1073753088, 22435, 1073772800, 31277, 1073773104, 31338, 1073773168, 31449, 1073773312, 31494, 1073773331, 31511, 31517, 1073773343, 31528, 1073773354, 31542, 1073773368, 31548, 31550, 1073773376, 31553, 1073773379, 31556, 1073773382, 31665, 1073773523, 32061, 1073773904, 32143, 1073773970, 32199, 1073774064, 32251, 1073774192, 32372, 1073774198, 32508, 1073774369, 32570, 1073774401, 32602, 1073774438, 32702, 1073774530, 32711, 1073774538, 32719, 1073774546, 32727, 1073774554, 32732 }; // NOLINT
static const uint16_t kLetterTable2Size = 48;
-static const uint16_t kLetterTable2[48] = { 32768, 11, 32781, 38, 32808, 58, 32828, 61, 32831, 77, 32848, 93, 32896, 250, 33536, 798, 33584, 832, 33602, 841, 33664, 925, 33696, 963, 33736, 975, 33792, 1181, 34816, 2053, 2056, 34826, 2101, 34871, 2104, 2108, 2111, 35072, 2325, 2560, 35344, 2579, 35349, 2583, 35353, 2611, 40960, 9070 }; // NOLINT
+static const int32_t kLetterTable2[48] = { 1073741824, 11, 1073741837, 38, 1073741864, 58, 1073741884, 61, 1073741887, 77, 1073741904, 93, 1073741952, 250, 1073742592, 798, 1073742640, 832, 1073742658, 841, 1073742720, 925, 1073742752, 963, 1073742792, 975, 1073742848, 1181, 1073743872, 2053, 2056, 1073743882, 2101, 1073743927, 2104, 2108, 2111, 1073744128, 2325, 2560, 1073744400, 2579, 1073744405, 2583, 1073744409, 2611, 1073750016, 9070 }; // NOLINT
static const uint16_t kLetterTable3Size = 57;
-static const uint16_t kLetterTable3[57] = { 54272, 21588, 54358, 21660, 54430, 21663, 21666, 54437, 21670, 54441, 21676, 54446, 21689, 21691, 54461, 21699, 54469, 21765, 54535, 21770, 54541, 21780, 54550, 21788, 54558, 21817, 54587, 21822, 54592, 21828, 21830, 54602, 21840, 54610, 22181, 54952, 22208, 54978, 22234, 55004, 22266, 55036, 22292, 55062, 22324, 55094, 22350, 55120, 22382, 55152, 22408, 55178, 22440, 55210, 22466, 55236, 22475 }; // NOLINT
+static const int32_t kLetterTable3[57] = { 1073763328, 21588, 1073763414, 21660, 1073763486, 21663, 21666, 1073763493, 21670, 1073763497, 21676, 1073763502, 21689, 21691, 1073763517, 21699, 1073763525, 21765, 1073763591, 21770, 1073763597, 21780, 1073763606, 21788, 1073763614, 21817, 1073763643, 21822, 1073763648, 21828, 21830, 1073763658, 21840, 1073763666, 22181, 1073764008, 22208, 1073764034, 22234, 1073764060, 22266, 1073764092, 22292, 1073764118, 22324, 1073764150, 22350, 1073764176, 22382, 1073764208, 22408, 1073764234, 22440, 1073764266, 22466, 1073764292, 22475 }; // NOLINT
static const uint16_t kLetterTable4Size = 2;
-static const uint16_t kLetterTable4[2] = { 32768, 32767 }; // NOLINT
+static const int32_t kLetterTable4[2] = { 1073741824, 32767 }; // NOLINT
static const uint16_t kLetterTable5Size = 4;
-static const uint16_t kLetterTable5[4] = { 32768, 9942, 63488, 31261 }; // NOLINT
+static const int32_t kLetterTable5[4] = { 1073741824, 9942, 1073772544, 31261 }; // NOLINT
bool Letter::Is(uchar c) {
int chunk_index = c >> 15;
switch (chunk_index) {
@@ -420,7 +433,7 @@
// Space: point.category == 'Zs'
static const uint16_t kSpaceTable0Size = 9;
-static const uint16_t kSpaceTable0[9] = { 32, 160, 5760, 6158, 40960, 8202, 8239, 8287, 12288 }; // NOLINT
+static const int32_t kSpaceTable0[9] = { 32, 160, 5760, 6158, 1073750016, 8202, 8239, 8287, 12288 }; // NOLINT
bool Space::Is(uchar c) {
int chunk_index = c >> 15;
switch (chunk_index) {
@@ -431,30 +444,16 @@
}
}
-// Titlecase: point.category == 'Lt'
-
-static const uint16_t kTitlecaseTable0Size = 13;
-static const uint16_t kTitlecaseTable0[13] = { 453, 456, 459, 498, 40840, 8079, 40856, 8095, 40872, 8111, 8124, 8140, 8188 }; // NOLINT
-bool Titlecase::Is(uchar c) {
- int chunk_index = c >> 15;
- switch (chunk_index) {
- case 0: return LookupPredicate(kTitlecaseTable0,
- kTitlecaseTable0Size,
- c);
- default: return false;
- }
-}
-
// Number: point.category in ['Nd', 'Nl', 'No' ]
static const uint16_t kNumberTable0Size = 86;
-static const uint16_t kNumberTable0[86] = { 32816, 57, 32946, 179, 185, 32956, 190, 34400, 1641, 34544, 1785, 34752, 1993, 35174, 2415, 35302, 2543, 35316, 2553, 35430, 2671, 35558, 2799, 35686, 2927, 35814, 3058, 35942, 3183, 36070, 3311, 36198, 3439, 36432, 3673, 36560, 3801, 36640, 3891, 36928, 4169, 37737, 4988, 38638, 5872, 38880, 6121, 38896, 6137, 38928, 6169, 39238, 6479, 39376, 6617, 39760, 7001, 8304, 41076, 8313, 41088, 8329, 41299, 8578, 42080, 9371, 42218, 9471, 42870, 10131, 11517, 12295, 45089, 12329, 45112, 12346, 45458, 12693, 45600, 12841, 45649, 12895, 45696, 12937, 45745, 12991 }; // NOLINT
+static const int32_t kNumberTable0[86] = { 1073741872, 57, 1073742002, 179, 185, 1073742012, 190, 1073743456, 1641, 1073743600, 1785, 1073743808, 1993, 1073744230, 2415, 1073744358, 2543, 1073744372, 2553, 1073744486, 2671, 1073744614, 2799, 1073744742, 2927, 1073744870, 3058, 1073744998, 3183, 1073745126, 3311, 1073745254, 3439, 1073745488, 3673, 1073745616, 3801, 1073745696, 3891, 1073745984, 4169, 1073746793, 4988, 1073747694, 5872, 1073747936, 6121, 1073747952, 6137, 1073747984, 6169, 1073748294, 6479, 1073748432, 6617, 1073748816, 7001, 8304, 1073750132, 8313, 1073750144, 8329, 1073750355, 8578, 1073751136, 9371, 1073751274, 9471, 1073751926, 10131, 11517, 12295, 1073754145, 12329, 1073754168, 12346, 1073754514, 12693, 1073754656, 12841, 1073754705, 12895, 1073754752, 12937, 1073754801, 12991 }; // NOLINT
static const uint16_t kNumberTable1Size = 2;
-static const uint16_t kNumberTable1[2] = { 65296, 32537 }; // NOLINT
+static const int32_t kNumberTable1[2] = { 1073774352, 32537 }; // NOLINT
static const uint16_t kNumberTable2Size = 19;
-static const uint16_t kNumberTable2[19] = { 33031, 307, 33088, 376, 394, 33568, 803, 833, 842, 33745, 981, 33952, 1193, 35094, 2329, 35392, 2631, 41984, 9314 }; // NOLINT
+static const int32_t kNumberTable2[19] = { 1073742087, 307, 1073742144, 376, 394, 1073742624, 803, 833, 842, 1073742801, 981, 1073743008, 1193, 1073744150, 2329, 1073744448, 2631, 1073751040, 9314 }; // NOLINT
static const uint16_t kNumberTable3Size = 4;
-static const uint16_t kNumberTable3[4] = { 54112, 21361, 55246, 22527 }; // NOLINT
+static const int32_t kNumberTable3[4] = { 1073763168, 21361, 1073764302, 22527 }; // NOLINT
bool Number::Is(uchar c) {
int chunk_index = c >> 15;
switch (chunk_index) {
@@ -474,68 +473,10 @@
}
}
-// DecimalDigit: point.category == 'Nd'
-
-static const uint16_t kDecimalDigitTable0Size = 44;
-static const uint16_t kDecimalDigitTable0[44] = { 32816, 57, 34400, 1641, 34544, 1785, 34752, 1993, 35174, 2415, 35302, 2543, 35430, 2671, 35558, 2799, 35686, 2927, 35814, 3055, 35942, 3183, 36070, 3311, 36198, 3439, 36432, 3673, 36560, 3801, 36640, 3881, 36928, 4169, 38880, 6121, 38928, 6169, 39238, 6479, 39376, 6617, 39760, 7001 }; // NOLINT
-static const uint16_t kDecimalDigitTable1Size = 2;
-static const uint16_t kDecimalDigitTable1[2] = { 65296, 32537 }; // NOLINT
-static const uint16_t kDecimalDigitTable2Size = 2;
-static const uint16_t kDecimalDigitTable2[2] = { 33952, 1193 }; // NOLINT
-static const uint16_t kDecimalDigitTable3Size = 2;
-static const uint16_t kDecimalDigitTable3[2] = { 55246, 22527 }; // NOLINT
-bool DecimalDigit::Is(uchar c) {
- int chunk_index = c >> 15;
- switch (chunk_index) {
- case 0: return LookupPredicate(kDecimalDigitTable0,
- kDecimalDigitTable0Size,
- c);
- case 1: return LookupPredicate(kDecimalDigitTable1,
- kDecimalDigitTable1Size,
- c);
- case 2: return LookupPredicate(kDecimalDigitTable2,
- kDecimalDigitTable2Size,
- c);
- case 3: return LookupPredicate(kDecimalDigitTable3,
- kDecimalDigitTable3Size,
- c);
- default: return false;
- }
-}
-
-// Ideographic: 'Id' in point.properties
-
-static const uint16_t kIdeographicTable0Size = 10;
-static const uint16_t kIdeographicTable0[10] = { 45062, 12295, 45089, 12329, 45112, 12346, 46080, 19893, 52736, 32767 }; // NOLINT
-static const uint16_t kIdeographicTable1Size = 6;
-static const uint16_t kIdeographicTable1[6] = { 32768, 8123, 63744, 31277, 64112, 31449 }; // NOLINT
-static const uint16_t kIdeographicTable4Size = 2;
-static const uint16_t kIdeographicTable4[2] = { 32768, 32767 }; // NOLINT
-static const uint16_t kIdeographicTable5Size = 4;
-static const uint16_t kIdeographicTable5[4] = { 32768, 9942, 63488, 31261 }; // NOLINT
-bool Ideographic::Is(uchar c) {
- int chunk_index = c >> 15;
- switch (chunk_index) {
- case 0: return LookupPredicate(kIdeographicTable0,
- kIdeographicTable0Size,
- c);
- case 1: return LookupPredicate(kIdeographicTable1,
- kIdeographicTable1Size,
- c);
- case 4: return LookupPredicate(kIdeographicTable4,
- kIdeographicTable4Size,
- c);
- case 5: return LookupPredicate(kIdeographicTable5,
- kIdeographicTable5Size,
- c);
- default: return false;
- }
-}
-
// WhiteSpace: 'Ws' in point.properties
static const uint16_t kWhiteSpaceTable0Size = 14;
-static const uint16_t kWhiteSpaceTable0[14] = { 32777, 13, 32, 133, 160, 5760, 6158, 40960, 8202, 41000, 8233, 8239, 8287, 12288 }; // NOLINT
+static const int32_t kWhiteSpaceTable0[14] = { 1073741833, 13, 32, 133, 160, 5760, 6158, 1073750016, 8202, 1073750056, 8233, 8239, 8287, 12288 }; // NOLINT
bool WhiteSpace::Is(uchar c) {
int chunk_index = c >> 15;
switch (chunk_index) {
@@ -546,109 +487,10 @@
}
}
-// HexDigit: 'Hd' in point.properties
-
-static const uint16_t kHexDigitTable0Size = 6;
-static const uint16_t kHexDigitTable0[6] = { 32816, 57, 32833, 70, 32865, 102 }; // NOLINT
-static const uint16_t kHexDigitTable1Size = 6;
-static const uint16_t kHexDigitTable1[6] = { 65296, 32537, 65313, 32550, 65345, 32582 }; // NOLINT
-bool HexDigit::Is(uchar c) {
- int chunk_index = c >> 15;
- switch (chunk_index) {
- case 0: return LookupPredicate(kHexDigitTable0,
- kHexDigitTable0Size,
- c);
- case 1: return LookupPredicate(kHexDigitTable1,
- kHexDigitTable1Size,
- c);
- default: return false;
- }
-}
-
-// AsciiHexDigit: 'Ah' in point.properties
-
-static const uint16_t kAsciiHexDigitTable0Size = 6;
-static const uint16_t kAsciiHexDigitTable0[6] = { 32816, 57, 32833, 70, 32865, 102 }; // NOLINT
-bool AsciiHexDigit::Is(uchar c) {
- int chunk_index = c >> 15;
- switch (chunk_index) {
- case 0: return LookupPredicate(kAsciiHexDigitTable0,
- kAsciiHexDigitTable0Size,
- c);
- default: return false;
- }
-}
-
-// BidiControl: 'Bc' in point.properties
-
-static const uint16_t kBidiControlTable0Size = 4;
-static const uint16_t kBidiControlTable0[4] = { 40974, 8207, 41002, 8238 }; // NOLINT
-bool BidiControl::Is(uchar c) {
- int chunk_index = c >> 15;
- switch (chunk_index) {
- case 0: return LookupPredicate(kBidiControlTable0,
- kBidiControlTable0Size,
- c);
- default: return false;
- }
-}
-
-// JoinControl: 'Jc' in point.properties
-
-static const uint16_t kJoinControlTable0Size = 2;
-static const uint16_t kJoinControlTable0[2] = { 40972, 8205 }; // NOLINT
-bool JoinControl::Is(uchar c) {
- int chunk_index = c >> 15;
- switch (chunk_index) {
- case 0: return LookupPredicate(kJoinControlTable0,
- kJoinControlTable0Size,
- c);
- default: return false;
- }
-}
-
-// Dash: 'Dh' in point.properties
-
-static const uint16_t kDashTable0Size = 14;
-static const uint16_t kDashTable0[14] = { 45, 1418, 1470, 6150, 40976, 8213, 8275, 8315, 8331, 8722, 11799, 12316, 12336, 12448 }; // NOLINT
-static const uint16_t kDashTable1Size = 5;
-static const uint16_t kDashTable1[5] = { 65073, 32306, 32344, 32355, 32525 }; // NOLINT
-bool Dash::Is(uchar c) {
- int chunk_index = c >> 15;
- switch (chunk_index) {
- case 0: return LookupPredicate(kDashTable0,
- kDashTable0Size,
- c);
- case 1: return LookupPredicate(kDashTable1,
- kDashTable1Size,
- c);
- default: return false;
- }
-}
-
-// Hyphen: 'Hp' in point.properties
-
-static const uint16_t kHyphenTable0Size = 8;
-static const uint16_t kHyphenTable0[8] = { 45, 173, 1418, 6150, 40976, 8209, 11799, 12539 }; // NOLINT
-static const uint16_t kHyphenTable1Size = 3;
-static const uint16_t kHyphenTable1[3] = { 32355, 32525, 32613 }; // NOLINT
-bool Hyphen::Is(uchar c) {
- int chunk_index = c >> 15;
- switch (chunk_index) {
- case 0: return LookupPredicate(kHyphenTable0,
- kHyphenTable0Size,
- c);
- case 1: return LookupPredicate(kHyphenTable1,
- kHyphenTable1Size,
- c);
- default: return false;
- }
-}
-
// LineTerminator: 'Lt' in point.properties
static const uint16_t kLineTerminatorTable0Size = 4;
-static const uint16_t kLineTerminatorTable0[4] = { 10, 13, 41000, 8233 }; // NOLINT
+static const int32_t kLineTerminatorTable0[4] = { 10, 13, 1073750056, 8233 }; // NOLINT
bool LineTerminator::Is(uchar c) {
int chunk_index = c >> 15;
switch (chunk_index) {
@@ -659,32 +501,18 @@
}
}
-// RegExpSpecialChar: 'Rx' in point.properties
-
-static const uint16_t kRegExpSpecialCharTable0Size = 9;
-static const uint16_t kRegExpSpecialCharTable0[9] = { 36, 32808, 43, 46, 63, 32859, 94, 32891, 125 }; // NOLINT
-bool RegExpSpecialChar::Is(uchar c) {
- int chunk_index = c >> 15;
- switch (chunk_index) {
- case 0: return LookupPredicate(kRegExpSpecialCharTable0,
- kRegExpSpecialCharTable0Size,
- c);
- default: return false;
- }
-}
-
// CombiningMark: point.category in ['Mn', 'Mc']
static const uint16_t kCombiningMarkTable0Size = 214;
-static const uint16_t kCombiningMarkTable0[214] = { 33536, 879, 33923, 1158, 34193, 1469, 1471, 34241, 1474, 34244, 1477, 1479, 34320, 1557, 34379, 1630, 1648, 34518, 1756, 34527, 1764, 34535, 1768, 34538, 1773, 1809, 34608, 1866, 34726, 1968, 34795, 2035, 35073, 2307, 2364, 35134, 2381, 35153, 2388, 35170, 2403, 35201, 2435, 2492, 35262, 2500, 35271, 2504, 35275, 2509, 2519, 35298, 2531, 35329, 2563, 2620, 35390, 2626, 35399, 2632, 35403, 2637, 35440, 2673, 35457, 2691, 2748, 35518, 2757, 35527, 2761, 35531, 2765, 35554, 2787, 35585, 2819, 2876, 35646, 2883, 35655, 2888, 35659, 2893, 35670, 2903, 2946, 35774, 3010, 35782, 3016, 35786, 3021, 3031, 35841, 3075, 35902, 3140, 35910, 3144, 35914, 3149, 35925, 3158, 35970, 3203, 3260, 36030, 3268, 36038, 3272, 36042, 3277, 36053, 3286, 36066, 3299, 36098, 3331, 36158, 3395, 36166, 3400, 36170, 3405, 3415, 36226, 3459, 3530, 36303, 3540, 3542, 36312, 3551, 36338, 3571, 3633, 36404, 3642, 36423, 3662, 3761, 36532, 3769, 36539, 3772, 36552, 3789, 36632, 3865, 3893, 3895, 3897, 36670, 3903, 36721, 3972, 36742, 3975, 36752, 3991, 36761, 4028, 4038, 36908, 4146, 36918, 4153, 36950, 4185, 4959, 38674, 5908, 38706, 5940, 38738, 5971, 38770, 6003, 38838, 6099, 6109, 38923, 6157, 6313, 39200, 6443, 39216, 6459, 39344, 6592, 39368, 6601, 39447, 6683, 39680, 6916, 39732, 6980, 39787, 7027, 40384, 7626, 40446, 7679, 41168, 8412, 8417, 41189, 8431, 45098, 12335, 45209, 12442 }; // NOLINT
+static const int32_t kCombiningMarkTable0[214] = { 1073742592, 879, 1073742979, 1158, 1073743249, 1469, 1471, 1073743297, 1474, 1073743300, 1477, 1479, 1073743376, 1557, 1073743435, 1630, 1648, 1073743574, 1756, 1073743583, 1764, 1073743591, 1768, 1073743594, 1773, 1809, 1073743664, 1866, 1073743782, 1968, 1073743851, 2035, 1073744129, 2307, 2364, 1073744190, 2381, 1073744209, 2388, 1073744226, 2403, 1073744257, 2435, 2492, 1073744318, 2500, 1073744327, 2504, 1073744331, 2509, 2519, 1073744354, 2531, 1073744385, 2563, 2620, 1073744446, 2626, 1073744455, 2632, 1073744459, 2637, 1073744496, 2673, 1073744513, 2691, 2748, 1073744574, 2757, 1073744583, 2761, 1073744587, 2765, 1073744610, 2787, 1073744641, 2819, 2876, 1073744702, 2883, 1073744711, 2888, 1073744715, 2893, 1073744726, 2903, 2946, 1073744830, 3010, 1073744838, 3016, 1073744842, 3021, 3031, 1073744897, 3075, 1073744958, 3140, 1073744966, 3144, 1073744970, 3149, 1073744981, 3158, 1073745026, 3203, 3260, 1073745086, 3268, 1073745094, 3272, 1073745098, 3277, 1073745109, 3286, 1073745122, 3299, 1073745154, 3331, 1073745214, 3395, 1073745222, 3400, 1073745226, 3405, 3415, 1073745282, 3459, 3530, 1073745359, 3540, 3542, 1073745368, 3551, 1073745394, 3571, 3633, 1073745460, 3642, 1073745479, 3662, 3761, 1073745588, 3769, 1073745595, 3772, 1073745608, 3789, 1073745688, 3865, 3893, 3895, 3897, 1073745726, 3903, 1073745777, 3972, 1073745798, 3975, 1073745808, 3991, 1073745817, 4028, 4038, 1073745964, 4146, 1073745974, 4153, 1073746006, 4185, 4959, 1073747730, 5908, 1073747762, 5940, 1073747794, 5971, 1073747826, 6003, 1073747894, 6099, 6109, 1073747979, 6157, 6313, 1073748256, 6443, 1073748272, 6459, 1073748400, 6592, 1073748424, 6601, 1073748503, 6683, 1073748736, 6916, 1073748788, 6980, 1073748843, 7027, 1073749440, 7626, 1073749502, 7679, 1073750224, 8412, 8417, 1073750245, 8431, 1073754154, 12335, 1073754265, 12442 }; // NOLINT
static const uint16_t kCombiningMarkTable1Size = 10;
-static const uint16_t kCombiningMarkTable1[10] = { 10242, 10246, 10251, 43043, 10279, 31518, 65024, 32271, 65056, 32291 }; // NOLINT
+static const int32_t kCombiningMarkTable1[10] = { 10242, 10246, 10251, 1073752099, 10279, 31518, 1073774080, 32271, 1073774112, 32291 }; // NOLINT
static const uint16_t kCombiningMarkTable2Size = 9;
-static const uint16_t kCombiningMarkTable2[9] = { 35329, 2563, 35333, 2566, 35340, 2575, 35384, 2618, 2623 }; // NOLINT
+static const int32_t kCombiningMarkTable2[9] = { 1073744385, 2563, 1073744389, 2566, 1073744396, 2575, 1073744440, 2618, 2623 }; // NOLINT
static const uint16_t kCombiningMarkTable3Size = 12;
-static const uint16_t kCombiningMarkTable3[12] = { 53605, 20841, 53613, 20850, 53627, 20866, 53637, 20875, 53674, 20909, 53826, 21060 }; // NOLINT
+static const int32_t kCombiningMarkTable3[12] = { 1073762661, 20841, 1073762669, 20850, 1073762683, 20866, 1073762693, 20875, 1073762730, 20909, 1073762882, 21060 }; // NOLINT
static const uint16_t kCombiningMarkTable28Size = 2;
-static const uint16_t kCombiningMarkTable28[2] = { 33024, 495 }; // NOLINT
+static const int32_t kCombiningMarkTable28[2] = { 1073742080, 495 }; // NOLINT
bool CombiningMark::Is(uchar c) {
int chunk_index = c >> 15;
switch (chunk_index) {
@@ -710,9 +538,9 @@
// ConnectorPunctuation: point.category == 'Pc'
static const uint16_t kConnectorPunctuationTable0Size = 4;
-static const uint16_t kConnectorPunctuationTable0[4] = { 95, 41023, 8256, 8276 }; // NOLINT
+static const int32_t kConnectorPunctuationTable0[4] = { 95, 1073750079, 8256, 8276 }; // NOLINT
static const uint16_t kConnectorPunctuationTable1Size = 5;
-static const uint16_t kConnectorPunctuationTable1[5] = { 65075, 32308, 65101, 32335, 32575 }; // NOLINT
+static const int32_t kConnectorPunctuationTable1[5] = { 1073774131, 32308, 1073774157, 32335, 32575 }; // NOLINT
bool ConnectorPunctuation::Is(uchar c) {
int chunk_index = c >> 15;
switch (chunk_index) {
@@ -726,15 +554,15 @@
}
}
-static const MultiCharacterSpecialCase kToLowercaseMultiStrings0[] = { {2, {105, 775}}, {0, {0}} }; // NOLINT
+static const MultiCharacterSpecialCase<3> kToLowercaseMultiStrings0[] = { {2, {105, 775}}, {0, {0}} }; // NOLINT
static const uint16_t kToLowercaseTable0Size = 531;
-static const uint16_t kToLowercaseTable0[1062] = { 32833, 128, 90, 128, 32960, 128, 214, 128, 32984, 128, 222, 128, 256, 4, 258, 4, 260, 4, 262, 4, 264, 4, 266, 4, 268, 4, 270, 4, 272, 4, 274, 4, 276, 4, 278, 4, 280, 4, 282, 4, 284, 4, 286, 4, 288, 4, 290, 4, 292, 4, 294, 4, 296, 4, 298, 4, 300, 4, 302, 4, 304, 1, 306, 4, 308, 4, 310, 4, 313, 4, 315, 4, 317, 4, 319, 4, 321, 4, 323, 4, 325, 4, 327, 4, 330, 4, 332, 4, 334, 4, 336, 4, 338, 4, 340, 4, 342, 4, 344, 4, 346, 4, 348, 4, 350, 4, 352, 4, 354, 4, 356, 4, 358, 4, 360, 4, 362, 4, 364, 4, 366, 4, 368, 4, 370, 4, 372, 4, 374, 4, 376, static_cast<uint16_t>(-484), 377, 4, 379, 4, 381, 4, 385, 840, 386, 4, 388, 4, 390, 824, 391, 4, 33161, 820, 394, 820, 395, 4, 398, 316, 399, 808, 400, 812, 401, 4, 403, 820, 404, 828, 406, 844, 407, 836, 408, 4, 412, 844, 413, 852, 415, 856, 416, 4, 418, 4, 420, 4, 422, 872, 423, 4, 425, 872, 428, 4, 430, 872, 431, 4, 33201, 868, 434, 868, 435, 4, 437, 4, 439, 876, 440, 4, 444, 4, 452, 8, 453, 4, 455, 8, 456, 4, 458, 8, 459, 4, 461, 4, 463, 4, 465, 4, 467, 4, 469, 4, 471, 4, 473, 4, 475, 4, 478, 4, 480, 4, 482, 4, 484, 4, 486, 4, 488, 4, 490, 4, 492, 4, 494, 4, 497, 8, 498, 4, 500, 4, 502, static_cast<uint16_t>(-388), 503, static_cast<uint16_t>(-224), 504, 4, 506, 4, 508, 4, 510, 4, 512, 4, 514, 4, 516, 4, 518, 4, 520, 4, 522, 4, 524, 4, 526, 4, 528, 4, 530, 4, 532, 4, 534, 4, 536, 4, 538, 4, 540, 4, 542, 4, 544, static_cast<uint16_t>(-520), 546, 4, 548, 4, 550, 4, 552, 4, 554, 4, 556, 4, 558, 4, 560, 4, 562, 4, 570, 43180, 571, 4, 573, static_cast<uint16_t>(-652), 574, 43168, 577, 4, 579, static_cast<uint16_t>(-780), 580, 276, 581, 284, 582, 4, 584, 4, 586, 4, 588, 4, 590, 4, 902, 152, 33672, 148, 906, 148, 908, 256, 33678, 252, 911, 252, 33681, 128, 929, 128, 33699, 6, 939, 128, 984, 4, 986, 4, 988, 4, 990, 4, 992, 4, 994, 4, 996, 4, 998, 4, 1000, 4, 1002, 4, 1004, 4, 1006, 4, 1012, static_cast<uint16_t>(-240), 1015, 4, 1017, static_cast<uint16_t>(-28), 1018, 4, 33789, static_cast<uint16_t>(-520), 1023, static_cast<uint16_t>(-520), 33792, 320, 1039, 320, 33808, 128, 1071, 128, 1120, 4, 1122, 4, 1124, 4, 1126, 4, 1128, 4, 1130, 4, 1132, 4, 1134, 4, 1136, 4, 1138, 4, 1140, 4, 1142, 4, 1144, 4, 1146, 4, 1148, 4, 1150, 4, 1152, 4, 1162, 4, 1164, 4, 1166, 4, 1168, 4, 1170, 4, 1172, 4, 1174, 4, 1176, 4, 1178, 4, 1180, 4, 1182, 4, 1184, 4, 1186, 4, 1188, 4, 1190, 4, 1192, 4, 1194, 4, 1196, 4, 1198, 4, 1200, 4, 1202, 4, 1204, 4, 1206, 4, 1208, 4, 1210, 4, 1212, 4, 1214, 4, 1216, 60, 1217, 4, 1219, 4, 1221, 4, 1223, 4, 1225, 4, 1227, 4, 1229, 4, 1232, 4, 1234, 4, 1236, 4, 1238, 4, 1240, 4, 1242, 4, 1244, 4, 1246, 4, 1248, 4, 1250, 4, 1252, 4, 1254, 4, 1256, 4, 1258, 4, 1260, 4, 1262, 4, 1264, 4, 1266, 4, 1268, 4, 1270, 4, 1272, 4, 1274, 4, 1276, 4, 1278, 4, 1280, 4, 1282, 4, 1284, 4, 1286, 4, 1288, 4, 1290, 4, 1292, 4, 1294, 4, 1296, 4, 1298, 4, 34097, 192, 1366, 192, 37024, 29056, 4293, 29056, 7680, 4, 7682, 4, 7684, 4, 7686, 4, 7688, 4, 7690, 4, 7692, 4, 7694, 4, 7696, 4, 7698, 4, 7700, 4, 7702, 4, 7704, 4, 7706, 4, 7708, 4, 7710, 4, 7712, 4, 7714, 4, 7716, 4, 7718, 4, 7720, 4, 7722, 4, 7724, 4, 7726, 4, 7728, 4, 7730, 4, 7732, 4, 7734, 4, 7736, 4, 7738, 4, 7740, 4, 7742, 4, 7744, 4, 7746, 4, 7748, 4, 7750, 4, 7752, 4, 7754, 4, 7756, 4, 7758, 4, 7760, 4, 7762, 4, 7764, 4, 7766, 4, 7768, 4, 7770, 4, 7772, 4, 7774, 4, 7776, 4, 7778, 4, 7780, 4, 7782, 4, 7784, 4, 7786, 4, 7788, 4, 7790, 4, 7792, 4, 7794, 4, 7796, 4, 7798, 4, 7800, 4, 7802, 4, 7804, 4, 7806, 4, 7808, 4, 7810, 4, 7812, 4, 7814, 4, 7816, 4, 7818, 4, 7820, 4, 7822, 4, 7824, 4, 7826, 4, 7828, 4, 7840, 4, 7842, 4, 7844, 4, 7846, 4, 7848, 4, 7850, 4, 7852, 4, 7854, 4, 7856, 4, 7858, 4, 7860, 4, 7862, 4, 7864, 4, 7866, 4, 7868, 4, 7870, 4, 7872, 4, 7874, 4, 7876, 4, 7878, 4, 7880, 4, 7882, 4, 7884, 4, 7886, 4, 7888, 4, 7890, 4, 7892, 4, 7894, 4, 7896, 4, 7898, 4, 7900, 4, 7902, 4, 7904, 4, 7906, 4, 7908, 4, 7910, 4, 7912, 4, 7914, 4, 7916, 4, 7918, 4, 7920, 4, 7922, 4, 7924, 4, 7926, 4, 7928, 4, 40712, static_cast<uint16_t>(-32), 7951, static_cast<uint16_t>(-32), 40728, static_cast<uint16_t>(-32), 7965, static_cast<uint16_t>(-32), 40744, static_cast<uint16_t>(-32), 7983, static_cast<uint16_t>(-32), 40760, static_cast<uint16_t>(-32), 7999, static_cast<uint16_t>(-32), 40776, static_cast<uint16_t>(-32), 8013, static_cast<uint16_t>(-32), 8025, static_cast<uint16_t>(-32), 8027, static_cast<uint16_t>(-32), 8029, static_cast<uint16_t>(-32), 8031, static_cast<uint16_t>(-32), 40808, static_cast<uint16_t>(-32), 8047, static_cast<uint16_t>(-32), 40840, static_cast<uint16_t>(-32), 8079, static_cast<uint16_t>(-32), 40856, static_cast<uint16_t>(-32), 8095, static_cast<uint16_t>(-32), 40872, static_cast<uint16_t>(-32), 8111, static_cast<uint16_t>(-32), 40888, static_cast<uint16_t>(-32), 8121, static_cast<uint16_t>(-32), 40890, static_cast<uint16_t>(-296), 8123, static_cast<uint16_t>(-296), 8124, static_cast<uint16_t>(-36), 40904, static_cast<uint16_t>(-344), 8139, static_cast<uint16_t>(-344), 8140, static_cast<uint16_t>(-36), 40920, static_cast<uint16_t>(-32), 8153, static_cast<uint16_t>(-32), 40922, static_cast<uint16_t>(-400), 8155, static_cast<uint16_t>(-400), 40936, static_cast<uint16_t>(-32), 8169, static_cast<uint16_t>(-32), 40938, static_cast<uint16_t>(-448), 8171, static_cast<uint16_t>(-448), 8172, static_cast<uint16_t>(-28), 40952, static_cast<uint16_t>(-512), 8185, static_cast<uint16_t>(-512), 40954, static_cast<uint16_t>(-504), 8187, static_cast<uint16_t>(-504), 8188, static_cast<uint16_t>(-36), 8486, static_cast<uint16_t>(-30068), 8490, static_cast<uint16_t>(-33532), 8491, static_cast<uint16_t>(-33048), 8498, 112, 41312, 64, 8559, 64, 8579, 4, 42166, 104, 9423, 104, 44032, 192, 11310, 192, 11360, 4, 11362, static_cast<uint16_t>(-42972), 11363, static_cast<uint16_t>(-15256), 11364, static_cast<uint16_t>(-42908), 11367, 4, 11369, 4, 11371, 4, 11381, 4, 11392, 4, 11394, 4, 11396, 4, 11398, 4, 11400, 4, 11402, 4, 11404, 4, 11406, 4, 11408, 4, 11410, 4, 11412, 4, 11414, 4, 11416, 4, 11418, 4, 11420, 4, 11422, 4, 11424, 4, 11426, 4, 11428, 4, 11430, 4, 11432, 4, 11434, 4, 11436, 4, 11438, 4, 11440, 4, 11442, 4, 11444, 4, 11446, 4, 11448, 4, 11450, 4, 11452, 4, 11454, 4, 11456, 4, 11458, 4, 11460, 4, 11462, 4, 11464, 4, 11466, 4, 11468, 4, 11470, 4, 11472, 4, 11474, 4, 11476, 4, 11478, 4, 11480, 4, 11482, 4, 11484, 4, 11486, 4, 11488, 4, 11490, 4 }; // NOLINT
-static const MultiCharacterSpecialCase kToLowercaseMultiStrings1[] = { {0, {0}} }; // NOLINT
+static const int32_t kToLowercaseTable0[1062] = { 1073741889, 128, 90, 128, 1073742016, 128, 214, 128, 1073742040, 128, 222, 128, 256, 4, 258, 4, 260, 4, 262, 4, 264, 4, 266, 4, 268, 4, 270, 4, 272, 4, 274, 4, 276, 4, 278, 4, 280, 4, 282, 4, 284, 4, 286, 4, 288, 4, 290, 4, 292, 4, 294, 4, 296, 4, 298, 4, 300, 4, 302, 4, 304, 1, 306, 4, 308, 4, 310, 4, 313, 4, 315, 4, 317, 4, 319, 4, 321, 4, 323, 4, 325, 4, 327, 4, 330, 4, 332, 4, 334, 4, 336, 4, 338, 4, 340, 4, 342, 4, 344, 4, 346, 4, 348, 4, 350, 4, 352, 4, 354, 4, 356, 4, 358, 4, 360, 4, 362, 4, 364, 4, 366, 4, 368, 4, 370, 4, 372, 4, 374, 4, 376, -484, 377, 4, 379, 4, 381, 4, 385, 840, 386, 4, 388, 4, 390, 824, 391, 4, 1073742217, 820, 394, 820, 395, 4, 398, 316, 399, 808, 400, 812, 401, 4, 403, 820, 404, 828, 406, 844, 407, 836, 408, 4, 412, 844, 413, 852, 415, 856, 416, 4, 418, 4, 420, 4, 422, 872, 423, 4, 425, 872, 428, 4, 430, 872, 431, 4, 1073742257, 868, 434, 868, 435, 4, 437, 4, 439, 876, 440, 4, 444, 4, 452, 8, 453, 4, 455, 8, 456, 4, 458, 8, 459, 4, 461, 4, 463, 4, 465, 4, 467, 4, 469, 4, 471, 4, 473, 4, 475, 4, 478, 4, 480, 4, 482, 4, 484, 4, 486, 4, 488, 4, 490, 4, 492, 4, 494, 4, 497, 8, 498, 4, 500, 4, 502, -388, 503, -224, 504, 4, 506, 4, 508, 4, 510, 4, 512, 4, 514, 4, 516, 4, 518, 4, 520, 4, 522, 4, 524, 4, 526, 4, 528, 4, 530, 4, 532, 4, 534, 4, 536, 4, 538, 4, 540, 4, 542, 4, 544, -520, 546, 4, 548, 4, 550, 4, 552, 4, 554, 4, 556, 4, 558, 4, 560, 4, 562, 4, 570, 43180, 571, 4, 573, -652, 574, 43168, 577, 4, 579, -780, 580, 276, 581, 284, 582, 4, 584, 4, 586, 4, 588, 4, 590, 4, 902, 152, 1073742728, 148, 906, 148, 908, 256, 1073742734, 252, 911, 252, 1073742737, 128, 929, 128, 1073742755, 6, 939, 128, 984, 4, 986, 4, 988, 4, 990, 4, 992, 4, 994, 4, 996, 4, 998, 4, 1000, 4, 1002, 4, 1004, 4, 1006, 4, 1012, -240, 1015, 4, 1017, -28, 1018, 4, 1073742845, -520, 1023, -520, 1073742848, 320, 1039, 320, 1073742864, 128, 1071, 128, 1120, 4, 1122, 4, 1124, 4, 1126, 4, 1128, 4, 1130, 4, 1132, 4, 1134, 4, 1136, 4, 1138, 4, 1140, 4, 1142, 4, 1144, 4, 1146, 4, 1148, 4, 1150, 4, 1152, 4, 1162, 4, 1164, 4, 1166, 4, 1168, 4, 1170, 4, 1172, 4, 1174, 4, 1176, 4, 1178, 4, 1180, 4, 1182, 4, 1184, 4, 1186, 4, 1188, 4, 1190, 4, 1192, 4, 1194, 4, 1196, 4, 1198, 4, 1200, 4, 1202, 4, 1204, 4, 1206, 4, 1208, 4, 1210, 4, 1212, 4, 1214, 4, 1216, 60, 1217, 4, 1219, 4, 1221, 4, 1223, 4, 1225, 4, 1227, 4, 1229, 4, 1232, 4, 1234, 4, 1236, 4, 1238, 4, 1240, 4, 1242, 4, 1244, 4, 1246, 4, 1248, 4, 1250, 4, 1252, 4, 1254, 4, 1256, 4, 1258, 4, 1260, 4, 1262, 4, 1264, 4, 1266, 4, 1268, 4, 1270, 4, 1272, 4, 1274, 4, 1276, 4, 1278, 4, 1280, 4, 1282, 4, 1284, 4, 1286, 4, 1288, 4, 1290, 4, 1292, 4, 1294, 4, 1296, 4, 1298, 4, 1073743153, 192, 1366, 192, 1073746080, 29056, 4293, 29056, 7680, 4, 7682, 4, 7684, 4, 7686, 4, 7688, 4, 7690, 4, 7692, 4, 7694, 4, 7696, 4, 7698, 4, 7700, 4, 7702, 4, 7704, 4, 7706, 4, 7708, 4, 7710, 4, 7712, 4, 7714, 4, 7716, 4, 7718, 4, 7720, 4, 7722, 4, 7724, 4, 7726, 4, 7728, 4, 7730, 4, 7732, 4, 7734, 4, 7736, 4, 7738, 4, 7740, 4, 7742, 4, 7744, 4, 7746, 4, 7748, 4, 7750, 4, 7752, 4, 7754, 4, 7756, 4, 7758, 4, 7760, 4, 7762, 4, 7764, 4, 7766, 4, 7768, 4, 7770, 4, 7772, 4, 7774, 4, 7776, 4, 7778, 4, 7780, 4, 7782, 4, 7784, 4, 7786, 4, 7788, 4, 7790, 4, 7792, 4, 7794, 4, 7796, 4, 7798, 4, 7800, 4, 7802, 4, 7804, 4, 7806, 4, 7808, 4, 7810, 4, 7812, 4, 7814, 4, 7816, 4, 7818, 4, 7820, 4, 7822, 4, 7824, 4, 7826, 4, 7828, 4, 7840, 4, 7842, 4, 7844, 4, 7846, 4, 7848, 4, 7850, 4, 7852, 4, 7854, 4, 7856, 4, 7858, 4, 7860, 4, 7862, 4, 7864, 4, 7866, 4, 7868, 4, 7870, 4, 7872, 4, 7874, 4, 7876, 4, 7878, 4, 7880, 4, 7882, 4, 7884, 4, 7886, 4, 7888, 4, 7890, 4, 7892, 4, 7894, 4, 7896, 4, 7898, 4, 7900, 4, 7902, 4, 7904, 4, 7906, 4, 7908, 4, 7910, 4, 7912, 4, 7914, 4, 7916, 4, 7918, 4, 7920, 4, 7922, 4, 7924, 4, 7926, 4, 7928, 4, 1073749768, -32, 7951, -32, 1073749784, -32, 7965, -32, 1073749800, -32, 7983, -32, 1073749816, -32, 7999, -32, 1073749832, -32, 8013, -32, 8025, -32, 8027, -32, 8029, -32, 8031, -32, 1073749864, -32, 8047, -32, 1073749896, -32, 8079, -32, 1073749912, -32, 8095, -32, 1073749928, -32, 8111, -32, 1073749944, -32, 8121, -32, 1073749946, -296, 8123, -296, 8124, -36, 1073749960, -344, 8139, -344, 8140, -36, 1073749976, -32, 8153, -32, 1073749978, -400, 8155, -400, 1073749992, -32, 8169, -32, 1073749994, -448, 8171, -448, 8172, -28, 1073750008, -512, 8185, -512, 1073750010, -504, 8187, -504, 8188, -36, 8486, -30068, 8490, -33532, 8491, -33048, 8498, 112, 1073750368, 64, 8559, 64, 8579, 4, 1073751222, 104, 9423, 104, 1073753088, 192, 11310, 192, 11360, 4, 11362, -42972, 11363, -15256, 11364, -42908, 11367, 4, 11369, 4, 11371, 4, 11381, 4, 11392, 4, 11394, 4, 11396, 4, 11398, 4, 11400, 4, 11402, 4, 11404, 4, 11406, 4, 11408, 4, 11410, 4, 11412, 4, 11414, 4, 11416, 4, 11418, 4, 11420, 4, 11422, 4, 11424, 4, 11426, 4, 11428, 4, 11430, 4, 11432, 4, 11434, 4, 11436, 4, 11438, 4, 11440, 4, 11442, 4, 11444, 4, 11446, 4, 11448, 4, 11450, 4, 11452, 4, 11454, 4, 11456, 4, 11458, 4, 11460, 4, 11462, 4, 11464, 4, 11466, 4, 11468, 4, 11470, 4, 11472, 4, 11474, 4, 11476, 4, 11478, 4, 11480, 4, 11482, 4, 11484, 4, 11486, 4, 11488, 4, 11490, 4 }; // NOLINT
+static const MultiCharacterSpecialCase<3> kToLowercaseMultiStrings1[] = { {0, {0}} }; // NOLINT
static const uint16_t kToLowercaseTable1Size = 2;
-static const uint16_t kToLowercaseTable1[4] = { 65313, 128, 32570, 128 }; // NOLINT
-static const MultiCharacterSpecialCase kToLowercaseMultiStrings2[] = { {0, {0}} }; // NOLINT
+static const int32_t kToLowercaseTable1[4] = { 1073774369, 128, 32570, 128 }; // NOLINT
+static const MultiCharacterSpecialCase<3> kToLowercaseMultiStrings2[] = { {0, {0}} }; // NOLINT
static const uint16_t kToLowercaseTable2Size = 2;
-static const uint16_t kToLowercaseTable2[4] = { 33792, 160, 1063, 160 }; // NOLINT
+static const int32_t kToLowercaseTable2[4] = { 1073742848, 160, 1063, 160 }; // NOLINT
int ToLowercase::Convert(uchar c,
uchar n,
uchar* result,
@@ -766,15 +594,15 @@
}
}
-static const MultiCharacterSpecialCase kToUppercaseMultiStrings0[] = { {2, {83, 83}}, {2, {700, 78}}, {2, {74, 780}}, {3, {921, 776, 769}}, {3, {933, 776, 769}}, {2, {1333, 1362}}, {2, {72, 817}}, {2, {84, 776}}, {2, {87, 778}}, {2, {89, 778}}, {2, {65, 702}}, {2, {933, 787}}, {3, {933, 787, 768}}, {3, {933, 787, 769}}, {3, {933, 787, 834}}, {2, {7944, 921}}, {2, {7945, 921}}, {2, {7946, 921}}, {2, {7947, 921}}, {2, {7948, 921}}, {2, {7949, 921}}, {2, {7950, 921}}, {2, {7951, 921}}, {2, {7944, 921}}, {2, {7945, 921}}, {2, {7946, 921}}, {2, {7947, 921}}, {2, {7948, 921}}, {2, {7949, 921}}, {2, {7950, 921}}, {2, {7951, 921}}, {2, {7976, 921}}, {2, {7977, 921}}, {2, {7978, 921}}, {2, {7979, 921}}, {2, {7980, 921}}, {2, {7981, 921}}, {2, {7982, 921}}, {2, {7983, 921}}, {2, {7976, 921}}, {2, {7977, 921}}, {2, {7978, 921}}, {2, {7979, 921}}, {2, {7980, 921}}, {2, {7981, 921}}, {2, {7982, 921}}, {2, {7983, 921}}, {2, {8040, 921}}, {2, {8041, 921}}, {2, {8042, 921}}, {2, {8043, 921}}, {2, {8044, 921}}, {2, {8045, 921}}, {2, {8046, 921}}, {2, {8047, 921}}, {2, {8040, 921}}, {2, {8041, 921}}, {2, {8042, 921}}, {2, {8043, 921}}, {2, {8044, 921}}, {2, {8045, 921}}, {2, {8046, 921}}, {2, {8047, 921}}, {2, {8122, 921}}, {2, {913, 921}}, {2, {902, 921}}, {2, {913, 834}}, {3, {913, 834, 921}}, {2, {913, 921}}, {2, {8138, 921}}, {2, {919, 921}}, {2, {905, 921}}, {2, {919, 834}}, {3, {919, 834, 921}}, {2, {919, 921}}, {3, {921, 776, 768}}, {3, {921, 776, 769}}, {2, {921, 834}}, {3, {921, 776, 834}}, {3, {933, 776, 768}}, {3, {933, 776, 769}}, {2, {929, 787}}, {2, {933, 834}}, {3, {933, 776, 834}}, {2, {8186, 921}}, {2, {937, 921}}, {2, {911, 921}}, {2, {937, 834}}, {3, {937, 834, 921}}, {2, {937, 921}}, {0, {0}} }; // NOLINT
+static const MultiCharacterSpecialCase<3> kToUppercaseMultiStrings0[] = { {2, {83, 83}}, {2, {700, 78}}, {2, {74, 780}}, {3, {921, 776, 769}}, {3, {933, 776, 769}}, {2, {1333, 1362}}, {2, {72, 817}}, {2, {84, 776}}, {2, {87, 778}}, {2, {89, 778}}, {2, {65, 702}}, {2, {933, 787}}, {3, {933, 787, 768}}, {3, {933, 787, 769}}, {3, {933, 787, 834}}, {2, {7944, 921}}, {2, {7945, 921}}, {2, {7946, 921}}, {2, {7947, 921}}, {2, {7948, 921}}, {2, {7949, 921}}, {2, {7950, 921}}, {2, {7951, 921}}, {2, {7944, 921}}, {2, {7945, 921}}, {2, {7946, 921}}, {2, {7947, 921}}, {2, {7948, 921}}, {2, {7949, 921}}, {2, {7950, 921}}, {2, {7951, 921}}, {2, {7976, 921}}, {2, {7977, 921}}, {2, {7978, 921}}, {2, {7979, 921}}, {2, {7980, 921}}, {2, {7981, 921}}, {2, {7982, 921}}, {2, {7983, 921}}, {2, {7976, 921}}, {2, {7977, 921}}, {2, {7978, 921}}, {2, {7979, 921}}, {2, {7980, 921}}, {2, {7981, 921}}, {2, {7982, 921}}, {2, {7983, 921}}, {2, {8040, 921}}, {2, {8041, 921}}, {2, {8042, 921}}, {2, {8043, 921}}, {2, {8044, 921}}, {2, {8045, 921}}, {2, {8046, 921}}, {2, {8047, 921}}, {2, {8040, 921}}, {2, {8041, 921}}, {2, {8042, 921}}, {2, {8043, 921}}, {2, {8044, 921}}, {2, {8045, 921}}, {2, {8046, 921}}, {2, {8047, 921}}, {2, {8122, 921}}, {2, {913, 921}}, {2, {902, 921}}, {2, {913, 834}}, {3, {913, 834, 921}}, {2, {913, 921}}, {2, {8138, 921}}, {2, {919, 921}}, {2, {905, 921}}, {2, {919, 834}}, {3, {919, 834, 921}}, {2, {919, 921}}, {3, {921, 776, 768}}, {3, {921, 776, 769}}, {2, {921, 834}}, {3, {921, 776, 834}}, {3, {933, 776, 768}}, {3, {933, 776, 769}}, {2, {929, 787}}, {2, {933, 834}}, {3, {933, 776, 834}}, {2, {8186, 921}}, {2, {937, 921}}, {2, {911, 921}}, {2, {937, 834}}, {3, {937, 834, 921}}, {2, {937, 921}}, {0, {0}} }; // NOLINT
static const uint16_t kToUppercaseTable0Size = 621;
-static const uint16_t kToUppercaseTable0[1242] = { 32865, static_cast<uint16_t>(-128), 122, static_cast<uint16_t>(-128), 181, 2972, 223, 1, 32992, static_cast<uint16_t>(-128), 246, static_cast<uint16_t>(-128), 33016, static_cast<uint16_t>(-128), 254, static_cast<uint16_t>(-128), 255, 484, 257, static_cast<uint16_t>(-4), 259, static_cast<uint16_t>(-4), 261, static_cast<uint16_t>(-4), 263, static_cast<uint16_t>(-4), 265, static_cast<uint16_t>(-4), 267, static_cast<uint16_t>(-4), 269, static_cast<uint16_t>(-4), 271, static_cast<uint16_t>(-4), 273, static_cast<uint16_t>(-4), 275, static_cast<uint16_t>(-4), 277, static_cast<uint16_t>(-4), 279, static_cast<uint16_t>(-4), 281, static_cast<uint16_t>(-4), 283, static_cast<uint16_t>(-4), 285, static_cast<uint16_t>(-4), 287, static_cast<uint16_t>(-4), 289, static_cast<uint16_t>(-4), 291, static_cast<uint16_t>(-4), 293, static_cast<uint16_t>(-4), 295, static_cast<uint16_t>(-4), 297, static_cast<uint16_t>(-4), 299, static_cast<uint16_t>(-4), 301, static_cast<uint16_t>(-4), 303, static_cast<uint16_t>(-4), 305, static_cast<uint16_t>(-928), 307, static_cast<uint16_t>(-4), 309, static_cast<uint16_t>(-4), 311, static_cast<uint16_t>(-4), 314, static_cast<uint16_t>(-4), 316, static_cast<uint16_t>(-4), 318, static_cast<uint16_t>(-4), 320, static_cast<uint16_t>(-4), 322, static_cast<uint16_t>(-4), 324, static_cast<uint16_t>(-4), 326, static_cast<uint16_t>(-4), 328, static_cast<uint16_t>(-4), 329, 5, 331, static_cast<uint16_t>(-4), 333, static_cast<uint16_t>(-4), 335, static_cast<uint16_t>(-4), 337, static_cast<uint16_t>(-4), 339, static_cast<uint16_t>(-4), 341, static_cast<uint16_t>(-4), 343, static_cast<uint16_t>(-4), 345, static_cast<uint16_t>(-4), 347, static_cast<uint16_t>(-4), 349, static_cast<uint16_t>(-4), 351, static_cast<uint16_t>(-4), 353, static_cast<uint16_t>(-4), 355, static_cast<uint16_t>(-4), 357, static_cast<uint16_t>(-4), 359, static_cast<uint16_t>(-4), 361, static_cast<uint16_t>(-4), 363, static_cast<uint16_t>(-4), 365, static_cast<uint16_t>(-4), 367, static_cast<uint16_t>(-4), 369, static_cast<uint16_t>(-4), 371, static_cast<uint16_t>(-4), 373, static_cast<uint16_t>(-4), 375, static_cast<uint16_t>(-4), 378, static_cast<uint16_t>(-4), 380, static_cast<uint16_t>(-4), 382, static_cast<uint16_t>(-4), 383, static_cast<uint16_t>(-1200), 384, 780, 387, static_cast<uint16_t>(-4), 389, static_cast<uint16_t>(-4), 392, static_cast<uint16_t>(-4), 396, static_cast<uint16_t>(-4), 402, static_cast<uint16_t>(-4), 405, 388, 409, static_cast<uint16_t>(-4), 410, 652, 414, 520, 417, static_cast<uint16_t>(-4), 419, static_cast<uint16_t>(-4), 421, static_cast<uint16_t>(-4), 424, static_cast<uint16_t>(-4), 429, static_cast<uint16_t>(-4), 432, static_cast<uint16_t>(-4), 436, static_cast<uint16_t>(-4), 438, static_cast<uint16_t>(-4), 441, static_cast<uint16_t>(-4), 445, static_cast<uint16_t>(-4), 447, 224, 453, static_cast<uint16_t>(-4), 454, static_cast<uint16_t>(-8), 456, static_cast<uint16_t>(-4), 457, static_cast<uint16_t>(-8), 459, static_cast<uint16_t>(-4), 460, static_cast<uint16_t>(-8), 462, static_cast<uint16_t>(-4), 464, static_cast<uint16_t>(-4), 466, static_cast<uint16_t>(-4), 468, static_cast<uint16_t>(-4), 470, static_cast<uint16_t>(-4), 472, static_cast<uint16_t>(-4), 474, static_cast<uint16_t>(-4), 476, static_cast<uint16_t>(-4), 477, static_cast<uint16_t>(-316), 479, static_cast<uint16_t>(-4), 481, static_cast<uint16_t>(-4), 483, static_cast<uint16_t>(-4), 485, static_cast<uint16_t>(-4), 487, static_cast<uint16_t>(-4), 489, static_cast<uint16_t>(-4), 491, static_cast<uint16_t>(-4), 493, static_cast<uint16_t>(-4), 495, static_cast<uint16_t>(-4), 496, 9, 498, static_cast<uint16_t>(-4), 499, static_cast<uint16_t>(-8), 501, static_cast<uint16_t>(-4), 505, static_cast<uint16_t>(-4), 507, static_cast<uint16_t>(-4), 509, static_cast<uint16_t>(-4), 511, static_cast<uint16_t>(-4), 513, static_cast<uint16_t>(-4), 515, static_cast<uint16_t>(-4), 517, static_cast<uint16_t>(-4), 519, static_cast<uint16_t>(-4), 521, static_cast<uint16_t>(-4), 523, static_cast<uint16_t>(-4), 525, static_cast<uint16_t>(-4), 527, static_cast<uint16_t>(-4), 529, static_cast<uint16_t>(-4), 531, static_cast<uint16_t>(-4), 533, static_cast<uint16_t>(-4), 535, static_cast<uint16_t>(-4), 537, static_cast<uint16_t>(-4), 539, static_cast<uint16_t>(-4), 541, static_cast<uint16_t>(-4), 543, static_cast<uint16_t>(-4), 547, static_cast<uint16_t>(-4), 549, static_cast<uint16_t>(-4), 551, static_cast<uint16_t>(-4), 553, static_cast<uint16_t>(-4), 555, static_cast<uint16_t>(-4), 557, static_cast<uint16_t>(-4), 559, static_cast<uint16_t>(-4), 561, static_cast<uint16_t>(-4), 563, static_cast<uint16_t>(-4), 572, static_cast<uint16_t>(-4), 578, static_cast<uint16_t>(-4), 583, static_cast<uint16_t>(-4), 585, static_cast<uint16_t>(-4), 587, static_cast<uint16_t>(-4), 589, static_cast<uint16_t>(-4), 591, static_cast<uint16_t>(-4), 595, static_cast<uint16_t>(-840), 596, static_cast<uint16_t>(-824), 33366, static_cast<uint16_t>(-820), 599, static_cast<uint16_t>(-820), 601, static_cast<uint16_t>(-808), 603, static_cast<uint16_t>(-812), 608, static_cast<uint16_t>(-820), 611, static_cast<uint16_t>(-828), 616, static_cast<uint16_t>(-836), 617, static_cast<uint16_t>(-844), 619, 42972, 623, static_cast<uint16_t>(-844), 626, static_cast<uint16_t>(-852), 629, static_cast<uint16_t>(-856), 637, 42908, 640, static_cast<uint16_t>(-872), 643, static_cast<uint16_t>(-872), 648, static_cast<uint16_t>(-872), 649, static_cast<uint16_t>(-276), 33418, static_cast<uint16_t>(-868), 651, static_cast<uint16_t>(-868), 652, static_cast<uint16_t>(-284), 658, static_cast<uint16_t>(-876), 837, 336, 33659, 520, 893, 520, 912, 13, 940, static_cast<uint16_t>(-152), 33709, static_cast<uint16_t>(-148), 943, static_cast<uint16_t>(-148), 944, 17, 33713, static_cast<uint16_t>(-128), 961, static_cast<uint16_t>(-128), 962, static_cast<uint16_t>(-124), 33731, static_cast<uint16_t>(-128), 971, static_cast<uint16_t>(-128), 972, static_cast<uint16_t>(-256), 33741, static_cast<uint16_t>(-252), 974, static_cast<uint16_t>(-252), 976, static_cast<uint16_t>(-248), 977, static_cast<uint16_t>(-228), 981, static_cast<uint16_t>(-188), 982, static_cast<uint16_t>(-216), 985, static_cast<uint16_t>(-4), 987, static_cast<uint16_t>(-4), 989, static_cast<uint16_t>(-4), 991, static_cast<uint16_t>(-4), 993, static_cast<uint16_t>(-4), 995, static_cast<uint16_t>(-4), 997, static_cast<uint16_t>(-4), 999, static_cast<uint16_t>(-4), 1001, static_cast<uint16_t>(-4), 1003, static_cast<uint16_t>(-4), 1005, static_cast<uint16_t>(-4), 1007, static_cast<uint16_t>(-4), 1008, static_cast<uint16_t>(-344), 1009, static_cast<uint16_t>(-320), 1010, 28, 1013, static_cast<uint16_t>(-384), 1016, static_cast<uint16_t>(-4), 1019, static_cast<uint16_t>(-4), 33840, static_cast<uint16_t>(-128), 1103, static_cast<uint16_t>(-128), 33872, static_cast<uint16_t>(-320), 1119, static_cast<uint16_t>(-320), 1121, static_cast<uint16_t>(-4), 1123, static_cast<uint16_t>(-4), 1125, static_cast<uint16_t>(-4), 1127, static_cast<uint16_t>(-4), 1129, static_cast<uint16_t>(-4), 1131, static_cast<uint16_t>(-4), 1133, static_cast<uint16_t>(-4), 1135, static_cast<uint16_t>(-4), 1137, static_cast<uint16_t>(-4), 1139, static_cast<uint16_t>(-4), 1141, static_cast<uint16_t>(-4), 1143, static_cast<uint16_t>(-4), 1145, static_cast<uint16_t>(-4), 1147, static_cast<uint16_t>(-4), 1149, static_cast<uint16_t>(-4), 1151, static_cast<uint16_t>(-4), 1153, static_cast<uint16_t>(-4), 1163, static_cast<uint16_t>(-4), 1165, static_cast<uint16_t>(-4), 1167, static_cast<uint16_t>(-4), 1169, static_cast<uint16_t>(-4), 1171, static_cast<uint16_t>(-4), 1173, static_cast<uint16_t>(-4), 1175, static_cast<uint16_t>(-4), 1177, static_cast<uint16_t>(-4), 1179, static_cast<uint16_t>(-4), 1181, static_cast<uint16_t>(-4), 1183, static_cast<uint16_t>(-4), 1185, static_cast<uint16_t>(-4), 1187, static_cast<uint16_t>(-4), 1189, static_cast<uint16_t>(-4), 1191, static_cast<uint16_t>(-4), 1193, static_cast<uint16_t>(-4), 1195, static_cast<uint16_t>(-4), 1197, static_cast<uint16_t>(-4), 1199, static_cast<uint16_t>(-4), 1201, static_cast<uint16_t>(-4), 1203, static_cast<uint16_t>(-4), 1205, static_cast<uint16_t>(-4), 1207, static_cast<uint16_t>(-4), 1209, static_cast<uint16_t>(-4), 1211, static_cast<uint16_t>(-4), 1213, static_cast<uint16_t>(-4), 1215, static_cast<uint16_t>(-4), 1218, static_cast<uint16_t>(-4), 1220, static_cast<uint16_t>(-4), 1222, static_cast<uint16_t>(-4), 1224, static_cast<uint16_t>(-4), 1226, static_cast<uint16_t>(-4), 1228, static_cast<uint16_t>(-4), 1230, static_cast<uint16_t>(-4), 1231, static_cast<uint16_t>(-60), 1233, static_cast<uint16_t>(-4), 1235, static_cast<uint16_t>(-4), 1237, static_cast<uint16_t>(-4), 1239, static_cast<uint16_t>(-4), 1241, static_cast<uint16_t>(-4), 1243, static_cast<uint16_t>(-4), 1245, static_cast<uint16_t>(-4), 1247, static_cast<uint16_t>(-4), 1249, static_cast<uint16_t>(-4), 1251, static_cast<uint16_t>(-4), 1253, static_cast<uint16_t>(-4), 1255, static_cast<uint16_t>(-4), 1257, static_cast<uint16_t>(-4), 1259, static_cast<uint16_t>(-4), 1261, static_cast<uint16_t>(-4), 1263, static_cast<uint16_t>(-4), 1265, static_cast<uint16_t>(-4), 1267, static_cast<uint16_t>(-4), 1269, static_cast<uint16_t>(-4), 1271, static_cast<uint16_t>(-4), 1273, static_cast<uint16_t>(-4), 1275, static_cast<uint16_t>(-4), 1277, static_cast<uint16_t>(-4), 1279, static_cast<uint16_t>(-4), 1281, static_cast<uint16_t>(-4), 1283, static_cast<uint16_t>(-4), 1285, static_cast<uint16_t>(-4), 1287, static_cast<uint16_t>(-4), 1289, static_cast<uint16_t>(-4), 1291, static_cast<uint16_t>(-4), 1293, static_cast<uint16_t>(-4), 1295, static_cast<uint16_t>(-4), 1297, static_cast<uint16_t>(-4), 1299, static_cast<uint16_t>(-4), 34145, static_cast<uint16_t>(-192), 1414, static_cast<uint16_t>(-192), 1415, 21, 7549, 15256, 7681, static_cast<uint16_t>(-4), 7683, static_cast<uint16_t>(-4), 7685, static_cast<uint16_t>(-4), 7687, static_cast<uint16_t>(-4), 7689, static_cast<uint16_t>(-4), 7691, static_cast<uint16_t>(-4), 7693, static_cast<uint16_t>(-4), 7695, static_cast<uint16_t>(-4), 7697, static_cast<uint16_t>(-4), 7699, static_cast<uint16_t>(-4), 7701, static_cast<uint16_t>(-4), 7703, static_cast<uint16_t>(-4), 7705, static_cast<uint16_t>(-4), 7707, static_cast<uint16_t>(-4), 7709, static_cast<uint16_t>(-4), 7711, static_cast<uint16_t>(-4), 7713, static_cast<uint16_t>(-4), 7715, static_cast<uint16_t>(-4), 7717, static_cast<uint16_t>(-4), 7719, static_cast<uint16_t>(-4), 7721, static_cast<uint16_t>(-4), 7723, static_cast<uint16_t>(-4), 7725, static_cast<uint16_t>(-4), 7727, static_cast<uint16_t>(-4), 7729, static_cast<uint16_t>(-4), 7731, static_cast<uint16_t>(-4), 7733, static_cast<uint16_t>(-4), 7735, static_cast<uint16_t>(-4), 7737, static_cast<uint16_t>(-4), 7739, static_cast<uint16_t>(-4), 7741, static_cast<uint16_t>(-4), 7743, static_cast<uint16_t>(-4), 7745, static_cast<uint16_t>(-4), 7747, static_cast<uint16_t>(-4), 7749, static_cast<uint16_t>(-4), 7751, static_cast<uint16_t>(-4), 7753, static_cast<uint16_t>(-4), 7755, static_cast<uint16_t>(-4), 7757, static_cast<uint16_t>(-4), 7759, static_cast<uint16_t>(-4), 7761, static_cast<uint16_t>(-4), 7763, static_cast<uint16_t>(-4), 7765, static_cast<uint16_t>(-4), 7767, static_cast<uint16_t>(-4), 7769, static_cast<uint16_t>(-4), 7771, static_cast<uint16_t>(-4), 7773, static_cast<uint16_t>(-4), 7775, static_cast<uint16_t>(-4), 7777, static_cast<uint16_t>(-4), 7779, static_cast<uint16_t>(-4), 7781, static_cast<uint16_t>(-4), 7783, static_cast<uint16_t>(-4), 7785, static_cast<uint16_t>(-4), 7787, static_cast<uint16_t>(-4), 7789, static_cast<uint16_t>(-4), 7791, static_cast<uint16_t>(-4), 7793, static_cast<uint16_t>(-4), 7795, static_cast<uint16_t>(-4), 7797, static_cast<uint16_t>(-4), 7799, static_cast<uint16_t>(-4), 7801, static_cast<uint16_t>(-4), 7803, static_cast<uint16_t>(-4), 7805, static_cast<uint16_t>(-4), 7807, static_cast<uint16_t>(-4), 7809, static_cast<uint16_t>(-4), 7811, static_cast<uint16_t>(-4), 7813, static_cast<uint16_t>(-4), 7815, static_cast<uint16_t>(-4), 7817, static_cast<uint16_t>(-4), 7819, static_cast<uint16_t>(-4), 7821, static_cast<uint16_t>(-4), 7823, static_cast<uint16_t>(-4), 7825, static_cast<uint16_t>(-4), 7827, static_cast<uint16_t>(-4), 7829, static_cast<uint16_t>(-4), 7830, 25, 7831, 29, 7832, 33, 7833, 37, 7834, 41, 7835, static_cast<uint16_t>(-236), 7841, static_cast<uint16_t>(-4), 7843, static_cast<uint16_t>(-4), 7845, static_cast<uint16_t>(-4), 7847, static_cast<uint16_t>(-4), 7849, static_cast<uint16_t>(-4), 7851, static_cast<uint16_t>(-4), 7853, static_cast<uint16_t>(-4), 7855, static_cast<uint16_t>(-4), 7857, static_cast<uint16_t>(-4), 7859, static_cast<uint16_t>(-4), 7861, static_cast<uint16_t>(-4), 7863, static_cast<uint16_t>(-4), 7865, static_cast<uint16_t>(-4), 7867, static_cast<uint16_t>(-4), 7869, static_cast<uint16_t>(-4), 7871, static_cast<uint16_t>(-4), 7873, static_cast<uint16_t>(-4), 7875, static_cast<uint16_t>(-4), 7877, static_cast<uint16_t>(-4), 7879, static_cast<uint16_t>(-4), 7881, static_cast<uint16_t>(-4), 7883, static_cast<uint16_t>(-4), 7885, static_cast<uint16_t>(-4), 7887, static_cast<uint16_t>(-4), 7889, static_cast<uint16_t>(-4), 7891, static_cast<uint16_t>(-4), 7893, static_cast<uint16_t>(-4), 7895, static_cast<uint16_t>(-4), 7897, static_cast<uint16_t>(-4), 7899, static_cast<uint16_t>(-4), 7901, static_cast<uint16_t>(-4), 7903, static_cast<uint16_t>(-4), 7905, static_cast<uint16_t>(-4), 7907, static_cast<uint16_t>(-4), 7909, static_cast<uint16_t>(-4), 7911, static_cast<uint16_t>(-4), 7913, static_cast<uint16_t>(-4), 7915, static_cast<uint16_t>(-4), 7917, static_cast<uint16_t>(-4), 7919, static_cast<uint16_t>(-4), 7921, static_cast<uint16_t>(-4), 7923, static_cast<uint16_t>(-4), 7925, static_cast<uint16_t>(-4), 7927, static_cast<uint16_t>(-4), 7929, static_cast<uint16_t>(-4), 40704, 32, 7943, 32, 40720, 32, 7957, 32, 40736, 32, 7975, 32, 40752, 32, 7991, 32, 40768, 32, 8005, 32, 8016, 45, 8017, 32, 8018, 49, 8019, 32, 8020, 53, 8021, 32, 8022, 57, 8023, 32, 40800, 32, 8039, 32, 40816, 296, 8049, 296, 40818, 344, 8053, 344, 40822, 400, 8055, 400, 40824, 512, 8057, 512, 40826, 448, 8059, 448, 40828, 504, 8061, 504, 8064, 61, 8065, 65, 8066, 69, 8067, 73, 8068, 77, 8069, 81, 8070, 85, 8071, 89, 8072, 93, 8073, 97, 8074, 101, 8075, 105, 8076, 109, 8077, 113, 8078, 117, 8079, 121, 8080, 125, 8081, 129, 8082, 133, 8083, 137, 8084, 141, 8085, 145, 8086, 149, 8087, 153, 8088, 157, 8089, 161, 8090, 165, 8091, 169, 8092, 173, 8093, 177, 8094, 181, 8095, 185, 8096, 189, 8097, 193, 8098, 197, 8099, 201, 8100, 205, 8101, 209, 8102, 213, 8103, 217, 8104, 221, 8105, 225, 8106, 229, 8107, 233, 8108, 237, 8109, 241, 8110, 245, 8111, 249, 40880, 32, 8113, 32, 8114, 253, 8115, 257, 8116, 261, 8118, 265, 8119, 269, 8124, 273, 8126, static_cast<uint16_t>(-28820), 8130, 277, 8131, 281, 8132, 285, 8134, 289, 8135, 293, 8140, 297, 40912, 32, 8145, 32, 8146, 301, 8147, 305, 8150, 309, 8151, 313, 40928, 32, 8161, 32, 8162, 317, 8163, 321, 8164, 325, 8165, 28, 8166, 329, 8167, 333, 8178, 337, 8179, 341, 8180, 345, 8182, 349, 8183, 353, 8188, 357, 8526, static_cast<uint16_t>(-112), 41328, static_cast<uint16_t>(-64), 8575, static_cast<uint16_t>(-64), 8580, static_cast<uint16_t>(-4), 42192, static_cast<uint16_t>(-104), 9449, static_cast<uint16_t>(-104), 44080, static_cast<uint16_t>(-192), 11358, static_cast<uint16_t>(-192), 11361, static_cast<uint16_t>(-4), 11365, static_cast<uint16_t>(-43180), 11366, static_cast<uint16_t>(-43168), 11368, static_cast<uint16_t>(-4), 11370, static_cast<uint16_t>(-4), 11372, static_cast<uint16_t>(-4), 11382, static_cast<uint16_t>(-4), 11393, static_cast<uint16_t>(-4), 11395, static_cast<uint16_t>(-4), 11397, static_cast<uint16_t>(-4), 11399, static_cast<uint16_t>(-4), 11401, static_cast<uint16_t>(-4), 11403, static_cast<uint16_t>(-4), 11405, static_cast<uint16_t>(-4), 11407, static_cast<uint16_t>(-4), 11409, static_cast<uint16_t>(-4), 11411, static_cast<uint16_t>(-4), 11413, static_cast<uint16_t>(-4), 11415, static_cast<uint16_t>(-4), 11417, static_cast<uint16_t>(-4), 11419, static_cast<uint16_t>(-4), 11421, static_cast<uint16_t>(-4), 11423, static_cast<uint16_t>(-4), 11425, static_cast<uint16_t>(-4), 11427, static_cast<uint16_t>(-4), 11429, static_cast<uint16_t>(-4), 11431, static_cast<uint16_t>(-4), 11433, static_cast<uint16_t>(-4), 11435, static_cast<uint16_t>(-4), 11437, static_cast<uint16_t>(-4), 11439, static_cast<uint16_t>(-4), 11441, static_cast<uint16_t>(-4), 11443, static_cast<uint16_t>(-4), 11445, static_cast<uint16_t>(-4), 11447, static_cast<uint16_t>(-4), 11449, static_cast<uint16_t>(-4), 11451, static_cast<uint16_t>(-4), 11453, static_cast<uint16_t>(-4), 11455, static_cast<uint16_t>(-4), 11457, static_cast<uint16_t>(-4), 11459, static_cast<uint16_t>(-4), 11461, static_cast<uint16_t>(-4), 11463, static_cast<uint16_t>(-4), 11465, static_cast<uint16_t>(-4), 11467, static_cast<uint16_t>(-4), 11469, static_cast<uint16_t>(-4), 11471, static_cast<uint16_t>(-4), 11473, static_cast<uint16_t>(-4), 11475, static_cast<uint16_t>(-4), 11477, static_cast<uint16_t>(-4), 11479, static_cast<uint16_t>(-4), 11481, static_cast<uint16_t>(-4), 11483, static_cast<uint16_t>(-4), 11485, static_cast<uint16_t>(-4), 11487, static_cast<uint16_t>(-4), 11489, static_cast<uint16_t>(-4), 11491, static_cast<uint16_t>(-4), 44288, static_cast<uint16_t>(-29056), 11557, static_cast<uint16_t>(-29056) }; // NOLINT
-static const MultiCharacterSpecialCase kToUppercaseMultiStrings1[] = { {2, {70, 70}}, {2, {70, 73}}, {2, {70, 76}}, {3, {70, 70, 73}}, {3, {70, 70, 76}}, {2, {83, 84}}, {2, {83, 84}}, {2, {1348, 1350}}, {2, {1348, 1333}}, {2, {1348, 1339}}, {2, {1358, 1350}}, {2, {1348, 1341}}, {0, {0}} }; // NOLINT
+static const int32_t kToUppercaseTable0[1242] = { 1073741921, -128, 122, -128, 181, 2972, 223, 1, 1073742048, -128, 246, -128, 1073742072, -128, 254, -128, 255, 484, 257, -4, 259, -4, 261, -4, 263, -4, 265, -4, 267, -4, 269, -4, 271, -4, 273, -4, 275, -4, 277, -4, 279, -4, 281, -4, 283, -4, 285, -4, 287, -4, 289, -4, 291, -4, 293, -4, 295, -4, 297, -4, 299, -4, 301, -4, 303, -4, 305, -928, 307, -4, 309, -4, 311, -4, 314, -4, 316, -4, 318, -4, 320, -4, 322, -4, 324, -4, 326, -4, 328, -4, 329, 5, 331, -4, 333, -4, 335, -4, 337, -4, 339, -4, 341, -4, 343, -4, 345, -4, 347, -4, 349, -4, 351, -4, 353, -4, 355, -4, 357, -4, 359, -4, 361, -4, 363, -4, 365, -4, 367, -4, 369, -4, 371, -4, 373, -4, 375, -4, 378, -4, 380, -4, 382, -4, 383, -1200, 384, 780, 387, -4, 389, -4, 392, -4, 396, -4, 402, -4, 405, 388, 409, -4, 410, 652, 414, 520, 417, -4, 419, -4, 421, -4, 424, -4, 429, -4, 432, -4, 436, -4, 438, -4, 441, -4, 445, -4, 447, 224, 453, -4, 454, -8, 456, -4, 457, -8, 459, -4, 460, -8, 462, -4, 464, -4, 466, -4, 468, -4, 470, -4, 472, -4, 474, -4, 476, -4, 477, -316, 479, -4, 481, -4, 483, -4, 485, -4, 487, -4, 489, -4, 491, -4, 493, -4, 495, -4, 496, 9, 498, -4, 499, -8, 501, -4, 505, -4, 507, -4, 509, -4, 511, -4, 513, -4, 515, -4, 517, -4, 519, -4, 521, -4, 523, -4, 525, -4, 527, -4, 529, -4, 531, -4, 533, -4, 535, -4, 537, -4, 539, -4, 541, -4, 543, -4, 547, -4, 549, -4, 551, -4, 553, -4, 555, -4, 557, -4, 559, -4, 561, -4, 563, -4, 572, -4, 578, -4, 583, -4, 585, -4, 587, -4, 589, -4, 591, -4, 595, -840, 596, -824, 1073742422, -820, 599, -820, 601, -808, 603, -812, 608, -820, 611, -828, 616, -836, 617, -844, 619, 42972, 623, -844, 626, -852, 629, -856, 637, 42908, 640, -872, 643, -872, 648, -872, 649, -276, 1073742474, -868, 651, -868, 652, -284, 658, -876, 837, 336, 1073742715, 520, 893, 520, 912, 13, 940, -152, 1073742765, -148, 943, -148, 944, 17, 1073742769, -128, 961, -128, 962, -124, 1073742787, -128, 971, -128, 972, -256, 1073742797, -252, 974, -252, 976, -248, 977, -228, 981, -188, 982, -216, 985, -4, 987, -4, 989, -4, 991, -4, 993, -4, 995, -4, 997, -4, 999, -4, 1001, -4, 1003, -4, 1005, -4, 1007, -4, 1008, -344, 1009, -320, 1010, 28, 1013, -384, 1016, -4, 1019, -4, 1073742896, -128, 1103, -128, 1073742928, -320, 1119, -320, 1121, -4, 1123, -4, 1125, -4, 1127, -4, 1129, -4, 1131, -4, 1133, -4, 1135, -4, 1137, -4, 1139, -4, 1141, -4, 1143, -4, 1145, -4, 1147, -4, 1149, -4, 1151, -4, 1153, -4, 1163, -4, 1165, -4, 1167, -4, 1169, -4, 1171, -4, 1173, -4, 1175, -4, 1177, -4, 1179, -4, 1181, -4, 1183, -4, 1185, -4, 1187, -4, 1189, -4, 1191, -4, 1193, -4, 1195, -4, 1197, -4, 1199, -4, 1201, -4, 1203, -4, 1205, -4, 1207, -4, 1209, -4, 1211, -4, 1213, -4, 1215, -4, 1218, -4, 1220, -4, 1222, -4, 1224, -4, 1226, -4, 1228, -4, 1230, -4, 1231, -60, 1233, -4, 1235, -4, 1237, -4, 1239, -4, 1241, -4, 1243, -4, 1245, -4, 1247, -4, 1249, -4, 1251, -4, 1253, -4, 1255, -4, 1257, -4, 1259, -4, 1261, -4, 1263, -4, 1265, -4, 1267, -4, 1269, -4, 1271, -4, 1273, -4, 1275, -4, 1277, -4, 1279, -4, 1281, -4, 1283, -4, 1285, -4, 1287, -4, 1289, -4, 1291, -4, 1293, -4, 1295, -4, 1297, -4, 1299, -4, 1073743201, -192, 1414, -192, 1415, 21, 7549, 15256, 7681, -4, 7683, -4, 7685, -4, 7687, -4, 7689, -4, 7691, -4, 7693, -4, 7695, -4, 7697, -4, 7699, -4, 7701, -4, 7703, -4, 7705, -4, 7707, -4, 7709, -4, 7711, -4, 7713, -4, 7715, -4, 7717, -4, 7719, -4, 7721, -4, 7723, -4, 7725, -4, 7727, -4, 7729, -4, 7731, -4, 7733, -4, 7735, -4, 7737, -4, 7739, -4, 7741, -4, 7743, -4, 7745, -4, 7747, -4, 7749, -4, 7751, -4, 7753, -4, 7755, -4, 7757, -4, 7759, -4, 7761, -4, 7763, -4, 7765, -4, 7767, -4, 7769, -4, 7771, -4, 7773, -4, 7775, -4, 7777, -4, 7779, -4, 7781, -4, 7783, -4, 7785, -4, 7787, -4, 7789, -4, 7791, -4, 7793, -4, 7795, -4, 7797, -4, 7799, -4, 7801, -4, 7803, -4, 7805, -4, 7807, -4, 7809, -4, 7811, -4, 7813, -4, 7815, -4, 7817, -4, 7819, -4, 7821, -4, 7823, -4, 7825, -4, 7827, -4, 7829, -4, 7830, 25, 7831, 29, 7832, 33, 7833, 37, 7834, 41, 7835, -236, 7841, -4, 7843, -4, 7845, -4, 7847, -4, 7849, -4, 7851, -4, 7853, -4, 7855, -4, 7857, -4, 7859, -4, 7861, -4, 7863, -4, 7865, -4, 7867, -4, 7869, -4, 7871, -4, 7873, -4, 7875, -4, 7877, -4, 7879, -4, 7881, -4, 7883, -4, 7885, -4, 7887, -4, 7889, -4, 7891, -4, 7893, -4, 7895, -4, 7897, -4, 7899, -4, 7901, -4, 7903, -4, 7905, -4, 7907, -4, 7909, -4, 7911, -4, 7913, -4, 7915, -4, 7917, -4, 7919, -4, 7921, -4, 7923, -4, 7925, -4, 7927, -4, 7929, -4, 1073749760, 32, 7943, 32, 1073749776, 32, 7957, 32, 1073749792, 32, 7975, 32, 1073749808, 32, 7991, 32, 1073749824, 32, 8005, 32, 8016, 45, 8017, 32, 8018, 49, 8019, 32, 8020, 53, 8021, 32, 8022, 57, 8023, 32, 1073749856, 32, 8039, 32, 1073749872, 296, 8049, 296, 1073749874, 344, 8053, 344, 1073749878, 400, 8055, 400, 1073749880, 512, 8057, 512, 1073749882, 448, 8059, 448, 1073749884, 504, 8061, 504, 8064, 61, 8065, 65, 8066, 69, 8067, 73, 8068, 77, 8069, 81, 8070, 85, 8071, 89, 8072, 93, 8073, 97, 8074, 101, 8075, 105, 8076, 109, 8077, 113, 8078, 117, 8079, 121, 8080, 125, 8081, 129, 8082, 133, 8083, 137, 8084, 141, 8085, 145, 8086, 149, 8087, 153, 8088, 157, 8089, 161, 8090, 165, 8091, 169, 8092, 173, 8093, 177, 8094, 181, 8095, 185, 8096, 189, 8097, 193, 8098, 197, 8099, 201, 8100, 205, 8101, 209, 8102, 213, 8103, 217, 8104, 221, 8105, 225, 8106, 229, 8107, 233, 8108, 237, 8109, 241, 8110, 245, 8111, 249, 1073749936, 32, 8113, 32, 8114, 253, 8115, 257, 8116, 261, 8118, 265, 8119, 269, 8124, 273, 8126, -28820, 8130, 277, 8131, 281, 8132, 285, 8134, 289, 8135, 293, 8140, 297, 1073749968, 32, 8145, 32, 8146, 301, 8147, 305, 8150, 309, 8151, 313, 1073749984, 32, 8161, 32, 8162, 317, 8163, 321, 8164, 325, 8165, 28, 8166, 329, 8167, 333, 8178, 337, 8179, 341, 8180, 345, 8182, 349, 8183, 353, 8188, 357, 8526, -112, 1073750384, -64, 8575, -64, 8580, -4, 1073751248, -104, 9449, -104, 1073753136, -192, 11358, -192, 11361, -4, 11365, -43180, 11366, -43168, 11368, -4, 11370, -4, 11372, -4, 11382, -4, 11393, -4, 11395, -4, 11397, -4, 11399, -4, 11401, -4, 11403, -4, 11405, -4, 11407, -4, 11409, -4, 11411, -4, 11413, -4, 11415, -4, 11417, -4, 11419, -4, 11421, -4, 11423, -4, 11425, -4, 11427, -4, 11429, -4, 11431, -4, 11433, -4, 11435, -4, 11437, -4, 11439, -4, 11441, -4, 11443, -4, 11445, -4, 11447, -4, 11449, -4, 11451, -4, 11453, -4, 11455, -4, 11457, -4, 11459, -4, 11461, -4, 11463, -4, 11465, -4, 11467, -4, 11469, -4, 11471, -4, 11473, -4, 11475, -4, 11477, -4, 11479, -4, 11481, -4, 11483, -4, 11485, -4, 11487, -4, 11489, -4, 11491, -4, 1073753344, -29056, 11557, -29056 }; // NOLINT
+static const MultiCharacterSpecialCase<3> kToUppercaseMultiStrings1[] = { {2, {70, 70}}, {2, {70, 73}}, {2, {70, 76}}, {3, {70, 70, 73}}, {3, {70, 70, 76}}, {2, {83, 84}}, {2, {83, 84}}, {2, {1348, 1350}}, {2, {1348, 1333}}, {2, {1348, 1339}}, {2, {1358, 1350}}, {2, {1348, 1341}}, {0, {0}} }; // NOLINT
static const uint16_t kToUppercaseTable1Size = 14;
-static const uint16_t kToUppercaseTable1[28] = { 31488, 1, 31489, 5, 31490, 9, 31491, 13, 31492, 17, 31493, 21, 31494, 25, 31507, 29, 31508, 33, 31509, 37, 31510, 41, 31511, 45, 65345, static_cast<uint16_t>(-128), 32602, static_cast<uint16_t>(-128) }; // NOLINT
-static const MultiCharacterSpecialCase kToUppercaseMultiStrings2[] = { {0, {0}} }; // NOLINT
+static const int32_t kToUppercaseTable1[28] = { 31488, 1, 31489, 5, 31490, 9, 31491, 13, 31492, 17, 31493, 21, 31494, 25, 31507, 29, 31508, 33, 31509, 37, 31510, 41, 31511, 45, 1073774401, -128, 32602, -128 }; // NOLINT
+static const MultiCharacterSpecialCase<3> kToUppercaseMultiStrings2[] = { {0, {0}} }; // NOLINT
static const uint16_t kToUppercaseTable2Size = 2;
-static const uint16_t kToUppercaseTable2[4] = { 33832, static_cast<uint16_t>(-160), 1103, static_cast<uint16_t>(-160) }; // NOLINT
+static const int32_t kToUppercaseTable2[4] = { 1073742888, -160, 1103, -160 }; // NOLINT
int ToUppercase::Convert(uchar c,
uchar n,
uchar* result,
@@ -806,11 +634,121 @@
}
}
+static const MultiCharacterSpecialCase<1> kEcma262CanonicalizeMultiStrings0[] = { {0, {0}} }; // NOLINT
+static const uint16_t kEcma262CanonicalizeTable0Size = 529;
+static const int32_t kEcma262CanonicalizeTable0[1058] = { 1073741921, -128, 122, -128, 181, 2972, 1073742048, -128, 246, -128, 1073742072, -128, 254, -128, 255, 484, 257, -4, 259, -4, 261, -4, 263, -4, 265, -4, 267, -4, 269, -4, 271, -4, 273, -4, 275, -4, 277, -4, 279, -4, 281, -4, 283, -4, 285, -4, 287, -4, 289, -4, 291, -4, 293, -4, 295, -4, 297, -4, 299, -4, 301, -4, 303, -4, 307, -4, 309, -4, 311, -4, 314, -4, 316, -4, 318, -4, 320, -4, 322, -4, 324, -4, 326, -4, 328, -4, 331, -4, 333, -4, 335, -4, 337, -4, 339, -4, 341, -4, 343, -4, 345, -4, 347, -4, 349, -4, 351, -4, 353, -4, 355, -4, 357, -4, 359, -4, 361, -4, 363, -4, 365, -4, 367, -4, 369, -4, 371, -4, 373, -4, 375, -4, 378, -4, 380, -4, 382, -4, 384, 780, 387, -4, 389, -4, 392, -4, 396, -4, 402, -4, 405, 388, 409, -4, 410, 652, 414, 520, 417, -4, 419, -4, 421, -4, 424, -4, 429, -4, 432, -4, 436, -4, 438, -4, 441, -4, 445, -4, 447, 224, 453, -4, 454, -8, 456, -4, 457, -8, 459, -4, 460, -8, 462, -4, 464, -4, 466, -4, 468, -4, 470, -4, 472, -4, 474, -4, 476, -4, 477, -316, 479, -4, 481, -4, 483, -4, 485, -4, 487, -4, 489, -4, 491, -4, 493, -4, 495, -4, 498, -4, 499, -8, 501, -4, 505, -4, 507, -4, 509, -4, 511, -4, 513, -4, 515, -4, 517, -4, 519, -4, 521, -4, 523, -4, 525, -4, 527, -4, 529, -4, 531, -4, 533, -4, 535, -4, 537, -4, 539, -4, 541, -4, 543, -4, 547, -4, 549, -4, 551, -4, 553, -4, 555, -4, 557, -4, 559, -4, 561, -4, 563, -4, 572, -4, 578, -4, 583, -4, 585, -4, 587, -4, 589, -4, 591, -4, 595, -840, 596, -824, 1073742422, -820, 599, -820, 601, -808, 603, -812, 608, -820, 611, -828, 616, -836, 617, -844, 619, 42972, 623, -844, 626, -852, 629, -856, 637, 42908, 640, -872, 643, -872, 648, -872, 649, -276, 1073742474, -868, 651, -868, 652, -284, 658, -876, 837, 336, 1073742715, 520, 893, 520, 940, -152, 1073742765, -148, 943, -148, 1073742769, -128, 961, -128, 962, -124, 1073742787, -128, 971, -128, 972, -256, 1073742797, -252, 974, -252, 976, -248, 977, -228, 981, -188, 982, -216, 985, -4, 987, -4, 989, -4, 991, -4, 993, -4, 995, -4, 997, -4, 999, -4, 1001, -4, 1003, -4, 1005, -4, 1007, -4, 1008, -344, 1009, -320, 1010, 28, 1013, -384, 1016, -4, 1019, -4, 1073742896, -128, 1103, -128, 1073742928, -320, 1119, -320, 1121, -4, 1123, -4, 1125, -4, 1127, -4, 1129, -4, 1131, -4, 1133, -4, 1135, -4, 1137, -4, 1139, -4, 1141, -4, 1143, -4, 1145, -4, 1147, -4, 1149, -4, 1151, -4, 1153, -4, 1163, -4, 1165, -4, 1167, -4, 1169, -4, 1171, -4, 1173, -4, 1175, -4, 1177, -4, 1179, -4, 1181, -4, 1183, -4, 1185, -4, 1187, -4, 1189, -4, 1191, -4, 1193, -4, 1195, -4, 1197, -4, 1199, -4, 1201, -4, 1203, -4, 1205, -4, 1207, -4, 1209, -4, 1211, -4, 1213, -4, 1215, -4, 1218, -4, 1220, -4, 1222, -4, 1224, -4, 1226, -4, 1228, -4, 1230, -4, 1231, -60, 1233, -4, 1235, -4, 1237, -4, 1239, -4, 1241, -4, 1243, -4, 1245, -4, 1247, -4, 1249, -4, 1251, -4, 1253, -4, 1255, -4, 1257, -4, 1259, -4, 1261, -4, 1263, -4, 1265, -4, 1267, -4, 1269, -4, 1271, -4, 1273, -4, 1275, -4, 1277, -4, 1279, -4, 1281, -4, 1283, -4, 1285, -4, 1287, -4, 1289, -4, 1291, -4, 1293, -4, 1295, -4, 1297, -4, 1299, -4, 1073743201, -192, 1414, -192, 7549, 15256, 7681, -4, 7683, -4, 7685, -4, 7687, -4, 7689, -4, 7691, -4, 7693, -4, 7695, -4, 7697, -4, 7699, -4, 7701, -4, 7703, -4, 7705, -4, 7707, -4, 7709, -4, 7711, -4, 7713, -4, 7715, -4, 7717, -4, 7719, -4, 7721, -4, 7723, -4, 7725, -4, 7727, -4, 7729, -4, 7731, -4, 7733, -4, 7735, -4, 7737, -4, 7739, -4, 7741, -4, 7743, -4, 7745, -4, 7747, -4, 7749, -4, 7751, -4, 7753, -4, 7755, -4, 7757, -4, 7759, -4, 7761, -4, 7763, -4, 7765, -4, 7767, -4, 7769, -4, 7771, -4, 7773, -4, 7775, -4, 7777, -4, 7779, -4, 7781, -4, 7783, -4, 7785, -4, 7787, -4, 7789, -4, 7791, -4, 7793, -4, 7795, -4, 7797, -4, 7799, -4, 7801, -4, 7803, -4, 7805, -4, 7807, -4, 7809, -4, 7811, -4, 7813, -4, 7815, -4, 7817, -4, 7819, -4, 7821, -4, 7823, -4, 7825, -4, 7827, -4, 7829, -4, 7835, -236, 7841, -4, 7843, -4, 7845, -4, 7847, -4, 7849, -4, 7851, -4, 7853, -4, 7855, -4, 7857, -4, 7859, -4, 7861, -4, 7863, -4, 7865, -4, 7867, -4, 7869, -4, 7871, -4, 7873, -4, 7875, -4, 7877, -4, 7879, -4, 7881, -4, 7883, -4, 7885, -4, 7887, -4, 7889, -4, 7891, -4, 7893, -4, 7895, -4, 7897, -4, 7899, -4, 7901, -4, 7903, -4, 7905, -4, 7907, -4, 7909, -4, 7911, -4, 7913, -4, 7915, -4, 7917, -4, 7919, -4, 7921, -4, 7923, -4, 7925, -4, 7927, -4, 7929, -4, 1073749760, 32, 7943, 32, 1073749776, 32, 7957, 32, 1073749792, 32, 7975, 32, 1073749808, 32, 7991, 32, 1073749824, 32, 8005, 32, 8017, 32, 8019, 32, 8021, 32, 8023, 32, 1073749856, 32, 8039, 32, 1073749872, 296, 8049, 296, 1073749874, 344, 8053, 344, 1073749878, 400, 8055, 400, 1073749880, 512, 8057, 512, 1073749882, 448, 8059, 448, 1073749884, 504, 8061, 504, 1073749936, 32, 8113, 32, 8126, -28820, 1073749968, 32, 8145, 32, 1073749984, 32, 8161, 32, 8165, 28, 8526, -112, 1073750384, -64, 8575, -64, 8580, -4, 1073751248, -104, 9449, -104, 1073753136, -192, 11358, -192, 11361, -4, 11365, -43180, 11366, -43168, 11368, -4, 11370, -4, 11372, -4, 11382, -4, 11393, -4, 11395, -4, 11397, -4, 11399, -4, 11401, -4, 11403, -4, 11405, -4, 11407, -4, 11409, -4, 11411, -4, 11413, -4, 11415, -4, 11417, -4, 11419, -4, 11421, -4, 11423, -4, 11425, -4, 11427, -4, 11429, -4, 11431, -4, 11433, -4, 11435, -4, 11437, -4, 11439, -4, 11441, -4, 11443, -4, 11445, -4, 11447, -4, 11449, -4, 11451, -4, 11453, -4, 11455, -4, 11457, -4, 11459, -4, 11461, -4, 11463, -4, 11465, -4, 11467, -4, 11469, -4, 11471, -4, 11473, -4, 11475, -4, 11477, -4, 11479, -4, 11481, -4, 11483, -4, 11485, -4, 11487, -4, 11489, -4, 11491, -4, 1073753344, -29056, 11557, -29056 }; // NOLINT
+static const MultiCharacterSpecialCase<1> kEcma262CanonicalizeMultiStrings1[] = { {0, {0}} }; // NOLINT
+static const uint16_t kEcma262CanonicalizeTable1Size = 2;
+static const int32_t kEcma262CanonicalizeTable1[4] = { 1073774401, -128, 32602, -128 }; // NOLINT
+static const MultiCharacterSpecialCase<1> kEcma262CanonicalizeMultiStrings2[] = { {0, {0}} }; // NOLINT
+static const uint16_t kEcma262CanonicalizeTable2Size = 2;
+static const int32_t kEcma262CanonicalizeTable2[4] = { 1073742888, -160, 1103, -160 }; // NOLINT
+int Ecma262Canonicalize::Convert(uchar c,
+ uchar n,
+ uchar* result,
+ bool* allow_caching_ptr) {
+ int chunk_index = c >> 15;
+ switch (chunk_index) {
+ case 0: return LookupMapping(kEcma262CanonicalizeTable0,
+ kEcma262CanonicalizeTable0Size,
+ kEcma262CanonicalizeMultiStrings0,
+ c,
+ n,
+ result,
+ allow_caching_ptr);
+ case 1: return LookupMapping(kEcma262CanonicalizeTable1,
+ kEcma262CanonicalizeTable1Size,
+ kEcma262CanonicalizeMultiStrings1,
+ c,
+ n,
+ result,
+ allow_caching_ptr);
+ case 2: return LookupMapping(kEcma262CanonicalizeTable2,
+ kEcma262CanonicalizeTable2Size,
+ kEcma262CanonicalizeMultiStrings2,
+ c,
+ n,
+ result,
+ allow_caching_ptr);
+ default: return 0;
+ }
+}
+
+static const MultiCharacterSpecialCase<4> kEcma262UnCanonicalizeMultiStrings0[] = { {2, {65, 97}}, {2, {66, 98}}, {2, {67, 99}}, {2, {68, 100}}, {2, {69, 101}}, {2, {70, 102}}, {2, {71, 103}}, {2, {72, 104}}, {2, {73, 105}}, {2, {74, 106}}, {2, {75, 107}}, {2, {76, 108}}, {2, {77, 109}}, {2, {78, 110}}, {2, {79, 111}}, {2, {80, 112}}, {2, {81, 113}}, {2, {82, 114}}, {2, {83, 115}}, {2, {84, 116}}, {2, {85, 117}}, {2, {86, 118}}, {2, {87, 119}}, {2, {88, 120}}, {2, {89, 121}}, {2, {90, 122}}, {2, {65, 97}}, {2, {66, 98}}, {2, {67, 99}}, {2, {68, 100}}, {2, {69, 101}}, {2, {70, 102}}, {2, {71, 103}}, {2, {72, 104}}, {2, {73, 105}}, {2, {74, 106}}, {2, {75, 107}}, {2, {76, 108}}, {2, {77, 109}}, {2, {78, 110}}, {2, {79, 111}}, {2, {80, 112}}, {2, {81, 113}}, {2, {82, 114}}, {2, {83, 115}}, {2, {84, 116}}, {2, {85, 117}}, {2, {86, 118}}, {2, {87, 119}}, {2, {88, 120}}, {2, {89, 121}}, {2, {90, 122}}, {3, {181, 924, 956}}, {2, {192, 224}}, {2, {193, 225}}, {2, {194, 226}}, {2, {195, 227}}, {2, {196, 228}}, {2, {197, 229}}, {2, {198, 230}}, {2, {199, 231}}, {2, {200, 232}}, {2, {201, 233}}, {2, {202, 234}}, {2, {203, 235}}, {2, {204, 236}}, {2, {205, 237}}, {2, {206, 238}}, {2, {207, 239}}, {2, {208, 240}}, {2, {209, 241}}, {2, {210, 242}}, {2, {211, 243}}, {2, {212, 244}}, {2, {213, 245}}, {2, {214, 246}}, {2, {216, 248}}, {2, {217, 249}}, {2, {218, 250}}, {2, {219, 251}}, {2, {220, 252}}, {2, {221, 253}}, {2, {222, 254}}, {2, {192, 224}}, {2, {193, 225}}, {2, {194, 226}}, {2, {195, 227}}, {2, {196, 228}}, {2, {197, 229}}, {2, {198, 230}}, {2, {199, 231}}, {2, {200, 232}}, {2, {201, 233}}, {2, {202, 234}}, {2, {203, 235}}, {2, {204, 236}}, {2, {205, 237}}, {2, {206, 238}}, {2, {207, 239}}, {2, {208, 240}}, {2, {209, 241}}, {2, {210, 242}}, {2, {211, 243}}, {2, {212, 244}}, {2, {213, 245}}, {2, {214, 246}}, {2, {216, 248}}, {2, {217, 249}}, {2, {218, 250}}, {2, {219, 251}}, {2, {220, 252}}, {2, {221, 253}}, {2, {222, 254}}, {2, {255, 376}}, {2, {256, 257}}, {2, {256, 257}}, {2, {258, 259}}, {2, {258, 259}}, {2, {260, 261}}, {2, {260, 261}}, {2, {262, 263}}, {2, {262, 263}}, {2, {264, 265}}, {2, {264, 265}}, {2, {266, 267}}, {2, {266, 267}}, {2, {268, 269}}, {2, {268, 269}}, {2, {270, 271}}, {2, {270, 271}}, {2, {272, 273}}, {2, {272, 273}}, {2, {274, 275}}, {2, {274, 275}}, {2, {276, 277}}, {2, {276, 277}}, {2, {278, 279}}, {2, {278, 279}}, {2, {280, 281}}, {2, {280, 281}}, {2, {282, 283}}, {2, {282, 283}}, {2, {284, 285}}, {2, {284, 285}}, {2, {286, 287}}, {2, {286, 287}}, {2, {288, 289}}, {2, {288, 289}}, {2, {290, 291}}, {2, {290, 291}}, {2, {292, 293}}, {2, {292, 293}}, {2, {294, 295}}, {2, {294, 295}}, {2, {296, 297}}, {2, {296, 297}}, {2, {298, 299}}, {2, {298, 299}}, {2, {300, 301}}, {2, {300, 301}}, {2, {302, 303}}, {2, {302, 303}}, {2, {306, 307}}, {2, {306, 307}}, {2, {308, 309}}, {2, {308, 309}}, {2, {310, 311}}, {2, {310, 311}}, {2, {313, 314}}, {2, {313, 314}}, {2, {315, 316}}, {2, {315, 316}}, {2, {317, 318}}, {2, {317, 318}}, {2, {319, 320}}, {2, {319, 320}}, {2, {321, 322}}, {2, {321, 322}}, {2, {323, 324}}, {2, {323, 324}}, {2, {325, 326}}, {2, {325, 326}}, {2, {327, 328}}, {2, {327, 328}}, {2, {330, 331}}, {2, {330, 331}}, {2, {332, 333}}, {2, {332, 333}}, {2, {334, 335}}, {2, {334, 335}}, {2, {336, 337}}, {2, {336, 337}}, {2, {338, 339}}, {2, {338, 339}}, {2, {340, 341}}, {2, {340, 341}}, {2, {342, 343}}, {2, {342, 343}}, {2, {344, 345}}, {2, {344, 345}}, {2, {346, 347}}, {2, {346, 347}}, {2, {348, 349}}, {2, {348, 349}}, {2, {350, 351}}, {2, {350, 351}}, {2, {352, 353}}, {2, {352, 353}}, {2, {354, 355}}, {2, {354, 355}}, {2, {356, 357}}, {2, {356, 357}}, {2, {358, 359}}, {2, {358, 359}}, {2, {360, 361}}, {2, {360, 361}}, {2, {362, 363}}, {2, {362, 363}}, {2, {364, 365}}, {2, {364, 365}}, {2, {366, 367}}, {2, {366, 367}}, {2, {368, 369}}, {2, {368, 369}}, {2, {370, 371}}, {2, {370, 371}}, {2, {372, 373}}, {2, {372, 373}}, {2, {374, 375}}, {2, {374, 375}}, {2, {255, 376}}, {2, {377, 378}}, {2, {377, 378}}, {2, {379, 380}}, {2, {379, 380}}, {2, {381, 382}}, {2, {381, 382}}, {2, {384, 579}}, {2, {385, 595}}, {2, {386, 387}}, {2, {386, 387}}, {2, {388, 389}}, {2, {388, 389}}, {2, {390, 596}}, {2, {391, 392}}, {2, {391, 392}}, {2, {393, 598}}, {2, {394, 599}}, {2, {395, 396}}, {2, {395, 396}}, {2, {398, 477}}, {2, {399, 601}}, {2, {400, 603}}, {2, {401, 402}}, {2, {401, 402}}, {2, {403, 608}}, {2, {404, 611}}, {2, {405, 502}}, {2, {406, 617}}, {2, {407, 616}}, {2, {408, 409}}, {2, {408, 409}}, {2, {410, 573}}, {2, {412, 623}}, {2, {413, 626}}, {2, {414, 544}}, {2, {415, 629}}, {2, {416, 417}}, {2, {416, 417}}, {2, {418, 419}}, {2, {418, 419}}, {2, {420, 421}}, {2, {420, 421}}, {2, {422, 640}}, {2, {423, 424}}, {2, {423, 424}}, {2, {425, 643}}, {2, {428, 429}}, {2, {428, 429}}, {2, {430, 648}}, {2, {431, 432}}, {2, {431, 432}}, {2, {433, 650}}, {2, {434, 651}}, {2, {435, 436}}, {2, {435, 436}}, {2, {437, 438}}, {2, {437, 438}}, {2, {439, 658}}, {2, {440, 441}}, {2, {440, 441}}, {2, {444, 445}}, {2, {444, 445}}, {2, {447, 503}}, {3, {452, 453, 454}}, {3, {452, 453, 454}}, {3, {452, 453, 454}}, {3, {455, 456, 457}}, {3, {455, 456, 457}}, {3, {455, 456, 457}}, {3, {458, 459, 460}}, {3, {458, 459, 460}}, {3, {458, 459, 460}}, {2, {461, 462}}, {2, {461, 462}}, {2, {463, 464}}, {2, {463, 464}}, {2, {465, 466}}, {2, {465, 466}}, {2, {467, 468}}, {2, {467, 468}}, {2, {469, 470}}, {2, {469, 470}}, {2, {471, 472}}, {2, {471, 472}}, {2, {473, 474}}, {2, {473, 474}}, {2, {475, 476}}, {2, {475, 476}}, {2, {398, 477}}, {2, {478, 479}}, {2, {478, 479}}, {2, {480, 481}}, {2, {480, 481}}, {2, {482, 483}}, {2, {482, 483}}, {2, {484, 485}}, {2, {484, 485}}, {2, {486, 487}}, {2, {486, 487}}, {2, {488, 489}}, {2, {488, 489}}, {2, {490, 491}}, {2, {490, 491}}, {2, {492, 493}}, {2, {492, 493}}, {2, {494, 495}}, {2, {494, 495}}, {3, {497, 498, 499}}, {3, {497, 498, 499}}, {3, {497, 498, 499}}, {2, {500, 501}}, {2, {500, 501}}, {2, {405, 502}}, {2, {447, 503}}, {2, {504, 505}}, {2, {504, 505}}, {2, {506, 507}}, {2, {506, 507}}, {2, {508, 509}}, {2, {508, 509}}, {2, {510, 511}}, {2, {510, 511}}, {2, {512, 513}}, {2, {512, 513}}, {2, {514, 515}}, {2, {514, 515}}, {2, {516, 517}}, {2, {516, 517}}, {2, {518, 519}}, {2, {518, 519}}, {2, {520, 521}}, {2, {520, 521}}, {2, {522, 523}}, {2, {522, 523}}, {2, {524, 525}}, {2, {524, 525}}, {2, {526, 527}}, {2, {526, 527}}, {2, {528, 529}}, {2, {528, 529}}, {2, {530, 531}}, {2, {530, 531}}, {2, {532, 533}}, {2, {532, 533}}, {2, {534, 535}}, {2, {534, 535}}, {2, {536, 537}}, {2, {536, 537}}, {2, {538, 539}}, {2, {538, 539}}, {2, {540, 541}}, {2, {540, 541}}, {2, {542, 543}}, {2, {542, 543}}, {2, {414, 544}}, {2, {546, 547}}, {2, {546, 547}}, {2, {548, 549}}, {2, {548, 549}}, {2, {550, 551}}, {2, {550, 551}}, {2, {552, 553}}, {2, {552, 553}}, {2, {554, 555}}, {2, {554, 555}}, {2, {556, 557}}, {2, {556, 557}}, {2, {558, 559}}, {2, {558, 559}}, {2, {560, 561}}, {2, {560, 561}}, {2, {562, 563}}, {2, {562, 563}}, {2, {570, 11365}}, {2, {571, 572}}, {2, {571, 572}}, {2, {410, 573}}, {2, {574, 11366}}, {2, {577, 578}}, {2, {577, 578}}, {2, {384, 579}}, {2, {580, 649}}, {2, {581, 652}}, {2, {582, 583}}, {2, {582, 583}}, {2, {584, 585}}, {2, {584, 585}}, {2, {586, 587}}, {2, {586, 587}}, {2, {588, 589}}, {2, {588, 589}}, {2, {590, 591}}, {2, {590, 591}}, {2, {385, 595}}, {2, {390, 596}}, {2, {393, 598}}, {2, {394, 599}}, {2, {399, 601}}, {2, {400, 603}}, {2, {403, 608}}, {2, {404, 611}}, {2, {407, 616}}, {2, {406, 617}}, {2, {619, 11362}}, {2, {412, 623}}, {2, {413, 626}}, {2, {415, 629}}, {2, {637, 11364}}, {2, {422, 640}}, {2, {425, 643}}, {2, {430, 648}}, {2, {580, 649}}, {2, {433, 650}}, {2, {434, 651}}, {2, {581, 652}}, {2, {439, 658}}, {4, {837, 921, 953, 8126}}, {2, {891, 1021}}, {2, {892, 1022}}, {2, {893, 1023}}, {2, {902, 940}}, {2, {904, 941}}, {2, {905, 942}}, {2, {906, 943}}, {2, {908, 972}}, {2, {910, 973}}, {2, {911, 974}}, {2, {913, 945}}, {3, {914, 946, 976}}, {2, {915, 947}}, {2, {916, 948}}, {3, {917, 949, 1013}}, {2, {918, 950}}, {2, {919, 951}}, {3, {920, 952, 977}}, {4, {837, 921, 953, 8126}}, {3, {922, 954, 1008}}, {2, {923, 955}}, {3, {181, 924, 956}}, {2, {925, 957}}, {2, {926, 958}}, {2, {927, 959}}, {3, {928, 960, 982}}, {3, {929, 961, 1009}}, {3, {931, 962, 963}}, {2, {932, 964}}, {2, {933, 965}}, {3, {934, 966, 981}}, {2, {935, 967}}, {2, {936, 968}}, {2, {937, 969}}, {2, {938, 970}}, {2, {939, 971}}, {2, {902, 940}}, {2, {904, 941}}, {2, {905, 942}}, {2, {906, 943}}, {2, {913, 945}}, {3, {914, 946, 976}}, {2, {915, 947}}, {2, {916, 948}}, {3, {917, 949, 1013}}, {2, {918, 950}}, {2, {919, 951}}, {3, {920, 952, 977}}, {4, {837, 921, 953, 8126}}, {3, {922, 954, 1008}}, {2, {923, 955}}, {3, {181, 924, 956}}, {2, {925, 957}}, {2, {926, 958}}, {2, {927, 959}}, {3, {928, 960, 982}}, {3, {929, 961, 1009}}, {3, {931, 962, 963}}, {3, {931, 962, 963}}, {2, {932, 964}}, {2, {933, 965}}, {3, {934, 966, 981}}, {2, {935, 967}}, {2, {936, 968}}, {2, {937, 969}}, {2, {938, 970}}, {2, {939, 971}}, {2, {908, 972}}, {2, {910, 973}}, {2, {911, 974}}, {3, {914, 946, 976}}, {3, {920, 952, 977}}, {3, {934, 966, 981}}, {3, {928, 960, 982}}, {2, {984, 985}}, {2, {984, 985}}, {2, {986, 987}}, {2, {986, 987}}, {2, {988, 989}}, {2, {988, 989}}, {2, {990, 991}}, {2, {990, 991}}, {2, {992, 993}}, {2, {992, 993}}, {2, {994, 995}}, {2, {994, 995}}, {2, {996, 997}}, {2, {996, 997}}, {2, {998, 999}}, {2, {998, 999}}, {2, {1000, 1001}}, {2, {1000, 1001}}, {2, {1002, 1003}}, {2, {1002, 1003}}, {2, {1004, 1005}}, {2, {1004, 1005}}, {2, {1006, 1007}}, {2, {1006, 1007}}, {3, {922, 954, 1008}}, {3, {929, 961, 1009}}, {2, {1010, 1017}}, {3, {917, 949, 1013}}, {2, {1015, 1016}}, {2, {1015, 1016}}, {2, {1010, 1017}}, {2, {1018, 1019}}, {2, {1018, 1019}}, {2, {891, 1021}}, {2, {892, 1022}}, {2, {893, 1023}}, {2, {1024, 1104}}, {2, {1025, 1105}}, {2, {1026, 1106}}, {2, {1027, 1107}}, {2, {1028, 1108}}, {2, {1029, 1109}}, {2, {1030, 1110}}, {2, {1031, 1111}}, {2, {1032, 1112}}, {2, {1033, 1113}}, {2, {1034, 1114}}, {2, {1035, 1115}}, {2, {1036, 1116}}, {2, {1037, 1117}}, {2, {1038, 1118}}, {2, {1039, 1119}}, {2, {1040, 1072}}, {2, {1041, 1073}}, {2, {1042, 1074}}, {2, {1043, 1075}}, {2, {1044, 1076}}, {2, {1045, 1077}}, {2, {1046, 1078}}, {2, {1047, 1079}}, {2, {1048, 1080}}, {2, {1049, 1081}}, {2, {1050, 1082}}, {2, {1051, 1083}}, {2, {1052, 1084}}, {2, {1053, 1085}}, {2, {1054, 1086}}, {2, {1055, 1087}}, {2, {1056, 1088}}, {2, {1057, 1089}}, {2, {1058, 1090}}, {2, {1059, 1091}}, {2, {1060, 1092}}, {2, {1061, 1093}}, {2, {1062, 1094}}, {2, {1063, 1095}}, {2, {1064, 1096}}, {2, {1065, 1097}}, {2, {1066, 1098}}, {2, {1067, 1099}}, {2, {1068, 1100}}, {2, {1069, 1101}}, {2, {1070, 1102}}, {2, {1071, 1103}}, {2, {1040, 1072}}, {2, {1041, 1073}}, {2, {1042, 1074}}, {2, {1043, 1075}}, {2, {1044, 1076}}, {2, {1045, 1077}}, {2, {1046, 1078}}, {2, {1047, 1079}}, {2, {1048, 1080}}, {2, {1049, 1081}}, {2, {1050, 1082}}, {2, {1051, 1083}}, {2, {1052, 1084}}, {2, {1053, 1085}}, {2, {1054, 1086}}, {2, {1055, 1087}}, {2, {1056, 1088}}, {2, {1057, 1089}}, {2, {1058, 1090}}, {2, {1059, 1091}}, {2, {1060, 1092}}, {2, {1061, 1093}}, {2, {1062, 1094}}, {2, {1063, 1095}}, {2, {1064, 1096}}, {2, {1065, 1097}}, {2, {1066, 1098}}, {2, {1067, 1099}}, {2, {1068, 1100}}, {2, {1069, 1101}}, {2, {1070, 1102}}, {2, {1071, 1103}}, {2, {1024, 1104}}, {2, {1025, 1105}}, {2, {1026, 1106}}, {2, {1027, 1107}}, {2, {1028, 1108}}, {2, {1029, 1109}}, {2, {1030, 1110}}, {2, {1031, 1111}}, {2, {1032, 1112}}, {2, {1033, 1113}}, {2, {1034, 1114}}, {2, {1035, 1115}}, {2, {1036, 1116}}, {2, {1037, 1117}}, {2, {1038, 1118}}, {2, {1039, 1119}}, {2, {1120, 1121}}, {2, {1120, 1121}}, {2, {1122, 1123}}, {2, {1122, 1123}}, {2, {1124, 1125}}, {2, {1124, 1125}}, {2, {1126, 1127}}, {2, {1126, 1127}}, {2, {1128, 1129}}, {2, {1128, 1129}}, {2, {1130, 1131}}, {2, {1130, 1131}}, {2, {1132, 1133}}, {2, {1132, 1133}}, {2, {1134, 1135}}, {2, {1134, 1135}}, {2, {1136, 1137}}, {2, {1136, 1137}}, {2, {1138, 1139}}, {2, {1138, 1139}}, {2, {1140, 1141}}, {2, {1140, 1141}}, {2, {1142, 1143}}, {2, {1142, 1143}}, {2, {1144, 1145}}, {2, {1144, 1145}}, {2, {1146, 1147}}, {2, {1146, 1147}}, {2, {1148, 1149}}, {2, {1148, 1149}}, {2, {1150, 1151}}, {2, {1150, 1151}}, {2, {1152, 1153}}, {2, {1152, 1153}}, {2, {1162, 1163}}, {2, {1162, 1163}}, {2, {1164, 1165}}, {2, {1164, 1165}}, {2, {1166, 1167}}, {2, {1166, 1167}}, {2, {1168, 1169}}, {2, {1168, 1169}}, {2, {1170, 1171}}, {2, {1170, 1171}}, {2, {1172, 1173}}, {2, {1172, 1173}}, {2, {1174, 1175}}, {2, {1174, 1175}}, {2, {1176, 1177}}, {2, {1176, 1177}}, {2, {1178, 1179}}, {2, {1178, 1179}}, {2, {1180, 1181}}, {2, {1180, 1181}}, {2, {1182, 1183}}, {2, {1182, 1183}}, {2, {1184, 1185}}, {2, {1184, 1185}}, {2, {1186, 1187}}, {2, {1186, 1187}}, {2, {1188, 1189}}, {2, {1188, 1189}}, {2, {1190, 1191}}, {2, {1190, 1191}}, {2, {1192, 1193}}, {2, {1192, 1193}}, {2, {1194, 1195}}, {2, {1194, 1195}}, {2, {1196, 1197}}, {2, {1196, 1197}}, {2, {1198, 1199}}, {2, {1198, 1199}}, {2, {1200, 1201}}, {2, {1200, 1201}}, {2, {1202, 1203}}, {2, {1202, 1203}}, {2, {1204, 1205}}, {2, {1204, 1205}}, {2, {1206, 1207}}, {2, {1206, 1207}}, {2, {1208, 1209}}, {2, {1208, 1209}}, {2, {1210, 1211}}, {2, {1210, 1211}}, {2, {1212, 1213}}, {2, {1212, 1213}}, {2, {1214, 1215}}, {2, {1214, 1215}}, {2, {1216, 1231}}, {2, {1217, 1218}}, {2, {1217, 1218}}, {2, {1219, 1220}}, {2, {1219, 1220}}, {2, {1221, 1222}}, {2, {1221, 1222}}, {2, {1223, 1224}}, {2, {1223, 1224}}, {2, {1225, 1226}}, {2, {1225, 1226}}, {2, {1227, 1228}}, {2, {1227, 1228}}, {2, {1229, 1230}}, {2, {1229, 1230}}, {2, {1216, 1231}}, {2, {1232, 1233}}, {2, {1232, 1233}}, {2, {1234, 1235}}, {2, {1234, 1235}}, {2, {1236, 1237}}, {2, {1236, 1237}}, {2, {1238, 1239}}, {2, {1238, 1239}}, {2, {1240, 1241}}, {2, {1240, 1241}}, {2, {1242, 1243}}, {2, {1242, 1243}}, {2, {1244, 1245}}, {2, {1244, 1245}}, {2, {1246, 1247}}, {2, {1246, 1247}}, {2, {1248, 1249}}, {2, {1248, 1249}}, {2, {1250, 1251}}, {2, {1250, 1251}}, {2, {1252, 1253}}, {2, {1252, 1253}}, {2, {1254, 1255}}, {2, {1254, 1255}}, {2, {1256, 1257}}, {2, {1256, 1257}}, {2, {1258, 1259}}, {2, {1258, 1259}}, {2, {1260, 1261}}, {2, {1260, 1261}}, {2, {1262, 1263}}, {2, {1262, 1263}}, {2, {1264, 1265}}, {2, {1264, 1265}}, {2, {1266, 1267}}, {2, {1266, 1267}}, {2, {1268, 1269}}, {2, {1268, 1269}}, {2, {1270, 1271}}, {2, {1270, 1271}}, {2, {1272, 1273}}, {2, {1272, 1273}}, {2, {1274, 1275}}, {2, {1274, 1275}}, {2, {1276, 1277}}, {2, {1276, 1277}}, {2, {1278, 1279}}, {2, {1278, 1279}}, {2, {1280, 1281}}, {2, {1280, 1281}}, {2, {1282, 1283}}, {2, {1282, 1283}}, {2, {1284, 1285}}, {2, {1284, 1285}}, {2, {1286, 1287}}, {2, {1286, 1287}}, {2, {1288, 1289}}, {2, {1288, 1289}}, {2, {1290, 1291}}, {2, {1290, 1291}}, {2, {1292, 1293}}, {2, {1292, 1293}}, {2, {1294, 1295}}, {2, {1294, 1295}}, {2, {1296, 1297}}, {2, {1296, 1297}}, {2, {1298, 1299}}, {2, {1298, 1299}}, {2, {1329, 1377}}, {2, {1330, 1378}}, {2, {1331, 1379}}, {2, {1332, 1380}}, {2, {1333, 1381}}, {2, {1334, 1382}}, {2, {1335, 1383}}, {2, {1336, 1384}}, {2, {1337, 1385}}, {2, {1338, 1386}}, {2, {1339, 1387}}, {2, {1340, 1388}}, {2, {1341, 1389}}, {2, {1342, 1390}}, {2, {1343, 1391}}, {2, {1344, 1392}}, {2, {1345, 1393}}, {2, {1346, 1394}}, {2, {1347, 1395}}, {2, {1348, 1396}}, {2, {1349, 1397}}, {2, {1350, 1398}}, {2, {1351, 1399}}, {2, {1352, 1400}}, {2, {1353, 1401}}, {2, {1354, 1402}}, {2, {1355, 1403}}, {2, {1356, 1404}}, {2, {1357, 1405}}, {2, {1358, 1406}}, {2, {1359, 1407}}, {2, {1360, 1408}}, {2, {1361, 1409}}, {2, {1362, 1410}}, {2, {1363, 1411}}, {2, {1364, 1412}}, {2, {1365, 1413}}, {2, {1366, 1414}}, {2, {1329, 1377}}, {2, {1330, 1378}}, {2, {1331, 1379}}, {2, {1332, 1380}}, {2, {1333, 1381}}, {2, {1334, 1382}}, {2, {1335, 1383}}, {2, {1336, 1384}}, {2, {1337, 1385}}, {2, {1338, 1386}}, {2, {1339, 1387}}, {2, {1340, 1388}}, {2, {1341, 1389}}, {2, {1342, 1390}}, {2, {1343, 1391}}, {2, {1344, 1392}}, {2, {1345, 1393}}, {2, {1346, 1394}}, {2, {1347, 1395}}, {2, {1348, 1396}}, {2, {1349, 1397}}, {2, {1350, 1398}}, {2, {1351, 1399}}, {2, {1352, 1400}}, {2, {1353, 1401}}, {2, {1354, 1402}}, {2, {1355, 1403}}, {2, {1356, 1404}}, {2, {1357, 1405}}, {2, {1358, 1406}}, {2, {1359, 1407}}, {2, {1360, 1408}}, {2, {1361, 1409}}, {2, {1362, 1410}}, {2, {1363, 1411}}, {2, {1364, 1412}}, {2, {1365, 1413}}, {2, {1366, 1414}}, {2, {4256, 11520}}, {2, {4257, 11521}}, {2, {4258, 11522}}, {2, {4259, 11523}}, {2, {4260, 11524}}, {2, {4261, 11525}}, {2, {4262, 11526}}, {2, {4263, 11527}}, {2, {4264, 11528}}, {2, {4265, 11529}}, {2, {4266, 11530}}, {2, {4267, 11531}}, {2, {4268, 11532}}, {2, {4269, 11533}}, {2, {4270, 11534}}, {2, {4271, 11535}}, {2, {4272, 11536}}, {2, {4273, 11537}}, {2, {4274, 11538}}, {2, {4275, 11539}}, {2, {4276, 11540}}, {2, {4277, 11541}}, {2, {4278, 11542}}, {2, {4279, 11543}}, {2, {4280, 11544}}, {2, {4281, 11545}}, {2, {4282, 11546}}, {2, {4283, 11547}}, {2, {4284, 11548}}, {2, {4285, 11549}}, {2, {4286, 11550}}, {2, {4287, 11551}}, {2, {4288, 11552}}, {2, {4289, 11553}}, {2, {4290, 11554}}, {2, {4291, 11555}}, {2, {4292, 11556}}, {2, {4293, 11557}}, {2, {7549, 11363}}, {2, {7680, 7681}}, {2, {7680, 7681}}, {2, {7682, 7683}}, {2, {7682, 7683}}, {2, {7684, 7685}}, {2, {7684, 7685}}, {2, {7686, 7687}}, {2, {7686, 7687}}, {2, {7688, 7689}}, {2, {7688, 7689}}, {2, {7690, 7691}}, {2, {7690, 7691}}, {2, {7692, 7693}}, {2, {7692, 7693}}, {2, {7694, 7695}}, {2, {7694, 7695}}, {2, {7696, 7697}}, {2, {7696, 7697}}, {2, {7698, 7699}}, {2, {7698, 7699}}, {2, {7700, 7701}}, {2, {7700, 7701}}, {2, {7702, 7703}}, {2, {7702, 7703}}, {2, {7704, 7705}}, {2, {7704, 7705}}, {2, {7706, 7707}}, {2, {7706, 7707}}, {2, {7708, 7709}}, {2, {7708, 7709}}, {2, {7710, 7711}}, {2, {7710, 7711}}, {2, {7712, 7713}}, {2, {7712, 7713}}, {2, {7714, 7715}}, {2, {7714, 7715}}, {2, {7716, 7717}}, {2, {7716, 7717}}, {2, {7718, 7719}}, {2, {7718, 7719}}, {2, {7720, 7721}}, {2, {7720, 7721}}, {2, {7722, 7723}}, {2, {7722, 7723}}, {2, {7724, 7725}}, {2, {7724, 7725}}, {2, {7726, 7727}}, {2, {7726, 7727}}, {2, {7728, 7729}}, {2, {7728, 7729}}, {2, {7730, 7731}}, {2, {7730, 7731}}, {2, {7732, 7733}}, {2, {7732, 7733}}, {2, {7734, 7735}}, {2, {7734, 7735}}, {2, {7736, 7737}}, {2, {7736, 7737}}, {2, {7738, 7739}}, {2, {7738, 7739}}, {2, {7740, 7741}}, {2, {7740, 7741}}, {2, {7742, 7743}}, {2, {7742, 7743}}, {2, {7744, 7745}}, {2, {7744, 7745}}, {2, {7746, 7747}}, {2, {7746, 7747}}, {2, {7748, 7749}}, {2, {7748, 7749}}, {2, {7750, 7751}}, {2, {7750, 7751}}, {2, {7752, 7753}}, {2, {7752, 7753}}, {2, {7754, 7755}}, {2, {7754, 7755}}, {2, {7756, 7757}}, {2, {7756, 7757}}, {2, {7758, 7759}}, {2, {7758, 7759}}, {2, {7760, 7761}}, {2, {7760, 7761}}, {2, {7762, 7763}}, {2, {7762, 7763}}, {2, {7764, 7765}}, {2, {7764, 7765}}, {2, {7766, 7767}}, {2, {7766, 7767}}, {2, {7768, 7769}}, {2, {7768, 7769}}, {2, {7770, 7771}}, {2, {7770, 7771}}, {2, {7772, 7773}}, {2, {7772, 7773}}, {2, {7774, 7775}}, {2, {7774, 7775}}, {3, {7776, 7777, 7835}}, {3, {7776, 7777, 7835}}, {2, {7778, 7779}}, {2, {7778, 7779}}, {2, {7780, 7781}}, {2, {7780, 7781}}, {2, {7782, 7783}}, {2, {7782, 7783}}, {2, {7784, 7785}}, {2, {7784, 7785}}, {2, {7786, 7787}}, {2, {7786, 7787}}, {2, {7788, 7789}}, {2, {7788, 7789}}, {2, {7790, 7791}}, {2, {7790, 7791}}, {2, {7792, 7793}}, {2, {7792, 7793}}, {2, {7794, 7795}}, {2, {7794, 7795}}, {2, {7796, 7797}}, {2, {7796, 7797}}, {2, {7798, 7799}}, {2, {7798, 7799}}, {2, {7800, 7801}}, {2, {7800, 7801}}, {2, {7802, 7803}}, {2, {7802, 7803}}, {2, {7804, 7805}}, {2, {7804, 7805}}, {2, {7806, 7807}}, {2, {7806, 7807}}, {2, {7808, 7809}}, {2, {7808, 7809}}, {2, {7810, 7811}}, {2, {7810, 7811}}, {2, {7812, 7813}}, {2, {7812, 7813}}, {2, {7814, 7815}}, {2, {7814, 7815}}, {2, {7816, 7817}}, {2, {7816, 7817}}, {2, {7818, 7819}}, {2, {7818, 7819}}, {2, {7820, 7821}}, {2, {7820, 7821}}, {2, {7822, 7823}}, {2, {7822, 7823}}, {2, {7824, 7825}}, {2, {7824, 7825}}, {2, {7826, 7827}}, {2, {7826, 7827}}, {2, {7828, 7829}}, {2, {7828, 7829}}, {3, {7776, 7777, 7835}}, {2, {7840, 7841}}, {2, {7840, 7841}}, {2, {7842, 7843}}, {2, {7842, 7843}}, {2, {7844, 7845}}, {2, {7844, 7845}}, {2, {7846, 7847}}, {2, {7846, 7847}}, {2, {7848, 7849}}, {2, {7848, 7849}}, {2, {7850, 7851}}, {2, {7850, 7851}}, {2, {7852, 7853}}, {2, {7852, 7853}}, {2, {7854, 7855}}, {2, {7854, 7855}}, {2, {7856, 7857}}, {2, {7856, 7857}}, {2, {7858, 7859}}, {2, {7858, 7859}}, {2, {7860, 7861}}, {2, {7860, 7861}}, {2, {7862, 7863}}, {2, {7862, 7863}}, {2, {7864, 7865}}, {2, {7864, 7865}}, {2, {7866, 7867}}, {2, {7866, 7867}}, {2, {7868, 7869}}, {2, {7868, 7869}}, {2, {7870, 7871}}, {2, {7870, 7871}}, {2, {7872, 7873}}, {2, {7872, 7873}}, {2, {7874, 7875}}, {2, {7874, 7875}}, {2, {7876, 7877}}, {2, {7876, 7877}}, {2, {7878, 7879}}, {2, {7878, 7879}}, {2, {7880, 7881}}, {2, {7880, 7881}}, {2, {7882, 7883}}, {2, {7882, 7883}}, {2, {7884, 7885}}, {2, {7884, 7885}}, {2, {7886, 7887}}, {2, {7886, 7887}}, {2, {7888, 7889}}, {2, {7888, 7889}}, {2, {7890, 7891}}, {2, {7890, 7891}}, {2, {7892, 7893}}, {2, {7892, 7893}}, {2, {7894, 7895}}, {2, {7894, 7895}}, {2, {7896, 7897}}, {2, {7896, 7897}}, {2, {7898, 7899}}, {2, {7898, 7899}}, {2, {7900, 7901}}, {2, {7900, 7901}}, {2, {7902, 7903}}, {2, {7902, 7903}}, {2, {7904, 7905}}, {2, {7904, 7905}}, {2, {7906, 7907}}, {2, {7906, 7907}}, {2, {7908, 7909}}, {2, {7908, 7909}}, {2, {7910, 7911}}, {2, {7910, 7911}}, {2, {7912, 7913}}, {2, {7912, 7913}}, {2, {7914, 7915}}, {2, {7914, 7915}}, {2, {7916, 7917}}, {2, {7916, 7917}}, {2, {7918, 7919}}, {2, {7918, 7919}}, {2, {7920, 7921}}, {2, {7920, 7921}}, {2, {7922, 7923}}, {2, {7922, 7923}}, {2, {7924, 7925}}, {2, {7924, 7925}}, {2, {7926, 7927}}, {2, {7926, 7927}}, {2, {7928, 7929}}, {2, {7928, 7929}}, {2, {7936, 7944}}, {2, {7937, 7945}}, {2, {7938, 7946}}, {2, {7939, 7947}}, {2, {7940, 7948}}, {2, {7941, 7949}}, {2, {7942, 7950}}, {2, {7943, 7951}}, {2, {7936, 7944}}, {2, {7937, 7945}}, {2, {7938, 7946}}, {2, {7939, 7947}}, {2, {7940, 7948}}, {2, {7941, 7949}}, {2, {7942, 7950}}, {2, {7943, 7951}}, {2, {7952, 7960}}, {2, {7953, 7961}}, {2, {7954, 7962}}, {2, {7955, 7963}}, {2, {7956, 7964}}, {2, {7957, 7965}}, {2, {7952, 7960}}, {2, {7953, 7961}}, {2, {7954, 7962}}, {2, {7955, 7963}}, {2, {7956, 7964}}, {2, {7957, 7965}}, {2, {7968, 7976}}, {2, {7969, 7977}}, {2, {7970, 7978}}, {2, {7971, 7979}}, {2, {7972, 7980}}, {2, {7973, 7981}}, {2, {7974, 7982}}, {2, {7975, 7983}}, {2, {7968, 7976}}, {2, {7969, 7977}}, {2, {7970, 7978}}, {2, {7971, 7979}}, {2, {7972, 7980}}, {2, {7973, 7981}}, {2, {7974, 7982}}, {2, {7975, 7983}}, {2, {7984, 7992}}, {2, {7985, 7993}}, {2, {7986, 7994}}, {2, {7987, 7995}}, {2, {7988, 7996}}, {2, {7989, 7997}}, {2, {7990, 7998}}, {2, {7991, 7999}}, {2, {7984, 7992}}, {2, {7985, 7993}}, {2, {7986, 7994}}, {2, {7987, 7995}}, {2, {7988, 7996}}, {2, {7989, 7997}}, {2, {7990, 7998}}, {2, {7991, 7999}}, {2, {8000, 8008}}, {2, {8001, 8009}}, {2, {8002, 8010}}, {2, {8003, 8011}}, {2, {8004, 8012}}, {2, {8005, 8013}}, {2, {8000, 8008}}, {2, {8001, 8009}}, {2, {8002, 8010}}, {2, {8003, 8011}}, {2, {8004, 8012}}, {2, {8005, 8013}}, {2, {8017, 8025}}, {2, {8019, 8027}}, {2, {8021, 8029}}, {2, {8023, 8031}}, {2, {8017, 8025}}, {2, {8019, 8027}}, {2, {8021, 8029}}, {2, {8023, 8031}}, {2, {8032, 8040}}, {2, {8033, 8041}}, {2, {8034, 8042}}, {2, {8035, 8043}}, {2, {8036, 8044}}, {2, {8037, 8045}}, {2, {8038, 8046}}, {2, {8039, 8047}}, {2, {8032, 8040}}, {2, {8033, 8041}}, {2, {8034, 8042}}, {2, {8035, 8043}}, {2, {8036, 8044}}, {2, {8037, 8045}}, {2, {8038, 8046}}, {2, {8039, 8047}}, {2, {8048, 8122}}, {2, {8049, 8123}}, {2, {8050, 8136}}, {2, {8051, 8137}}, {2, {8052, 8138}}, {2, {8053, 8139}}, {2, {8054, 8154}}, {2, {8055, 8155}}, {2, {8056, 8184}}, {2, {8057, 8185}}, {2, {8058, 8170}}, {2, {8059, 8171}}, {2, {8060, 8186}}, {2, {8061, 8187}}, {2, {8112, 8120}}, {2, {8113, 8121}}, {2, {8112, 8120}}, {2, {8113, 8121}}, {2, {8048, 8122}}, {2, {8049, 8123}}, {4, {837, 921, 953, 8126}}, {2, {8050, 8136}}, {2, {8051, 8137}}, {2, {8052, 8138}}, {2, {8053, 8139}}, {2, {8144, 8152}}, {2, {8145, 8153}}, {2, {8144, 8152}}, {2, {8145, 8153}}, {2, {8054, 8154}}, {2, {8055, 8155}}, {2, {8160, 8168}}, {2, {8161, 8169}}, {2, {8165, 8172}}, {2, {8160, 8168}}, {2, {8161, 8169}}, {2, {8058, 8170}}, {2, {8059, 8171}}, {2, {8165, 8172}}, {2, {8056, 8184}}, {2, {8057, 8185}}, {2, {8060, 8186}}, {2, {8061, 8187}}, {2, {8498, 8526}}, {2, {8498, 8526}}, {2, {8544, 8560}}, {2, {8545, 8561}}, {2, {8546, 8562}}, {2, {8547, 8563}}, {2, {8548, 8564}}, {2, {8549, 8565}}, {2, {8550, 8566}}, {2, {8551, 8567}}, {2, {8552, 8568}}, {2, {8553, 8569}}, {2, {8554, 8570}}, {2, {8555, 8571}}, {2, {8556, 8572}}, {2, {8557, 8573}}, {2, {8558, 8574}}, {2, {8559, 8575}}, {2, {8544, 8560}}, {2, {8545, 8561}}, {2, {8546, 8562}}, {2, {8547, 8563}}, {2, {8548, 8564}}, {2, {8549, 8565}}, {2, {8550, 8566}}, {2, {8551, 8567}}, {2, {8552, 8568}}, {2, {8553, 8569}}, {2, {8554, 8570}}, {2, {8555, 8571}}, {2, {8556, 8572}}, {2, {8557, 8573}}, {2, {8558, 8574}}, {2, {8559, 8575}}, {2, {8579, 8580}}, {2, {8579, 8580}}, {2, {9398, 9424}}, {2, {9399, 9425}}, {2, {9400, 9426}}, {2, {9401, 9427}}, {2, {9402, 9428}}, {2, {9403, 9429}}, {2, {9404, 9430}}, {2, {9405, 9431}}, {2, {9406, 9432}}, {2, {9407, 9433}}, {2, {9408, 9434}}, {2, {9409, 9435}}, {2, {9410, 9436}}, {2, {9411, 9437}}, {2, {9412, 9438}}, {2, {9413, 9439}}, {2, {9414, 9440}}, {2, {9415, 9441}}, {2, {9416, 9442}}, {2, {9417, 9443}}, {2, {9418, 9444}}, {2, {9419, 9445}}, {2, {9420, 9446}}, {2, {9421, 9447}}, {2, {9422, 9448}}, {2, {9423, 9449}}, {2, {9398, 9424}}, {2, {9399, 9425}}, {2, {9400, 9426}}, {2, {9401, 9427}}, {2, {9402, 9428}}, {2, {9403, 9429}}, {2, {9404, 9430}}, {2, {9405, 9431}}, {2, {9406, 9432}}, {2, {9407, 9433}}, {2, {9408, 9434}}, {2, {9409, 9435}}, {2, {9410, 9436}}, {2, {9411, 9437}}, {2, {9412, 9438}}, {2, {9413, 9439}}, {2, {9414, 9440}}, {2, {9415, 9441}}, {2, {9416, 9442}}, {2, {9417, 9443}}, {2, {9418, 9444}}, {2, {9419, 9445}}, {2, {9420, 9446}}, {2, {9421, 9447}}, {2, {9422, 9448}}, {2, {9423, 9449}}, {2, {11264, 11312}}, {2, {11265, 11313}}, {2, {11266, 11314}}, {2, {11267, 11315}}, {2, {11268, 11316}}, {2, {11269, 11317}}, {2, {11270, 11318}}, {2, {11271, 11319}}, {2, {11272, 11320}}, {2, {11273, 11321}}, {2, {11274, 11322}}, {2, {11275, 11323}}, {2, {11276, 11324}}, {2, {11277, 11325}}, {2, {11278, 11326}}, {2, {11279, 11327}}, {2, {11280, 11328}}, {2, {11281, 11329}}, {2, {11282, 11330}}, {2, {11283, 11331}}, {2, {11284, 11332}}, {2, {11285, 11333}}, {2, {11286, 11334}}, {2, {11287, 11335}}, {2, {11288, 11336}}, {2, {11289, 11337}}, {2, {11290, 11338}}, {2, {11291, 11339}}, {2, {11292, 11340}}, {2, {11293, 11341}}, {2, {11294, 11342}}, {2, {11295, 11343}}, {2, {11296, 11344}}, {2, {11297, 11345}}, {2, {11298, 11346}}, {2, {11299, 11347}}, {2, {11300, 11348}}, {2, {11301, 11349}}, {2, {11302, 11350}}, {2, {11303, 11351}}, {2, {11304, 11352}}, {2, {11305, 11353}}, {2, {11306, 11354}}, {2, {11307, 11355}}, {2, {11308, 11356}}, {2, {11309, 11357}}, {2, {11310, 11358}}, {2, {11264, 11312}}, {2, {11265, 11313}}, {2, {11266, 11314}}, {2, {11267, 11315}}, {2, {11268, 11316}}, {2, {11269, 11317}}, {2, {11270, 11318}}, {2, {11271, 11319}}, {2, {11272, 11320}}, {2, {11273, 11321}}, {2, {11274, 11322}}, {2, {11275, 11323}}, {2, {11276, 11324}}, {2, {11277, 11325}}, {2, {11278, 11326}}, {2, {11279, 11327}}, {2, {11280, 11328}}, {2, {11281, 11329}}, {2, {11282, 11330}}, {2, {11283, 11331}}, {2, {11284, 11332}}, {2, {11285, 11333}}, {2, {11286, 11334}}, {2, {11287, 11335}}, {2, {11288, 11336}}, {2, {11289, 11337}}, {2, {11290, 11338}}, {2, {11291, 11339}}, {2, {11292, 11340}}, {2, {11293, 11341}}, {2, {11294, 11342}}, {2, {11295, 11343}}, {2, {11296, 11344}}, {2, {11297, 11345}}, {2, {11298, 11346}}, {2, {11299, 11347}}, {2, {11300, 11348}}, {2, {11301, 11349}}, {2, {11302, 11350}}, {2, {11303, 11351}}, {2, {11304, 11352}}, {2, {11305, 11353}}, {2, {11306, 11354}}, {2, {11307, 11355}}, {2, {11308, 11356}}, {2, {11309, 11357}}, {2, {11310, 11358}}, {2, {11360, 11361}}, {2, {11360, 11361}}, {2, {619, 11362}}, {2, {7549, 11363}}, {2, {637, 11364}}, {2, {570, 11365}}, {2, {574, 11366}}, {2, {11367, 11368}}, {2, {11367, 11368}}, {2, {11369, 11370}}, {2, {11369, 11370}}, {2, {11371, 11372}}, {2, {11371, 11372}}, {2, {11381, 11382}}, {2, {11381, 11382}}, {2, {11392, 11393}}, {2, {11392, 11393}}, {2, {11394, 11395}}, {2, {11394, 11395}}, {2, {11396, 11397}}, {2, {11396, 11397}}, {2, {11398, 11399}}, {2, {11398, 11399}}, {2, {11400, 11401}}, {2, {11400, 11401}}, {2, {11402, 11403}}, {2, {11402, 11403}}, {2, {11404, 11405}}, {2, {11404, 11405}}, {2, {11406, 11407}}, {2, {11406, 11407}}, {2, {11408, 11409}}, {2, {11408, 11409}}, {2, {11410, 11411}}, {2, {11410, 11411}}, {2, {11412, 11413}}, {2, {11412, 11413}}, {2, {11414, 11415}}, {2, {11414, 11415}}, {2, {11416, 11417}}, {2, {11416, 11417}}, {2, {11418, 11419}}, {2, {11418, 11419}}, {2, {11420, 11421}}, {2, {11420, 11421}}, {2, {11422, 11423}}, {2, {11422, 11423}}, {2, {11424, 11425}}, {2, {11424, 11425}}, {2, {11426, 11427}}, {2, {11426, 11427}}, {2, {11428, 11429}}, {2, {11428, 11429}}, {2, {11430, 11431}}, {2, {11430, 11431}}, {2, {11432, 11433}}, {2, {11432, 11433}}, {2, {11434, 11435}}, {2, {11434, 11435}}, {2, {11436, 11437}}, {2, {11436, 11437}}, {2, {11438, 11439}}, {2, {11438, 11439}}, {2, {11440, 11441}}, {2, {11440, 11441}}, {2, {11442, 11443}}, {2, {11442, 11443}}, {2, {11444, 11445}}, {2, {11444, 11445}}, {2, {11446, 11447}}, {2, {11446, 11447}}, {2, {11448, 11449}}, {2, {11448, 11449}}, {2, {11450, 11451}}, {2, {11450, 11451}}, {2, {11452, 11453}}, {2, {11452, 11453}}, {2, {11454, 11455}}, {2, {11454, 11455}}, {2, {11456, 11457}}, {2, {11456, 11457}}, {2, {11458, 11459}}, {2, {11458, 11459}}, {2, {11460, 11461}}, {2, {11460, 11461}}, {2, {11462, 11463}}, {2, {11462, 11463}}, {2, {11464, 11465}}, {2, {11464, 11465}}, {2, {11466, 11467}}, {2, {11466, 11467}}, {2, {11468, 11469}}, {2, {11468, 11469}}, {2, {11470, 11471}}, {2, {11470, 11471}}, {2, {11472, 11473}}, {2, {11472, 11473}}, {2, {11474, 11475}}, {2, {11474, 11475}}, {2, {11476, 11477}}, {2, {11476, 11477}}, {2, {11478, 11479}}, {2, {11478, 11479}}, {2, {11480, 11481}}, {2, {11480, 11481}}, {2, {11482, 11483}}, {2, {11482, 11483}}, {2, {11484, 11485}}, {2, {11484, 11485}}, {2, {11486, 11487}}, {2, {11486, 11487}}, {2, {11488, 11489}}, {2, {11488, 11489}}, {2, {11490, 11491}}, {2, {11490, 11491}}, {2, {4256, 11520}}, {2, {4257, 11521}}, {2, {4258, 11522}}, {2, {4259, 11523}}, {2, {4260, 11524}}, {2, {4261, 11525}}, {2, {4262, 11526}}, {2, {4263, 11527}}, {2, {4264, 11528}}, {2, {4265, 11529}}, {2, {4266, 11530}}, {2, {4267, 11531}}, {2, {4268, 11532}}, {2, {4269, 11533}}, {2, {4270, 11534}}, {2, {4271, 11535}}, {2, {4272, 11536}}, {2, {4273, 11537}}, {2, {4274, 11538}}, {2, {4275, 11539}}, {2, {4276, 11540}}, {2, {4277, 11541}}, {2, {4278, 11542}}, {2, {4279, 11543}}, {2, {4280, 11544}}, {2, {4281, 11545}}, {2, {4282, 11546}}, {2, {4283, 11547}}, {2, {4284, 11548}}, {2, {4285, 11549}}, {2, {4286, 11550}}, {2, {4287, 11551}}, {2, {4288, 11552}}, {2, {4289, 11553}}, {2, {4290, 11554}}, {2, {4291, 11555}}, {2, {4292, 11556}}, {2, {4293, 11557}}, {0, {0}} }; // NOLINT
+static const uint16_t kEcma262UnCanonicalizeTable0Size = 1656;
+static const int32_t kEcma262UnCanonicalizeTable0[3312] = { 65, 1, 66, 5, 67, 9, 68, 13, 69, 17, 70, 21, 71, 25, 72, 29, 73, 33, 74, 37, 75, 41, 76, 45, 77, 49, 78, 53, 79, 57, 80, 61, 81, 65, 82, 69, 83, 73, 84, 77, 85, 81, 86, 85, 87, 89, 88, 93, 89, 97, 90, 101, 97, 105, 98, 109, 99, 113, 100, 117, 101, 121, 102, 125, 103, 129, 104, 133, 105, 137, 106, 141, 107, 145, 108, 149, 109, 153, 110, 157, 111, 161, 112, 165, 113, 169, 114, 173, 115, 177, 116, 181, 117, 185, 118, 189, 119, 193, 120, 197, 121, 201, 122, 205, 181, 209, 192, 213, 193, 217, 194, 221, 195, 225, 196, 229, 197, 233, 198, 237, 199, 241, 200, 245, 201, 249, 202, 253, 203, 257, 204, 261, 205, 265, 206, 269, 207, 273, 208, 277, 209, 281, 210, 285, 211, 289, 212, 293, 213, 297, 214, 301, 216, 305, 217, 309, 218, 313, 219, 317, 220, 321, 221, 325, 222, 329, 224, 333, 225, 337, 226, 341, 227, 345, 228, 349, 229, 353, 230, 357, 231, 361, 232, 365, 233, 369, 234, 373, 235, 377, 236, 381, 237, 385, 238, 389, 239, 393, 240, 397, 241, 401, 242, 405, 243, 409, 244, 413, 245, 417, 246, 421, 248, 425, 249, 429, 250, 433, 251, 437, 252, 441, 253, 445, 254, 449, 255, 453, 256, 457, 257, 461, 258, 465, 259, 469, 260, 473, 261, 477, 262, 481, 263, 485, 264, 489, 265, 493, 266, 497, 267, 501, 268, 505, 269, 509, 270, 513, 271, 517, 272, 521, 273, 525, 274, 529, 275, 533, 276, 537, 277, 541, 278, 545, 279, 549, 280, 553, 281, 557, 282, 561, 283, 565, 284, 569, 285, 573, 286, 577, 287, 581, 288, 585, 289, 589, 290, 593, 291, 597, 292, 601, 293, 605, 294, 609, 295, 613, 296, 617, 297, 621, 298, 625, 299, 629, 300, 633, 301, 637, 302, 641, 303, 645, 306, 649, 307, 653, 308, 657, 309, 661, 310, 665, 311, 669, 313, 673, 314, 677, 315, 681, 316, 685, 317, 689, 318, 693, 319, 697, 320, 701, 321, 705, 322, 709, 323, 713, 324, 717, 325, 721, 326, 725, 327, 729, 328, 733, 330, 737, 331, 741, 332, 745, 333, 749, 334, 753, 335, 757, 336, 761, 337, 765, 338, 769, 339, 773, 340, 777, 341, 781, 342, 785, 343, 789, 344, 793, 345, 797, 346, 801, 347, 805, 348, 809, 349, 813, 350, 817, 351, 821, 352, 825, 353, 829, 354, 833, 355, 837, 356, 841, 357, 845, 358, 849, 359, 853, 360, 857, 361, 861, 362, 865, 363, 869, 364, 873, 365, 877, 366, 881, 367, 885, 368, 889, 369, 893, 370, 897, 371, 901, 372, 905, 373, 909, 374, 913, 375, 917, 376, 921, 377, 925, 378, 929, 379, 933, 380, 937, 381, 941, 382, 945, 384, 949, 385, 953, 386, 957, 387, 961, 388, 965, 389, 969, 390, 973, 391, 977, 392, 981, 393, 985, 394, 989, 395, 993, 396, 997, 398, 1001, 399, 1005, 400, 1009, 401, 1013, 402, 1017, 403, 1021, 404, 1025, 405, 1029, 406, 1033, 407, 1037, 408, 1041, 409, 1045, 410, 1049, 412, 1053, 413, 1057, 414, 1061, 415, 1065, 416, 1069, 417, 1073, 418, 1077, 419, 1081, 420, 1085, 421, 1089, 422, 1093, 423, 1097, 424, 1101, 425, 1105, 428, 1109, 429, 1113, 430, 1117, 431, 1121, 432, 1125, 433, 1129, 434, 1133, 435, 1137, 436, 1141, 437, 1145, 438, 1149, 439, 1153, 440, 1157, 441, 1161, 444, 1165, 445, 1169, 447, 1173, 452, 1177, 453, 1181, 454, 1185, 455, 1189, 456, 1193, 457, 1197, 458, 1201, 459, 1205, 460, 1209, 461, 1213, 462, 1217, 463, 1221, 464, 1225, 465, 1229, 466, 1233, 467, 1237, 468, 1241, 469, 1245, 470, 1249, 471, 1253, 472, 1257, 473, 1261, 474, 1265, 475, 1269, 476, 1273, 477, 1277, 478, 1281, 479, 1285, 480, 1289, 481, 1293, 482, 1297, 483, 1301, 484, 1305, 485, 1309, 486, 1313, 487, 1317, 488, 1321, 489, 1325, 490, 1329, 491, 1333, 492, 1337, 493, 1341, 494, 1345, 495, 1349, 497, 1353, 498, 1357, 499, 1361, 500, 1365, 501, 1369, 502, 1373, 503, 1377, 504, 1381, 505, 1385, 506, 1389, 507, 1393, 508, 1397, 509, 1401, 510, 1405, 511, 1409, 512, 1413, 513, 1417, 514, 1421, 515, 1425, 516, 1429, 517, 1433, 518, 1437, 519, 1441, 520, 1445, 521, 1449, 522, 1453, 523, 1457, 524, 1461, 525, 1465, 526, 1469, 527, 1473, 528, 1477, 529, 1481, 530, 1485, 531, 1489, 532, 1493, 533, 1497, 534, 1501, 535, 1505, 536, 1509, 537, 1513, 538, 1517, 539, 1521, 540, 1525, 541, 1529, 542, 1533, 543, 1537, 544, 1541, 546, 1545, 547, 1549, 548, 1553, 549, 1557, 550, 1561, 551, 1565, 552, 1569, 553, 1573, 554, 1577, 555, 1581, 556, 1585, 557, 1589, 558, 1593, 559, 1597, 560, 1601, 561, 1605, 562, 1609, 563, 1613, 570, 1617, 571, 1621, 572, 1625, 573, 1629, 574, 1633, 577, 1637, 578, 1641, 579, 1645, 580, 1649, 581, 1653, 582, 1657, 583, 1661, 584, 1665, 585, 1669, 586, 1673, 587, 1677, 588, 1681, 589, 1685, 590, 1689, 591, 1693, 595, 1697, 596, 1701, 598, 1705, 599, 1709, 601, 1713, 603, 1717, 608, 1721, 611, 1725, 616, 1729, 617, 1733, 619, 1737, 623, 1741, 626, 1745, 629, 1749, 637, 1753, 640, 1757, 643, 1761, 648, 1765, 649, 1769, 650, 1773, 651, 1777, 652, 1781, 658, 1785, 837, 1789, 891, 1793, 892, 1797, 893, 1801, 902, 1805, 904, 1809, 905, 1813, 906, 1817, 908, 1821, 910, 1825, 911, 1829, 913, 1833, 914, 1837, 915, 1841, 916, 1845, 917, 1849, 918, 1853, 919, 1857, 920, 1861, 921, 1865, 922, 1869, 923, 1873, 924, 1877, 925, 1881, 926, 1885, 927, 1889, 928, 1893, 929, 1897, 931, 1901, 932, 1905, 933, 1909, 934, 1913, 935, 1917, 936, 1921, 937, 1925, 938, 1929, 939, 1933, 940, 1937, 941, 1941, 942, 1945, 943, 1949, 945, 1953, 946, 1957, 947, 1961, 948, 1965, 949, 1969, 950, 1973, 951, 1977, 952, 1981, 953, 1985, 954, 1989, 955, 1993, 956, 1997, 957, 2001, 958, 2005, 959, 2009, 960, 2013, 961, 2017, 962, 2021, 963, 2025, 964, 2029, 965, 2033, 966, 2037, 967, 2041, 968, 2045, 969, 2049, 970, 2053, 971, 2057, 972, 2061, 973, 2065, 974, 2069, 976, 2073, 977, 2077, 981, 2081, 982, 2085, 984, 2089, 985, 2093, 986, 2097, 987, 2101, 988, 2105, 989, 2109, 990, 2113, 991, 2117, 992, 2121, 993, 2125, 994, 2129, 995, 2133, 996, 2137, 997, 2141, 998, 2145, 999, 2149, 1000, 2153, 1001, 2157, 1002, 2161, 1003, 2165, 1004, 2169, 1005, 2173, 1006, 2177, 1007, 2181, 1008, 2185, 1009, 2189, 1010, 2193, 1013, 2197, 1015, 2201, 1016, 2205, 1017, 2209, 1018, 2213, 1019, 2217, 1021, 2221, 1022, 2225, 1023, 2229, 1024, 2233, 1025, 2237, 1026, 2241, 1027, 2245, 1028, 2249, 1029, 2253, 1030, 2257, 1031, 2261, 1032, 2265, 1033, 2269, 1034, 2273, 1035, 2277, 1036, 2281, 1037, 2285, 1038, 2289, 1039, 2293, 1040, 2297, 1041, 2301, 1042, 2305, 1043, 2309, 1044, 2313, 1045, 2317, 1046, 2321, 1047, 2325, 1048, 2329, 1049, 2333, 1050, 2337, 1051, 2341, 1052, 2345, 1053, 2349, 1054, 2353, 1055, 2357, 1056, 2361, 1057, 2365, 1058, 2369, 1059, 2373, 1060, 2377, 1061, 2381, 1062, 2385, 1063, 2389, 1064, 2393, 1065, 2397, 1066, 2401, 1067, 2405, 1068, 2409, 1069, 2413, 1070, 2417, 1071, 2421, 1072, 2425, 1073, 2429, 1074, 2433, 1075, 2437, 1076, 2441, 1077, 2445, 1078, 2449, 1079, 2453, 1080, 2457, 1081, 2461, 1082, 2465, 1083, 2469, 1084, 2473, 1085, 2477, 1086, 2481, 1087, 2485, 1088, 2489, 1089, 2493, 1090, 2497, 1091, 2501, 1092, 2505, 1093, 2509, 1094, 2513, 1095, 2517, 1096, 2521, 1097, 2525, 1098, 2529, 1099, 2533, 1100, 2537, 1101, 2541, 1102, 2545, 1103, 2549, 1104, 2553, 1105, 2557, 1106, 2561, 1107, 2565, 1108, 2569, 1109, 2573, 1110, 2577, 1111, 2581, 1112, 2585, 1113, 2589, 1114, 2593, 1115, 2597, 1116, 2601, 1117, 2605, 1118, 2609, 1119, 2613, 1120, 2617, 1121, 2621, 1122, 2625, 1123, 2629, 1124, 2633, 1125, 2637, 1126, 2641, 1127, 2645, 1128, 2649, 1129, 2653, 1130, 2657, 1131, 2661, 1132, 2665, 1133, 2669, 1134, 2673, 1135, 2677, 1136, 2681, 1137, 2685, 1138, 2689, 1139, 2693, 1140, 2697, 1141, 2701, 1142, 2705, 1143, 2709, 1144, 2713, 1145, 2717, 1146, 2721, 1147, 2725, 1148, 2729, 1149, 2733, 1150, 2737, 1151, 2741, 1152, 2745, 1153, 2749, 1162, 2753, 1163, 2757, 1164, 2761, 1165, 2765, 1166, 2769, 1167, 2773, 1168, 2777, 1169, 2781, 1170, 2785, 1171, 2789, 1172, 2793, 1173, 2797, 1174, 2801, 1175, 2805, 1176, 2809, 1177, 2813, 1178, 2817, 1179, 2821, 1180, 2825, 1181, 2829, 1182, 2833, 1183, 2837, 1184, 2841, 1185, 2845, 1186, 2849, 1187, 2853, 1188, 2857, 1189, 2861, 1190, 2865, 1191, 2869, 1192, 2873, 1193, 2877, 1194, 2881, 1195, 2885, 1196, 2889, 1197, 2893, 1198, 2897, 1199, 2901, 1200, 2905, 1201, 2909, 1202, 2913, 1203, 2917, 1204, 2921, 1205, 2925, 1206, 2929, 1207, 2933, 1208, 2937, 1209, 2941, 1210, 2945, 1211, 2949, 1212, 2953, 1213, 2957, 1214, 2961, 1215, 2965, 1216, 2969, 1217, 2973, 1218, 2977, 1219, 2981, 1220, 2985, 1221, 2989, 1222, 2993, 1223, 2997, 1224, 3001, 1225, 3005, 1226, 3009, 1227, 3013, 1228, 3017, 1229, 3021, 1230, 3025, 1231, 3029, 1232, 3033, 1233, 3037, 1234, 3041, 1235, 3045, 1236, 3049, 1237, 3053, 1238, 3057, 1239, 3061, 1240, 3065, 1241, 3069, 1242, 3073, 1243, 3077, 1244, 3081, 1245, 3085, 1246, 3089, 1247, 3093, 1248, 3097, 1249, 3101, 1250, 3105, 1251, 3109, 1252, 3113, 1253, 3117, 1254, 3121, 1255, 3125, 1256, 3129, 1257, 3133, 1258, 3137, 1259, 3141, 1260, 3145, 1261, 3149, 1262, 3153, 1263, 3157, 1264, 3161, 1265, 3165, 1266, 3169, 1267, 3173, 1268, 3177, 1269, 3181, 1270, 3185, 1271, 3189, 1272, 3193, 1273, 3197, 1274, 3201, 1275, 3205, 1276, 3209, 1277, 3213, 1278, 3217, 1279, 3221, 1280, 3225, 1281, 3229, 1282, 3233, 1283, 3237, 1284, 3241, 1285, 3245, 1286, 3249, 1287, 3253, 1288, 3257, 1289, 3261, 1290, 3265, 1291, 3269, 1292, 3273, 1293, 3277, 1294, 3281, 1295, 3285, 1296, 3289, 1297, 3293, 1298, 3297, 1299, 3301, 1329, 3305, 1330, 3309, 1331, 3313, 1332, 3317, 1333, 3321, 1334, 3325, 1335, 3329, 1336, 3333, 1337, 3337, 1338, 3341, 1339, 3345, 1340, 3349, 1341, 3353, 1342, 3357, 1343, 3361, 1344, 3365, 1345, 3369, 1346, 3373, 1347, 3377, 1348, 3381, 1349, 3385, 1350, 3389, 1351, 3393, 1352, 3397, 1353, 3401, 1354, 3405, 1355, 3409, 1356, 3413, 1357, 3417, 1358, 3421, 1359, 3425, 1360, 3429, 1361, 3433, 1362, 3437, 1363, 3441, 1364, 3445, 1365, 3449, 1366, 3453, 1377, 3457, 1378, 3461, 1379, 3465, 1380, 3469, 1381, 3473, 1382, 3477, 1383, 3481, 1384, 3485, 1385, 3489, 1386, 3493, 1387, 3497, 1388, 3501, 1389, 3505, 1390, 3509, 1391, 3513, 1392, 3517, 1393, 3521, 1394, 3525, 1395, 3529, 1396, 3533, 1397, 3537, 1398, 3541, 1399, 3545, 1400, 3549, 1401, 3553, 1402, 3557, 1403, 3561, 1404, 3565, 1405, 3569, 1406, 3573, 1407, 3577, 1408, 3581, 1409, 3585, 1410, 3589, 1411, 3593, 1412, 3597, 1413, 3601, 1414, 3605, 4256, 3609, 4257, 3613, 4258, 3617, 4259, 3621, 4260, 3625, 4261, 3629, 4262, 3633, 4263, 3637, 4264, 3641, 4265, 3645, 4266, 3649, 4267, 3653, 4268, 3657, 4269, 3661, 4270, 3665, 4271, 3669, 4272, 3673, 4273, 3677, 4274, 3681, 4275, 3685, 4276, 3689, 4277, 3693, 4278, 3697, 4279, 3701, 4280, 3705, 4281, 3709, 4282, 3713, 4283, 3717, 4284, 3721, 4285, 3725, 4286, 3729, 4287, 3733, 4288, 3737, 4289, 3741, 4290, 3745, 4291, 3749, 4292, 3753, 4293, 3757, 7549, 3761, 7680, 3765, 7681, 3769, 7682, 3773, 7683, 3777, 7684, 3781, 7685, 3785, 7686, 3789, 7687, 3793, 7688, 3797, 7689, 3801, 7690, 3805, 7691, 3809, 7692, 3813, 7693, 3817, 7694, 3821, 7695, 3825, 7696, 3829, 7697, 3833, 7698, 3837, 7699, 3841, 7700, 3845, 7701, 3849, 7702, 3853, 7703, 3857, 7704, 3861, 7705, 3865, 7706, 3869, 7707, 3873, 7708, 3877, 7709, 3881, 7710, 3885, 7711, 3889, 7712, 3893, 7713, 3897, 7714, 3901, 7715, 3905, 7716, 3909, 7717, 3913, 7718, 3917, 7719, 3921, 7720, 3925, 7721, 3929, 7722, 3933, 7723, 3937, 7724, 3941, 7725, 3945, 7726, 3949, 7727, 3953, 7728, 3957, 7729, 3961, 7730, 3965, 7731, 3969, 7732, 3973, 7733, 3977, 7734, 3981, 7735, 3985, 7736, 3989, 7737, 3993, 7738, 3997, 7739, 4001, 7740, 4005, 7741, 4009, 7742, 4013, 7743, 4017, 7744, 4021, 7745, 4025, 7746, 4029, 7747, 4033, 7748, 4037, 7749, 4041, 7750, 4045, 7751, 4049, 7752, 4053, 7753, 4057, 7754, 4061, 7755, 4065, 7756, 4069, 7757, 4073, 7758, 4077, 7759, 4081, 7760, 4085, 7761, 4089, 7762, 4093, 7763, 4097, 7764, 4101, 7765, 4105, 7766, 4109, 7767, 4113, 7768, 4117, 7769, 4121, 7770, 4125, 7771, 4129, 7772, 4133, 7773, 4137, 7774, 4141, 7775, 4145, 7776, 4149, 7777, 4153, 7778, 4157, 7779, 4161, 7780, 4165, 7781, 4169, 7782, 4173, 7783, 4177, 7784, 4181, 7785, 4185, 7786, 4189, 7787, 4193, 7788, 4197, 7789, 4201, 7790, 4205, 7791, 4209, 7792, 4213, 7793, 4217, 7794, 4221, 7795, 4225, 7796, 4229, 7797, 4233, 7798, 4237, 7799, 4241, 7800, 4245, 7801, 4249, 7802, 4253, 7803, 4257, 7804, 4261, 7805, 4265, 7806, 4269, 7807, 4273, 7808, 4277, 7809, 4281, 7810, 4285, 7811, 4289, 7812, 4293, 7813, 4297, 7814, 4301, 7815, 4305, 7816, 4309, 7817, 4313, 7818, 4317, 7819, 4321, 7820, 4325, 7821, 4329, 7822, 4333, 7823, 4337, 7824, 4341, 7825, 4345, 7826, 4349, 7827, 4353, 7828, 4357, 7829, 4361, 7835, 4365, 7840, 4369, 7841, 4373, 7842, 4377, 7843, 4381, 7844, 4385, 7845, 4389, 7846, 4393, 7847, 4397, 7848, 4401, 7849, 4405, 7850, 4409, 7851, 4413, 7852, 4417, 7853, 4421, 7854, 4425, 7855, 4429, 7856, 4433, 7857, 4437, 7858, 4441, 7859, 4445, 7860, 4449, 7861, 4453, 7862, 4457, 7863, 4461, 7864, 4465, 7865, 4469, 7866, 4473, 7867, 4477, 7868, 4481, 7869, 4485, 7870, 4489, 7871, 4493, 7872, 4497, 7873, 4501, 7874, 4505, 7875, 4509, 7876, 4513, 7877, 4517, 7878, 4521, 7879, 4525, 7880, 4529, 7881, 4533, 7882, 4537, 7883, 4541, 7884, 4545, 7885, 4549, 7886, 4553, 7887, 4557, 7888, 4561, 7889, 4565, 7890, 4569, 7891, 4573, 7892, 4577, 7893, 4581, 7894, 4585, 7895, 4589, 7896, 4593, 7897, 4597, 7898, 4601, 7899, 4605, 7900, 4609, 7901, 4613, 7902, 4617, 7903, 4621, 7904, 4625, 7905, 4629, 7906, 4633, 7907, 4637, 7908, 4641, 7909, 4645, 7910, 4649, 7911, 4653, 7912, 4657, 7913, 4661, 7914, 4665, 7915, 4669, 7916, 4673, 7917, 4677, 7918, 4681, 7919, 4685, 7920, 4689, 7921, 4693, 7922, 4697, 7923, 4701, 7924, 4705, 7925, 4709, 7926, 4713, 7927, 4717, 7928, 4721, 7929, 4725, 7936, 4729, 7937, 4733, 7938, 4737, 7939, 4741, 7940, 4745, 7941, 4749, 7942, 4753, 7943, 4757, 7944, 4761, 7945, 4765, 7946, 4769, 7947, 4773, 7948, 4777, 7949, 4781, 7950, 4785, 7951, 4789, 7952, 4793, 7953, 4797, 7954, 4801, 7955, 4805, 7956, 4809, 7957, 4813, 7960, 4817, 7961, 4821, 7962, 4825, 7963, 4829, 7964, 4833, 7965, 4837, 7968, 4841, 7969, 4845, 7970, 4849, 7971, 4853, 7972, 4857, 7973, 4861, 7974, 4865, 7975, 4869, 7976, 4873, 7977, 4877, 7978, 4881, 7979, 4885, 7980, 4889, 7981, 4893, 7982, 4897, 7983, 4901, 7984, 4905, 7985, 4909, 7986, 4913, 7987, 4917, 7988, 4921, 7989, 4925, 7990, 4929, 7991, 4933, 7992, 4937, 7993, 4941, 7994, 4945, 7995, 4949, 7996, 4953, 7997, 4957, 7998, 4961, 7999, 4965, 8000, 4969, 8001, 4973, 8002, 4977, 8003, 4981, 8004, 4985, 8005, 4989, 8008, 4993, 8009, 4997, 8010, 5001, 8011, 5005, 8012, 5009, 8013, 5013, 8017, 5017, 8019, 5021, 8021, 5025, 8023, 5029, 8025, 5033, 8027, 5037, 8029, 5041, 8031, 5045, 8032, 5049, 8033, 5053, 8034, 5057, 8035, 5061, 8036, 5065, 8037, 5069, 8038, 5073, 8039, 5077, 8040, 5081, 8041, 5085, 8042, 5089, 8043, 5093, 8044, 5097, 8045, 5101, 8046, 5105, 8047, 5109, 8048, 5113, 8049, 5117, 8050, 5121, 8051, 5125, 8052, 5129, 8053, 5133, 8054, 5137, 8055, 5141, 8056, 5145, 8057, 5149, 8058, 5153, 8059, 5157, 8060, 5161, 8061, 5165, 8112, 5169, 8113, 5173, 8120, 5177, 8121, 5181, 8122, 5185, 8123, 5189, 8126, 5193, 8136, 5197, 8137, 5201, 8138, 5205, 8139, 5209, 8144, 5213, 8145, 5217, 8152, 5221, 8153, 5225, 8154, 5229, 8155, 5233, 8160, 5237, 8161, 5241, 8165, 5245, 8168, 5249, 8169, 5253, 8170, 5257, 8171, 5261, 8172, 5265, 8184, 5269, 8185, 5273, 8186, 5277, 8187, 5281, 8498, 5285, 8526, 5289, 8544, 5293, 8545, 5297, 8546, 5301, 8547, 5305, 8548, 5309, 8549, 5313, 8550, 5317, 8551, 5321, 8552, 5325, 8553, 5329, 8554, 5333, 8555, 5337, 8556, 5341, 8557, 5345, 8558, 5349, 8559, 5353, 8560, 5357, 8561, 5361, 8562, 5365, 8563, 5369, 8564, 5373, 8565, 5377, 8566, 5381, 8567, 5385, 8568, 5389, 8569, 5393, 8570, 5397, 8571, 5401, 8572, 5405, 8573, 5409, 8574, 5413, 8575, 5417, 8579, 5421, 8580, 5425, 9398, 5429, 9399, 5433, 9400, 5437, 9401, 5441, 9402, 5445, 9403, 5449, 9404, 5453, 9405, 5457, 9406, 5461, 9407, 5465, 9408, 5469, 9409, 5473, 9410, 5477, 9411, 5481, 9412, 5485, 9413, 5489, 9414, 5493, 9415, 5497, 9416, 5501, 9417, 5505, 9418, 5509, 9419, 5513, 9420, 5517, 9421, 5521, 9422, 5525, 9423, 5529, 9424, 5533, 9425, 5537, 9426, 5541, 9427, 5545, 9428, 5549, 9429, 5553, 9430, 5557, 9431, 5561, 9432, 5565, 9433, 5569, 9434, 5573, 9435, 5577, 9436, 5581, 9437, 5585, 9438, 5589, 9439, 5593, 9440, 5597, 9441, 5601, 9442, 5605, 9443, 5609, 9444, 5613, 9445, 5617, 9446, 5621, 9447, 5625, 9448, 5629, 9449, 5633, 11264, 5637, 11265, 5641, 11266, 5645, 11267, 5649, 11268, 5653, 11269, 5657, 11270, 5661, 11271, 5665, 11272, 5669, 11273, 5673, 11274, 5677, 11275, 5681, 11276, 5685, 11277, 5689, 11278, 5693, 11279, 5697, 11280, 5701, 11281, 5705, 11282, 5709, 11283, 5713, 11284, 5717, 11285, 5721, 11286, 5725, 11287, 5729, 11288, 5733, 11289, 5737, 11290, 5741, 11291, 5745, 11292, 5749, 11293, 5753, 11294, 5757, 11295, 5761, 11296, 5765, 11297, 5769, 11298, 5773, 11299, 5777, 11300, 5781, 11301, 5785, 11302, 5789, 11303, 5793, 11304, 5797, 11305, 5801, 11306, 5805, 11307, 5809, 11308, 5813, 11309, 5817, 11310, 5821, 11312, 5825, 11313, 5829, 11314, 5833, 11315, 5837, 11316, 5841, 11317, 5845, 11318, 5849, 11319, 5853, 11320, 5857, 11321, 5861, 11322, 5865, 11323, 5869, 11324, 5873, 11325, 5877, 11326, 5881, 11327, 5885, 11328, 5889, 11329, 5893, 11330, 5897, 11331, 5901, 11332, 5905, 11333, 5909, 11334, 5913, 11335, 5917, 11336, 5921, 11337, 5925, 11338, 5929, 11339, 5933, 11340, 5937, 11341, 5941, 11342, 5945, 11343, 5949, 11344, 5953, 11345, 5957, 11346, 5961, 11347, 5965, 11348, 5969, 11349, 5973, 11350, 5977, 11351, 5981, 11352, 5985, 11353, 5989, 11354, 5993, 11355, 5997, 11356, 6001, 11357, 6005, 11358, 6009, 11360, 6013, 11361, 6017, 11362, 6021, 11363, 6025, 11364, 6029, 11365, 6033, 11366, 6037, 11367, 6041, 11368, 6045, 11369, 6049, 11370, 6053, 11371, 6057, 11372, 6061, 11381, 6065, 11382, 6069, 11392, 6073, 11393, 6077, 11394, 6081, 11395, 6085, 11396, 6089, 11397, 6093, 11398, 6097, 11399, 6101, 11400, 6105, 11401, 6109, 11402, 6113, 11403, 6117, 11404, 6121, 11405, 6125, 11406, 6129, 11407, 6133, 11408, 6137, 11409, 6141, 11410, 6145, 11411, 6149, 11412, 6153, 11413, 6157, 11414, 6161, 11415, 6165, 11416, 6169, 11417, 6173, 11418, 6177, 11419, 6181, 11420, 6185, 11421, 6189, 11422, 6193, 11423, 6197, 11424, 6201, 11425, 6205, 11426, 6209, 11427, 6213, 11428, 6217, 11429, 6221, 11430, 6225, 11431, 6229, 11432, 6233, 11433, 6237, 11434, 6241, 11435, 6245, 11436, 6249, 11437, 6253, 11438, 6257, 11439, 6261, 11440, 6265, 11441, 6269, 11442, 6273, 11443, 6277, 11444, 6281, 11445, 6285, 11446, 6289, 11447, 6293, 11448, 6297, 11449, 6301, 11450, 6305, 11451, 6309, 11452, 6313, 11453, 6317, 11454, 6321, 11455, 6325, 11456, 6329, 11457, 6333, 11458, 6337, 11459, 6341, 11460, 6345, 11461, 6349, 11462, 6353, 11463, 6357, 11464, 6361, 11465, 6365, 11466, 6369, 11467, 6373, 11468, 6377, 11469, 6381, 11470, 6385, 11471, 6389, 11472, 6393, 11473, 6397, 11474, 6401, 11475, 6405, 11476, 6409, 11477, 6413, 11478, 6417, 11479, 6421, 11480, 6425, 11481, 6429, 11482, 6433, 11483, 6437, 11484, 6441, 11485, 6445, 11486, 6449, 11487, 6453, 11488, 6457, 11489, 6461, 11490, 6465, 11491, 6469, 11520, 6473, 11521, 6477, 11522, 6481, 11523, 6485, 11524, 6489, 11525, 6493, 11526, 6497, 11527, 6501, 11528, 6505, 11529, 6509, 11530, 6513, 11531, 6517, 11532, 6521, 11533, 6525, 11534, 6529, 11535, 6533, 11536, 6537, 11537, 6541, 11538, 6545, 11539, 6549, 11540, 6553, 11541, 6557, 11542, 6561, 11543, 6565, 11544, 6569, 11545, 6573, 11546, 6577, 11547, 6581, 11548, 6585, 11549, 6589, 11550, 6593, 11551, 6597, 11552, 6601, 11553, 6605, 11554, 6609, 11555, 6613, 11556, 6617, 11557, 6621 }; // NOLINT
+static const MultiCharacterSpecialCase<4> kEcma262UnCanonicalizeMultiStrings1[] = { {2, {65313, 65345}}, {2, {65314, 65346}}, {2, {65315, 65347}}, {2, {65316, 65348}}, {2, {65317, 65349}}, {2, {65318, 65350}}, {2, {65319, 65351}}, {2, {65320, 65352}}, {2, {65321, 65353}}, {2, {65322, 65354}}, {2, {65323, 65355}}, {2, {65324, 65356}}, {2, {65325, 65357}}, {2, {65326, 65358}}, {2, {65327, 65359}}, {2, {65328, 65360}}, {2, {65329, 65361}}, {2, {65330, 65362}}, {2, {65331, 65363}}, {2, {65332, 65364}}, {2, {65333, 65365}}, {2, {65334, 65366}}, {2, {65335, 65367}}, {2, {65336, 65368}}, {2, {65337, 65369}}, {2, {65338, 65370}}, {2, {65313, 65345}}, {2, {65314, 65346}}, {2, {65315, 65347}}, {2, {65316, 65348}}, {2, {65317, 65349}}, {2, {65318, 65350}}, {2, {65319, 65351}}, {2, {65320, 65352}}, {2, {65321, 65353}}, {2, {65322, 65354}}, {2, {65323, 65355}}, {2, {65324, 65356}}, {2, {65325, 65357}}, {2, {65326, 65358}}, {2, {65327, 65359}}, {2, {65328, 65360}}, {2, {65329, 65361}}, {2, {65330, 65362}}, {2, {65331, 65363}}, {2, {65332, 65364}}, {2, {65333, 65365}}, {2, {65334, 65366}}, {2, {65335, 65367}}, {2, {65336, 65368}}, {2, {65337, 65369}}, {2, {65338, 65370}}, {0, {0}} }; // NOLINT
+static const uint16_t kEcma262UnCanonicalizeTable1Size = 52;
+static const int32_t kEcma262UnCanonicalizeTable1[104] = { 32545, 1, 32546, 5, 32547, 9, 32548, 13, 32549, 17, 32550, 21, 32551, 25, 32552, 29, 32553, 33, 32554, 37, 32555, 41, 32556, 45, 32557, 49, 32558, 53, 32559, 57, 32560, 61, 32561, 65, 32562, 69, 32563, 73, 32564, 77, 32565, 81, 32566, 85, 32567, 89, 32568, 93, 32569, 97, 32570, 101, 32577, 105, 32578, 109, 32579, 113, 32580, 117, 32581, 121, 32582, 125, 32583, 129, 32584, 133, 32585, 137, 32586, 141, 32587, 145, 32588, 149, 32589, 153, 32590, 157, 32591, 161, 32592, 165, 32593, 169, 32594, 173, 32595, 177, 32596, 181, 32597, 185, 32598, 189, 32599, 193, 32600, 197, 32601, 201, 32602, 205 }; // NOLINT
+static const MultiCharacterSpecialCase<4> kEcma262UnCanonicalizeMultiStrings2[] = { {2, {66560, 66600}}, {2, {66561, 66601}}, {2, {66562, 66602}}, {2, {66563, 66603}}, {2, {66564, 66604}}, {2, {66565, 66605}}, {2, {66566, 66606}}, {2, {66567, 66607}}, {2, {66568, 66608}}, {2, {66569, 66609}}, {2, {66570, 66610}}, {2, {66571, 66611}}, {2, {66572, 66612}}, {2, {66573, 66613}}, {2, {66574, 66614}}, {2, {66575, 66615}}, {2, {66576, 66616}}, {2, {66577, 66617}}, {2, {66578, 66618}}, {2, {66579, 66619}}, {2, {66580, 66620}}, {2, {66581, 66621}}, {2, {66582, 66622}}, {2, {66583, 66623}}, {2, {66584, 66624}}, {2, {66585, 66625}}, {2, {66586, 66626}}, {2, {66587, 66627}}, {2, {66588, 66628}}, {2, {66589, 66629}}, {2, {66590, 66630}}, {2, {66591, 66631}}, {2, {66592, 66632}}, {2, {66593, 66633}}, {2, {66594, 66634}}, {2, {66595, 66635}}, {2, {66596, 66636}}, {2, {66597, 66637}}, {2, {66598, 66638}}, {2, {66599, 66639}}, {2, {66560, 66600}}, {2, {66561, 66601}}, {2, {66562, 66602}}, {2, {66563, 66603}}, {2, {66564, 66604}}, {2, {66565, 66605}}, {2, {66566, 66606}}, {2, {66567, 66607}}, {2, {66568, 66608}}, {2, {66569, 66609}}, {2, {66570, 66610}}, {2, {66571, 66611}}, {2, {66572, 66612}}, {2, {66573, 66613}}, {2, {66574, 66614}}, {2, {66575, 66615}}, {2, {66576, 66616}}, {2, {66577, 66617}}, {2, {66578, 66618}}, {2, {66579, 66619}}, {2, {66580, 66620}}, {2, {66581, 66621}}, {2, {66582, 66622}}, {2, {66583, 66623}}, {2, {66584, 66624}}, {2, {66585, 66625}}, {2, {66586, 66626}}, {2, {66587, 66627}}, {2, {66588, 66628}}, {2, {66589, 66629}}, {2, {66590, 66630}}, {2, {66591, 66631}}, {2, {66592, 66632}}, {2, {66593, 66633}}, {2, {66594, 66634}}, {2, {66595, 66635}}, {2, {66596, 66636}}, {2, {66597, 66637}}, {2, {66598, 66638}}, {2, {66599, 66639}}, {0, {0}} }; // NOLINT
+static const uint16_t kEcma262UnCanonicalizeTable2Size = 80;
+static const int32_t kEcma262UnCanonicalizeTable2[160] = { 1024, 1, 1025, 5, 1026, 9, 1027, 13, 1028, 17, 1029, 21, 1030, 25, 1031, 29, 1032, 33, 1033, 37, 1034, 41, 1035, 45, 1036, 49, 1037, 53, 1038, 57, 1039, 61, 1040, 65, 1041, 69, 1042, 73, 1043, 77, 1044, 81, 1045, 85, 1046, 89, 1047, 93, 1048, 97, 1049, 101, 1050, 105, 1051, 109, 1052, 113, 1053, 117, 1054, 121, 1055, 125, 1056, 129, 1057, 133, 1058, 137, 1059, 141, 1060, 145, 1061, 149, 1062, 153, 1063, 157, 1064, 161, 1065, 165, 1066, 169, 1067, 173, 1068, 177, 1069, 181, 1070, 185, 1071, 189, 1072, 193, 1073, 197, 1074, 201, 1075, 205, 1076, 209, 1077, 213, 1078, 217, 1079, 221, 1080, 225, 1081, 229, 1082, 233, 1083, 237, 1084, 241, 1085, 245, 1086, 249, 1087, 253, 1088, 257, 1089, 261, 1090, 265, 1091, 269, 1092, 273, 1093, 277, 1094, 281, 1095, 285, 1096, 289, 1097, 293, 1098, 297, 1099, 301, 1100, 305, 1101, 309, 1102, 313, 1103, 317 }; // NOLINT
+int Ecma262UnCanonicalize::Convert(uchar c,
+ uchar n,
+ uchar* result,
+ bool* allow_caching_ptr) {
+ int chunk_index = c >> 15;
+ switch (chunk_index) {
+ case 0: return LookupMapping(kEcma262UnCanonicalizeTable0,
+ kEcma262UnCanonicalizeTable0Size,
+ kEcma262UnCanonicalizeMultiStrings0,
+ c,
+ n,
+ result,
+ allow_caching_ptr);
+ case 1: return LookupMapping(kEcma262UnCanonicalizeTable1,
+ kEcma262UnCanonicalizeTable1Size,
+ kEcma262UnCanonicalizeMultiStrings1,
+ c,
+ n,
+ result,
+ allow_caching_ptr);
+ case 2: return LookupMapping(kEcma262UnCanonicalizeTable2,
+ kEcma262UnCanonicalizeTable2Size,
+ kEcma262UnCanonicalizeMultiStrings2,
+ c,
+ n,
+ result,
+ allow_caching_ptr);
+ default: return 0;
+ }
+}
+
+static const MultiCharacterSpecialCase<1> kCanonicalizationRangeMultiStrings0[] = { {0, {0}} }; // NOLINT
+static const uint16_t kCanonicalizationRangeTable0Size = 1831;
+static const int32_t kCanonicalizationRangeTable0[3662] = { 0, 67109124, 1073741825, 0, 64, 0, 65, 67108708, 1073741890, -260, 90, -260, 91, 67108524, 1073741916, -364, 96, -364, 97, 67108580, 1073741922, -388, 122, -388, 123, 67108604, 1073741948, -492, 180, -492, 181, 67108144, 182, 67108176, 1073742007, -728, 191, -728, 192, 67108188, 1073742017, -768, 214, -768, 215, 67108008, 216, 67108028, 1073742041, -864, 222, -864, 223, 67107976, 224, 67108060, 1073742049, -896, 246, -896, 247, 67107880, 248, 67107900, 1073742073, -992, 254, -992, 255, 67107848, 256, 67107844, 257, 67107840, 258, 67107836, 259, 67107832, 260, 67107828, 261, 67107824, 262, 67107820, 263, 67107816, 264, 67107812, 265, 67107808, 266, 67107804, 267, 67107800, 268, 67107796, 269, 67107792, 270, 67107788, 271, 67107784, 272, 67107780, 273, 67107776, 274, 67107772, 275, 67107768, 276, 67107764, 277, 67107760, 278, 67107756, 279, 67107752, 280, 67107748, 281, 67107744, 282, 67107740, 283, 67107736, 284, 67107732, 285, 67107728, 286, 67107724, 287, 67107720, 288, 67107716, 289, 67107712, 290, 67107708, 291, 67107704, 292, 67107700, 293, 67107696, 294, 67107692, 295, 67107688, 296, 67107684, 297, 67107680, 298, 67107676, 299, 67107672, 300, 67107668, 301, 67107664, 302, 67107660, 1073742127, 67107656, 304, 67107656, 305, -1216, 306, 67107644, 307, 67107640, 308, 67107636, 309, 67107632, 310, 67107628, 311, 67107624, 312, 67107620, 313, 67107616, 314, 67107612, 315, 67107608, 316, 67107604, 317, 67107600, 318, 67107596, 319, 67107592, 320, 67107588, 321, 67107584, 322, 67107580, 323, 67107576, 324, 67107572, 325, 67107568, 326, 67107564, 327, 67107560, 328, 67107556, 329, 67107552, 330, 67107548, 331, 67107544, 332, 67107540, 333, 67107536, 334, 67107532, 335, 67107528, 336, 67107524, 337, 67107520, 338, 67107516, 339, 67107512, 340, 67107508, 341, 67107504, 342, 67107500, 343, 67107496, 344, 67107492, 345, 67107488, 346, 67107484, 347, 67107480, 348, 67107476, 349, 67107472, 350, 67107468, 351, 67107464, 352, 67107460, 353, 67107456, 354, 67107452, 355, 67107448, 356, 67107444, 357, 67107440, 358, 67107436, 359, 67107432, 360, 67107428, 361, 67107424, 362, 67107420, 363, 67107416, 364, 67107412, 365, 67107408, 366, 67107404, 367, 67107400, 368, 67107396, 369, 67107392, 370, 67107388, 371, 67107384, 372, 67107380, 373, 67107376, 374, 67107372, 375, 67107368, 376, 67107364, 377, 67107360, 378, 67107356, 379, 67107352, 380, 67107348, 381, 67107344, 382, 67107340, 383, 67107336, 384, 67107332, 385, 67107328, 386, 67107324, 387, 67107320, 388, 67107316, 389, 67107312, 390, 67107308, 391, 67107304, 1073742216, 67107300, 393, 67107300, 394, -1572, 395, 67107288, 396, 67107284, 397, 67107280, 398, 67107276, 399, 67107272, 400, 67107268, 401, 67107264, 402, 67107260, 403, 67107256, 404, 67107252, 405, 67107248, 406, 67107244, 407, 67107240, 408, 67107236, 409, 67107232, 410, 67107228, 411, 67107224, 412, 67107220, 413, 67107216, 414, 67107212, 415, 67107208, 416, 67107204, 417, 67107200, 418, 67107196, 419, 67107192, 420, 67107188, 421, 67107184, 422, 67107180, 423, 67107176, 424, 67107172, 1073742249, 67107168, 426, 67107168, 427, -1704, 428, 67107156, 429, 67107152, 430, 67107148, 431, 67107144, 1073742256, 67107140, 433, 67107140, 434, -1732, 435, 67107128, 436, 67107124, 437, 67107120, 438, 67107116, 439, 67107112, 440, 67107108, 1073742265, 67107104, 442, 67107104, 443, -1768, 444, 67107092, 445, 67107088, 446, 67107084, 447, 67107080, 448, 67107088, 1073742273, -1792, 451, -1792, 452, 67107060, 453, 67107056, 454, 67107052, 455, 67107048, 456, 67107044, 457, 67107040, 458, 67107036, 459, 67107032, 460, 67107028, 461, 67107024, 462, 67107020, 463, 67107016, 464, 67107012, 465, 67107008, 466, 67107004, 467, 67107000, 468, 67106996, 469, 67106992, 470, 67106988, 471, 67106984, 472, 67106980, 473, 67106976, 474, 67106972, 475, 67106968, 476, 67106964, 477, 67106960, 478, 67106956, 479, 67106952, 480, 67106948, 481, 67106944, 482, 67106940, 483, 67106936, 484, 67106932, 485, 67106928, 486, 67106924, 487, 67106920, 488, 67106916, 489, 67106912, 490, 67106908, 491, 67106904, 492, 67106900, 493, 67106896, 494, 67106892, 495, 67106888, 496, 67106884, 497, 67106880, 498, 67106876, 499, 67106872, 500, 67106868, 501, 67106864, 502, 67106860, 503, 67106856, 504, 67106852, 505, 67106848, 506, 67106844, 507, 67106840, 508, 67106836, 509, 67106832, 510, 67106828, 511, 67106824, 512, 67106820, 513, 67106816, 514, 67106812, 515, 67106808, 516, 67106804, 517, 67106800, 518, 67106796, 519, 67106792, 520, 67106788, 521, 67106784, 522, 67106780, 523, 67106776, 524, 67106772, 525, 67106768, 526, 67106764, 527, 67106760, 528, 67106756, 529, 67106752, 530, 67106748, 531, 67106744, 532, 67106740, 533, 67106736, 534, 67106732, 535, 67106728, 536, 67106724, 537, 67106720, 538, 67106716, 539, 67106712, 540, 67106708, 541, 67106704, 542, 67106700, 543, 67106696, 544, 67106692, 545, 67106688, 546, 67106684, 547, 67106680, 548, 67106676, 549, 67106672, 550, 67106668, 551, 67106664, 552, 67106660, 553, 67106656, 554, 67106652, 555, 67106648, 556, 67106644, 557, 67106640, 558, 67106636, 559, 67106632, 560, 67106628, 561, 67106624, 562, 67106620, 563, 67106616, 564, 67106632, 1073742389, -2256, 569, -2256, 570, 67106588, 571, 67106584, 572, 67106580, 573, 67106576, 1073742398, 67106572, 575, 67106572, 576, -2300, 577, 67106560, 578, 67106556, 579, 67106552, 580, 67106548, 581, 67106544, 582, 67106540, 583, 67106536, 584, 67106532, 585, 67106528, 586, 67106524, 587, 67106520, 588, 67106516, 589, 67106512, 590, 67106508, 591, 67106504, 592, 67106508, 1073742417, -2368, 594, -2368, 595, 67106488, 596, 67106484, 1073742421, 67106480, 598, 67106480, 599, -2392, 600, 67106468, 601, 67106464, 602, 67106460, 603, 67106456, 604, 67106464, 1073742429, -2416, 607, -2416, 1073742432, 67106436, 609, 67106436, 610, -2436, 611, 67106424, 612, 67106432, 1073742437, -2448, 615, -2448, 616, 67106404, 617, 67106400, 618, 67106396, 619, 67106392, 620, 67106396, 1073742445, -2480, 622, -2480, 1073742447, 67106376, 624, 67106376, 625, -2496, 1073742450, 67106364, 627, 67106364, 628, -2508, 629, 67106352, 630, 67106372, 1073742455, -2520, 636, -2520, 1073742461, 67106320, 638, 67106320, 639, -2552, 1073742464, 67106308, 641, 67106308, 642, -2564, 643, 67106296, 644, 67106304, 1073742469, -2576, 647, -2576, 648, 67106276, 1073742473, 67106272, 650, 67106272, 651, -2600, 652, 67106260, 653, 67106272, 1073742478, -2612, 657, -2612, 658, 67106236, 659, 67106940, 1073742484, -2636, 836, -2636, 837, 67105520, 838, 67105724, 1073742663, -3352, 879, -3352, 1073742708, -3352, 885, -3352, 890, -3352, 891, 67105312, 1073742716, -3564, 893, -3564, 894, 67105320, 1073742724, -3576, 901, -3576, 902, 67105260, 903, 67105256, 904, 67105260, 1073742729, -3616, 906, -3616, 908, 67105236, 910, 67105232, 911, -3640, 912, 67105220, 913, 67105216, 1073742738, 67105212, 915, 67105212, 916, -3660, 1073742741, 67105200, 918, 67105200, 919, -3672, 920, 67105188, 921, 67105184, 922, 67105180, 923, 67105176, 924, 67105172, 925, 67105176, 1073742750, -3700, 927, -3700, 928, 67105156, 929, 67105152, 1073742755, 67105144, 932, 67105144, 933, -3728, 934, 67105132, 935, 67105144, 1073742760, -3740, 939, -3740, 940, 67105108, 941, 67105112, 1073742766, -3764, 943, -3764, 944, 67105092, 945, 67105088, 1073742770, 67105084, 947, 67105084, 948, -3788, 1073742773, 67105072, 950, 67105072, 951, -3800, 952, 67105060, 953, 67105056, 954, 67105052, 955, 67105048, 956, 67105044, 957, 67105048, 1073742782, -3828, 959, -3828, 960, 67105028, 961, 67105024, 962, 67105020, 1073742787, 67105016, 964, 67105016, 965, -3856, 966, 67105004, 967, 67105016, 1073742792, -3868, 971, -3868, 1073742796, 67104980, 973, 67104980, 974, -3892, 976, 67104964, 977, 67104960, 978, 67104964, 1073742803, -3912, 980, -3912, 981, 67104944, 982, 67104940, 983, 67104936, 984, 67104932, 985, 67104928, 986, 67104924, 987, 67104920, 988, 67104916, 989, 67104912, 990, 67104908, 991, 67104904, 992, 67104900, 993, 67104896, 994, 67104892, 995, 67104888, 996, 67104884, 997, 67104880, 998, 67104876, 999, 67104872, 1000, 67104868, 1001, 67104864, 1002, 67104860, 1003, 67104856, 1004, 67104852, 1005, 67104848, 1006, 67104844, 1007, 67104840, 1008, 67104836, 1009, 67104832, 1073742834, 67104828, 1011, 67104828, 1012, -4044, 1013, 67104816, 1014, 67104812, 1015, 67104808, 1016, 67104804, 1017, 67104800, 1018, 67104796, 1019, 67104792, 1020, 67104788, 1021, 67104792, 1073742846, -4084, 1023, -4084, 1024, 67104832, 1073742849, -4096, 1039, -4096, 1040, 67104832, 1073742865, -4160, 1071, -4160, 1072, 67104704, 1073742897, -4288, 1103, -4288, 1104, 67104512, 1073742929, -4416, 1119, -4416, 1120, 67104388, 1121, 67104384, 1122, 67104380, 1123, 67104376, 1124, 67104372, 1125, 67104368, 1126, 67104364, 1127, 67104360, 1128, 67104356, 1129, 67104352, 1130, 67104348, 1131, 67104344, 1132, 67104340, 1133, 67104336, 1134, 67104332, 1135, 67104328, 1136, 67104324, 1137, 67104320, 1138, 67104316, 1139, 67104312, 1140, 67104308, 1141, 67104304, 1142, 67104300, 1143, 67104296, 1144, 67104292, 1145, 67104288, 1146, 67104284, 1147, 67104280, 1148, 67104276, 1149, 67104272, 1150, 67104268, 1151, 67104264, 1152, 67104260, 1153, 67104256, 1154, 67104280, 1073742979, -4616, 1158, -4616, 1073742984, -4616, 1161, -4616, 1162, 67104220, 1163, 67104216, 1164, 67104212, 1165, 67104208, 1166, 67104204, 1167, 67104200, 1168, 67104196, 1169, 67104192, 1170, 67104188, 1171, 67104184, 1172, 67104180, 1173, 67104176, 1174, 67104172, 1175, 67104168, 1176, 67104164, 1177, 67104160, 1178, 67104156, 1179, 67104152, 1180, 67104148, 1181, 67104144, 1182, 67104140, 1183, 67104136, 1184, 67104132, 1185, 67104128, 1186, 67104124, 1187, 67104120, 1188, 67104116, 1189, 67104112, 1190, 67104108, 1191, 67104104, 1192, 67104100, 1193, 67104096, 1194, 67104092, 1195, 67104088, 1196, 67104084, 1197, 67104080, 1198, 67104076, 1199, 67104072, 1200, 67104068, 1201, 67104064, 1202, 67104060, 1203, 67104056, 1204, 67104052, 1205, 67104048, 1206, 67104044, 1207, 67104040, 1208, 67104036, 1209, 67104032, 1210, 67104028, 1211, 67104024, 1212, 67104020, 1213, 67104016, 1214, 67104012, 1215, 67104008, 1216, 67104004, 1217, 67104000, 1218, 67103996, 1219, 67103992, 1220, 67103988, 1221, 67103984, 1222, 67103980, 1223, 67103976, 1224, 67103972, 1225, 67103968, 1226, 67103964, 1227, 67103960, 1228, 67103956, 1229, 67103952, 1230, 67103948, 1231, 67103944, 1232, 67103940, 1233, 67103936, 1234, 67103932, 1235, 67103928, 1236, 67103924, 1237, 67103920, 1238, 67103916, 1239, 67103912, 1240, 67103908, 1241, 67103904, 1242, 67103900, 1243, 67103896, 1244, 67103892, 1245, 67103888, 1246, 67103884, 1247, 67103880, 1248, 67103876, 1249, 67103872, 1250, 67103868, 1251, 67103864, 1252, 67103860, 1253, 67103856, 1254, 67103852, 1255, 67103848, 1256, 67103844, 1257, 67103840, 1258, 67103836, 1259, 67103832, 1260, 67103828, 1261, 67103824, 1262, 67103820, 1263, 67103816, 1264, 67103812, 1265, 67103808, 1266, 67103804, 1267, 67103800, 1268, 67103796, 1269, 67103792, 1270, 67103788, 1271, 67103784, 1272, 67103780, 1273, 67103776, 1274, 67103772, 1275, 67103768, 1276, 67103764, 1277, 67103760, 1278, 67103756, 1279, 67103752, 1280, 67103748, 1281, 67103744, 1282, 67103740, 1283, 67103736, 1284, 67103732, 1285, 67103728, 1286, 67103724, 1287, 67103720, 1288, 67103716, 1289, 67103712, 1290, 67103708, 1291, 67103704, 1292, 67103700, 1293, 67103696, 1294, 67103692, 1295, 67103688, 1296, 67103684, 1297, 67103680, 1298, 67103676, 1299, 67103672, 1329, 67103700, 1073743154, -5316, 1366, -5316, 1073743193, -5468, 1375, -5468, 1377, 67103508, 1073743202, -5508, 1414, -5508, 1415, 67114568, 1073743241, -5660, 1418, -5660, 1073743249, -5660, 1479, -5660, 1073743312, -5660, 1514, -5660, 1073743344, -5660, 1524, -5660, 1073743360, -5660, 1539, -5660, 1073743371, -5660, 1557, -5660, 1563, -5660, 1073743390, -5660, 1567, -5660, 1073743393, -5660, 1594, -5660, 1073743424, -5660, 1630, -5660, 1073743456, -5660, 1805, -5660, 1073743631, -5660, 1866, -5660, 1073743693, -5660, 1901, -5660, 1073743744, -5660, 1969, -5660, 1073743808, -5660, 2042, -5660, 1073744129, -5660, 2361, -5660, 1073744188, -5660, 2381, -5660, 1073744208, -5660, 2388, -5660, 1073744216, -5660, 2416, -5660, 1073744251, -5660, 2431, -5660, 1073744257, -5660, 2435, -5660, 1073744261, -5660, 2444, -5660, 1073744271, -5660, 2448, -5660, 1073744275, -5660, 2472, -5660, 1073744298, -5660, 2480, -5660, 2482, -5660, 1073744310, -5660, 2489, -5660, 1073744316, -5660, 2500, -5660, 1073744327, -5660, 2504, -5660, 1073744331, -5660, 2510, -5660, 2519, -5660, 1073744348, -5660, 2525, -5660, 1073744351, -5660, 2531, -5660, 1073744358, -5660, 2554, -5660, 1073744385, -5660, 2563, -5660, 1073744389, -5660, 2570, -5660, 1073744399, -5660, 2576, -5660, 1073744403, -5660, 2600, -5660, 1073744426, -5660, 2608, -5660, 1073744434, -5660, 2611, -5660, 1073744437, -5660, 2614, -5660, 1073744440, -5660, 2617, -5660, 2620, -5660, 1073744446, -5660, 2626, -5660, 1073744455, -5660, 2632, -5660, 1073744459, -5660, 2637, -5660, 1073744473, -5660, 2652, -5660, 2654, -5660, 1073744486, -5660, 2676, -5660, 1073744513, -5660, 2691, -5660, 1073744517, -5660, 2701, -5660, 1073744527, -5660, 2705, -5660, 1073744531, -5660, 2728, -5660, 1073744554, -5660, 2736, -5660, 1073744562, -5660, 2739, -5660, 1073744565, -5660, 2745, -5660, 1073744572, -5660, 2757, -5660, 1073744583, -5660, 2761, -5660, 1073744587, -5660, 2765, -5660, 2768, -5660, 1073744608, -5660, 2787, -5660, 1073744614, -5660, 2799, -5660, 2801, -5660, 1073744641, -5660, 2819, -5660, 1073744645, -5660, 2828, -5660, 1073744655, -5660, 2832, -5660, 1073744659, -5660, 2856, -5660, 1073744682, -5660, 2864, -5660, 1073744690, -5660, 2867, -5660, 1073744693, -5660, 2873, -5660, 1073744700, -5660, 2883, -5660, 1073744711, -5660, 2888, -5660, 1073744715, -5660, 2893, -5660, 1073744726, -5660, 2903, -5660, 1073744732, -5660, 2909, -5660, 1073744735, -5660, 2913, -5660, 1073744742, -5660, 2929, -5660, 1073744770, -5660, 2947, -5660, 1073744773, -5660, 2954, -5660, 1073744782, -5660, 2960, -5660, 1073744786, -5660, 2965, -5660, 1073744793, -5660, 2970, -5660, 2972, -5660, 1073744798, -5660, 2975, -5660, 1073744803, -5660, 2980, -5660, 1073744808, -5660, 2986, -5660, 1073744814, -5660, 3001, -5660, 1073744830, -5660, 3010, -5660, 1073744838, -5660, 3016, -5660, 1073744842, -5660, 3021, -5660, 3031, -5660, 1073744870, -5660, 3066, -5660, 1073744897, -5660, 3075, -5660, 1073744901, -5660, 3084, -5660, 1073744910, -5660, 3088, -5660, 1073744914, -5660, 3112, -5660, 1073744938, -5660, 3123, -5660, 1073744949, -5660, 3129, -5660, 1073744958, -5660, 3140, -5660, 1073744966, -5660, 3144, -5660, 1073744970, -5660, 3149, -5660, 1073744981, -5660, 3158, -5660, 1073744992, -5660, 3169, -5660, 1073744998, -5660, 3183, -5660, 1073745026, -5660, 3203, -5660, 1073745029, -5660, 3212, -5660, 1073745038, -5660, 3216, -5660, 1073745042, -5660, 3240, -5660, 1073745066, -5660, 3251, -5660, 1073745077, -5660, 3257, -5660, 1073745084, -5660, 3268, -5660, 1073745094, -5660, 3272, -5660, 1073745098, -5660, 3277, -5660, 1073745109, -5660, 3286, -5660, 3294, -5660, 1073745120, -5660, 3299, -5660, 1073745126, -5660, 3311, -5660, 1073745137, -5660, 3314, -5660, 1073745154, -5660, 3331, -5660, 1073745157, -5660, 3340, -5660, 1073745166, -5660, 3344, -5660, 1073745170, -5660, 3368, -5660, 1073745194, -5660, 3385, -5660, 1073745214, -5660, 3395, -5660, 1073745222, -5660, 3400, -5660, 1073745226, -5660, 3405, -5660, 3415, -5660, 1073745248, -5660, 3425, -5660, 1073745254, -5660, 3439, -5660, 1073745282, -5660, 3459, -5660, 1073745285, -5660, 3478, -5660, 1073745306, -5660, 3505, -5660, 1073745331, -5660, 3515, -5660, 3517, -5660, 1073745344, -5660, 3526, -5660, 3530, -5660, 1073745359, -5660, 3540, -5660, 3542, -5660, 1073745368, -5660, 3551, -5660, 1073745394, -5660, 3572, -5660, 1073745409, -5660, 3642, -5660, 1073745471, -5660, 3675, -5660, 1073745537, -5660, 3714, -5660, 3716, -5660, 1073745543, -5660, 3720, -5660, 3722, -5660, 3725, -5660, 1073745556, -5660, 3735, -5660, 1073745561, -5660, 3743, -5660, 1073745569, -5660, 3747, -5660, 3749, -5660, 3751, -5660, 1073745578, -5660, 3755, -5660, 1073745581, -5660, 3769, -5660, 1073745595, -5660, 3773, -5660, 1073745600, -5660, 3780, -5660, 3782, -5660, 1073745608, -5660, 3789, -5660, 1073745616, -5660, 3801, -5660, 1073745628, -5660, 3805, -5660, 1073745664, -5660, 3911, -5660, 1073745737, -5660, 3946, -5660, 1073745777, -5660, 3979, -5660, 1073745808, -5660, 3991, -5660, 1073745817, -5660, 4028, -5660, 1073745854, -5660, 4044, -5660, 1073745871, -5660, 4049, -5660, 1073745920, -5660, 4129, -5660, 1073745955, -5660, 4135, -5660, 1073745961, -5660, 4138, -5660, 1073745964, -5660, 4146, -5660, 1073745974, -5660, 4153, -5660, 1073745984, -5660, 4185, -5660, 4256, 67091992, 1073746081, -17024, 4293, -17024, 1073746128, -17176, 4348, -17176, 1073746176, -17176, 4441, -17176, 1073746271, -17176, 4514, -17176, 1073746344, -17176, 4601, -17176, 1073746432, -17176, 4680, -17176, 1073746506, -17176, 4685, -17176, 1073746512, -17176, 4694, -17176, 4696, -17176, 1073746522, -17176, 4701, -17176, 1073746528, -17176, 4744, -17176, 1073746570, -17176, 4749, -17176, 1073746576, -17176, 4784, -17176, 1073746610, -17176, 4789, -17176, 1073746616, -17176, 4798, -17176, 4800, -17176, 1073746626, -17176, 4805, -17176, 1073746632, -17176, 4822, -17176, 1073746648, -17176, 4880, -17176, 1073746706, -17176, 4885, -17176, 1073746712, -17176, 4954, -17176, 1073746783, -17176, 4988, -17176, 1073746816, -17176, 5017, -17176, 1073746848, -17176, 5108, -17176, 1073746945, -17176, 5750, -17176, 1073747584, -17176, 5788, -17176, 1073747616, -17176, 5872, -17176, 1073747712, -17176, 5900, -17176, 1073747726, -17176, 5908, -17176, 1073747744, -17176, 5942, -17176, 1073747776, -17176, 5971, -17176, 1073747808, -17176, 5996, -17176, 1073747822, -17176, 6000, -17176, 1073747826, -17176, 6003, -17176, 1073747840, -17176, 6109, -17176, 1073747936, -17176, 6121, -17176, 1073747952, -17176, 6137, -17176, 1073747968, -17176, 6158, -17176, 1073747984, -17176, 6169, -17176, 1073748000, -17176, 6263, -17176, 1073748096, -17176, 6313, -17176, 1073748224, -17176, 6428, -17176, 1073748256, -17176, 6443, -17176, 1073748272, -17176, 6459, -17176, 6464, -17176, 1073748292, -17176, 6509, -17176, 1073748336, -17176, 6516, -17176, 1073748352, -17176, 6569, -17176, 1073748400, -17176, 6601, -17176, 1073748432, -17176, 6617, -17176, 1073748446, -17176, 6683, -17176, 1073748510, -17176, 6687, -17176, 1073748736, -17176, 6987, -17176, 1073748816, -17176, 7036, -17176, 1073749248, -17176, 7548, -17176, 7549, 67078672, 7550, 67079184, 1073749375, -30200, 7626, -30200, 1073749502, -30200, 7679, -30200, 7680, 67078148, 7681, 67078144, 7682, 67078140, 7683, 67078136, 7684, 67078132, 7685, 67078128, 7686, 67078124, 7687, 67078120, 7688, 67078116, 7689, 67078112, 7690, 67078108, 7691, 67078104, 7692, 67078100, 7693, 67078096, 7694, 67078092, 7695, 67078088, 7696, 67078084, 7697, 67078080, 7698, 67078076, 7699, 67078072, 7700, 67078068, 7701, 67078064, 7702, 67078060, 7703, 67078056, 7704, 67078052, 7705, 67078048, 7706, 67078044, 7707, 67078040, 7708, 67078036, 7709, 67078032, 7710, 67078028, 7711, 67078024, 7712, 67078020, 7713, 67078016, 7714, 67078012, 7715, 67078008, 7716, 67078004, 7717, 67078000, 7718, 67077996, 7719, 67077992, 7720, 67077988, 7721, 67077984, 7722, 67077980, 7723, 67077976, 7724, 67077972, 7725, 67077968, 7726, 67077964, 7727, 67077960, 7728, 67077956, 7729, 67077952, 7730, 67077948, 7731, 67077944, 7732, 67077940, 7733, 67077936, 7734, 67077932, 7735, 67077928, 7736, 67077924, 7737, 67077920, 7738, 67077916, 7739, 67077912, 7740, 67077908, 7741, 67077904, 7742, 67077900, 7743, 67077896, 7744, 67077892, 7745, 67077888, 7746, 67077884, 7747, 67077880, 7748, 67077876, 7749, 67077872, 7750, 67077868, 7751, 67077864, 7752, 67077860, 7753, 67077856, 7754, 67077852, 7755, 67077848, 7756, 67077844, 7757, 67077840, 7758, 67077836, 7759, 67077832, 7760, 67077828, 7761, 67077824, 7762, 67077820, 7763, 67077816, 7764, 67077812, 7765, 67077808, 7766, 67077804, 7767, 67077800, 7768, 67077796, 7769, 67077792, 7770, 67077788, 7771, 67077784, 7772, 67077780, 7773, 67077776, 7774, 67077772, 7775, 67077768, 7776, 67077764, 7777, 67077760, 7778, 67077756, 7779, 67077752, 7780, 67077748, 7781, 67077744, 7782, 67077740, 7783, 67077736, 7784, 67077732, 7785, 67077728, 7786, 67077724, 7787, 67077720, 7788, 67077716, 7789, 67077712, 7790, 67077708, 7791, 67077704, 7792, 67077700, 7793, 67077696, 7794, 67077692, 7795, 67077688, 7796, 67077684, 7797, 67077680, 7798, 67077676, 7799, 67077672, 7800, 67077668, 7801, 67077664, 7802, 67077660, 7803, 67077656, 7804, 67077652, 7805, 67077648, 7806, 67077644, 7807, 67077640, 7808, 67077636, 7809, 67077632, 7810, 67077628, 7811, 67077624, 7812, 67077620, 7813, 67077616, 7814, 67077612, 7815, 67077608, 7816, 67077604, 7817, 67077600, 7818, 67077596, 7819, 67077592, 7820, 67077588, 7821, 67077584, 7822, 67077580, 7823, 67077576, 7824, 67077572, 7825, 67077568, 7826, 67077564, 7827, 67077560, 7828, 67077556, 7829, 67077552, 7830, 67077564, 1073749655, -31320, 7834, -31320, 7835, 67077528, 7840, 67077508, 7841, 67077504, 7842, 67077500, 7843, 67077496, 7844, 67077492, 7845, 67077488, 7846, 67077484, 7847, 67077480, 7848, 67077476, 7849, 67077472, 7850, 67077468, 7851, 67077464, 7852, 67077460, 7853, 67077456, 7854, 67077452, 7855, 67077448, 7856, 67077444, 7857, 67077440, 7858, 67077436, 7859, 67077432, 7860, 67077428, 7861, 67077424, 7862, 67077420, 7863, 67077416, 7864, 67077412, 7865, 67077408, 7866, 67077404, 7867, 67077400, 7868, 67077396, 7869, 67077392, 7870, 67077388, 7871, 67077384, 7872, 67077380, 7873, 67077376, 7874, 67077372, 7875, 67077368, 7876, 67077364, 7877, 67077360, 7878, 67077356, 7879, 67077352, 7880, 67077348, 7881, 67077344, 7882, 67077340, 7883, 67077336, 7884, 67077332, 7885, 67077328, 7886, 67077324, 7887, 67077320, 7888, 67077316, 7889, 67077312, 7890, 67077308, 7891, 67077304, 7892, 67077300, 7893, 67077296, 7894, 67077292, 7895, 67077288, 7896, 67077284, 7897, 67077280, 7898, 67077276, 7899, 67077272, 7900, 67077268, 7901, 67077264, 7902, 67077260, 7903, 67077256, 7904, 67077252, 7905, 67077248, 7906, 67077244, 7907, 67077240, 7908, 67077236, 7909, 67077232, 7910, 67077228, 7911, 67077224, 7912, 67077220, 7913, 67077216, 7914, 67077212, 7915, 67077208, 7916, 67077204, 7917, 67077200, 7918, 67077196, 7919, 67077192, 7920, 67077188, 7921, 67077184, 7922, 67077180, 7923, 67077176, 7924, 67077172, 7925, 67077168, 7926, 67077164, 7927, 67077160, 7928, 67077156, 7929, 67077152, 7936, 67077152, 1073749761, -31744, 7943, -31744, 7944, 67077120, 1073749769, -31776, 7951, -31776, 7952, 67077080, 1073749777, -31808, 7957, -31808, 7960, 67077048, 1073749785, -31840, 7965, -31840, 7968, 67077024, 1073749793, -31872, 7975, -31872, 7976, 67076992, 1073749801, -31904, 7983, -31904, 7984, 67076960, 1073749809, -31936, 7991, -31936, 7992, 67076928, 1073749817, -31968, 7999, -31968, 8000, 67076888, 1073749825, -32000, 8005, -32000, 8008, 67076856, 1073749833, -32032, 8013, -32032, 8016, -32056, 8017, 67076800, 8018, 67076796, 8019, 67076792, 8020, 67076788, 8021, 67076784, 8022, 67076780, 8023, 67076776, 8025, 67076768, 8027, 67076760, 8029, 67076752, 8031, 67076744, 8032, 67076768, 1073749857, -32128, 8039, -32128, 8040, 67076736, 1073749865, -32160, 8047, -32160, 8048, 67076680, 8049, -32192, 8050, 67076680, 1073749875, -32200, 8053, -32200, 8054, 67076656, 8055, -32216, 8056, 67076648, 8057, -32224, 8058, 67076640, 8059, -32232, 8060, 67076632, 8061, -32240, 1073749888, -32248, 8111, -32248, 8112, 67076424, 8113, -32448, 8114, 67076432, 1073749939, -32456, 8116, -32456, 1073749942, -32456, 8119, -32456, 8120, 67076392, 8121, -32480, 8122, 67076384, 8123, -32488, 8124, 67076376, 8125, -32496, 8126, 67076364, 8127, 67076392, 1073749952, -32508, 8132, -32508, 1073749958, -32508, 8135, -32508, 8136, 67076336, 1073749961, -32544, 8139, -32544, 8140, 67076320, 1073749965, -32560, 8143, -32560, 8144, 67076296, 8145, -32576, 8146, 67076304, 8147, -32584, 1073749974, -32584, 8151, -32584, 8152, 67076264, 8153, -32608, 8154, 67076256, 8155, -32616, 1073749981, -32624, 8159, -32624, 8160, 67076232, 8161, -32640, 8162, 67076228, 1073749987, -32648, 8164, -32648, 1073749989, 67076208, 8166, 67076208, 8167, -32664, 8168, 67076200, 8169, -32672, 8170, 67076192, 8171, -32680, 8172, 67076180, 8173, 67076216, 1073749998, -32692, 8175, -32692, 1073750002, -32692, 8180, -32692, 1073750006, -32692, 8183, -32692, 8184, 67076136, 8185, -32736, 8186, 67076128, 8187, -32744, 8188, 67077352, 1073750013, -32752, 8190, -32752, 1073750016, -32752, 8291, -32752, 1073750122, -32752, 8305, -32752, 1073750132, -32752, 8334, -32752, 1073750160, -32752, 8340, -32752, 1073750176, -32752, 8373, -32752, 1073750224, -32752, 8431, -32752, 1073750272, -32752, 8497, -32752, 8498, 67074876, 8499, 67074976, 1073750324, -33996, 8525, -33996, 8526, 67074764, 1073750355, -34108, 8543, -34108, 8544, 67074752, 1073750369, -34176, 8559, -34176, 8560, 67074688, 1073750385, -34240, 8575, -34240, 8576, 67074572, 1073750401, -34304, 8578, -34304, 8579, 67074552, 8580, 67074548, 1073750416, -34324, 9191, -34324, 1073751040, -34324, 9254, -34324, 1073751104, -34324, 9290, -34324, 1073751136, -34324, 9397, -34324, 9398, 67071376, 1073751223, -37592, 9423, -37592, 9424, 67071272, 1073751249, -37696, 9449, -37696, 9450, 67078320, 1073751275, -37800, 9884, -37800, 1073751712, -37800, 9906, -37800, 1073751809, -37800, 9988, -37800, 1073751814, -37800, 9993, -37800, 1073751820, -37800, 10023, -37800, 1073751849, -37800, 10059, -37800, 10061, -37800, 1073751887, -37800, 10066, -37800, 10070, -37800, 1073751896, -37800, 10078, -37800, 1073751905, -37800, 10132, -37800, 1073751960, -37800, 10159, -37800, 1073751985, -37800, 10174, -37800, 1073752000, -37800, 10186, -37800, 1073752016, -37800, 10219, -37800, 1073752048, -37800, 11034, -37800, 1073752864, -37800, 11043, -37800, 11264, 67063996, 1073753089, -45056, 11310, -45056, 11312, 67063804, 1073753137, -45248, 11358, -45248, 11360, 67063428, 11361, 67063424, 11362, 67063420, 11363, 67063416, 11364, 67063412, 11365, 67063408, 11366, 67063404, 11367, 67063400, 11368, 67063396, 11369, 67063392, 11370, 67063388, 11371, 67063384, 11372, 67063380, 11380, -45492, 11381, 67063344, 11382, 67063340, 11383, 67063368, 11392, 67063300, 11393, 67063296, 11394, 67063292, 11395, 67063288, 11396, 67063284, 11397, 67063280, 11398, 67063276, 11399, 67063272, 11400, 67063268, 11401, 67063264, 11402, 67063260, 11403, 67063256, 11404, 67063252, 11405, 67063248, 11406, 67063244, 11407, 67063240, 11408, 67063236, 11409, 67063232, 11410, 67063228, 11411, 67063224, 11412, 67063220, 11413, 67063216, 11414, 67063212, 11415, 67063208, 11416, 67063204, 11417, 67063200, 11418, 67063196, 11419, 67063192, 11420, 67063188, 11421, 67063184, 11422, 67063180, 11423, 67063176, 11424, 67063172, 11425, 67063168, 11426, 67063164, 11427, 67063160, 11428, 67063156, 11429, 67063152, 11430, 67063148, 11431, 67063144, 11432, 67063140, 11433, 67063136, 11434, 67063132, 11435, 67063128, 11436, 67063124, 11437, 67063120, 11438, 67063116, 11439, 67063112, 11440, 67063108, 11441, 67063104, 11442, 67063100, 11443, 67063096, 11444, 67063092, 11445, 67063088, 11446, 67063084, 11447, 67063080, 11448, 67063076, 11449, 67063072, 11450, 67063068, 11451, 67063064, 11452, 67063060, 11453, 67063056, 11454, 67063052, 11455, 67063048, 11456, 67063044, 11457, 67063040, 11458, 67063036, 11459, 67063032, 11460, 67063028, 11461, 67063024, 11462, 67063020, 11463, 67063016, 11464, 67063012, 11465, 67063008, 11466, 67063004, 11467, 67063000, 11468, 67062996, 11469, 67062992, 11470, 67062988, 11471, 67062984, 11472, 67062980, 11473, 67062976, 11474, 67062972, 11475, 67062968, 11476, 67062964, 11477, 67062960, 11478, 67062956, 11479, 67062952, 11480, 67062948, 11481, 67062944, 11482, 67062940, 11483, 67062936, 11484, 67062932, 11485, 67062928, 11486, 67062924, 11487, 67062920, 11488, 67062916, 11489, 67062912, 11490, 67062908, 11491, 67062904, 11492, 67063008, 1073753317, -45968, 11498, -45968, 1073753337, -45968, 11519, -45968, 11520, 67062936, 1073753345, -46080, 11557, -46080, 1073753392, -46232, 11621, -46232, 11631, -46232, 1073753472, -46232, 11670, -46232, 1073753504, -46232, 11686, -46232, 1073753512, -46232, 11694, -46232, 1073753520, -46232, 11702, -46232, 1073753528, -46232, 11710, -46232, 1073753536, -46232, 11718, -46232, 1073753544, -46232, 11726, -46232, 1073753552, -46232, 11734, -46232, 1073753560, -46232, 11742, -46232, 1073753600, -46232, 11799, -46232, 1073753628, -46232, 11805, -46232, 1073753728, -46232, 11929, -46232, 1073753755, -46232, 12019, -46232, 1073753856, -46232, 12245, -46232, 1073754096, -46232, 12283, -46232, 1073754112, -46232, 12351, -46232, 1073754177, -46232, 12438, -46232, 1073754265, -46232, 12543, -46232, 1073754373, -46232, 12588, -46232, 1073754417, -46232, 12686, -46232, 1073754512, -46232, 12727, -46232, 1073754560, -46232, 12751, -46232, 1073754608, -46232, 12830, -46232, 1073754656, -46232, 12867, -46232, 1073754704, -46232, 13054, -46232, 1073754880, -46232, 19893, -46232, 1073761728, -46232, 32767, -46232 }; // NOLINT
+static const MultiCharacterSpecialCase<1> kCanonicalizationRangeMultiStrings1[] = { {0, {0}} }; // NOLINT
+static const uint16_t kCanonicalizationRangeTable1Size = 88;
+static const int32_t kCanonicalizationRangeTable1[176] = { 1073741824, -46232, 8123, -46232, 1073750016, -46232, 9356, -46232, 1073751184, -46232, 9414, -46232, 1073751808, -46232, 10010, -46232, 1073751840, -46232, 10017, -46232, 1073752064, -46232, 10283, -46232, 1073752128, -46232, 10359, -46232, 1073753088, -46232, 22435, -46232, 1073764352, -46232, 31277, -46232, 1073773104, -46232, 31338, -46232, 1073773168, -46232, 31449, -46232, 1073773312, -46232, 31494, -46232, 1073773331, -46232, 31511, -46232, 1073773341, -46232, 31542, -46232, 1073773368, -46232, 31548, -46232, 31550, -46232, 1073773376, -46232, 31553, -46232, 1073773379, -46232, 31556, -46232, 1073773382, -46232, 31665, -46232, 1073773523, -46232, 32063, -46232, 1073773904, -46232, 32143, -46232, 1073773970, -46232, 32199, -46232, 1073774064, -46232, 32253, -46232, 1073774080, -46232, 32281, -46232, 1073774112, -46232, 32291, -46232, 1073774128, -46232, 32338, -46232, 1073774164, -46232, 32358, -46232, 1073774184, -46232, 32363, -46232, 1073774192, -46232, 32372, -46232, 1073774198, -46232, 32508, -46232, 32511, -46232, 1073774337, -46232, 32544, -46232, 32545, 66847716, 1073774370, -261252, 32570, -261252, 32571, 66847532, 1073774396, -261356, 32576, -261356, 32577, 66847588, 1073774402, -261380, 32602, -261380, 32603, 66848040, 1073774428, -261484, 32702, -261484, 1073774530, -261484, 32711, -261484, 1073774538, -261484, 32719, -261484, 1073774546, -261484, 32727, -261484, 1073774554, -261484, 32732, -261484, 1073774560, -261484, 32742, -261484, 1073774568, -261484, 32750, -261484, 1073774585, -261484, 32765, -261484 }; // NOLINT
+int CanonicalizationRange::Convert(uchar c,
+ uchar n,
+ uchar* result,
+ bool* allow_caching_ptr) {
+ int chunk_index = c >> 15;
+ switch (chunk_index) {
+ case 0: return LookupMapping(kCanonicalizationRangeTable0,
+ kCanonicalizationRangeTable0Size,
+ kCanonicalizationRangeMultiStrings0,
+ c,
+ n,
+ result,
+ allow_caching_ptr);
+ case 1: return LookupMapping(kCanonicalizationRangeTable1,
+ kCanonicalizationRangeTable1Size,
+ kCanonicalizationRangeMultiStrings1,
+ c,
+ n,
+ result,
+ allow_caching_ptr);
+ default: return 0;
+ }
+}
+
uchar UnicodeData::kMaxCodePoint = 1114109;
int UnicodeData::GetByteCount() {
- return 0 + (sizeof(uint16_t) * kUppercaseTable0Size) + (sizeof(uint16_t) * kUppercaseTable1Size) + (sizeof(uint16_t) * kUppercaseTable2Size) + (sizeof(uint16_t) * kUppercaseTable3Size) + (sizeof(uint16_t) * kLowercaseTable0Size) + (sizeof(uint16_t) * kLowercaseTable1Size) + (sizeof(uint16_t) * kLowercaseTable2Size) + (sizeof(uint16_t) * kLowercaseTable3Size) + (sizeof(uint16_t) * kLetterTable0Size) + (sizeof(uint16_t) * kLetterTable1Size) + (sizeof(uint16_t) * kLetterTable2Size) + (sizeof(uint16_t) * kLetterTable3Size) + (sizeof(uint16_t) * kLetterTable4Size) + (sizeof(uint16_t) * kLetterTable5Size) + (sizeof(uint16_t) * kSpaceTable0Size) + (sizeof(uint16_t) * kTitlecaseTable0Size) + (sizeof(uint16_t) * kNumberTable0Size) + (sizeof(uint16_t) * kNumberTable1Size) + (sizeof(uint16_t) * kNumberTable2Size) + (sizeof(uint16_t) * kNumberTable3Size) + (sizeof(uint16_t) * kDecimalDigitTable0Size) + (sizeof(uint16_t) * kDecimalDigitTable1Size) + (sizeof(uint16_t) * kDecimalDigitTable2Size) + (sizeof(uint16_t) * kDecimalDigitTable3Size) + (sizeof(uint16_t) * kIdeographicTable0Size) + (sizeof(uint16_t) * kIdeographicTable1Size) + (sizeof(uint16_t) * kIdeographicTable4Size) + (sizeof(uint16_t) * kIdeographicTable5Size) + (sizeof(uint16_t) * kWhiteSpaceTable0Size) + (sizeof(uint16_t) * kHexDigitTable0Size) + (sizeof(uint16_t) * kHexDigitTable1Size) + (sizeof(uint16_t) * kAsciiHexDigitTable0Size) + (sizeof(uint16_t) * kBidiControlTable0Size) + (sizeof(uint16_t) * kJoinControlTable0Size) + (sizeof(uint16_t) * kDashTable0Size) + (sizeof(uint16_t) * kDashTable1Size) + (sizeof(uint16_t) * kHyphenTable0Size) + (sizeof(uint16_t) * kHyphenTable1Size) + (sizeof(uint16_t) * kLineTerminatorTable0Size) + (sizeof(uint16_t) * kRegExpSpecialCharTable0Size) + (sizeof(uint16_t) * kCombiningMarkTable0Size) + (sizeof(uint16_t) * kCombiningMarkTable1Size) + (sizeof(uint16_t) * kCombiningMarkTable2Size) + (sizeof(uint16_t) * kCombiningMarkTable3Size) + (sizeof(uint16_t) * kCombiningMarkTable28Size) + (sizeof(uint16_t) * kConnectorPunctuationTable0Size) + (sizeof(uint16_t) * kConnectorPunctuationTable1Size) + (sizeof(uint16_t) * kToLowercaseTable0Size) + (sizeof(uint16_t) * kToLowercaseTable1Size) + (sizeof(uint16_t) * kToLowercaseTable2Size) + (sizeof(uint16_t) * kToUppercaseTable0Size) + (sizeof(uint16_t) * kToUppercaseTable1Size) + (sizeof(uint16_t) * kToUppercaseTable2Size); // NOLINT
+ return 0 + (sizeof(uint16_t) * kUppercaseTable0Size) + (sizeof(uint16_t) * kUppercaseTable1Size) + (sizeof(uint16_t) * kUppercaseTable2Size) + (sizeof(uint16_t) * kUppercaseTable3Size) + (sizeof(uint16_t) * kLowercaseTable0Size) + (sizeof(uint16_t) * kLowercaseTable1Size) + (sizeof(uint16_t) * kLowercaseTable2Size) + (sizeof(uint16_t) * kLowercaseTable3Size) + (sizeof(uint16_t) * kLetterTable0Size) + (sizeof(uint16_t) * kLetterTable1Size) + (sizeof(uint16_t) * kLetterTable2Size) + (sizeof(uint16_t) * kLetterTable3Size) + (sizeof(uint16_t) * kLetterTable4Size) + (sizeof(uint16_t) * kLetterTable5Size) + (sizeof(uint16_t) * kSpaceTable0Size) + (sizeof(uint16_t) * kNumberTable0Size) + (sizeof(uint16_t) * kNumberTable1Size) + (sizeof(uint16_t) * kNumberTable2Size) + (sizeof(uint16_t) * kNumberTable3Size) + (sizeof(uint16_t) * kWhiteSpaceTable0Size) + (sizeof(uint16_t) * kLineTerminatorTable0Size) + (sizeof(uint16_t) * kCombiningMarkTable0Size) + (sizeof(uint16_t) * kCombiningMarkTable1Size) + (sizeof(uint16_t) * kCombiningMarkTable2Size) + (sizeof(uint16_t) * kCombiningMarkTable3Size) + (sizeof(uint16_t) * kCombiningMarkTable28Size) + (sizeof(uint16_t) * kConnectorPunctuationTable0Size) + (sizeof(uint16_t) * kConnectorPunctuationTable1Size) + (sizeof(uint16_t) * kToLowercaseTable0Size) + (sizeof(uint16_t) * kToLowercaseTable1Size) + (sizeof(uint16_t) * kToLowercaseTable2Size) + (sizeof(uint16_t) * kToUppercaseTable0Size) + (sizeof(uint16_t) * kToUppercaseTable1Size) + (sizeof(uint16_t) * kToUppercaseTable2Size) + (sizeof(uint16_t) * kEcma262CanonicalizeTable0Size) + (sizeof(uint16_t) * kEcma262CanonicalizeTable1Size) + (sizeof(uint16_t) * kEcma262CanonicalizeTable2Size) + (sizeof(uint16_t) * kEcma262UnCanonicalizeTable0Size) + (sizeof(uint16_t) * kEcma262UnCanonicalizeTable1Size) + (sizeof(uint16_t) * kEcma262UnCanonicalizeTable2Size) + (sizeof(uint16_t) * kCanonicalizationRangeTable0Size) + (sizeof(uint16_t) * kCanonicalizationRangeTable1Size); // NOLINT
}
} // namespace unicode
diff --git a/src/unicode.h b/src/unicode.h
index fd7dfbc..86fd498 100644
--- a/src/unicode.h
+++ b/src/unicode.h
@@ -44,7 +44,7 @@
* The max length of the result of converting the case of a single
* character.
*/
-static const int kMaxCaseConvertedSize = 3;
+static const int kMaxMappingSize = 4;
template <class T, int size = 256>
class Predicate {
@@ -80,12 +80,13 @@
friend class Test;
int CalculateValue(uchar c, uchar n, uchar* result);
struct CacheEntry {
- inline CacheEntry() : code_point_(0), offset_(0) { }
+ inline CacheEntry() : code_point_(kNoChar), offset_(0) { }
inline CacheEntry(uchar code_point, signed offset)
: code_point_(code_point),
offset_(offset) { }
- uchar code_point_ : 21;
- signed offset_ : 11;
+ uchar code_point_;
+ signed offset_;
+ static const int kNoChar = (1 << 21) - 1;
};
static const int kSize = size;
static const int kMask = kSize - 1;
@@ -222,45 +223,15 @@
struct Space {
static bool Is(uchar c);
};
-struct Titlecase {
- static bool Is(uchar c);
-};
struct Number {
static bool Is(uchar c);
};
-struct DecimalDigit {
- static bool Is(uchar c);
-};
-struct Ideographic {
- static bool Is(uchar c);
-};
struct WhiteSpace {
static bool Is(uchar c);
};
-struct HexDigit {
- static bool Is(uchar c);
-};
-struct AsciiHexDigit {
- static bool Is(uchar c);
-};
-struct BidiControl {
- static bool Is(uchar c);
-};
-struct JoinControl {
- static bool Is(uchar c);
-};
-struct Dash {
- static bool Is(uchar c);
-};
-struct Hyphen {
- static bool Is(uchar c);
-};
struct LineTerminator {
static bool Is(uchar c);
};
-struct RegExpSpecialChar {
- static bool Is(uchar c);
-};
struct CombiningMark {
static bool Is(uchar c);
};
@@ -268,12 +239,35 @@
static bool Is(uchar c);
};
struct ToLowercase {
+ static const int kMaxWidth = 3;
static int Convert(uchar c,
uchar n,
uchar* result,
bool* allow_caching_ptr);
};
struct ToUppercase {
+ static const int kMaxWidth = 3;
+ static int Convert(uchar c,
+ uchar n,
+ uchar* result,
+ bool* allow_caching_ptr);
+};
+struct Ecma262Canonicalize {
+ static const int kMaxWidth = 1;
+ static int Convert(uchar c,
+ uchar n,
+ uchar* result,
+ bool* allow_caching_ptr);
+};
+struct Ecma262UnCanonicalize {
+ static const int kMaxWidth = 4;
+ static int Convert(uchar c,
+ uchar n,
+ uchar* result,
+ bool* allow_caching_ptr);
+};
+struct CanonicalizationRange {
+ static const int kMaxWidth = 1;
static int Convert(uchar c,
uchar n,
uchar* result,
diff --git a/src/usage-analyzer.cc b/src/usage-analyzer.cc
index 43f29a1..ad26cac 100644
--- a/src/usage-analyzer.cc
+++ b/src/usage-analyzer.cc
@@ -39,7 +39,7 @@
static const int InitialWeight = 100;
-class UsageComputer: public Visitor {
+class UsageComputer: public AstVisitor {
public:
static bool Traverse(Node* node);
@@ -73,6 +73,7 @@
void VisitThrow(Throw* node);
void VisitProperty(Property* node);
void VisitCall(Call* node);
+ void VisitCallEval(CallEval* node);
void VisitCallNew(CallNew* node);
void VisitCallRuntime(CallRuntime* node);
void VisitUnaryOperation(UnaryOperation* node);
@@ -321,6 +322,11 @@
}
+void UsageComputer::VisitCallEval(CallEval* node) {
+ VisitCall(node);
+}
+
+
void UsageComputer::VisitCallNew(CallNew* node) {
VisitCall(node);
}
diff --git a/src/utils.h b/src/utils.h
index 9f24079..34478ba 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -28,6 +28,8 @@
#ifndef V8_UTILS_H_
#define V8_UTILS_H_
+#include <stdlib.h>
+
namespace v8 { namespace internal {
// ----------------------------------------------------------------------------
@@ -83,6 +85,23 @@
}
+template <typename T>
+static int Compare(const T& a, const T& b) {
+ if (a == b)
+ return 0;
+ else if (a < b)
+ return -1;
+ else
+ return 1;
+}
+
+
+template <typename T>
+static int PointerValueCompare(const T* a, const T* b) {
+ return Compare<T>(*a, *b);
+}
+
+
// Returns the smallest power of two which is >= x. If you pass in a
// number that is already a power of two, it is returned as is.
uint32_t RoundUpToPowerOf2(uint32_t x);
@@ -283,6 +302,15 @@
return Vector<T>(NewArray<T>(length), length);
}
+ // Returns a vector using the same backing storage as this one,
+ // spanning from and including 'from', to but not including 'to'.
+ Vector<T> SubVector(int from, int to) {
+ ASSERT(from < length_);
+ ASSERT(to <= length_);
+ ASSERT(from < to);
+ return Vector<T>(start() + from, to - from);
+ }
+
// Returns the length of the vector.
int length() const { return length_; }
@@ -298,6 +326,10 @@
return start_[index];
}
+ T& first() { return start_[0]; }
+
+ T& last() { return start_[length_ - 1]; }
+
// Returns a clone of this vector with a new backing store.
Vector<T> Clone() const {
T* result = NewArray<T>(length_);
@@ -305,6 +337,18 @@
return Vector<T>(result, length_);
}
+ void Sort(int (*cmp)(const T*, const T*)) {
+ typedef int (*RawComparer)(const void*, const void*);
+ qsort(start(),
+ length(),
+ sizeof(T),
+ reinterpret_cast<RawComparer>(cmp));
+ }
+
+ void Sort() {
+ Sort(PointerValueCompare<T>);
+ }
+
// Releases the array underlying this vector. Once disposed the
// vector is empty.
void Dispose() {
@@ -465,6 +509,55 @@
}
}
+
+static inline int Load16(const byte* ptr) {
+#ifdef CAN_READ_UNALIGNED
+ return *reinterpret_cast<const uint16_t*>(ptr);
+#else
+ uint32_t word;
+ word = ptr[1];
+ word |= ptr[0] << 8;
+ return word;
+#endif
+}
+
+
+static inline int Load32(const byte* ptr) {
+#ifdef CAN_READ_UNALIGNED
+ return *reinterpret_cast<const uint32_t*>(ptr);
+#else
+ uint32_t word;
+ word = ptr[3];
+ word |= ptr[2] << 8;
+ word |= ptr[1] << 16;
+ word |= ptr[0] << 24;
+ return word;
+#endif
+}
+
+
+static inline void Store16(byte* ptr, uint16_t value) {
+#ifdef CAN_READ_UNALIGNED
+ *reinterpret_cast<uint16_t*>(ptr) = value;
+#else
+ ptr[1] = value;
+ ptr[0] = value >> 8;
+#endif
+}
+
+
+static inline void Store32(byte* ptr, uint32_t value) {
+#ifdef CAN_READ_UNALIGNED
+ *reinterpret_cast<uint32_t*>(ptr) = value;
+#else
+ ptr[3] = value;
+ ptr[2] = value >> 8;
+ ptr[1] = value >> 16;
+ ptr[0] = value >> 24;
+#endif
+}
+
+
} } // namespace v8::internal
#endif // V8_UTILS_H_
diff --git a/src/v8-counters.cc b/src/v8-counters.cc
index 95847f6..473dbd3 100644
--- a/src/v8-counters.cc
+++ b/src/v8-counters.cc
@@ -33,14 +33,14 @@
#define SR(name, caption) \
StatsRate Counters::name = { \
- { { L"t:" L###caption, NULL, false }, 0, 0 }, \
- { L"c:" L###caption, NULL, false } };
+ { { "t:" #caption, NULL, false }, 0, 0 }, \
+ { "c:" #caption, NULL, false } };
STATS_RATE_LIST(SR)
#undef SR
#define SC(name, caption) \
- StatsCounter Counters::name = { L"c:" L###caption, NULL, false };
+ StatsCounter Counters::name = { "c:" #caption, NULL, false };
STATS_COUNTER_LIST_1(SC)
STATS_COUNTER_LIST_2(SC)
@@ -48,7 +48,7 @@
StatsCounter Counters::state_counters[] = {
#define COUNTER_NAME(name) \
- { L"c:V8.State" L###name, NULL, false },
+ { "c:V8.State" #name, NULL, false },
STATE_TAG_LIST(COUNTER_NAME)
#undef COUNTER_NAME
};
diff --git a/src/v8-counters.h b/src/v8-counters.h
index 0f5af8a..586e002 100644
--- a/src/v8-counters.h
+++ b/src/v8-counters.h
@@ -118,7 +118,8 @@
SC(enum_cache_hits, V8.EnumCacheHits) \
SC(enum_cache_misses, V8.EnumCacheMisses) \
SC(reloc_info_count, V8.RelocInfoCount) \
- SC(reloc_info_size, V8.RelocInfoSize)
+ SC(reloc_info_size, V8.RelocInfoSize) \
+ SC(zone_segment_bytes, V8.ZoneSegmentBytes)
// This file contains all the v8 counters that are in use.
diff --git a/src/v8natives.js b/src/v8natives.js
index f3c98a5..9ca3b08 100644
--- a/src/v8natives.js
+++ b/src/v8natives.js
@@ -105,15 +105,15 @@
function GlobalEval(x) {
if (!IS_STRING(x)) return x;
- if (this !== %GlobalReceiver(global)) {
+ if (this !== global && this !== %GlobalReceiver(global)) {
throw new $EvalError('The "this" object passed to eval must ' +
'be the global object from which eval originated');
}
- var f = %CompileString(x, 0, true);
+ var f = %CompileString(x, 0);
if (!IS_FUNCTION(f)) return f;
- return f.call(%EvalReceiver(this));
+ return f.call(this);
}
@@ -121,7 +121,7 @@
function GlobalExecScript(expr, lang) {
// NOTE: We don't care about the character casing.
if (!lang || /javascript/i.test(lang)) {
- var f = %CompileString(ToString(expr), 0, false);
+ var f = %CompileString(ToString(expr), 0);
f.call(%GlobalReceiver(global));
}
return null;
@@ -140,7 +140,7 @@
// ECMA-262 - 15.1.1.3.
%SetProperty(global, "undefined", void 0, DONT_ENUM | DONT_DELETE);
-
+
// Setup non-enumerable function on the global object.
InstallFunctions(global, DONT_ENUM, $Array(
"isNaN", GlobalIsNaN,
@@ -521,7 +521,7 @@
// The call to SetNewFunctionAttributes will ensure the prototype
// property of the resulting function is enumerable (ECMA262, 15.3.5.2).
- var f = %CompileString(source, -1, false)();
+ var f = %CompileString(source, -1)();
%FunctionSetName(f, "anonymous");
return %SetNewFunctionAttributes(f);
}
diff --git a/src/zone-inl.h b/src/zone-inl.h
index 7ed4e6b..fd66b64 100644
--- a/src/zone-inl.h
+++ b/src/zone-inl.h
@@ -29,12 +29,14 @@
#define V8_ZONE_INL_H_
#include "zone.h"
+#include "v8-counters.h"
namespace v8 { namespace internal {
inline void* Zone::New(int size) {
ASSERT(AssertNoZoneAllocation::allow_allocation());
+ ASSERT(ZoneScope::nesting() > 0);
// Round up the requested size to fit the alignment.
size = RoundUp(size, kAlignment);
@@ -48,6 +50,17 @@
}
+bool Zone::excess_allocation() {
+ return segment_bytes_allocated_ > zone_excess_limit_;
+}
+
+
+void Zone::adjust_segment_bytes_allocated(int delta) {
+ segment_bytes_allocated_ += delta;
+ Counters::zone_segment_bytes.Set(segment_bytes_allocated_);
+}
+
+
} } // namespace v8::internal
#endif // V8_ZONE_INL_H_
diff --git a/src/zone.cc b/src/zone.cc
index d37f4f7..cfa161a 100644
--- a/src/zone.cc
+++ b/src/zone.cc
@@ -34,6 +34,8 @@
Address Zone::position_ = 0;
Address Zone::limit_ = 0;
+int Zone::zone_excess_limit_ = 256 * MB;
+int Zone::segment_bytes_allocated_ = 0;
bool AssertNoZoneAllocation::allow_allocation_ = true;
@@ -63,6 +65,7 @@
// of the segment chain. Returns the new segment.
static Segment* New(int size) {
Segment* result = reinterpret_cast<Segment*>(Malloced::New(size));
+ Zone::adjust_segment_bytes_allocated(size);
if (result != NULL) {
result->next_ = head_;
result->size_ = size;
@@ -72,10 +75,13 @@
}
// Deletes the given segment. Does not touch the segment chain.
- static void Delete(Segment* segment) {
+ static void Delete(Segment* segment, int size) {
+ Zone::adjust_segment_bytes_allocated(-size);
Malloced::Delete(segment);
}
+ static int bytes_allocated() { return bytes_allocated_; }
+
private:
// Computes the address of the nth byte in this segment.
Address address(int n) const {
@@ -83,12 +89,14 @@
}
static Segment* head_;
+ static int bytes_allocated_;
Segment* next_;
int size_;
};
Segment* Segment::head_ = NULL;
+int Segment::bytes_allocated_ = 0;
void Zone::DeleteAll() {
@@ -112,11 +120,12 @@
// Unlink the segment we wish to keep from the list.
current->clear_next();
} else {
+ int size = current->size();
#ifdef DEBUG
// Zap the entire current segment (including the header).
- memset(current, kZapDeadByte, current->size());
+ memset(current, kZapDeadByte, size);
#endif
- Segment::Delete(current);
+ Segment::Delete(current, size);
}
current = next;
}
diff --git a/src/zone.h b/src/zone.h
index c7129ec..612819e 100644
--- a/src/zone.h
+++ b/src/zone.h
@@ -61,7 +61,14 @@
// Delete all objects and free all memory allocated in the Zone.
static void DeleteAll();
+ // Returns true if more memory has been allocated in zones than
+ // the limit allows.
+ static inline bool excess_allocation();
+
+ static inline void adjust_segment_bytes_allocated(int delta);
+
private:
+
// All pointers returned from New() have this alignment.
static const int kAlignment = kPointerSize;
@@ -71,6 +78,13 @@
// Never keep segments larger than this size in bytes around.
static const int kMaximumKeptSegmentSize = 64 * KB;
+ // Report zone excess when allocation exceeds this limit.
+ static int zone_excess_limit_;
+
+ // The number of bytes allocated in segments. Note that this number
+ // includes memory allocated from the OS but not yet allocated from
+ // the zone.
+ static int segment_bytes_allocated_;
// The Zone is intentionally a singleton; you should not try to
// allocate instances of the class.
@@ -170,6 +184,8 @@
mode_ = DELETE_ON_EXIT;
}
+ static int nesting() { return nesting_; }
+
private:
ZoneScopeMode mode_;
static int nesting_;