Bug 897322 - Allow callers to manually fire OnNewGlobalObject when bootstrapping is complete. r=luke

This commit is contained in:
Bobby Holley 2013-08-01 18:38:47 -07:00
Родитель fa44cda1c7
Коммит 6f87931f0a
24 изменённых файлов: 99 добавлений и 31 удалений

Просмотреть файл

@ -256,6 +256,7 @@ nsXBLDocGlobalObject::EnsureScriptEnvironment()
.setInvisibleToDebugger(true);
mJSObject = JS_NewGlobalObject(cx, &gSharedGlobalClass,
nsJSPrincipals::get(GetPrincipal()),
JS::DontFireOnNewGlobalHook,
options);
if (!mJSObject)
return NS_OK;

Просмотреть файл

@ -767,7 +767,8 @@ nsXULPDGlobalObject::EnsureScriptEnvironment()
.setInvisibleToDebugger(true);
JS::Rooted<JSObject*> newGlob(cx,
JS_NewGlobalObject(cx, &gSharedGlobalClass,
nsJSPrincipals::get(GetPrincipal()), options));
nsJSPrincipals::get(GetPrincipal()), JS::DontFireOnNewGlobalHook,
options));
if (!newGlob)
return NS_OK;

Просмотреть файл

@ -535,7 +535,8 @@ class ThreadLocalJSRuntime
JSAutoRequest ar(mContext);
mGlobal = JS_NewGlobalObject(mContext, &sGlobalClass, NULL);
mGlobal = JS_NewGlobalObject(mContext, &sGlobalClass, NULL,
JS::FireOnNewGlobalHook);
NS_ENSURE_TRUE(mGlobal, NS_ERROR_OUT_OF_MEMORY);
js::SetDefaultObjectForContext(mContext, mGlobal);

Просмотреть файл

@ -955,7 +955,7 @@ CreateDedicatedWorkerGlobalScope(JSContext* aCx)
options.setVersion(JSVERSION_LATEST);
JS::Rooted<JSObject*> global(aCx,
JS_NewGlobalObject(aCx, DedicatedWorkerGlobalScope::Class(),
GetWorkerPrincipal(), options));
GetWorkerPrincipal(), JS::DontFireOnNewGlobalHook, options));
if (!global) {
return NULL;
}
@ -1033,6 +1033,8 @@ CreateDedicatedWorkerGlobalScope(JSContext* aCx)
return NULL;
}
JS_FireOnNewGlobalObject(aCx, global);
return global;
}

Просмотреть файл

@ -3350,7 +3350,7 @@ CreateJSDGlobal(JSContext *aCx, JSClass *aClasp)
NS_ENSURE_SUCCESS(rv, nullptr);
JSPrincipals *jsPrin = nsJSPrincipals::get(nullPrin);
JSObject *global = JS_NewGlobalObject(aCx, aClasp, jsPrin);
JS::RootedObject global(aCx, JS_NewGlobalObject(aCx, aClasp, jsPrin, JS::DontFireOnNewGlobalHook));
NS_ENSURE_TRUE(global, nullptr);
// We have created a new global let's attach a private to it
@ -3359,6 +3359,8 @@ CreateJSDGlobal(JSContext *aCx, JSClass *aClasp)
new SandboxPrivate(nullPrin, global);
JS_SetPrivate(global, sbp.forget().get());
JS_FireOnNewGlobalObject(aCx, global);
return global;
}

Просмотреть файл

@ -70,7 +70,8 @@ main (int argc, const char **argv)
/* Create the global object. */
JS::CompartmentOptions options;
options.setVersion(JSVERSION_LATEST);
RootedObject global(cx, checkPtr(JS_NewGlobalObject(cx, &global_class, NULL, options)));
RootedObject global(cx, checkPtr(JS_NewGlobalObject(cx, &global_class, NULL,
JS::FireOnNewGlobalHook, options)));
js::SetDefaultObjectForContext(cx, global);
JSAutoCompartment ac(cx, global);

