void GetEntryHelper::CompleteOperation(JSObject* aObj) { MOZ_ASSERT(mParts.IsEmpty()); if (mType == FileSystemDirectoryEntry::eGetFile) { RefPtr<File> file; if (NS_FAILED(UNWRAP_OBJECT(File, aObj, file))) { Error(NS_ERROR_DOM_TYPE_MISMATCH_ERR); return; } RefPtr<FileSystemFileEntry> entry = new FileSystemFileEntry(mParentEntry->GetParentObject(), file, mParentEntry, mFileSystem); mSuccessCallback->HandleEvent(*entry); return; } MOZ_ASSERT(mType == FileSystemDirectoryEntry::eGetDirectory); RefPtr<Directory> directory; if (NS_FAILED(UNWRAP_OBJECT(Directory, aObj, directory))) { Error(NS_ERROR_DOM_TYPE_MISMATCH_ERR); return; } RefPtr<FileSystemDirectoryEntry> entry = new FileSystemDirectoryEntry(mParentEntry->GetParentObject(), directory, mParentEntry, mFileSystem); mSuccessCallback->HandleEvent(*entry); }
Promise* WrapperPromiseCallback::GetDependentPromise() { // Per spec, various algorithms like all() and race() are actually implemented // in terms of calling then() but passing it the resolve/reject functions that // are passed as arguments to function passed to the Promise constructor. // That will cause the promise in question to hold on to a // WrapperPromiseCallback, but the dependent promise should really be the one // whose constructor those functions came from, not the about-to-be-ignored // return value of "then". So try to determine whether we're in that case and // if so go ahead and dig the dependent promise out of the function we have. JSObject* callable = mCallback->Callable(); // Unwrap it, in case it's a cross-compartment wrapper. Our caller here is // system, so it's really ok to just go and unwrap. callable = js::UncheckedUnwrap(callable); if (JS_IsNativeFunction(callable, Promise::JSCallback)) { JS::Value promiseVal = js::GetFunctionNativeReserved(callable, Promise::SLOT_PROMISE); Promise* promise; UNWRAP_OBJECT(Promise, &promiseVal.toObject(), promise); return promise; } if (mNextPromise) { return mNextPromise; } Promise* promise; if (NS_SUCCEEDED(UNWRAP_OBJECT(Promise, mNextPromiseObj, promise))) { return promise; } // Oh, well. return nullptr; }
bool StructuredCloneHelper::WriteCallback(JSContext* aCx, JSStructuredCloneWriter* aWriter, JS::Handle<JSObject*> aObj) { if (!mSupportsCloning) { return false; } // See if this is a File/Blob object. { Blob* blob = nullptr; if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) { BlobImpl* blobImpl = blob->Impl(); if (JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB, mBlobImplArray.Length())) { mBlobImplArray.AppendElement(blobImpl); return true; } return false; } } { FileList* fileList = nullptr; if (NS_SUCCEEDED(UNWRAP_OBJECT(FileList, aObj, fileList))) { // A FileList is serialized writing the X number of elements and the offset // from mBlobImplArray. The Read will take X elements from mBlobImplArray // starting from the offset. if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILELIST, fileList->Length()) || !JS_WriteUint32Pair(aWriter, 0, mBlobImplArray.Length())) { return false; } for (uint32_t i = 0; i < fileList->Length(); ++i) { mBlobImplArray.AppendElement(fileList->Item(i)->Impl()); } return true; } } // See if this is an ImageBitmap object. { ImageBitmap* imageBitmap = nullptr; if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageBitmap, aObj, imageBitmap))) { return ImageBitmap::WriteStructuredClone(aWriter, GetImages(), imageBitmap); } } return NS_DOMWriteStructuredClone(aCx, aWriter, aObj, nullptr); }
static bool NativeHandlerCallback(JSContext* aCx, unsigned aArgc, JS::Value* aVp) { JS::CallArgs args = CallArgsFromVp(aArgc, aVp); JS::Rooted<JS::Value> v(aCx, js::GetFunctionNativeReserved(&args.callee(), SLOT_NATIVEHANDLER)); MOZ_ASSERT(v.isObject()); PromiseNativeHandler* handler = nullptr; if (NS_FAILED(UNWRAP_OBJECT(PromiseNativeHandler, &v.toObject(), handler))) { return Throw(aCx, NS_ERROR_UNEXPECTED); } v = js::GetFunctionNativeReserved(&args.callee(), SLOT_NATIVEHANDLER_TASK); NativeHandlerTask task = static_cast<NativeHandlerTask>(v.toInt32()); if (task == NativeHandlerTask::Resolve) { handler->ResolvedCallback(aCx, args.get(0)); } else { MOZ_ASSERT(task == NativeHandlerTask::Reject); handler->RejectedCallback(aCx, args.get(0)); } return true; }
bool StructuredCloneHelper::WriteTransferCallback(JSContext* aCx, JS::Handle<JSObject*> aObj, uint32_t* aTag, JS::TransferableOwnership* aOwnership, void** aContent, uint64_t* aExtraData) { if (!mSupportsTransferring) { return false; } { MessagePortBase* port = nullptr; nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port); if (NS_SUCCEEDED(rv)) { // We use aExtraData to store the index of this new port identifier. *aExtraData = mPortIdentifiers.Length(); MessagePortIdentifier* identifier = mPortIdentifiers.AppendElement(); if (!port->CloneAndDisentangle(*identifier)) { return false; } *aTag = SCTAG_DOM_MAP_MESSAGEPORT; *aOwnership = JS::SCTAG_TMO_CUSTOM; *aContent = nullptr; return true; } } return false; }
bool WriteTransfer(JSContext* aCx, JS::Handle<JSObject*> aObj, void* aClosure, uint32_t* aTag, JS::TransferableOwnership* aOwnership, void** aContent, uint64_t* aExtraData) { MOZ_ASSERT(aClosure); auto* closure = static_cast<StructuredCloneClosureInternal*>(aClosure); MessagePortBase* port = nullptr; nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port); if (NS_FAILED(rv)) { return false; } if (closure->mTransferredPorts.Contains(port)) { // No duplicates. return false; } MessagePortIdentifier identifier; if (!port->CloneAndDisentangle(identifier)) { return false; } closure->mClosure.mMessagePortIdentifiers.AppendElement(identifier); closure->mTransferredPorts.AppendElement(port); *aTag = SCTAG_DOM_MAP_MESSAGEPORT; *aOwnership = JS::SCTAG_TMO_CUSTOM; *aContent = nullptr; *aExtraData = closure->mClosure.mMessagePortIdentifiers.Length() - 1; return true; }
static bool PostMessageTransferStructuredClone(JSContext* aCx, JS::Handle<JSObject*> aObj, void* aClosure, uint32_t* aTag, JS::TransferableOwnership* aOwnership, void** aContent, uint64_t *aExtraData) { StructuredCloneInfo* scInfo = static_cast<StructuredCloneInfo*>(aClosure); NS_ASSERTION(scInfo, "Must have scInfo!"); MessagePortBase *port = nullptr; nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port); if (NS_SUCCEEDED(rv)) { nsRefPtr<MessagePortBase> newPort; if (scInfo->mPorts.Get(port, getter_AddRefs(newPort))) { // No duplicate. return false; } newPort = port->Clone(); scInfo->mPorts.Put(port, newPort); *aTag = SCTAG_DOM_MAP_MESSAGEPORT; *aOwnership = JS::SCTAG_TMO_CUSTOM; *aContent = newPort; *aExtraData = 0; return true; } return false; }
already_AddRefed<JSWindowActorChild> WindowGlobalChild::GetActor( const nsAString& aName, ErrorResult& aRv) { // Check if this actor has already been created, and return it if it has. if (mWindowActors.Contains(aName)) { return do_AddRef(mWindowActors.GetWeak(aName)); } // Otherwise, we want to create a new instance of this actor. Call into the // JSWindowActorService to trigger construction. RefPtr<JSWindowActorService> actorSvc = JSWindowActorService::GetSingleton(); if (!actorSvc) { return nullptr; } JS::RootedObject obj(RootingCx()); actorSvc->ConstructActor(aName, /* aChildSide */ false, mBrowsingContext, &obj, aRv); if (aRv.Failed()) { return nullptr; } // Unwrap our actor to a JSWindowActorChild object. RefPtr<JSWindowActorChild> actor; if (NS_FAILED(UNWRAP_OBJECT(JSWindowActorChild, &obj, actor))) { return nullptr; } MOZ_RELEASE_ASSERT(!actor->Manager(), "mManager was already initialized once!"); actor->Init(aName, this); mWindowActors.Put(aName, actor); return actor.forget(); }
static Promise* UnwrapPromise(JS::Handle<JSObject*> aPromise, ErrorResult& aRv) { Promise* promise; if (NS_WARN_IF(NS_FAILED(UNWRAP_OBJECT(Promise, aPromise, promise)))) { aRv.ThrowTypeError<MSG_IS_NOT_PROMISE>(NS_LITERAL_STRING("Argument")); return nullptr; } return promise; }
Promise* GetPromise(JSContext* aCx, JS::Handle<JSObject*> aFunc) { JS::Value promiseVal = js::GetFunctionNativeReserved(aFunc, SLOT_PROMISE); MOZ_ASSERT(promiseVal.isObject()); Promise* promise; UNWRAP_OBJECT(Promise, &promiseVal.toObject(), promise); return promise; }
Promise* InvokePromiseFuncCallback::GetDependentPromise() { Promise* promise; if (NS_SUCCEEDED(UNWRAP_OBJECT(Promise, mNextPromiseObj, promise))) { return promise; } // Oh, well. return nullptr; }
static nsGlobalWindow* GetWindowFromGlobal(JSObject* aGlobal) { nsGlobalWindow* win; if (NS_SUCCEEDED(UNWRAP_OBJECT(Window, aGlobal, win))) { return win; } XPCWrappedNative* wrapper = XPCWrappedNative::Get(aGlobal); nsCOMPtr<nsPIDOMWindow> piWin = do_QueryWrappedNative(wrapper); MOZ_ASSERT(piWin); return static_cast<nsGlobalWindow*>(piWin.get()); }
NS_IMETHODIMP WebVTTListener::OnRegion(JS::Handle<JS::Value> aRegion, JSContext* aCx) { if (!aRegion.isObject()) { return NS_ERROR_FAILURE; } TextTrackRegion* region; nsresult rv = UNWRAP_OBJECT(VTTRegion, &aRegion.toObject(), region); NS_ENSURE_SUCCESS(rv, rv); mElement->mTrack->AddRegion(*region); return NS_OK; }
NS_IMETHODIMP WebVTTListener::OnCue(JS::Handle<JS::Value> aCue, JSContext* aCx) { if (!aCue.isObject()) { return NS_ERROR_FAILURE; } TextTrackCue* cue = nullptr; nsresult rv = UNWRAP_OBJECT(VTTCue, &aCue.toObject(), cue); NS_ENSURE_SUCCESS(rv, rv); cue->SetTrackElement(mElement); mElement->mTrack->AddCue(*cue); return NS_OK; }
// static nsresult IDBKeyRange::FromJSVal(JSContext* aCx, JS::Handle<JS::Value> aVal, IDBKeyRange** aKeyRange) { MOZ_ASSERT_IF(!aCx, aVal.isUndefined()); RefPtr<IDBKeyRange> keyRange; if (aVal.isNullOrUndefined()) { // undefined and null returns no IDBKeyRange. keyRange.forget(aKeyRange); return NS_OK; } JS::Rooted<JSObject*> obj(aCx, aVal.isObject() ? &aVal.toObject() : nullptr); bool isValidKey = aVal.isPrimitive(); if (!isValidKey) { js::ESClass cls; if (!js::GetBuiltinClass(aCx, obj, &cls)) { return NS_ERROR_UNEXPECTED; } isValidKey = cls == js::ESClass::Array || cls == js::ESClass::Date; } if (isValidKey) { // A valid key returns an 'only' IDBKeyRange. keyRange = new IDBKeyRange(nullptr, false, false, true); nsresult rv = GetKeyFromJSVal(aCx, aVal, keyRange->Lower()); if (NS_FAILED(rv)) { return rv; } } else { MOZ_ASSERT(aVal.isObject()); // An object is not permitted unless it's another IDBKeyRange. if (NS_FAILED(UNWRAP_OBJECT(IDBKeyRange, obj, keyRange))) { return NS_ERROR_DOM_INDEXEDDB_DATA_ERR; } } keyRange.forget(aKeyRange); return NS_OK; }
already_AddRefed<XPathResult> XPathExpression::EvaluateWithContext(JSContext* aCx, nsINode& aContextNode, uint32_t aContextPosition, uint32_t aContextSize, uint16_t aType, JS::Handle<JSObject*> aInResult, ErrorResult& aRv) { RefPtr<XPathResult> inResult; if (aInResult) { nsresult rv = UNWRAP_OBJECT(XPathResult, aInResult, inResult); if (NS_FAILED(rv) && rv != NS_ERROR_XPC_BAD_CONVERT_JS) { aRv.Throw(rv); return nullptr; } } return EvaluateWithContext(aContextNode, aContextPosition, aContextSize, aType, inResult, aRv); }
void GetEntryHelper::ContinueRunning(JSObject* aObj) { MOZ_ASSERT(!mParts.IsEmpty()); RefPtr<Directory> directory; if (NS_FAILED(UNWRAP_OBJECT(Directory, aObj, directory))) { Error(NS_ERROR_DOM_TYPE_MISMATCH_ERR); return; } RefPtr<FileSystemDirectoryEntry> entry = new FileSystemDirectoryEntry(mParentEntry->GetParentObject(), directory, mParentEntry, mFileSystem); // Update the internal values. mParentEntry = entry; mDirectory = directory; Run(); }
static bool GetDataStoresStructuredCloneCallbacksWrite(JSContext* aCx, JSStructuredCloneWriter* aWriter, JS::Handle<JSObject*> aObj, void* aClosure) { AssertIsOnMainThread(); PromiseWorkerProxy* proxy = static_cast<PromiseWorkerProxy*>(aClosure); NS_ASSERTION(proxy, "must have proxy!"); if (!JS_WriteUint32Pair(aWriter, WORKER_DATA_STORES_TAG, 0)) { MOZ_ASSERT(false, "cannot write pair for WORKER_DATA_STORES_TAG!"); return false; } JS::Rooted<JSObject*> storeObj(aCx, aObj); DataStore* store = nullptr; nsresult rv = UNWRAP_OBJECT(DataStore, storeObj, store); if (NS_FAILED(rv)) { MOZ_ASSERT(false, "cannot unwrap the DataStore object!"); return false; } // We keep the data store alive here. proxy->StoreISupports(store); // Construct the nsMainThreadPtrHolder pointing to the data store. nsMainThreadPtrHolder<DataStore>* dataStoreholder = new nsMainThreadPtrHolder<DataStore>(store); // And write the dataStoreholder into the buffer. if (!JS_WriteBytes(aWriter, &dataStoreholder, sizeof(dataStoreholder))) { MOZ_ASSERT(false, "cannot write bytes for dataStoreholder!"); return false; } return true; }
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); }
void WrapperPromiseCallback::Call(JSContext* aCx, JS::Handle<JS::Value> 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; } 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(aCx); mCallback->Call(value, &retValue, rv, CallbackObject::eRethrowExceptions); rv.WouldReportJSException(); if (rv.Failed() && rv.IsJSException()) { JS::Rooted<JS::Value> value(aCx); rv.StealJSException(aCx, &value); if (!JS_WrapValue(aCx, &value)) { NS_WARNING("Failed to wrap value into the right compartment."); return; } mNextPromise->RejectInternal(aCx, value, Promise::SyncTask); return; } // If the return value is the same as the promise itself, throw TypeError. if (retValue.isObject()) { JS::Rooted<JSObject*> valueObj(aCx, &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(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*> stack(aCx, JS_GetEmptyString(JS_GetRuntime(aCx))); JS::Rooted<JSString*> fn(aCx, JS_NewStringCopyZ(aCx, fileName)); if (!fn) { // Out of memory. Promise will stay unresolved. JS_ClearPendingException(aCx); return; } 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; } JS::Rooted<JS::Value> typeError(aCx); if (!JS::CreateTypeError(aCx, stack, fn, lineNumber, 0, nullptr, message, &typeError)) { // Out of memory. Promise will stay unresolved. JS_ClearPendingException(aCx); return; } mNextPromise->RejectInternal(aCx, typeError, Promise::SyncTask); return; } } // Otherwise, run resolver's resolve with value and the synchronous flag // set. if (!JS_WrapValue(aCx, &retValue)) { NS_WARNING("Failed to wrap value into the right compartment."); return; } mNextPromise->ResolveInternal(aCx, retValue, Promise::SyncTask); }