Bug 628758 - Various compartment and request fixes for JSD (r=luke)
--- a/js/jsd/jsd_scpt.c
+++ b/js/jsd/jsd_scpt.c
@@ -522,40 +522,51 @@ jsd_GetScriptLineExtent(JSDContext* jsdc
if( NOT_SET_YET == (int)jsdscript->lineExtent )
jsdscript->lineExtent = JS_GetScriptLineExtent(jsdc->dumbContext, jsdscript->script);
return jsdscript->lineExtent;
}
jsuword
jsd_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, uintN line)
{
+ jsuword pc;
+ JSCrossCompartmentCall *call;
+
#ifdef LIVEWIRE
if( jsdscript && jsdscript->lwscript )
{
uintN newline;
jsdlw_RawToProcessedLineNumber(jsdc, jsdscript, line, &newline);
if( line != newline )
line = newline;
}
#endif
- return (jsuword) JS_LineNumberToPC(jsdc->dumbContext,
- jsdscript->script, line );
+ call = JS_EnterCrossCompartmentCallScript(jsdc->dumbContext, jsdscript->script);
+ if(!call)
+ return 0;
+ pc = (jsuword) JS_LineNumberToPC(jsdc->dumbContext, jsdscript->script, line );
+ JS_LeaveCrossCompartmentCall(call);
+ return pc;
}
uintN
jsd_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, jsuword pc)
{
+ JSCrossCompartmentCall *call;
uintN first = jsdscript->lineBase;
uintN last = first + jsd_GetScriptLineExtent(jsdc, jsdscript) - 1;
- uintN line = pc
- ? JS_PCToLineNumber(jsdc->dumbContext,
- jsdscript->script,
- (jsbytecode*)pc)
- : 0;
+ uintN line = 0;
+
+ call = JS_EnterCrossCompartmentCallScript(jsdc->dumbContext, jsdscript->script);
+ if(!call)
+ return 0;
+ if (pc)
+ line = JS_PCToLineNumber(jsdc->dumbContext, jsdscript->script, (jsbytecode*)pc);
+ JS_LeaveCrossCompartmentCall(call);
if( line < first )
return first;
if( line > last )
return last;
#ifdef LIVEWIRE
if( jsdscript && jsdscript->lwscript )
@@ -589,20 +600,25 @@ jsd_GetScriptHook(JSDContext* jsdc, JSD_
*callerdata = jsdc->scriptHookData;
JSD_UNLOCK();
return JS_TRUE;
}
JSBool
jsd_EnableSingleStepInterrupts(JSDContext* jsdc, JSDScript* jsdscript, JSBool enable)
{
+ JSCrossCompartmentCall *call;
JSBool rv;
+ call = JS_EnterCrossCompartmentCallScript(jsdc->dumbContext, jsdscript->script);
+ if(!call)
+ return JS_FALSE;
JSD_LOCK();
rv = JS_SetSingleStepMode(jsdc->dumbContext, jsdscript->script, enable);
JSD_UNLOCK();
+ JS_LeaveCrossCompartmentCall(call);
return rv;
}
/***************************************************************************/
void
jsd_NewScriptHookProc(
@@ -797,16 +813,18 @@ jsd_TrapHandler(JSContext *cx, JSScript
JSBool
jsd_SetExecutionHook(JSDContext* jsdc,
JSDScript* jsdscript,
jsuword pc,
JSD_ExecutionHookProc hook,
void* callerdata)
{
JSDExecHook* jsdhook;
+ JSBool rv;
+ JSCrossCompartmentCall *call;
JSD_LOCK();
if( ! hook )
{
jsd_ClearExecutionHook(jsdc, jsdscript, pc);
JSD_UNLOCK();
return JS_TRUE;
}
@@ -826,50 +844,69 @@ jsd_SetExecutionHook(JSDContext*
JSD_UNLOCK();
return JS_FALSE;
}
jsdhook->jsdscript = jsdscript;
jsdhook->pc = pc;
jsdhook->hook = hook;
jsdhook->callerdata = callerdata;
- if( ! JS_SetTrap(jsdc->dumbContext, jsdscript->script,
- (jsbytecode*)pc, jsd_TrapHandler,
- PRIVATE_TO_JSVAL(jsdhook)) )
- {
+ call = JS_EnterCrossCompartmentCallScript(jsdc->dumbContext, jsdscript->script);
+ if(!call) {
+ free(jsdhook);
+ JSD_UNLOCK();
+ return JS_FALSE;
+ }
+
+ rv = JS_SetTrap(jsdc->dumbContext, jsdscript->script,
+ (jsbytecode*)pc, jsd_TrapHandler,
+ PRIVATE_TO_JSVAL(jsdhook));
+
+ JS_LeaveCrossCompartmentCall(call);
+
+ if ( ! rv ) {
free(jsdhook);
JSD_UNLOCK();
return JS_FALSE;
}
JS_APPEND_LINK(&jsdhook->links, &jsdscript->hooks);
JSD_UNLOCK();
return JS_TRUE;
}
JSBool
jsd_ClearExecutionHook(JSDContext* jsdc,
JSDScript* jsdscript,
jsuword pc)
{
+ JSCrossCompartmentCall *call;
JSDExecHook* jsdhook;
JSD_LOCK();
jsdhook = _findHook(jsdc, jsdscript, pc);
if( ! jsdhook )
{
JSD_UNLOCK();
return JS_FALSE;
}
+ call = JS_EnterCrossCompartmentCallScript(jsdc->dumbContext, jsdscript->script);
+ if(!call) {
+ JSD_UNLOCK();
+ return JS_FALSE;
+ }
+
JS_ClearTrap(jsdc->dumbContext, jsdscript->script,
(jsbytecode*)pc, NULL, NULL );
+ JS_LeaveCrossCompartmentCall(call);
+
JS_REMOVE_LINK(&jsdhook->links);
free(jsdhook);
JSD_UNLOCK();
return JS_TRUE;
}
JSBool
@@ -881,16 +918,17 @@ jsd_ClearAllExecutionHooksForScript(JSDC
JSD_LOCK();
while( (JSDExecHook*)list != (jsdhook = (JSDExecHook*)list->next) )
{
JS_REMOVE_LINK(&jsdhook->links);
free(jsdhook);
}
+ /* No cross-compartment call here because we may be in the middle of GC */
JS_ClearScriptTraps(jsdc->dumbContext, jsdscript->script);
JSD_UNLOCK();
return JS_TRUE;
}
JSBool
jsd_ClearAllExecutionHooks(JSDContext* jsdc)
--- a/js/jsd/jsd_val.c
+++ b/js/jsd/jsd_val.c
@@ -206,46 +206,60 @@ jsd_GetValueDouble(JSDContext* jsdc, JSD
}
JSString*
jsd_GetValueString(JSDContext* jsdc, JSDValue* jsdval)
{
JSContext* cx = jsdc->dumbContext;
JSExceptionState* exceptionState;
JSCrossCompartmentCall *call = NULL;
+ jsval stringval;
+ JSString *string;
+ JSBool needWrap;
+ JSObject *scopeObj;
- if(!jsdval->string)
- {
- /* if the jsval is a string, then we don't need to double root it */
- if(JSVAL_IS_STRING(jsdval->val))
- jsdval->string = JSVAL_TO_STRING(jsdval->val);
- else
- {
- JS_BeginRequest(cx);
- call = JSVAL_IS_PRIMITIVE(jsdval->val)
- ? NULL
- : JS_EnterCrossCompartmentCall(jsdc->dumbContext, JSVAL_TO_OBJECT(jsdval->val));
- if(!call) {
- JS_EndRequest(cx);
+ if(jsdval->string)
+ return jsdval->string;
+
+ /* Reuse the string without copying or re-rooting it */
+ if(JSVAL_IS_STRING(jsdval->val)) {
+ jsdval->string = JSVAL_TO_STRING(jsdval->val);
+ return jsdval->string;
+ }
+
+ JS_BeginRequest(cx);
- return NULL;
- }
+ /* Objects call JS_ValueToString in their own compartment. */
+ scopeObj = JSVAL_IS_OBJECT(jsdval->val) ? JSVAL_TO_OBJECT(jsdval->val) : jsdc->glob;
+ call = JS_EnterCrossCompartmentCall(cx, scopeObj);
+ if(!call) {
+ JS_EndRequest(cx);
+ return NULL;
+ }
+ exceptionState = JS_SaveExceptionState(cx);
+
+ string = JS_ValueToString(cx, jsdval->val);
+
+ JS_RestoreExceptionState(cx, exceptionState);
+ JS_LeaveCrossCompartmentCall(call);
- exceptionState = JS_SaveExceptionState(cx);
- jsdval->string = JS_ValueToString(cx, jsdval->val);
- JS_RestoreExceptionState(cx, exceptionState);
- if(jsdval->string)
- {
- if(!JS_AddNamedStringRoot(cx, &jsdval->string, "ValueString"))
- jsdval->string = NULL;
- }
- JS_LeaveCrossCompartmentCall(call);
- JS_EndRequest(cx);
- }
+ stringval = STRING_TO_JSVAL(string);
+ call = JS_EnterCrossCompartmentCall(cx, jsdc->glob);
+ if(!call || !JS_WrapValue(cx, &stringval)) {
+ JS_EndRequest(cx);
+ return NULL;
}
+
+ jsdval->string = JSVAL_TO_STRING(stringval);
+ if(!JS_AddNamedStringRoot(cx, &jsdval->string, "ValueString"))
+ jsdval->string = NULL;
+
+ JS_LeaveCrossCompartmentCall(call);
+ JS_EndRequest(cx);
+
return jsdval->string;
}
JSString*
jsd_GetValueFunctionId(JSDContext* jsdc, JSDValue* jsdval)
{
JSContext* cx = jsdc->dumbContext;
JSFunction* fun;
@@ -276,38 +290,49 @@ jsd_GetValueFunctionId(JSDContext* jsdc,
if (!jsdval->funName)
jsdval->funName = JS_GetAnonymousString(jsdc->jsrt);
}
return jsdval->funName;
}
/***************************************************************************/
+/*
+ * Create a new JSD value referring to a jsval. Copy string values into the
+ * JSD compartment. Leave all other GCTHINGs in their native compartments
+ * and access them through cross-compartment calls.
+ */
JSDValue*
jsd_NewValue(JSDContext* jsdc, jsval val)
{
JSDValue* jsdval;
JSCrossCompartmentCall *call = NULL;
if(!(jsdval = (JSDValue*) calloc(1, sizeof(JSDValue))))
return NULL;
if(JSVAL_IS_GCTHING(val))
{
- JSBool ok = JS_FALSE;
+ JSBool ok;
JS_BeginRequest(jsdc->dumbContext);
call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, jsdc->glob);
if(!call) {
JS_EndRequest(jsdc->dumbContext);
free(jsdval);
return NULL;
}
ok = JS_AddNamedValueRoot(jsdc->dumbContext, &jsdval->val, "JSDValue");
+ if(ok && JSVAL_IS_STRING(val)) {
+ if(!JS_WrapValue(jsdc->dumbContext, &val)) {
+ ok = JS_FALSE;
+ }
+ }
+
JS_LeaveCrossCompartmentCall(call);
JS_EndRequest(jsdc->dumbContext);
if(!ok)
{
free(jsdval);
return NULL;
}
}
--- a/js/jsd/jsd_xpc.cpp
+++ b/js/jsd/jsd_xpc.cpp
@@ -1035,73 +1035,70 @@ jsdScript::~jsdScript ()
*/
PCMapEntry *
jsdScript::CreatePPLineMap()
{
JSContext *cx = JSD_GetDefaultJSContext (mCx);
JSAutoRequest ar(cx);
JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL);
JSFunction *fun = JSD_GetJSFunction (mCx, mScript);
- JSScript *script;
- JSString *jsstr;
+ JSScript *script; /* In JSD compartment */
PRUint32 baseLine;
PRBool scriptOwner = PR_FALSE;
+ JSString *jsstr;
+ size_t length;
+ const jschar *chars;
if (fun) {
uintN nargs;
- /* Enter a new block so we can leave before the end of this block */
- do {
+ {
JSAutoEnterCompartment ac;
if (!ac.enter(cx, JS_GetFunctionObject(fun)))
return nsnull;
nargs = JS_GetFunctionArgumentCount(cx, fun);
if (nargs > 12)
return nsnull;
jsstr = JS_DecompileFunctionBody (cx, fun, 4);
if (!jsstr)
return nsnull;
- } while(false);
-
- size_t length;
- const jschar *chars = JS_GetStringCharsAndLength(cx, jsstr, &length);
- if (!chars)
- return nsnull;
-
+
+ if (!(chars = JS_GetStringCharsAndLength(cx, jsstr, &length)))
+ return nsnull;
+ }
+
+ JS::Anchor<JSString *> kungFuDeathGrip(jsstr);
const char *argnames[] = {"arg1", "arg2", "arg3", "arg4",
"arg5", "arg6", "arg7", "arg8",
"arg9", "arg10", "arg11", "arg12" };
fun = JS_CompileUCFunction (cx, obj, "ppfun", nargs, argnames, chars,
length, "x-jsd:ppbuffer?type=function", 3);
if (!fun || !(script = JS_GetFunctionScript(cx, fun)))
return nsnull;
baseLine = 3;
} else {
- /* Enter a new block so we can leave before the end of this block */
- do {
- script = JSD_GetJSScript(mCx, mScript);
-
+ script = JSD_GetJSScript(mCx, mScript);
+ JSString *jsstr;
+
+ {
JSAutoEnterCompartment ac;
if (!ac.enter(cx, script))
return nsnull;
- jsstr = JS_DecompileScript (cx, JSD_GetJSScript(mCx, mScript),
- "ppscript", 4);
+ jsstr = JS_DecompileScript (cx, JSD_GetJSScript(mCx, mScript), "ppscript", 4);
if (!jsstr)
return nsnull;
- } while(false);
-
- size_t length;
- const jschar *chars = JS_GetStringCharsAndLength(cx, jsstr, &length);
- if (!chars)
- return nsnull;
-
- script = JS_CompileUCScript (cx, obj, chars, length,
- "x-jsd:ppbuffer?type=script", 1);
+
+ if (!(chars = JS_GetStringCharsAndLength(cx, jsstr, &length)))
+ return nsnull;
+ }
+
+ JS::Anchor<JSString *> kungFuDeathGrip(jsstr);
+ script = JS_CompileUCScript (cx, obj, chars, length, "x-jsd:ppbuffer?type=script", 1);
if (!script)
return nsnull;
scriptOwner = PR_TRUE;
baseLine = 1;
}
PRUint32 scriptExtent = JS_GetScriptLineExtent (cx, script);
jsbytecode* firstPC = JS_LineNumberToPC (cx, script, 0);
@@ -1185,16 +1182,19 @@ jsdScript::GetJSDScript(JSDScript **_rva
}
NS_IMETHODIMP
jsdScript::GetVersion (PRInt32 *_rval)
{
ASSERT_VALID_EPHEMERAL;
JSContext *cx = JSD_GetDefaultJSContext (mCx);
JSScript *script = JSD_GetJSScript(mCx, mScript);
+ JSAutoEnterCompartment ac;
+ if (!ac.enter(cx, script))
+ return NS_ERROR_FAILURE;
*_rval = static_cast<PRInt32>(JS_GetScriptVersion(cx, script));
return NS_OK;
}
NS_IMETHODIMP
jsdScript::GetTag(PRUint32 *_rval)
{
if (!mTag)
@@ -1283,16 +1283,19 @@ jsdScript::GetParameterNames(PRUint32* c
JSContext *cx = JSD_GetDefaultJSContext (mCx);
if (!cx) {
NS_WARNING("No default context !?");
return NS_ERROR_FAILURE;
}
JSFunction *fun = JSD_GetJSFunction (mCx, mScript);
JSAutoRequest ar(cx);
+ JSAutoEnterCompartment ac;
+ if (!ac.enter(cx, JS_GetFunctionObject(fun)))
+ return NS_ERROR_FAILURE;
uintN nargs;
if (!fun ||
!JS_FunctionHasLocalNames(cx, fun) ||
(nargs = JS_GetFunctionArgumentCount(cx, fun)) == 0) {
*count = 0;
*paramNames = nsnull;
return NS_OK;