Просмотреть файл

@ -67,9 +67,9 @@ BEGIN_TEST(testBug604087)
{
JS::RootedObject outerObj(cx, js::Wrapper::New(cx, global, global->getProto(), global,
&OuterWrapper::singleton));
JS::RootedObject compartment2(cx, JS_NewGlobalObject(cx, getGlobalClass(), NULL));
JS::RootedObject compartment3(cx, JS_NewGlobalObject(cx, getGlobalClass(), NULL));
JS::RootedObject compartment4(cx, JS_NewGlobalObject(cx, getGlobalClass(), NULL));
JS::RootedObject compartment2(cx, JS_NewGlobalObject(cx, getGlobalClass(), NULL, JS::FireOnNewGlobalHook));
JS::RootedObject compartment3(cx, JS_NewGlobalObject(cx, getGlobalClass(), NULL, JS::FireOnNewGlobalHook));
JS::RootedObject compartment4(cx, JS_NewGlobalObject(cx, getGlobalClass(), NULL, JS::FireOnNewGlobalHook));
JS::RootedObject c2wrapper(cx, wrap(cx, outerObj, compartment2));
CHECK(c2wrapper);

Просмотреть файл

@ -44,7 +44,7 @@ CustomMethod(JSContext *cx, unsigned argc, Value *vp)
BEGIN_TEST(test_CallNonGenericMethodOnProxy)
{
// Create the first global object and compartment
JS::RootedObject globalA(cx, JS_NewGlobalObject(cx, getGlobalClass(), NULL));
JS::RootedObject globalA(cx, JS_NewGlobalObject(cx, getGlobalClass(), NULL, JS::FireOnNewGlobalHook));
CHECK(globalA);
JS::RootedObject customA(cx, JS_NewObject(cx, &CustomClass, NULL, NULL));
@ -60,7 +60,7 @@ BEGIN_TEST(test_CallNonGenericMethodOnProxy)
// Now create the second global object and compartment...
{
JS::RootedObject globalB(cx, JS_NewGlobalObject(cx, getGlobalClass(), NULL));
JS::RootedObject globalB(cx, JS_NewGlobalObject(cx, getGlobalClass(), NULL, JS::FireOnNewGlobalHook));
CHECK(globalB);
// ...and enter it.

Просмотреть файл

@ -43,7 +43,7 @@ BEGIN_TEST(testChromeBuffer)
{
JS_SetTrustedPrincipals(rt, &system_principals);
trusted_glob = JS_NewGlobalObject(cx, &global_class, &system_principals);
trusted_glob = JS_NewGlobalObject(cx, &global_class, &system_principals, JS::FireOnNewGlobalHook);
CHECK(trusted_glob);
if (!JS_AddNamedObjectRoot(cx, &trusted_glob, "trusted-global"))

Просмотреть файл

@ -149,7 +149,7 @@ END_TEST(testDebugger_throwHook)
BEGIN_TEST(testDebugger_debuggerObjectVsDebugMode)
{
CHECK(JS_DefineDebuggerObject(cx, global));
JS::RootedObject debuggee(cx, JS_NewGlobalObject(cx, getGlobalClass(), NULL));
JS::RootedObject debuggee(cx, JS_NewGlobalObject(cx, getGlobalClass(), NULL, JS::FireOnNewGlobalHook));
CHECK(debuggee);
{
@ -189,7 +189,7 @@ BEGIN_TEST(testDebugger_newScriptHook)
{
// Test that top-level indirect eval fires the newScript hook.
CHECK(JS_DefineDebuggerObject(cx, global));
JS::RootedObject g(cx, JS_NewGlobalObject(cx, getGlobalClass(), NULL));
JS::RootedObject g(cx, JS_NewGlobalObject(cx, getGlobalClass(), NULL, JS::FireOnNewGlobalHook));
CHECK(g);
{
JSAutoCompartment ae(cx, g);

Просмотреть файл

@ -61,7 +61,7 @@ eval(const char *asciiChars, JSPrincipals *principals, JSPrincipals *originPrinc
chars[i] = asciiChars[i];
chars[len] = 0;
JS::RootedObject global(cx, JS_NewGlobalObject(cx, getGlobalClass(), principals));
JS::RootedObject global(cx, JS_NewGlobalObject(cx, getGlobalClass(), principals, JS::FireOnNewGlobalHook));
CHECK(global);
JSAutoCompartment ac(cx, global);
CHECK(JS_InitStandardClasses(cx, global));

Просмотреть файл

@ -56,7 +56,7 @@ JSObject * JSAPITest::createGlobal(JSPrincipals *principals)
/* Create the global object. */
JS::CompartmentOptions options;
options.setVersion(JSVERSION_LATEST);
global = JS_NewGlobalObject(cx, getGlobalClass(), principals, options);
global = JS_NewGlobalObject(cx, getGlobalClass(), principals, JS::FireOnNewGlobalHook, options);
if (!global)
return NULL;
JS_AddNamedObjectRoot(cx, &global, "test-global");

Просмотреть файл

@ -2907,6 +2907,7 @@ class AutoHoldZone
JS_PUBLIC_API(JSObject *)
JS_NewGlobalObject(JSContext *cx, JSClass *clasp, JSPrincipals *principals,
JS::OnNewGlobalHookOption hookOption,
const JS::CompartmentOptions &options)
{
AssertHeapIsIdle(cx);
@ -2944,16 +2945,23 @@ JS_NewGlobalObject(JSContext *cx, JSClass *clasp, JSPrincipals *principals,
if (!global)
return NULL;
// This hook is infallible, because we can't really throw at this point.
// The global object is already created and in the heap, which is
// externally observable since the finalize hook will be called when the
// global is GCed. This will eat OOM and slow script, but if that happens
// we'll likely run up into them again soon in a fallible context.
Debugger::onNewGlobalObject(cx, global);
if (hookOption == JS::FireOnNewGlobalHook)
JS_FireOnNewGlobalObject(cx, global);
return global;
}
JS_PUBLIC_API(void)
JS_FireOnNewGlobalObject(JSContext *cx, JS::HandleObject global)
{
// This hook is infallible, because we don't really want arbitrary script
// to be able to throw errors during delicate global creation routines.
// This infallibility will eat OOM and slow script, but if that happens
// we'll likely run up into them again soon in a fallible context.
Rooted<js::GlobalObject*> globalObject(cx, &global->as<GlobalObject>());
Debugger::onNewGlobalObject(cx, globalObject);
}
JS_PUBLIC_API(JSObject *)
JS_NewObject(JSContext *cx, JSClass *jsclasp, JSObject *protoArg, JSObject *parentArg)
{

Просмотреть файл

@ -3247,12 +3247,41 @@ struct JS_PUBLIC_API(CompartmentOptions) {
}
};
// During global creation, we fire notifications to callbacks registered
// via the Debugger API. These callbacks are arbitrary script, and can touch
// the global in arbitrary ways. When that happens, the global should not be
// in a half-baked state. But this creates a problem for consumers that need
// to set slots on the global to put it in a consistent state.
//
// This API provides a way for consumers to set slots atomically (immediately
// after the global is created), before any debugger hooks are fired. It's
// unfortunately on the clunky side, but that's the way the cookie crumbles.
//
// If callers have no additional state on the global to set up, they may pass
// |FireOnNewGlobalHook| to JS_NewGlobalObject, which causes that function to
// fire the hook as its final act before returning. Otherwise, callers should
// pass |DontFireOnNewGlobalHook|, which means that they are responsible for
// invoking JS_FireOnNewGlobalObject upon successfully creating the global. If
// an error occurs and the operation aborts, callers should skip firing the
// hook. But otherwise, callers must take care to fire the hook exactly once
// before compiling any script in the global's scope (we have assertions in
// place to enforce this). This lets us be sure that debugger clients never miss
// breakpoints.
enum OnNewGlobalHookOption {
FireOnNewGlobalHook,
DontFireOnNewGlobalHook
};
} /* namespace JS */
extern JS_PUBLIC_API(JSObject *)
JS_NewGlobalObject(JSContext *cx, JSClass *clasp, JSPrincipals *principals,
JS::OnNewGlobalHookOption hookOption,
const JS::CompartmentOptions &options = JS::CompartmentOptions());
extern JS_PUBLIC_API(void)
JS_FireOnNewGlobalObject(JSContext *cx, JS::HandleObject global);
extern JS_PUBLIC_API(JSObject *)
JS_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent);

Просмотреть файл

@ -204,7 +204,8 @@ js::StartOffThreadParseScript(JSContext *cx, const CompileOptions &options,
JS::CompartmentOptions compartmentOptions(cx->compartment()->options());
compartmentOptions.setZone(JS::FreshZone);
JSObject *global = JS_NewGlobalObject(cx, &workerGlobalClass, NULL, compartmentOptions);
JSObject *global = JS_NewGlobalObject(cx, &workerGlobalClass, NULL,
JS::FireOnNewGlobalHook, compartmentOptions);
if (!global)
return false;

Просмотреть файл

@ -2507,7 +2507,8 @@ static JSClass sandbox_class = {
static JSObject *
NewSandbox(JSContext *cx, bool lazy)
{
RootedObject obj(cx, JS_NewGlobalObject(cx, &sandbox_class, NULL));
RootedObject obj(cx, JS_NewGlobalObject(cx, &sandbox_class, NULL,
JS::DontFireOnNewGlobalHook));
if (!obj)
return NULL;
@ -2521,6 +2522,8 @@ NewSandbox(JSContext *cx, bool lazy)
return NULL;
}
JS_FireOnNewGlobalObject(cx, obj);
if (!cx->compartment()->wrap(cx, obj.address()))
return NULL;
return obj;
@ -4884,7 +4887,8 @@ DestroyContext(JSContext *cx, bool withGC)
static JSObject *
NewGlobalObject(JSContext *cx, JS::CompartmentOptions &options)
{
RootedObject glob(cx, JS_NewGlobalObject(cx, &global_class, NULL, options));
RootedObject glob(cx, JS_NewGlobalObject(cx, &global_class, NULL,
JS::DontFireOnNewGlobalHook, options));
if (!glob)
return NULL;
@ -4953,6 +4957,8 @@ NewGlobalObject(JSContext *cx, JS::CompartmentOptions &options)
InitDOMObject(domProto);
}
JS_FireOnNewGlobalObject(cx, glob);
return glob;
}

Просмотреть файл

@ -688,7 +688,8 @@ JSRuntime::initSelfHosting(JSContext *cx)
{
JS_ASSERT(!selfHostingGlobal_);
RootedObject savedGlobal(cx, js::DefaultObjectForContextOrNull(cx));
if (!(selfHostingGlobal_ = JS_NewGlobalObject(cx, &self_hosting_global_class, NULL)))
if (!(selfHostingGlobal_ = JS_NewGlobalObject(cx, &self_hosting_global_class,
NULL, JS::DontFireOnNewGlobalHook)))
return false;
JSAutoCompartment ac(cx, selfHostingGlobal_);
js::SetDefaultObjectForContext(cx, selfHostingGlobal_);
@ -704,6 +705,8 @@ JSRuntime::initSelfHosting(JSContext *cx)
if (!JS_DefineFunctions(cx, shg, intrinsic_functions))
return false;
JS_FireOnNewGlobalObject(cx, shg);
/*
* In self-hosting mode, scripts emit JSOP_CALLINTRINSIC instead of
* JSOP_NAME or JSOP_GNAME to access unbound variables. JSOP_CALLINTRINSIC

Просмотреть файл

@ -3368,6 +3368,8 @@ xpc_CreateSandboxObject(JSContext *cx, jsval *vp, nsISupports *prinOrSop, Sandbo
// about:memory may use that information
xpc::SetLocationForGlobal(sandbox, options.sandboxName);
JS_FireOnNewGlobalObject(cx, sandbox);
return NS_OK;
}

Просмотреть файл

@ -177,6 +177,8 @@ XPCJSContextStack::GetSafeJSContext()
if (NS_FAILED(xpc->InitClasses(mSafeJSContext, glob)))
MOZ_CRASH();
JS_FireOnNewGlobalObject(mSafeJSContext, glob);
// Save it off so we can destroy it later.
mOwnSafeJSContext = mSafeJSContext;

Просмотреть файл

@ -407,8 +407,12 @@ XPCWrappedNative::WrapNewGlobal(xpcObjectHelper &nativeHelper,
// Call the common creation finish routine. This does all of the bookkeeping
// like inserting the wrapper into the wrapper map and setting up the wrapper
// cache.
return FinishCreate(scope, iface, nativeHelper.GetWrapperCache(),
wrapper, wrappedGlobal);
nsresult rv = FinishCreate(scope, iface, nativeHelper.GetWrapperCache(),
wrapper, wrappedGlobal);
NS_ENSURE_SUCCESS(rv, rv);
JS_FireOnNewGlobalObject(cx, global);
return NS_OK;
}
// static

Просмотреть файл

@ -469,7 +469,8 @@ CreateGlobalObject(JSContext *cx, JSClass *clasp, nsIPrincipal *principal,
MOZ_ASSERT(principal);
RootedObject global(cx,
JS_NewGlobalObject(cx, clasp, nsJSPrincipals::get(principal), aOptions));
JS_NewGlobalObject(cx, clasp, nsJSPrincipals::get(principal),
JS::DontFireOnNewGlobalHook, aOptions));
if (!global)
return nullptr;
JSAutoCompartment ac(cx, global);

Просмотреть файл

@ -540,7 +540,8 @@ private:
JS::CompartmentOptions options;
options.setZone(JS::SystemZone)
.setVersion(JSVERSION_LATEST);
mGlobal = JS_NewGlobalObject(mContext, &sGlobalClass, nullptr, options);
mGlobal = JS_NewGlobalObject(mContext, &sGlobalClass, nullptr,
JS::DontFireOnNewGlobalHook, options);
NS_ENSURE_TRUE(mGlobal, NS_ERROR_OUT_OF_MEMORY);
JSAutoCompartment ac(mContext, mGlobal);
@ -552,6 +553,9 @@ private:
if (!JS_DefineFunctions(mContext, mGlobal, PACGlobalFunctions))
return NS_ERROR_FAILURE;
JS::Rooted<JSObject*> rootedGlobal(mContext, mGlobal);
JS_FireOnNewGlobalObject(mContext, rootedGlobal);
return NS_OK;
}
};

Просмотреть файл

@ -522,7 +522,7 @@ int main(int argc, char** argv)
};
JSObject *glob = nullptr;
if (use_js)
glob = JS_NewGlobalObject(cx, &global_class, nullptr);
glob = JS_NewGlobalObject(cx, &global_class, nullptr, JS::FireOnNewGlobalHook);
if (!glob)
use_js = false;
mozilla::Maybe<JSAutoCompartment> ac;

Просмотреть файл

@ -63,7 +63,7 @@ SaveProfileTask::Run() {
JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
};
JSObject *obj = JS_NewGlobalObject(cx, &c, NULL);
JSObject *obj = JS_NewGlobalObject(cx, &c, NULL, JS::FireOnNewGlobalHook);
std::ofstream stream;
stream.open(tmpPath.get());