зеркало из https://github.com/mozilla/pjs.git
Make functions per compartment, and deep copy instead of clone them if needed (584789, r=mrbkap).
This commit is contained in:
Родитель
398734ce25
Коммит
64d575a614
|
@ -50,6 +50,7 @@ CPPSRCS = \
|
|||
tests.cpp \
|
||||
selfTest.cpp \
|
||||
testClassGetter.cpp \
|
||||
testCloneScript.cpp \
|
||||
testConservativeGC.cpp \
|
||||
testContexts.cpp \
|
||||
testDebugger.cpp \
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=99:
|
||||
*
|
||||
* Test script cloning.
|
||||
*/
|
||||
|
||||
#include "tests.h"
|
||||
#include "jsapi.h"
|
||||
|
||||
BEGIN_TEST(test_cloneScript)
|
||||
{
|
||||
JSObject *A, *B;
|
||||
|
||||
CHECK(A = createGlobal());
|
||||
CHECK(B = createGlobal());
|
||||
|
||||
const char *source =
|
||||
"var i = 0;\n"
|
||||
"var sum = 0;\n"
|
||||
"while (i < 10) {\n"
|
||||
" sum += i;\n"
|
||||
" ++i;\n"
|
||||
"}\n"
|
||||
"(sum);\n";
|
||||
|
||||
JSObject *obj;
|
||||
|
||||
// compile for A
|
||||
{
|
||||
JSAutoEnterCompartment a;
|
||||
if (!a.enter(cx, A))
|
||||
return false;
|
||||
|
||||
JSFunction *fun;
|
||||
CHECK(fun = JS_CompileFunction(cx, A, "f", 0, NULL, source, strlen(source), __FILE__, 1));
|
||||
CHECK(obj = JS_GetFunctionObject(fun));
|
||||
}
|
||||
|
||||
// clone into B
|
||||
{
|
||||
JSAutoEnterCompartment b;
|
||||
if (!b.enter(cx, B))
|
||||
return false;
|
||||
|
||||
CHECK(JS_CloneFunctionObject(cx, obj, B));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
END_TEST(test_cloneScript)
|
|
@ -4516,6 +4516,7 @@ JS_NewScriptObject(JSContext *cx, JSScript *script)
|
|||
* described in the comment for JSScript::u.object.
|
||||
*/
|
||||
JS_ASSERT(script->u.object);
|
||||
JS_ASSERT(script != JSScript::emptyScript());
|
||||
return script->u.object;
|
||||
}
|
||||
|
||||
|
|
|
@ -567,8 +567,11 @@ class CompartmentChecker
|
|||
}
|
||||
|
||||
void check(JSScript *script) {
|
||||
if (script && script->u.object)
|
||||
check(script->u.object);
|
||||
if (script && script != JSScript::emptyScript()) {
|
||||
check(script->compartment);
|
||||
if (script->u.object)
|
||||
check(script->u.object);
|
||||
}
|
||||
}
|
||||
|
||||
void check(JSString *) { /* nothing for now */ }
|
||||
|
|
|
@ -2935,14 +2935,47 @@ js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent,
|
|||
JS_ASSERT(parent);
|
||||
JS_ASSERT(proto);
|
||||
|
||||
/*
|
||||
* The cloned function object does not need the extra JSFunction members
|
||||
* beyond JSObject as it points to fun via the private slot.
|
||||
*/
|
||||
JSObject *clone = NewNativeClassInstance(cx, &js_FunctionClass, proto, parent);
|
||||
if (!clone)
|
||||
return NULL;
|
||||
clone->setPrivate(fun);
|
||||
JSObject *clone;
|
||||
if (cx->compartment == fun->compartment()) {
|
||||
/*
|
||||
* The cloned function object does not need the extra JSFunction members
|
||||
* beyond JSObject as it points to fun via the private slot.
|
||||
*/
|
||||
clone = NewNativeClassInstance(cx, &js_FunctionClass, proto, parent);
|
||||
if (!clone)
|
||||
return NULL;
|
||||
clone->setPrivate(fun);
|
||||
} else {
|
||||
/*
|
||||
* Across compartments we have to deep copy JSFunction and clone the
|
||||
* script (for interpreted functions).
|
||||
*/
|
||||
clone = NewFunction(cx, parent);
|
||||
if (!clone)
|
||||
return NULL;
|
||||
JSFunction *cfun = (JSFunction *) clone;
|
||||
cfun->nargs = fun->nargs;
|
||||
cfun->flags = fun->flags;
|
||||
cfun->u = fun->getFunctionPrivate()->u;
|
||||
cfun->atom = fun->atom;
|
||||
clone->setPrivate(cfun);
|
||||
if (cfun->isInterpreted()) {
|
||||
JSScript *script = cfun->u.i.script;
|
||||
JS_ASSERT(script);
|
||||
JS_ASSERT(script->compartment == fun->compartment());
|
||||
JS_ASSERT(script->compartment != cx->compartment);
|
||||
cfun->u.i.script = js_CloneScript(cx, script);
|
||||
if (!cfun->u.i.script)
|
||||
return NULL;
|
||||
|
||||
if (cfun->u.i.script != JSScript::emptyScript()) {
|
||||
#ifdef CHECK_SCRIPT_OWNER
|
||||
cfun->u.i.script->owner = NULL;
|
||||
#endif
|
||||
js_CallNewScriptHook(cx, cfun->u.i.script, cfun);
|
||||
}
|
||||
}
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ static const jsbytecode emptyScriptCode[] = {JSOP_STOP, SRC_NULL};
|
|||
false, /* debugMode */
|
||||
#endif
|
||||
const_cast<jsbytecode*>(emptyScriptCode),
|
||||
{0, NULL}, NULL, 0, 0, 0,
|
||||
{0, NULL}, NULL, NULL, 0, 0, 0,
|
||||
0, /* nClosedArgs */
|
||||
0, /* nClosedVars */
|
||||
NULL, {NULL},
|
||||
|
@ -1065,6 +1065,7 @@ JSScript::NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natom
|
|||
nsrcnotes * sizeof(jssrcnote) ==
|
||||
(uint8 *)script + size);
|
||||
|
||||
script->compartment = cx->compartment;
|
||||
#ifdef CHECK_SCRIPT_OWNER
|
||||
script->owner = cx->thread;
|
||||
#endif
|
||||
|
@ -1641,6 +1642,82 @@ js_GetScriptLineExtent(JSScript *script)
|
|||
return 1 + lineno - script->lineno;
|
||||
}
|
||||
|
||||
class DisablePrincipalsTranscoding {
|
||||
JSSecurityCallbacks *callbacks;
|
||||
JSPrincipalsTranscoder temp;
|
||||
|
||||
public:
|
||||
DisablePrincipalsTranscoding(JSContext *cx) {
|
||||
callbacks = JS_GetRuntimeSecurityCallbacks(cx->runtime);
|
||||
if (callbacks) {
|
||||
temp = callbacks->principalsTranscoder;
|
||||
callbacks->principalsTranscoder = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
~DisablePrincipalsTranscoding() {
|
||||
if (callbacks)
|
||||
callbacks->principalsTranscoder = temp;
|
||||
}
|
||||
};
|
||||
|
||||
JSScript *
|
||||
js_CloneScript(JSContext *cx, JSScript *script)
|
||||
{
|
||||
// don't clone the empty script
|
||||
if (script == JSScript::emptyScript())
|
||||
return script;
|
||||
|
||||
JS_ASSERT(cx->compartment != script->compartment);
|
||||
JS_ASSERT(script->compartment);
|
||||
|
||||
// serialize script
|
||||
JSXDRState *w = JS_XDRNewMem(cx, JSXDR_ENCODE);
|
||||
if (!w)
|
||||
return NULL;
|
||||
|
||||
// we don't want gecko to transcribe our principals for us
|
||||
DisablePrincipalsTranscoding disable(cx);
|
||||
|
||||
if (!JS_XDRScript(w, &script)) {
|
||||
JS_XDRDestroy(w);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32 nbytes;
|
||||
void *p = JS_XDRMemGetData(w, &nbytes);
|
||||
if (!p) {
|
||||
JS_XDRDestroy(w);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// de-serialize script
|
||||
JSXDRState *r = JS_XDRNewMem(cx, JSXDR_DECODE);
|
||||
if (!r) {
|
||||
JS_XDRDestroy(w);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Hand p off from w to r. Don't want them to share the data
|
||||
// mem, lest they both try to free it in JS_XDRDestroy
|
||||
JS_XDRMemSetData(r, p, nbytes);
|
||||
JS_XDRMemSetData(w, NULL, 0);
|
||||
|
||||
// We can't use the public API because it makes a script object.
|
||||
if (!js_XDRScript(r, &script, true, NULL))
|
||||
return NULL;
|
||||
|
||||
JS_XDRDestroy(r);
|
||||
JS_XDRDestroy(w);
|
||||
|
||||
// set the proper principals for the script
|
||||
script->principals = script->compartment->principals;
|
||||
if (script->principals)
|
||||
JSPRINCIPALS_HOLD(cx, script->principals);
|
||||
|
||||
return script;
|
||||
}
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
bool
|
||||
JSScript::isValidJitCode(void *jcode)
|
||||
|
|
|
@ -250,6 +250,7 @@ struct JSScript {
|
|||
|
||||
jsbytecode *main; /* main entry point, after predef'ing prolog */
|
||||
JSAtomMap atomMap; /* maps immediate index to literal struct */
|
||||
JSCompartment *compartment; /* compartment the script was compiled for */
|
||||
const char *filename; /* source filename or null */
|
||||
uint32 lineno; /* base line number of script */
|
||||
uint16 nslots; /* vars plus maximum stack depth */
|
||||
|
@ -277,6 +278,7 @@ struct JSScript {
|
|||
JSObject *object;
|
||||
JSScript *nextToGC; /* next to GC in rt->scriptsToGC list */
|
||||
} u;
|
||||
|
||||
#ifdef CHECK_SCRIPT_OWNER
|
||||
JSThread *owner; /* for thread-safe life-cycle assertions */
|
||||
#endif
|
||||
|
@ -548,6 +550,9 @@ js_GetOpcode(JSContext *cx, JSScript *script, jsbytecode *pc)
|
|||
return op;
|
||||
}
|
||||
|
||||
extern JSScript *
|
||||
js_CloneScript(JSContext *cx, JSScript *script);
|
||||
|
||||
/*
|
||||
* If magic is non-null, js_XDRScript succeeds on magic number mismatch but
|
||||
* returns false in *magic; it reflects a match via a true *magic out param.
|
||||
|
|
Загрузка…
Ссылка в новой задаче