Пример #1
0
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)
        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);

    /* 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);
    call = NULL;

    if(string) {
        stringval = STRING_TO_JSVAL(string);
        call = JS_EnterCrossCompartmentCall(cx, jsdc->glob);
    }
    if(!string || !call || !JS_WrapValue(cx, &stringval)) {
        if(call)
            JS_LeaveCrossCompartmentCall(call);
        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;
}
Пример #2
0
const char*
jsd_GetValueClassName(JSDContext* jsdc, JSDValue* jsdval)
{
    jsval val = jsdval->val;
    JSCrossCompartmentCall *call = NULL;

    if(!jsdval->className && JSVAL_IS_OBJECT(val))
    {
        JSObject* obj;
        if(!(obj = JSVAL_TO_OBJECT(val)))
            return NULL;
        JS_BeginRequest(jsdc->dumbContext);
        call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, obj);
        if(!call) {
            JS_EndRequest(jsdc->dumbContext);

            return NULL;
        }
        if(JS_GET_CLASS(jsdc->dumbContext, obj))
            jsdval->className = JS_GET_CLASS(jsdc->dumbContext, obj)->name;
        JS_LeaveCrossCompartmentCall(call);
        JS_EndRequest(jsdc->dumbContext);
    }
    return jsdval->className;
}
Пример #3
0
JSDValue*
jsd_GetValueParent(JSDContext* jsdc, JSDValue* jsdval)
{
    JSCrossCompartmentCall *call = NULL;

    if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PARENT)))
    {
        JSObject* obj;
        JSObject* parent;
        JS_ASSERT(!jsdval->parent);
        SET_BIT_FLAG(jsdval->flags, GOT_PARENT);
        if(!JSVAL_IS_OBJECT(jsdval->val))
            return NULL;
        if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
            return NULL;
        JS_BeginRequest(jsdc->dumbContext);
        call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, obj);
        if(!call) {
            JS_EndRequest(jsdc->dumbContext);

            return NULL;
        }
        parent = JS_GetParent(jsdc->dumbContext,obj);
        JS_LeaveCrossCompartmentCall(call);
        JS_EndRequest(jsdc->dumbContext);
        if(!parent)
            return NULL;
        jsdval->parent = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(parent));
    }
    if(jsdval->parent)
        jsdval->parent->nref++;
    return jsdval->parent;
}
Пример #4
0
JSDValue*
jsd_GetValuePrototype(JSDContext* jsdc, JSDValue* jsdval)
{
    JSCrossCompartmentCall *call = NULL;

    if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROTO)))
    {
        JSObject* obj;
        JSObject* proto;
        JS_ASSERT(!jsdval->proto);
        SET_BIT_FLAG(jsdval->flags, GOT_PROTO);
        if(!JSVAL_IS_OBJECT(jsdval->val))
            return NULL;
        if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
            return NULL;
        JS_BeginRequest(jsdc->dumbContext);
        call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, obj);
        if(!call) {
            JS_EndRequest(jsdc->dumbContext);

            return NULL;
        }
        proto = JS_GetPrototype(jsdc->dumbContext, obj);
        JS_LeaveCrossCompartmentCall(call);
        JS_EndRequest(jsdc->dumbContext);
        if(!proto)
            return NULL;
        jsdval->proto = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(proto));
    }
    if(jsdval->proto)
        jsdval->proto->nref++;
    return jsdval->proto;
}
Пример #5
0
void
jsd_RefreshValue(JSDContext* jsdc, JSDValue* jsdval)
{
    JSContext* cx = jsdc->dumbContext;
    JSCrossCompartmentCall *call = NULL;

    if(jsdval->string)
    {
        /* if the jsval is a string, then we didn't need to root the string */
        if(!JSVAL_IS_STRING(jsdval->val))
        {
            JS_BeginRequest(cx);
            call = JS_EnterCrossCompartmentCall(cx, jsdc->glob);
            if(!call) {
                JS_EndRequest(cx);

                return;
            }

            JS_RemoveStringRoot(cx, &jsdval->string);
            JS_LeaveCrossCompartmentCall(call);
            JS_EndRequest(cx);
        }
        jsdval->string = NULL;
    }

    jsdval->funName = NULL;
    jsdval->className = NULL;
    DROP_CLEAR_VALUE(jsdc, jsdval->proto);
    DROP_CLEAR_VALUE(jsdc, jsdval->parent);
    DROP_CLEAR_VALUE(jsdc, jsdval->ctor);
    _freeProps(jsdc, jsdval);
    jsdval->flags = 0;
}
Пример #6
0
void
jsd_DropValue(JSDContext* jsdc, JSDValue* jsdval)
{
    JSCrossCompartmentCall *call = NULL;

    JS_ASSERT(jsdval->nref > 0);
    if(0 == --jsdval->nref)
    {
        jsd_RefreshValue(jsdc, jsdval);
        if(JSVAL_IS_GCTHING(jsdval->val))
        {
            JS_BeginRequest(jsdc->dumbContext);
            call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, jsdc->glob);
            if(!call) {
                JS_EndRequest(jsdc->dumbContext);

                return;
            }

            JS_RemoveValueRoot(jsdc->dumbContext, &jsdval->val);
            JS_LeaveCrossCompartmentCall(call);
            JS_EndRequest(jsdc->dumbContext);
        }
        free(jsdval);
    }
}
Пример #7
0
JSString*
jsd_GetValueFunctionId(JSDContext* jsdc, JSDValue* jsdval)
{
    JSContext* cx = jsdc->dumbContext;
    JSFunction* fun;
    JSExceptionState* exceptionState;
    JSCrossCompartmentCall *call = NULL;

    if(!jsdval->funName && jsd_IsValueFunction(jsdc, jsdval))
    {
        JS_BeginRequest(cx);

        call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, JSVAL_TO_OBJECT(jsdval->val));
        if(!call) {
            JS_EndRequest(cx);

            return NULL;
        }

        exceptionState = JS_SaveExceptionState(cx);
        fun = JSD_GetValueFunction(jsdc, jsdval);
        JS_RestoreExceptionState(cx, exceptionState);
        JS_LeaveCrossCompartmentCall(call);
        JS_EndRequest(cx);
        if(!fun)
            return NULL;
        jsdval->funName = JS_GetFunctionId(fun);

        /* For compatibility we return "anonymous", not an empty string here. */
        if (!jsdval->funName)
            jsdval->funName = JS_GetAnonymousString(jsdc->jsrt);
    }
    return jsdval->funName;
}
Пример #8
0
JSBool
jsd_IsValueNative(JSDContext* jsdc, JSDValue* jsdval)
{
    JSContext* cx = jsdc->dumbContext;
    JSFunction* fun;
    JSExceptionState* exceptionState;
    JSCrossCompartmentCall *call = NULL;

    if(jsd_IsValueFunction(jsdc, jsdval))
    {
        JSBool ok = JS_FALSE;
        JS_BeginRequest(cx);
        call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, JSVAL_TO_OBJECT(jsdval->val));
        if(!call) {
            JS_EndRequest(cx);

            return JS_FALSE;
        }

        exceptionState = JS_SaveExceptionState(cx);
        fun = JSD_GetValueFunction(jsdc, jsdval);
        JS_RestoreExceptionState(cx, exceptionState);
        if(fun)
            ok = JS_GetFunctionScript(cx, fun) ? JS_FALSE : JS_TRUE;
        JS_LeaveCrossCompartmentCall(call);
        JS_EndRequest(cx);
        JS_ASSERT(fun);
        return ok;
    }
    return !JSVAL_IS_PRIMITIVE(jsdval->val);
}
Пример #9
0
static JSBool _buildProps(JSDContext* jsdc, JSDValue* jsdval)
{
    JSContext* cx = jsdc->dumbContext;
    JSObject *obj;
    JSPropertyDescArray pda;
    uintN i;
    JSCrossCompartmentCall *call = NULL;

    JS_ASSERT(JS_CLIST_IS_EMPTY(&jsdval->props));
    JS_ASSERT(!(CHECK_BIT_FLAG(jsdval->flags, GOT_PROPS)));
    JS_ASSERT(JSVAL_IS_OBJECT(jsdval->val));

    if(JSVAL_IS_PRIMITIVE(jsdval->val))
        return JS_FALSE;

    obj = JSVAL_TO_OBJECT(jsdval->val);

    JS_BeginRequest(cx);
    call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, obj);
    if(!call)
    {
        JS_EndRequest(jsdc->dumbContext);
        return JS_FALSE;
    }

    if(!JS_GetPropertyDescArray(cx, obj, &pda))
    {
        JS_EndRequest(cx);
        JS_LeaveCrossCompartmentCall(call);
        return JS_FALSE;
    }

    for(i = 0; i < pda.length; i++)
    {
        JSDProperty* prop = _newProperty(jsdc, &pda.array[i], 0);
        if(!prop)
        {
            _freeProps(jsdc, jsdval);
            break;
        }
        JS_APPEND_LINK(&prop->links, &jsdval->props);
    }
    JS_PutPropertyDescArray(cx, &pda);
    JS_LeaveCrossCompartmentCall(call);
    JS_EndRequest(cx);
    SET_BIT_FLAG(jsdval->flags, GOT_PROPS);
    return !JS_CLIST_IS_EMPTY(&jsdval->props);
}
Пример #10
0
/*
 * 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_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;
        }
    }
    jsdval->val  = val;
    jsdval->nref = 1;
    JS_INIT_CLIST(&jsdval->props);

    return jsdval;
}
Пример #11
0
/*
 * Retrieve a JSFunction* from a JSDValue*. This differs from
 * JS_ValueToFunction by fully unwrapping the object first.
 */
