From ff54e6899f3a3405a242558eb83d96f76984b235 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Bargull?=
Date: Tue, 12 Nov 2019 17:02:16 +0100
Subject: [PATCH 01/14] Issue #1283 - Implement Promise.prototype.finally()
This resolves #1283.
---
js/src/builtin/Promise.cpp | 8 +++
js/src/builtin/Promise.h | 8 +++
js/src/builtin/Promise.js | 69 +++++++++++++++++++++
js/src/vm/SelfHosting.cpp | 19 ++++++
js/xpconnect/tests/chrome/test_xrayToJS.xul | 2 +-
5 files changed, 105 insertions(+), 1 deletion(-)
diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp
index ec7845e89d..1d068f8c64 100644
--- a/js/src/builtin/Promise.cpp
+++ b/js/src/builtin/Promise.cpp
@@ -2006,6 +2006,13 @@ CommonStaticResolveRejectImpl(JSContext* cx, HandleValue thisVal, HandleValue ar
return promise;
}
+MOZ_MUST_USE JSObject*
+js::PromiseResolve(JSContext* cx, HandleObject constructor, HandleValue value)
+{
+ RootedValue C(cx, ObjectValue(*constructor));
+ return CommonStaticResolveRejectImpl(cx, C, value, ResolveMode);
+}
+
/**
* ES2016, 25.4.4.4, Promise.reject.
*/
@@ -2739,6 +2746,7 @@ CreatePromisePrototype(JSContext* cx, JSProtoKey key)
static const JSFunctionSpec promise_methods[] = {
JS_SELF_HOSTED_FN("catch", "Promise_catch", 1, 0),
JS_FN("then", Promise_then, 2, 0),
+ JS_SELF_HOSTED_FN("finally", "Promise_finally", 1, 0),
JS_FS_END
};
diff --git a/js/src/builtin/Promise.h b/js/src/builtin/Promise.h
index c76dc358c7..6a6453e465 100644
--- a/js/src/builtin/Promise.h
+++ b/js/src/builtin/Promise.h
@@ -128,6 +128,14 @@ OriginalPromiseThen(JSContext* cx, Handle promise,
HandleValue onFulfilled, HandleValue onRejected,
MutableHandleObject dependent, bool createDependent);
+/**
+ * PromiseResolve ( C, x )
+ *
+ * The abstract operation PromiseResolve, given a constructor and a value,
+ * returns a new promise resolved with that value.
+ */
+MOZ_MUST_USE JSObject*
+PromiseResolve(JSContext* cx, HandleObject constructor, HandleValue value);
MOZ_MUST_USE PromiseObject*
CreatePromiseObjectForAsync(JSContext* cx, HandleValue generatorVal);
diff --git a/js/src/builtin/Promise.js b/js/src/builtin/Promise.js
index 704cbab0be..91a1e1f562 100644
--- a/js/src/builtin/Promise.js
+++ b/js/src/builtin/Promise.js
@@ -14,3 +14,72 @@ function Promise_catch(onRejected) {
// Steps 1-2.
return callContentFunction(this.then, this, undefined, onRejected);
}
+
+// Promise.prototype.finally(onFinally)
+// See https://tc39.es/proposal-promise-finally/
+function Promise_finally(onFinally) {
+ // Step 1.
+ var promise = this;
+
+ // Step 2.
+ if (!IsObject(promise))
+ ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "Promise", "finally", "value");
+
+ // Step 3.
+ var C = SpeciesConstructor(promise, GetBuiltinConstructor("Promise"));
+
+ // Step 4.
+ assert(IsConstructor(C), "SpeciesConstructor returns a constructor function");
+
+ // Steps 5-6.
+ var thenFinally, catchFinally;
+ if (!IsCallable(onFinally)) {
+ thenFinally = onFinally;
+ catchFinally = onFinally;
+ } else {
+ // ThenFinally Function.
+ // The parentheses prevent the inferring of a function name.
+ (thenFinally) = function(value) {
+ // Steps 1-2 (implicit).
+
+ // Step 3.
+ var result = onFinally();
+
+ // Steps 4-5 (implicit).
+
+ // Step 6.
+ var promise = PromiseResolve(C, result);
+
+ // Step 7.
+ // FIXME: spec issue - "be equivalent to a function that" is not a defined spec term.
+ // https://github.com/tc39/ecma262/issues/933
+
+ // Step 8.
+ return callContentFunction(promise.then, promise, function() { return value; });
+ };
+
+ // CatchFinally Function.
+ // The parentheses prevent the inferring of a function name.
+ (catchFinally) = function(reason) {
+ // Steps 1-2 (implicit).
+
+ // Step 3.
+ var result = onFinally();
+
+ // Steps 4-5 (implicit).
+
+ // Step 6.
+ var promise = PromiseResolve(C, result);
+
+ // Step 7.
+ // FIXME: spec issue - "be equivalent to a function that" is not a defined spec term.
+ // https://github.com/tc39/ecma262/issues/933
+
+ // Step 8.
+ return callContentFunction(promise.then, promise, function() { throw reason; });
+ };
+ }
+
+ // Step 7.
+ return callContentFunction(promise.then, promise, thenFinally, catchFinally);
+}
diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp
index 82d2cde642..8334104652 100644
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -2102,6 +2102,21 @@ intrinsic_ModuleNamespaceExports(JSContext* cx, unsigned argc, Value* vp)
return true;
}
+static bool
+intrinsic_PromiseResolve(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 2);
+
+ RootedObject constructor(cx, &args[0].toObject());
+ JSObject* promise = js::PromiseResolve(cx, constructor, args[1]);
+ if (!promise)
+ return false;
+
+ args.rval().setObject(*promise);
+ return true;
+}
+
// The self-hosting global isn't initialized with the normal set of builtins.
// Instead, individual C++-implemented functions that're required by
// self-hosted code are defined as global functions. Accessing these
@@ -2498,6 +2513,10 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("AddModuleNamespaceBinding", intrinsic_AddModuleNamespaceBinding, 4, 0),
JS_FN("ModuleNamespaceExports", intrinsic_ModuleNamespaceExports, 1, 0),
+ JS_FN("IsPromiseObject", intrinsic_IsInstanceOfBuiltin, 1, 0),
+ JS_FN("CallPromiseMethodIfWrapped", CallNonGenericSelfhostedMethod>, 2, 0),
+ JS_FN("PromiseResolve", intrinsic_PromiseResolve, 2, 0),
+
JS_FS_END
};
diff --git a/js/xpconnect/tests/chrome/test_xrayToJS.xul b/js/xpconnect/tests/chrome/test_xrayToJS.xul
index 495b996074..38f3f447d8 100644
--- a/js/xpconnect/tests/chrome/test_xrayToJS.xul
+++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul
@@ -243,7 +243,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681
"$`", "$'", Symbol.species])
gPrototypeProperties['Promise'] =
- ["constructor", "catch", "then", Symbol.toStringTag];
+ ["constructor", "catch", "then", "finally", Symbol.toStringTag];
gConstructorProperties['Promise'] =
constructorProps(["resolve", "reject", "all", "race", Symbol.species]);
From 63b7dedc94f414d9e123b3bf74c2a3e60178f2bd Mon Sep 17 00:00:00 2001
From: wolfbeast
Date: Mon, 11 Nov 2019 23:37:35 +0100
Subject: [PATCH 02/14] Issue #1279 - Implement regular expression lookbehind
Based on Tom Schuster's work, with extra minters for unicode.
---
.../irregexp/NativeRegExpMacroAssembler.cpp | 8 +-
js/src/irregexp/NativeRegExpMacroAssembler.h | 7 +-
js/src/irregexp/RegExpAST.cpp | 8 +-
js/src/irregexp/RegExpAST.h | 33 ++--
js/src/irregexp/RegExpBytecode.h | 23 +--
js/src/irregexp/RegExpEngine.cpp | 149 +++++++++++-------
js/src/irregexp/RegExpEngine.h | 31 +++-
js/src/irregexp/RegExpInterpreter.cpp | 74 ++++++++-
js/src/irregexp/RegExpMacroAssembler.cpp | 17 +-
js/src/irregexp/RegExpMacroAssembler.h | 15 +-
js/src/irregexp/RegExpParser.cpp | 130 ++++++++++-----
js/src/irregexp/RegExpParser.h | 19 ++-
12 files changed, 358 insertions(+), 156 deletions(-)
diff --git a/js/src/irregexp/NativeRegExpMacroAssembler.cpp b/js/src/irregexp/NativeRegExpMacroAssembler.cpp
index 0fb5072973..e17eecb9bb 100644
--- a/js/src/irregexp/NativeRegExpMacroAssembler.cpp
+++ b/js/src/irregexp/NativeRegExpMacroAssembler.cpp
@@ -582,7 +582,7 @@ NativeRegExpMacroAssembler::CheckAtStart(Label* on_at_start)
}
void
-NativeRegExpMacroAssembler::CheckNotAtStart(Label* on_not_at_start)
+NativeRegExpMacroAssembler::CheckNotAtStart(int cp_offset, Label* on_not_at_start)
{
JitSpew(SPEW_PREFIX "CheckNotAtStart");
@@ -673,7 +673,7 @@ NativeRegExpMacroAssembler::CheckGreedyLoop(Label* on_tos_equals_current_positio
}
void
-NativeRegExpMacroAssembler::CheckNotBackReference(int start_reg, Label* on_no_match)
+NativeRegExpMacroAssembler::CheckNotBackReference(int start_reg, bool read_backward, Label* on_no_match)
{
JitSpew(SPEW_PREFIX "CheckNotBackReference(%d)", start_reg);
@@ -744,8 +744,8 @@ NativeRegExpMacroAssembler::CheckNotBackReference(int start_reg, Label* on_no_ma
}
void
-NativeRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase(int start_reg, Label* on_no_match,
- bool unicode)
+NativeRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase(int start_reg, bool read_backward,
+ Label* on_no_match, bool unicode)
{
JitSpew(SPEW_PREFIX "CheckNotBackReferenceIgnoreCase(%d, %d)", start_reg, unicode);
diff --git a/js/src/irregexp/NativeRegExpMacroAssembler.h b/js/src/irregexp/NativeRegExpMacroAssembler.h
index 7a72e252ff..fc582dccf2 100644
--- a/js/src/irregexp/NativeRegExpMacroAssembler.h
+++ b/js/src/irregexp/NativeRegExpMacroAssembler.h
@@ -105,9 +105,10 @@ class MOZ_STACK_CLASS NativeRegExpMacroAssembler final : public RegExpMacroAssem
void CheckCharacterGT(char16_t limit, jit::Label* on_greater);
void CheckCharacterLT(char16_t limit, jit::Label* on_less);
void CheckGreedyLoop(jit::Label* on_tos_equals_current_position);
- void CheckNotAtStart(jit::Label* on_not_at_start);
- void CheckNotBackReference(int start_reg, jit::Label* on_no_match);
- void CheckNotBackReferenceIgnoreCase(int start_reg, jit::Label* on_no_match, bool unicode);
+ void CheckNotAtStart(int cp_offset, jit::Label* on_not_at_start);
+ void CheckNotBackReference(int start_reg, bool read_backward, jit::Label* on_no_match);
+ void CheckNotBackReferenceIgnoreCase(int start_reg, bool read_backward,
+ jit::Label* on_no_match, bool unicode);
void CheckNotCharacter(unsigned c, jit::Label* on_not_equal);
void CheckNotCharacterAfterAnd(unsigned c, unsigned and_with, jit::Label* on_not_equal);
void CheckNotCharacterAfterMinusAnd(char16_t c, char16_t minus, char16_t and_with,
diff --git a/js/src/irregexp/RegExpAST.cpp b/js/src/irregexp/RegExpAST.cpp
index 8dfd99057b..43867c3123 100644
--- a/js/src/irregexp/RegExpAST.cpp
+++ b/js/src/irregexp/RegExpAST.cpp
@@ -250,16 +250,16 @@ RegExpCapture::CaptureRegisters()
}
// ----------------------------------------------------------------------------
-// RegExpLookahead
+// RegExpLookaround
Interval
-RegExpLookahead::CaptureRegisters()
+RegExpLookaround::CaptureRegisters()
{
return body()->CaptureRegisters();
}
bool
-RegExpLookahead::IsAnchoredAtStart()
+RegExpLookaround::IsAnchoredAtStart()
{
- return is_positive() && body()->IsAnchoredAtStart();
+ return is_positive() && type() == LOOKAHEAD && body()->IsAnchoredAtStart();
}
diff --git a/js/src/irregexp/RegExpAST.h b/js/src/irregexp/RegExpAST.h
index 7bda6fc7e6..6f59842bcb 100644
--- a/js/src/irregexp/RegExpAST.h
+++ b/js/src/irregexp/RegExpAST.h
@@ -360,6 +360,7 @@ class RegExpCapture : public RegExpTree
virtual int min_match() { return body_->min_match(); }
virtual int max_match() { return body_->max_match(); }
RegExpTree* body() { return body_; }
+ void set_body(RegExpTree* body) { body_ = body; }
int index() { return index_; }
static int StartRegister(int index) { return index * 2; }
static int EndRegister(int index) { return index * 2 + 1; }
@@ -369,25 +370,29 @@ class RegExpCapture : public RegExpTree
int index_;
};
-class RegExpLookahead : public RegExpTree
+class RegExpLookaround : public RegExpTree
{
public:
- RegExpLookahead(RegExpTree* body,
- bool is_positive,
- int capture_count,
- int capture_from)
+ enum Type { LOOKAHEAD, LOOKBEHIND };
+
+ RegExpLookaround(RegExpTree* body,
+ bool is_positive,
+ int capture_count,
+ int capture_from,
+ Type type)
: body_(body),
is_positive_(is_positive),
capture_count_(capture_count),
- capture_from_(capture_from)
+ capture_from_(capture_from),
+ type_(type)
{}
virtual void* Accept(RegExpVisitor* visitor, void* data);
virtual RegExpNode* ToNode(RegExpCompiler* compiler,
RegExpNode* on_success);
- virtual RegExpLookahead* AsLookahead();
+ virtual RegExpLookaround* AsLookaround();
virtual Interval CaptureRegisters();
- virtual bool IsLookahead();
+ virtual bool IsLookaround();
virtual bool IsAnchoredAtStart();
virtual int min_match() { return 0; }
virtual int max_match() { return 0; }
@@ -395,12 +400,14 @@ class RegExpLookahead : public RegExpTree
bool is_positive() { return is_positive_; }
int capture_count() { return capture_count_; }
int capture_from() { return capture_from_; }
+ Type type() { return type_; }
private:
RegExpTree* body_;
bool is_positive_;
int capture_count_;
int capture_from_;
+ Type type_;
};
typedef InfallibleVector RegExpCaptureVector;
@@ -417,8 +424,14 @@ class RegExpBackReference : public RegExpTree
RegExpNode* on_success);
virtual RegExpBackReference* AsBackReference();
virtual bool IsBackReference();
- virtual int min_match() { return 0; }
- virtual int max_match() { return capture_->max_match(); }
+ virtual int min_match() override { return 0; }
+ // The capture may not be completely parsed yet, if the reference occurs
+ // before the capture. In the ordinary case, nothing has been captured yet,
+ // so the back reference must have the length 0. If the back reference is
+ // inside a lookbehind, effectively making it a forward reference, we return
+ virtual int max_match() override {
+ return capture_->body() ? capture_->max_match() : 0;
+ }
int index() { return capture_->index(); }
RegExpCapture* capture() { return capture_; }
private:
diff --git a/js/src/irregexp/RegExpBytecode.h b/js/src/irregexp/RegExpBytecode.h
index f31b78c593..ea3f80b4f0 100644
--- a/js/src/irregexp/RegExpBytecode.h
+++ b/js/src/irregexp/RegExpBytecode.h
@@ -82,16 +82,19 @@ V(CHECK_LT, 35, 8) /* bc8 pad8 uc16 addr32 */ \
V(CHECK_GT, 36, 8) /* bc8 pad8 uc16 addr32 */ \
V(CHECK_NOT_BACK_REF, 37, 8) /* bc8 reg_idx24 addr32 */ \
V(CHECK_NOT_BACK_REF_NO_CASE, 38, 8) /* bc8 reg_idx24 addr32 */ \
-V(CHECK_NOT_REGS_EQUAL, 39, 12) /* bc8 regidx24 reg_idx32 addr32 */ \
-V(CHECK_REGISTER_LT, 40, 12) /* bc8 reg_idx24 value32 addr32 */ \
-V(CHECK_REGISTER_GE, 41, 12) /* bc8 reg_idx24 value32 addr32 */ \
-V(CHECK_REGISTER_EQ_POS, 42, 8) /* bc8 reg_idx24 addr32 */ \
-V(CHECK_AT_START, 43, 8) /* bc8 pad24 addr32 */ \
-V(CHECK_NOT_AT_START, 44, 8) /* bc8 pad24 addr32 */ \
-V(CHECK_GREEDY, 45, 8) /* bc8 pad24 addr32 */ \
-V(ADVANCE_CP_AND_GOTO, 46, 8) /* bc8 offset24 addr32 */ \
-V(SET_CURRENT_POSITION_FROM_END, 47, 4) /* bc8 idx24 */ \
-V(CHECK_NOT_BACK_REF_NO_CASE_UNICODE, 48, 8) /* bc8 reg_idx24 addr32 */
+V(CHECK_NOT_BACK_REF_BACKWARD, 39, 8) /* bc8 reg_idx24 addr32 */ \
+V(CHECK_NOT_BACK_REF_NO_CASE_BACKWARD, 40, 8) /* bc8 reg_idx24 addr32 */ \
+V(CHECK_NOT_REGS_EQUAL, 41, 12) /* bc8 regidx24 reg_idx32 addr32 */ \
+V(CHECK_REGISTER_LT, 42, 12) /* bc8 reg_idx24 value32 addr32 */ \
+V(CHECK_REGISTER_GE, 43, 12) /* bc8 reg_idx24 value32 addr32 */ \
+V(CHECK_REGISTER_EQ_POS, 44, 8) /* bc8 reg_idx24 addr32 */ \
+V(CHECK_AT_START, 45, 8) /* bc8 pad24 addr32 */ \
+V(CHECK_NOT_AT_START, 46, 8) /* bc8 pad24 addr32 */ \
+V(CHECK_GREEDY, 47, 8) /* bc8 pad24 addr32 */ \
+V(ADVANCE_CP_AND_GOTO, 48, 8) /* bc8 offset24 addr32 */ \
+V(SET_CURRENT_POSITION_FROM_END, 49, 4) /* bc8 idx24 */ \
+V(CHECK_NOT_BACK_REF_NO_CASE_UNICODE, 50, 8) /* bc8 reg_idx24 addr32 */ \
+V(CHECK_NOT_BACK_REF_NO_CASE_BACKWARD_UNICODE, 51, 8) /* bc8 reg_idx24 addr32 */
#define DECLARE_BYTECODES(name, code, length) \
static const int BC_##name = code;
diff --git a/js/src/irregexp/RegExpEngine.cpp b/js/src/irregexp/RegExpEngine.cpp
index 4d691a5dc9..62f94c3e72 100644
--- a/js/src/irregexp/RegExpEngine.cpp
+++ b/js/src/irregexp/RegExpEngine.cpp
@@ -721,6 +721,8 @@ ActionNode::EmptyMatchCheck(int start_register,
int
TextNode::EatsAtLeast(int still_to_find, int budget, bool not_at_start)
{
+ if (read_backward())
+ return 0;
int answer = Length();
if (answer >= still_to_find)
return answer;
@@ -736,8 +738,7 @@ TextNode::EatsAtLeast(int still_to_find, int budget, bool not_at_start)
int
TextNode::GreedyLoopTextLength()
{
- TextElement elm = elements()[elements().length() - 1];
- return elm.cp_offset() + elm.length();
+ return Length();
}
RegExpNode*
@@ -887,6 +888,8 @@ AssertionNode::FillInBMInfo(int offset, int budget, BoyerMooreLookahead* bm, boo
int
BackReferenceNode::EatsAtLeast(int still_to_find, int budget, bool not_at_start)
{
+ if (read_backward())
+ return 0;
if (budget <= 0)
return 0;
return on_success()->EatsAtLeast(still_to_find, budget - 1, not_at_start);
@@ -1578,6 +1581,9 @@ class irregexp::RegExpCompiler
current_expansion_factor_ = value;
}
+ bool read_backward() { return read_backward_; }
+ void set_read_backward(bool value) { read_backward_ = value; }
+
JSContext* cx() const { return cx_; }
LifoAlloc* alloc() const { return alloc_; }
@@ -1595,6 +1601,7 @@ class irregexp::RegExpCompiler
bool unicode_;
bool reg_exp_too_big_;
int current_expansion_factor_;
+ bool read_backward_;
FrequencyCollator frequency_collator_;
JSContext* cx_;
LifoAlloc* alloc_;
@@ -1624,6 +1631,7 @@ RegExpCompiler::RegExpCompiler(JSContext* cx, LifoAlloc* alloc, int capture_coun
unicode_(unicode),
reg_exp_too_big_(false),
current_expansion_factor_(1),
+ read_backward_(false),
frequency_collator_(),
cx_(cx),
alloc_(alloc)
@@ -1747,7 +1755,7 @@ irregexp::CompilePattern(JSContext* cx, RegExpShared* shared, RegExpCompileData*
// at the start of input.
ChoiceNode* first_step_node = alloc.newInfallible(&alloc, 2);
RegExpNode* char_class =
- alloc.newInfallible(alloc.newInfallible('*'), loop_node);
+ alloc.newInfallible(alloc.newInfallible('*'), false, loop_node);
first_step_node->AddAlternative(GuardedAlternative(captured_body));
first_step_node->AddAlternative(GuardedAlternative(char_class));
node = first_step_node;
@@ -1850,19 +1858,19 @@ RegExpAtom::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
TextElementVector* elms =
compiler->alloc()->newInfallible(*compiler->alloc());
elms->append(TextElement::Atom(this));
- return compiler->alloc()->newInfallible(elms, on_success);
+ return compiler->alloc()->newInfallible(elms, compiler->read_backward(), on_success);
}
RegExpNode*
RegExpText::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
{
- return compiler->alloc()->newInfallible(&elements_, on_success);
+ return compiler->alloc()->newInfallible(&elements_, compiler->read_backward(), on_success);
}
RegExpNode*
RegExpCharacterClass::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
{
- return compiler->alloc()->newInfallible(this, on_success);
+ return compiler->alloc()->newInfallible(this, compiler->read_backward(), on_success);
}
RegExpNode*
@@ -2003,7 +2011,8 @@ RegExpQuantifier::ToNode(int min,
alternation->AddAlternative(GuardedAlternative(body->ToNode(compiler, answer)));
}
answer = alternation;
- if (not_at_start) alternation->set_not_at_start();
+ if (not_at_start && !compiler->read_backward())
+ alternation->set_not_at_start();
}
return answer;
}
@@ -2015,8 +2024,9 @@ RegExpQuantifier::ToNode(int min,
int reg_ctr = needs_counter
? compiler->AllocateRegister()
: RegExpCompiler::kNoRegister;
- LoopChoiceNode* center = alloc->newInfallible(alloc, body->min_match() == 0);
- if (not_at_start)
+ LoopChoiceNode* center = alloc->newInfallible(alloc, body->min_match() == 0,
+ compiler->read_backward());
+ if (not_at_start && !compiler->read_backward())
center->set_not_at_start();
RegExpNode* loop_return = needs_counter
? static_cast(ActionNode::IncrementRegister(reg_ctr, center))
@@ -2092,7 +2102,7 @@ RegExpAssertion::ToNode(RegExpCompiler* compiler,
CharacterRange::AddClassEscape(alloc, 'n', newline_ranges);
RegExpCharacterClass* newline_atom = alloc->newInfallible('n');
TextNode* newline_matcher =
- alloc->newInfallible(newline_atom,
+ alloc->newInfallible(newline_atom, false,
ActionNode::PositiveSubmatchSuccess(stack_pointer_register,
position_register,
0, // No captures inside.
@@ -2124,6 +2134,7 @@ RegExpBackReference::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
{
return compiler->alloc()->newInfallible(RegExpCapture::StartRegister(index()),
RegExpCapture::EndRegister(index()),
+ compiler->read_backward(),
on_success);
}
@@ -2134,7 +2145,7 @@ RegExpEmpty::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
}
RegExpNode*
-RegExpLookahead::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
+RegExpLookaround::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
{
int stack_pointer_register = compiler->AllocateRegister();
int position_register = compiler->AllocateRegister();
@@ -2145,6 +2156,10 @@ RegExpLookahead::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
int register_start =
register_of_first_capture + capture_from_ * registers_per_capture;
+ RegExpNode* result;
+ bool was_reading_backward = compiler->read_backward();
+ compiler->set_read_backward(type() == LOOKBEHIND);
+
if (is_positive()) {
RegExpNode* bodyNode =
body()->ToNode(compiler,
@@ -2153,37 +2168,39 @@ RegExpLookahead::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
register_count,
register_start,
on_success));
- return ActionNode::BeginSubmatch(stack_pointer_register,
+ result = ActionNode::BeginSubmatch(stack_pointer_register,
+ position_register,
+ bodyNode);
+ } else {
+ // We use a ChoiceNode for a negative lookahead because it has most of
+ // the characteristics we need. It has the body of the lookahead as its
+ // first alternative and the expression after the lookahead of the second
+ // alternative. If the first alternative succeeds then the
+ // NegativeSubmatchSuccess will unwind the stack including everything the
+ // choice node set up and backtrack. If the first alternative fails then
+ // the second alternative is tried, which is exactly the desired result
+ // for a negative lookahead. The NegativeLookaheadChoiceNode is a special
+ // ChoiceNode that knows to ignore the first exit when calculating quick
+ // checks.
+ LifoAlloc* alloc = compiler->alloc();
+
+ RegExpNode* success =
+ alloc->newInfallible(alloc,
+ stack_pointer_register,
+ position_register,
+ register_count,
+ register_start);
+ GuardedAlternative body_alt(body()->ToNode(compiler, success));
+
+ ChoiceNode* choice_node =
+ alloc->newInfallible(alloc, body_alt, GuardedAlternative(on_success));
+
+ result = ActionNode::BeginSubmatch(stack_pointer_register,
position_register,
- bodyNode);
+ choice_node);
}
-
- // We use a ChoiceNode for a negative lookahead because it has most of
- // the characteristics we need. It has the body of the lookahead as its
- // first alternative and the expression after the lookahead of the second
- // alternative. If the first alternative succeeds then the
- // NegativeSubmatchSuccess will unwind the stack including everything the
- // choice node set up and backtrack. If the first alternative fails then
- // the second alternative is tried, which is exactly the desired result
- // for a negative lookahead. The NegativeLookaheadChoiceNode is a special
- // ChoiceNode that knows to ignore the first exit when calculating quick
- // checks.
- LifoAlloc* alloc = compiler->alloc();
-
- RegExpNode* success =
- alloc->newInfallible(alloc,
- stack_pointer_register,
- position_register,
- register_count,
- register_start);
- GuardedAlternative body_alt(body()->ToNode(compiler, success));
-
- ChoiceNode* choice_node =
- alloc->newInfallible(alloc, body_alt, GuardedAlternative(on_success));
-
- return ActionNode::BeginSubmatch(stack_pointer_register,
- position_register,
- choice_node);
+ compiler->set_read_backward(was_reading_backward);
+ return result;
}
RegExpNode*
@@ -2198,8 +2215,14 @@ RegExpCapture::ToNode(RegExpTree* body,
RegExpCompiler* compiler,
RegExpNode* on_success)
{
+ MOZ_ASSERT(body);
int start_reg = RegExpCapture::StartRegister(index);
int end_reg = RegExpCapture::EndRegister(index);
+ if (compiler->read_backward()) {
+ // std::swap(start_reg, end_reg);
+ start_reg = RegExpCapture::EndRegister(index);
+ end_reg = RegExpCapture::StartRegister(index);
+ }
RegExpNode* store_end = ActionNode::StorePosition(end_reg, true, on_success);
RegExpNode* body_node = body->ToNode(compiler, store_end);
return ActionNode::StorePosition(start_reg, true, body_node);
@@ -2210,8 +2233,15 @@ RegExpAlternative::ToNode(RegExpCompiler* compiler, RegExpNode* on_success)
{
const RegExpTreeVector& children = nodes();
RegExpNode* current = on_success;
- for (int i = children.length() - 1; i >= 0; i--)
- current = children[i]->ToNode(compiler, current);
+ if (compiler->read_backward()) {
+ for (int i = 0; i < children.length(); i++) {
+ current = children[i]->ToNode(compiler, current);
+ }
+ } else {
+ for (int i = children.length() - 1; i >= 0; i--) {
+ current = children[i]->ToNode(compiler, current);
+ }
+ }
return current;
}
@@ -2764,7 +2794,6 @@ Trace::InvalidateCurrentCharacter()
void
Trace::AdvanceCurrentPositionInTrace(int by, RegExpCompiler* compiler)
{
- MOZ_ASSERT(by > 0);
// We don't have an instruction for shifting the current character register
// down or for using a shifted value for anything so lets just forget that
// we preloaded any characters into it.
@@ -3109,9 +3138,9 @@ AssertionNode::Emit(RegExpCompiler* compiler, Trace* trace)
return;
}
if (trace->at_start() == Trace::UNKNOWN) {
- assembler->CheckNotAtStart(trace->backtrack());
+ assembler->CheckNotAtStart(trace->cp_offset(), trace->backtrack());
Trace at_start_trace = *trace;
- at_start_trace.set_at_start(true);
+ at_start_trace.set_at_start(Trace::TRUE_VALUE);
on_success()->Emit(compiler, &at_start_trace);
return;
}
@@ -3814,9 +3843,10 @@ TextNode::TextEmitPass(RegExpCompiler* compiler,
jit::Label* backtrack = trace->backtrack();
QuickCheckDetails* quick_check = trace->quick_check_performed();
int element_count = elements().length();
+ int backward_offset = read_backward() ? -Length() : 0;
for (int i = preloaded ? 0 : element_count - 1; i >= 0; i--) {
TextElement elm = elements()[i];
- int cp_offset = trace->cp_offset() + elm.cp_offset();
+ int cp_offset = trace->cp_offset() + elm.cp_offset() + backward_offset;
if (elm.text_type() == TextElement::ATOM) {
const CharacterVector& quarks = elm.atom()->data();
for (int j = preloaded ? 0 : quarks.length() - 1; j >= 0; j--) {
@@ -3844,11 +3874,12 @@ TextNode::TextEmitPass(RegExpCompiler* compiler,
break;
}
if (emit_function != nullptr) {
+ bool bounds_check = *checked_up_to < cp_offset + j || read_backward();
bool bound_checked = emit_function(compiler,
quarks[j],
backtrack,
cp_offset + j,
- *checked_up_to < cp_offset + j,
+ bounds_check,
preloaded);
if (bound_checked) UpdateBoundsCheck(cp_offset + j, checked_up_to);
}
@@ -3859,13 +3890,14 @@ TextNode::TextEmitPass(RegExpCompiler* compiler,
if (first_element_checked && i == 0) continue;
if (DeterminedAlready(quick_check, elm.cp_offset())) continue;
RegExpCharacterClass* cc = elm.char_class();
+ bool bounds_check = *checked_up_to < cp_offset || read_backward();
EmitCharClass(alloc(),
assembler,
cc,
ascii,
backtrack,
cp_offset,
- *checked_up_to < cp_offset,
+ bounds_check,
preloaded);
UpdateBoundsCheck(cp_offset, checked_up_to);
}
@@ -3945,8 +3977,11 @@ TextNode::Emit(RegExpCompiler* compiler, Trace* trace)
}
Trace successor_trace(*trace);
- successor_trace.set_at_start(false);
- successor_trace.AdvanceCurrentPositionInTrace(Length(), compiler);
+ // If we advance backward, we may end up at the start.
+ successor_trace.AdvanceCurrentPositionInTrace(
+ read_backward() ? -Length() : Length(), compiler);
+ successor_trace.set_at_start(read_backward() ? Trace::UNKNOWN
+ : Trace::FALSE_VALUE);
RecursionCheck rc(compiler);
on_success()->Emit(compiler, &successor_trace);
}
@@ -4118,6 +4153,8 @@ ChoiceNode::CalculatePreloadCharacters(RegExpCompiler* compiler, int eats_at_lea
RegExpNode*
TextNode::GetSuccessorOfOmnivorousTextNode(RegExpCompiler* compiler)
{
+ if (read_backward()) return NULL;
+
if (elements().length() != 1)
return nullptr;
@@ -4165,7 +4202,7 @@ ChoiceNode::GreedyLoopTextLengthForAlternative(GuardedAlternative* alternative)
SeqRegExpNode* seq_node = static_cast(node);
node = seq_node->on_success();
}
- return length;
+ return read_backward() ? -length : length;
}
// Creates a list of AlternativeGenerations. If the list has a reasonable
@@ -4240,7 +4277,7 @@ ChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace)
jit::Label greedy_loop_label;
Trace counter_backtrack_trace;
counter_backtrack_trace.set_backtrack(&greedy_loop_label);
- if (not_at_start()) counter_backtrack_trace.set_at_start(false);
+ if (not_at_start()) counter_backtrack_trace.set_at_start(Trace::FALSE_VALUE);
if (choice_count > 1 && text_length != kNodeIsTooComplexForGreedyLoops) {
// Here we have special handling for greedy loops containing only text nodes
@@ -4256,7 +4293,7 @@ ChoiceNode::Emit(RegExpCompiler* compiler, Trace* trace)
current_trace = &counter_backtrack_trace;
jit::Label greedy_match_failed;
Trace greedy_match_trace;
- if (not_at_start()) greedy_match_trace.set_at_start(false);
+ if (not_at_start()) greedy_match_trace.set_at_start(Trace::FALSE_VALUE);
greedy_match_trace.set_backtrack(&greedy_match_failed);
jit::Label loop_label;
macro_assembler->Bind(&loop_label);
@@ -4605,11 +4642,14 @@ BackReferenceNode::Emit(RegExpCompiler* compiler, Trace* trace)
MOZ_ASSERT(start_reg_ + 1 == end_reg_);
if (compiler->ignore_case()) {
assembler->CheckNotBackReferenceIgnoreCase(start_reg_,
+ read_backward(),
trace->backtrack(),
compiler->unicode());
} else {
- assembler->CheckNotBackReference(start_reg_, trace->backtrack());
+ assembler->CheckNotBackReference(start_reg_, read_backward(), trace->backtrack());
}
+ // We are going to advance backward, so we may end up at the start.
+ if (read_backward()) trace->set_at_start(Trace::UNKNOWN);
on_success()->Emit(compiler, trace);
}
@@ -4977,7 +5017,6 @@ QuickCheckDetails::Clear()
void
QuickCheckDetails::Advance(int by, bool ascii)
{
- MOZ_ASSERT(by >= 0);
if (by >= characters_) {
Clear();
return;
diff --git a/js/src/irregexp/RegExpEngine.h b/js/src/irregexp/RegExpEngine.h
index 1a8fd4b220..c4409dcca0 100644
--- a/js/src/irregexp/RegExpEngine.h
+++ b/js/src/irregexp/RegExpEngine.h
@@ -119,7 +119,7 @@ InterpretCode(JSContext* cx, const uint8_t* byteCode, const CharT* chars, size_t
VISIT(Atom) \
VISIT(Quantifier) \
VISIT(Capture) \
- VISIT(Lookahead) \
+ VISIT(Lookaround) \
VISIT(BackReference) \
VISIT(Empty) \
VISIT(Text)
@@ -763,15 +763,19 @@ class TextNode : public SeqRegExpNode
{
public:
TextNode(TextElementVector* elements,
+ bool read_backward,
RegExpNode* on_success)
: SeqRegExpNode(on_success),
- elements_(elements)
+ elements_(elements),
+ read_backward_(read_backward)
{}
TextNode(RegExpCharacterClass* that,
+ bool read_backward,
RegExpNode* on_success)
: SeqRegExpNode(on_success),
- elements_(alloc()->newInfallible(*alloc()))
+ elements_(alloc()->newInfallible(*alloc())),
+ read_backward_(read_backward)
{
elements_->append(TextElement::CharClass(that));
}
@@ -784,6 +788,7 @@ class TextNode : public SeqRegExpNode
int characters_filled_in,
bool not_at_start);
TextElementVector& elements() { return *elements_; }
+ bool read_backward() { return read_backward_; }
void MakeCaseIndependent(bool is_ascii, bool unicode);
virtual int GreedyLoopTextLength();
virtual RegExpNode* GetSuccessorOfOmnivorousTextNode(
@@ -814,6 +819,7 @@ class TextNode : public SeqRegExpNode
int* checked_up_to);
int Length();
TextElementVector* elements_;
+ bool read_backward_;
};
class AssertionNode : public SeqRegExpNode
@@ -882,15 +888,18 @@ class BackReferenceNode : public SeqRegExpNode
public:
BackReferenceNode(int start_reg,
int end_reg,
+ bool read_backward,
RegExpNode* on_success)
: SeqRegExpNode(on_success),
start_reg_(start_reg),
- end_reg_(end_reg)
+ end_reg_(end_reg),
+ read_backward_(read_backward)
{}
virtual void Accept(NodeVisitor* visitor);
int start_register() { return start_reg_; }
int end_register() { return end_reg_; }
+ bool read_backward() { return read_backward_; }
virtual void Emit(RegExpCompiler* compiler, Trace* trace);
virtual int EatsAtLeast(int still_to_find,
int recursion_depth,
@@ -909,6 +918,7 @@ class BackReferenceNode : public SeqRegExpNode
private:
int start_reg_;
int end_reg_;
+ bool read_backward_;
};
class EndNode : public RegExpNode
@@ -1053,6 +1063,7 @@ class ChoiceNode : public RegExpNode
void set_being_calculated(bool b) { being_calculated_ = b; }
virtual bool try_to_emit_quick_check_for_alternative(int i) { return true; }
virtual RegExpNode* FilterASCII(int depth, bool ignore_case, bool unicode);
+ virtual bool read_backward() { return false; }
protected:
int GreedyLoopTextLengthForAlternative(GuardedAlternative* alternative);
@@ -1111,11 +1122,13 @@ class NegativeLookaheadChoiceNode : public ChoiceNode
class LoopChoiceNode : public ChoiceNode
{
public:
- explicit LoopChoiceNode(LifoAlloc* alloc, bool body_can_be_zero_length)
+ explicit LoopChoiceNode(LifoAlloc* alloc, bool body_can_be_zero_length,
+ bool read_backward)
: ChoiceNode(alloc, 2),
loop_node_(nullptr),
continue_node_(nullptr),
- body_can_be_zero_length_(body_can_be_zero_length)
+ body_can_be_zero_length_(body_can_be_zero_length),
+ read_backward_(read_backward)
{}
void AddLoopAlternative(GuardedAlternative alt);
@@ -1133,6 +1146,7 @@ class LoopChoiceNode : public ChoiceNode
RegExpNode* loop_node() { return loop_node_; }
RegExpNode* continue_node() { return continue_node_; }
bool body_can_be_zero_length() { return body_can_be_zero_length_; }
+ virtual bool read_backward() { return read_backward_; }
virtual void Accept(NodeVisitor* visitor);
virtual RegExpNode* FilterASCII(int depth, bool ignore_case, bool unicode);
@@ -1147,6 +1161,7 @@ class LoopChoiceNode : public ChoiceNode
RegExpNode* loop_node_;
RegExpNode* continue_node_;
bool body_can_be_zero_length_;
+ bool read_backward_;
};
// Improve the speed that we scan for an initial point where a non-anchored
@@ -1422,8 +1437,8 @@ class Trace
}
TriBool at_start() { return at_start_; }
- void set_at_start(bool at_start) {
- at_start_ = at_start ? TRUE_VALUE : FALSE_VALUE;
+ void set_at_start(TriBool at_start) {
+ at_start_ = at_start;
}
jit::Label* backtrack() { return backtrack_; }
jit::Label* loop_label() { return loop_label_; }
diff --git a/js/src/irregexp/RegExpInterpreter.cpp b/js/src/irregexp/RegExpInterpreter.cpp
index 7fd2d983a5..d09b4671e4 100644
--- a/js/src/irregexp/RegExpInterpreter.cpp
+++ b/js/src/irregexp/RegExpInterpreter.cpp
@@ -222,8 +222,8 @@ irregexp::InterpretCode(JSContext* cx, const uint8_t* byteCode, const CharT* cha
}
break;
BYTECODE(LOAD_CURRENT_CHAR) {
- size_t pos = current + (insn >> BYTECODE_SHIFT);
- if (pos >= length) {
+ int pos = current + (insn >> BYTECODE_SHIFT);
+ if (pos >= (int)length || pos < 0) {
pc = byteCode + Load32Aligned(pc + 4);
} else {
current_char = chars[pos];
@@ -238,8 +238,8 @@ irregexp::InterpretCode(JSContext* cx, const uint8_t* byteCode, const CharT* cha
break;
}
BYTECODE(LOAD_2_CURRENT_CHARS) {
- size_t pos = current + (insn >> BYTECODE_SHIFT);
- if (pos + 2 > length) {
+ int pos = current + (insn >> BYTECODE_SHIFT);
+ if (pos + 2 > (int)length || pos < 0) {
pc = byteCode + Load32Aligned(pc + 4);
} else {
CharT next = chars[pos + 1];
@@ -425,6 +425,30 @@ irregexp::InterpretCode(JSContext* cx, const uint8_t* byteCode, const CharT* cha
pc += BC_CHECK_NOT_BACK_REF_LENGTH;
break;
}
+ BYTECODE(CHECK_NOT_BACK_REF_BACKWARD) {
+ int from = registers[insn >> BYTECODE_SHIFT];
+ int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
+ if (from < 0 || len <= 0) {
+ pc += BC_CHECK_NOT_BACK_REF_BACKWARD_LENGTH;
+ break;
+ }
+ if (int(current) - len < 0) {
+ pc = byteCode + Load32Aligned(pc + 4);
+ break;
+ } else {
+ int i;
+ for (i = 0; i < len; i++) {
+ if (chars[from + i] != chars[int(current) - len + i]) {
+ pc = byteCode + Load32Aligned(pc + 4);
+ break;
+ }
+ }
+ if (i < len) break;
+ current -= len;
+ }
+ pc += BC_CHECK_NOT_BACK_REF_BACKWARD_LENGTH;
+ break;
+ }
BYTECODE(CHECK_NOT_BACK_REF_NO_CASE) {
int from = registers[insn >> BYTECODE_SHIFT];
int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
@@ -465,6 +489,46 @@ irregexp::InterpretCode(JSContext* cx, const uint8_t* byteCode, const CharT* cha
}
break;
}
+ BYTECODE(CHECK_NOT_BACK_REF_NO_CASE_BACKWARD) {
+ int from = registers[insn >> BYTECODE_SHIFT];
+ int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
+ if (from < 0 || len <= 0) {
+ pc += BC_CHECK_NOT_BACK_REF_NO_CASE_BACKWARD_LENGTH;
+ break;
+ }
+ if (int(current) - len < 0) {
+ pc = byteCode + Load32Aligned(pc + 4);
+ break;
+ }
+ if (CaseInsensitiveCompareStrings(chars + from, chars + int(current) - len, len * sizeof(CharT))) {
+ current -= len;
+ pc += BC_CHECK_NOT_BACK_REF_NO_CASE_BACKWARD_LENGTH;
+ } else {
+ pc = byteCode + Load32Aligned(pc + 4);
+ }
+ break;
+
+ }
+ BYTECODE(CHECK_NOT_BACK_REF_NO_CASE_BACKWARD_UNICODE) {
+ int from = registers[insn >> BYTECODE_SHIFT];
+ int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
+ if (from < 0 || len <= 0) {
+ pc += BC_CHECK_NOT_BACK_REF_NO_CASE_BACKWARD_LENGTH;
+ break;
+ }
+ if (int(current) - len < 0) {
+ pc = byteCode + Load32Aligned(pc + 4);
+ break;
+ }
+ if (CaseInsensitiveCompareUCStrings(chars + from, chars + int(current) - len, len * sizeof(CharT))) {
+ current -= len;
+ pc += BC_CHECK_NOT_BACK_REF_NO_CASE_BACKWARD_LENGTH;
+ } else {
+ pc = byteCode + Load32Aligned(pc + 4);
+ }
+ break;
+
+ }
BYTECODE(CHECK_AT_START)
if (current == 0)
pc = byteCode + Load32Aligned(pc + 4);
@@ -472,7 +536,7 @@ irregexp::InterpretCode(JSContext* cx, const uint8_t* byteCode, const CharT* cha
pc += BC_CHECK_AT_START_LENGTH;
break;
BYTECODE(CHECK_NOT_AT_START)
- if (current == 0)
+ if (current + (insn >> BYTECODE_SHIFT) == 0)
pc += BC_CHECK_NOT_AT_START_LENGTH;
else
pc = byteCode + Load32Aligned(pc + 4);
diff --git a/js/src/irregexp/RegExpMacroAssembler.cpp b/js/src/irregexp/RegExpMacroAssembler.cpp
index d66d0d204a..6b1ceba8ad 100644
--- a/js/src/irregexp/RegExpMacroAssembler.cpp
+++ b/js/src/irregexp/RegExpMacroAssembler.cpp
@@ -226,32 +226,37 @@ InterpretedRegExpMacroAssembler::CheckGreedyLoop(jit::Label* on_tos_equals_curre
}
void
-InterpretedRegExpMacroAssembler::CheckNotAtStart(jit::Label* on_not_at_start)
+InterpretedRegExpMacroAssembler::CheckNotAtStart(int cp_offset, jit::Label* on_not_at_start)
{
- Emit(BC_CHECK_NOT_AT_START, 0);
+ Emit(BC_CHECK_NOT_AT_START, cp_offset);
EmitOrLink(on_not_at_start);
}
void
-InterpretedRegExpMacroAssembler::CheckNotBackReference(int start_reg, jit::Label* on_no_match)
+InterpretedRegExpMacroAssembler::CheckNotBackReference(int start_reg, bool read_backward,
+ jit::Label* on_no_match)
{
MOZ_ASSERT(start_reg >= 0);
MOZ_ASSERT(start_reg <= kMaxRegister);
- Emit(BC_CHECK_NOT_BACK_REF, start_reg);
+ Emit(read_backward ? BC_CHECK_NOT_BACK_REF_BACKWARD : BC_CHECK_NOT_BACK_REF,
+ start_reg);
EmitOrLink(on_no_match);
}
void
InterpretedRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase(int start_reg,
+ bool read_backward,
jit::Label* on_no_match,
bool unicode)
{
MOZ_ASSERT(start_reg >= 0);
MOZ_ASSERT(start_reg <= kMaxRegister);
if (unicode)
- Emit(BC_CHECK_NOT_BACK_REF_NO_CASE_UNICODE, start_reg);
+ Emit(read_backward ? BC_CHECK_NOT_BACK_REF_NO_CASE_BACKWARD_UNICODE : BC_CHECK_NOT_BACK_REF_NO_CASE_UNICODE,
+ start_reg);
else
- Emit(BC_CHECK_NOT_BACK_REF_NO_CASE, start_reg);
+ Emit(read_backward ? BC_CHECK_NOT_BACK_REF_NO_CASE_BACKWARD : BC_CHECK_NOT_BACK_REF_NO_CASE,
+ start_reg);
EmitOrLink(on_no_match);
}
diff --git a/js/src/irregexp/RegExpMacroAssembler.h b/js/src/irregexp/RegExpMacroAssembler.h
index dca2edf905..c5def92f29 100644
--- a/js/src/irregexp/RegExpMacroAssembler.h
+++ b/js/src/irregexp/RegExpMacroAssembler.h
@@ -110,10 +110,10 @@ class MOZ_STACK_CLASS RegExpMacroAssembler
virtual void CheckCharacterGT(char16_t limit, jit::Label* on_greater) = 0;
virtual void CheckCharacterLT(char16_t limit, jit::Label* on_less) = 0;
virtual void CheckGreedyLoop(jit::Label* on_tos_equals_current_position) = 0;
- virtual void CheckNotAtStart(jit::Label* on_not_at_start) = 0;
- virtual void CheckNotBackReference(int start_reg, jit::Label* on_no_match) = 0;
- virtual void CheckNotBackReferenceIgnoreCase(int start_reg, jit::Label* on_no_match,
- bool unicode) = 0;
+ virtual void CheckNotAtStart(int cp_offset, jit::Label* on_not_at_start) = 0;
+ virtual void CheckNotBackReference(int start_reg, bool read_backward, jit::Label* on_no_match) = 0;
+ virtual void CheckNotBackReferenceIgnoreCase(int start_reg, bool read_backward,
+ jit::Label* on_no_match, bool unicode) = 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
@@ -245,9 +245,10 @@ class MOZ_STACK_CLASS InterpretedRegExpMacroAssembler final : public RegExpMacro
void CheckCharacterGT(char16_t limit, jit::Label* on_greater);
void CheckCharacterLT(char16_t limit, jit::Label* on_less);
void CheckGreedyLoop(jit::Label* on_tos_equals_current_position);
- void CheckNotAtStart(jit::Label* on_not_at_start);
- void CheckNotBackReference(int start_reg, jit::Label* on_no_match);
- void CheckNotBackReferenceIgnoreCase(int start_reg, jit::Label* on_no_match, bool unicode);
+ void CheckNotAtStart(int cp_offset, jit::Label* on_not_at_start);
+ void CheckNotBackReference(int start_reg, bool read_backward, jit::Label* on_no_match);
+ void CheckNotBackReferenceIgnoreCase(int start_reg, bool read_backward,
+ jit::Label* on_no_match, bool unicode);
void CheckNotCharacter(unsigned c, jit::Label* on_not_equal);
void CheckNotCharacterAfterAnd(unsigned c, unsigned and_with, jit::Label* on_not_equal);
void CheckNotCharacterAfterMinusAnd(char16_t c, char16_t minus, char16_t and_with,
diff --git a/js/src/irregexp/RegExpParser.cpp b/js/src/irregexp/RegExpParser.cpp
index 8bd88047af..9ef9fe3e2f 100644
--- a/js/src/irregexp/RegExpParser.cpp
+++ b/js/src/irregexp/RegExpParser.cpp
@@ -227,6 +227,7 @@ RegExpParser::RegExpParser(frontend::TokenStream& ts, LifoAlloc* alloc,
alloc(alloc),
captures_(nullptr),
next_pos_(chars),
+ captures_started_(0),
end_(end),
current_(kEndMarker),
capture_count_(0),
@@ -418,7 +419,8 @@ RangeAtom(LifoAlloc* alloc, char16_t from, char16_t to)
static inline RegExpTree*
NegativeLookahead(LifoAlloc* alloc, char16_t from, char16_t to)
{
- return alloc->newInfallible(RangeAtom(alloc, from, to), false, 0, 0);
+ return alloc->newInfallible(RangeAtom(alloc, from, to), false,
+ 0, 0, RegExpLookaround::LOOKAHEAD);
}
static bool
@@ -1213,6 +1215,38 @@ RegExpParser::ParseBackReferenceIndex(int* index_out)
return true;
}
+template
+RegExpCapture*
+RegExpParser::GetCapture(int index) {
+ // The index for the capture groups are one-based. Its index in the list is
+ // zero-based.
+ int known_captures =
+ is_scanned_for_captures_ ? capture_count_ : captures_started_;
+ MOZ_ASSERT(index <= known_captures);
+ if (captures_ == NULL) {
+ captures_ = alloc->newInfallible(*alloc);
+ }
+ while ((int)captures_->length() < known_captures) {
+ RegExpCapture* capture = alloc->newInfallible(nullptr, captures_->length() + 1);
+ captures_->append(capture);
+ }
+ return (*captures_)[index - 1];
+}
+
+
+template
+bool
+RegExpParser::RegExpParserState::IsInsideCaptureGroup(int index) {
+ for (RegExpParserState* s = this; s != NULL; s = s->previous_state()) {
+ if (s->group_type() != CAPTURE) continue;
+ // Return true if we found the matching capture index.
+ if (index == s->capture_index()) return true;
+ // Abort if index is larger than what has been parsed up till this state.
+ if (index > s->capture_index()) return false;
+ }
+ return false;
+}
+
// QuantifierPrefix ::
// { DecimalDigits }
// { DecimalDigits , }
@@ -1423,24 +1457,24 @@ RegExpTree*
RegExpParser::ParseDisjunction()
{
// Used to store current state while parsing subexpressions.
- RegExpParserState initial_state(alloc, nullptr, INITIAL, 0);
- RegExpParserState* stored_state = &initial_state;
+ RegExpParserState initial_state(alloc, nullptr, INITIAL, RegExpLookaround::LOOKAHEAD, 0);
+ RegExpParserState* state = &initial_state;
// Cache the builder in a local variable for quick access.
RegExpBuilder* builder = initial_state.builder();
while (true) {
switch (current()) {
case kEndMarker:
- if (stored_state->IsSubexpression()) {
+ if (state->IsSubexpression()) {
// Inside a parenthesized group when hitting end of input.
return ReportError(JSMSG_MISSING_PAREN);
}
- MOZ_ASSERT(INITIAL == stored_state->group_type());
+ MOZ_ASSERT(INITIAL == state->group_type());
// Parsing completed successfully.
return builder->ToRegExp();
case ')': {
- if (!stored_state->IsSubexpression())
+ if (!state->IsSubexpression())
return ReportError(JSMSG_UNMATCHED_RIGHT_PAREN);
- MOZ_ASSERT(INITIAL != stored_state->group_type());
+ MOZ_ASSERT(INITIAL != state->group_type());
Advance();
// End disjunction parsing and convert builder content to new single
@@ -1449,29 +1483,30 @@ RegExpParser::ParseDisjunction()
int end_capture_index = captures_started();
- int capture_index = stored_state->capture_index();
- SubexpressionType group_type = stored_state->group_type();
-
- // Restore previous state.
- stored_state = stored_state->previous_state();
- builder = stored_state->builder();
+ int capture_index = state->capture_index();
+ SubexpressionType group_type = state->group_type();
// Build result of subexpression.
if (group_type == CAPTURE) {
- RegExpCapture* capture = alloc->newInfallible(body, capture_index);
- (*captures_)[capture_index - 1] = capture;
+ RegExpCapture* capture = GetCapture(capture_index);
+ capture->set_body(body);
body = capture;
} else if (group_type != GROUPING) {
- MOZ_ASSERT(group_type == POSITIVE_LOOKAHEAD ||
- group_type == NEGATIVE_LOOKAHEAD);
- bool is_positive = (group_type == POSITIVE_LOOKAHEAD);
- body = alloc->newInfallible(body,
+ MOZ_ASSERT(group_type == POSITIVE_LOOKAROUND ||
+ group_type == NEGATIVE_LOOKAROUND);
+ bool is_positive = (group_type == POSITIVE_LOOKAROUND);
+ body = alloc->newInfallible(body,
is_positive,
end_capture_index - capture_index,
- capture_index);
+ capture_index,
+ state->lookaround_type());
}
+
+ // Restore previous state.
+ state = state->previous_state();
+ builder = state->builder();
builder->AddAtom(body);
- if (unicode_ && (group_type == POSITIVE_LOOKAHEAD || group_type == NEGATIVE_LOOKAHEAD))
+ if (unicode_ && (group_type == POSITIVE_LOOKAROUND || group_type == NEGATIVE_LOOKAROUND))
continue;
// For compatability with JSC and ES3, we allow quantifiers after
// lookaheads, and break in all cases.
@@ -1519,6 +1554,7 @@ RegExpParser::ParseDisjunction()
}
case '(': {
SubexpressionType subexpr_type = CAPTURE;
+ RegExpLookaround::Type lookaround_type = state->lookaround_type();
Advance();
if (current() == '?') {
switch (Next()) {
@@ -1526,26 +1562,39 @@ RegExpParser::ParseDisjunction()
subexpr_type = GROUPING;
break;
case '=':
- subexpr_type = POSITIVE_LOOKAHEAD;
+ lookaround_type = RegExpLookaround::LOOKAHEAD;
+ subexpr_type = POSITIVE_LOOKAROUND;
break;
case '!':
- subexpr_type = NEGATIVE_LOOKAHEAD;
+ lookaround_type = RegExpLookaround::LOOKAHEAD;
+ subexpr_type = NEGATIVE_LOOKAROUND;
break;
+ case '<':
+ Advance();
+ lookaround_type = RegExpLookaround::LOOKBEHIND;
+ if (Next() == '=') {
+ subexpr_type = POSITIVE_LOOKAROUND;
+ break;
+ } else if (Next() == '!') {
+ subexpr_type = NEGATIVE_LOOKAROUND;
+ break;
+ }
+ // We didn't get a positive or negative after '<'.
+ // That's an error.
+ return ReportError(JSMSG_INVALID_GROUP);
default:
return ReportError(JSMSG_INVALID_GROUP);
}
Advance(2);
} else {
- if (captures_ == nullptr)
- captures_ = alloc->newInfallible(*alloc);
if (captures_started() >= kMaxCaptures)
return ReportError(JSMSG_TOO_MANY_PARENS);
- captures_->append((RegExpCapture*) nullptr);
+ captures_started_++;
}
// Store current state and begin new disjunction parsing.
- stored_state = alloc->newInfallible(alloc, stored_state, subexpr_type,
- captures_started());
- builder = stored_state->builder();
+ state = alloc->newInfallible(alloc, state, subexpr_type,
+ lookaround_type, captures_started_);
+ builder = state->builder();
continue;
}
case '[': {
@@ -1600,19 +1649,18 @@ RegExpParser::ParseDisjunction()
case '7': case '8': case '9': {
int index = 0;
if (ParseBackReferenceIndex(&index)) {
- RegExpCapture* capture = nullptr;
- if (captures_ != nullptr && index <= (int) captures_->length()) {
- capture = (*captures_)[index - 1];
+ if (state->IsInsideCaptureGroup(index)) {
+ // The backreference is inside the capture group it refers to.
+ // Nothing can possibly have been captured yet.
+ builder->AddEmpty();
+ } else {
+ RegExpCapture* capture = GetCapture(index);
+ RegExpTree* atom = alloc->newInfallible(capture);
+ if (unicode_)
+ builder->AddAtom(UnicodeBackReferenceAtom(alloc, atom));
+ else
+ builder->AddAtom(atom);
}
- if (capture == nullptr) {
- builder->AddEmpty();
- break;
- }
- RegExpTree* atom = alloc->newInfallible(capture);
- if (unicode_)
- builder->AddAtom(UnicodeBackReferenceAtom(alloc, atom));
- else
- builder->AddAtom(atom);
break;
}
if (unicode_)
diff --git a/js/src/irregexp/RegExpParser.h b/js/src/irregexp/RegExpParser.h
index 0a7e618589..2f02625b5c 100644
--- a/js/src/irregexp/RegExpParser.h
+++ b/js/src/irregexp/RegExpParser.h
@@ -229,7 +229,7 @@ class RegExpParser
bool simple() { return simple_; }
bool contains_anchor() { return contains_anchor_; }
void set_contains_anchor() { contains_anchor_ = true; }
- int captures_started() { return captures_ == nullptr ? 0 : captures_->length(); }
+ int captures_started() { return captures_started_; }
const CharT* position() { return next_pos_ - 1; }
static const int kMaxCaptures = 1 << 16;
@@ -239,8 +239,8 @@ class RegExpParser
enum SubexpressionType {
INITIAL,
CAPTURE, // All positive values represent captures.
- POSITIVE_LOOKAHEAD,
- NEGATIVE_LOOKAHEAD,
+ POSITIVE_LOOKAROUND,
+ NEGATIVE_LOOKAROUND,
GROUPING
};
@@ -249,10 +249,12 @@ class RegExpParser
RegExpParserState(LifoAlloc* alloc,
RegExpParserState* previous_state,
SubexpressionType group_type,
+ RegExpLookaround::Type lookaround_type,
int disjunction_capture_index)
: previous_state_(previous_state),
builder_(alloc->newInfallible(alloc)),
group_type_(group_type),
+ lookaround_type_(lookaround_type),
disjunction_capture_index_(disjunction_capture_index)
{}
// Parser state of containing expression, if any.
@@ -262,11 +264,16 @@ class RegExpParser
RegExpBuilder* builder() { return builder_; }
// Type of regexp being parsed (parenthesized group or entire regexp).
SubexpressionType group_type() { return group_type_; }
+ // Lookahead or Lookbehind.
+ RegExpLookaround::Type lookaround_type() { return lookaround_type_; }
// Index in captures array of first capture in this sub-expression, if any.
// Also the capture index of this sub-expression itself, if group_type
// is CAPTURE.
int capture_index() { return disjunction_capture_index_; }
+ // Check whether the parser is inside a capture group with the given index.
+ bool IsInsideCaptureGroup(int index);
+
private:
// Linked list implementation of stack of states.
RegExpParserState* previous_state_;
@@ -274,10 +281,15 @@ class RegExpParser
RegExpBuilder* builder_;
// Stored disjunction type (capture, look-ahead or grouping), if any.
SubexpressionType group_type_;
+ // Stored read direction.
+ RegExpLookaround::Type lookaround_type_;
// Stored disjunction's capture index (if any).
int disjunction_capture_index_;
};
+ // Return the 1-indexed RegExpCapture object, allocate if necessary.
+ RegExpCapture* GetCapture(int index);
+
widechar current() { return current_; }
bool has_more() { return has_more_; }
bool has_next() { return next_pos_ < end_; }
@@ -294,6 +306,7 @@ class RegExpParser
const CharT* next_pos_;
const CharT* end_;
widechar current_;
+ int captures_started_;
// The capture count is only valid after we have scanned for captures.
int capture_count_;
bool has_more_;
From 729ee0f18a38e3d08e6f1eb4ed2b0f043d08f792 Mon Sep 17 00:00:00 2001
From: wolfbeast
Date: Thu, 14 Nov 2019 09:07:29 +0100
Subject: [PATCH 03/14] Issue #1288 - Part 1a: Update brotli to 1.0.7
This also reorganizes the exports in the build system to use `brotli/`
as include directory.
---
layout/inspector/nsFontFace.cpp | 10 +-
modules/brotli/README.mozilla | 5 +-
modules/brotli/common/constants.h | 64 +
modules/brotli/{dec => common}/context.h | 330 +-
modules/brotli/common/dictionary.bin | 432 +
modules/brotli/common/dictionary.bin.br | Bin 0 -> 51687 bytes
modules/brotli/common/dictionary.c | 5905 ++++++++++
modules/brotli/common/dictionary.h | 64 +
modules/brotli/common/platform.h | 568 +
modules/brotli/common/transform.c | 235 +
modules/brotli/common/transform.h | 80 +
modules/brotli/common/version.h | 26 +
modules/brotli/dec/Makefile | 12 -
modules/brotli/dec/bit_reader.c | 14 +-
modules/brotli/dec/bit_reader.h | 190 +-
modules/brotli/dec/decode.c | 1818 ++--
modules/brotli/dec/decode.h | 162 -
modules/brotli/dec/dictionary.c | 9466 -----------------
modules/brotli/dec/dictionary.h | 38 -
modules/brotli/dec/huffman.c | 143 +-
modules/brotli/dec/huffman.h | 85 +-
modules/brotli/dec/port.h | 252 -
modules/brotli/dec/prefix.h | 15 +-
modules/brotli/dec/state.c | 110 +-
modules/brotli/dec/state.h | 98 +-
modules/brotli/dec/transform.h | 300 -
modules/brotli/dec/types.h | 38 -
modules/brotli/enc/backward_references.c | 144 +
modules/brotli/enc/backward_references.h | 38 +
modules/brotli/enc/backward_references_hq.c | 825 ++
modules/brotli/enc/backward_references_hq.h | 92 +
modules/brotli/enc/backward_references_inc.h | 153 +
modules/brotli/enc/bit_cost.c | 35 +
modules/brotli/enc/bit_cost.h | 63 +
modules/brotli/enc/bit_cost_inc.h | 127 +
modules/brotli/enc/block_encoder_inc.h | 34 +
modules/brotli/enc/block_splitter.c | 194 +
modules/brotli/enc/block_splitter.h | 51 +
modules/brotli/enc/block_splitter_inc.h | 431 +
modules/brotli/enc/brotli_bit_stream.c | 1331 +++
modules/brotli/enc/brotli_bit_stream.h | 84 +
modules/brotli/enc/cluster.c | 56 +
modules/brotli/enc/cluster.h | 48 +
modules/brotli/enc/cluster_inc.h | 317 +
modules/brotli/enc/command.h | 190 +
modules/brotli/enc/compress_fragment.c | 790 ++
modules/brotli/enc/compress_fragment.h | 61 +
.../brotli/enc/compress_fragment_two_pass.c | 645 ++
.../brotli/enc/compress_fragment_two_pass.h | 54 +
modules/brotli/enc/dictionary_hash.c | 1120 ++
modules/brotli/enc/dictionary_hash.h | 24 +
modules/brotli/enc/encode.c | 1862 ++++
modules/brotli/enc/encoder_dict.c | 32 +
modules/brotli/enc/encoder_dict.h | 41 +
modules/brotli/enc/entropy_encode.c | 501 +
modules/brotli/enc/entropy_encode.h | 122 +
modules/brotli/enc/entropy_encode_static.h | 539 +
modules/brotli/enc/fast_log.h | 147 +
modules/brotli/enc/find_match_length.h | 80 +
modules/brotli/enc/hash.h | 498 +
modules/brotli/enc/hash_composite_inc.h | 136 +
modules/brotli/enc/hash_forgetful_chain_inc.h | 254 +
modules/brotli/enc/hash_longest_match64_inc.h | 267 +
modules/brotli/enc/hash_longest_match_inc.h | 259 +
.../enc/hash_longest_match_quickly_inc.h | 235 +
modules/brotli/enc/hash_rolling_inc.h | 216 +
modules/brotli/enc/hash_to_binary_tree_inc.h | 328 +
modules/brotli/enc/histogram.c | 100 +
modules/brotli/enc/histogram.h | 63 +
modules/brotli/enc/histogram_inc.h | 51 +
modules/brotli/enc/literal_cost.c | 175 +
modules/brotli/enc/literal_cost.h | 30 +
modules/brotli/enc/memory.c | 170 +
modules/brotli/enc/memory.h | 102 +
modules/brotli/enc/metablock.c | 667 ++
modules/brotli/enc/metablock.h | 105 +
modules/brotli/enc/metablock_inc.h | 183 +
modules/brotli/enc/params.h | 44 +
modules/brotli/enc/prefix.h | 53 +
modules/brotli/enc/quality.h | 165 +
modules/brotli/enc/ringbuffer.h | 164 +
modules/brotli/enc/static_dict.c | 486 +
modules/brotli/enc/static_dict.h | 40 +
modules/brotli/enc/static_dict_lut.h | 5864 ++++++++++
modules/brotli/enc/utf8_util.c | 85 +
modules/brotli/enc/utf8_util.h | 32 +
modules/brotli/enc/write_bits.h | 85 +
modules/brotli/include/brotli/decode.h | 344 +
modules/brotli/include/brotli/encode.h | 427 +
modules/brotli/include/brotli/port.h | 274 +
modules/brotli/include/brotli/types.h | 83 +
modules/brotli/moz.build | 53 +-
modules/brotli/tools/brotli.c | 1061 ++
modules/brotli/tools/brotli.md | 107 +
modules/brotli/update.sh | 18 +-
netwerk/build/moz.build | 1 +
netwerk/streamconv/converters/moz.build | 1 +
97 files changed, 32335 insertions(+), 11582 deletions(-)
create mode 100644 modules/brotli/common/constants.h
rename modules/brotli/{dec => common}/context.h (59%)
create mode 100644 modules/brotli/common/dictionary.bin
create mode 100644 modules/brotli/common/dictionary.bin.br
create mode 100644 modules/brotli/common/dictionary.c
create mode 100644 modules/brotli/common/dictionary.h
create mode 100644 modules/brotli/common/platform.h
create mode 100644 modules/brotli/common/transform.c
create mode 100644 modules/brotli/common/transform.h
create mode 100644 modules/brotli/common/version.h
delete mode 100644 modules/brotli/dec/Makefile
delete mode 100644 modules/brotli/dec/decode.h
delete mode 100644 modules/brotli/dec/dictionary.c
delete mode 100644 modules/brotli/dec/dictionary.h
delete mode 100644 modules/brotli/dec/port.h
delete mode 100644 modules/brotli/dec/transform.h
delete mode 100644 modules/brotli/dec/types.h
create mode 100644 modules/brotli/enc/backward_references.c
create mode 100644 modules/brotli/enc/backward_references.h
create mode 100644 modules/brotli/enc/backward_references_hq.c
create mode 100644 modules/brotli/enc/backward_references_hq.h
create mode 100644 modules/brotli/enc/backward_references_inc.h
create mode 100644 modules/brotli/enc/bit_cost.c
create mode 100644 modules/brotli/enc/bit_cost.h
create mode 100644 modules/brotli/enc/bit_cost_inc.h
create mode 100644 modules/brotli/enc/block_encoder_inc.h
create mode 100644 modules/brotli/enc/block_splitter.c
create mode 100644 modules/brotli/enc/block_splitter.h
create mode 100644 modules/brotli/enc/block_splitter_inc.h
create mode 100644 modules/brotli/enc/brotli_bit_stream.c
create mode 100644 modules/brotli/enc/brotli_bit_stream.h
create mode 100644 modules/brotli/enc/cluster.c
create mode 100644 modules/brotli/enc/cluster.h
create mode 100644 modules/brotli/enc/cluster_inc.h
create mode 100644 modules/brotli/enc/command.h
create mode 100644 modules/brotli/enc/compress_fragment.c
create mode 100644 modules/brotli/enc/compress_fragment.h
create mode 100644 modules/brotli/enc/compress_fragment_two_pass.c
create mode 100644 modules/brotli/enc/compress_fragment_two_pass.h
create mode 100644 modules/brotli/enc/dictionary_hash.c
create mode 100644 modules/brotli/enc/dictionary_hash.h
create mode 100644 modules/brotli/enc/encode.c
create mode 100644 modules/brotli/enc/encoder_dict.c
create mode 100644 modules/brotli/enc/encoder_dict.h
create mode 100644 modules/brotli/enc/entropy_encode.c
create mode 100644 modules/brotli/enc/entropy_encode.h
create mode 100644 modules/brotli/enc/entropy_encode_static.h
create mode 100644 modules/brotli/enc/fast_log.h
create mode 100644 modules/brotli/enc/find_match_length.h
create mode 100644 modules/brotli/enc/hash.h
create mode 100644 modules/brotli/enc/hash_composite_inc.h
create mode 100644 modules/brotli/enc/hash_forgetful_chain_inc.h
create mode 100644 modules/brotli/enc/hash_longest_match64_inc.h
create mode 100644 modules/brotli/enc/hash_longest_match_inc.h
create mode 100644 modules/brotli/enc/hash_longest_match_quickly_inc.h
create mode 100644 modules/brotli/enc/hash_rolling_inc.h
create mode 100644 modules/brotli/enc/hash_to_binary_tree_inc.h
create mode 100644 modules/brotli/enc/histogram.c
create mode 100644 modules/brotli/enc/histogram.h
create mode 100644 modules/brotli/enc/histogram_inc.h
create mode 100644 modules/brotli/enc/literal_cost.c
create mode 100644 modules/brotli/enc/literal_cost.h
create mode 100644 modules/brotli/enc/memory.c
create mode 100644 modules/brotli/enc/memory.h
create mode 100644 modules/brotli/enc/metablock.c
create mode 100644 modules/brotli/enc/metablock.h
create mode 100644 modules/brotli/enc/metablock_inc.h
create mode 100644 modules/brotli/enc/params.h
create mode 100644 modules/brotli/enc/prefix.h
create mode 100644 modules/brotli/enc/quality.h
create mode 100644 modules/brotli/enc/ringbuffer.h
create mode 100644 modules/brotli/enc/static_dict.c
create mode 100644 modules/brotli/enc/static_dict.h
create mode 100644 modules/brotli/enc/static_dict_lut.h
create mode 100644 modules/brotli/enc/utf8_util.c
create mode 100644 modules/brotli/enc/utf8_util.h
create mode 100644 modules/brotli/enc/write_bits.h
create mode 100644 modules/brotli/include/brotli/decode.h
create mode 100644 modules/brotli/include/brotli/encode.h
create mode 100644 modules/brotli/include/brotli/port.h
create mode 100644 modules/brotli/include/brotli/types.h
create mode 100644 modules/brotli/tools/brotli.c
create mode 100644 modules/brotli/tools/brotli.md
diff --git a/layout/inspector/nsFontFace.cpp b/layout/inspector/nsFontFace.cpp
index a4a9231e26..abf9f6439c 100644
--- a/layout/inspector/nsFontFace.cpp
+++ b/layout/inspector/nsFontFace.cpp
@@ -9,7 +9,7 @@
#include "gfxUserFontSet.h"
#include "nsFontFaceLoader.h"
#include "mozilla/gfx/2D.h"
-#include "decode.h"
+#include "brotli/decode.h"
#include "zlib.h"
#include "mozilla/dom/FontFaceSet.h"
@@ -208,10 +208,10 @@ nsFontFace::GetMetadata(nsAString & aMetadata)
case gfxUserFontData::kBrotliCompression:
{
size_t decodedSize = userFontData->mMetaOrigLen;
- if (BrotliDecompressBuffer(userFontData->mMetadata.Length(),
- userFontData->mMetadata.Elements(),
- &decodedSize,
- (uint8_t*)str.BeginWriting()) == 1 &&
+ if (BrotliDecoderDecompress(userFontData->mMetadata.Length(),
+ userFontData->mMetadata.Elements(),
+ &decodedSize,
+ (uint8_t*)str.BeginWriting()) == 1 &&
decodedSize == userFontData->mMetaOrigLen) {
AppendUTF8toUTF16(str, aMetadata);
}
diff --git a/modules/brotli/README.mozilla b/modules/brotli/README.mozilla
index 474afa2e40..47520e4535 100644
--- a/modules/brotli/README.mozilla
+++ b/modules/brotli/README.mozilla
@@ -1,9 +1,6 @@
This is the Brotli data compression library from
https://github.com/google/brotli.
-Currently, we import only the Brotli decoder (the /dec/ subdirectory), not the
-encoder (/enc/ subdirectory).
-
Upstream code can be viewed at
https://github.com/google/brotli/tree/master/dec
@@ -14,4 +11,4 @@ The in-tree copy is updated by running
sh update.sh
from within the modules/brotli directory.
-Current version: [commit 29d31d5921b0a2b323ac24e7f7d0cdc9a3c0dd08].
+Current version: [commit d6d98957ca8ccb1ef45922e978bb10efca0ea541].
diff --git a/modules/brotli/common/constants.h b/modules/brotli/common/constants.h
new file mode 100644
index 0000000000..d1b88d12af
--- /dev/null
+++ b/modules/brotli/common/constants.h
@@ -0,0 +1,64 @@
+/* Copyright 2016 Google Inc. All Rights Reserved.
+
+ Distributed under MIT license.
+ See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+#ifndef BROTLI_COMMON_CONSTANTS_H_
+#define BROTLI_COMMON_CONSTANTS_H_
+
+/* Specification: 7.3. Encoding of the context map */
+#define BROTLI_CONTEXT_MAP_MAX_RLE 16
+
+/* Specification: 2. Compressed representation overview */
+#define BROTLI_MAX_NUMBER_OF_BLOCK_TYPES 256
+
+/* Specification: 3.3. Alphabet sizes: insert-and-copy length */
+#define BROTLI_NUM_LITERAL_SYMBOLS 256
+#define BROTLI_NUM_COMMAND_SYMBOLS 704
+#define BROTLI_NUM_BLOCK_LEN_SYMBOLS 26
+#define BROTLI_MAX_CONTEXT_MAP_SYMBOLS (BROTLI_MAX_NUMBER_OF_BLOCK_TYPES + \
+ BROTLI_CONTEXT_MAP_MAX_RLE)
+#define BROTLI_MAX_BLOCK_TYPE_SYMBOLS (BROTLI_MAX_NUMBER_OF_BLOCK_TYPES + 2)
+
+/* Specification: 3.5. Complex prefix codes */
+#define BROTLI_REPEAT_PREVIOUS_CODE_LENGTH 16
+#define BROTLI_REPEAT_ZERO_CODE_LENGTH 17
+#define BROTLI_CODE_LENGTH_CODES (BROTLI_REPEAT_ZERO_CODE_LENGTH + 1)
+/* "code length of 8 is repeated" */
+#define BROTLI_INITIAL_REPEATED_CODE_LENGTH 8
+
+/* "Large Window Brotli" */
+#define BROTLI_LARGE_MAX_DISTANCE_BITS 62U
+#define BROTLI_LARGE_MIN_WBITS 10
+#define BROTLI_LARGE_MAX_WBITS 30
+
+/* Specification: 4. Encoding of distances */
+#define BROTLI_NUM_DISTANCE_SHORT_CODES 16
+#define BROTLI_MAX_NPOSTFIX 3
+#define BROTLI_MAX_NDIRECT 120
+#define BROTLI_MAX_DISTANCE_BITS 24U
+#define BROTLI_DISTANCE_ALPHABET_SIZE(NPOSTFIX, NDIRECT, MAXNBITS) ( \
+ BROTLI_NUM_DISTANCE_SHORT_CODES + (NDIRECT) + \
+ ((MAXNBITS) << ((NPOSTFIX) + 1)))
+/* BROTLI_NUM_DISTANCE_SYMBOLS == 1128 */
+#define BROTLI_NUM_DISTANCE_SYMBOLS \
+ BROTLI_DISTANCE_ALPHABET_SIZE( \
+ BROTLI_MAX_NDIRECT, BROTLI_MAX_NPOSTFIX, BROTLI_LARGE_MAX_DISTANCE_BITS)
+#define BROTLI_MAX_DISTANCE 0x3FFFFFC
+#define BROTLI_MAX_ALLOWED_DISTANCE 0x7FFFFFFC
+
+/* 7.1. Context modes and context ID lookup for literals */
+/* "context IDs for literals are in the range of 0..63" */
+#define BROTLI_LITERAL_CONTEXT_BITS 6
+
+/* 7.2. Context ID for distances */
+#define BROTLI_DISTANCE_CONTEXT_BITS 2
+
+/* 9.1. Format of the Stream Header */
+/* Number of slack bytes for window size. Don't confuse
+ with BROTLI_NUM_DISTANCE_SHORT_CODES. */
+#define BROTLI_WINDOW_GAP 16
+#define BROTLI_MAX_BACKWARD_LIMIT(W) (((size_t)1 << (W)) - BROTLI_WINDOW_GAP)
+
+#endif /* BROTLI_COMMON_CONSTANTS_H_ */
diff --git a/modules/brotli/dec/context.h b/modules/brotli/common/context.h
similarity index 59%
rename from modules/brotli/dec/context.h
rename to modules/brotli/common/context.h
index 37ebe6aebc..24b3eb48f5 100644
--- a/modules/brotli/dec/context.h
+++ b/modules/brotli/common/context.h
@@ -6,110 +6,171 @@
/* Lookup table to map the previous two bytes to a context id.
- There are four different context modeling modes defined here:
- CONTEXT_LSB6: context id is the least significant 6 bits of the last byte,
- CONTEXT_MSB6: context id is the most significant 6 bits of the last byte,
- CONTEXT_UTF8: second-order context model tuned for UTF8-encoded text,
- CONTEXT_SIGNED: second-order context model tuned for signed integers.
+ There are four different context modeling modes defined here:
+ CONTEXT_LSB6: context id is the least significant 6 bits of the last byte,
+ CONTEXT_MSB6: context id is the most significant 6 bits of the last byte,
+ CONTEXT_UTF8: second-order context model tuned for UTF8-encoded text,
+ CONTEXT_SIGNED: second-order context model tuned for signed integers.
- The context id for the UTF8 context model is calculated as follows. If p1
- and p2 are the previous two bytes, we calculate the context as
+ If |p1| and |p2| are the previous two bytes, and |mode| is current context
+ mode, we calculate the context as:
- context = kContextLookup[p1] | kContextLookup[p2 + 256].
+ context = ContextLut(mode)[p1] | ContextLut(mode)[p2 + 256].
- If the previous two bytes are ASCII characters (i.e. < 128), this will be
- equivalent to
+ For CONTEXT_UTF8 mode, if the previous two bytes are ASCII characters
+ (i.e. < 128), this will be equivalent to
- context = 4 * context1(p1) + context2(p2),
+ context = 4 * context1(p1) + context2(p2),
- where context1 is based on the previous byte in the following way:
+ where context1 is based on the previous byte in the following way:
- 0 : non-ASCII control
- 1 : \t, \n, \r
- 2 : space
- 3 : other punctuation
- 4 : " '
- 5 : %
- 6 : ( < [ {
- 7 : ) > ] }
- 8 : , ; :
- 9 : .
- 10 : =
- 11 : number
- 12 : upper-case vowel
- 13 : upper-case consonant
- 14 : lower-case vowel
- 15 : lower-case consonant
+ 0 : non-ASCII control
+ 1 : \t, \n, \r
+ 2 : space
+ 3 : other punctuation
+ 4 : " '
+ 5 : %
+ 6 : ( < [ {
+ 7 : ) > ] }
+ 8 : , ; :
+ 9 : .
+ 10 : =
+ 11 : number
+ 12 : upper-case vowel
+ 13 : upper-case consonant
+ 14 : lower-case vowel
+ 15 : lower-case consonant
- and context2 is based on the second last byte:
+ and context2 is based on the second last byte:
- 0 : control, space
- 1 : punctuation
- 2 : upper-case letter, number
- 3 : lower-case letter
+ 0 : control, space
+ 1 : punctuation
+ 2 : upper-case letter, number
+ 3 : lower-case letter
- If the last byte is ASCII, and the second last byte is not (in a valid UTF8
- stream it will be a continuation byte, value between 128 and 191), the
- context is the same as if the second last byte was an ASCII control or space.
+ If the last byte is ASCII, and the second last byte is not (in a valid UTF8
+ stream it will be a continuation byte, value between 128 and 191), the
+ context is the same as if the second last byte was an ASCII control or space.
- If the last byte is a UTF8 lead byte (value >= 192), then the next byte will
- be a continuation byte and the context id is 2 or 3 depending on the LSB of
- the last byte and to a lesser extent on the second last byte if it is ASCII.
+ If the last byte is a UTF8 lead byte (value >= 192), then the next byte will
+ be a continuation byte and the context id is 2 or 3 depending on the LSB of
+ the last byte and to a lesser extent on the second last byte if it is ASCII.
- If the last byte is a UTF8 continuation byte, the second last byte can be:
- - continuation byte: the next byte is probably ASCII or lead byte (assuming
- 4-byte UTF8 characters are rare) and the context id is 0 or 1.
- - lead byte (192 - 207): next byte is ASCII or lead byte, context is 0 or 1
- - lead byte (208 - 255): next byte is continuation byte, context is 2 or 3
+ If the last byte is a UTF8 continuation byte, the second last byte can be:
+ - continuation byte: the next byte is probably ASCII or lead byte (assuming
+ 4-byte UTF8 characters are rare) and the context id is 0 or 1.
+ - lead byte (192 - 207): next byte is ASCII or lead byte, context is 0 or 1
+ - lead byte (208 - 255): next byte is continuation byte, context is 2 or 3
- The possible value combinations of the previous two bytes, the range of
- context ids and the type of the next byte is summarized in the table below:
+ The possible value combinations of the previous two bytes, the range of
+ context ids and the type of the next byte is summarized in the table below:
- |--------\-----------------------------------------------------------------|
- | \ Last byte |
- | Second \---------------------------------------------------------------|
- | last byte \ ASCII | cont. byte | lead byte |
- | \ (0-127) | (128-191) | (192-) |
- |=============|===================|=====================|==================|
- | ASCII | next: ASCII/lead | not valid | next: cont. |
- | (0-127) | context: 4 - 63 | | context: 2 - 3 |
- |-------------|-------------------|---------------------|------------------|
- | cont. byte | next: ASCII/lead | next: ASCII/lead | next: cont. |
- | (128-191) | context: 4 - 63 | context: 0 - 1 | context: 2 - 3 |
- |-------------|-------------------|---------------------|------------------|
- | lead byte | not valid | next: ASCII/lead | not valid |
- | (192-207) | | context: 0 - 1 | |
- |-------------|-------------------|---------------------|------------------|
- | lead byte | not valid | next: cont. | not valid |
- | (208-) | | context: 2 - 3 | |
- |-------------|-------------------|---------------------|------------------|
-
- The context id for the signed context mode is calculated as:
-
- context = (kContextLookup[512 + p1] << 3) | kContextLookup[512 + p2].
-
- For any context modeling modes, the context ids can be calculated by |-ing
- together two lookups from one table using context model dependent offsets:
-
- context = kContextLookup[offset1 + p1] | kContextLookup[offset2 + p2].
-
- where offset1 and offset2 are dependent on the context mode.
+ |--------\-----------------------------------------------------------------|
+ | \ Last byte |
+ | Second \---------------------------------------------------------------|
+ | last byte \ ASCII | cont. byte | lead byte |
+ | \ (0-127) | (128-191) | (192-) |
+ |=============|===================|=====================|==================|
+ | ASCII | next: ASCII/lead | not valid | next: cont. |
+ | (0-127) | context: 4 - 63 | | context: 2 - 3 |
+ |-------------|-------------------|---------------------|------------------|
+ | cont. byte | next: ASCII/lead | next: ASCII/lead | next: cont. |
+ | (128-191) | context: 4 - 63 | context: 0 - 1 | context: 2 - 3 |
+ |-------------|-------------------|---------------------|------------------|
+ | lead byte | not valid | next: ASCII/lead | not valid |
+ | (192-207) | | context: 0 - 1 | |
+ |-------------|-------------------|---------------------|------------------|
+ | lead byte | not valid | next: cont. | not valid |
+ | (208-) | | context: 2 - 3 | |
+ |-------------|-------------------|---------------------|------------------|
*/
-#ifndef BROTLI_DEC_CONTEXT_H_
-#define BROTLI_DEC_CONTEXT_H_
+#ifndef BROTLI_COMMON_CONTEXT_H_
+#define BROTLI_COMMON_CONTEXT_H_
-#include "./types.h"
+#include
-enum ContextType {
+typedef enum ContextType {
CONTEXT_LSB6 = 0,
CONTEXT_MSB6 = 1,
CONTEXT_UTF8 = 2,
CONTEXT_SIGNED = 3
-};
+} ContextType;
/* Common context lookup table for all context modes. */
-static const uint8_t kContextLookup[1792] = {
+static const uint8_t kContextLookup[2048] = {
+ /* CONTEXT_LSB6, last byte. */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+
+ /* CONTEXT_LSB6, second last byte, */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ /* CONTEXT_MSB6, last byte. */
+ 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
+ 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
+ 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11,
+ 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,
+ 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19,
+ 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,
+ 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27,
+ 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31,
+ 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35,
+ 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,
+ 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43,
+ 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47,
+ 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51,
+ 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55,
+ 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59,
+ 60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63,
+
+ /* CONTEXT_MSB6, second last byte, */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
/* CONTEXT_UTF8, last byte. */
/* ASCII range. */
0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 4, 0, 0,
@@ -130,6 +191,7 @@ static const uint8_t kContextLookup[1792] = {
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
+
/* CONTEXT_UTF8 second last byte. */
/* ASCII range. */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -150,23 +212,7 @@ static const uint8_t kContextLookup[1792] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- /* CONTEXT_SIGNED, second last byte. */
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7,
+
/* CONTEXT_SIGNED, last byte, same as the above values shifted by 3 bits. */
0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
@@ -184,68 +230,32 @@ static const uint8_t kContextLookup[1792] = {
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 56,
- /* CONTEXT_LSB6, last byte. */
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- /* CONTEXT_MSB6, last byte. */
- 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
- 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
- 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11,
- 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,
- 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19,
- 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,
- 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27,
- 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31,
- 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35,
- 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,
- 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43,
- 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47,
- 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51,
- 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55,
- 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59,
- 60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63,
- /* CONTEXT_{M,L}SB6, second last byte, */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ /* CONTEXT_SIGNED, second last byte. */
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7,
};
-static const int kContextLookupOffsets[8] = {
- /* CONTEXT_LSB6 */
- 1024, 1536,
- /* CONTEXT_MSB6 */
- 1280, 1536,
- /* CONTEXT_UTF8 */
- 0, 256,
- /* CONTEXT_SIGNED */
- 768, 512,
-};
+typedef const uint8_t* ContextLut;
-#endif /* BROTLI_DEC_CONTEXT_H_ */
+/* typeof(MODE) == ContextType; returns ContextLut */
+#define BROTLI_CONTEXT_LUT(MODE) (&kContextLookup[(MODE) << 9])
+
+/* typeof(LUT) == ContextLut */
+#define BROTLI_CONTEXT(P1, P2, LUT) ((LUT)[P1] | ((LUT) + 256)[P2])
+
+#endif /* BROTLI_COMMON_CONTEXT_H_ */
diff --git a/modules/brotli/common/dictionary.bin b/modules/brotli/common/dictionary.bin
new file mode 100644
index 0000000000..a585c0e292
--- /dev/null
+++ b/modules/brotli/common/dictionary.bin
@@ -0,0 +1,432 @@
+timedownlifeleftbackcodedatashowonlysitecityopenjustlikefreeworktextyearoverbodyloveformbookplaylivelinehelphomesidemorewordlongthemviewfindpagedaysfullheadtermeachareafromtruemarkableuponhighdatelandnewsevennextcasebothpostusedmadehandherewhatnameLinkblogsizebaseheldmakemainuser') +holdendswithNewsreadweresigntakehavegameseencallpathwellplusmenufilmpartjointhislistgoodneedwayswestjobsmindalsologorichuseslastteamarmyfoodkingwilleastwardbestfirePageknowaway.pngmovethanloadgiveselfnotemuchfeedmanyrockicononcelookhidediedHomerulehostajaxinfoclublawslesshalfsomesuchzone100%onescareTimeracebluefourweekfacehopegavehardlostwhenparkkeptpassshiproomHTMLplanTypedonesavekeepflaglinksoldfivetookratetownjumpthusdarkcardfilefearstaykillthatfallautoever.comtalkshopvotedeepmoderestturnbornbandfellroseurl(skinrolecomeactsagesmeetgold.jpgitemvaryfeltthensenddropViewcopy1.0"stopelseliestourpack.gifpastcss?graymean>rideshotlatesaidroadvar feeljohnrickportfast'UA-deadpoorbilltypeU.S.woodmust2px;Inforankwidewantwalllead[0];paulwavesure$('#waitmassarmsgoesgainlangpaid!-- lockunitrootwalkfirmwifexml"songtest20pxkindrowstoolfontmailsafestarmapscorerainflowbabyspansays4px;6px;artsfootrealwikiheatsteptriporg/lakeweaktoldFormcastfansbankveryrunsjulytask1px;goalgrewslowedgeid="sets5px;.js?40pxif (soonseatnonetubezerosentreedfactintogiftharm18pxcamehillboldzoomvoideasyringfillpeakinitcost3px;jacktagsbitsrolleditknewnearironfreddiskwentsoilputs/js/holyT22:ISBNT20:adamseesjson', 'contT21: RSSloopasiamoon
soulLINEfortcartT14:80px!--<9px;T04:mike:46ZniceinchYorkricezh:ä'));puremageparatonebond:37Z_of_']);000,zh:çtankyardbowlbush:56ZJava30px
+|}
+%C3%:34ZjeffEXPIcashvisagolfsnowzh:équer.csssickmeatmin.binddellhirepicsrent:36ZHTTP-201fotowolfEND xbox:54ZBODYdick;
+}
+exit:35Zvarsbeat'});diet999;anne}}[i].Langkm²wiretoysaddssealalex;
+ }echonine.org005)tonyjewssandlegsroof000) 200winegeardogsbootgarycutstyletemption.xmlcockgang$('.50pxPh.Dmiscalanloandeskmileryanunixdisc);}
+dustclip).
+
+70px-200DVDs7]>sonyguysfuckpipe|-
+!002)ndow[1];[];
+Log salt
+ bangtrimbath){
+00px
+});ko:ìfeesad>
s:// [];tollplug(){
+{
+ .js'200pdualboat.JPG);
+}quot);
+
+');
+
+}
201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037201320122011201020092008200720062005200420032002200120001999199819971996199519941993199219911990198919881987198619851984198319821981198019791978197719761975197419731972197119701969196819671966196519641963196219611960195919581957195619551954195319521951195010001024139400009999comomásesteestaperotodohacecadaañobiendÃaasÃvidacasootroforosolootracualdijosidograntipotemadebealgoquéestonadatrespococasabajotodasinoaguapuesunosantediceluisellamayozonaamorpisoobraclicellodioshoracasiзанаомрарутанепоотизнодотожеонихÐаеебымыВыÑовывоÐообПолиниРФÐеМытыОнимдаЗаДаÐуОбтеИзейнуммТыужÙيأنمامعكلأوردياÙÙ‰Ù‡ÙˆÙ„Ù…Ù„ÙƒØ§ÙˆÙ„Ù‡Ø¨Ø³Ø§Ù„Ø¥Ù†Ù‡ÙŠØ£ÙŠÙ‚Ø¯Ù‡Ù„Ø«Ù…Ø¨Ù‡Ù„ÙˆÙ„ÙŠØ¨Ù„Ø§ÙŠØ¨ÙƒØ´ÙŠØ§Ù…Ø£Ù…Ù†ØªØ¨ÙŠÙ„Ù†ØØ¨Ù‡Ù…مشوشfirstvideolightworldmediawhitecloseblackrightsmallbooksplacemusicfieldorderpointvalueleveltableboardhousegroupworksyearsstatetodaywaterstartstyledeathpowerphonenighterrorinputabouttermstitletoolseventlocaltimeslargewordsgamesshortspacefocusclearmodelblockguideradiosharewomenagainmoneyimagenamesyounglineslatercolorgreenfront&watchforcepricerulesbeginaftervisitissueareasbelowindextotalhourslabelprintpressbuiltlinksspeedstudytradefoundsenseundershownformsrangeaddedstillmovedtakenaboveflashfixedoftenotherviewschecklegalriveritemsquickshapehumanexistgoingmoviethirdbasicpeacestagewidthloginideaswrotepagesusersdrivestorebreaksouthvoicesitesmonthwherebuildwhichearthforumthreesportpartyClicklowerlivesclasslayerentrystoryusagesoundcourtyour birthpopuptypesapplyImagebeinguppernoteseveryshowsmeansextramatchtrackknownearlybegansuperpapernorthlearngivennamedendedTermspartsGroupbrandusingwomanfalsereadyaudiotakeswhile.com/livedcasesdailychildgreatjudgethoseunitsneverbroadcoastcoverapplefilescyclesceneplansclickwritequeenpieceemailframeolderphotolimitcachecivilscaleenterthemetheretouchboundroyalaskedwholesincestock namefaithheartemptyofferscopeownedmightalbumthinkbloodarraymajortrustcanonunioncountvalidstoneStyleLoginhappyoccurleft:freshquitefilmsgradeneedsurbanfightbasishoverauto;route.htmlmixedfinalYour slidetopicbrownalonedrawnsplitreachRightdatesmarchquotegoodsLinksdoubtasyncthumballowchiefyouthnovel10px;serveuntilhandsCheckSpacequeryjamesequaltwice0,000Startpanelsongsroundeightshiftworthpostsleadsweeksavoidthesemilesplanesmartalphaplantmarksratesplaysclaimsalestextsstarswrongthing.org/multiheardPowerstandtokensolid(thisbringshipsstafftriedcallsfullyfactsagentThis //-->adminegyptEvent15px;Emailtrue"crossspentblogsbox">notedleavechinasizesguestrobotheavytrue,sevengrandcrimesignsawaredancephase>
+
+
+name=diegopage swiss-->
+
+#fff;">Log.com"treatsheet) && 14px;sleepntentfiledja:ãƒid="cName"worseshots-box-delta
+<bears:48Z spendbakershops= "";php">ction13px;brianhellosize=o=%2F joinmaybe
, fjsimg" ")[0]MTopBType"newlyDanskczechtrailknowsfaq">zh-cn10);
+-1");type=bluestrulydavis.js';>
+
+form jesus100% menu.
+
+walesrisksumentddingb-likteachgif" vegasdanskeestishqipsuomisobredesdeentretodospuedeañosestátienehastaotrospartedondenuevohacerformamismomejormundoaquÃdÃassóloayudafechatodastantomenosdatosotrassitiomuchoahoralugarmayorestoshorastenerantesfotosestaspaÃsnuevasaludforosmedioquienmesespoderchileserávecesdecirjoséestarventagrupohechoellostengoamigocosasnivelgentemismaairesjuliotemashaciafavorjuniolibrepuntobuenoautorabrilbuenatextomarzosaberlistaluegocómoenerojuegoperúhaberestoynuncamujervalorfueralibrogustaigualvotoscasosguÃapuedosomosavisousteddebennochebuscafaltaeurosseriedichocursoclavecasasleónplazolargoobrasvistaapoyojuntotratavistocrearcampohemoscincocargopisosordenhacenáreadiscopedrocercapuedapapelmenorútilclarojorgecalleponertardenadiemarcasigueellassiglocochemotosmadreclaserestoniñoquedapasarbancohijosviajepabloéstevienereinodejarfondocanalnorteletracausatomarmanoslunesautosvillavendopesartipostengamarcollevapadreunidovamoszonasambosbandamariaabusomuchasubirriojavivirgradochicaallÃjovendichaestantalessalirsuelopesosfinesllamabuscoéstalleganegroplazahumorpagarjuntadobleislasbolsabañohablaluchaÃreadicenjugarnotasvalleallácargadolorabajoestégustomentemariofirmacostofichaplatahogarartesleyesaquelmuseobasespocosmitadcielochicomiedoganarsantoetapadebesplayaredessietecortecoreadudasdeseoviejodeseaaguas"domaincommonstatuseventsmastersystemactionbannerremovescrollupdateglobalmediumfilternumberchangeresultpublicscreenchoosenormaltravelissuessourcetargetspringmodulemobileswitchphotosborderregionitselfsocialactivecolumnrecordfollowtitle>eitherlengthfamilyfriendlayoutauthorcreatereviewsummerserverplayedplayerexpandpolicyformatdoublepointsseriespersonlivingdesignmonthsforcesuniqueweightpeopleenergynaturesearchfigurehavingcustomoffsetletterwindowsubmitrendergroupsuploadhealthmethodvideosschoolfutureshadowdebatevaluesObjectothersrightsleaguechromesimplenoticesharedendingseasonreportonlinesquarebuttonimagesenablemovinglatestwinterFranceperiodstrongrepeatLondondetailformeddemandsecurepassedtoggleplacesdevicestaticcitiesstreamyellowattackstreetflighthiddeninfo">openedusefulvalleycausesleadersecretseconddamagesportsexceptratingsignedthingseffectfieldsstatesofficevisualeditorvolumeReportmuseummoviesparentaccessmostlymother" id="marketgroundchancesurveybeforesymbolmomentspeechmotioninsidematterCenterobjectexistsmiddleEuropegrowthlegacymannerenoughcareeransweroriginportalclientselectrandomclosedtopicscomingfatheroptionsimplyraisedescapechosenchurchdefinereasoncorneroutputmemoryiframepolicemodelsNumberduringoffersstyleskilledlistedcalledsilvermargindeletebetterbrowselimitsGlobalsinglewidgetcenterbudgetnowrapcreditclaimsenginesafetychoicespirit-stylespreadmakingneededrussiapleaseextentScriptbrokenallowschargedividefactormember-basedtheoryconfigaroundworkedhelpedChurchimpactshouldalwayslogo" bottomlist">){var prefixorangeHeader.push(couplegardenbridgelaunchReviewtakingvisionlittledatingButtonbeautythemesforgotSearchanchoralmostloadedChangereturnstringreloadMobileincomesupplySourceordersviewed courseAbout islandPhilipawardshandleimportOfficeregardskillsnationSportsdegreeweekly (e.g.behinddoctorloggedunitedbeyond-scaleacceptservedmarineFootercamera
+_form"leavesstress" />
+.gif" onloadloaderOxfordsistersurvivlistenfemaleDesignsize="appealtext">levelsthankshigherforcedanimalanyoneAfricaagreedrecentPeople
wonderpricesturned|| {};main">inlinesundaywrap">failedcensusminutebeaconquotes150px|estateremoteemail"linkedright;signalformal1.htmlsignupprincefloat:.png" forum.AccesspaperssoundsextendHeightsliderUTF-8"& Before. WithstudioownersmanageprofitjQueryannualparamsboughtfamousgooglelongeri++) {israelsayingdecidehome">headerensurebranchpiecesblock;statedtop">boston.test(avatartested_countforumsschemaindex,filledsharesreaderalert(appearSubmitline">body">
+* TheThoughseeingjerseyNews
+System DavidcancertablesprovedApril reallydriveritem">more">boardscolorscampusfirst || [];media.guitarfinishwidth:showedOther .php" assumelayerswilsonstoresreliefswedenCustomeasily your String
+
+Whiltaylorclear:resortfrenchthough") + "buyingbrandsMembername">oppingsector5px;">vspacepostermajor coffeemartinmaturehappenkansaslink">Images=falsewhile hspace0&
+
+In powerPolski-colorjordanBottomStart -count2.htmlnews">01.jpgOnline-rightmillerseniorISBN 00,000 guidesvalue)ectionrepair.xml" rights.html-blockregExp:hoverwithinvirginphones
using
+ var >');
+
+
+bahasabrasilgalegomagyarpolskisrpskiØ±Ø¯Ùˆä¸æ–‡ç®€ä½“ç¹é«”ä¿¡æ¯ä¸å›½æˆ‘们一个公å¸ç®¡ç†è®ºå›å¯ä»¥æœåŠ¡æ—¶é—´ä¸ªäººäº§å“自己ä¼ä¸šæŸ¥çœ‹å·¥ä½œè”系没有网站所有评论ä¸å¿ƒæ–‡ç« 用户首页作者技术问题相关下载æœç´¢ä½¿ç”¨è½¯ä»¶åœ¨çº¿ä¸»é¢˜èµ„æ–™è§†é¢‘å›žå¤æ³¨å†Œç½‘络收è—内容推è市场消æ¯ç©ºé—´å‘布什么好å‹ç”Ÿæ´»å›¾ç‰‡å‘展如果手机新闻最新方å¼åŒ—京æä¾›å…³äºŽæ›´å¤šè¿™ä¸ªç³»ç»ŸçŸ¥é“游æˆå¹¿å‘Šå…¶ä»–å‘表安全第一会员进行点击版æƒç”µå世界设计å…è´¹æ•™è‚²åŠ å…¥æ´»åŠ¨ä»–ä»¬å•†å“åšå®¢çŽ°åœ¨ä¸Šæµ·å¦‚ä½•å·²ç»ç•™è¨€è¯¦ç»†ç¤¾åŒºç™»å½•本站需è¦ä»·æ ¼æ”¯æŒå›½é™…链接国家建设朋å‹é˜…读法律ä½ç½®ç»æµŽé€‰æ‹©è¿™æ ·å½“å‰åˆ†ç±»æŽ’è¡Œå› ä¸ºäº¤æ˜“æœ€åŽéŸ³ä¹ä¸èƒ½é€šè¿‡è¡Œä¸šç§‘技å¯èƒ½è®¾å¤‡åˆä½œå¤§å®¶ç¤¾ä¼šç ”究专业全部项目这里还是开始情况电脑文件å“牌帮助文化资æºå¤§å¦å¦ä¹ åœ°å€æµè§ˆæŠ•èµ„å·¥ç¨‹è¦æ±‚怎么时候功能主è¦ç›®å‰èµ„讯城市方法电影招è˜å£°æ˜Žä»»ä½•å¥åº·æ•°æ®ç¾Žå›½æ±½è½¦ä»‹ç»ä½†æ˜¯äº¤æµç”Ÿäº§æ‰€ä»¥ç”µè¯æ˜¾ç¤ºä¸€äº›å•ä½äººå‘˜åˆ†æžåœ°å›¾æ—…游工具å¦ç”Ÿç³»åˆ—网å‹å¸–å密ç é¢‘é“æŽ§åˆ¶åœ°åŒºåŸºæœ¬å…¨å›½ç½‘ä¸Šé‡è¦ç¬¬äºŒå–œæ¬¢è¿›å…¥å‹æƒ…这些考试å‘现培è®ä»¥ä¸Šæ”¿åºœæˆä¸ºçŽ¯å¢ƒé¦™æ¸¯åŒæ—¶å¨±ä¹å‘é€ä¸€å®šå¼€å‘ä½œå“æ ‡å‡†æ¬¢è¿Žè§£å†³åœ°æ–¹ä¸€ä¸‹ä»¥åŠè´£ä»»æˆ–者客户代表积分女人数ç 销售出现离线应用列表ä¸åŒç¼–辑统计查询ä¸è¦æœ‰å…³æœºæž„å¾ˆå¤šæ’æ”¾ç»„织政ç–ç›´æŽ¥èƒ½åŠ›æ¥æºæ™‚間看到çƒé—¨å…³é”®ä¸“区éžå¸¸è‹±è¯ç™¾åº¦å¸Œæœ›ç¾Žå¥³æ¯”较知识规定建议部门æ„è§ç²¾å½©æ—¥æœ¬æé«˜å‘言方é¢åŸºé‡‘å¤„ç†æƒé™å½±ç‰‡é“¶è¡Œè¿˜æœ‰åˆ†äº«ç‰©å“ç»è¥æ·»åŠ ä¸“å®¶è¿™ç§è¯é¢˜èµ·æ¥ä¸šåŠ¡å…¬å‘Šè®°å½•ç®€ä»‹è´¨é‡ç”·äººå½±å“引用报告部分快速咨询时尚注æ„ç”³è¯·å¦æ ¡åº”该历å²åªæ˜¯è¿”回è´ä¹°å称为了æˆåŠŸè¯´æ˜Žä¾›åº”å©å专题程åºä¸€èˆ¬æœƒå“¡åªæœ‰å…¶å®ƒä¿æŠ¤è€Œä¸”今天窗å£åЍæ€çжæ€ç‰¹åˆ«è®¤ä¸ºå¿…须更新å°è¯´æˆ‘å€‘ä½œä¸ºåª’ä½“åŒ…æ‹¬é‚£ä¹ˆä¸€æ ·å›½å†…æ˜¯å¦æ ¹æ®ç”µè§†å¦é™¢å…·æœ‰è¿‡ç¨‹ç”±äºŽäººæ‰å‡ºæ¥ä¸è¿‡æ£åœ¨æ˜Žæ˜Ÿæ•…äº‹å…³ç³»æ ‡é¢˜å•†åŠ¡è¾“å…¥ä¸€ç›´åŸºç¡€æ•™å¦äº†è§£å»ºç‘结果全çƒé€šçŸ¥è®¡åˆ’对于艺术相册å‘生真的建立ç‰çº§ç±»åž‹ç»éªŒå®žçŽ°åˆ¶ä½œæ¥è‡ªæ ‡ç¾ä»¥ä¸‹åŽŸåˆ›æ— æ³•å…¶ä¸å€‹äººä¸€åˆ‡æŒ‡å—å…³é—é›†å›¢ç¬¬ä¸‰å…³æ³¨å› æ¤ç…§ç‰‡æ·±åœ³å•†ä¸šå¹¿å·žæ—¥æœŸé«˜çº§æœ€è¿‘综åˆè¡¨ç¤ºä¸“辑行为交通评价觉得精åŽå®¶åºå®Œæˆæ„Ÿè§‰å®‰è£…得到邮件制度食å“虽然转载报价记者方案行政人民用å“东西æå‡ºé…’店然åŽä»˜æ¬¾çƒç‚¹ä»¥å‰å®Œå…¨å‘帖设置领导工业医院看看ç»å…¸åŽŸå› å¹³å°å„ç§å¢žåŠ ææ–™æ–°å¢žä¹‹åŽèŒä¸šæ•ˆæžœä»Šå¹´è®ºæ–‡æˆ‘国告诉版主修改å‚与打å°å¿«ä¹æœºæ¢°è§‚点å˜åœ¨ç²¾ç¥žèŽ·å¾—åˆ©ç”¨ç»§ç»ä½ 们这么模å¼è¯è¨€èƒ½å¤Ÿé›…虎æ“ä½œé£Žæ ¼ä¸€èµ·ç§‘å¦ä½“育çŸä¿¡æ¡ä»¶æ²»ç–—è¿åŠ¨äº§ä¸šä¼šè®®å¯¼èˆªå…ˆç”Ÿè”ç›Ÿå¯æ˜¯å•題结构作用调查資料自动负责农业访问实施接å—讨论那个åé¦ˆåŠ å¼ºå¥³æ€§èŒƒå›´æœå‹™ä¼‘闲今日客æœè§€çœ‹å‚åŠ çš„è¯ä¸€ç‚¹ä¿è¯å›¾ä¹¦æœ‰æ•ˆæµ‹è¯•移动æ‰èƒ½å†³å®šè‚¡ç¥¨ä¸æ–需求ä¸å¾—办法之间采用è¥é”€æŠ•è¯‰ç›®æ ‡çˆ±æƒ…æ‘„å½±æœ‰äº›è¤‡è£½æ–‡å¦æœºä¼šæ•°å—装修è´ç‰©å†œæ‘å…¨é¢ç²¾å“其实事情水平æç¤ºä¸Šå¸‚è°¢è°¢æ™®é€šæ•™å¸ˆä¸Šä¼ ç±»åˆ«æŒæ›²æ‹¥æœ‰åˆ›æ–°é…ä»¶åªè¦æ—¶ä»£è³‡è¨Šè¾¾åˆ°äººç”Ÿè®¢é˜…è€å¸ˆå±•示心ç†è´´åç¶²ç«™ä¸»é¡Œè‡ªç„¶çº§åˆ«ç®€å•æ”¹é©é‚£äº›æ¥è¯´æ‰“开代ç åˆ é™¤è¯åˆ¸èŠ‚ç›®é‡ç‚¹æ¬¡æ•¸å¤šå°‘规划资金找到以åŽå¤§å…¨ä¸»é¡µæœ€ä½³å›žç”天下ä¿éšœçŽ°ä»£æ£€æŸ¥æŠ•ç¥¨å°æ—¶æ²’有æ£å¸¸ç”šè‡³ä»£ç†ç›®å½•公开å¤åˆ¶é‡‘èžå¹¸ç¦ç‰ˆæœ¬å½¢æˆå‡†å¤‡è¡Œæƒ…å›žåˆ°æ€æƒ³æ€Žæ ·åè®®è®¤è¯æœ€å¥½äº§ç”ŸæŒ‰ç…§æœè£…å¹¿ä¸œåŠ¨æ¼«é‡‡è´æ–°æ‰‹ç»„图颿¿å‚考政治容易天地努力人们å‡çº§é€Ÿåº¦äººç‰©è°ƒæ•´æµè¡Œé€ æˆæ–‡å—韩国贸易开展相關表现影视如æ¤ç¾Žå®¹å¤§å°æŠ¥é“æ¡æ¬¾å¿ƒæƒ…许多法规家居书店连接立å³ä¸¾æŠ¥æŠ€å·§å¥¥è¿ç™»å…¥ä»¥æ¥ç†è®ºäº‹ä»¶è‡ªç”±ä¸åŽåŠžå…¬å¦ˆå¦ˆçœŸæ£ä¸é”™å…¨æ–‡åˆåŒä»·å€¼åˆ«äººç›‘ç£å…·ä½“ä¸–çºªå›¢é˜Ÿåˆ›ä¸šæ‰¿æ‹…å¢žé•¿æœ‰äººä¿æŒå•†å®¶ç»´ä¿®å°æ¹¾å·¦å³è‚¡ä»½ç”案实际电信ç»ç†ç”Ÿå‘½å®£ä¼ 任务æ£å¼ç‰¹è‰²ä¸‹æ¥å会åªèƒ½å½“ç„¶é‡æ–°å…§å®¹æŒ‡å¯¼è¿è¡Œæ—¥å¿—賣家超过土地浙江支付推出站长æå·žæ‰§è¡Œåˆ¶é€ 之一推广现场æè¿°å˜åŒ–ä¼ ç»ŸæŒæ‰‹ä¿é™©è¯¾ç¨‹åŒ»ç–—ç»è¿‡è¿‡å޻之剿”¶å…¥å¹´åº¦æ‚志美丽最高登陆未æ¥åŠ å·¥å…责教程版å—身体é‡åº†å‡ºå”®æˆæœ¬å½¢å¼åœŸè±†å‡ºåƒ¹ä¸œæ–¹é‚®ç®±å—京求èŒå–å¾—èŒä½ç›¸ä¿¡é¡µé¢åˆ†é’Ÿç½‘页确定图例网å€ç§¯æžé”™è¯¯ç›®çš„å®è´æœºå…³é£Žé™©æŽˆæƒç—…æ¯’å® ç‰©é™¤äº†è©•è«–ç–¾ç—…åŠæ—¶æ±‚è´ç«™ç‚¹å„¿ç«¥æ¯å¤©ä¸å¤®è®¤è¯†æ¯ä¸ªå¤©æ´¥å—体å°ç£ç»´æŠ¤æœ¬é¡µä¸ªæ€§å®˜æ–¹å¸¸è§ç›¸æœºæˆ˜ç•¥åº”å½“å¾‹å¸ˆæ–¹ä¾¿æ ¡å›è‚¡å¸‚房屋æ 目员工导致çªç„¶é“å…·æœ¬ç½‘ç»“åˆæ¡£æ¡ˆåŠ³åŠ¨å¦å¤–美元引起改å˜ç¬¬å››ä¼šè®¡èªªæ˜Žéšç§å®å®è§„范消费共åŒå¿˜è®°ä½“系带æ¥åå—ç™¼è¡¨å¼€æ”¾åŠ ç›Ÿå—åˆ°äºŒæ‰‹å¤§é‡æˆäººæ•°é‡å…±äº«åŒºåŸŸå¥³å©åŽŸåˆ™æ‰€åœ¨ç»“æŸé€šä¿¡è¶…级é…ç½®å½“æ—¶ä¼˜ç§€æ€§æ„Ÿæˆ¿äº§éŠæˆ²å‡ºå£æäº¤å°±ä¸šä¿å¥ç¨‹åº¦å‚数事业整个山东情感特殊分類æœå°‹å±žäºŽé—¨æˆ·è´¢åŠ¡å£°éŸ³åŠå…¶è´¢ç»åšæŒå¹²éƒ¨æˆç«‹åˆ©ç›Šè€ƒè™‘æˆéƒ½åŒ…装用戶比赛文明招商完整真是眼ç›ä¼™ä¼´å¨æœ›é¢†åŸŸå«ç”Ÿä¼˜æƒ 論壇公共良好充分符åˆé™„件特点ä¸å¯è‹±æ–‡èµ„äº§æ ¹æœ¬æ˜Žæ˜¾å¯†ç¢¼å…¬ä¼—æ°‘æ—æ›´åŠ äº«å—åŒå¦å¯åЍ适åˆåŽŸæ¥é—®ç”本文美食绿色稳定终于生物供求æœç‹åŠ›é‡ä¸¥é‡æ°¸è¿œå†™çœŸæœ‰é™ç«žäº‰å¯¹è±¡è´¹ç”¨ä¸å¥½ç»å¯¹å分促进点评影音优势ä¸å°‘欣èµå¹¶ä¸”有点方å‘å…¨æ–°ä¿¡ç”¨è®¾æ–½å½¢è±¡èµ„æ ¼çªç ´éšç€é‡å¤§äºŽæ˜¯æ¯•ä¸šæ™ºèƒ½åŒ–å·¥å®Œç¾Žå•†åŸŽç»Ÿä¸€å‡ºç‰ˆæ‰“é€ ç”¢å“æ¦‚况用于ä¿ç•™å› ç´ ä¸åœ‹å˜å‚¨è´´å›¾æœ€æ„›é•¿æœŸå£ä»·ç†è´¢åŸºåœ°å®‰æŽ’æ¦æ±‰é‡Œé¢åˆ›å»ºå¤©ç©ºé¦–先完善驱动下é¢ä¸å†è¯šä¿¡æ„义阳光英国漂亮军事玩家群众农民å³å¯å稱家具动画想到注明å°å¦æ€§èƒ½è€ƒç ”硬件观看清楚æžç¬‘首é 黄金适用江è‹çœŸå®žä¸»ç®¡é˜¶æ®µè¨»å†Šç¿»è¯‘æƒåˆ©åšå¥½ä¼¼ä¹Žé€šè®¯æ–½å·¥ç‹€æ…‹ä¹Ÿè®¸çޝä¿åŸ¹å…»æ¦‚念大型机票ç†è§£åŒ¿åcuandoenviarmadridbuscariniciotiempoporquecuentaestadopuedenjuegoscontraestánnombretienenperfilmaneraamigosciudadcentroaunquepuedesdentroprimerpreciosegúnbuenosvolverpuntossemanahabÃaagostonuevosunidoscarlosequiponiñosmuchosalgunacorreoimagenpartirarribamarÃahombreempleoverdadcambiomuchasfueronpasadolÃneaparecenuevascursosestabaquierolibroscuantoaccesomiguelvarioscuatrotienesgruposseráneuropamediosfrenteacercademásofertacochesmodeloitalialetrasalgúncompracualesexistecuerposiendoprensallegarviajesdineromurciapodrápuestodiariopuebloquieremanuelpropiocrisisciertoseguromuertefuentecerrargrandeefectopartesmedidapropiaofrecetierrae-mailvariasformasfuturoobjetoseguirriesgonormasmismosúnicocaminositiosrazóndebidopruebatoledotenÃajesúsesperococinaorigentiendacientocádizhablarserÃalatinafuerzaestiloguerraentraréxitolópezagendavÃdeoevitarpaginametrosjavierpadresfácilcabezaáreassalidaenvÃojapónabusosbienestextosllevarpuedanfuertecomúnclaseshumanotenidobilbaounidadestáseditarcreadoдлÑчтокакилиÑтовÑеегопритакещеужеКакбезбылониВÑеподÐтотомчемнетлетразонагдемнеДлÑПринаÑнихтемктогодвоттамСШÐмаÑЧтоваÑвамемуТакдванамÑтиÑтуВамтехпротутнадднÑВоттринейВаÑнимÑамтотрубОнимирнееОООлицÑтаОнанемдоммойдвеоноÑудकेहैकीसेकाकोऔरपरनेà¤à¤•किà¤à¥€à¤‡à¤¸à¤•रतोहोआपहीयहयातकथाjagranआजजोअबदोगईजागà¤à¤¹à¤®à¤‡à¤¨à¤µà¤¹à¤¯à¥‡à¤¥à¥‡à¤¥à¥€à¤˜à¤°à¤œà¤¬à¤¦à¥€à¤•ईजीवेनईनà¤à¤¹à¤°à¤‰à¤¸à¤®à¥‡à¤•मवोलेसबमईदेओरआमबसà¤à¤°à¤¬à¤¨à¤šà¤²à¤®à¤¨à¤†à¤—à¤¸à¥€à¤²à¥€Ø¹Ù„Ù‰Ø¥Ù„Ù‰Ù‡Ø°Ø§Ø¢Ø®Ø±Ø¹Ø¯Ø¯Ø§Ù„Ù‰Ù‡Ø°Ù‡ØµÙˆØ±ØºÙŠØ±ÙƒØ§Ù†ÙˆÙ„Ø§Ø¨ÙŠÙ†Ø¹Ø±Ø¶Ø°Ù„ÙƒÙ‡Ù†Ø§ÙŠÙˆÙ…Ù‚Ø§Ù„Ø¹Ù„ÙŠØ§Ù†Ø§Ù„ÙƒÙ†ØØªÙ‰Ù‚Ø¨Ù„ÙˆØØ©Ø§Ø®Ø±ÙÙ‚Ø·Ø¹Ø¨Ø¯Ø±ÙƒÙ†Ø¥Ø°Ø§ÙƒÙ…Ø§Ø§ØØ¯Ø¥Ù„اÙÙŠÙ‡Ø¨Ø¹Ø¶ÙƒÙŠÙØ¨ØØ«ÙˆÙ…نوهوأناجدالهاسلمعندليسعبرصلىمنذبهاأنهمثلكنتالاØÙŠØ«Ù…ØµØ±Ø´Ø±ØØÙˆÙ„ÙˆÙÙŠØ§Ø°Ø§Ù„ÙƒÙ„Ù…Ø±Ø©Ø§Ù†ØªØ§Ù„ÙØ£Ø¨ÙˆØ®Ø§ØµØ£Ù†ØªØ§Ù†Ù‡Ø§Ù„ÙŠØ¹Ø¶ÙˆÙˆÙ‚Ø¯Ø§Ø¨Ù†Ø®ÙŠØ±Ø¨Ù†ØªÙ„ÙƒÙ…Ø´Ø§Ø¡ÙˆÙ‡ÙŠØ§Ø¨ÙˆÙ‚ØµØµÙˆÙ…Ø§Ø±Ù‚Ù…Ø£ØØ¯Ù†ØÙ†Ø¹Ø¯Ù…Ø±Ø£ÙŠØ§ØØ©ÙƒØªØ¨Ø¯ÙˆÙ†ÙŠØ¬Ø¨Ù…Ù†Ù‡ØªØØªØ¬Ù‡Ø©Ø³Ù†Ø©ÙŠØªÙ…ÙƒØ±Ø©ØºØ²Ø©Ù†ÙØ³Ø¨ÙŠØªÙ„لهلناتلكقلبلماعنهأولشيءنورأماÙيكبكلذاترتببأنهمسانكبيعÙÙ‚Ø¯ØØ³Ù†Ù„همشعرأهلشهرقطرطلبprofileservicedefaulthimselfdetailscontentsupportstartedmessagesuccessfashioncountryaccountcreatedstoriesresultsrunningprocesswritingobjectsvisiblewelcomearticleunknownnetworkcompanydynamicbrowserprivacyproblemServicerespectdisplayrequestreservewebsitehistoryfriendsoptionsworkingversionmillionchannelwindow.addressvisitedweathercorrectproductedirectforwardyou canremovedsubjectcontrolarchivecurrentreadinglibrarylimitedmanagerfurthersummarymachineminutesprivatecontextprogramsocietynumberswrittenenabledtriggersourcesloadingelementpartnerfinallyperfectmeaningsystemskeepingculture",journalprojectsurfaces"expiresreviewsbalanceEnglishContentthroughPlease opinioncontactaverageprimaryvillageSpanishgallerydeclinemeetingmissionpopularqualitymeasuregeneralspeciessessionsectionwriterscounterinitialreportsfiguresmembersholdingdisputeearlierexpressdigitalpictureAnothermarriedtrafficleadingchangedcentralvictoryimages/reasonsstudiesfeaturelistingmust beschoolsVersionusuallyepisodeplayinggrowingobviousoverlaypresentactions
+wrapperalreadycertainrealitystorageanotherdesktopofferedpatternunusualDigitalcapitalWebsitefailureconnectreducedAndroiddecadesregular & animalsreleaseAutomatgettingmethodsnothingPopularcaptionletterscapturesciencelicensechangesEngland=1&History = new CentralupdatedSpecialNetworkrequirecommentwarningCollegetoolbarremainsbecauseelectedDeutschfinanceworkersquicklybetweenexactlysettingdiseaseSocietyweaponsexhibit<!--Controlclassescoveredoutlineattacksdevices(windowpurposetitle="Mobile killingshowingItaliandroppedheavilyeffects-1']);
+confirmCurrentadvancesharingopeningdrawingbillionorderedGermanyrelatedincludewhetherdefinedSciencecatalogArticlebuttonslargestuniformjourneysidebarChicagoholidayGeneralpassage,"animatefeelingarrivedpassingnaturalroughly.
+
+The but notdensityBritainChineselack oftributeIreland" data-factorsreceivethat isLibraryhusbandin factaffairsCharlesradicalbroughtfindinglanding:lang="return leadersplannedpremiumpackageAmericaEdition]"Messageneed tovalue="complexlookingstationbelievesmaller-mobilerecordswant tokind ofFirefoxyou aresimilarstudiedmaximumheadingrapidlyclimatekingdomemergedamountsfoundedpioneerformuladynastyhow to SupportrevenueeconomyResultsbrothersoldierlargelycalling."AccountEdward segmentRobert effortsPacificlearnedup withheight:we haveAngelesnations_searchappliedacquiremassivegranted: falsetreatedbiggestbenefitdrivingStudiesminimumperhapsmorningsellingis usedreversevariant role="missingachievepromotestudentsomeoneextremerestorebottom:evolvedall thesitemapenglishway to AugustsymbolsCompanymattersmusicalagainstserving})();
+paymenttroubleconceptcompareparentsplayersregionsmonitor ''The winningexploreadaptedGalleryproduceabilityenhancecareers). The collectSearch ancientexistedfooter handlerprintedconsoleEasternexportswindowsChannelillegalneutralsuggest_headersigning.html">settledwesterncausing-webkitclaimedJusticechaptervictimsThomas mozillapromisepartieseditionoutside:false,hundredOlympic_buttonauthorsreachedchronicdemandssecondsprotectadoptedprepareneithergreatlygreateroverallimprovecommandspecialsearch.worshipfundingthoughthighestinsteadutilityquarterCulturetestingclearlyexposedBrowserliberal} catchProjectexamplehide();FloridaanswersallowedEmperordefenseseriousfreedomSeveral-buttonFurtherout of != nulltrainedDenmarkvoid(0)/all.jspreventRequestStephen
+
+When observe
+Modern provide" alt="borders.
+
+For
+
+Many artistspoweredperformfictiontype ofmedicalticketsopposedCouncilwitnessjusticeGeorge Belgium...twitternotablywaitingwarfare Other rankingphrasesmentionsurvivescholar
+ Countryignoredloss ofjust asGeorgiastrange
+ severalbecomesselect wedding00.htmlmonarchoff theteacherhighly biologylife ofor evenrise of»plusonehunting(thoughDouglasjoiningcirclesFor theAncientVietnamvehiclesuch ascrystalvalue =Windowsenjoyeda smallassumed