Merge mozilla-inbound and mozilla-central
@ -734,19 +734,11 @@ pref("urlclassifier.gethashtables", "goog-phish-shavar,goog-malware-shavar");
|
||||
// the database.
|
||||
pref("urlclassifier.confirm-age", 2700);
|
||||
|
||||
#ifdef MOZ_WIDGET_GTK2
|
||||
#define RESTRICT_CACHEMAX
|
||||
#endif
|
||||
#ifdef XP_OS2
|
||||
#define RESTRICT_CACHEMAX
|
||||
#endif
|
||||
|
||||
// Maximum size of the sqlite3 cache during an update, in bytes
|
||||
#ifdef RESTRICT_CACHEMAX
|
||||
pref("urlclassifier.updatecachemax", 104857600);
|
||||
#else
|
||||
pref("urlclassifier.updatecachemax", -1);
|
||||
#endif
|
||||
pref("urlclassifier.updatecachemax", 41943040);
|
||||
|
||||
// Maximum size of the sqlite3 cache for lookups, in bytes
|
||||
pref("urlclassifier.lookupcachemax", 1048576);
|
||||
|
||||
// URL for checking the reason for a malware warning.
|
||||
pref("browser.safebrowsing.malware.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");
|
||||
|
@ -10,7 +10,7 @@
|
||||
#endif
|
||||
>
|
||||
<uses-sdk android:minSdkVersion="5"
|
||||
android:targetSdkVersion="5"/>
|
||||
android:targetSdkVersion="11"/>
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
|
@ -15,20 +15,20 @@
|
||||
android:layout_height="25dp"
|
||||
android:scaleType="fitCenter" />
|
||||
<TextView android:id="@+id/notificationTitle"
|
||||
android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent.Title"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="marquee"
|
||||
android:fadingEdge="horizontal"
|
||||
android:textStyle="bold"
|
||||
android:textSize="18sp"
|
||||
android:paddingLeft="4dp"
|
||||
android:textColor="#ff000000" />
|
||||
/>
|
||||
</LinearLayout>
|
||||
<TextView android:id="@+id/notificationText"
|
||||
android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="4dp"
|
||||
android:textColor="#ff000000" />
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
@ -16,16 +16,15 @@
|
||||
android:layout_height="25dp"
|
||||
android:scaleType="fitCenter" />
|
||||
<TextView android:id="@+id/notificationTitle"
|
||||
android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent.Title"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="marquee"
|
||||
android:fadingEdge="horizontal"
|
||||
android:textStyle="bold"
|
||||
android:textSize="18sp"
|
||||
android:paddingLeft="10dp"
|
||||
android:textColor="#ff000000" />
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
@ -34,10 +33,11 @@
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
<TextView android:id="@+id/notificationText"
|
||||
android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="3dp"
|
||||
android:textColor="#ff000000" />
|
||||
/>
|
||||
|
||||
<ProgressBar android:id="@+id/notificationProgressbar"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
|
@ -15,16 +15,15 @@
|
||||
android:layout_height="25dp"
|
||||
android:scaleType="fitCenter" />
|
||||
<TextView android:id="@+id/notificationTitle"
|
||||
android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent.Title"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="marquee"
|
||||
android:fadingEdge="horizontal"
|
||||
android:textStyle="bold"
|
||||
android:textSize="18sp"
|
||||
android:paddingLeft="4dp"
|
||||
android:textColor="#ff000000" />
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
||||
<ProgressBar android:id="@+id/notificationProgressbar"
|
||||
@ -38,9 +37,10 @@
|
||||
android:layout_centerHorizontal="true" />
|
||||
|
||||
<TextView android:id="@+id/notificationText"
|
||||
android:textAppearance="@android:style/TextAppearance.StatusBar.EventContent"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="4dp"
|
||||
android:textColor="#ff000000" />
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -130,6 +130,17 @@ void Histogram::Add(int value) {
|
||||
Accumulate(value, 1, index);
|
||||
}
|
||||
|
||||
void Histogram::Subtract(int value) {
|
||||
if (value > kSampleType_MAX - 1)
|
||||
value = kSampleType_MAX - 1;
|
||||
if (value < 0)
|
||||
value = 0;
|
||||
size_t index = BucketIndex(value);
|
||||
DCHECK_GE(value, ranges(index));
|
||||
DCHECK_LT(value, ranges(index + 1));
|
||||
Accumulate(value, -1, index);
|
||||
}
|
||||
|
||||
void Histogram::AddBoolean(bool value) {
|
||||
DCHECK(false);
|
||||
}
|
||||
|
@ -381,6 +381,7 @@ class Histogram {
|
||||
Flags flags);
|
||||
|
||||
void Add(int value);
|
||||
void Subtract(int value);
|
||||
|
||||
// This method is an interface, used only by BooleanHistogram.
|
||||
virtual void AddBoolean(bool value);
|
||||
|
@ -155,6 +155,7 @@ CPPSRCS = \
|
||||
jsxml.cpp \
|
||||
prmjtime.cpp \
|
||||
sharkctl.cpp \
|
||||
CallObject.cpp \
|
||||
Debugger.cpp \
|
||||
GlobalObject.cpp \
|
||||
Stack.cpp \
|
||||
@ -247,6 +248,7 @@ EXPORTS_NAMESPACES = vm
|
||||
|
||||
EXPORTS_vm = \
|
||||
ArgumentsObject.h \
|
||||
CallObject.h \
|
||||
GlobalObject.h \
|
||||
Stack.h \
|
||||
String.h \
|
||||
|
185
js/src/jsfun.cpp
@ -72,6 +72,7 @@
|
||||
#include "jsexn.h"
|
||||
#include "jsstaticcheck.h"
|
||||
#include "jstracer.h"
|
||||
#include "vm/CallObject.h"
|
||||
#include "vm/Debugger.h"
|
||||
|
||||
#if JS_HAS_GENERATORS
|
||||
@ -91,7 +92,7 @@
|
||||
#include "jsinferinlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
#include "vm/CallObject-inl.h"
|
||||
#include "vm/ArgumentsObject-inl.h"
|
||||
#include "vm/Stack-inl.h"
|
||||
|
||||
@ -283,7 +284,7 @@ js_GetArgsObject(JSContext *cx, StackFrame *fp)
|
||||
if (argsobj->isStrictArguments())
|
||||
fp->forEachCanonicalActualArg(PutArg(argsobj->data()->slots));
|
||||
else
|
||||
argsobj->setPrivate(fp);
|
||||
argsobj->setStackFrame(fp);
|
||||
|
||||
fp->setArgsObj(*argsobj);
|
||||
return argsobj;
|
||||
@ -294,11 +295,11 @@ js_PutArgsObject(StackFrame *fp)
|
||||
{
|
||||
ArgumentsObject &argsobj = fp->argsObj();
|
||||
if (argsobj.isNormalArguments()) {
|
||||
JS_ASSERT(argsobj.getPrivate() == fp);
|
||||
JS_ASSERT(argsobj.maybeStackFrame() == fp);
|
||||
fp->forEachCanonicalActualArg(PutArg(argsobj.data()->slots));
|
||||
argsobj.setPrivate(NULL);
|
||||
argsobj.setStackFrame(NULL);
|
||||
} else {
|
||||
JS_ASSERT(!argsobj.getPrivate());
|
||||
JS_ASSERT(!argsobj.maybeStackFrame());
|
||||
}
|
||||
}
|
||||
|
||||
@ -319,9 +320,9 @@ js_NewArgumentsOnTrace(JSContext *cx, uint32 argc, JSObject *callee)
|
||||
* Strict mode callers must copy arguments into the created arguments
|
||||
* object. The trace-JITting code is in TraceRecorder::newArguments.
|
||||
*/
|
||||
JS_ASSERT(!argsobj->getPrivate());
|
||||
JS_ASSERT(!argsobj->maybeStackFrame());
|
||||
} else {
|
||||
argsobj->setPrivate(JS_ARGUMENTS_OBJECT_ON_TRACE);
|
||||
argsobj->setOnTrace();
|
||||
}
|
||||
|
||||
return argsobj;
|
||||
@ -335,7 +336,7 @@ js_PutArgumentsOnTrace(JSContext *cx, JSObject *obj, Value *argv)
|
||||
{
|
||||
NormalArgumentsObject *argsobj = obj->asNormalArguments();
|
||||
|
||||
JS_ASSERT(argsobj->getPrivate() == JS_ARGUMENTS_OBJECT_ON_TRACE);
|
||||
JS_ASSERT(argsobj->onTrace());
|
||||
|
||||
/*
|
||||
* TraceRecorder::putActivationObjects builds a single, contiguous array of
|
||||
@ -349,7 +350,7 @@ js_PutArgumentsOnTrace(JSContext *cx, JSObject *obj, Value *argv)
|
||||
*dst = *src;
|
||||
}
|
||||
|
||||
argsobj->setPrivate(NULL);
|
||||
argsobj->clearOnTrace();
|
||||
return true;
|
||||
}
|
||||
JS_DEFINE_CALLINFO_3(extern, BOOL, js_PutArgumentsOnTrace, CONTEXT, OBJECT, VALUEPTR, 0,
|
||||
@ -390,7 +391,7 @@ ArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
uintN arg = uintN(JSID_TO_INT(id));
|
||||
if (arg < argsobj->initialLength()) {
|
||||
JS_ASSERT(!argsobj->element(arg).isMagic(JS_ARGS_HOLE));
|
||||
if (StackFrame *fp = reinterpret_cast<StackFrame *>(argsobj->getPrivate()))
|
||||
if (StackFrame *fp = argsobj->maybeStackFrame())
|
||||
*vp = fp->canonicalActualArg(arg);
|
||||
else
|
||||
*vp = argsobj->element(arg);
|
||||
@ -427,7 +428,7 @@ ArgSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
||||
if (JSID_IS_INT(id)) {
|
||||
uintN arg = uintN(JSID_TO_INT(id));
|
||||
if (arg < argsobj->initialLength()) {
|
||||
if (StackFrame *fp = reinterpret_cast<StackFrame *>(argsobj->getPrivate())) {
|
||||
if (StackFrame *fp = argsobj->maybeStackFrame()) {
|
||||
JSScript *script = fp->functionScript();
|
||||
if (script->usesArguments) {
|
||||
if (arg < fp->numFormalArgs())
|
||||
@ -673,7 +674,7 @@ static void
|
||||
args_trace(JSTracer *trc, JSObject *obj)
|
||||
{
|
||||
ArgumentsObject *argsobj = obj->asArguments();
|
||||
if (argsobj->getPrivate() == JS_ARGUMENTS_OBJECT_ON_TRACE) {
|
||||
if (argsobj->onTrace()) {
|
||||
JS_ASSERT(!argsobj->isStrictArguments());
|
||||
return;
|
||||
}
|
||||
@ -757,57 +758,6 @@ Class js::DeclEnvClass = {
|
||||
ConvertStub
|
||||
};
|
||||
|
||||
/*
|
||||
* Construct a call object for the given bindings. If this is a call object
|
||||
* for a function invocation, callee should be the function being called.
|
||||
* Otherwise it must be a call object for eval of strict mode code, and callee
|
||||
* must be null.
|
||||
*/
|
||||
static JSObject *
|
||||
NewCallObject(JSContext *cx, JSScript *script, JSObject &scopeChain, JSObject *callee)
|
||||
{
|
||||
Bindings &bindings = script->bindings;
|
||||
size_t argsVars = bindings.countArgsAndVars();
|
||||
size_t slots = JSObject::CALL_RESERVED_SLOTS + argsVars;
|
||||
gc::AllocKind kind = gc::GetGCObjectKind(slots);
|
||||
|
||||
/*
|
||||
* Make sure that the arguments and variables in the call object all end up
|
||||
* in a contiguous range of slots. We need this to be able to embed the
|
||||
* args/vars arrays in the TypeScriptNesting for the function, after the
|
||||
* call object's frame has finished.
|
||||
*/
|
||||
if (cx->typeInferenceEnabled() && gc::GetGCKindSlots(kind) < slots) {
|
||||
kind = gc::GetGCObjectKind(JSObject::CALL_RESERVED_SLOTS);
|
||||
JS_ASSERT(gc::GetGCKindSlots(kind) == JSObject::CALL_RESERVED_SLOTS);
|
||||
}
|
||||
|
||||
JSObject *callobj = js_NewGCObject(cx, kind);
|
||||
if (!callobj)
|
||||
return NULL;
|
||||
|
||||
/* Init immediately to avoid GC seeing a half-init'ed object. */
|
||||
callobj->initCall(cx, bindings, &scopeChain);
|
||||
callobj->makeVarObj();
|
||||
|
||||
/* This must come after callobj->lastProp has been set. */
|
||||
if (!callobj->ensureInstanceReservedSlots(cx, argsVars))
|
||||
return NULL;
|
||||
|
||||
#ifdef DEBUG
|
||||
for (Shape::Range r = callobj->lastProp; !r.empty(); r.popFront()) {
|
||||
const Shape &s = r.front();
|
||||
if (s.slot != SHAPE_INVALID_SLOT) {
|
||||
JS_ASSERT(s.slot + 1 == callobj->slotSpan());
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
callobj->setCallObjCallee(callee);
|
||||
return callobj;
|
||||
}
|
||||
|
||||
static inline JSObject *
|
||||
NewDeclEnvObject(JSContext *cx, StackFrame *fp)
|
||||
{
|
||||
@ -826,7 +776,7 @@ NewDeclEnvObject(JSContext *cx, StackFrame *fp)
|
||||
|
||||
namespace js {
|
||||
|
||||
JSObject *
|
||||
CallObject *
|
||||
CreateFunCallObject(JSContext *cx, StackFrame *fp)
|
||||
{
|
||||
JS_ASSERT(fp->isNonEvalFunctionFrame());
|
||||
@ -852,23 +802,23 @@ CreateFunCallObject(JSContext *cx, StackFrame *fp)
|
||||
}
|
||||
}
|
||||
|
||||
JSObject *callobj = NewCallObject(cx, fp->script(), *scopeChain, &fp->callee());
|
||||
CallObject *callobj = CallObject::create(cx, fp->script(), *scopeChain, &fp->callee());
|
||||
if (!callobj)
|
||||
return NULL;
|
||||
|
||||
callobj->setPrivate(fp);
|
||||
callobj->setStackFrame(fp);
|
||||
fp->setScopeChainWithOwnCallObj(*callobj);
|
||||
return callobj;
|
||||
}
|
||||
|
||||
JSObject *
|
||||
CallObject *
|
||||
CreateEvalCallObject(JSContext *cx, StackFrame *fp)
|
||||
{
|
||||
JSObject *callobj = NewCallObject(cx, fp->script(), fp->scopeChain(), NULL);
|
||||
CallObject *callobj = CallObject::create(cx, fp->script(), fp->scopeChain(), NULL);
|
||||
if (!callobj)
|
||||
return NULL;
|
||||
|
||||
callobj->setPrivate(fp);
|
||||
callobj->setStackFrame(fp);
|
||||
fp->setScopeChainWithOwnCallObj(*callobj);
|
||||
return callobj;
|
||||
}
|
||||
@ -881,52 +831,44 @@ js_CreateCallObjectOnTrace(JSContext *cx, JSFunction *fun, JSObject *callee, JSO
|
||||
JS_ASSERT(!js_IsNamedLambda(fun));
|
||||
JS_ASSERT(scopeChain);
|
||||
JS_ASSERT(callee);
|
||||
return NewCallObject(cx, fun->script(), *scopeChain, callee);
|
||||
return CallObject::create(cx, fun->script(), *scopeChain, callee);
|
||||
}
|
||||
|
||||
JS_DEFINE_CALLINFO_4(extern, OBJECT, js_CreateCallObjectOnTrace, CONTEXT, FUNCTION, OBJECT, OBJECT,
|
||||
0, nanojit::ACCSET_STORE_ANY)
|
||||
|
||||
inline static void
|
||||
CopyValuesToCallObject(JSObject &callobj, uintN nargs, Value *argv, uintN nvars, Value *slots)
|
||||
{
|
||||
JS_ASSERT(callobj.numSlots() >= JSObject::CALL_RESERVED_SLOTS + nargs + nvars);
|
||||
callobj.copySlotRange(JSObject::CALL_RESERVED_SLOTS, argv, nargs);
|
||||
callobj.copySlotRange(JSObject::CALL_RESERVED_SLOTS + nargs, slots, nvars);
|
||||
}
|
||||
|
||||
void
|
||||
js_PutCallObject(StackFrame *fp)
|
||||
{
|
||||
JSObject &callobj = fp->callObj();
|
||||
JS_ASSERT(callobj.getPrivate() == fp);
|
||||
CallObject &callobj = fp->callObj().asCall();
|
||||
JS_ASSERT(callobj.maybeStackFrame() == fp);
|
||||
JS_ASSERT_IF(fp->isEvalFrame(), fp->isStrictEvalFrame());
|
||||
JS_ASSERT(fp->isEvalFrame() == callobj.callIsForEval());
|
||||
JS_ASSERT(fp->isEvalFrame() == callobj.isForEval());
|
||||
|
||||
/* Get the arguments object to snapshot fp's actual argument values. */
|
||||
if (fp->hasArgsObj()) {
|
||||
if (!fp->hasOverriddenArgs())
|
||||
callobj.setCallObjArguments(ObjectValue(fp->argsObj()));
|
||||
callobj.setArguments(ObjectValue(fp->argsObj()));
|
||||
js_PutArgsObject(fp);
|
||||
}
|
||||
|
||||
JSScript *script = fp->script();
|
||||
Bindings &bindings = script->bindings;
|
||||
|
||||
if (callobj.callIsForEval()) {
|
||||
if (callobj.isForEval()) {
|
||||
JS_ASSERT(script->strictModeCode);
|
||||
JS_ASSERT(bindings.countArgs() == 0);
|
||||
|
||||
/* This could be optimized as below, but keep it simple for now. */
|
||||
CopyValuesToCallObject(callobj, 0, NULL, bindings.countVars(), fp->slots());
|
||||
callobj.copyValues(0, NULL, bindings.countVars(), fp->slots());
|
||||
} else {
|
||||
JSFunction *fun = fp->fun();
|
||||
JS_ASSERT(fun == callobj.getCallObjCalleeFunction());
|
||||
JS_ASSERT(fun == callobj.getCalleeFunction());
|
||||
JS_ASSERT(script == fun->script());
|
||||
|
||||
uintN n = bindings.countArgsAndVars();
|
||||
if (n > 0) {
|
||||
JS_ASSERT(JSObject::CALL_RESERVED_SLOTS + n <= callobj.numSlots());
|
||||
JS_ASSERT(CallObject::RESERVED_SLOTS + n <= callobj.numSlots());
|
||||
|
||||
uint32 nvars = bindings.countVars();
|
||||
uint32 nargs = bindings.countArgs();
|
||||
@ -939,7 +881,7 @@ js_PutCallObject(StackFrame *fp)
|
||||
|| script->debugMode
|
||||
#endif
|
||||
) {
|
||||
CopyValuesToCallObject(callobj, nargs, fp->formalArgs(), nvars, fp->slots());
|
||||
callobj.copyValues(nargs, fp->formalArgs(), nvars, fp->slots());
|
||||
} else {
|
||||
/*
|
||||
* For each arg & var that is closed over, copy it from the stack
|
||||
@ -948,13 +890,13 @@ js_PutCallObject(StackFrame *fp)
|
||||
uint32 nclosed = script->nClosedArgs;
|
||||
for (uint32 i = 0; i < nclosed; i++) {
|
||||
uint32 e = script->getClosedArg(i);
|
||||
callobj.setSlot(JSObject::CALL_RESERVED_SLOTS + e, fp->formalArg(e));
|
||||
callobj.setArg(e, fp->formalArg(e));
|
||||
}
|
||||
|
||||
nclosed = script->nClosedVars;
|
||||
for (uint32 i = 0; i < nclosed; i++) {
|
||||
uint32 e = script->getClosedVar(i);
|
||||
callobj.setSlot(JSObject::CALL_RESERVED_SLOTS + nargs + e, fp->slots()[e]);
|
||||
callobj.setVar(e, fp->slots()[e]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -964,8 +906,8 @@ js_PutCallObject(StackFrame *fp)
|
||||
*/
|
||||
types::TypeScriptNesting *nesting = script->nesting();
|
||||
if (nesting && script->isOuterFunction) {
|
||||
nesting->argArray = callobj.callObjArgArray();
|
||||
nesting->varArray = callobj.callObjVarArray();
|
||||
nesting->argArray = callobj.argArray();
|
||||
nesting->varArray = callobj.varArray();
|
||||
}
|
||||
}
|
||||
|
||||
@ -979,19 +921,19 @@ js_PutCallObject(StackFrame *fp)
|
||||
}
|
||||
}
|
||||
|
||||
callobj.setPrivate(NULL);
|
||||
callobj.setStackFrame(NULL);
|
||||
}
|
||||
|
||||
JSBool JS_FASTCALL
|
||||
js_PutCallObjectOnTrace(JSObject *callobj, uint32 nargs, Value *argv,
|
||||
js_PutCallObjectOnTrace(JSObject *obj, uint32 nargs, Value *argv,
|
||||
uint32 nvars, Value *slots)
|
||||
{
|
||||
JS_ASSERT(callobj->isCall());
|
||||
JS_ASSERT(!callobj->getPrivate());
|
||||
CallObject &callobj = obj->asCall();
|
||||
JS_ASSERT(!callobj.maybeStackFrame());
|
||||
|
||||
uintN n = nargs + nvars;
|
||||
if (n != 0)
|
||||
CopyValuesToCallObject(*callobj, nargs, argv, nvars, slots);
|
||||
callobj.copyValues(nargs, argv, nvars, slots);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1004,14 +946,16 @@ namespace js {
|
||||
static JSBool
|
||||
GetCallArguments(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
{
|
||||
StackFrame *fp = obj->maybeCallObjStackFrame();
|
||||
CallObject &callobj = obj->asCall();
|
||||
|
||||
StackFrame *fp = callobj.maybeStackFrame();
|
||||
if (fp && !fp->hasOverriddenArgs()) {
|
||||
JSObject *argsobj = js_GetArgsObject(cx, fp);
|
||||
if (!argsobj)
|
||||
return false;
|
||||
vp->setObject(*argsobj);
|
||||
} else {
|
||||
*vp = obj->getCallObjArguments();
|
||||
*vp = callobj.getArguments();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -1019,37 +963,41 @@ GetCallArguments(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
static JSBool
|
||||
SetCallArguments(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
||||
{
|
||||
if (StackFrame *fp = obj->maybeCallObjStackFrame())
|
||||
CallObject &callobj = obj->asCall();
|
||||
|
||||
if (StackFrame *fp = callobj.maybeStackFrame())
|
||||
fp->setOverriddenArgs();
|
||||
obj->setCallObjArguments(*vp);
|
||||
callobj.setArguments(*vp);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
GetCallArg(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
{
|
||||
CallObject &callobj = obj->asCall();
|
||||
JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
|
||||
uintN i = (uint16) JSID_TO_INT(id);
|
||||
|
||||
if (StackFrame *fp = obj->maybeCallObjStackFrame())
|
||||
if (StackFrame *fp = callobj.maybeStackFrame())
|
||||
*vp = fp->formalArg(i);
|
||||
else
|
||||
*vp = obj->callObjArg(i);
|
||||
*vp = callobj.arg(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
SetCallArg(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
||||
{
|
||||
CallObject &callobj = obj->asCall();
|
||||
JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
|
||||
uintN i = (uint16) JSID_TO_INT(id);
|
||||
|
||||
if (StackFrame *fp = obj->maybeCallObjStackFrame())
|
||||
if (StackFrame *fp = callobj.maybeStackFrame())
|
||||
fp->formalArg(i) = *vp;
|
||||
else
|
||||
obj->setCallObjArg(i, *vp);
|
||||
callobj.setArg(i, *vp);
|
||||
|
||||
JSFunction *fun = obj->getCallObjCalleeFunction();
|
||||
JSFunction *fun = callobj.getCalleeFunction();
|
||||
JSScript *script = fun->script();
|
||||
if (!script->ensureHasTypes(cx, fun))
|
||||
return false;
|
||||
@ -1062,40 +1010,43 @@ SetCallArg(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
||||
JSBool
|
||||
GetCallUpvar(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
{
|
||||
CallObject &callobj = obj->asCall();
|
||||
JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
|
||||
uintN i = (uint16) JSID_TO_INT(id);
|
||||
|
||||
*vp = obj->getCallObjCallee()->getFlatClosureUpvar(i);
|
||||
*vp = callobj.getCallee()->getFlatClosureUpvar(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
SetCallUpvar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
||||
{
|
||||
CallObject &callobj = obj->asCall();
|
||||
JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
|
||||
uintN i = (uint16) JSID_TO_INT(id);
|
||||
|
||||
obj->getCallObjCallee()->setFlatClosureUpvar(i, *vp);
|
||||
callobj.getCallee()->setFlatClosureUpvar(i, *vp);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
GetCallVar(JSContext *cx, JSObject *obj, jsid id, Value *vp)
|
||||
{
|
||||
CallObject &callobj = obj->asCall();
|
||||
JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
|
||||
uintN i = (uint16) JSID_TO_INT(id);
|
||||
|
||||
if (StackFrame *fp = obj->maybeCallObjStackFrame())
|
||||
if (StackFrame *fp = callobj.maybeStackFrame())
|
||||
*vp = fp->varSlot(i);
|
||||
else
|
||||
*vp = obj->callObjVar(i);
|
||||
*vp = callobj.var(i);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
SetCallVar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
||||
{
|
||||
JS_ASSERT(obj->isCall());
|
||||
CallObject &callobj = obj->asCall();
|
||||
|
||||
JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id));
|
||||
uintN i = (uint16) JSID_TO_INT(id);
|
||||
@ -1115,12 +1066,12 @@ SetCallVar(JSContext *cx, JSObject *obj, jsid id, JSBool strict, Value *vp)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (StackFrame *fp = obj->maybeCallObjStackFrame())
|
||||
if (StackFrame *fp = callobj.maybeStackFrame())
|
||||
fp->varSlot(i) = *vp;
|
||||
else
|
||||
obj->setCallObjVar(i, *vp);
|
||||
callobj.setVar(i, *vp);
|
||||
|
||||
JSFunction *fun = obj->getCallObjCalleeFunction();
|
||||
JSFunction *fun = callobj.getCalleeFunction();
|
||||
JSScript *script = fun->script();
|
||||
if (!script->ensureHasTypes(cx, fun))
|
||||
return false;
|
||||
@ -1153,16 +1104,14 @@ JS_DEFINE_CALLINFO_4(extern, BOOL, js_SetCallVar, CONTEXT, OBJECT, JSID, VALUE,
|
||||
#endif
|
||||
|
||||
static JSBool
|
||||
call_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
||||
JSObject **objp)
|
||||
call_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp)
|
||||
{
|
||||
JS_ASSERT(obj->isCall());
|
||||
JS_ASSERT(!obj->getProto());
|
||||
|
||||
if (!JSID_IS_ATOM(id))
|
||||
return true;
|
||||
|
||||
JSObject *callee = obj->getCallObjCallee();
|
||||
JSObject *callee = obj->asCall().getCallee();
|
||||
#ifdef DEBUG
|
||||
if (callee) {
|
||||
JSScript *script = callee->getFunctionPrivate()->script();
|
||||
@ -1204,7 +1153,7 @@ call_trace(JSTracer *trc, JSObject *obj)
|
||||
JS_PUBLIC_DATA(Class) js::CallClass = {
|
||||
"Call",
|
||||
JSCLASS_HAS_PRIVATE |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(JSObject::CALL_RESERVED_SLOTS) |
|
||||
JSCLASS_HAS_RESERVED_SLOTS(CallObject::RESERVED_SLOTS) |
|
||||
JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS,
|
||||
PropertyStub, /* addProperty */
|
||||
PropertyStub, /* delProperty */
|
||||
|
@ -503,10 +503,10 @@ js_PutCallObjectOnTrace(JSObject *scopeChain, uint32 nargs, js::Value *argv,
|
||||
|
||||
namespace js {
|
||||
|
||||
JSObject *
|
||||
CallObject *
|
||||
CreateFunCallObject(JSContext *cx, StackFrame *fp);
|
||||
|
||||
JSObject *
|
||||
CallObject *
|
||||
CreateEvalCallObject(JSContext *cx, StackFrame *fp);
|
||||
|
||||
extern JSBool
|
||||
|
@ -95,6 +95,7 @@
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
#include "vm/String-inl.h"
|
||||
#include "vm/CallObject-inl.h"
|
||||
|
||||
#ifdef MOZ_VALGRIND
|
||||
# define JS_VALGRIND
|
||||
|
@ -5055,8 +5055,8 @@ TypeScript::SetScope(JSContext *cx, JSScript *script, JSObject *scope)
|
||||
* The scope object must be the initial one for the script, before any call
|
||||
* object has been created in the heavyweight case.
|
||||
*/
|
||||
JS_ASSERT_IF(scope && scope->isCall() && !scope->callIsForEval(),
|
||||
scope->getCallObjCalleeFunction() != fun);
|
||||
JS_ASSERT_IF(scope && scope->isCall() && !scope->asCall().isForEval(),
|
||||
scope->asCall().getCalleeFunction() != fun);
|
||||
|
||||
if (!script->compileAndGo) {
|
||||
script->types->global = NULL;
|
||||
@ -5089,11 +5089,13 @@ TypeScript::SetScope(JSContext *cx, JSScript *script, JSObject *scope)
|
||||
while (!scope->isCall())
|
||||
scope = scope->getParent();
|
||||
|
||||
CallObject &call = scope->asCall();
|
||||
|
||||
/* The isInnerFunction test ensures there is no intervening strict eval call object. */
|
||||
JS_ASSERT(!scope->callIsForEval());
|
||||
JS_ASSERT(!call.isForEval());
|
||||
|
||||
/* Don't track non-heavyweight parents, NAME ops won't reach into them. */
|
||||
JSFunction *parentFun = scope->getCallObjCalleeFunction();
|
||||
JSFunction *parentFun = call.getCalleeFunction();
|
||||
if (!parentFun || !parentFun->isHeavyweight())
|
||||
return true;
|
||||
JSScript *parent = parentFun->script();
|
||||
@ -5121,8 +5123,8 @@ TypeScript::SetScope(JSContext *cx, JSScript *script, JSObject *scope)
|
||||
if (!SetScope(cx, parent, scope->getParent()))
|
||||
return false;
|
||||
parent->nesting()->activeCall = scope;
|
||||
parent->nesting()->argArray = scope->callObjArgArray();
|
||||
parent->nesting()->varArray = scope->callObjVarArray();
|
||||
parent->nesting()->argArray = call.argArray();
|
||||
parent->nesting()->varArray = call.varArray();
|
||||
}
|
||||
|
||||
JS_ASSERT(!script->types->nesting);
|
||||
@ -5212,7 +5214,7 @@ CheckNestingParent(JSContext *cx, JSObject *scope, JSScript *script)
|
||||
JSScript *parent = script->nesting()->parent;
|
||||
JS_ASSERT(parent);
|
||||
|
||||
while (!scope->isCall() || scope->getCallObjCalleeFunction()->script() != parent)
|
||||
while (!scope->isCall() || scope->asCall().getCalleeFunction()->script() != parent)
|
||||
scope = scope->getParent();
|
||||
|
||||
if (scope != parent->nesting()->activeCall) {
|
||||
|
@ -55,7 +55,7 @@ namespace js {
|
||||
namespace analyze {
|
||||
class ScriptAnalysis;
|
||||
}
|
||||
struct GlobalObject;
|
||||
class GlobalObject;
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
@ -3900,7 +3900,7 @@ BEGIN_CASE(JSOP_GETELEM)
|
||||
if (arg < argsobj->initialLength()) {
|
||||
copyFrom = &argsobj->element(arg);
|
||||
if (!copyFrom->isMagic(JS_ARGS_HOLE)) {
|
||||
if (StackFrame *afp = reinterpret_cast<StackFrame *>(argsobj->getPrivate()))
|
||||
if (StackFrame *afp = argsobj->maybeStackFrame())
|
||||
copyFrom = &afp->canonicalActualArg(arg);
|
||||
goto end_getelem;
|
||||
}
|
||||
|
@ -4491,7 +4491,7 @@ JSObject::growSlots(JSContext *cx, size_t newcap)
|
||||
* stack (and an eval, DEFFUN, etc. happens). We thus do not need to
|
||||
* worry about updating any active outer function args/vars.
|
||||
*/
|
||||
JS_ASSERT_IF(isCall(), maybeCallObjStackFrame() != NULL);
|
||||
JS_ASSERT_IF(isCall(), asCall().maybeStackFrame() != NULL);
|
||||
|
||||
/*
|
||||
* When an object with CAPACITY_DOUBLING_MAX or fewer slots needs to
|
||||
|
@ -66,6 +66,7 @@ namespace js {
|
||||
class AutoPropDescArrayRooter;
|
||||
class JSProxyHandler;
|
||||
class RegExp;
|
||||
class CallObject;
|
||||
struct GCMarker;
|
||||
struct NativeIterator;
|
||||
|
||||
@ -733,6 +734,8 @@ struct JSObject : js::gc::Cell {
|
||||
|
||||
private:
|
||||
inline js::Value* fixedSlots() const;
|
||||
|
||||
protected:
|
||||
inline bool hasContiguousSlots(size_t start, size_t count) const;
|
||||
|
||||
public:
|
||||
@ -1065,58 +1068,10 @@ struct JSObject : js::gc::Cell {
|
||||
inline js::NormalArgumentsObject *asNormalArguments();
|
||||
inline js::StrictArgumentsObject *asStrictArguments();
|
||||
|
||||
private:
|
||||
/*
|
||||
* Reserved slot structure for Call objects:
|
||||
*
|
||||
* private - the stack frame corresponding to the Call object
|
||||
* until js_PutCallObject or its on-trace analog
|
||||
* is called, null thereafter
|
||||
* JSSLOT_CALL_CALLEE - callee function for the stack frame, or null if
|
||||
* the stack frame is for strict mode eval code
|
||||
* JSSLOT_CALL_ARGUMENTS - arguments object for non-strict mode eval stack
|
||||
* frames (not valid for strict mode eval frames)
|
||||
*/
|
||||
static const uint32 JSSLOT_CALL_CALLEE = 0;
|
||||
static const uint32 JSSLOT_CALL_ARGUMENTS = 1;
|
||||
public:
|
||||
inline js::CallObject &asCall();
|
||||
|
||||
public:
|
||||
/* Number of reserved slots. */
|
||||
static const uint32 CALL_RESERVED_SLOTS = 2;
|
||||
|
||||
/* True if this is for a strict mode eval frame or for a function call. */
|
||||
inline bool callIsForEval() const;
|
||||
|
||||
/* The stack frame for this Call object, if the frame is still active. */
|
||||
inline js::StackFrame *maybeCallObjStackFrame() const;
|
||||
|
||||
/*
|
||||
* The callee function if this Call object was created for a function
|
||||
* invocation, or null if it was created for a strict mode eval frame.
|
||||
*/
|
||||
inline JSObject *getCallObjCallee() const;
|
||||
inline JSFunction *getCallObjCalleeFunction() const;
|
||||
inline void setCallObjCallee(JSObject *callee);
|
||||
|
||||
inline const js::Value &getCallObjArguments() const;
|
||||
inline void setCallObjArguments(const js::Value &v);
|
||||
|
||||
/* Returns the formal argument at the given index. */
|
||||
inline const js::Value &callObjArg(uintN i) const;
|
||||
inline void setCallObjArg(uintN i, const js::Value &v);
|
||||
|
||||
/* Returns the variable at the given index. */
|
||||
inline const js::Value &callObjVar(uintN i) const;
|
||||
inline void setCallObjVar(uintN i, const js::Value &v);
|
||||
|
||||
/*
|
||||
* Get the actual arrays of arguments and variables. Only call if type
|
||||
* inference is enabled, where we ensure that call object variables are in
|
||||
* contiguous slots (see NewCallObject).
|
||||
*/
|
||||
inline js::Value *callObjArgArray();
|
||||
inline js::Value *callObjVarArray();
|
||||
|
||||
/*
|
||||
* Date-specific getters and setters.
|
||||
*/
|
||||
@ -1926,10 +1881,7 @@ IsCacheableNonGlobalScope(JSObject *obj)
|
||||
{
|
||||
JS_ASSERT(obj->getParent());
|
||||
|
||||
js::Class *clasp = obj->getClass();
|
||||
bool cacheable = (clasp == &CallClass ||
|
||||
clasp == &BlockClass ||
|
||||
clasp == &DeclEnvClass);
|
||||
bool cacheable = (obj->isCall() || obj->isBlock() || obj->isDeclEnv());
|
||||
|
||||
JS_ASSERT_IF(cacheable, !obj->getOps()->lookupProperty);
|
||||
return cacheable;
|
||||
|
@ -540,112 +540,6 @@ JSObject::denseArrayHasInlineSlots() const
|
||||
return slots == fixedSlots();
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSObject::callIsForEval() const
|
||||
{
|
||||
JS_ASSERT(isCall());
|
||||
JS_ASSERT(getFixedSlot(JSSLOT_CALL_CALLEE).isObjectOrNull());
|
||||
JS_ASSERT_IF(getFixedSlot(JSSLOT_CALL_CALLEE).isObject(),
|
||||
getFixedSlot(JSSLOT_CALL_CALLEE).toObject().isFunction());
|
||||
return getFixedSlot(JSSLOT_CALL_CALLEE).isNull();
|
||||
}
|
||||
|
||||
inline js::StackFrame *
|
||||
JSObject::maybeCallObjStackFrame() const
|
||||
{
|
||||
JS_ASSERT(isCall());
|
||||
return reinterpret_cast<js::StackFrame *>(getPrivate());
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setCallObjCallee(JSObject *callee)
|
||||
{
|
||||
JS_ASSERT(isCall());
|
||||
JS_ASSERT_IF(callee, callee->isFunction());
|
||||
setFixedSlot(JSSLOT_CALL_CALLEE, js::ObjectOrNullValue(callee));
|
||||
}
|
||||
|
||||
inline JSObject *
|
||||
JSObject::getCallObjCallee() const
|
||||
{
|
||||
JS_ASSERT(isCall());
|
||||
return getFixedSlot(JSSLOT_CALL_CALLEE).toObjectOrNull();
|
||||
}
|
||||
|
||||
inline JSFunction *
|
||||
JSObject::getCallObjCalleeFunction() const
|
||||
{
|
||||
JS_ASSERT(isCall());
|
||||
return getFixedSlot(JSSLOT_CALL_CALLEE).toObject().getFunctionPrivate();
|
||||
}
|
||||
|
||||
inline const js::Value &
|
||||
JSObject::getCallObjArguments() const
|
||||
{
|
||||
JS_ASSERT(isCall());
|
||||
JS_ASSERT(!callIsForEval());
|
||||
return getFixedSlot(JSSLOT_CALL_ARGUMENTS);
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setCallObjArguments(const js::Value &v)
|
||||
{
|
||||
JS_ASSERT(isCall());
|
||||
JS_ASSERT(!callIsForEval());
|
||||
setFixedSlot(JSSLOT_CALL_ARGUMENTS, v);
|
||||
}
|
||||
|
||||
inline const js::Value &
|
||||
JSObject::callObjArg(uintN i) const
|
||||
{
|
||||
JS_ASSERT(isCall());
|
||||
JS_ASSERT(i < getCallObjCalleeFunction()->nargs);
|
||||
return getSlot(JSObject::CALL_RESERVED_SLOTS + i);
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setCallObjArg(uintN i, const js::Value &v)
|
||||
{
|
||||
JS_ASSERT(isCall());
|
||||
JS_ASSERT(i < getCallObjCalleeFunction()->nargs);
|
||||
setSlot(JSObject::CALL_RESERVED_SLOTS + i, v);
|
||||
}
|
||||
|
||||
inline js::Value *
|
||||
JSObject::callObjArgArray()
|
||||
{
|
||||
js::DebugOnly<JSFunction*> fun = getCallObjCalleeFunction();
|
||||
JS_ASSERT(hasContiguousSlots(JSObject::CALL_RESERVED_SLOTS, fun->nargs));
|
||||
return getSlotAddress(JSObject::CALL_RESERVED_SLOTS);
|
||||
}
|
||||
|
||||
inline const js::Value &
|
||||
JSObject::callObjVar(uintN i) const
|
||||
{
|
||||
JSFunction *fun = getCallObjCalleeFunction();
|
||||
JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
|
||||
JS_ASSERT(i < fun->script()->bindings.countVars());
|
||||
return getSlot(JSObject::CALL_RESERVED_SLOTS + fun->nargs + i);
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setCallObjVar(uintN i, const js::Value &v)
|
||||
{
|
||||
JSFunction *fun = getCallObjCalleeFunction();
|
||||
JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
|
||||
JS_ASSERT(i < fun->script()->bindings.countVars());
|
||||
setSlot(JSObject::CALL_RESERVED_SLOTS + fun->nargs + i, v);
|
||||
}
|
||||
|
||||
inline js::Value *
|
||||
JSObject::callObjVarArray()
|
||||
{
|
||||
JSFunction *fun = getCallObjCalleeFunction();
|
||||
JS_ASSERT(hasContiguousSlots(JSObject::CALL_RESERVED_SLOTS + fun->nargs,
|
||||
fun->script()->bindings.countVars()));
|
||||
return getSlotAddress(JSObject::CALL_RESERVED_SLOTS + fun->nargs);
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
|
@ -120,7 +120,7 @@ Bindings::add(JSContext *cx, JSAtom *name, BindingKind kind)
|
||||
uint16 *indexp;
|
||||
PropertyOp getter;
|
||||
StrictPropertyOp setter;
|
||||
uint32 slot = JSObject::CALL_RESERVED_SLOTS;
|
||||
uint32 slot = CallObject::RESERVED_SLOTS;
|
||||
|
||||
if (kind == ARGUMENT) {
|
||||
JS_ASSERT(nvars == 0);
|
||||
|
@ -93,6 +93,7 @@
|
||||
#include "jsopcodeinlines.h"
|
||||
#include "jstypedarrayinlines.h"
|
||||
|
||||
#include "vm/CallObject-inl.h"
|
||||
#include "vm/Stack-inl.h"
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
@ -3286,9 +3287,9 @@ public:
|
||||
JS_ASSERT_IF(fp->hasArgsObj(), frameobj == &fp->argsObj());
|
||||
fp->setArgsObj(*frameobj->asArguments());
|
||||
if (frameobj->isNormalArguments())
|
||||
frameobj->setPrivate(fp);
|
||||
frameobj->asArguments()->setStackFrame(fp);
|
||||
else
|
||||
JS_ASSERT(!frameobj->getPrivate());
|
||||
JS_ASSERT(!frameobj->asArguments()->maybeStackFrame());
|
||||
debug_only_printf(LC_TMTracer,
|
||||
"argsobj<%p> ",
|
||||
(void *)frameobj);
|
||||
@ -3301,12 +3302,12 @@ public:
|
||||
} else {
|
||||
JS_ASSERT(p == fp->addressOfScopeChain());
|
||||
if (frameobj->isCall() &&
|
||||
!frameobj->getPrivate() &&
|
||||
fp->maybeCalleev().toObjectOrNull() == frameobj->getCallObjCallee())
|
||||
!frameobj->asCall().maybeStackFrame() &&
|
||||
fp->maybeCalleev().toObjectOrNull() == frameobj->asCall().getCallee())
|
||||
{
|
||||
JS_ASSERT(&fp->scopeChain() == StackFrame::sInvalidScopeChain);
|
||||
frameobj->setPrivate(fp);
|
||||
fp->setScopeChainWithOwnCallObj(*frameobj);
|
||||
frameobj->asCall().setStackFrame(fp);
|
||||
fp->setScopeChainWithOwnCallObj(frameobj->asCall());
|
||||
} else {
|
||||
fp->setScopeChainNoCallObj(*frameobj);
|
||||
}
|
||||
@ -3539,7 +3540,7 @@ GetFromClosure(JSContext* cx, JSObject* call, const ClosureVarInfo* cv, double*
|
||||
|
||||
// We already guarded on trace that we aren't touching an outer tree's entry frame
|
||||
VOUCH_DOES_NOT_REQUIRE_STACK();
|
||||
StackFrame* fp = (StackFrame*) call->getPrivate();
|
||||
StackFrame* fp = call->asCall().maybeStackFrame();
|
||||
JS_ASSERT(fp != cx->fp());
|
||||
|
||||
Value v;
|
||||
@ -3577,12 +3578,12 @@ struct ArgClosureTraits
|
||||
|
||||
// Get the offset of our object slots from the object's slots pointer.
|
||||
static inline uint32 slot_offset(JSObject* obj) {
|
||||
return JSObject::CALL_RESERVED_SLOTS;
|
||||
return CallObject::RESERVED_SLOTS;
|
||||
}
|
||||
|
||||
// Get the maximum slot index of this type that should be allowed
|
||||
static inline uint16 slot_count(JSObject* obj) {
|
||||
return obj->getCallObjCalleeFunction()->nargs;
|
||||
return obj->asCall().getCalleeFunction()->nargs;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -3608,12 +3609,12 @@ struct VarClosureTraits
|
||||
}
|
||||
|
||||
static inline uint32 slot_offset(JSObject* obj) {
|
||||
return JSObject::CALL_RESERVED_SLOTS +
|
||||
obj->getCallObjCalleeFunction()->nargs;
|
||||
return CallObject::RESERVED_SLOTS +
|
||||
obj->asCall().getCalleeFunction()->nargs;
|
||||
}
|
||||
|
||||
static inline uint16 slot_count(JSObject* obj) {
|
||||
return obj->getCallObjCalleeFunction()->script()->bindings.countVars();
|
||||
return obj->asCall().getCalleeFunction()->script()->bindings.countVars();
|
||||
}
|
||||
|
||||
private:
|
||||
@ -8149,9 +8150,10 @@ TraceRecorder::entryFrameIns() const
|
||||
* filled in with the depth of the call object's frame relevant to cx->fp().
|
||||
*/
|
||||
JS_REQUIRES_STACK StackFrame*
|
||||
TraceRecorder::frameIfInRange(JSObject* obj, unsigned* depthp) const
|
||||
TraceRecorder::frameIfInRange(JSObject *obj, unsigned* depthp) const
|
||||
{
|
||||
StackFrame* ofp = (StackFrame*) obj->getPrivate();
|
||||
JS_ASSERT(obj->isCall() || obj->isArguments());
|
||||
StackFrame* ofp = (StackFrame *) obj->getPrivate();
|
||||
StackFrame* fp = cx->fp();
|
||||
for (unsigned depth = 0; depth <= callDepth; ++depth) {
|
||||
if (fp == ofp) {
|
||||
@ -8264,7 +8266,8 @@ TraceRecorder::callProp(JSObject* obj, JSProperty* prop, jsid id, const Value*&
|
||||
uintN slot = uint16(shape->shortid);
|
||||
|
||||
vp = NULL;
|
||||
StackFrame* cfp = (StackFrame*) obj->getPrivate();
|
||||
CallObject &callobj = obj->asCall();
|
||||
StackFrame* cfp = callobj.maybeStackFrame();
|
||||
if (cfp) {
|
||||
if (shape->getterOp() == GetCallArg) {
|
||||
JS_ASSERT(slot < cfp->numFormalArgs());
|
||||
@ -8281,7 +8284,7 @@ TraceRecorder::callProp(JSObject* obj, JSProperty* prop, jsid id, const Value*&
|
||||
// Now assert that our use of shape->shortid was in fact kosher.
|
||||
JS_ASSERT(shape->hasShortID());
|
||||
|
||||
if (frameIfInRange(obj)) {
|
||||
if (frameIfInRange(&callobj)) {
|
||||
// At this point we are guaranteed to be looking at an active call oject
|
||||
// whose properties are stored in the corresponding StackFrame.
|
||||
ins = get(vp);
|
||||
@ -12299,11 +12302,13 @@ TraceRecorder::setUpwardTrackedVar(Value* stackVp, const Value &v, LIns* v_ins)
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK RecordingStatus
|
||||
TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, const Shape *shape,
|
||||
TraceRecorder::setCallProp(JSObject *obj, LIns *callobj_ins, const Shape *shape,
|
||||
LIns *v_ins, const Value &v)
|
||||
{
|
||||
CallObject &callobj = obj->asCall();
|
||||
|
||||
// Set variables in on-trace-stack call objects by updating the tracker.
|
||||
StackFrame *fp = frameIfInRange(callobj);
|
||||
StackFrame *fp = frameIfInRange(&callobj);
|
||||
if (fp) {
|
||||
if (shape->setterOp() == SetCallArg) {
|
||||
JS_ASSERT(shape->hasShortID());
|
||||
@ -12322,7 +12327,7 @@ TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, const Shape *sh
|
||||
RETURN_STOP("can't trace special CallClass setter");
|
||||
}
|
||||
|
||||
if (!callobj->getPrivate()) {
|
||||
if (!callobj.maybeStackFrame()) {
|
||||
// Because the parent guard in guardCallee ensures this Call object
|
||||
// will be the same object now and on trace, and because once a Call
|
||||
// object loses its frame it never regains one, on trace we will also
|
||||
@ -12330,11 +12335,11 @@ TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, const Shape *sh
|
||||
// write the value to the Call object's slot.
|
||||
intN slot = uint16(shape->shortid);
|
||||
if (shape->setterOp() == SetCallArg) {
|
||||
JS_ASSERT(slot < ArgClosureTraits::slot_count(callobj));
|
||||
slot += ArgClosureTraits::slot_offset(callobj);
|
||||
JS_ASSERT(slot < ArgClosureTraits::slot_count(&callobj));
|
||||
slot += ArgClosureTraits::slot_offset(obj);
|
||||
} else if (shape->setterOp() == SetCallVar) {
|
||||
JS_ASSERT(slot < VarClosureTraits::slot_count(callobj));
|
||||
slot += VarClosureTraits::slot_offset(callobj);
|
||||
JS_ASSERT(slot < VarClosureTraits::slot_count(&callobj));
|
||||
slot += VarClosureTraits::slot_offset(obj);
|
||||
} else {
|
||||
RETURN_STOP("can't trace special CallClass setter");
|
||||
}
|
||||
@ -12345,7 +12350,7 @@ TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, const Shape *sh
|
||||
JS_ASSERT(shape->hasShortID());
|
||||
|
||||
LIns* slots_ins = NULL;
|
||||
stobj_set_slot(callobj, callobj_ins, slot, slots_ins, v, v_ins);
|
||||
stobj_set_slot(&callobj, callobj_ins, slot, slots_ins, v, v_ins);
|
||||
return RECORD_CONTINUE;
|
||||
}
|
||||
|
||||
@ -14997,7 +15002,7 @@ static inline bool
|
||||
IsFindableCallObj(JSObject *obj)
|
||||
{
|
||||
return obj->isCall() &&
|
||||
(obj->callIsForEval() || obj->getCallObjCalleeFunction()->isHeavyweight());
|
||||
(obj->asCall().isForEval() || obj->asCall().getCalleeFunction()->isHeavyweight());
|
||||
}
|
||||
|
||||
/*
|
||||
@ -15134,8 +15139,7 @@ TraceRecorder::record_JSOP_BINDNAME()
|
||||
* it. For now just don't trace this case.
|
||||
*/
|
||||
if (obj != globalObj) {
|
||||
JS_ASSERT(obj->isCall());
|
||||
JS_ASSERT(obj->callIsForEval());
|
||||
JS_ASSERT(obj->asCall().isForEval());
|
||||
RETURN_STOP_A("BINDNAME within strict eval code");
|
||||
}
|
||||
|
||||
|
@ -1272,7 +1272,7 @@ class TraceRecorder
|
||||
JS_REQUIRES_STACK nanojit::LIns* scopeChain();
|
||||
JS_REQUIRES_STACK nanojit::LIns* entryScopeChain() const;
|
||||
JS_REQUIRES_STACK nanojit::LIns* entryFrameIns() const;
|
||||
JS_REQUIRES_STACK StackFrame* frameIfInRange(JSObject* obj, unsigned* depthp = NULL) const;
|
||||
JS_REQUIRES_STACK StackFrame* frameIfInRange(JSObject *obj, unsigned* depthp = NULL) const;
|
||||
JS_REQUIRES_STACK RecordingStatus traverseScopeChain(JSObject *obj, nanojit::LIns *obj_ins, JSObject *obj2, nanojit::LIns *&obj2_ins);
|
||||
JS_REQUIRES_STACK AbortableRecordingStatus scopeChainProp(JSObject* obj, const Value*& vp, nanojit::LIns*& ins, NameResult& nr, JSObject **scopeObjp = NULL);
|
||||
JS_REQUIRES_STACK RecordingStatus callProp(JSObject* obj, JSProperty* shape, jsid id, const Value*& vp, nanojit::LIns*& ins, NameResult& nr);
|
||||
|
@ -54,6 +54,8 @@
|
||||
#include "jsinterpinlines.h"
|
||||
#include "jsautooplen.h"
|
||||
|
||||
#include "vm/CallObject-inl.h"
|
||||
|
||||
#if defined JS_POLYIC
|
||||
|
||||
using namespace js;
|
||||
@ -421,7 +423,7 @@ class SetPropCompiler : public PICStubCompiler
|
||||
// \\ V and getters, and
|
||||
// \===/ 2. arguments and locals have different getters
|
||||
// then we can rely on fun->nargs remaining invariant.
|
||||
JSFunction *fun = obj->getCallObjCalleeFunction();
|
||||
JSFunction *fun = obj->asCall().getCalleeFunction();
|
||||
uint16 slot = uint16(shape->shortid);
|
||||
|
||||
/* Guard that the call object has a frame. */
|
||||
@ -441,7 +443,7 @@ class SetPropCompiler : public PICStubCompiler
|
||||
if (shape->setterOp() == SetCallVar)
|
||||
slot += fun->nargs;
|
||||
|
||||
slot += JSObject::CALL_RESERVED_SLOTS;
|
||||
slot += CallObject::RESERVED_SLOTS;
|
||||
Address address = masm.objPropAddress(obj, pic.objReg, slot);
|
||||
|
||||
masm.storeValue(pic.u.vr, address);
|
||||
@ -691,7 +693,7 @@ class SetPropCompiler : public PICStubCompiler
|
||||
* objects may differ due to eval(), DEFFUN, etc.).
|
||||
*/
|
||||
RecompilationMonitor monitor(cx);
|
||||
JSFunction *fun = obj->getCallObjCalleeFunction();
|
||||
JSFunction *fun = obj->asCall().getCalleeFunction();
|
||||
JSScript *script = fun->script();
|
||||
uint16 slot = uint16(shape->shortid);
|
||||
if (!script->ensureHasTypes(cx, fun))
|
||||
@ -1504,7 +1506,7 @@ class ScopeNameCompiler : public PICStubCompiler
|
||||
/* Get callobj's stack frame. */
|
||||
masm.loadObjPrivate(pic.objReg, pic.shapeReg);
|
||||
|
||||
JSFunction *fun = getprop.holder->getCallObjCalleeFunction();
|
||||
JSFunction *fun = getprop.holder->asCall().getCalleeFunction();
|
||||
uint16 slot = uint16(shape->shortid);
|
||||
|
||||
Jump skipOver;
|
||||
@ -1525,7 +1527,7 @@ class ScopeNameCompiler : public PICStubCompiler
|
||||
if (kind == VAR)
|
||||
slot += fun->nargs;
|
||||
|
||||
slot += JSObject::CALL_RESERVED_SLOTS;
|
||||
slot += CallObject::RESERVED_SLOTS;
|
||||
Address address = masm.objPropAddress(obj, pic.objReg, slot);
|
||||
|
||||
/* Safe because type is loaded first. */
|
||||
|
@ -482,7 +482,7 @@ stubs::GetElem(VMFrame &f)
|
||||
if (arg < argsobj->initialLength()) {
|
||||
copyFrom = &argsobj->element(arg);
|
||||
if (!copyFrom->isMagic()) {
|
||||
if (StackFrame *afp = (StackFrame *) argsobj->getPrivate())
|
||||
if (StackFrame *afp = argsobj->maybeStackFrame())
|
||||
copyFrom = &afp->canonicalActualArg(arg);
|
||||
goto end_getelem;
|
||||
}
|
||||
|
@ -110,6 +110,37 @@ ArgumentsObject::setElement(uint32 i, const js::Value &v)
|
||||
data()->slots[i] = v;
|
||||
}
|
||||
|
||||
inline js::StackFrame *
|
||||
ArgumentsObject::maybeStackFrame() const
|
||||
{
|
||||
return reinterpret_cast<js::StackFrame *>(getPrivate());
|
||||
}
|
||||
|
||||
inline void
|
||||
ArgumentsObject::setStackFrame(StackFrame *frame)
|
||||
{
|
||||
return setPrivate(frame);
|
||||
}
|
||||
|
||||
#define JS_ARGUMENTS_OBJECT_ON_TRACE ((void *)0xa126)
|
||||
inline bool
|
||||
ArgumentsObject::onTrace() const
|
||||
{
|
||||
return getPrivate() == JS_ARGUMENTS_OBJECT_ON_TRACE;
|
||||
}
|
||||
|
||||
inline void
|
||||
ArgumentsObject::setOnTrace()
|
||||
{
|
||||
return setPrivate(JS_ARGUMENTS_OBJECT_ON_TRACE);
|
||||
}
|
||||
|
||||
inline void
|
||||
ArgumentsObject::clearOnTrace()
|
||||
{
|
||||
return setPrivate(NULL);
|
||||
}
|
||||
|
||||
inline const js::Value &
|
||||
NormalArgumentsObject::callee() const
|
||||
{
|
||||
|
@ -47,8 +47,6 @@
|
||||
class GetPropCompiler;
|
||||
#endif
|
||||
|
||||
#define JS_ARGUMENTS_OBJECT_ON_TRACE ((void *)0xa126)
|
||||
|
||||
#ifdef JS_TRACER
|
||||
namespace nanojit {
|
||||
class ValidateWriter;
|
||||
@ -229,6 +227,14 @@ class ArgumentsObject : public ::JSObject
|
||||
inline const js::Value &element(uint32 i) const;
|
||||
inline const js::Value *elements() const;
|
||||
inline void setElement(uint32 i, const js::Value &v);
|
||||
|
||||
/* The stack frame for this ArgumentsObject, if the frame is still active. */
|
||||
inline js::StackFrame *maybeStackFrame() const;
|
||||
inline void setStackFrame(js::StackFrame *frame);
|
||||
|
||||
inline bool onTrace() const;
|
||||
inline void setOnTrace();
|
||||
inline void clearOnTrace();
|
||||
};
|
||||
|
||||
/*
|
||||
|
161
js/src/vm/CallObject-inl.h
Normal file
@ -0,0 +1,161 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=78:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is SpiderMonkey call object code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Paul Biggar <pbiggar@mozilla.com> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef CallObject_inl_h___
|
||||
#define CallObject_inl_h___
|
||||
|
||||
#include "CallObject.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
inline bool
|
||||
CallObject::isForEval() const
|
||||
{
|
||||
JS_ASSERT(getFixedSlot(CALLEE_SLOT).isObjectOrNull());
|
||||
JS_ASSERT_IF(getFixedSlot(CALLEE_SLOT).isObject(),
|
||||
getFixedSlot(CALLEE_SLOT).toObject().isFunction());
|
||||
return getFixedSlot(CALLEE_SLOT).isNull();
|
||||
}
|
||||
|
||||
inline js::StackFrame *
|
||||
CallObject::maybeStackFrame() const
|
||||
{
|
||||
return reinterpret_cast<js::StackFrame *>(getPrivate());
|
||||
}
|
||||
|
||||
inline void
|
||||
CallObject::setStackFrame(StackFrame *frame)
|
||||
{
|
||||
return setPrivate(frame);
|
||||
}
|
||||
|
||||
inline void
|
||||
CallObject::setCallee(JSObject *callee)
|
||||
{
|
||||
JS_ASSERT_IF(callee, callee->isFunction());
|
||||
setFixedSlot(CALLEE_SLOT, js::ObjectOrNullValue(callee));
|
||||
}
|
||||
|
||||
inline JSObject *
|
||||
CallObject::getCallee() const
|
||||
{
|
||||
return getFixedSlot(CALLEE_SLOT).toObjectOrNull();
|
||||
}
|
||||
|
||||
inline JSFunction *
|
||||
CallObject::getCalleeFunction() const
|
||||
{
|
||||
return getFixedSlot(CALLEE_SLOT).toObject().getFunctionPrivate();
|
||||
}
|
||||
|
||||
inline const js::Value &
|
||||
CallObject::getArguments() const
|
||||
{
|
||||
JS_ASSERT(!isForEval());
|
||||
return getFixedSlot(ARGUMENTS_SLOT);
|
||||
}
|
||||
|
||||
inline void
|
||||
CallObject::setArguments(const js::Value &v)
|
||||
{
|
||||
JS_ASSERT(!isForEval());
|
||||
setFixedSlot(ARGUMENTS_SLOT, v);
|
||||
}
|
||||
|
||||
inline const js::Value &
|
||||
CallObject::arg(uintN i) const
|
||||
{
|
||||
JS_ASSERT(i < getCalleeFunction()->nargs);
|
||||
return getSlot(RESERVED_SLOTS + i);
|
||||
}
|
||||
|
||||
inline void
|
||||
CallObject::setArg(uintN i, const js::Value &v)
|
||||
{
|
||||
JS_ASSERT(i < getCalleeFunction()->nargs);
|
||||
setSlot(RESERVED_SLOTS + i, v);
|
||||
}
|
||||
|
||||
inline const js::Value &
|
||||
CallObject::var(uintN i) const
|
||||
{
|
||||
JSFunction *fun = getCalleeFunction();
|
||||
JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
|
||||
JS_ASSERT(i < fun->script()->bindings.countVars());
|
||||
return getSlot(RESERVED_SLOTS + fun->nargs + i);
|
||||
}
|
||||
|
||||
inline void
|
||||
CallObject::setVar(uintN i, const js::Value &v)
|
||||
{
|
||||
JSFunction *fun = getCalleeFunction();
|
||||
JS_ASSERT(fun->nargs == fun->script()->bindings.countArgs());
|
||||
JS_ASSERT(i < fun->script()->bindings.countVars());
|
||||
setSlot(RESERVED_SLOTS + fun->nargs + i, v);
|
||||
}
|
||||
|
||||
inline void
|
||||
CallObject::copyValues(uintN nargs, Value *argv, uintN nvars, Value *slots)
|
||||
{
|
||||
JS_ASSERT(numSlots() >= RESERVED_SLOTS + nargs + nvars);
|
||||
copySlotRange(RESERVED_SLOTS, argv, nargs);
|
||||
copySlotRange(RESERVED_SLOTS + nargs, slots, nvars);
|
||||
}
|
||||
|
||||
inline js::Value *
|
||||
CallObject::argArray()
|
||||
{
|
||||
js::DebugOnly<JSFunction*> fun = getCalleeFunction();
|
||||
JS_ASSERT(hasContiguousSlots(RESERVED_SLOTS, fun->nargs));
|
||||
return getSlotAddress(RESERVED_SLOTS);
|
||||
}
|
||||
|
||||
inline js::Value *
|
||||
CallObject::varArray()
|
||||
{
|
||||
JSFunction *fun = getCalleeFunction();
|
||||
JS_ASSERT(hasContiguousSlots(RESERVED_SLOTS + fun->nargs,
|
||||
fun->script()->bindings.countVars()));
|
||||
return getSlotAddress(RESERVED_SLOTS + fun->nargs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif /* CallObject_inl_h___ */
|
100
js/src/vm/CallObject.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=78:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is SpiderMonkey call object code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Paul Biggar <pbiggar@mozilla.com> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "jsobjinlines.h"
|
||||
#include "CallObject.h"
|
||||
|
||||
#include "CallObject-inl.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
* Construct a call object for the given bindings. If this is a call object
|
||||
* for a function invocation, callee should be the function being called.
|
||||
* Otherwise it must be a call object for eval of strict mode code, and callee
|
||||
* must be null.
|
||||
*/
|
||||
CallObject *
|
||||
CallObject::create(JSContext *cx, JSScript *script, JSObject &scopeChain, JSObject *callee)
|
||||
{
|
||||
Bindings &bindings = script->bindings;
|
||||
size_t argsVars = bindings.countArgsAndVars();
|
||||
size_t slots = RESERVED_SLOTS + argsVars;
|
||||
gc::AllocKind kind = gc::GetGCObjectKind(slots);
|
||||
|
||||
/*
|
||||
* Make sure that the arguments and variables in the call object all end up
|
||||
* in a contiguous range of slots. We need this to be able to embed the
|
||||
* args/vars arrays in the TypeScriptNesting for the function, after the
|
||||
* call object's frame has finished.
|
||||
*/
|
||||
if (cx->typeInferenceEnabled() && gc::GetGCKindSlots(kind) < slots) {
|
||||
kind = gc::GetGCObjectKind(RESERVED_SLOTS);
|
||||
JS_ASSERT(gc::GetGCKindSlots(kind) == RESERVED_SLOTS);
|
||||
}
|
||||
|
||||
JSObject *obj = js_NewGCObject(cx, kind);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
/* Init immediately to avoid GC seeing a half-init'ed object. */
|
||||
obj->initCall(cx, bindings, &scopeChain);
|
||||
obj->makeVarObj();
|
||||
|
||||
/* This must come after callobj->lastProp has been set. */
|
||||
if (!obj->ensureInstanceReservedSlots(cx, argsVars))
|
||||
return NULL;
|
||||
|
||||
#ifdef DEBUG
|
||||
for (Shape::Range r = obj->lastProp; !r.empty(); r.popFront()) {
|
||||
const Shape &s = r.front();
|
||||
if (s.slot != SHAPE_INVALID_SLOT) {
|
||||
JS_ASSERT(s.slot + 1 == obj->slotSpan());
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
CallObject &callobj = obj->asCall();
|
||||
callobj.setCallee(callee);
|
||||
return &callobj;
|
||||
}
|
||||
|
||||
}
|
116
js/src/vm/CallObject.h
Normal file
@ -0,0 +1,116 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=78:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is SpiderMonkey call object code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Paul Biggar <pbiggar@mozilla.com> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef CallObject_h___
|
||||
#define CallObject_h___
|
||||
|
||||
namespace js {
|
||||
|
||||
class CallObject : public ::JSObject
|
||||
{
|
||||
/*
|
||||
* Reserved slot structure for Call objects:
|
||||
*
|
||||
* private - the stack frame corresponding to the Call object
|
||||
* until js_PutCallObject or its on-trace analog
|
||||
* is called, null thereafter
|
||||
* JSSLOT_CALL_CALLEE - callee function for the stack frame, or null if
|
||||
* the stack frame is for strict mode eval code
|
||||
* JSSLOT_CALL_ARGUMENTS - arguments object for non-strict mode eval stack
|
||||
* frames (not valid for strict mode eval frames)
|
||||
*/
|
||||
static const uint32 CALLEE_SLOT = 0;
|
||||
static const uint32 ARGUMENTS_SLOT = 1;
|
||||
|
||||
public:
|
||||
/* Create a CallObject for the given callee function. */
|
||||
static CallObject *
|
||||
create(JSContext *cx, JSScript *script, JSObject &scopeChain, JSObject *callee);
|
||||
|
||||
static const uint32 RESERVED_SLOTS = 2;
|
||||
|
||||
/* True if this is for a strict mode eval frame or for a function call. */
|
||||
inline bool isForEval() const;
|
||||
|
||||
/* The stack frame for this CallObject, if the frame is still active. */
|
||||
inline js::StackFrame *maybeStackFrame() const;
|
||||
inline void setStackFrame(js::StackFrame *frame);
|
||||
|
||||
/*
|
||||
* The callee function if this CallObject was created for a function
|
||||
* invocation, or null if it was created for a strict mode eval frame.
|
||||
*/
|
||||
inline JSObject *getCallee() const;
|
||||
inline JSFunction *getCalleeFunction() const;
|
||||
inline void setCallee(JSObject *callee);
|
||||
|
||||
/* Returns the callee's arguments object. */
|
||||
inline const js::Value &getArguments() const;
|
||||
inline void setArguments(const js::Value &v);
|
||||
|
||||
/* Returns the formal argument at the given index. */
|
||||
inline const js::Value &arg(uintN i) const;
|
||||
inline void setArg(uintN i, const js::Value &v);
|
||||
|
||||
/* Returns the variable at the given index. */
|
||||
inline const js::Value &var(uintN i) const;
|
||||
inline void setVar(uintN i, const js::Value &v);
|
||||
|
||||
/*
|
||||
* Get the actual arrays of arguments and variables. Only call if type
|
||||
* inference is enabled, where we ensure that call object variables are in
|
||||
* contiguous slots (see NewCallObject).
|
||||
*/
|
||||
inline js::Value *argArray();
|
||||
inline js::Value *varArray();
|
||||
|
||||
inline void copyValues(uintN nargs, Value *argv, uintN nvars, Value *slots);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
js::CallObject &
|
||||
JSObject::asCall()
|
||||
{
|
||||
JS_ASSERT(isCall());
|
||||
return *reinterpret_cast<js::CallObject *>(this);
|
||||
}
|
||||
|
||||
#endif /* CallObject_h___ */
|
@ -48,6 +48,8 @@
|
||||
|
||||
#include "jsscriptinlines.h"
|
||||
#include "ArgumentsObject-inl.h"
|
||||
#include "CallObject-inl.h"
|
||||
|
||||
#include "methodjit/MethodJIT.h"
|
||||
|
||||
namespace js {
|
||||
@ -340,15 +342,15 @@ StackFrame::setScopeChainNoCallObj(JSObject &obj)
|
||||
}
|
||||
|
||||
inline void
|
||||
StackFrame::setScopeChainWithOwnCallObj(JSObject &obj)
|
||||
StackFrame::setScopeChainWithOwnCallObj(CallObject &obj)
|
||||
{
|
||||
JS_ASSERT(&obj != NULL);
|
||||
JS_ASSERT(!hasCallObj() && obj.isCall() && obj.getPrivate() == this);
|
||||
JS_ASSERT(!hasCallObj() && obj.maybeStackFrame() == this);
|
||||
scopeChain_ = &obj;
|
||||
flags_ |= HAS_SCOPECHAIN | HAS_CALL_OBJ;
|
||||
}
|
||||
|
||||
inline JSObject &
|
||||
inline CallObject &
|
||||
StackFrame::callObj() const
|
||||
{
|
||||
JS_ASSERT_IF(isNonEvalFunctionFrame() || isStrictEvalFrame(), hasCallObj());
|
||||
@ -358,7 +360,7 @@ StackFrame::callObj() const
|
||||
JS_ASSERT(IsCacheableNonGlobalScope(pobj) || pobj->isWith());
|
||||
pobj = pobj->getParent();
|
||||
}
|
||||
return *pobj;
|
||||
return pobj->asCall();
|
||||
}
|
||||
|
||||
inline bool
|
||||
@ -415,11 +417,11 @@ inline void
|
||||
StackFrame::markFunctionEpilogueDone(bool activationOnly)
|
||||
{
|
||||
if (flags_ & (HAS_ARGS_OBJ | HAS_CALL_OBJ)) {
|
||||
if (hasArgsObj() && !argsObj().getPrivate()) {
|
||||
if (hasArgsObj() && !argsObj().maybeStackFrame()) {
|
||||
args.nactual = args.obj->initialLength();
|
||||
flags_ &= ~HAS_ARGS_OBJ;
|
||||
}
|
||||
if (hasCallObj() && !callObj().getPrivate()) {
|
||||
if (hasCallObj() && !callObj().maybeStackFrame()) {
|
||||
/*
|
||||
* For function frames, the call object may or may not have have an
|
||||
* enclosing DeclEnv object, so we use the callee's parent, since
|
||||
@ -687,8 +689,7 @@ ArgumentsObject::getElement(uint32 i, Value *vp)
|
||||
* If this arguments object was created on trace the actual argument value
|
||||
* could be in a register or something, so we can't optimize.
|
||||
*/
|
||||
StackFrame *fp = reinterpret_cast<StackFrame *>(getPrivate());
|
||||
if (fp == JS_ARGUMENTS_OBJECT_ON_TRACE)
|
||||
if (onTrace())
|
||||
return false;
|
||||
|
||||
/*
|
||||
@ -696,6 +697,7 @@ ArgumentsObject::getElement(uint32 i, Value *vp)
|
||||
* the canonical argument value. Note that strict arguments objects do not
|
||||
* alias named arguments and never have a stack frame.
|
||||
*/
|
||||
StackFrame *fp = maybeStackFrame();
|
||||
JS_ASSERT_IF(isStrictArguments(), !fp);
|
||||
if (fp)
|
||||
*vp = fp->canonicalActualArg(i);
|
||||
@ -711,7 +713,7 @@ ArgumentsObject::getElements(uint32 start, uint32 count, Value *vp)
|
||||
if (start > length || start + count > length)
|
||||
return false;
|
||||
|
||||
StackFrame *fp = reinterpret_cast<StackFrame *>(getPrivate());
|
||||
StackFrame *fp = maybeStackFrame();
|
||||
|
||||
/* If there's no stack frame for this, argument values are in elements(). */
|
||||
if (!fp) {
|
||||
@ -727,7 +729,7 @@ ArgumentsObject::getElements(uint32 start, uint32 count, Value *vp)
|
||||
}
|
||||
|
||||
/* If we're on trace, there's no canonical location for elements: fail. */
|
||||
if (fp == JS_ARGUMENTS_OBJECT_ON_TRACE)
|
||||
if (onTrace())
|
||||
return false;
|
||||
|
||||
/* Otherwise, element values are on the stack. */
|
||||
|
@ -159,9 +159,9 @@ StackFrame::stealFrameAndSlots(Value *vp, StackFrame *otherfp,
|
||||
if (hasArgsObj()) {
|
||||
ArgumentsObject &argsobj = argsObj();
|
||||
if (argsobj.isNormalArguments())
|
||||
argsobj.setPrivate(this);
|
||||
argsobj.setStackFrame(this);
|
||||
else
|
||||
JS_ASSERT(!argsobj.getPrivate());
|
||||
JS_ASSERT(!argsobj.maybeStackFrame());
|
||||
otherfp->flags_ &= ~HAS_ARGS_OBJ;
|
||||
}
|
||||
}
|
||||
|
@ -851,9 +851,9 @@ class StackFrame
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline JSObject &callObj() const;
|
||||
inline CallObject &callObj() const;
|
||||
inline void setScopeChainNoCallObj(JSObject &obj);
|
||||
inline void setScopeChainWithOwnCallObj(JSObject &obj);
|
||||
inline void setScopeChainWithOwnCallObj(CallObject &obj);
|
||||
|
||||
/*
|
||||
* Prologue for function frames: make a call object for heavyweight
|
||||
|
@ -76,6 +76,7 @@ const AnimatedZoom = {
|
||||
start: function start() {
|
||||
this.tab = Browser.selectedTab;
|
||||
this.browser = this.tab.browser;
|
||||
this.bcr = this.browser.getBoundingClientRect();
|
||||
this.zoomFrom = this.zoomRect || this.getStartRect();
|
||||
this.startScale = this.browser.scale;
|
||||
this.beginTime = mozAnimationStartTime;
|
||||
@ -84,14 +85,13 @@ const AnimatedZoom = {
|
||||
/** Get the visible rect, in device pixels relative to the content origin. */
|
||||
getStartRect: function getStartRect() {
|
||||
let browser = this.browser;
|
||||
let bcr = browser.getBoundingClientRect();
|
||||
let scroll = browser.getRootView().getPosition();
|
||||
return new Rect(scroll.x, scroll.y, bcr.width, bcr.height);
|
||||
return new Rect(scroll.x, scroll.y, this.bcr.width, this.bcr.height);
|
||||
},
|
||||
|
||||
/** Update the visible rect, in device pixels relative to the content origin. */
|
||||
updateTo: function(nextRect) {
|
||||
let zoomRatio = window.innerWidth / nextRect.width;
|
||||
let zoomRatio = this.bcr.width / nextRect.width;
|
||||
let scale = this.startScale * zoomRatio;
|
||||
let scrollX = nextRect.left * zoomRatio;
|
||||
let scrollY = nextRect.top * zoomRatio;
|
||||
|
@ -161,15 +161,29 @@ let Util = {
|
||||
return (!appInfo || appInfo.getService(Ci.nsIXULRuntime).processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT);
|
||||
},
|
||||
|
||||
isTablet: function isTablet() {
|
||||
isTablet: function isTablet(options) {
|
||||
let forceUpdate = options && 'forceUpdate' in options && options.forceUpdate;
|
||||
|
||||
if ('_isTablet' in this && !forceUpdate)
|
||||
return this._isTablet;
|
||||
|
||||
let tabletPref = Services.prefs.getIntPref("browser.ui.layout.tablet");
|
||||
|
||||
// Act according to user prefs if tablet mode has been
|
||||
// explicitly disabled or enabled.
|
||||
if (tabletPref == 0)
|
||||
return this._isTablet = false;
|
||||
else if (tabletPref == 1)
|
||||
return this._isTablet = true;
|
||||
|
||||
let dpi = this.displayDPI;
|
||||
if (dpi <= 96)
|
||||
return (window.innerWidth > 1024);
|
||||
return this._isTablet = (window.innerWidth > 1024);
|
||||
|
||||
// See the tablet_panel_minwidth from mobile/themes/core/defines.inc
|
||||
let tablet_panel_minwidth = 124;
|
||||
let dpmm = 25.4 * window.innerWidth / dpi;
|
||||
return (dpmm >= tablet_panel_minwidth);
|
||||
return this._isTablet = (dpmm >= tablet_panel_minwidth);
|
||||
},
|
||||
|
||||
isPortrait: function isPortrait() {
|
||||
|
@ -186,6 +186,8 @@ var BrowserUI = {
|
||||
},
|
||||
|
||||
lockToolbar: function lockToolbar() {
|
||||
if (Util.isTablet())
|
||||
return;
|
||||
this._toolbarLocked++;
|
||||
document.getElementById("toolbar-moveable-container").top = "0";
|
||||
if (this._toolbarLocked == 1)
|
||||
@ -379,11 +381,6 @@ var BrowserUI = {
|
||||
return this._toolbarH;
|
||||
},
|
||||
|
||||
get sidebarW() {
|
||||
delete this._sidebarW;
|
||||
return this._sidebarW = Elements.controls.getBoundingClientRect().width;
|
||||
},
|
||||
|
||||
sizeControls: function(windowW, windowH) {
|
||||
// tabs
|
||||
document.getElementById("tabs").resize();
|
||||
@ -552,11 +549,27 @@ var BrowserUI = {
|
||||
},
|
||||
|
||||
updateTabletLayout: function updateTabletLayout() {
|
||||
let tabletPref = Services.prefs.getIntPref("browser.ui.layout.tablet");
|
||||
if (tabletPref == 1 || (tabletPref == -1 && Util.isTablet()))
|
||||
if (Util.isTablet({ forceUpdate: true })) {
|
||||
this.unlockToolbar();
|
||||
Elements.urlbarState.setAttribute("tablet", "true");
|
||||
else
|
||||
} else {
|
||||
Elements.urlbarState.removeAttribute("tablet");
|
||||
}
|
||||
|
||||
// Tablet mode changes the size of the thumbnails
|
||||
// in the tabs container. Hence we have to force a
|
||||
// thumbnail update on all tabs.
|
||||
setTimeout(function(self) {
|
||||
self._updateAllTabThumbnails();
|
||||
}, 0, this);
|
||||
},
|
||||
|
||||
_updateAllTabThumbnails: function() {
|
||||
let tabs = Browser.tabs;
|
||||
|
||||
tabs.forEach(function(tab) {
|
||||
tab.updateThumbnail({ force: true });
|
||||
});
|
||||
},
|
||||
|
||||
update: function(aState) {
|
||||
|
@ -1038,7 +1038,7 @@ var Browser = {
|
||||
},
|
||||
|
||||
tryFloatToolbar: function tryFloatToolbar(dx, dy) {
|
||||
if (this.floatedWhileDragging)
|
||||
if (this.floatedWhileDragging || Util.isTablet())
|
||||
return;
|
||||
|
||||
let [leftvis, ritevis, leftw, ritew] = Browser.computeSidebarVisibility(dx, dy);
|
||||
@ -1289,7 +1289,7 @@ Browser.MainDragger.prototype = {
|
||||
let bcr = browser.getBoundingClientRect();
|
||||
this._contentView = browser.getViewAt(clientX - bcr.left, clientY - bcr.top);
|
||||
this._stopAtSidebar = 0;
|
||||
this._panToolbars = !Elements.urlbarState.getAttribute("tablet");
|
||||
this._panToolbars = !Util.isTablet();
|
||||
if (this._sidebarTimeout) {
|
||||
clearTimeout(this._sidebarTimeout);
|
||||
this._sidebarTimeout = null;
|
||||
@ -1908,7 +1908,7 @@ const ContentTouchHandler = {
|
||||
// or if the urlbar is showing
|
||||
this.canCancelPan = (aX >= rect.left + kSafetyX) && (aX <= rect.right - kSafetyX) &&
|
||||
(aY >= rect.top + kSafetyY) &&
|
||||
(bcr.top == 0 || Elements.urlbarState.getAttribute("tablet"));
|
||||
(bcr.top == 0 || Util.isTablet());
|
||||
},
|
||||
|
||||
tapDown: function tapDown(aX, aY) {
|
||||
@ -2899,7 +2899,6 @@ Tab.prototype = {
|
||||
let notification = this._notification = document.createElement("notificationbox");
|
||||
notification.classList.add("inputHandler");
|
||||
|
||||
// Create the browser using the current width the dynamically size the height
|
||||
let browser = this._browser = document.createElement("browser");
|
||||
browser.setAttribute("class", "viewable-width viewable-height");
|
||||
this._chromeTab.linkedBrowser = browser;
|
||||
@ -3155,15 +3154,18 @@ function rendererFactory(aBrowser, aCanvas) {
|
||||
*/
|
||||
var ViewableAreaObserver = {
|
||||
get width() {
|
||||
return this._width || window.innerWidth;
|
||||
let width = this._width || window.innerWidth;
|
||||
if (Util.isTablet()) {
|
||||
let sidebarWidth = Math.round(Elements.tabs.getBoundingClientRect().width);
|
||||
width -= sidebarWidth;
|
||||
}
|
||||
return width;
|
||||
},
|
||||
|
||||
get height() {
|
||||
let height = (this._height || window.innerHeight);
|
||||
if (Elements.urlbarState.getAttribute("tablet")) {
|
||||
let toolbarHeight = Math.round(document.getElementById("toolbar-main").getBoundingClientRect().height);
|
||||
height -= toolbarHeight;
|
||||
}
|
||||
if (Util.isTablet())
|
||||
height -= BrowserUI.toolbarH;
|
||||
return height;
|
||||
},
|
||||
|
||||
|
@ -198,22 +198,22 @@
|
||||
<stack flex="1" id="stack">
|
||||
<scrollbox id="controls-scrollbox" style="overflow: hidden; -moz-box-orient: horizontal; position: relative;" flex="1" observes="bcast_urlbarState">
|
||||
<vbox id="tabs-sidebar" class="sidebar" observes="bcast_uidiscovery">
|
||||
<spacer class="toolbar-height"/>
|
||||
<spacer class="toolbar-height" id="tabs-spacer" observes="bcast_urlbarState"/>
|
||||
<!-- Left toolbar -->
|
||||
<vbox id="tabs-container" class="panel-dark" flex="1">
|
||||
<vbox id="tabs" flex="1"
|
||||
<vbox id="tabs-container" class="panel-dark" flex="1" observes="bcast_urlbarState">
|
||||
<vbox id="tabs" flex="1" observes="bcast_urlbarState"
|
||||
onselect="BrowserUI.selectTab(this);"
|
||||
onreloadtab="BrowserUI.undoCloseTab()"
|
||||
onclosetab="BrowserUI.closeTab(this)"
|
||||
onclosereloadtab="this._container.removeTab(this)"/>
|
||||
<hbox id="tabs-controls">
|
||||
<toolbarbutton id="newtab-button" class="button-control" command="cmd_newTab"/>
|
||||
<toolbarbutton id="newtab-button" class="button-control" command="cmd_newTab" observes="bcast_urlbarState"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</vbox>
|
||||
|
||||
<!-- Page Area -->
|
||||
<stack>
|
||||
<stack id="page-stack" observes="bcast_urlbarState">
|
||||
<scrollbox id="page-scrollbox">
|
||||
<vbox>
|
||||
<!-- Main Toolbar -->
|
||||
|
@ -1209,6 +1209,7 @@ GestureModule.prototype = {
|
||||
let delta = 0;
|
||||
let browser = AnimatedZoom.browser;
|
||||
let oldScale = browser.scale;
|
||||
let bcr = this._browserBCR;
|
||||
|
||||
// Accumulate pinch delta. Small changes are just jitter.
|
||||
this._pinchDelta += aEvent.delta;
|
||||
@ -1223,13 +1224,13 @@ GestureModule.prototype = {
|
||||
let newScale = Browser.selectedTab.clampZoomLevel(oldScale * (1 + delta / this._scalingFactor));
|
||||
let startScale = AnimatedZoom.startScale;
|
||||
let scaleRatio = startScale / newScale;
|
||||
let cX = aEvent.clientX - this._browserBCR.left;
|
||||
let cY = aEvent.clientY - this._browserBCR.top;
|
||||
let cX = aEvent.clientX - bcr.left;
|
||||
let cY = aEvent.clientY - bcr.top;
|
||||
|
||||
// Calculate the new zoom rect.
|
||||
let rect = AnimatedZoom.zoomFrom.clone();
|
||||
rect.translate(this._pinchStartX - cX + (1-scaleRatio) * cX * rect.width / window.innerWidth,
|
||||
this._pinchStartY - cY + (1-scaleRatio) * cY * rect.height / window.innerHeight);
|
||||
rect.translate(this._pinchStartX - cX + (1-scaleRatio) * cX * rect.width / bcr.width,
|
||||
this._pinchStartY - cY + (1-scaleRatio) * cY * rect.height / bcr.height);
|
||||
|
||||
rect.width *= scaleRatio;
|
||||
rect.height *= scaleRatio;
|
||||
|
@ -7,21 +7,61 @@
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<binding id="documenttab">
|
||||
<content>
|
||||
<content observes="bcast_urlbarState">
|
||||
<xul:stack anonid="page" class="documenttab-container" flex="1">
|
||||
<html:canvas anonid="thumbnail" class="documenttab-thumbnail" left="0" width="104" height="65" moz-opaque="true" empty="true"
|
||||
onclick="document.getBindingParent(this)._onClick()"/>
|
||||
<xul:hbox class="documenttab-reload" left="0" top="0" width="104" height="65" onclick="document.getBindingParent(this)._onUndo();"/>
|
||||
<xul:hbox class="documenttab-close-container" start="-16" top="0" height="65" width="55" align="center" onclick="document.getBindingParent(this)._onClose()">
|
||||
<xul:image anonid="close" class="documenttab-close" mousethrough="always"/>
|
||||
<html:canvas anonid="thumbnail" class="documenttab-thumbnail" left="0" moz-opaque="true" empty="true"
|
||||
onclick="document.getBindingParent(this)._onClick()" observes="bcast_urlbarState"/>
|
||||
<xul:hbox anonid="reload" class="documenttab-reload" left="0" top="0" onclick="document.getBindingParent(this)._onUndo();" observes="bcast_urlbarState"/>
|
||||
<xul:hbox anonid="close-container" class="documenttab-close-container" top="0" align="center" onclick="document.getBindingParent(this)._onClose()" observes="bcast_urlbarState">
|
||||
<xul:image anonid="close" class="documenttab-close" mousethrough="always" observes="bcast_urlbarState"/>
|
||||
</xul:hbox>
|
||||
</xul:stack>
|
||||
</content>
|
||||
|
||||
<implementation>
|
||||
<field name="ignoreUndo">false</field>
|
||||
<field name="thumbnail">document.getAnonymousElementByAttribute(this, "anonid", "thumbnail");</field>
|
||||
<field name="_container">this.parentNode.parentNode;</field>
|
||||
<field name="thumbnail" readonly="true">document.getAnonymousElementByAttribute(this, "anonid", "thumbnail");</field>
|
||||
<field name="_reload" readonly="true">document.getAnonymousElementByAttribute(this, "anonid", "reload");</field>
|
||||
<field name="_closeContainer" readonly="true">document.getAnonymousElementByAttribute(this, "anonid", "close-container");</field>
|
||||
<field name="_container" readonly="true">this.parentNode.parentNode;</field>
|
||||
|
||||
<constructor>
|
||||
<![CDATA[
|
||||
this.updateTabletLayout(this.thumbnail);
|
||||
]]>
|
||||
</constructor>
|
||||
|
||||
<method name="updateTabletLayout">
|
||||
<parameter name="thumbnail"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
let tabWidth, tabHeight, closeWidth, closeHeight;
|
||||
|
||||
if (Util.isTablet()) {
|
||||
tabWidth = 176;
|
||||
tabHeight = 110;
|
||||
closeWidth = 41;
|
||||
closeHeight = 117;
|
||||
} else {
|
||||
tabWidth = 104;
|
||||
tabHeight = 65;
|
||||
closeWidth = 55;
|
||||
closeHeight = 65;
|
||||
}
|
||||
|
||||
if (tabWidth != thumbnail.width) {
|
||||
let reload = this._reload;
|
||||
let closeContainer = this._closeContainer;
|
||||
|
||||
thumbnail.width = reload.width = tabWidth;
|
||||
thumbnail.height = reload.height = tabHeight;
|
||||
closeContainer.width = closeWidth;
|
||||
closeContainer.height = closeHeight;
|
||||
}
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="_onClick">
|
||||
<body>
|
||||
<![CDATA[
|
||||
@ -61,14 +101,18 @@
|
||||
<body>
|
||||
<![CDATA[
|
||||
let thumbnail = this.thumbnail;
|
||||
// Ensure the thumbnail will have the correct
|
||||
// dimensions for tablet and phone modes
|
||||
this.updateTabletLayout(thumbnail);
|
||||
|
||||
if (browser.currentURI.spec == "about:blank") {
|
||||
thumbnail.setAttribute("empty", "true");
|
||||
return;
|
||||
}
|
||||
thumbnail.removeAttribute("empty");
|
||||
|
||||
const tabWidth = 104;
|
||||
const tabHeight = 65;
|
||||
const tabWidth = thumbnail.width;
|
||||
const tabHeight = thumbnail.height;
|
||||
|
||||
let ratio = tabHeight / tabWidth;
|
||||
if (browser.contentDocumentWidth > 0)
|
||||
@ -118,7 +162,7 @@
|
||||
|
||||
<binding id="tablist">
|
||||
<content>
|
||||
<xul:scrollbox anonid="tabs-scrollbox" flex="1">
|
||||
<xul:scrollbox anonid="tabs-scrollbox" class="tabs-scrollbox" flex="1">
|
||||
<xul:vbox class="tabs-list" anonid="tabs-children" />
|
||||
</xul:scrollbox>
|
||||
<xul:box class="tabs-list" anonid="tabs-undo"/>
|
||||
@ -241,7 +285,7 @@
|
||||
// We can't rely on getBoundingClientRect() for this.children height
|
||||
// it is not synced (sometimes, especially during resize) with the
|
||||
// style.height rule
|
||||
let columnsCount = Math.ceil(this.children.childNodes.length / Math.floor(parseInt(this.children.style.height) / (firstBox.height + 4)));
|
||||
let columnsCount = Util.isTablet() ? 1 : Math.ceil(this.children.childNodes.length / Math.floor(parseInt(this.children.style.height) / (firstBox.height + 4)));
|
||||
if (this._columnsCount != columnsCount && window.innerWidth > 1) { // > 1 to ignore column resizing while the main window is loading
|
||||
let width = columnsCount * (COLUMN_MARGIN + firstBox.width);
|
||||
this.children.style.width = width + "px";
|
||||
|
@ -929,7 +929,7 @@ autocompleteresult.noresults > .autocomplete-item-container {
|
||||
-moz-box-align: start;
|
||||
}
|
||||
|
||||
#tabs > scrollbox {
|
||||
#tabs > .tabs-scrollbox {
|
||||
max-width: 350px;
|
||||
}
|
||||
|
||||
@ -986,6 +986,7 @@ documenttab[selected="true"] > stack > .documenttab-thumbnail {
|
||||
.documenttab-close-container {
|
||||
position: relative;
|
||||
left: -16px;
|
||||
-moz-margin-start: -16px;
|
||||
-moz-margin-end: 49px;
|
||||
}
|
||||
|
||||
@ -1575,46 +1576,6 @@ setting {
|
||||
to { -moz-transform: translateX(0); }
|
||||
}
|
||||
|
||||
/* Tablet mode */
|
||||
|
||||
.spacer-actionbar,
|
||||
.button-actionbar {
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
.button-actionbar[disabled="true"] {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.button-actionbar:hover:active {
|
||||
background-color: #8db8d8;
|
||||
}
|
||||
|
||||
#toolbar-main[tablet="true"] > .spacer-actionbar,
|
||||
#toolbar-main[tablet="true"] > .button-actionbar {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
#controls-scrollbox[tablet="true"] > #controls-sidebar {
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
#controls-scrollbox[tablet="true"] > #tabs-sidebar {
|
||||
border: none;
|
||||
position: fixed;
|
||||
top: -moz-calc(@touch_button_xlarge@ + @margin_normal@);
|
||||
visibility: collapse;
|
||||
}
|
||||
#controls-scrollbox[tablet="true"] > #tabs-sidebar:-moz-locale-dir(ltr) {
|
||||
right: 0;
|
||||
}
|
||||
#controls-scrollbox[tablet="true"] > #tabs-sidebar:-moz-locale-dir(rtl) {
|
||||
left: 0;
|
||||
}
|
||||
#controls-scrollbox[tablet="true"] > #tabs-sidebar[open] {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
/* Text selection handles */
|
||||
|
||||
#selectionhandle-start,
|
||||
@ -1640,4 +1601,6 @@ setting {
|
||||
#search-engines-popup {
|
||||
max-width: -moz-calc(@tablet_panel_minwidth@);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
%include tablet.css
|
||||
|
@ -879,7 +879,7 @@ autocompleteresult.noresults > .autocomplete-item-container {
|
||||
-moz-box-align: start;
|
||||
}
|
||||
|
||||
#tabs > scrollbox {
|
||||
#tabs > .tabs-scrollbox {
|
||||
max-width: 350px;
|
||||
}
|
||||
|
||||
@ -935,6 +935,7 @@ documenttab[selected="true"] > stack > .documenttab-thumbnail {
|
||||
.documenttab-close-container {
|
||||
position: relative;
|
||||
left: -16px;
|
||||
-moz-margin-start: -16px;
|
||||
-moz-margin-end: 49px;
|
||||
}
|
||||
|
||||
@ -1545,46 +1546,6 @@ setting {
|
||||
to { -moz-transform: translateX(0); }
|
||||
}
|
||||
|
||||
/* Tablet mode */
|
||||
|
||||
.spacer-actionbar,
|
||||
.button-actionbar {
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
.button-actionbar[disabled="true"] {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.button-actionbar:hover:active {
|
||||
background-color: #8db8d8;
|
||||
}
|
||||
|
||||
#toolbar-main[tablet="true"] > .spacer-actionbar,
|
||||
#toolbar-main[tablet="true"] > .button-actionbar {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
#controls-scrollbox[tablet="true"] > #controls-sidebar {
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
#controls-scrollbox[tablet="true"] > #tabs-sidebar {
|
||||
border: none;
|
||||
position: fixed;
|
||||
top: -moz-calc(@touch_button_xlarge@ + @margin_normal@);
|
||||
visibility: collapse;
|
||||
}
|
||||
#controls-scrollbox[tablet="true"] > #tabs-sidebar:-moz-locale-dir(ltr) {
|
||||
right: 0;
|
||||
}
|
||||
#controls-scrollbox[tablet="true"] > #tabs-sidebar:-moz-locale-dir(rtl) {
|
||||
left: 0;
|
||||
}
|
||||
#controls-scrollbox[tablet="true"] > #tabs-sidebar[open] {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
/* Text selection handles */
|
||||
|
||||
#selectionhandle-start,
|
||||
@ -1603,11 +1564,4 @@ setting {
|
||||
list-style-image: url("chrome://browser/skin/images/handle-end.png");
|
||||
}
|
||||
|
||||
@media (min-width: @tablet_panel_minwidth@) {
|
||||
#awesome-panels {
|
||||
-moz-box-shadow: 0px 0px @shadow_width_small@ black;
|
||||
}
|
||||
#search-engines-popup {
|
||||
max-width: -moz-calc(@tablet_panel_minwidth@);
|
||||
}
|
||||
}
|
||||
%include ../tablet.css
|
||||
|
After Width: | Height: | Size: 626 B |
BIN
mobile/themes/core/gingerbread/images/close-background-hdpi.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 626 B |
After Width: | Height: | Size: 546 B |
After Width: | Height: | Size: 263 B |
BIN
mobile/themes/core/gingerbread/images/tab-reopen-tablet-hdpi.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
@ -37,6 +37,7 @@
|
||||
|
||||
%filter substitution
|
||||
%include defines.inc
|
||||
%define honeycomb 1
|
||||
|
||||
/* main toolbar (URL bar) -------------------------------------------------- */
|
||||
#toolbar-main {
|
||||
@ -962,7 +963,7 @@ autocompleteresult.noresults > .autocomplete-item-container {
|
||||
-moz-box-align: start;
|
||||
}
|
||||
|
||||
#tabs > scrollbox {
|
||||
#tabs > .tabs-scrollbox {
|
||||
max-width: 350px;
|
||||
}
|
||||
|
||||
@ -1018,6 +1019,7 @@ documenttab[selected="true"] > stack > .documenttab-thumbnail {
|
||||
.documenttab-close-container {
|
||||
position: relative;
|
||||
left: -16px;
|
||||
-moz-margin-start: -16px;
|
||||
-moz-margin-end: 49px;
|
||||
}
|
||||
|
||||
@ -1694,42 +1696,6 @@ setting {
|
||||
to { -moz-transform: translateX(0); }
|
||||
}
|
||||
|
||||
/* Tablet mode */
|
||||
|
||||
.spacer-actionbar,
|
||||
.button-actionbar {
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
.button-actionbar[disabled="true"] {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
#toolbar-main[tablet="true"] > .spacer-actionbar,
|
||||
#toolbar-main[tablet="true"] > .button-actionbar {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
#controls-scrollbox[tablet="true"] > #controls-sidebar {
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
#controls-scrollbox[tablet="true"] > #tabs-sidebar {
|
||||
border: none;
|
||||
position: fixed;
|
||||
top: @touch_button_xlarge@;
|
||||
visibility: collapse;
|
||||
}
|
||||
#controls-scrollbox[tablet="true"] > #tabs-sidebar:-moz-locale-dir(ltr) {
|
||||
left: 0;
|
||||
}
|
||||
#controls-scrollbox[tablet="true"] > #tabs-sidebar:-moz-locale-dir(rtl) {
|
||||
right: 0;
|
||||
}
|
||||
#controls-scrollbox[tablet="true"] > #tabs-sidebar[open] {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
/* Text selection handles */
|
||||
|
||||
#selectionhandle-start,
|
||||
@ -1814,3 +1780,5 @@ setting {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
%include ../tablet.css
|
||||
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.2 KiB |
BIN
mobile/themes/core/honeycomb/images/close-active-tablet-hdpi.png
Normal file
After Width: | Height: | Size: 626 B |
BIN
mobile/themes/core/honeycomb/images/close-background-hdpi.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 626 B |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 546 B |
Before Width: | Height: | Size: 940 B After Width: | Height: | Size: 208 B |
After Width: | Height: | Size: 263 B |
BIN
mobile/themes/core/honeycomb/images/tab-reopen-tablet-hdpi.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
mobile/themes/core/images/close-active-tablet-hdpi.png
Normal file
After Width: | Height: | Size: 626 B |
BIN
mobile/themes/core/images/close-background-hdpi.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
mobile/themes/core/images/close-default-tablet-hdpi.png
Normal file
After Width: | Height: | Size: 626 B |
BIN
mobile/themes/core/images/close-inactive-tab-tablet-hdpi.png
Normal file
After Width: | Height: | Size: 546 B |
BIN
mobile/themes/core/images/newtab-default-tablet-hdpi.png
Normal file
After Width: | Height: | Size: 263 B |
BIN
mobile/themes/core/images/tab-reopen-tablet-hdpi.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
@ -90,10 +90,12 @@ chrome.jar:
|
||||
skin/images/row-header-bg.png (images/row-header-bg.png)
|
||||
skin/images/console-default-hdpi.png (images/console-default-hdpi.png)
|
||||
skin/images/newtab-default-hdpi.png (images/newtab-default-hdpi.png)
|
||||
skin/images/newtab-default-tablet-hdpi.png (images/newtab-default-tablet-hdpi.png)
|
||||
skin/images/tab-active-hdpi.png (images/tab-active-hdpi.png)
|
||||
skin/images/tab-inactive-hdpi.png (images/tab-inactive-hdpi.png)
|
||||
skin/images/tab-closed-hdpi.png (images/tab-closed-hdpi.png)
|
||||
skin/images/tab-reopen-hdpi.png (images/tab-reopen-hdpi.png)
|
||||
skin/images/tab-reopen-tablet-hdpi.png (images/tab-reopen-tablet-hdpi.png)
|
||||
skin/images/remotetabs-48.png (images/remotetabs-48.png)
|
||||
skin/images/remotetabs-32.png (images/remotetabs-32.png)
|
||||
skin/images/mozilla-32.png (images/mozilla-32.png)
|
||||
@ -110,8 +112,12 @@ chrome.jar:
|
||||
skin/images/unlocked-hdpi.png (images/unlocked-hdpi.png)
|
||||
skin/images/locked-hdpi.png (images/locked-hdpi.png)
|
||||
skin/images/close-default-hdpi.png (images/close-default-hdpi.png)
|
||||
skin/images/close-default-tablet-hdpi.png (images/close-default-tablet-hdpi.png)
|
||||
skin/images/close-active-hdpi.png (images/close-active-hdpi.png)
|
||||
skin/images/close-active-tablet-hdpi.png (images/close-active-tablet-hdpi.png)
|
||||
skin/images/close-inactive-tab-hdpi.png (images/close-inactive-tab-hdpi.png)
|
||||
skin/images/close-inactive-tab-tablet-hdpi.png (images/close-inactive-tab-tablet-hdpi.png)
|
||||
skin/images/close-background-hdpi.png (images/close-background-hdpi.png)
|
||||
skin/images/check-30.png (images/check-30.png)
|
||||
skin/images/search-glass-30.png (images/search-glass-30.png)
|
||||
skin/images/search-clear-30.png (images/search-clear-30.png)
|
||||
@ -214,10 +220,12 @@ chrome.jar:
|
||||
skin/gingerbread/images/row-header-bg.png (gingerbread/images/row-header-bg.png)
|
||||
skin/gingerbread/images/console-default-hdpi.png (gingerbread/images/console-default-hdpi.png)
|
||||
skin/gingerbread/images/newtab-default-hdpi.png (gingerbread/images/newtab-default-hdpi.png)
|
||||
skin/gingerbread/images/newtab-default-tablet-hdpi.png (gingerbread/images/newtab-default-tablet-hdpi.png)
|
||||
skin/gingerbread/images/tab-active-hdpi.png (gingerbread/images/tab-active-hdpi.png)
|
||||
skin/gingerbread/images/tab-inactive-hdpi.png (gingerbread/images/tab-inactive-hdpi.png)
|
||||
skin/gingerbread/images/tab-closed-hdpi.png (gingerbread/images/tab-closed-hdpi.png)
|
||||
skin/gingerbread/images/tab-reopen-hdpi.png (gingerbread/images/tab-reopen-hdpi.png)
|
||||
skin/gingerbread/images/tab-reopen-tablet-hdpi.png (gingerbread/images/tab-reopen-tablet-hdpi.png)
|
||||
skin/gingerbread/images/remotetabs-48.png (gingerbread/images/remotetabs-48.png)
|
||||
skin/gingerbread/images/remotetabs-32.png (gingerbread/images/remotetabs-32.png)
|
||||
skin/gingerbread/images/mozilla-32.png (images/mozilla-32.png)
|
||||
@ -233,8 +241,12 @@ chrome.jar:
|
||||
skin/gingerbread/images/unlocked-hdpi.png (gingerbread/images/unlocked-hdpi.png)
|
||||
skin/gingerbread/images/locked-hdpi.png (gingerbread/images/locked-hdpi.png)
|
||||
skin/gingerbread/images/close-default-hdpi.png (gingerbread/images/close-default-hdpi.png)
|
||||
skin/gingerbread/images/close-default-tablet-hdpi.png (gingerbread/images/close-default-tablet-hdpi.png)
|
||||
skin/gingerbread/images/close-active-hdpi.png (gingerbread/images/close-active-hdpi.png)
|
||||
skin/gingerbread/images/close-active-tablet-hdpi.png (gingerbread/images/close-active-tablet-hdpi.png)
|
||||
skin/gingerbread/images/close-background-hdpi.png (gingerbread/images/close-background-hdpi.png)
|
||||
skin/gingerbread/images/close-inactive-tab-hdpi.png (gingerbread/images/close-inactive-tab-hdpi.png)
|
||||
skin/gingerbread/images/close-inactive-tab-tablet-hdpi.png (gingerbread/images/close-inactive-tab-tablet-hdpi.png)
|
||||
skin/gingerbread/images/check-30.png (gingerbread/images/check-30.png)
|
||||
skin/gingerbread/images/search-glass-30.png (gingerbread/images/search-glass-30.png)
|
||||
skin/gingerbread/images/search-clear-30.png (gingerbread/images/search-clear-30.png)
|
||||
@ -339,10 +351,12 @@ chrome.jar:
|
||||
skin/honeycomb/images/row-header-bg.png (honeycomb/images/row-header-bg.png)
|
||||
skin/honeycomb/images/console-default-hdpi.png (honeycomb/images/console-default-hdpi.png)
|
||||
skin/honeycomb/images/newtab-default-hdpi.png (honeycomb/images/newtab-default-hdpi.png)
|
||||
skin/honeycomb/images/newtab-default-tablet-hdpi.png (honeycomb/images/newtab-default-tablet-hdpi.png)
|
||||
skin/honeycomb/images/tab-active-hdpi.png (honeycomb/images/tab-active-hdpi.png)
|
||||
skin/honeycomb/images/tab-inactive-hdpi.png (honeycomb/images/tab-inactive-hdpi.png)
|
||||
skin/honeycomb/images/tab-closed-hdpi.png (honeycomb/images/tab-closed-hdpi.png)
|
||||
skin/honeycomb/images/tab-reopen-hdpi.png (honeycomb/images/tab-reopen-hdpi.png)
|
||||
skin/honeycomb/images/tab-reopen-tablet-hdpi.png (honeycomb/images/tab-reopen-tablet-hdpi.png)
|
||||
skin/honeycomb/images/remotetabs-48.png (honeycomb/images/remotetabs-48.png)
|
||||
skin/honeycomb/images/remotetabs-32.png (honeycomb/images/remotetabs-32.png)
|
||||
skin/honeycomb/images/mozilla-32.png (images/mozilla-32.png)
|
||||
@ -359,8 +373,12 @@ chrome.jar:
|
||||
skin/honeycomb/images/unlocked-hdpi.png (honeycomb/images/unlocked-hdpi.png)
|
||||
skin/honeycomb/images/locked-hdpi.png (honeycomb/images/locked-hdpi.png)
|
||||
skin/honeycomb/images/close-default-hdpi.png (honeycomb/images/close-default-hdpi.png)
|
||||
skin/honeycomb/images/close-default-tablet-hdpi.png (honeycomb/images/close-default-tablet-hdpi.png)
|
||||
skin/honeycomb/images/close-active-hdpi.png (honeycomb/images/close-active-hdpi.png)
|
||||
skin/honeycomb/images/close-active-tablet-hdpi.png (honeycomb/images/close-active-tablet-hdpi.png)
|
||||
skin/honeycomb/images/close-background-hdpi.png (honeycomb/images/close-background-hdpi.png)
|
||||
skin/honeycomb/images/close-inactive-tab-hdpi.png (honeycomb/images/close-inactive-tab-hdpi.png)
|
||||
skin/honeycomb/images/close-inactive-tab-tablet-hdpi.png (honeycomb/images/close-inactive-tab-tablet-hdpi.png)
|
||||
skin/honeycomb/images/check-30.png (images/check-30.png)
|
||||
skin/honeycomb/images/check-selected-hdpi.png (honeycomb/images/check-selected-hdpi.png)
|
||||
skin/honeycomb/images/check-unselected-hdpi.png (honeycomb/images/check-unselected-hdpi.png)
|
||||
|
144
mobile/themes/core/tablet.css
Normal file
@ -0,0 +1,144 @@
|
||||
|
||||
.spacer-actionbar,
|
||||
.button-actionbar {
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
.button-actionbar[disabled="true"] {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
%ifndef honeycomb
|
||||
.button-actionbar:hover:active {
|
||||
background-color: #8db8d8;
|
||||
}
|
||||
%endif
|
||||
|
||||
#toolbar-main[tablet="true"] > .spacer-actionbar,
|
||||
#toolbar-main[tablet="true"] > .button-actionbar {
|
||||
visibility: visible;
|
||||
}
|
||||
#toolbar-main[tablet="true"] > #tool-tabs {
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
#controls-scrollbox[tablet="true"] > #controls-sidebar {
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
#tabs-spacer[tablet="true"] {
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
#tabs-container[tablet="true"] {
|
||||
-moz-border-end: 0px;
|
||||
background: #000;
|
||||
}
|
||||
|
||||
#tabs[tablet="true"] > .tabs-scrollbox {
|
||||
max-width: 200px;
|
||||
-moz-box-orient: vertical;
|
||||
}
|
||||
|
||||
#tabs[tablet="true"] .tabs-list {
|
||||
}
|
||||
|
||||
#tabs[tablet="true"] .tabs-list {
|
||||
width: 200px;
|
||||
-moz-column-width: auto;
|
||||
-moz-padding-end: 0px;
|
||||
-moz-padding-start: 0px;
|
||||
}
|
||||
|
||||
documenttab[tablet="true"] {
|
||||
/* Use px instead of mozmm because tab bar items have hard-coded pixel sizes */
|
||||
width: 200px;
|
||||
padding: 12px;
|
||||
-moz-margin-start: 0px;
|
||||
background: none;
|
||||
}
|
||||
|
||||
documenttab[tablet="true"][selected="true"] {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.documenttab-thumbnail[tablet="true"] {
|
||||
border-radius: @border_radius_tiny@;
|
||||
}
|
||||
|
||||
.documenttab-close-container[tablet="true"] {
|
||||
left: 0px;
|
||||
-moz-margin-end: 0px;
|
||||
-moz-margin-start: 135px;
|
||||
-moz-box-pack: end;
|
||||
-moz-box-align: center;
|
||||
}
|
||||
|
||||
documenttab[selected="true"] > stack > .documenttab-close-container[tablet="true"] {
|
||||
background: url("chrome://browser/skin/images/close-background-hdpi.png");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right;
|
||||
-moz-margin-end: -12px;
|
||||
padding-right: 2px;
|
||||
}
|
||||
|
||||
.documenttab-close[tablet="true"] {
|
||||
width: 30px;
|
||||
height: 44px;
|
||||
list-style-image: url("chrome://browser/skin/images/close-inactive-tab-tablet-hdpi.png");
|
||||
}
|
||||
|
||||
documenttab[selected="true"] > stack > hbox > .documenttab-close[tablet="true"] {
|
||||
list-style-image: url("chrome://browser/skin/images/close-default-tablet-hdpi.png");
|
||||
}
|
||||
|
||||
.documenttab-close-container:hover:active > .documenttab-close[tablet="true"] {
|
||||
list-style-image: url("chrome://browser/skin/images/close-active-tablet-hdpi.png");
|
||||
}
|
||||
|
||||
.documenttab-reload[tablet="true"] {
|
||||
background: url("chrome://browser/skin/images/tab-reopen-tablet-hdpi.png");
|
||||
}
|
||||
|
||||
#newtab-button[tablet="true"] {
|
||||
list-style-image: url("images/newtab-default-tablet-hdpi.png");
|
||||
}
|
||||
|
||||
@media (@orientation@: portrait) {
|
||||
#toolbar-main[tablet="true"] > #tool-tabs {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
#controls-scrollbox[tablet="true"] > #tabs-sidebar {
|
||||
border: none;
|
||||
%ifdef honeycomb
|
||||
top: @touch_button_xlarge@;
|
||||
%else
|
||||
top: -moz-calc(@touch_button_xlarge@ + @margin_normal@);
|
||||
%endif
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
#controls-scrollbox[tablet="true"] > #tabs-sidebar:-moz-locale-dir(ltr) {
|
||||
left: 0;
|
||||
}
|
||||
#controls-scrollbox[tablet="true"] > #tabs-sidebar:-moz-locale-dir(rtl) {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
#controls-scrollbox[tablet="true"] > #tabs-sidebar[open] {
|
||||
position: fixed;
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
%ifndef honeycomb
|
||||
@media (min-width: @tablet_panel_minwidth@) {
|
||||
#awesome-panels {
|
||||
-moz-box-shadow: 0px 0px @shadow_width_small@ black;
|
||||
}
|
||||
#search-engines-popup {
|
||||
max-width: -moz-calc(@tablet_panel_minwidth@);
|
||||
}
|
||||
}
|
||||
%endif
|
@ -78,6 +78,7 @@ LOCAL_INCLUDES += \
|
||||
LOCAL_INCLUDES += -I$(topsrcdir)/layout/svg/base/src
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
include $(topsrcdir)/ipc/chromium/chromium-config.mk
|
||||
|
||||
# Because imgFrame.cpp includes "cairo.h"
|
||||
CXXFLAGS += $(MOZ_CAIRO_CFLAGS)
|
||||
|
@ -42,6 +42,7 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "base/histogram.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "imgIContainerObserver.h"
|
||||
#include "ImageErrors.h"
|
||||
@ -191,6 +192,7 @@ RasterImage::RasterImage(imgStatusTracker* aStatusTracker) :
|
||||
mDecoder(nsnull),
|
||||
mWorker(nsnull),
|
||||
mBytesDecoded(0),
|
||||
mDecodeCount(0),
|
||||
#ifdef DEBUG
|
||||
mFramesNotified(0),
|
||||
#endif
|
||||
@ -208,6 +210,7 @@ RasterImage::RasterImage(imgStatusTracker* aStatusTracker) :
|
||||
// Set up the discard tracker node.
|
||||
mDiscardTrackerNode.curr = this;
|
||||
mDiscardTrackerNode.prev = mDiscardTrackerNode.next = nsnull;
|
||||
Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)->Add(0);
|
||||
|
||||
// Statistics
|
||||
num_containers++;
|
||||
@ -2197,6 +2200,12 @@ RasterImage::InitDecoder(bool aDoSizeDecode)
|
||||
|
||||
// Create a decode worker
|
||||
mWorker = new imgDecodeWorker(this);
|
||||
|
||||
if (!aDoSizeDecode) {
|
||||
Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)->Subtract(mDecodeCount);
|
||||
mDecodeCount++;
|
||||
Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)->Add(mDecodeCount);
|
||||
}
|
||||
CONTAINER_ENSURE_TRUE(mWorker, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
return NS_OK;
|
||||
|
@ -503,6 +503,10 @@ private: // data
|
||||
nsRefPtr<imgDecodeWorker> mWorker;
|
||||
PRUint32 mBytesDecoded;
|
||||
|
||||
// How many times we've decoded this image.
|
||||
// This is currently only used for statistics
|
||||
PRInt32 mDecodeCount;
|
||||
|
||||
#ifdef DEBUG
|
||||
PRUint32 mFramesNotified;
|
||||
#endif
|
||||
|
@ -234,7 +234,7 @@ nsIOService::Init()
|
||||
if (observerService) {
|
||||
observerService->AddObserver(this, kProfileChangeNetTeardownTopic, PR_TRUE);
|
||||
observerService->AddObserver(this, kProfileChangeNetRestoreTopic, PR_TRUE);
|
||||
observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_TRUE);
|
||||
observerService->AddObserver(this, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID, PR_TRUE);
|
||||
observerService->AddObserver(this, NS_NETWORK_LINK_TOPIC, PR_TRUE);
|
||||
}
|
||||
else
|
||||
@ -969,7 +969,7 @@ nsIOService::Observe(nsISupports *subject,
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
|
||||
else if (!strcmp(topic, NS_XPCOM_WILL_SHUTDOWN_OBSERVER_ID)) {
|
||||
// Remember we passed XPCOM shutdown notification to prevent any
|
||||
// changes of the offline status from now. We must not allow going
|
||||
// online after this point.
|
||||
|
@ -81,6 +81,9 @@
|
||||
#define NS_PARENTALCONTROLSSERVICE_CONTRACTID \
|
||||
"@mozilla.org/parental-controls-service;1"
|
||||
|
||||
#define NS_URLCLASSIFIERPREFIXSET_CONTRACTID \
|
||||
"@mozilla.org/url-classifier/prefixset;1"
|
||||
|
||||
#define NS_URLCLASSIFIERDBSERVICE_CONTRACTID \
|
||||
"@mozilla.org/url-classifier/dbservice;1"
|
||||
|
||||
@ -156,7 +159,11 @@
|
||||
// {e7f70966-9a37-48d7-8aeb-35998f31090e}
|
||||
#define NS_TYPEAHEADFIND_CID \
|
||||
{ 0xe7f70966, 0x9a37, 0x48d7, { 0x8a, 0xeb, 0x35, 0x99, 0x8f, 0x31, 0x09, 0x0e} }
|
||||
|
||||
|
||||
// {42ef1d52-3351-4973-98f8-d18f089bccfa}
|
||||
#define NS_URLCLASSIFIERPREFIXSET_CID \
|
||||
{ 0x42ef1d52, 0x3351, 0x4973, { 0x98, 0xf8, 0xd1, 0x8f, 0x08, 0x9b, 0xcc, 0xfa} }
|
||||
|
||||
// {5eb7c3c1-ec1f-4007-87cc-eefb37d68ce6}
|
||||
#define NS_URLCLASSIFIERDBSERVICE_CID \
|
||||
{ 0x5eb7c3c1, 0xec1f, 0x4007, { 0x87, 0xcc, 0xee, 0xfb, 0x37, 0xd6, 0x8c, 0xe6} }
|
||||
|
@ -63,6 +63,7 @@
|
||||
#include "nsUrlClassifierDBService.h"
|
||||
#include "nsUrlClassifierStreamUpdater.h"
|
||||
#include "nsUrlClassifierUtils.h"
|
||||
#include "nsUrlClassifierPrefixSet.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_FEEDS
|
||||
@ -94,6 +95,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsDownloadProxy)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsTypeAheadFind)
|
||||
|
||||
#ifdef MOZ_URL_CLASSIFIER
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsUrlClassifierPrefixSet)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsUrlClassifierStreamUpdater)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsUrlClassifierUtils, Init)
|
||||
|
||||
@ -138,6 +140,7 @@ NS_DEFINE_NAMED_CID(NS_DOWNLOAD_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_FIND_SERVICE_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_TYPEAHEADFIND_CID);
|
||||
#ifdef MOZ_URL_CLASSIFIER
|
||||
NS_DEFINE_NAMED_CID(NS_URLCLASSIFIERPREFIXSET_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_URLCLASSIFIERDBSERVICE_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_URLCLASSIFIERSTREAMUPDATER_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_URLCLASSIFIERUTILS_CID);
|
||||
@ -164,6 +167,7 @@ static const mozilla::Module::CIDEntry kToolkitCIDs[] = {
|
||||
{ &kNS_FIND_SERVICE_CID, false, NULL, nsFindServiceConstructor },
|
||||
{ &kNS_TYPEAHEADFIND_CID, false, NULL, nsTypeAheadFindConstructor },
|
||||
#ifdef MOZ_URL_CLASSIFIER
|
||||
{ &kNS_URLCLASSIFIERPREFIXSET_CID, false, NULL, nsUrlClassifierPrefixSetConstructor },
|
||||
{ &kNS_URLCLASSIFIERDBSERVICE_CID, false, NULL, nsUrlClassifierDBServiceConstructor },
|
||||
{ &kNS_URLCLASSIFIERSTREAMUPDATER_CID, false, NULL, nsUrlClassifierStreamUpdaterConstructor },
|
||||
{ &kNS_URLCLASSIFIERUTILS_CID, false, NULL, nsUrlClassifierUtilsConstructor },
|
||||
@ -192,6 +196,7 @@ static const mozilla::Module::ContractIDEntry kToolkitContracts[] = {
|
||||
{ NS_FIND_SERVICE_CONTRACTID, &kNS_FIND_SERVICE_CID },
|
||||
{ NS_TYPEAHEADFIND_CONTRACTID, &kNS_TYPEAHEADFIND_CID },
|
||||
#ifdef MOZ_URL_CLASSIFIER
|
||||
{ NS_URLCLASSIFIERPREFIXSET_CONTRACTID, &kNS_URLCLASSIFIERPREFIXSET_CID },
|
||||
{ NS_URLCLASSIFIERDBSERVICE_CONTRACTID, &kNS_URLCLASSIFIERDBSERVICE_CID },
|
||||
{ NS_URICLASSIFIERSERVICE_CONTRACTID, &kNS_URLCLASSIFIERDBSERVICE_CID },
|
||||
{ NS_URLCLASSIFIERSTREAMUPDATER_CONTRACTID, &kNS_URLCLASSIFIERSTREAMUPDATER_CID },
|
||||
|
@ -149,7 +149,7 @@ GetHistogramByEnumId(Telemetry::ID id, Histogram **ret)
|
||||
const TelemetryHistogram &p = gHistograms[id];
|
||||
nsresult rv = HistogramGet(p.id, p.min, p.max, p.bucketCount, p.histogramType, &h);
|
||||
if (NS_FAILED(rv))
|
||||
return NS_ERROR_FAILURE;
|
||||
return rv;
|
||||
|
||||
*ret = knownHistograms[id] = h;
|
||||
return NS_OK;
|
||||
@ -411,6 +411,14 @@ Accumulate(ID aHistogram, PRUint32 aSample)
|
||||
h->Add(aSample);
|
||||
}
|
||||
|
||||
base::Histogram*
|
||||
GetHistogramById(ID id)
|
||||
{
|
||||
Histogram *h = NULL;
|
||||
GetHistogramByEnumId(id, &h);
|
||||
return h;
|
||||
}
|
||||
|
||||
} // namespace Telemetry
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -42,6 +42,10 @@
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/AutoRestore.h"
|
||||
|
||||
namespace base {
|
||||
class Histogram;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
namespace Telemetry {
|
||||
|
||||
@ -62,6 +66,11 @@ HistogramCount
|
||||
*/
|
||||
void Accumulate(ID id, PRUint32 sample);
|
||||
|
||||
/**
|
||||
* Return a raw Histogram for direct manipulation for users who can not use Accumulate().
|
||||
*/
|
||||
base::Histogram* GetHistogramById(ID id);
|
||||
|
||||
template<ID id>
|
||||
class AutoTimer {
|
||||
public:
|
||||
|
@ -97,6 +97,7 @@ HISTOGRAM(IMAGE_DECODE_LATENCY, 50, 5000000, 100, EXPONENTIAL, "Time spent deco
|
||||
HISTOGRAM(IMAGE_DECODE_TIME, 50, 50000000, 100, EXPONENTIAL, "Time spent decoding an image (us)")
|
||||
HISTOGRAM(IMAGE_DECODE_ON_DRAW_LATENCY, 50, 50000000, 100, EXPONENTIAL, "Time from starting a decode to it showing up on the screen (us)")
|
||||
HISTOGRAM(IMAGE_DECODE_CHUNKS, 1, 500, 50, EXPONENTIAL, "Number of chunks per decode attempt")
|
||||
HISTOGRAM(IMAGE_DECODE_COUNT, 1, 500, 50, EXPONENTIAL, "Decode count")
|
||||
|
||||
/**
|
||||
* Networking telemetry
|
||||
@ -167,6 +168,15 @@ HISTOGRAM(NETWORK_DISK_CACHE_OPEN, 1, 10000, 10, EXPONENTIAL, "Time spent openin
|
||||
HISTOGRAM(NETWORK_DISK_CACHE_TRASHRENAME, 1, 10000, 10, EXPONENTIAL, "Time spent renaming bad Cache to Cache.Trash (ms)")
|
||||
HISTOGRAM(NETWORK_DISK_CACHE_DELETEDIR, 1, 10000, 10, EXPONENTIAL, "Time spent deleting disk cache (ms)")
|
||||
|
||||
/**
|
||||
* Url-Classifier telemetry
|
||||
*/
|
||||
#ifdef MOZ_URL_CLASSIFIER
|
||||
HISTOGRAM(URLCLASSIFIER_PS_FILELOAD_TIME, 1, 1000, 10, EXPONENTIAL, "Time spent loading PrefixSet from file (ms)")
|
||||
HISTOGRAM(URLCLASSIFIER_PS_CONSTRUCT_TIME, 1, 5000, 15, EXPONENTIAL, "Time spent constructing PrefixSet from DB (ms)")
|
||||
HISTOGRAM(URLCLASSIFIER_PS_LOOKUP_TIME, 1, 500, 10, EXPONENTIAL, "Time spent per PrefixSet lookup (ms)")
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Places telemetry.
|
||||
*/
|
||||
|
@ -53,6 +53,7 @@ XPIDLSRCS = \
|
||||
nsIUrlClassifierDBService.idl \
|
||||
nsIUrlClassifierHashCompleter.idl \
|
||||
nsIUrlClassifierStreamUpdater.idl \
|
||||
nsIUrlClassifierPrefixSet.idl \
|
||||
nsIUrlClassifierUtils.idl \
|
||||
nsIUrlListManager.idl \
|
||||
$(NULL)
|
||||
@ -61,6 +62,7 @@ CPPSRCS = \
|
||||
nsUrlClassifierDBService.cpp \
|
||||
nsUrlClassifierStreamUpdater.cpp \
|
||||
nsUrlClassifierUtils.cpp \
|
||||
nsUrlClassifierPrefixSet.cpp \
|
||||
nsUrlClassifierProxies.cpp \
|
||||
$(NULL)
|
||||
|
||||
|
@ -0,0 +1,21 @@
|
||||
#include "nsISupports.idl"
|
||||
#include "nsIFile.idl"
|
||||
|
||||
interface nsIArray;
|
||||
|
||||
[scriptable, uuid(42ef1d52-3351-4973-98f8-d18f089bccfa)]
|
||||
interface nsIUrlClassifierPrefixSet : nsISupports
|
||||
{
|
||||
void setPrefixes([const, array, size_is(aLength)] in unsigned long aPrefixes,
|
||||
in unsigned long aLength);
|
||||
void addPrefixes([const, array, size_is(aLength)] in unsigned long aPrefixes,
|
||||
in unsigned long aLength);
|
||||
boolean contains(in unsigned long aPrefix);
|
||||
boolean probe(in unsigned long aPrefix, in unsigned long aKey,
|
||||
inout boolean aReady);
|
||||
PRUint32 estimateSize();
|
||||
PRUint32 getKey();
|
||||
boolean isEmpty();
|
||||
void loadFromFile(in nsIFile aFile);
|
||||
void storeToFile(in nsIFile aFile);
|
||||
};
|
@ -45,10 +45,13 @@
|
||||
#include "nsID.h"
|
||||
#include "nsInterfaceHashtable.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsUrlClassifierPrefixSet.h"
|
||||
#include "nsIUrlClassifierHashCompleter.h"
|
||||
#include "nsIUrlClassifierDBService.h"
|
||||
#include "nsIURIClassifier.h"
|
||||
#include "nsToolkitCompsCID.h"
|
||||
#include "nsICryptoHash.h"
|
||||
#include "nsICryptoHMAC.h"
|
||||
|
||||
// The hash length for a domain key.
|
||||
#define DOMAIN_LENGTH 4
|
||||
@ -99,9 +102,13 @@ private:
|
||||
nsresult LookupURI(nsIURI* uri, nsIUrlClassifierCallback* c,
|
||||
PRBool forceCheck, PRBool *didCheck);
|
||||
|
||||
// Close db connection and join the background thread if it exists.
|
||||
// Close db connection and join the background thread if it exists.
|
||||
nsresult Shutdown();
|
||||
|
||||
|
||||
// Check if the key is on a known-clean host.
|
||||
nsresult CheckClean(const nsACString &lookupKey,
|
||||
PRBool *clean);
|
||||
|
||||
nsCOMPtr<nsUrlClassifierDBServiceWorker> mWorker;
|
||||
nsCOMPtr<nsIUrlClassifierDBServiceWorker> mWorkerProxy;
|
||||
|
||||
@ -124,6 +131,10 @@ private:
|
||||
// The list of tables that can use the default hash completer object.
|
||||
nsTArray<nsCString> mGethashWhitelist;
|
||||
|
||||
// Set of prefixes known to be in the database
|
||||
nsRefPtr<nsUrlClassifierPrefixSet> mPrefixSet;
|
||||
nsCOMPtr<nsICryptoHash> mHash;
|
||||
|
||||
// Thread that we do the updates on.
|
||||
static nsIThread* gDbBackgroundThread;
|
||||
};
|
||||
|
439
toolkit/components/url-classifier/nsUrlClassifierPrefixSet.cpp
Normal file
@ -0,0 +1,439 @@
|
||||
//* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Url Classifier code
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Gian-Carlo Pascutto <gpascutto@mozilla.com>
|
||||
* Mehdi Mulani <mars.martian+bugmail@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsUrlClassifierPrefixSet.h"
|
||||
#include "nsIUrlClassifierPrefixSet.h"
|
||||
#include "nsIRandomGenerator.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsILocalFile.h"
|
||||
#include "nsToolkitCompsCID.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/FileUtils.h"
|
||||
#include "prlog.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
// NSPR_LOG_MODULES=UrlClassifierPrefixSet:5
|
||||
#if defined(PR_LOGGING)
|
||||
static const PRLogModuleInfo *gUrlClassifierPrefixSetLog = nsnull;
|
||||
#define LOG(args) PR_LOG(gUrlClassifierPrefixSetLog, PR_LOG_DEBUG, args)
|
||||
#define LOG_ENABLED() PR_LOG_TEST(gUrlClassifierPrefixSetLog, 4)
|
||||
#else
|
||||
#define LOG(args)
|
||||
#define LOG_ENABLED() (PR_FALSE)
|
||||
#endif
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsUrlClassifierPrefixSet, nsIUrlClassifierPrefixSet)
|
||||
|
||||
nsUrlClassifierPrefixSet::nsUrlClassifierPrefixSet()
|
||||
: mPrefixSetLock("mPrefixSetLock"),
|
||||
mSetIsReady(mPrefixSetLock, "mSetIsReady"),
|
||||
mHasPrefixes(PR_FALSE),
|
||||
mRandomKey(0)
|
||||
{
|
||||
#if defined(PR_LOGGING)
|
||||
if (!gUrlClassifierPrefixSetLog)
|
||||
gUrlClassifierPrefixSetLog = PR_NewLogModule("UrlClassifierPrefixSet");
|
||||
#endif
|
||||
|
||||
nsresult rv = InitKey();
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("Failed to initialize PrefixSet"));
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsUrlClassifierPrefixSet::InitKey()
|
||||
{
|
||||
nsCOMPtr<nsIRandomGenerator> rg =
|
||||
do_GetService("@mozilla.org/security/random-generator;1");
|
||||
NS_ENSURE_STATE(rg);
|
||||
|
||||
PRUint8 *temp;
|
||||
nsresult rv = rg->GenerateRandomBytes(sizeof(mRandomKey), &temp);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
memcpy(&mRandomKey, temp, sizeof(mRandomKey));
|
||||
NS_Free(temp);
|
||||
|
||||
LOG(("Initialized PrefixSet, key = %X", mRandomKey));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUrlClassifierPrefixSet::SetPrefixes(const PRUint32 * aArray, PRUint32 aLength)
|
||||
{
|
||||
{
|
||||
MutexAutoLock lock(mPrefixSetLock);
|
||||
if (mHasPrefixes) {
|
||||
LOG(("Clearing PrefixSet"));
|
||||
mDeltas.Clear();
|
||||
mIndexPrefixes.Clear();
|
||||
mIndexStarts.Clear();
|
||||
mHasPrefixes = PR_FALSE;
|
||||
}
|
||||
}
|
||||
if (aLength > 0) {
|
||||
// Ensure they are sorted before adding
|
||||
nsTArray<PRUint32> prefixes;
|
||||
prefixes.AppendElements(aArray, aLength);
|
||||
prefixes.Sort();
|
||||
AddPrefixes(prefixes.Elements(), prefixes.Length());
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUrlClassifierPrefixSet::AddPrefixes(const PRUint32 * prefixes, PRUint32 aLength)
|
||||
{
|
||||
if (aLength == 0) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsTArray<PRUint32> mNewIndexPrefixes(mIndexPrefixes);
|
||||
nsTArray<PRUint32> mNewIndexStarts(mIndexStarts);
|
||||
nsTArray<PRUint16> mNewDeltas(mDeltas);
|
||||
|
||||
mNewIndexPrefixes.AppendElement(prefixes[0]);
|
||||
mNewIndexStarts.AppendElement(mNewDeltas.Length());
|
||||
|
||||
PRUint32 numOfDeltas = 0;
|
||||
PRUint32 currentItem = prefixes[0];
|
||||
for (PRUint32 i = 1; i < aLength; i++) {
|
||||
if ((numOfDeltas >= DELTAS_LIMIT) ||
|
||||
(prefixes[i] - currentItem >= MAX_INDEX_DIFF)) {
|
||||
mNewIndexStarts.AppendElement(mNewDeltas.Length());
|
||||
mNewIndexPrefixes.AppendElement(prefixes[i]);
|
||||
numOfDeltas = 0;
|
||||
} else {
|
||||
PRUint16 delta = prefixes[i] - currentItem;
|
||||
mNewDeltas.AppendElement(delta);
|
||||
numOfDeltas++;
|
||||
}
|
||||
currentItem = prefixes[i];
|
||||
}
|
||||
|
||||
mNewIndexPrefixes.Compact();
|
||||
mNewIndexStarts.Compact();
|
||||
mNewDeltas.Compact();
|
||||
|
||||
LOG(("Total number of indices: %d", mNewIndexPrefixes.Length()));
|
||||
LOG(("Total number of deltas: %d", mNewDeltas.Length()));
|
||||
|
||||
MutexAutoLock lock(mPrefixSetLock);
|
||||
|
||||
// This just swaps some pointers
|
||||
mIndexPrefixes.SwapElements(mNewIndexPrefixes);
|
||||
mIndexStarts.SwapElements(mNewIndexStarts);
|
||||
mDeltas.SwapElements(mNewDeltas);
|
||||
|
||||
mHasPrefixes = PR_TRUE;
|
||||
mSetIsReady.NotifyAll();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRUint32 nsUrlClassifierPrefixSet::BinSearch(PRUint32 start,
|
||||
PRUint32 end,
|
||||
PRUint32 target)
|
||||
{
|
||||
while (start != end && end >= start) {
|
||||
PRUint32 i = start + ((end - start) >> 1);
|
||||
PRUint32 value = mIndexPrefixes[i];
|
||||
if (value < target) {
|
||||
start = i + 1;
|
||||
} else if (value > target) {
|
||||
end = i - 1;
|
||||
} else {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUrlClassifierPrefixSet::Contains(PRUint32 aPrefix, PRBool * aFound)
|
||||
{
|
||||
*aFound = PR_FALSE;
|
||||
|
||||
if (!mHasPrefixes) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PRUint32 target = aPrefix;
|
||||
|
||||
// We want to do a "Price is Right" binary search, that is, we want to find
|
||||
// the index of the value either equal to the target or the closest value
|
||||
// that is less than the target.
|
||||
//
|
||||
if (target < mIndexPrefixes[0]) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// |binsearch| does not necessarily return the correct index (when the
|
||||
// target is not found) but rather it returns an index at least one away
|
||||
// from the correct index.
|
||||
// Because of this, we need to check if the target lies before the beginning
|
||||
// of the indices.
|
||||
|
||||
PRUint32 i = BinSearch(0, mIndexPrefixes.Length() - 1, target);
|
||||
if (mIndexPrefixes[i] > target && i > 0) {
|
||||
i--;
|
||||
}
|
||||
|
||||
// Now search through the deltas for the target.
|
||||
PRUint32 diff = target - mIndexPrefixes[i];
|
||||
PRUint32 deltaIndex = mIndexStarts[i];
|
||||
PRUint32 end = (i + 1 < mIndexStarts.Length()) ? mIndexStarts[i+1]
|
||||
: mDeltas.Length();
|
||||
while (diff > 0 && deltaIndex < end) {
|
||||
diff -= mDeltas[deltaIndex];
|
||||
deltaIndex++;
|
||||
}
|
||||
|
||||
if (diff == 0) {
|
||||
*aFound = PR_TRUE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUrlClassifierPrefixSet::EstimateSize(PRUint32 * aSize)
|
||||
{
|
||||
MutexAutoLock lock(mPrefixSetLock);
|
||||
*aSize = sizeof(PRBool);
|
||||
if (mHasPrefixes) {
|
||||
*aSize += sizeof(PRUint16) * mDeltas.Length();
|
||||
*aSize += sizeof(PRUint32) * mIndexPrefixes.Length();
|
||||
*aSize += sizeof(PRUint32) * mIndexStarts.Length();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUrlClassifierPrefixSet::IsEmpty(PRBool * aEmpty)
|
||||
{
|
||||
MutexAutoLock lock(mPrefixSetLock);
|
||||
*aEmpty = !mHasPrefixes;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUrlClassifierPrefixSet::GetKey(PRUint32 * aKey)
|
||||
{
|
||||
MutexAutoLock lock(mPrefixSetLock);
|
||||
*aKey = mRandomKey;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUrlClassifierPrefixSet::Probe(PRUint32 aPrefix, PRUint32 aKey,
|
||||
PRBool* aReady, PRBool* aFound)
|
||||
{
|
||||
MutexAutoLock lock(mPrefixSetLock);
|
||||
|
||||
// We might have raced here with a LoadPrefixSet call,
|
||||
// loading a saved PrefixSet with another key than the one used to probe us.
|
||||
// This must occur exactly between the GetKey call and the Probe call.
|
||||
// This could cause a false negative immediately after browser start.
|
||||
// Claim we are still busy loading instead.
|
||||
if (aKey != mRandomKey) {
|
||||
LOG(("Potential race condition detected, avoiding"));
|
||||
*aReady = PR_FALSE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// check whether we are opportunistically probing or should wait
|
||||
if (*aReady) {
|
||||
// we should block until we are ready
|
||||
while (!mHasPrefixes) {
|
||||
LOG(("Set is empty, probe must wait"));
|
||||
mSetIsReady.Wait();
|
||||
}
|
||||
} else {
|
||||
// opportunistic probe -> check if set is loaded
|
||||
if (mHasPrefixes) {
|
||||
*aReady = PR_TRUE;
|
||||
} else {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv = Contains(aPrefix, aFound);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsUrlClassifierPrefixSet::LoadFromFd(AutoFDClose & fileFd)
|
||||
{
|
||||
PRUint32 magic;
|
||||
PRInt32 read;
|
||||
|
||||
read = PR_Read(fileFd, &magic, sizeof(PRUint32));
|
||||
NS_ENSURE_TRUE(read > 0, NS_ERROR_FAILURE);
|
||||
|
||||
if (magic == PREFIXSET_VERSION_MAGIC) {
|
||||
PRUint32 indexSize;
|
||||
PRUint32 deltaSize;
|
||||
|
||||
read = PR_Read(fileFd, &mRandomKey, sizeof(PRUint32));
|
||||
NS_ENSURE_TRUE(read > 0, NS_ERROR_FAILURE);
|
||||
read = PR_Read(fileFd, &indexSize, sizeof(PRUint32));
|
||||
NS_ENSURE_TRUE(read > 0, NS_ERROR_FAILURE);
|
||||
read = PR_Read(fileFd, &deltaSize, sizeof(PRUint32));
|
||||
NS_ENSURE_TRUE(read > 0, NS_ERROR_FAILURE);
|
||||
|
||||
if (indexSize == 0) {
|
||||
LOG(("stored PrefixSet is empty!"));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsTArray<PRUint32> mNewIndexPrefixes;
|
||||
nsTArray<PRUint32> mNewIndexStarts;
|
||||
nsTArray<PRUint16> mNewDeltas;
|
||||
|
||||
mNewIndexStarts.SetLength(indexSize);
|
||||
mNewIndexPrefixes.SetLength(indexSize);
|
||||
mNewDeltas.SetLength(deltaSize);
|
||||
|
||||
read = PR_Read(fileFd, mNewIndexPrefixes.Elements(), indexSize*sizeof(PRUint32));
|
||||
NS_ENSURE_TRUE(read > 0, NS_ERROR_FAILURE);
|
||||
read = PR_Read(fileFd, mNewIndexStarts.Elements(), indexSize*sizeof(PRUint32));
|
||||
NS_ENSURE_TRUE(read > 0, NS_ERROR_FAILURE);
|
||||
if (deltaSize > 0) {
|
||||
read = PR_Read(fileFd, mNewDeltas.Elements(), deltaSize*sizeof(PRUint16));
|
||||
NS_ENSURE_TRUE(read > 0, NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
MutexAutoLock lock(mPrefixSetLock);
|
||||
|
||||
mIndexPrefixes.SwapElements(mNewIndexPrefixes);
|
||||
mIndexStarts.SwapElements(mNewIndexStarts);
|
||||
mDeltas.SwapElements(mNewDeltas);
|
||||
|
||||
mHasPrefixes = PR_TRUE;
|
||||
mSetIsReady.NotifyAll();
|
||||
} else {
|
||||
LOG(("Version magic mismatch, not loading"));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
LOG(("Loading PrefixSet successful"));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUrlClassifierPrefixSet::LoadFromFile(nsIFile * aFile)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsILocalFile> file(do_QueryInterface(aFile, &rv));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
AutoFDClose fileFd;
|
||||
rv = file->OpenNSPRFileDesc(PR_RDONLY, 0, &fileFd);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return LoadFromFd(fileFd);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsUrlClassifierPrefixSet::StoreToFd(AutoFDClose & fileFd)
|
||||
{
|
||||
PRInt32 written;
|
||||
PRUint32 magic = PREFIXSET_VERSION_MAGIC;
|
||||
written = PR_Write(fileFd, &magic, sizeof(PRUint32));
|
||||
NS_ENSURE_TRUE(written > 0, NS_ERROR_FAILURE);
|
||||
|
||||
written = PR_Write(fileFd, &mRandomKey, sizeof(PRUint32));
|
||||
NS_ENSURE_TRUE(written > 0, NS_ERROR_FAILURE);
|
||||
|
||||
PRUint32 indexSize = mIndexStarts.Length();
|
||||
PRUint32 deltaSize = mDeltas.Length();
|
||||
written = PR_Write(fileFd, &indexSize, sizeof(PRUint32));
|
||||
NS_ENSURE_TRUE(written > 0, NS_ERROR_FAILURE);
|
||||
written = PR_Write(fileFd, &deltaSize, sizeof(PRUint32));
|
||||
NS_ENSURE_TRUE(written > 0, NS_ERROR_FAILURE);
|
||||
|
||||
written = PR_Write(fileFd, mIndexPrefixes.Elements(), indexSize * sizeof(PRUint32));
|
||||
NS_ENSURE_TRUE(written > 0, NS_ERROR_FAILURE);
|
||||
written = PR_Write(fileFd, mIndexStarts.Elements(), indexSize * sizeof(PRUint32));
|
||||
NS_ENSURE_TRUE(written > 0, NS_ERROR_FAILURE);
|
||||
if (deltaSize > 0) {
|
||||
written = PR_Write(fileFd, mDeltas.Elements(), deltaSize * sizeof(PRUint16));
|
||||
NS_ENSURE_TRUE(written > 0, NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
LOG(("Saving PrefixSet successful\n"));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUrlClassifierPrefixSet::StoreToFile(nsIFile * aFile)
|
||||
{
|
||||
if (!mHasPrefixes) {
|
||||
LOG(("Attempt to serialize empty PrefixSet"));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsILocalFile> file(do_QueryInterface(aFile, &rv));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
AutoFDClose fileFd;
|
||||
rv = file->OpenNSPRFileDesc(PR_RDWR | PR_TRUNCATE | PR_CREATE_FILE,
|
||||
0644, &fileFd);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
MutexAutoLock lock(mPrefixSetLock);
|
||||
|
||||
return StoreToFd(fileFd);
|
||||
}
|
108
toolkit/components/url-classifier/nsUrlClassifierPrefixSet.h
Normal file
@ -0,0 +1,108 @@
|
||||
//* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Url Classifier code
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Gian-Carlo Pascutto <gpascutto@mozilla.com>
|
||||
* Mehdi Mulani <mars.martian+bugmail@gmail.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsUrlClassifierPrefixSet_h_
|
||||
#define nsUrlClassifierPrefixSet_h_
|
||||
|
||||
#include "nsISupportsUtils.h"
|
||||
#include "nsID.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIUrlClassifierPrefixSet.h"
|
||||
#include "nsToolkitCompsCID.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/CondVar.h"
|
||||
#include "mozilla/FileUtils.h"
|
||||
|
||||
class nsUrlClassifierPrefixSet : public nsIUrlClassifierPrefixSet
|
||||
{
|
||||
public:
|
||||
nsUrlClassifierPrefixSet();
|
||||
virtual ~nsUrlClassifierPrefixSet() {};
|
||||
|
||||
// Can send an empty Array to clean the tree
|
||||
NS_IMETHOD SetPrefixes(const PRUint32* aArray, PRUint32 aLength);
|
||||
// Given prefixes must be in sorted order and bigger than
|
||||
// anything currently in the Prefix Set
|
||||
NS_IMETHOD AddPrefixes(const PRUint32* aArray, PRUint32 aLength);
|
||||
// Does the PrefixSet contain this prefix? not thread-safe
|
||||
NS_IMETHOD Contains(PRUint32 aPrefix, PRBool* aFound);
|
||||
// Do a lookup in the PrefixSet
|
||||
// if aReady is set, we will block until there are any entries
|
||||
// if not set, we will return in aReady whether we were ready or not
|
||||
NS_IMETHOD Probe(PRUint32 aPrefix, PRUint32 aKey, PRBool* aReady, PRBool* aFound);
|
||||
// Return the estimated size of the set on disk and in memory,
|
||||
// in bytes
|
||||
NS_IMETHOD EstimateSize(PRUint32* aSize);
|
||||
NS_IMETHOD IsEmpty(PRBool * aEmpty);
|
||||
NS_IMETHOD LoadFromFile(nsIFile* aFile);
|
||||
NS_IMETHOD StoreToFile(nsIFile* aFile);
|
||||
// Return a key that is used to randomize the collisions in the prefixes
|
||||
NS_IMETHOD GetKey(PRUint32* aKey);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
protected:
|
||||
static const PRUint32 DELTAS_LIMIT = 100;
|
||||
static const PRUint32 MAX_INDEX_DIFF = (1 << 16);
|
||||
static const PRUint32 PREFIXSET_VERSION_MAGIC = 1;
|
||||
|
||||
mozilla::Mutex mPrefixSetLock;
|
||||
mozilla::CondVar mSetIsReady;
|
||||
|
||||
PRUint32 BinSearch(PRUint32 start, PRUint32 end, PRUint32 target);
|
||||
nsresult LoadFromFd(mozilla::AutoFDClose & fileFd);
|
||||
nsresult StoreToFd(mozilla::AutoFDClose & fileFd);
|
||||
nsresult InitKey();
|
||||
|
||||
// boolean indicating whether |setPrefixes| has been
|
||||
// called with a non-empty array.
|
||||
PRBool mHasPrefixes;
|
||||
// key used to randomize hash collisions
|
||||
PRUint32 mRandomKey;
|
||||
// the prefix for each index.
|
||||
nsTArray<PRUint32> mIndexPrefixes;
|
||||
// the value corresponds to the beginning of the run
|
||||
// (an index in |_deltas|) for the index
|
||||
nsTArray<PRUint32> mIndexStarts;
|
||||
// array containing deltas from indices.
|
||||
nsTArray<PRUint16> mDeltas;
|
||||
};
|
||||
|
||||
#endif
|
@ -124,125 +124,4 @@ private:
|
||||
nsAutoPtr<Charmap> mEscapeCharmap;
|
||||
};
|
||||
|
||||
// An MRU list of fragments. This is used by the DB service to
|
||||
// keep a set of known-clean fragments that don't need a database
|
||||
// lookup.
|
||||
class nsUrlClassifierFragmentSet
|
||||
{
|
||||
public:
|
||||
nsUrlClassifierFragmentSet() : mFirst(nsnull), mLast(nsnull), mCapacity(16) {}
|
||||
|
||||
PRBool Init(PRUint32 maxEntries) {
|
||||
mCapacity = maxEntries;
|
||||
if (!mEntryStorage.SetCapacity(mCapacity))
|
||||
return PR_FALSE;
|
||||
|
||||
if (!mEntries.Init())
|
||||
return PR_FALSE;
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool Put(const nsACString &fragment) {
|
||||
Entry *entry = nsnull;
|
||||
if (mEntries.Get(fragment, &entry)) {
|
||||
// Remove this entry from the list, we'll add it back
|
||||
// to the front.
|
||||
UnlinkEntry(entry);
|
||||
} else {
|
||||
if (mEntryStorage.Length() < mEntryStorage.Capacity()) {
|
||||
entry = mEntryStorage.AppendElement();
|
||||
if (!entry)
|
||||
return PR_FALSE;
|
||||
} else {
|
||||
// Reuse the oldest entry.
|
||||
entry = mLast;
|
||||
UnlinkEntry(entry);
|
||||
mEntries.Remove(entry->mFragment);
|
||||
}
|
||||
entry->mFragment = fragment;
|
||||
mEntries.Put(fragment, entry);
|
||||
}
|
||||
|
||||
LinkEntry(entry);
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool Has(const nsACString &fragment, PRBool update = PR_TRUE) {
|
||||
Entry *entry = nsnull;
|
||||
PRBool exists = mEntries.Get(fragment, &entry);
|
||||
// Move this entry to the front of the list (if it isn't already there)
|
||||
if (update && exists && entry != mFirst) {
|
||||
UnlinkEntry(entry);
|
||||
LinkEntry(entry);
|
||||
}
|
||||
|
||||
return exists;
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
mFirst = mLast = nsnull;
|
||||
mEntries.Clear();
|
||||
mEntryStorage.Clear();
|
||||
mEntryStorage.SetCapacity(mCapacity);
|
||||
}
|
||||
|
||||
private:
|
||||
// One entry in the set. We maintain a doubly-linked list, with
|
||||
// the most recently used entry at the front.
|
||||
class Entry {
|
||||
public:
|
||||
Entry() : mNext(nsnull), mPrev(nsnull) {};
|
||||
~Entry() { }
|
||||
|
||||
Entry *mNext;
|
||||
Entry *mPrev;
|
||||
nsCString mFragment;
|
||||
};
|
||||
|
||||
void LinkEntry(Entry *entry)
|
||||
{
|
||||
// Add the entry to the front of the list
|
||||
entry->mPrev = nsnull;
|
||||
entry->mNext = mFirst;
|
||||
if (mFirst) {
|
||||
mFirst->mPrev = entry;
|
||||
}
|
||||
mFirst = entry;
|
||||
if (!mLast) {
|
||||
mLast = entry;
|
||||
}
|
||||
}
|
||||
|
||||
void UnlinkEntry(Entry *entry)
|
||||
{
|
||||
if (entry->mPrev)
|
||||
entry->mPrev->mNext = entry->mNext;
|
||||
else
|
||||
mFirst = entry->mNext;
|
||||
|
||||
if (entry->mNext)
|
||||
entry->mNext->mPrev = entry->mPrev;
|
||||
else
|
||||
mLast = entry->mPrev;
|
||||
|
||||
entry->mPrev = entry->mNext = nsnull;
|
||||
}
|
||||
|
||||
// The newest entry in the cache.
|
||||
Entry *mFirst;
|
||||
// The oldest entry in the cache.
|
||||
Entry *mLast;
|
||||
|
||||
// Max entries in the cache.
|
||||
PRUint32 mCapacity;
|
||||
|
||||
// Storage for the entries in this set.
|
||||
nsTArray<Entry> mEntryStorage;
|
||||
|
||||
// Entry lookup by fragment.
|
||||
nsDataHashtable<nsCStringHashKey, Entry*> mEntries;
|
||||
};
|
||||
|
||||
#endif // nsUrlClassifierUtils_h_
|
||||
|
@ -1,3 +1,4 @@
|
||||
//* -*- Mode: Javascript; tab-width: 8; indent-tabs-mode: nil; js-indent-level: 2 -*- *
|
||||
function dumpn(s) {
|
||||
dump(s + "\n");
|
||||
}
|
||||
@ -277,6 +278,8 @@ function runNextTest()
|
||||
dbservice.setHashCompleter('test-phish-simple', null);
|
||||
dumpn("running " + gTests[gNextTest]);
|
||||
|
||||
dump("running " + gTests[gNextTest]);
|
||||
|
||||
gTests[gNextTest++]();
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
//* -*- Mode: Javascript; tab-width: 8; indent-tabs-mode: nil; js-indent-level: 2 -*- *
|
||||
// Test an add of two urls to a fresh database
|
||||
function testCleanHostKeys() {
|
||||
var addUrls = [ "foo.com/a" ];
|
||||
@ -24,45 +25,12 @@ function testCleanHostKeys() {
|
||||
});
|
||||
// second call shouldn't result in a callback.
|
||||
do_check_eq(result2, false);
|
||||
|
||||
runNextTest();
|
||||
do_throw("shouldn't get a callback");
|
||||
});
|
||||
|
||||
// The first classifier call should result in a callback.
|
||||
do_check_eq(result, true);
|
||||
}, updateError);
|
||||
}
|
||||
|
||||
// Test an add of two urls to a fresh database
|
||||
function testDirtyHostKeys() {
|
||||
var addUrls = [ "foo.com/a" ];
|
||||
var update = buildPhishingUpdate(
|
||||
[
|
||||
{ "chunkNum" : 1,
|
||||
"urls" : addUrls
|
||||
}]);
|
||||
|
||||
doStreamUpdate(update, function() {
|
||||
var ios = Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService);
|
||||
|
||||
// Check with a dirty host key - both checks should happen.
|
||||
var uri = ios.newURI("http://foo.com/b", null, null);
|
||||
|
||||
// Use the nsIURIClassifier interface (the
|
||||
// nsIUrlClassifierDBService will always queue a lookup,
|
||||
// nsIURIClassifier won't if the host key is known to be clean.
|
||||
var classifier = dbservice.QueryInterface(Ci.nsIURIClassifier);
|
||||
var result = classifier.classify(uri, function(errorCode) {
|
||||
var result2 = classifier.classify(uri, function() {
|
||||
runNextTest();
|
||||
});
|
||||
// second call should result in a callback.
|
||||
do_check_eq(result2, true);
|
||||
});
|
||||
|
||||
// The first classifier call should result in a callback.
|
||||
do_check_eq(result, true);
|
||||
// The first classifier call will not result in a callback
|
||||
do_check_eq(result, false);
|
||||
runNextTest();
|
||||
}, updateError);
|
||||
}
|
||||
|
||||
@ -71,109 +39,128 @@ function testUpdate() {
|
||||
var ios = Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService);
|
||||
|
||||
// First lookup should happen...
|
||||
var uri = ios.newURI("http://foo.com/a", null, null);
|
||||
// Must put something in the PrefixSet
|
||||
var preUrls = [ "foo.com/b" ];
|
||||
var preUpdate = buildPhishingUpdate(
|
||||
[
|
||||
{ "chunkNum" : 1,
|
||||
"urls" : preUrls
|
||||
}]);
|
||||
|
||||
// Use the nsIURIClassifier interface (the
|
||||
// nsIUrlClassifierDBService will always queue a lookup,
|
||||
// nsIURIClassifier won't if the host key is known to be clean.
|
||||
var classifier = dbservice.QueryInterface(Ci.nsIURIClassifier);
|
||||
var result = classifier.classify(uri, function(errorCode) {
|
||||
// This check will succeed, which will cause the key to
|
||||
// be put in the clean host key cache...
|
||||
doStreamUpdate(preUpdate, function() {
|
||||
// First lookup won't happen...
|
||||
var uri = ios.newURI("http://foo.com/a", null, null);
|
||||
|
||||
// Use the nsIURIClassifier interface (the
|
||||
// nsIUrlClassifierDBService will always queue a lookup,
|
||||
// nsIURIClassifier won't if the host key is known to be clean.
|
||||
var classifier = dbservice.QueryInterface(Ci.nsIURIClassifier);
|
||||
var result = classifier.classify(uri, function(errorCode) {
|
||||
// shouldn't arrive here
|
||||
do_check_eq(errorCode, Cr.NS_OK);
|
||||
|
||||
// Now add the url to the db...
|
||||
var addUrls = [ "foo.com/a" ];
|
||||
var update = buildPhishingUpdate(
|
||||
[
|
||||
{ "chunkNum" : 1,
|
||||
"urls" : addUrls
|
||||
}]);
|
||||
doStreamUpdate(update, function() {
|
||||
// The clean key cache should be blown now that we've
|
||||
// added, and this callback should execute.
|
||||
var result2 = classifier.classify(uri, function(errorCode) {
|
||||
do_check_neq(errorCode, Cr.NS_OK);
|
||||
runNextTest();
|
||||
});
|
||||
// second call should result in a callback.
|
||||
do_check_eq(result2, true);
|
||||
}, updateError);
|
||||
do_throw("shouldn't get a callback");
|
||||
});
|
||||
do_check_eq(result, false);
|
||||
|
||||
// Now add the url to the db...
|
||||
var addUrls = [ "foo.com/a" ];
|
||||
var update = buildPhishingUpdate(
|
||||
[
|
||||
{ "chunkNum" : 2,
|
||||
"urls" : addUrls
|
||||
}]);
|
||||
doStreamUpdate(update, function() {
|
||||
var result2 = classifier.classify(uri, function(errorCode) {
|
||||
do_check_neq(errorCode, Cr.NS_OK);
|
||||
runNextTest();
|
||||
});
|
||||
// second call should result in a callback.
|
||||
do_check_eq(result2, true);
|
||||
}, updateError);
|
||||
}, updateError);
|
||||
}
|
||||
|
||||
function testResetFullCache() {
|
||||
// First do enough queries to fill up the clean hostkey cache
|
||||
var ios = Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService);
|
||||
// Must put something in the PrefixSet
|
||||
var preUrls = [ "zaz.com/b" ];
|
||||
var preUpdate = buildPhishingUpdate(
|
||||
[
|
||||
{ "chunkNum" : 1,
|
||||
"urls" : preUrls
|
||||
}]);
|
||||
|
||||
// Use the nsIURIClassifier interface (the
|
||||
// nsIUrlClassifierDBService will always queue a lookup,
|
||||
// nsIURIClassifier won't if the host key is known to be clean.
|
||||
var classifier = dbservice.QueryInterface(Ci.nsIURIClassifier);
|
||||
doStreamUpdate(preUpdate, function() {
|
||||
// First do enough queries to fill up the clean hostkey cache
|
||||
var ios = Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService);
|
||||
|
||||
var uris1 = [
|
||||
"www.foo.com/",
|
||||
"www.bar.com/",
|
||||
"www.blah.com/",
|
||||
"www.site.com/",
|
||||
"www.example.com/",
|
||||
"www.test.com/",
|
||||
"www.malware.com/",
|
||||
"www.phishing.com/",
|
||||
"www.clean.com/" ];
|
||||
// Use the nsIURIClassifier interface (the
|
||||
// nsIUrlClassifierDBService will always queue a lookup,
|
||||
// nsIURIClassifier won't if the host key is known to be clean.
|
||||
var classifier = dbservice.QueryInterface(Ci.nsIURIClassifier);
|
||||
|
||||
var uris2 = [];
|
||||
var uris1 = [
|
||||
"www.foo.com/",
|
||||
"www.bar.com/",
|
||||
"www.blah.com/",
|
||||
"www.site.com/",
|
||||
"www.example.com/",
|
||||
"www.test.com/",
|
||||
"www.malware.com/",
|
||||
"www.phishing.com/",
|
||||
"www.clean.com/" ];
|
||||
|
||||
var runSecondLookup = function() {
|
||||
if (uris2.length == 0) {
|
||||
runNextTest();
|
||||
return;
|
||||
var uris2 = [];
|
||||
|
||||
var runSecondLookup = function() {
|
||||
if (uris2.length == 0) {
|
||||
runNextTest();
|
||||
return;
|
||||
}
|
||||
|
||||
var spec = uris2.pop();
|
||||
var uri = ios.newURI("http://" + spec, null, null);
|
||||
|
||||
var result = classifier.classify(uri, function(errorCode) {
|
||||
});
|
||||
runSecondLookup();
|
||||
// now look up a few more times.
|
||||
}
|
||||
|
||||
var spec = uris2.pop();
|
||||
var uri = ios.newURI("http://" + spec, null, null);
|
||||
|
||||
var result = classifier.classify(uri, function(errorCode) {
|
||||
runSecondLookup();
|
||||
});
|
||||
// now look up a few more times.
|
||||
}
|
||||
|
||||
var runInitialLookup = function() {
|
||||
if (uris1.length == 0) {
|
||||
// We're done filling up the cache. Run an update to flush it,
|
||||
// then start lookup up again.
|
||||
var addUrls = [ "notgoingtocheck.com/a" ];
|
||||
var update = buildPhishingUpdate(
|
||||
[
|
||||
{ "chunkNum" : 1,
|
||||
"urls" : addUrls
|
||||
}]);
|
||||
doStreamUpdate(update, function() {
|
||||
var runInitialLookup = function() {
|
||||
if (uris1.length == 0) {
|
||||
// We're done filling up the cache. Run an update to flush it,
|
||||
// then start lookup up again.
|
||||
var addUrls = [ "notgoingtocheck.com/a" ];
|
||||
var update = buildPhishingUpdate(
|
||||
[
|
||||
{ "chunkNum" : 1,
|
||||
"urls" : addUrls
|
||||
}]);
|
||||
doStreamUpdate(update, function() {
|
||||
runSecondLookup();
|
||||
}, updateError);
|
||||
return;
|
||||
}
|
||||
var spec = uris1.pop();
|
||||
return;
|
||||
}
|
||||
var spec = uris1.pop();
|
||||
|
||||
uris2.push(spec);
|
||||
var uri = ios.newURI("http://" + spec, null, null);
|
||||
var result = classifier.classify(uri, function(errorCode) {
|
||||
runInitialLookup();
|
||||
uris2.push(spec);
|
||||
var uri = ios.newURI("http://" + spec, null, null);
|
||||
var result = classifier.classify(uri, function(errorCode) {
|
||||
});
|
||||
// All of these classifications should succeed.
|
||||
do_check_eq(result, true);
|
||||
if (result) {
|
||||
doNextTest();
|
||||
runInitialLookup();
|
||||
// None of these will generate a callback
|
||||
do_check_eq(result, false);
|
||||
if (!result) {
|
||||
doNextTest();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// XXX bug 457790: dbservice.resetDatabase() doesn't have a way to
|
||||
// wait to make sure it has been applied. Until this is added, we'll
|
||||
// just use a timeout.
|
||||
var t = new Timer(3000, runInitialLookup);
|
||||
// XXX bug 457790: dbservice.resetDatabase() doesn't have a way to
|
||||
// wait to make sure it has been applied. Until this is added, we'll
|
||||
// just use a timeout.
|
||||
var t = new Timer(3000, runInitialLookup);
|
||||
}, updateError);
|
||||
}
|
||||
|
||||
function testBug475436() {
|
||||
@ -200,7 +187,6 @@ function run_test()
|
||||
// directly after dbservice.resetDatabase().
|
||||
testUpdate,
|
||||
testCleanHostKeys,
|
||||
testDirtyHostKeys,
|
||||
testResetFullCache,
|
||||
testBug475436
|
||||
]);
|
||||
|
@ -87,12 +87,12 @@ compareQueries: function(fragments)
|
||||
for (var i = 0; i < fragments.length; i++) {
|
||||
expectedQueries.push(this.getHash(fragments[i]).slice(0, 4));
|
||||
}
|
||||
do_check_eq(this.queries.length, expectedQueries.length);
|
||||
expectedQueries.sort();
|
||||
this.queries.sort();
|
||||
for (var i = 0; i < this.queries.length; i++) {
|
||||
do_check_eq(this.queries[i], expectedQueries[i]);
|
||||
}
|
||||
do_check_eq(this.queries.length, expectedQueries.length);
|
||||
}
|
||||
};
|
||||
|
||||
@ -421,15 +421,23 @@ function testInvalidHashSize()
|
||||
}],
|
||||
12); // only 4 and 32 are legal hash sizes
|
||||
|
||||
var addUrls2 = [ "zaz.com/a", "xyz.com/b" ];
|
||||
var update2 = buildPhishingUpdate(
|
||||
[
|
||||
{ "chunkNum" : 2,
|
||||
"urls" : addUrls2
|
||||
}],
|
||||
4);
|
||||
|
||||
var completer = installCompleter('test-phish-simple', [[1, addUrls]], []);
|
||||
|
||||
var assertions = {
|
||||
"tableData" : "",
|
||||
"tableData" : "test-phish-simple;a:2",
|
||||
"urlsDontExist" : addUrls
|
||||
};
|
||||
|
||||
// A successful update will trigger an error
|
||||
doUpdateTest([update], assertions, updateError, runNextTest);
|
||||
doUpdateTest([update2, update], assertions, updateError, runNextTest);
|
||||
}
|
||||
|
||||
function testWrongTable()
|
||||
|
168
toolkit/components/url-classifier/tests/unit/test_prefixset.js
Normal file
@ -0,0 +1,168 @@
|
||||
// newPset: returns an empty nsIUrlClassifierPrefixSet.
|
||||
function newPset() {
|
||||
return Cc["@mozilla.org/url-classifier/prefixset;1"]
|
||||
.createInstance(Ci.nsIUrlClassifierPrefixSet);
|
||||
}
|
||||
|
||||
// arrContains: returns true if |arr| contains the element |target|. Uses binary
|
||||
// search and requires |arr| to be sorted.
|
||||
function arrContains(arr, target) {
|
||||
let start = 0;
|
||||
let end = arr.length - 1;
|
||||
let i = 0;
|
||||
|
||||
while (end > start) {
|
||||
i = start + (end - start >> 1);
|
||||
let value = arr[i];
|
||||
|
||||
if (value < target)
|
||||
start = i+1;
|
||||
else if (value > target)
|
||||
end = i-1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (start == end)
|
||||
i = start;
|
||||
|
||||
return (!(i < 0 || i >= arr.length) && arr[i] == target);
|
||||
}
|
||||
|
||||
// doRandomLookups: we use this to test for false membership with random input
|
||||
// over the range of prefixes (unsigned 32-bits integers).
|
||||
// pset: a nsIUrlClassifierPrefixSet to test.
|
||||
// prefixes: an array of prefixes supposed to make up the prefix set.
|
||||
// N: number of random lookups to make.
|
||||
function doRandomLookups(pset, prefixes, N) {
|
||||
for (let i = 0; i < N; i++) {
|
||||
let randInt = prefixes[0];
|
||||
while (arrContains(prefixes, randInt))
|
||||
randInt = Math.floor(Math.random() * Math.pow(2, 32));
|
||||
|
||||
do_check_false(pset.contains(randInt));
|
||||
}
|
||||
}
|
||||
|
||||
// doExpectedLookups: we use this to test expected membership.
|
||||
// pset: a nsIUrlClassifierPrefixSet to test.
|
||||
// prefixes:
|
||||
function doExpectedLookups(pset, prefixes, N) {
|
||||
for (let i = 0; i < N; i++) {
|
||||
prefixes.forEach(function (x) {
|
||||
dump("Checking " + x + "\n");
|
||||
do_check_true(pset.contains(x));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// testBasicPset: A very basic test of the prefix set to make sure that it
|
||||
// exists and to give a basic example of its use.
|
||||
function testBasicPset() {
|
||||
let pset = Cc["@mozilla.org/url-classifier/prefixset;1"]
|
||||
.createInstance(Ci.nsIUrlClassifierPrefixSet);
|
||||
let prefixes = [2,100,50,2000,78000,1593203];
|
||||
pset.setPrefixes(prefixes, prefixes.length);
|
||||
|
||||
do_check_true(pset.contains(100));
|
||||
do_check_false(pset.contains(100000));
|
||||
do_check_true(pset.contains(1593203));
|
||||
do_check_false(pset.contains(999));
|
||||
do_check_false(pset.contains(0));
|
||||
}
|
||||
|
||||
function testDuplicates() {
|
||||
let pset = Cc["@mozilla.org/url-classifier/prefixset;1"]
|
||||
.createInstance(Ci.nsIUrlClassifierPrefixSet);
|
||||
let prefixes = [1,1,2,2,2,3,3,3,3,3,3,5,6,6,7,7,9,9,9];
|
||||
pset.setPrefixes(prefixes, prefixes.length);
|
||||
|
||||
do_check_true(pset.contains(1));
|
||||
do_check_true(pset.contains(2));
|
||||
do_check_true(pset.contains(5));
|
||||
do_check_true(pset.contains(9));
|
||||
do_check_false(pset.contains(4));
|
||||
do_check_false(pset.contains(8));
|
||||
}
|
||||
|
||||
function testSimplePset() {
|
||||
let pset = newPset();
|
||||
let prefixes = [1,2,100,400,123456789];
|
||||
pset.setPrefixes(prefixes, prefixes.length);
|
||||
|
||||
doRandomLookups(pset, prefixes, 100);
|
||||
doExpectedLookups(pset, prefixes, 1);
|
||||
}
|
||||
|
||||
function testUnsortedPset() {
|
||||
let pset = newPset();
|
||||
let prefixes = [5,1,20,100,200000,100000];
|
||||
pset.setPrefixes(prefixes, prefixes.length);
|
||||
|
||||
doRandomLookups(pset, prefixes, 100);
|
||||
doExpectedLookups(pset, prefixes, 1);
|
||||
}
|
||||
|
||||
function testReSetPrefixes() {
|
||||
let pset = newPset();
|
||||
let prefixes = [1, 5, 100, 1000, 150000];
|
||||
pset.setPrefixes(prefixes, prefixes.length);
|
||||
|
||||
doExpectedLookups(pset, prefixes, 1);
|
||||
|
||||
let secondPrefixes = [12, 50, 300, 2000, 5000, 200000];
|
||||
pset.setPrefixes(secondPrefixes, secondPrefixes.length);
|
||||
|
||||
doExpectedLookups(pset, secondPrefixes, 1);
|
||||
for (let i = 0; i < prefixes.length; i++) {
|
||||
do_check_false(pset.contains(prefixes[i]));
|
||||
}
|
||||
}
|
||||
|
||||
function testLargeSet() {
|
||||
let N = 1000;
|
||||
let arr = [];
|
||||
|
||||
for (let i = 0; i < N; i++) {
|
||||
let randInt = Math.floor(Math.random() * Math.pow(2, 32));
|
||||
arr.push(randInt);
|
||||
}
|
||||
|
||||
arr.sort(function(x,y) x - y);
|
||||
|
||||
let pset = newPset();
|
||||
pset.setPrefixes(arr, arr.length);
|
||||
|
||||
doExpectedLookups(pset, arr, 1);
|
||||
doRandomLookups(pset, arr, 1000);
|
||||
}
|
||||
|
||||
function testTinySet() {
|
||||
let pset = Cc["@mozilla.org/url-classifier/prefixset;1"]
|
||||
.createInstance(Ci.nsIUrlClassifierPrefixSet);
|
||||
let prefixes = [1];
|
||||
pset.setPrefixes(prefixes, prefixes.length);
|
||||
|
||||
do_check_true(pset.contains(1));
|
||||
do_check_false(pset.contains(100000));
|
||||
|
||||
prefixes = [];
|
||||
pset.setPrefixes(prefixes, prefixes.length);
|
||||
do_check_false(pset.contains(1));
|
||||
}
|
||||
|
||||
let tests = [testBasicPset,
|
||||
testSimplePset,
|
||||
testUnsortedPset,
|
||||
testReSetPrefixes,
|
||||
testLargeSet,
|
||||
testDuplicates,
|
||||
testTinySet];
|
||||
|
||||
function run_test() {
|
||||
// None of the tests use |executeSoon| or any sort of callbacks, so we can
|
||||
// just run them in succession.
|
||||
for (let i = 0; i < tests.length; i++) {
|
||||
dump("Running " + tests[i].name + "\n");
|
||||
tests[i]();
|
||||
}
|
||||
}
|
@ -27,6 +27,25 @@ function doTest(updates, assertions, expectError, clientKey)
|
||||
}
|
||||
}
|
||||
|
||||
function testFillDb() {
|
||||
var add1Urls = [ "zaz.com/a", "yxz.com/c" ];
|
||||
|
||||
var update = "n:1000\n";
|
||||
update += "i:test-phish-simple\n";
|
||||
|
||||
var update1 = buildBareUpdate(
|
||||
[{ "chunkNum" : 1,
|
||||
"urls" : add1Urls }]);
|
||||
update += "u:data:," + encodeURIComponent(update1) + "\n";
|
||||
|
||||
var assertions = {
|
||||
"tableData" : "test-phish-simple;a:1",
|
||||
"urlsExist" : add1Urls
|
||||
};
|
||||
|
||||
doTest([update], assertions, false);
|
||||
}
|
||||
|
||||
function testSimpleForward() {
|
||||
var add1Urls = [ "foo.com/a", "bar.com/c" ];
|
||||
var add2Urls = [ "foo.com/b" ];
|
||||
@ -61,6 +80,8 @@ function testSimpleForward() {
|
||||
// Make sure that a nested forward (a forward within a forward) causes
|
||||
// the update to fail.
|
||||
function testNestedForward() {
|
||||
testFillDb(); // Make sure the db isn't empty
|
||||
|
||||
var add1Urls = [ "foo.com/a", "bar.com/c" ];
|
||||
var add2Urls = [ "foo.com/b" ];
|
||||
|
||||
@ -182,6 +203,8 @@ function testValidMAC() {
|
||||
|
||||
// Test a simple update with an invalid message authentication code.
|
||||
function testInvalidMAC() {
|
||||
testFillDb(); // Make sure the db isn't empty
|
||||
|
||||
var addUrls = [ "foo.com/a", "foo.com/b", "bar.com/c" ];
|
||||
var update = buildPhishingUpdate(
|
||||
[
|
||||
@ -201,6 +224,8 @@ function testInvalidMAC() {
|
||||
// Test a simple update without a message authentication code, when it is
|
||||
// expecting one.
|
||||
function testNoMAC() {
|
||||
testFillDb(); // Make sure the db isn't empty
|
||||
|
||||
var addUrls = [ "foo.com/a", "foo.com/b", "bar.com/c" ];
|
||||
var update = buildPhishingUpdate(
|
||||
[
|
||||
@ -257,6 +282,8 @@ function testValidForwardMAC() {
|
||||
// Test an update with a valid message authentication code, but with
|
||||
// invalid MACs on the forwards.
|
||||
function testInvalidForwardMAC() {
|
||||
testFillDb(); // Make sure the db isn't empty
|
||||
|
||||
var add1Urls = [ "foo.com/a", "bar.com/c" ];
|
||||
var add2Urls = [ "foo.com/b" ];
|
||||
var add3Urls = [ "bar.com/d" ];
|
||||
@ -296,6 +323,8 @@ function testInvalidForwardMAC() {
|
||||
// Test an update with a valid message authentication code, but no MAC
|
||||
// specified for sub-urls.
|
||||
function testNoForwardMAC() {
|
||||
testFillDb(); // Make sure the db isn't empty
|
||||
|
||||
var add1Urls = [ "foo.com/a", "bar.com/c" ];
|
||||
var add2Urls = [ "foo.com/b" ];
|
||||
var add3Urls = [ "bar.com/d" ];
|
||||
@ -362,6 +391,8 @@ gAssertions.gotRekey = function(data, cb)
|
||||
|
||||
// Tests a rekey request.
|
||||
function testRekey() {
|
||||
testFillDb();
|
||||
|
||||
var addUrls = [ "foo.com/a", "foo.com/b", "bar.com/c" ];
|
||||
var update = buildPhishingUpdate(
|
||||
[
|
||||
|
@ -8,4 +8,5 @@ tail = tail_urlclassifier.js
|
||||
[test_dbservice.js]
|
||||
[test_hashcompleter.js]
|
||||
[test_partial.js]
|
||||
[test_prefixset.js]
|
||||
[test_streamupdater.js]
|
||||
|
@ -446,10 +446,6 @@ nsAppShell::PeekNextEvent()
|
||||
void
|
||||
nsAppShell::PostEvent(AndroidGeckoEvent *ae)
|
||||
{
|
||||
if (ae->Type() == AndroidGeckoEvent::ACTIVITY_STOPPING) {
|
||||
PostEvent(new AndroidGeckoEvent(AndroidGeckoEvent::SURFACE_DESTROYED));
|
||||
}
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mQueueLock);
|
||||
if (ae->Type() == AndroidGeckoEvent::SURFACE_DESTROYED) {
|
||||
|