JSFunction*
jsd_GetValueFunction(JSDContext* jsdc, JSDValue* jsdval)
{
    JSObject *obj;
    JSFunction *fun;
    JSCrossCompartmentCall *call = NULL;
    if (!JSVAL_IS_OBJECT(jsdval->val))
        return NULL;
    if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
        return NULL;
    obj = JS_UnwrapObject(obj);

    call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, obj);
    if (!call)
        return NULL;
    fun = JS_ValueToFunction(jsdc->dumbContext, OBJECT_TO_JSVAL(obj));
    JS_LeaveCrossCompartmentCall(call);

    return fun;
}
Пример #12
0
JSDScript*
jsd_GetScriptForValue(JSDContext* jsdc, JSDValue* jsdval)
{
    JSContext* cx = jsdc->dumbContext;
    jsval val = jsdval->val;
    JSFunction* fun = NULL;
    JSExceptionState* exceptionState;
    JSScript* script = NULL;
    JSDScript* jsdscript;
    JSCrossCompartmentCall *call = NULL;

    if (!jsd_IsValueFunction(jsdc, jsdval))
        return NULL;

    JS_BeginRequest(cx);
    call = JS_EnterCrossCompartmentCall(cx, JSVAL_TO_OBJECT(val));
    if (!call) {
        JS_EndRequest(cx);

        return NULL;
    }

    exceptionState = JS_SaveExceptionState(cx);
    fun = JSD_GetValueFunction(jsdc, jsdval);
    JS_RestoreExceptionState(cx, exceptionState);
    if (fun)
        script = JS_GetFunctionScript(cx, fun);
    JS_LeaveCrossCompartmentCall(call);
    JS_EndRequest(cx);

    if (!script)
        return NULL;

    JSD_LOCK_SCRIPTS(jsdc);
    jsdscript = jsd_FindJSDScript(jsdc, script);
    JSD_UNLOCK_SCRIPTS(jsdc);
    return jsdscript;
}
Пример #13
0
JSDValue*
jsd_GetValueConstructor(JSDContext* jsdc, JSDValue* jsdval)
{
    JSCrossCompartmentCall *call = NULL;

    if(!(CHECK_BIT_FLAG(jsdval->flags, GOT_CTOR)))
    {
        JSObject* obj;
        JSObject* proto;
        JSObject* ctor;
        JS_ASSERT(!jsdval->ctor);
        SET_BIT_FLAG(jsdval->flags, GOT_CTOR);
        if(!JSVAL_IS_OBJECT(jsdval->val))
            return NULL;
        if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
            return NULL;
        proto = JS_GetPrototype(obj);
        if(!proto)
            return NULL;
        JS_BeginRequest(jsdc->dumbContext);
        call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, obj);
        if(!call) {
            JS_EndRequest(jsdc->dumbContext);

            return NULL;
        }
        ctor = JS_GetConstructor(jsdc->dumbContext,proto);
        JS_LeaveCrossCompartmentCall(call);
        JS_EndRequest(jsdc->dumbContext);
        if(!ctor)
            return NULL;
        jsdval->ctor = jsd_NewValue(jsdc, OBJECT_TO_JSVAL(ctor));
    }
    if(jsdval->ctor)
        jsdval->ctor->nref++;
    return jsdval->ctor;
}
Пример #14
0
JSDProperty*
jsd_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* name)
{
    JSContext* cx = jsdc->dumbContext;
    JSDProperty* jsdprop;
    JSDProperty* iter = NULL;
    JSObject* obj;
    uintN  attrs = 0;
    JSBool found;
    JSPropertyDesc pd;
    const jschar * nameChars;
    size_t nameLen;
    jsval val, nameval;
    jsid nameid;
    JSCrossCompartmentCall *call = NULL;

    if(!jsd_IsValueObject(jsdc, jsdval))
        return NULL;

    /* If we already have the prop, then return it */
    while(NULL != (jsdprop = jsd_IterateProperties(jsdc, jsdval, &iter)))
    {
        JSString* propName = jsd_GetValueString(jsdc, jsdprop->name);
        if(propName) {
            intN result;
            if (JS_CompareStrings(cx, propName, name, &result) && !result)
                return jsdprop;
        }
        JSD_DropProperty(jsdc, jsdprop);
    }
    /* Not found in property list, look it up explicitly */

    if(!(obj = JSVAL_TO_OBJECT(jsdval->val)))
        return NULL;

    if (!(nameChars = JS_GetStringCharsZAndLength(cx, name, &nameLen)))
        return NULL;

    JS_BeginRequest(cx);
    call = JS_EnterCrossCompartmentCall(cx, obj);
    if(!call) {
        JS_EndRequest(cx);

        return NULL;
    }

    JS_GetUCPropertyAttributes(cx, obj, nameChars, nameLen, &attrs, &found);
    if (!found)
    {
        JS_LeaveCrossCompartmentCall(call);
        JS_EndRequest(cx);
        return NULL;
    }

    JS_ClearPendingException(cx);

    if(!JS_GetUCProperty(cx, obj, nameChars, nameLen, &val))
    {
        if (JS_IsExceptionPending(cx))
        {
            if (!JS_GetPendingException(cx, &pd.value))
            {
                JS_LeaveCrossCompartmentCall(call);
                JS_EndRequest(cx);
                return NULL;
            }
            pd.flags = JSPD_EXCEPTION;
        }
        else
        {
            pd.flags = JSPD_ERROR;
            pd.value = JSVAL_VOID;
        }
    }
    else
    {
        pd.value = val;
    }

    JS_LeaveCrossCompartmentCall(call);
    JS_EndRequest(cx);

    nameval = STRING_TO_JSVAL(name);
    if (!JS_ValueToId(cx, nameval, &nameid) ||
        !JS_IdToValue(cx, nameid, &pd.id)) {
        return NULL;
    }

    pd.slot = pd.spare = 0;
    pd.alias = JSVAL_NULL;
    pd.flags |= (attrs & JSPROP_ENUMERATE) ? JSPD_ENUMERATE : 0
        | (attrs & JSPROP_READONLY)  ? JSPD_READONLY  : 0
        | (attrs & JSPROP_PERMANENT) ? JSPD_PERMANENT : 0;

    return _newProperty(jsdc, &pd, JSDPD_HINTED);
}
Пример #15
0
ScriptInterface_impl::ScriptInterface_impl(const char* nativeScopeName, const shared_ptr<ScriptRuntime>& runtime) :
	m_runtime(runtime)
{
	JSBool ok;

	m_cx = JS_NewContext(m_runtime->m_rt, STACK_CHUNK_SIZE);
	ENSURE(m_cx);

	// For GC debugging:
	// JS_SetGCZeal(m_cx, 2);

	JS_SetContextPrivate(m_cx, NULL);

	JS_SetErrorReporter(m_cx, ErrorReporter);

	uint32 options = 0;
	options |= JSOPTION_STRICT; // "warn on dubious practice"
	options |= JSOPTION_XML; // "ECMAScript for XML support: parse <!-- --> as a token"
	options |= JSOPTION_VAROBJFIX; // "recommended" (fixes variable scoping)

	// Enable method JIT, unless script profiling/debugging is enabled (since profiling/debugging
	// hooks are incompatible with the JIT)
	// TODO: Verify what exactly is incompatible
	if (!g_ScriptProfilingEnabled && !g_JSDebuggerEnabled)
	{
		options |= JSOPTION_METHODJIT;

		// Some other JIT flags to experiment with:
		options |= JSOPTION_JIT;
		options |= JSOPTION_PROFILING;
	}

	JS_SetOptions(m_cx, options);

	JS_SetVersion(m_cx, JSVERSION_LATEST);

	// Threadsafe SpiderMonkey requires that we have a request before doing anything much
	JS_BeginRequest(m_cx);

	// We only want a single compartment per runtime
	if (m_runtime->m_compartmentGlobal)
	{
		m_call = JS_EnterCrossCompartmentCall(m_cx, m_runtime->m_compartmentGlobal);
		m_glob = JS_NewGlobalObject(m_cx, &global_class);
	}
	else
	{
		m_call = NULL;
		m_glob = JS_NewCompartmentAndGlobalObject(m_cx, &global_class, NULL);
		m_runtime->m_compartmentGlobal = m_glob;
	}

	ok = JS_InitStandardClasses(m_cx, m_glob);
	ENSURE(ok);

	JS_DefineProperty(m_cx, m_glob, "global", OBJECT_TO_JSVAL(m_glob), NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY
			| JSPROP_PERMANENT);

	m_nativeScope = JS_DefineObject(m_cx, m_glob, nativeScopeName, NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY
			| JSPROP_PERMANENT);

	JS_DefineFunction(m_cx, m_glob, "print", ::print,        0, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
	JS_DefineFunction(m_cx, m_glob, "log",   ::logmsg,       1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
	JS_DefineFunction(m_cx, m_glob, "warn",  ::warn,         1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
	JS_DefineFunction(m_cx, m_glob, "error", ::error,        1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
	JS_DefineFunction(m_cx, m_glob, "deepcopy", ::deepcopy,  1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);

	Register("ProfileStart", ::ProfileStart, 1);
	Register("ProfileStop", ::ProfileStop, 0);
}
Пример #16
0
static JSDContext*
_newJSDContext(JSRuntime*         jsrt, 
               JSD_UserCallbacks* callbacks, 
               void*              user,
               JSObject*          scopeobj)
{
    JSDContext* jsdc = NULL;
    JSCrossCompartmentCall *call = NULL;
    JSBool ok;

    if( ! jsrt )
        return NULL;

    if( ! _validateUserCallbacks(callbacks) )
        return NULL;

    jsdc = (JSDContext*) calloc(1, sizeof(JSDContext));
    if( ! jsdc )
        goto label_newJSDContext_failure;

    if( ! JSD_INIT_LOCKS(jsdc) )
        goto label_newJSDContext_failure;

    JS_INIT_CLIST(&jsdc->links);

    jsdc->jsrt = jsrt;

    if( callbacks )
        memcpy(&jsdc->userCallbacks, callbacks, callbacks->size);
    
    jsdc->user = user;

#ifdef JSD_HAS_DANGEROUS_THREAD
    jsdc->dangerousThread = _dangerousThread;
#endif

    JS_INIT_CLIST(&jsdc->threadsStates);
    JS_INIT_CLIST(&jsdc->sources);
    JS_INIT_CLIST(&jsdc->removedSources);

    jsdc->sourceAlterCount = 1;

    if( ! jsd_CreateAtomTable(jsdc) )
        goto label_newJSDContext_failure;

    if( ! jsd_InitObjectManager(jsdc) )
        goto label_newJSDContext_failure;

    if( ! jsd_InitScriptManager(jsdc) )
        goto label_newJSDContext_failure;

    jsdc->dumbContext = JS_NewContext(jsdc->jsrt, 256);
    if( ! jsdc->dumbContext )
        goto label_newJSDContext_failure;

    JS_BeginRequest(jsdc->dumbContext);
    JS_SetOptions(jsdc->dumbContext, JS_GetOptions(jsdc->dumbContext) | JSOPTION_ALLOW_XML);

    jsdc->glob = JS_NewCompartmentAndGlobalObject(jsdc->dumbContext, &global_class, NULL);

    if( ! jsdc->glob )
        goto label_newJSDContext_failure;

    call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, jsdc->glob);
    if( ! call )
        goto label_newJSDContext_failure;

    if ( ! JS_AddNamedObjectRoot(jsdc->dumbContext, &jsdc->glob, "JSD context global") )
        goto label_newJSDContext_failure;

    ok = JS_InitStandardClasses(jsdc->dumbContext, jsdc->glob);

    JS_LeaveCrossCompartmentCall(call);
    if( ! ok )
        goto label_newJSDContext_failure;

    JS_EndRequest(jsdc->dumbContext);

    jsdc->data = NULL;
    jsdc->inited = JS_TRUE;

    JSD_LOCK();
    JS_INSERT_LINK(&jsdc->links, &_jsd_context_list);
    JSD_UNLOCK();

    return jsdc;

label_newJSDContext_failure:
    if( jsdc ) {
        if ( jsdc->dumbContext && jsdc->glob )
            JS_RemoveObjectRootRT(JS_GetRuntime(jsdc->dumbContext), &jsdc->glob);
        jsd_DestroyObjectManager(jsdc);
        jsd_DestroyAtomTable(jsdc);
        if( jsdc->dumbContext )
            JS_EndRequest(jsdc->dumbContext);
        free(jsdc);
    }
    return NULL;
}