mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 438633: Give new JSScript objects lifetimes like GCThings. r=brendan
Attach script objects immediately in all JSAPI script-creating functions; have JS_NewScriptObject simply return the already-allocated object; and make JS_DestroyScript a no-op. Verify that all scripts given to JSAPI script-consuming functions have objects, or are the canonical empty script object.
This commit is contained in:
parent
16f4c21b3c
commit
285b03968f
@ -4414,6 +4414,10 @@ JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj, JSPrincipals *prin
|
||||
uint32 tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
|
||||
JSScript *script = Compiler::compileScript(cx, obj, NULL, principals, tcflags,
|
||||
chars, length, NULL, filename, lineno);
|
||||
if (script && !js_NewScriptObject(cx, script)) {
|
||||
js_DestroyScript(cx, script);
|
||||
script = NULL;
|
||||
}
|
||||
LAST_FRAME_CHECKS(cx, script);
|
||||
return script;
|
||||
}
|
||||
@ -4514,6 +4518,10 @@ JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename)
|
||||
NULL, 0, fp, filename, 1);
|
||||
if (fp != stdin)
|
||||
fclose(fp);
|
||||
if (script && !js_NewScriptObject(cx, script)) {
|
||||
js_DestroyScript(cx, script);
|
||||
script = NULL;
|
||||
}
|
||||
LAST_FRAME_CHECKS(cx, script);
|
||||
return script;
|
||||
}
|
||||
@ -4530,6 +4538,10 @@ JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj, const char *file
|
||||
tcflags = JS_OPTIONS_TO_TCFLAGS(cx) | TCF_NEED_MUTABLE_SCRIPT;
|
||||
script = Compiler::compileScript(cx, obj, NULL, principals, tcflags,
|
||||
NULL, 0, file, filename, 1);
|
||||
if (script && !js_NewScriptObject(cx, script)) {
|
||||
js_DestroyScript(cx, script);
|
||||
script = NULL;
|
||||
}
|
||||
LAST_FRAME_CHECKS(cx, script);
|
||||
return script;
|
||||
}
|
||||
@ -4543,34 +4555,29 @@ JS_CompileFileHandle(JSContext *cx, JSObject *obj, const char *filename, FILE *f
|
||||
JS_PUBLIC_API(JSObject *)
|
||||
JS_NewScriptObject(JSContext *cx, JSScript *script)
|
||||
{
|
||||
JSObject *obj;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, script);
|
||||
if (!script)
|
||||
return NewNonFunction<WithProto::Class>(cx, &js_ScriptClass, NULL, NULL);
|
||||
|
||||
JS_ASSERT(!script->u.object);
|
||||
|
||||
{
|
||||
AutoScriptRooter root(cx, script);
|
||||
|
||||
obj = NewNonFunction<WithProto::Class>(cx, &js_ScriptClass, NULL, NULL);
|
||||
if (obj) {
|
||||
obj->setPrivate(script);
|
||||
script->u.object = obj;
|
||||
#ifdef CHECK_SCRIPT_OWNER
|
||||
script->owner = NULL;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
/*
|
||||
* This function should only ever be applied to JSScripts that had
|
||||
* script objects allocated for them when they were created, as
|
||||
* described in the comment for JSScript::u.object.
|
||||
*/
|
||||
JS_ASSERT(script->u.object);
|
||||
return script->u.object;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSObject *)
|
||||
JS_GetScriptObject(JSScript *script)
|
||||
{
|
||||
/*
|
||||
* This function should only ever be applied to JSScripts that had
|
||||
* script objects allocated for them when they were created, as
|
||||
* described in the comment for JSScript::u.object.
|
||||
*/
|
||||
JS_ASSERT(script->u.object);
|
||||
return script->u.object;
|
||||
}
|
||||
|
||||
@ -4578,8 +4585,17 @@ JS_PUBLIC_API(void)
|
||||
JS_DestroyScript(JSContext *cx, JSScript *script)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, script);
|
||||
js_DestroyScript(cx, script);
|
||||
|
||||
/*
|
||||
* Originally, JSScript lifetimes were managed explicitly, and this function
|
||||
* was used to free a JSScript. Now, this function does nothing, and the
|
||||
* garbage collector manages JSScripts; you must root the JSScript's script
|
||||
* object (obtained via JS_GetScriptObject) to keep it alive.
|
||||
*
|
||||
* However, since the script objects have taken over this responsibility, it
|
||||
* follows that every script passed here must have a script object.
|
||||
*/
|
||||
JS_ASSERT(script->u.object);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSFunction *)
|
||||
@ -4741,6 +4757,8 @@ JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval)
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
assertSameCompartment(cx, obj, script);
|
||||
/* This should receive only scripts handed out via the JSAPI. */
|
||||
JS_ASSERT(script == JSScript::emptyScript() || script->u.object);
|
||||
ok = Execute(cx, obj, script, NULL, 0, Valueify(rval));
|
||||
LAST_FRAME_CHECKS(cx, ok);
|
||||
return ok;
|
||||
@ -4768,7 +4786,7 @@ JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj,
|
||||
}
|
||||
ok = Execute(cx, obj, script, NULL, 0, Valueify(rval));
|
||||
LAST_FRAME_CHECKS(cx, ok);
|
||||
JS_DestroyScript(cx, script);
|
||||
js_DestroyScript(cx, script);
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
@ -6081,8 +6081,11 @@ JSObject::getCompartment(JSContext *cx)
|
||||
return cx->runtime->defaultCompartment;
|
||||
}
|
||||
|
||||
// Compile-time Function, Block, and RegExp objects are not parented.
|
||||
if (clasp == &js_FunctionClass || clasp == &js_BlockClass || clasp == &js_RegExpClass) {
|
||||
/*
|
||||
* Script objects and compile-time Function, Block, RegExp objects
|
||||
* are not parented.
|
||||
*/
|
||||
if (clasp == &js_FunctionClass || clasp == &js_BlockClass || clasp == &js_RegExpClass || clasp == &js_ScriptClass) {
|
||||
// This is a bogus answer, but it'll do for now.
|
||||
return cx->runtime->defaultCompartment;
|
||||
}
|
||||
|
@ -1277,6 +1277,33 @@ js_TraceScript(JSTracer *trc, JSScript *script)
|
||||
js_MarkScriptFilename(script->filename);
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_NewScriptObject(JSContext *cx, JSScript *script)
|
||||
{
|
||||
AutoScriptRooter root(cx, script);
|
||||
|
||||
JS_ASSERT(!script->u.object);
|
||||
JS_ASSERT(script != JSScript::emptyScript());
|
||||
|
||||
JSObject *obj = NewNonFunction<WithProto::Class>(cx, &js_ScriptClass, NULL, NULL);
|
||||
if (!obj)
|
||||
return JS_FALSE;
|
||||
obj->setPrivate(script);
|
||||
script->u.object = obj;
|
||||
|
||||
/*
|
||||
* Clear the object's proto, to avoid entraining stuff. Once we no longer use the parent
|
||||
* for security checks, then we can clear the parent, too.
|
||||
*/
|
||||
obj->clearProto();
|
||||
|
||||
#ifdef CHECK_SCRIPT_OWNER
|
||||
script->owner = NULL;
|
||||
#endif
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
typedef struct GSNCacheEntry {
|
||||
JSDHashEntryHdr hdr;
|
||||
jsbytecode *pc;
|
||||
|
@ -184,7 +184,23 @@ struct JSScript {
|
||||
uint16 staticLevel;/* static level for display maintenance */
|
||||
JSPrincipals *principals;/* principals for this script */
|
||||
union {
|
||||
JSObject *object; /* optional Script-class object wrapper */
|
||||
/*
|
||||
* A script object of class js_ScriptClass, to ensure the script is GC'd.
|
||||
* - All scripts returned by JSAPI functions (JS_CompileScript,
|
||||
* JS_CompileFile, etc.) have these objects.
|
||||
* - Function scripts never have script objects; such scripts are owned
|
||||
* by their function objects.
|
||||
* - Temporary scripts created by obj_eval, JS_EvaluateScript, and
|
||||
* similar functions never have these objects; such scripts are
|
||||
* explicitly destroyed by the code that created them.
|
||||
* Debugging API functions (JSDebugHooks::newScriptHook;
|
||||
* JS_GetFunctionScript) may reveal sans-script-object Function and
|
||||
* temporary scripts to clients, but clients must never call
|
||||
* JS_NewScriptObject on such scripts: doing so would double-free them,
|
||||
* once from the explicit call to js_DestroyScript, and once when the
|
||||
* script object is garbage collected.
|
||||
*/
|
||||
JSObject *object;
|
||||
JSScript *nextToGC; /* next to GC in rt->scriptsToGC list */
|
||||
} u;
|
||||
#ifdef CHECK_SCRIPT_OWNER
|
||||
@ -375,6 +391,9 @@ js_DestroyScript(JSContext *cx, JSScript *script);
|
||||
extern void
|
||||
js_TraceScript(JSTracer *trc, JSScript *script);
|
||||
|
||||
extern JSBool
|
||||
js_NewScriptObject(JSContext *cx, JSScript *script);
|
||||
|
||||
/*
|
||||
* To perturb as little code as possible, we introduce a js_GetSrcNote lookup
|
||||
* cache without adding an explicit cx parameter. Thus js_GetSrcNote becomes
|
||||
|
@ -671,8 +671,17 @@ JS_XDRScript(JSXDRState *xdr, JSScript **scriptp)
|
||||
{
|
||||
if (!js_XDRScript(xdr, scriptp, true, NULL))
|
||||
return JS_FALSE;
|
||||
if (xdr->mode == JSXDR_DECODE)
|
||||
|
||||
if (xdr->mode == JSXDR_DECODE) {
|
||||
js_CallNewScriptHook(xdr->cx, *scriptp, NULL);
|
||||
if (*scriptp != JSScript::emptyScript() &&
|
||||
!js_NewScriptObject(xdr->cx, *scriptp)) {
|
||||
js_DestroyScript(xdr->cx, *scriptp);
|
||||
*scriptp = NULL;
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user