// static JSObject* DOMProxyHandler::GetAndClearExpandoObject(JSObject* obj) { MOZ_ASSERT(IsDOMProxy(obj), "expected a DOM proxy object"); JS::Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO); if (v.isUndefined()) { return nullptr; } if (v.isObject()) { js::SetProxyExtra(obj, JSPROXYSLOT_EXPANDO, UndefinedValue()); xpc::GetObjectScope(obj)->RemoveDOMExpandoObject(obj); } else { js::ExpandoAndGeneration* expandoAndGeneration = static_cast<js::ExpandoAndGeneration*>(v.toPrivate()); v = expandoAndGeneration->expando; if (v.isUndefined()) { return nullptr; } expandoAndGeneration->expando = UndefinedValue(); } return &v.toObject(); }
js::DOMProxyShadowsResult DOMProxyShadows(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id) { JS::Rooted<JSObject*> expando(cx, DOMProxyHandler::GetExpandoObject(proxy)); JS::Value v = js::GetProxyExtra(proxy, JSPROXYSLOT_EXPANDO); bool isOverrideBuiltins = !v.isObject() && !v.isUndefined(); if (expando) { bool hasOwn; if (!JS_AlreadyHasOwnPropertyById(cx, expando, id, &hasOwn)) return js::ShadowCheckFailed; if (hasOwn) { return isOverrideBuiltins ? js::ShadowsViaIndirectExpando : js::ShadowsViaDirectExpando; } } if (!isOverrideBuiltins) { // Our expando, if any, didn't shadow, so we're not shadowing at all. return js::DoesntShadow; } bool hasOwn; if (!GetProxyHandler(proxy)->hasOwn(cx, proxy, id, &hasOwn)) return js::ShadowCheckFailed; return hasOwn ? js::Shadows : js::DoesntShadowUnique; }
static inline void CheckExpandoAndGeneration( JSObject* proxy, js::ExpandoAndGeneration* expandoAndGeneration) { #ifdef DEBUG JS::Value value = expandoAndGeneration->expando; if (!value.isUndefined()) CheckExpandoObject(proxy, value); #endif }
void ModuleScript::SetParseError(const JS::Value& aError) { MOZ_ASSERT(!aError.isUndefined()); MOZ_ASSERT(!HasParseError()); MOZ_ASSERT(!HasErrorToRethrow()); UnlinkModuleRecord(); mParseError = aError; HoldJSObjects(this); }
//static JSObject * DOMProxyHandler::GetExpandoObject(JSObject *obj) { MOZ_ASSERT(IsDOMProxy(obj), "expected a DOM proxy object"); JS::Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO); if (v.isObject()) { return &v.toObject(); } if (v.isUndefined()) { return nullptr; } js::ExpandoAndGeneration* expandoAndGeneration = static_cast<js::ExpandoAndGeneration*>(v.toPrivate()); v = expandoAndGeneration->expando; return v.isUndefined() ? nullptr : &v.toObject(); }
void ModuleScript::SetErrorToRethrow(const JS::Value& aError) { MOZ_ASSERT(!aError.isUndefined()); // This is only called after SetModuleRecord() or SetParseError() so we don't // need to call HoldJSObjects() here. MOZ_ASSERT(ModuleRecord() || HasParseError()); mErrorToRethrow = aError; }
// static JSObject* DOMProxyHandler::GetExpandoObject(JSObject* obj) { CheckDOMProxy(obj); JS::Value v = js::GetProxyPrivate(obj); if (v.isObject()) { CheckExpandoObject(obj, v); return &v.toObject(); } if (v.isUndefined()) { return nullptr; } js::ExpandoAndGeneration* expandoAndGeneration = static_cast<js::ExpandoAndGeneration*>(v.toPrivate()); CheckExpandoAndGeneration(obj, expandoAndGeneration); v = expandoAndGeneration->expando; return v.isUndefined() ? nullptr : &v.toObject(); }
bool CoerceDouble(const JS::Value& v, double* d) { if (v.isDouble()) { *d = v.toDouble(); } else if (v.isInt32()) { *d = double(v.toInt32()); } else if (v.isUndefined()) { *d = 0.0; } else { return false; } return true; }
/** * Extract the FinalizationEvent from an instance of FinalizationWitness * and clear the slot containing the FinalizationEvent. */ already_AddRefed<FinalizationEvent> ExtractFinalizationEvent(JSObject *objSelf) { JS::Value slotEvent = JS_GetReservedSlot(objSelf, WITNESS_SLOT_EVENT); if (slotEvent.isUndefined()) { // Forget() has been called return nullptr; } JS_SetReservedSlot(objSelf, WITNESS_SLOT_EVENT, JS::UndefinedValue()); return dont_AddRef(static_cast<FinalizationEvent*>(slotEvent.toPrivate())); }
// static JSObject* DOMProxyHandler::GetAndClearExpandoObject(JSObject* obj) { MOZ_ASSERT(IsDOMProxy(obj), "expected a DOM proxy object"); JS::Value v = js::GetProxyPrivate(obj); if (v.isUndefined()) { return nullptr; } if (v.isObject()) { js::SetProxyPrivate(obj, UndefinedValue()); } else { js::ExpandoAndGeneration* expandoAndGeneration = static_cast<js::ExpandoAndGeneration*>(v.toPrivate()); v = expandoAndGeneration->expando; if (v.isUndefined()) { return nullptr; } // We have to expose v to active JS here. The reason for that is that we // might be in the middle of a GC right now. If our proxy hasn't been // traced yet, when it _does_ get traced it won't trace the expando, since // we're breaking that link. But the Rooted we're presumably being placed // into is also not going to trace us, because Rooted marking is done at // the very beginning of the GC. In that situation, we need to manually // mark the expando as live here. JS::ExposeValueToActiveJS will do just // that for us. // // We don't need to do this in the non-expandoAndGeneration case, because // in that case our value is stored in a slot and slots will already mark // the old thing live when the value in the slot changes. JS::ExposeValueToActiveJS(v); expandoAndGeneration->expando = UndefinedValue(); } return &v.toObject(); }
// static JSObject* DOMProxyHandler::GetAndClearExpandoObject(JSObject* obj) { CheckDOMProxy(obj); JS::Value v = js::GetProxyPrivate(obj); if (v.isUndefined()) { return nullptr; } if (v.isObject()) { js::SetProxyPrivate(obj, UndefinedValue()); } else { js::ExpandoAndGeneration* expandoAndGeneration = static_cast<js::ExpandoAndGeneration*>(v.toPrivate()); v = expandoAndGeneration->expando; if (v.isUndefined()) { return nullptr; } expandoAndGeneration->expando = UndefinedValue(); } CheckExpandoObject(obj, v); return &v.toObject(); }
bool GetSendMmsMessageRequestFromParams(uint32_t aServiceId, const JS::Value& aParam, SendMmsMessageRequest& request) { if (aParam.isUndefined() || aParam.isNull() || !aParam.isObject()) { return false; } mozilla::AutoJSContext cx; JS::Rooted<JS::Value> param(cx, aParam); RootedDictionary<MmsParameters> params(cx); if (!params.Init(cx, param)) { return false; } // SendMobileMessageRequest.receivers if (!params.mReceivers.WasPassed()) { return false; } request.receivers().AppendElements(params.mReceivers.Value()); // SendMobileMessageRequest.attachments mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton(); if (!params.mAttachments.WasPassed()) { return false; } for (uint32_t i = 0; i < params.mAttachments.Value().Length(); i++) { mozilla::dom::MmsAttachment& attachment = params.mAttachments.Value()[i]; MmsAttachmentData mmsAttachment; mmsAttachment.id().Assign(attachment.mId); mmsAttachment.location().Assign(attachment.mLocation); mmsAttachment.contentChild() = cc->GetOrCreateActorForBlob(attachment.mContent); if (!mmsAttachment.contentChild()) { return false; } request.attachments().AppendElement(mmsAttachment); } request.smil() = params.mSmil; request.subject() = params.mSubject; // Set service ID. request.serviceId() = aServiceId; return true; }
void ShadowingDOMProxyHandler::trace(JSTracer* trc, JSObject* proxy) const { DOMProxyHandler::trace(trc, proxy); MOZ_ASSERT(IsDOMProxy(proxy), "expected a DOM proxy object"); JS::Value v = js::GetProxyPrivate(proxy); MOZ_ASSERT(!v.isObject(), "Should not have expando object directly!"); // The proxy's private slot is set when we allocate the proxy, // so it cannot be |undefined|. MOZ_ASSERT(!v.isUndefined()); js::ExpandoAndGeneration* expandoAndGeneration = static_cast<js::ExpandoAndGeneration*>(v.toPrivate()); JS::TraceEdge(trc, &expandoAndGeneration->expando, "Shadowing DOM proxy expando"); }
// static JSObject* DOMProxyHandler::EnsureExpandoObject(JSContext* cx, JS::Handle<JSObject*> obj) { NS_ASSERTION(IsDOMProxy(obj), "expected a DOM proxy object"); JS::Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO); if (v.isObject()) { return &v.toObject(); } js::ExpandoAndGeneration* expandoAndGeneration; if (!v.isUndefined()) { expandoAndGeneration = static_cast<js::ExpandoAndGeneration*>(v.toPrivate()); if (expandoAndGeneration->expando.isObject()) { return &expandoAndGeneration->expando.toObject(); } } else { expandoAndGeneration = nullptr; } JS::Rooted<JSObject*> expando(cx, JS_NewObjectWithGivenProto(cx, nullptr, nullptr, js::GetObjectParent(obj))); if (!expando) { return nullptr; } nsISupports* native = UnwrapDOMObject<nsISupports>(obj); nsWrapperCache* cache; CallQueryInterface(native, &cache); if (expandoAndGeneration) { cache->PreserveWrapper(native); expandoAndGeneration->expando.setObject(*expando); return expando; } XPCWrappedNativeScope* scope = xpc::GetObjectScope(obj); if (!scope->RegisterDOMExpandoObject(obj)) { return nullptr; } cache->SetPreservingWrapper(true); js::SetProxyExtra(obj, JSPROXYSLOT_EXPANDO, ObjectValue(*expando)); return expando; }
/** * Get a field of an object as an object. * * If the field does not exist, create it. If it exists but is not an * object, throw a JS error. */ JSObject *GetOrCreateObjectProperty(JSContext *cx, JSObject *aObject, const char *aProperty) { JS::Value val; if (!JS_GetProperty(cx, aObject, aProperty, &val)) { return NULL; } if (!val.isUndefined()) { if (val.isObject()) { return &val.toObject(); } JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNEXPECTED_TYPE, aProperty, "not an object"); return NULL; } return JS_DefineObject(cx, aObject, aProperty, NULL, NULL, JSPROP_ENUMERATE); }
std::string gjs_debug_value(JS::Value v) { std::ostringstream out; if (v.isNull()) return "null"; if (v.isUndefined()) return "undefined"; if (v.isInt32()) { out << v.toInt32(); return out.str(); } if (v.isDouble()) { out << v.toDouble(); return out.str(); } if (v.isString()) { out << gjs_debug_string(v.toString()); return out.str(); } if (v.isSymbol()) { out << gjs_debug_symbol(v.toSymbol()); return out.str(); } if (v.isObject() && js::IsFunctionObject(&v.toObject())) { JSFunction* fun = JS_GetObjectFunction(&v.toObject()); JSString *display_name = JS_GetFunctionDisplayId(fun); if (display_name) out << "<function " << gjs_debug_string(display_name); else out << "<unnamed function"; out << " at " << fun << '>'; return out.str(); } if (v.isObject()) { out << gjs_debug_object(&v.toObject()); return out.str(); } if (v.isBoolean()) return (v.toBoolean() ? "true" : "false"); if (v.isMagic()) return "<magic>"; return "unexpected value"; }
// static JSObject* DOMProxyHandler::EnsureExpandoObject(JSContext* cx, JS::Handle<JSObject*> obj) { CheckDOMProxy(obj); JS::Value v = js::GetProxyPrivate(obj); if (v.isObject()) { CheckExpandoObject(obj, v); return &v.toObject(); } js::ExpandoAndGeneration* expandoAndGeneration; if (!v.isUndefined()) { expandoAndGeneration = static_cast<js::ExpandoAndGeneration*>(v.toPrivate()); CheckExpandoAndGeneration(obj, expandoAndGeneration); if (expandoAndGeneration->expando.isObject()) { return &expandoAndGeneration->expando.toObject(); } } else { expandoAndGeneration = nullptr; } JS::Rooted<JSObject*> expando( cx, JS_NewObjectWithGivenProto(cx, nullptr, nullptr)); if (!expando) { return nullptr; } nsISupports* native = UnwrapDOMObject<nsISupports>(obj); nsWrapperCache* cache; CallQueryInterface(native, &cache); cache->PreserveWrapper(native); if (expandoAndGeneration) { expandoAndGeneration->expando.setObject(*expando); return expando; } js::SetProxyPrivate(obj, ObjectValue(*expando)); return expando; }
js::DOMProxyShadowsResult DOMProxyShadows(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id) { JS::Value v = js::GetProxyExtra(proxy, JSPROXYSLOT_EXPANDO); if (v.isObject()) { bool hasOwn; if (!JS_AlreadyHasOwnPropertyById(cx, &v.toObject(), id, &hasOwn)) return js::ShadowCheckFailed; return hasOwn ? js::Shadows : js::DoesntShadow; } if (v.isUndefined()) { return js::DoesntShadow; } bool hasOwn; if (!GetProxyHandler(proxy)->hasOwn(cx, proxy, id, &hasOwn)) return js::ShadowCheckFailed; return hasOwn ? js::Shadows : js::DoesntShadowUnique; }
NS_IMETHODIMP TCPSocketParent::SendCallback(const nsAString& aType, const JS::Value& aDataVal, const nsAString& aReadyState, uint32_t aBuffered, JSContext* aCx) { if (!mIPCOpen) { NS_WARNING("Dropping callback due to no IPC connection"); return NS_OK; } CallbackData data; if (aDataVal.isString()) { JSString* jsstr = aDataVal.toString(); nsDependentJSString str; if (!str.init(aCx, jsstr)) { FireInteralError(this, __LINE__); return NS_ERROR_OUT_OF_MEMORY; } data = str; } else if (aDataVal.isUndefined() || aDataVal.isNull()) { data = mozilla::void_t(); } else if (aDataVal.isObject()) { JSObject* obj = &aDataVal.toObject(); if (JS_IsTypedArrayObject(obj)) { NS_ENSURE_TRUE(JS_IsUint8Array(obj), NS_ERROR_FAILURE); uint32_t nbytes = JS_GetTypedArrayByteLength(obj); uint8_t* buffer = JS_GetUint8ArrayData(obj); if (!buffer) { FireInteralError(this, __LINE__); return NS_ERROR_OUT_OF_MEMORY; } FallibleTArray<uint8_t> fallibleArr; if (!fallibleArr.InsertElementsAt(0, buffer, nbytes)) { FireInteralError(this, __LINE__); return NS_ERROR_OUT_OF_MEMORY; } InfallibleTArray<uint8_t> arr; arr.SwapElements(fallibleArr); data = SendableData(arr); } else { nsDependentJSString message, filename; uint32_t lineNumber = 0; uint32_t columnNumber = 0; jsval val; if (!JS_GetProperty(aCx, obj, "message", &val)) { NS_ERROR("No message property on supposed error object"); } else if (JSVAL_IS_STRING(val)) { if (!message.init(aCx, JSVAL_TO_STRING(val))) { NS_WARNING("couldn't initialize string"); } } if (!JS_GetProperty(aCx, obj, "fileName", &val)) { NS_ERROR("No fileName property on supposed error object"); } else if (JSVAL_IS_STRING(val)) { if (!filename.init(aCx, JSVAL_TO_STRING(val))) { NS_WARNING("couldn't initialize string"); } } if (!JS_GetProperty(aCx, obj, "lineNumber", &val)) { NS_ERROR("No lineNumber property on supposed error object"); } else if (JSVAL_IS_INT(val)) { lineNumber = JSVAL_TO_INT(val); } if (!JS_GetProperty(aCx, obj, "columnNumber", &val)) { NS_ERROR("No columnNumber property on supposed error object"); } else if (JSVAL_IS_INT(val)) { columnNumber = JSVAL_TO_INT(val); } data = JSError(message, filename, lineNumber, columnNumber); } } else { NS_ERROR("Unexpected JS value encountered"); FireInteralError(this, __LINE__); return NS_ERROR_FAILURE; } mozilla::unused << PTCPSocketParent::SendCallback(nsString(aType), data, nsString(aReadyState), aBuffered); return NS_OK; }
NS_IMETHODIMP TCPSocketParent::SendCallback(const nsAString& aType, const JS::Value& aDataVal, const nsAString& aReadyState, uint32_t aBuffered, JSContext* aCx) { if (!mIPCOpen) { NS_WARNING("Dropping callback due to no IPC connection"); return NS_OK; } CallbackData data; if (aDataVal.isString()) { JSString* jsstr = aDataVal.toString(); nsDependentJSString str; if (!str.init(aCx, jsstr)) { FireInteralError(this, __LINE__); return NS_ERROR_OUT_OF_MEMORY; } data = SendableData(str); } else if (aDataVal.isUndefined() || aDataVal.isNull()) { data = mozilla::void_t(); } else if (aDataVal.isObject()) { JSObject* obj = &aDataVal.toObject(); if (JS_IsArrayBufferObject(obj)) { uint32_t nbytes = JS_GetArrayBufferByteLength(obj); uint8_t* buffer = JS_GetArrayBufferData(obj); if (!buffer) { FireInteralError(this, __LINE__); return NS_ERROR_OUT_OF_MEMORY; } FallibleTArray<uint8_t> fallibleArr; if (!fallibleArr.InsertElementsAt(0, buffer, nbytes)) { FireInteralError(this, __LINE__); return NS_ERROR_OUT_OF_MEMORY; } InfallibleTArray<uint8_t> arr; arr.SwapElements(fallibleArr); data = SendableData(arr); } else { nsDependentJSString name; JS::Rooted<JS::Value> val(aCx); if (!JS_GetProperty(aCx, obj, "name", val.address())) { NS_ERROR("No name property on supposed error object"); } else if (JSVAL_IS_STRING(val)) { if (!name.init(aCx, JSVAL_TO_STRING(val))) { NS_WARNING("couldn't initialize string"); } } data = TCPError(name); } } else { NS_ERROR("Unexpected JS value encountered"); FireInteralError(this, __LINE__); return NS_ERROR_FAILURE; } mozilla::unused << PTCPSocketParent::SendCallback(nsString(aType), data, nsString(aReadyState), aBuffered); return NS_OK; }