void WrapperPromiseCallback::Call(JS::Handle<JS::Value> aValue) { // AutoCxPusher and co. interact with xpconnect, which crashes on // workers. On workers we'll get the right context from // GetDefaultJSContextForThread(), and since there is only one context, we // don't need to push or pop it from the stack. JSContext* cx = nsContentUtils::GetDefaultJSContextForThread(); Maybe<AutoCxPusher> pusher; if (NS_IsMainThread()) { pusher.construct(cx); } Maybe<JSAutoCompartment> ac; EnterCompartment(ac, cx, aValue); ErrorResult rv; // If invoking callback threw an exception, run resolver's reject with the // thrown exception as argument and the synchronous flag set. JS::Rooted<JS::Value> value(cx, mCallback->Call(aValue, rv, CallbackObject::eRethrowExceptions)); rv.WouldReportJSException(); if (rv.Failed() && rv.IsJSException()) { JS::Rooted<JS::Value> value(cx); rv.StealJSException(cx, &value); Maybe<JSAutoCompartment> ac2; EnterCompartment(ac2, cx, value); mNextPromise->RejectInternal(cx, value, Promise::SyncTask); return; } // If the return value is the same as the promise itself, throw TypeError. if (value.isObject()) { JS::Rooted<JSObject*> valueObj(cx, &value.toObject()); Promise* returnedPromise; nsresult r = UNWRAP_OBJECT(Promise, valueObj, returnedPromise); if (NS_SUCCEEDED(r) && returnedPromise == mNextPromise) { const char* fileName = nullptr; uint32_t lineNumber = 0; // Try to get some information about the callback to report a sane error, // but don't try too hard (only deals with scripted functions). JS::Rooted<JSObject*> unwrapped(cx, js::CheckedUnwrap(mCallback->Callback())); if (unwrapped) { JSAutoCompartment ac(cx, unwrapped); if (JS_ObjectIsFunction(cx, unwrapped)) { JS::Rooted<JS::Value> asValue(cx, JS::ObjectValue(*unwrapped)); JS::Rooted<JSFunction*> func(cx, JS_ValueToFunction(cx, asValue)); MOZ_ASSERT(func); JSScript* script = JS_GetFunctionScript(cx, func); if (script) { fileName = JS_GetScriptFilename(cx, script); lineNumber = JS_GetScriptBaseLineNumber(cx, script); } } } // We're back in aValue's compartment here. JS::Rooted<JSString*> stack(cx, JS_GetEmptyString(JS_GetRuntime(cx))); JS::Rooted<JSString*> fn(cx, JS_NewStringCopyZ(cx, fileName)); if (!fn) { // Out of memory. Promise will stay unresolved. JS_ClearPendingException(cx); return; } JS::Rooted<JSString*> message(cx, JS_NewStringCopyZ(cx, "then() cannot return same Promise that it resolves.")); if (!message) { // Out of memory. Promise will stay unresolved. JS_ClearPendingException(cx); return; } JS::Rooted<JS::Value> typeError(cx); if (!JS::CreateTypeError(cx, stack, fn, lineNumber, 0, nullptr, message, &typeError)) { // Out of memory. Promise will stay unresolved. JS_ClearPendingException(cx); return; } mNextPromise->RejectInternal(cx, typeError, Promise::SyncTask); return; } } // Otherwise, run resolver's resolve with value and the synchronous flag // set. Maybe<JSAutoCompartment> ac2; EnterCompartment(ac2, cx, value); mNextPromise->ResolveInternal(cx, value, Promise::SyncTask); }
static JSScript * GetScript(JSContext *cx, JS::HandleObject funobj) { return JS_GetFunctionScript(cx, JS_GetObjectFunction(funobj)); }
nsresult leakmonJSObjectInfo::Init(leakmonObjectsInReportTable &aObjectsInReport) { mIsInitialized = PR_TRUE; JSContext *cx = leakmonService::GetJSContext(); NS_ENSURE_TRUE(cx, NS_ERROR_UNEXPECTED); JSAutoRequest ar(cx); if (!JSVAL_IS_PRIMITIVE(mJSValue)) { JSObject *obj = JSVAL_TO_OBJECT(mJSValue); // All of the objects in obj's prototype chain, and all // objects reachable from JS_NewPropertyIterator should // (I think?) be in the same compartment. JSAutoEnterCompartment ac; if (!ac.enter(cx, obj)) { return NS_ERROR_FAILURE; } JSObject *p; for (p = obj; p; p = JS_GetPrototype(cx, p)) { // Stack-scanning protects newly-created objects // (etor) from GC. (And protecting |etor| // should in turn protect |id|.) // JS_NewPropertyIterator has the nice property that it // avoids JS_Enumerate on native objects (where it can // execute code) and uses the scope properties, but doesn't // require this code to use the unstable OBJ_IS_NATIVE API. JSObject *etor = JS_NewPropertyIterator(cx, p); if (!etor) return NS_ERROR_OUT_OF_MEMORY; jsid id; while (JS_NextProperty(cx, etor, &id) && !JSID_IS_VOID(id)) { nsresult rv = AppendProperty(id, cx, aObjectsInReport); NS_ENSURE_SUCCESS(rv, rv); } } if (JS_ObjectIsFunction(cx, obj)) { JSFunction *fun = JS_ValueToFunction(cx, mJSValue); NS_ENSURE_TRUE(fun, NS_ERROR_UNEXPECTED); JSScript *script = JS_GetFunctionScript(cx, fun); if (script) { // null for native code const char *fname = JS_GetScriptFilename(cx, script); // XXX Do we know the encoding of this file name? mFileName = NS_ConvertUTF8toUTF16(fname); mLineStart = JS_GetScriptBaseLineNumber(cx, script); mLineEnd = mLineStart + JS_GetScriptLineExtent(cx, script) - 1; } } } ValueToString(cx, mJSValue, mString); return NS_OK; }
void WrapperPromiseCallback::Call(JS::Handle<JS::Value> aValue) { ThreadsafeAutoSafeJSContext cx; JSAutoCompartment ac(cx, mGlobal); JS::Rooted<JS::Value> value(cx, aValue); if (!JS_WrapValue(cx, &value)) { NS_WARNING("Failed to wrap value into the right compartment."); return; } ErrorResult rv; // If invoking callback threw an exception, run resolver's reject with the // thrown exception as argument and the synchronous flag set. JS::Rooted<JS::Value> retValue(cx, mCallback->Call(value, rv, CallbackObject::eRethrowExceptions)); rv.WouldReportJSException(); if (rv.Failed() && rv.IsJSException()) { JS::Rooted<JS::Value> value(cx); rv.StealJSException(cx, &value); if (!JS_WrapValue(cx, &value)) { NS_WARNING("Failed to wrap value into the right compartment."); return; } mNextPromise->RejectInternal(cx, value, Promise::SyncTask); return; } // If the return value is the same as the promise itself, throw TypeError. if (retValue.isObject()) { JS::Rooted<JSObject*> valueObj(cx, &retValue.toObject()); Promise* returnedPromise; nsresult r = UNWRAP_OBJECT(Promise, valueObj, returnedPromise); if (NS_SUCCEEDED(r) && returnedPromise == mNextPromise) { const char* fileName = nullptr; uint32_t lineNumber = 0; // Try to get some information about the callback to report a sane error, // but don't try too hard (only deals with scripted functions). JS::Rooted<JSObject*> unwrapped(cx, js::CheckedUnwrap(mCallback->Callback())); if (unwrapped) { JSAutoCompartment ac(cx, unwrapped); if (JS_ObjectIsFunction(cx, unwrapped)) { JS::Rooted<JS::Value> asValue(cx, JS::ObjectValue(*unwrapped)); JS::Rooted<JSFunction*> func(cx, JS_ValueToFunction(cx, asValue)); MOZ_ASSERT(func); JSScript* script = JS_GetFunctionScript(cx, func); if (script) { fileName = JS_GetScriptFilename(script); lineNumber = JS_GetScriptBaseLineNumber(cx, script); } } } // We're back in aValue's compartment here. JS::Rooted<JSString*> stack(cx, JS_GetEmptyString(JS_GetRuntime(cx))); JS::Rooted<JSString*> fn(cx, JS_NewStringCopyZ(cx, fileName)); if (!fn) { // Out of memory. Promise will stay unresolved. JS_ClearPendingException(cx); return; } JS::Rooted<JSString*> message(cx, JS_NewStringCopyZ(cx, "then() cannot return same Promise that it resolves.")); if (!message) { // Out of memory. Promise will stay unresolved. JS_ClearPendingException(cx); return; } JS::Rooted<JS::Value> typeError(cx); if (!JS::CreateTypeError(cx, stack, fn, lineNumber, 0, nullptr, message, &typeError)) { // Out of memory. Promise will stay unresolved. JS_ClearPendingException(cx); return; } mNextPromise->RejectInternal(cx, typeError, Promise::SyncTask); return; } } // Otherwise, run resolver's resolve with value and the synchronous flag // set. if (!JS_WrapValue(cx, &retValue)) { NS_WARNING("Failed to wrap value into the right compartment."); return; } mNextPromise->ResolveInternal(cx, retValue, Promise::SyncTask); }
AutoPushJSContext::AutoPushJSContext(nsISupports* aSecuritySupports, JSContext *cx) : mContext(cx), mPushResult(NS_OK) { nsCOMPtr<nsIJSContextStack> contextStack = do_GetService("@mozilla.org/js/xpc/ContextStack;1"); JS_BeginRequest(cx); JSContext* currentCX; if(contextStack && // Don't push if the current context is already on the stack. (NS_FAILED(contextStack->Peek(¤tCX)) || cx != currentCX) ) { if (NS_SUCCEEDED(contextStack->Push(cx))) { // Leave the reference in mContextStack to // indicate that we need to pop it in our dtor. mContextStack.swap(contextStack); } } nsCOMPtr<nsIScriptSecurityManager> secMan( do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &mPushResult)); if (NS_FAILED(mPushResult)) return; nsCOMPtr<nsIPrincipal> principal; mPushResult = secMan->GetPrincipalFromContext(cx, getter_AddRefs(principal)); if (NS_FAILED(mPushResult)) { JS_ReportError(cx, "failed to get a principal"); return; } // See if JavaScript is enabled for the current window PRBool jsEnabled = PR_FALSE; mPushResult = secMan->CanExecuteScripts(cx, principal, &jsEnabled); if (!jsEnabled) mPushResult = NS_ERROR_FAILURE; memset(&mFrame, 0, sizeof(mFrame)); if (NS_SUCCEEDED(mPushResult)) { // See if there are any scripts on the stack. // If not, we need to add a dummy frame with a principal. PRBool hasScript = PR_FALSE; JSStackFrame* tempFP = cx->fp; while (tempFP) { if (tempFP->script) { hasScript = PR_TRUE; break; } tempFP = tempFP->down; }; if (!hasScript) { JSPrincipals* jsprinc; principal->GetJSPrincipals(cx, &jsprinc); JSFunction *fun = JS_CompileFunctionForPrincipals(cx, JS_GetGlobalObject(cx), jsprinc, "anonymous", 0, nsnull, "", 0, "", 1); JSPRINCIPALS_DROP(cx, jsprinc); if (fun) { JSScript *script = JS_GetFunctionScript(cx, fun); mFrame.fun = fun; mFrame.script = script; mFrame.callee = JS_GetFunctionObject(fun); mFrame.scopeChain = JS_GetParent(cx, mFrame.callee); mFrame.down = cx->fp; mRegs.pc = script->code + script->length - 1; JS_ASSERT(static_cast<JSOp>(*mRegs.pc) == JSOP_STOP); mRegs.sp = NULL; mFrame.regs = &mRegs; cx->fp = &mFrame; } else mPushResult = NS_ERROR_OUT_OF_MEMORY; } } }
static JSScript * GetScript(JSContext *cx, JS::HandleObject funobj) { JS::RootedFunction fun(cx, JS_GetObjectFunction(funobj)); return JS_GetFunctionScript(cx, fun); }
nsresult WrapperPromiseCallback::Call(JSContext* aCx, JS::Handle<JS::Value> aValue) { JS::ExposeObjectToActiveJS(mGlobal); JS::ExposeValueToActiveJS(aValue); JSAutoCompartment ac(aCx, mGlobal); JS::Rooted<JS::Value> value(aCx, aValue); if (!JS_WrapValue(aCx, &value)) { NS_WARNING("Failed to wrap value into the right compartment."); return NS_ERROR_FAILURE; } ErrorResult rv; // PromiseReactionTask step 6 JS::Rooted<JS::Value> retValue(aCx); JSCompartment* compartment; if (mNextPromise) { compartment = mNextPromise->Compartment(); } else { MOZ_ASSERT(mNextPromiseObj); compartment = js::GetObjectCompartment(mNextPromiseObj); } mCallback->Call(value, &retValue, rv, "promise callback", CallbackObject::eRethrowExceptions, compartment); rv.WouldReportJSException(); // PromiseReactionTask step 7 if (rv.Failed()) { JS::Rooted<JS::Value> value(aCx); { // Scope for JSAutoCompartment // Convert the ErrorResult to a JS exception object that we can reject // ourselves with. This will be exactly the exception that would get // thrown from a binding method whose ErrorResult ended up with whatever // is on "rv" right now. Do this in the promise reflector compartment. Maybe<JSAutoCompartment> ac; if (mNextPromise) { ac.emplace(aCx, mNextPromise->GlobalJSObject()); } else { ac.emplace(aCx, mNextPromiseObj); } DebugOnly<bool> conversionResult = ToJSValue(aCx, rv, &value); MOZ_ASSERT(conversionResult); } if (mNextPromise) { mNextPromise->RejectInternal(aCx, value); } else { JS::Rooted<JS::Value> ignored(aCx); ErrorResult rejectRv; mRejectFunc->Call(value, &ignored, rejectRv); // This reported any JS exceptions; we just have a pointless exception on // there now. rejectRv.SuppressException(); } return NS_OK; } // If the return value is the same as the promise itself, throw TypeError. if (retValue.isObject()) { JS::Rooted<JSObject*> valueObj(aCx, &retValue.toObject()); valueObj = js::CheckedUnwrap(valueObj); JS::Rooted<JSObject*> nextPromiseObj(aCx); if (mNextPromise) { nextPromiseObj = mNextPromise->GetWrapper(); } else { MOZ_ASSERT(mNextPromiseObj); nextPromiseObj = mNextPromiseObj; } // XXXbz shouldn't this check be over in ResolveInternal anyway? if (valueObj == nextPromiseObj) { const char* fileName = nullptr; uint32_t lineNumber = 0; // Try to get some information about the callback to report a sane error, // but don't try too hard (only deals with scripted functions). JS::Rooted<JSObject*> unwrapped(aCx, js::CheckedUnwrap(mCallback->Callback())); if (unwrapped) { JSAutoCompartment ac(aCx, unwrapped); if (JS_ObjectIsFunction(aCx, unwrapped)) { JS::Rooted<JS::Value> asValue(aCx, JS::ObjectValue(*unwrapped)); JS::Rooted<JSFunction*> func(aCx, JS_ValueToFunction(aCx, asValue)); MOZ_ASSERT(func); JSScript* script = JS_GetFunctionScript(aCx, func); if (script) { fileName = JS_GetScriptFilename(script); lineNumber = JS_GetScriptBaseLineNumber(aCx, script); } } } // We're back in aValue's compartment here. JS::Rooted<JSString*> fn(aCx, JS_NewStringCopyZ(aCx, fileName)); if (!fn) { // Out of memory. Promise will stay unresolved. JS_ClearPendingException(aCx); return NS_ERROR_OUT_OF_MEMORY; } JS::Rooted<JSString*> message(aCx, JS_NewStringCopyZ(aCx, "then() cannot return same Promise that it resolves.")); if (!message) { // Out of memory. Promise will stay unresolved. JS_ClearPendingException(aCx); return NS_ERROR_OUT_OF_MEMORY; } JS::Rooted<JS::Value> typeError(aCx); if (!JS::CreateError(aCx, JSEXN_TYPEERR, nullptr, fn, lineNumber, 0, nullptr, message, &typeError)) { // Out of memory. Promise will stay unresolved. JS_ClearPendingException(aCx); return NS_ERROR_OUT_OF_MEMORY; } if (mNextPromise) { mNextPromise->RejectInternal(aCx, typeError); } else { JS::Rooted<JS::Value> ignored(aCx); ErrorResult rejectRv; mRejectFunc->Call(typeError, &ignored, rejectRv); // This reported any JS exceptions; we just have a pointless exception // on there now. rejectRv.SuppressException(); } return NS_OK; } } // Otherwise, run resolver's resolve with value. if (!JS_WrapValue(aCx, &retValue)) { NS_WARNING("Failed to wrap value into the right compartment."); return NS_ERROR_FAILURE; } if (mNextPromise) { mNextPromise->ResolveInternal(aCx, retValue); } else { JS::Rooted<JS::Value> ignored(aCx); ErrorResult resolveRv; mResolveFunc->Call(retValue, &ignored, resolveRv); // This reported any JS exceptions; we just have a pointless exception // on there now. resolveRv.SuppressException(); } return NS_OK; }