1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/bindings/BindingUtils.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2392 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ 1.5 +/* vim: set ts=2 sw=2 et tw=79: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.8 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "BindingUtils.h" 1.11 + 1.12 +#include <algorithm> 1.13 +#include <stdarg.h> 1.14 + 1.15 +#include "JavaScriptParent.h" 1.16 + 1.17 +#include "mozilla/DebugOnly.h" 1.18 +#include "mozilla/FloatingPoint.h" 1.19 +#include "mozilla/Assertions.h" 1.20 + 1.21 +#include "AccessCheck.h" 1.22 +#include "jsfriendapi.h" 1.23 +#include "js/OldDebugAPI.h" 1.24 +#include "nsContentUtils.h" 1.25 +#include "nsIDOMGlobalPropertyInitializer.h" 1.26 +#include "nsIPrincipal.h" 1.27 +#include "nsIXPConnect.h" 1.28 +#include "WrapperFactory.h" 1.29 +#include "xpcprivate.h" 1.30 +#include "XPCQuickStubs.h" 1.31 +#include "XrayWrapper.h" 1.32 +#include "nsPrintfCString.h" 1.33 +#include "prprf.h" 1.34 + 1.35 +#include "mozilla/dom/ScriptSettings.h" 1.36 +#include "mozilla/dom/DOMError.h" 1.37 +#include "mozilla/dom/DOMErrorBinding.h" 1.38 +#include "mozilla/dom/HTMLObjectElement.h" 1.39 +#include "mozilla/dom/HTMLObjectElementBinding.h" 1.40 +#include "mozilla/dom/HTMLSharedObjectElement.h" 1.41 +#include "mozilla/dom/HTMLEmbedElementBinding.h" 1.42 +#include "mozilla/dom/HTMLAppletElementBinding.h" 1.43 +#include "mozilla/dom/Promise.h" 1.44 +#include "WorkerPrivate.h" 1.45 + 1.46 +namespace mozilla { 1.47 +namespace dom { 1.48 + 1.49 +JSErrorFormatString ErrorFormatString[] = { 1.50 +#define MSG_DEF(_name, _argc, _str) \ 1.51 + { _str, _argc, JSEXN_TYPEERR }, 1.52 +#include "mozilla/dom/Errors.msg" 1.53 +#undef MSG_DEF 1.54 +}; 1.55 + 1.56 +const JSErrorFormatString* 1.57 +GetErrorMessage(void* aUserRef, const char* aLocale, 1.58 + const unsigned aErrorNumber) 1.59 +{ 1.60 + MOZ_ASSERT(aErrorNumber < ArrayLength(ErrorFormatString)); 1.61 + return &ErrorFormatString[aErrorNumber]; 1.62 +} 1.63 + 1.64 +bool 1.65 +ThrowErrorMessage(JSContext* aCx, const ErrNum aErrorNumber, ...) 1.66 +{ 1.67 + va_list ap; 1.68 + va_start(ap, aErrorNumber); 1.69 + JS_ReportErrorNumberVA(aCx, GetErrorMessage, nullptr, 1.70 + static_cast<const unsigned>(aErrorNumber), ap); 1.71 + va_end(ap); 1.72 + return false; 1.73 +} 1.74 + 1.75 +bool 1.76 +ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs, 1.77 + const ErrNum aErrorNumber, 1.78 + const char* aInterfaceName) 1.79 +{ 1.80 + NS_ConvertASCIItoUTF16 ifaceName(aInterfaceName); 1.81 + // This should only be called for DOM methods/getters/setters, which 1.82 + // are JSNative-backed functions, so we can assume that 1.83 + // JS_ValueToFunction and JS_GetFunctionDisplayId will both return 1.84 + // non-null and that JS_GetStringCharsZ returns non-null. 1.85 + JS::Rooted<JSFunction*> func(aCx, JS_ValueToFunction(aCx, aArgs.calleev())); 1.86 + MOZ_ASSERT(func); 1.87 + JS::Rooted<JSString*> funcName(aCx, JS_GetFunctionDisplayId(func)); 1.88 + MOZ_ASSERT(funcName); 1.89 + JS_ReportErrorNumberUC(aCx, GetErrorMessage, nullptr, 1.90 + static_cast<const unsigned>(aErrorNumber), 1.91 + JS_GetStringCharsZ(aCx, funcName), 1.92 + ifaceName.get()); 1.93 + return false; 1.94 +} 1.95 + 1.96 +bool 1.97 +ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs, 1.98 + const ErrNum aErrorNumber, 1.99 + prototypes::ID aProtoId) 1.100 +{ 1.101 + return ThrowInvalidThis(aCx, aArgs, aErrorNumber, 1.102 + NamesOfInterfacesWithProtos(aProtoId)); 1.103 +} 1.104 + 1.105 +bool 1.106 +ThrowNoSetterArg(JSContext* aCx, prototypes::ID aProtoId) 1.107 +{ 1.108 + nsPrintfCString errorMessage("%s attribute setter", 1.109 + NamesOfInterfacesWithProtos(aProtoId)); 1.110 + return ThrowErrorMessage(aCx, MSG_MISSING_ARGUMENTS, errorMessage.get()); 1.111 +} 1.112 + 1.113 +} // namespace dom 1.114 + 1.115 +struct ErrorResult::Message { 1.116 + nsTArray<nsString> mArgs; 1.117 + dom::ErrNum mErrorNumber; 1.118 +}; 1.119 + 1.120 +void 1.121 +ErrorResult::ThrowTypeError(const dom::ErrNum errorNumber, ...) 1.122 +{ 1.123 + va_list ap; 1.124 + va_start(ap, errorNumber); 1.125 + if (IsJSException()) { 1.126 + // We have rooted our mJSException, and we don't have the info 1.127 + // needed to unroot here, so just bail. 1.128 + va_end(ap); 1.129 + MOZ_ASSERT(false, 1.130 + "Ignoring ThrowTypeError call because we have a JS exception"); 1.131 + return; 1.132 + } 1.133 + if (IsTypeError()) { 1.134 + delete mMessage; 1.135 + } 1.136 + mResult = NS_ERROR_TYPE_ERR; 1.137 + Message* message = new Message(); 1.138 + message->mErrorNumber = errorNumber; 1.139 + uint16_t argCount = 1.140 + dom::GetErrorMessage(nullptr, nullptr, errorNumber)->argCount; 1.141 + MOZ_ASSERT(argCount <= 10); 1.142 + argCount = std::min<uint16_t>(argCount, 10); 1.143 + while (argCount--) { 1.144 + message->mArgs.AppendElement(*va_arg(ap, nsString*)); 1.145 + } 1.146 + mMessage = message; 1.147 + va_end(ap); 1.148 +} 1.149 + 1.150 +void 1.151 +ErrorResult::ReportTypeError(JSContext* aCx) 1.152 +{ 1.153 + MOZ_ASSERT(mMessage, "ReportTypeError() can be called only once"); 1.154 + 1.155 + Message* message = mMessage; 1.156 + const uint32_t argCount = message->mArgs.Length(); 1.157 + const jschar* args[11]; 1.158 + for (uint32_t i = 0; i < argCount; ++i) { 1.159 + args[i] = message->mArgs.ElementAt(i).get(); 1.160 + } 1.161 + args[argCount] = nullptr; 1.162 + 1.163 + JS_ReportErrorNumberUCArray(aCx, dom::GetErrorMessage, nullptr, 1.164 + static_cast<const unsigned>(message->mErrorNumber), 1.165 + argCount > 0 ? args : nullptr); 1.166 + 1.167 + ClearMessage(); 1.168 +} 1.169 + 1.170 +void 1.171 +ErrorResult::ClearMessage() 1.172 +{ 1.173 + if (IsTypeError()) { 1.174 + delete mMessage; 1.175 + mMessage = nullptr; 1.176 + } 1.177 +} 1.178 + 1.179 +void 1.180 +ErrorResult::ThrowJSException(JSContext* cx, JS::Handle<JS::Value> exn) 1.181 +{ 1.182 + MOZ_ASSERT(mMightHaveUnreportedJSException, 1.183 + "Why didn't you tell us you planned to throw a JS exception?"); 1.184 + 1.185 + if (IsTypeError()) { 1.186 + delete mMessage; 1.187 + } 1.188 + 1.189 + // Make sure mJSException is initialized _before_ we try to root it. But 1.190 + // don't set it to exn yet, because we don't want to do that until after we 1.191 + // root. 1.192 + mJSException = JS::UndefinedValue(); 1.193 + if (!js::AddRawValueRoot(cx, &mJSException, "ErrorResult::mJSException")) { 1.194 + // Don't use NS_ERROR_DOM_JS_EXCEPTION, because that indicates we have 1.195 + // in fact rooted mJSException. 1.196 + mResult = NS_ERROR_OUT_OF_MEMORY; 1.197 + } else { 1.198 + mJSException = exn; 1.199 + mResult = NS_ERROR_DOM_JS_EXCEPTION; 1.200 + } 1.201 +} 1.202 + 1.203 +void 1.204 +ErrorResult::ReportJSException(JSContext* cx) 1.205 +{ 1.206 + MOZ_ASSERT(!mMightHaveUnreportedJSException, 1.207 + "Why didn't you tell us you planned to handle JS exceptions?"); 1.208 + 1.209 + JS::Rooted<JS::Value> exception(cx, mJSException); 1.210 + if (JS_WrapValue(cx, &exception)) { 1.211 + JS_SetPendingException(cx, exception); 1.212 + } 1.213 + mJSException = exception; 1.214 + // If JS_WrapValue failed, not much we can do about it... No matter 1.215 + // what, go ahead and unroot mJSException. 1.216 + js::RemoveRawValueRoot(cx, &mJSException); 1.217 +} 1.218 + 1.219 +void 1.220 +ErrorResult::ReportJSExceptionFromJSImplementation(JSContext* aCx) 1.221 +{ 1.222 + MOZ_ASSERT(!mMightHaveUnreportedJSException, 1.223 + "Why didn't you tell us you planned to handle JS exceptions?"); 1.224 + 1.225 + dom::DOMError* domError; 1.226 + nsresult rv = UNWRAP_OBJECT(DOMError, &mJSException.toObject(), domError); 1.227 + if (NS_FAILED(rv)) { 1.228 + // Unwrapping really shouldn't fail here, if mExceptionHandling is set to 1.229 + // eRethrowContentExceptions then the CallSetup destructor only stores an 1.230 + // exception if it unwraps to DOMError. If we reach this then either 1.231 + // mExceptionHandling wasn't set to eRethrowContentExceptions and we 1.232 + // shouldn't be calling ReportJSExceptionFromJSImplementation or something 1.233 + // went really wrong. 1.234 + NS_RUNTIMEABORT("We stored a non-DOMError exception!"); 1.235 + } 1.236 + 1.237 + nsString message; 1.238 + domError->GetMessage(message); 1.239 + 1.240 + JS_ReportError(aCx, "%hs", message.get()); 1.241 + js::RemoveRawValueRoot(aCx, &mJSException); 1.242 + 1.243 + // We no longer have a useful exception but we do want to signal that an error 1.244 + // occured. 1.245 + mResult = NS_ERROR_FAILURE; 1.246 +} 1.247 + 1.248 +void 1.249 +ErrorResult::StealJSException(JSContext* cx, 1.250 + JS::MutableHandle<JS::Value> value) 1.251 +{ 1.252 + MOZ_ASSERT(!mMightHaveUnreportedJSException, 1.253 + "Must call WouldReportJSException unconditionally in all codepaths that might call StealJSException"); 1.254 + MOZ_ASSERT(IsJSException(), "No exception to steal"); 1.255 + 1.256 + value.set(mJSException); 1.257 + js::RemoveRawValueRoot(cx, &mJSException); 1.258 + mResult = NS_OK; 1.259 +} 1.260 + 1.261 +void 1.262 +ErrorResult::ReportNotEnoughArgsError(JSContext* cx, 1.263 + const char* ifaceName, 1.264 + const char* memberName) 1.265 +{ 1.266 + MOZ_ASSERT(ErrorCode() == NS_ERROR_XPC_NOT_ENOUGH_ARGS); 1.267 + 1.268 + nsPrintfCString errorMessage("%s.%s", ifaceName, memberName); 1.269 + ThrowErrorMessage(cx, dom::MSG_MISSING_ARGUMENTS, errorMessage.get()); 1.270 +} 1.271 + 1.272 +namespace dom { 1.273 + 1.274 +bool 1.275 +DefineConstants(JSContext* cx, JS::Handle<JSObject*> obj, 1.276 + const ConstantSpec* cs) 1.277 +{ 1.278 + JS::Rooted<JS::Value> value(cx); 1.279 + for (; cs->name; ++cs) { 1.280 + value = cs->value; 1.281 + bool ok = 1.282 + JS_DefineProperty(cx, obj, cs->name, value, 1.283 + JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); 1.284 + if (!ok) { 1.285 + return false; 1.286 + } 1.287 + } 1.288 + return true; 1.289 +} 1.290 + 1.291 +static inline bool 1.292 +Define(JSContext* cx, JS::Handle<JSObject*> obj, const JSFunctionSpec* spec) { 1.293 + return JS_DefineFunctions(cx, obj, spec); 1.294 +} 1.295 +static inline bool 1.296 +Define(JSContext* cx, JS::Handle<JSObject*> obj, const JSPropertySpec* spec) { 1.297 + return JS_DefineProperties(cx, obj, spec); 1.298 +} 1.299 +static inline bool 1.300 +Define(JSContext* cx, JS::Handle<JSObject*> obj, const ConstantSpec* spec) { 1.301 + return DefineConstants(cx, obj, spec); 1.302 +} 1.303 + 1.304 +template<typename T> 1.305 +bool 1.306 +DefinePrefable(JSContext* cx, JS::Handle<JSObject*> obj, 1.307 + const Prefable<T>* props) 1.308 +{ 1.309 + MOZ_ASSERT(props); 1.310 + MOZ_ASSERT(props->specs); 1.311 + do { 1.312 + // Define if enabled 1.313 + if (props->isEnabled(cx, obj)) { 1.314 + if (!Define(cx, obj, props->specs)) { 1.315 + return false; 1.316 + } 1.317 + } 1.318 + } while ((++props)->specs); 1.319 + return true; 1.320 +} 1.321 + 1.322 +bool 1.323 +DefineUnforgeableAttributes(JSContext* cx, JS::Handle<JSObject*> obj, 1.324 + const Prefable<const JSPropertySpec>* props) 1.325 +{ 1.326 + return DefinePrefable(cx, obj, props); 1.327 +} 1.328 + 1.329 + 1.330 +// We should use JSFunction objects for interface objects, but we need a custom 1.331 +// hasInstance hook because we have new interface objects on prototype chains of 1.332 +// old (XPConnect-based) bindings. Because Function.prototype.toString throws if 1.333 +// passed a non-Function object we also need to provide our own toString method 1.334 +// for interface objects. 1.335 + 1.336 +enum { 1.337 + TOSTRING_CLASS_RESERVED_SLOT = 0, 1.338 + TOSTRING_NAME_RESERVED_SLOT = 1 1.339 +}; 1.340 + 1.341 +static bool 1.342 +InterfaceObjectToString(JSContext* cx, unsigned argc, JS::Value *vp) 1.343 +{ 1.344 + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); 1.345 + JS::Rooted<JSObject*> callee(cx, &args.callee()); 1.346 + 1.347 + if (!args.thisv().isObject()) { 1.348 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, 1.349 + JSMSG_CANT_CONVERT_TO, "null", "object"); 1.350 + return false; 1.351 + } 1.352 + 1.353 + JS::Value v = js::GetFunctionNativeReserved(callee, 1.354 + TOSTRING_CLASS_RESERVED_SLOT); 1.355 + const JSClass* clasp = static_cast<const JSClass*>(v.toPrivate()); 1.356 + 1.357 + v = js::GetFunctionNativeReserved(callee, TOSTRING_NAME_RESERVED_SLOT); 1.358 + JSString* jsname = static_cast<JSString*>(JSVAL_TO_STRING(v)); 1.359 + size_t length; 1.360 + const jschar* name = JS_GetInternedStringCharsAndLength(jsname, &length); 1.361 + 1.362 + if (js::GetObjectJSClass(&args.thisv().toObject()) != clasp) { 1.363 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, 1.364 + JSMSG_INCOMPATIBLE_PROTO, 1.365 + NS_ConvertUTF16toUTF8(name).get(), "toString", 1.366 + "object"); 1.367 + return false; 1.368 + } 1.369 + 1.370 + nsString str; 1.371 + str.AppendLiteral("function "); 1.372 + str.Append(name, length); 1.373 + str.AppendLiteral("() {"); 1.374 + str.Append('\n'); 1.375 + str.AppendLiteral(" [native code]"); 1.376 + str.Append('\n'); 1.377 + str.AppendLiteral("}"); 1.378 + 1.379 + return xpc::NonVoidStringToJsval(cx, str, args.rval()); 1.380 +} 1.381 + 1.382 +bool 1.383 +Constructor(JSContext* cx, unsigned argc, JS::Value* vp) 1.384 +{ 1.385 + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); 1.386 + const JS::Value& v = 1.387 + js::GetFunctionNativeReserved(&args.callee(), 1.388 + CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT); 1.389 + const JSNativeHolder* nativeHolder = 1.390 + static_cast<const JSNativeHolder*>(v.toPrivate()); 1.391 + return (nativeHolder->mNative)(cx, argc, vp); 1.392 +} 1.393 + 1.394 +static JSObject* 1.395 +CreateConstructor(JSContext* cx, JS::Handle<JSObject*> global, const char* name, 1.396 + const JSNativeHolder* nativeHolder, unsigned ctorNargs) 1.397 +{ 1.398 + JSFunction* fun = js::NewFunctionWithReserved(cx, Constructor, ctorNargs, 1.399 + JSFUN_CONSTRUCTOR, global, 1.400 + name); 1.401 + if (!fun) { 1.402 + return nullptr; 1.403 + } 1.404 + 1.405 + JSObject* constructor = JS_GetFunctionObject(fun); 1.406 + js::SetFunctionNativeReserved(constructor, 1.407 + CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT, 1.408 + js::PrivateValue(const_cast<JSNativeHolder*>(nativeHolder))); 1.409 + return constructor; 1.410 +} 1.411 + 1.412 +static bool 1.413 +DefineConstructor(JSContext* cx, JS::Handle<JSObject*> global, const char* name, 1.414 + JS::Handle<JSObject*> constructor) 1.415 +{ 1.416 + bool alreadyDefined; 1.417 + if (!JS_AlreadyHasOwnProperty(cx, global, name, &alreadyDefined)) { 1.418 + return false; 1.419 + } 1.420 + 1.421 + // This is Enumerable: False per spec. 1.422 + return alreadyDefined || 1.423 + JS_DefineProperty(cx, global, name, constructor, 0); 1.424 +} 1.425 + 1.426 +static JSObject* 1.427 +CreateInterfaceObject(JSContext* cx, JS::Handle<JSObject*> global, 1.428 + JS::Handle<JSObject*> constructorProto, 1.429 + const JSClass* constructorClass, 1.430 + const JSNativeHolder* constructorNative, 1.431 + unsigned ctorNargs, const NamedConstructor* namedConstructors, 1.432 + JS::Handle<JSObject*> proto, 1.433 + const NativeProperties* properties, 1.434 + const NativeProperties* chromeOnlyProperties, 1.435 + const char* name, bool defineOnGlobal) 1.436 +{ 1.437 + JS::Rooted<JSObject*> constructor(cx); 1.438 + if (constructorClass) { 1.439 + MOZ_ASSERT(constructorProto); 1.440 + constructor = JS_NewObject(cx, constructorClass, constructorProto, global); 1.441 + } else { 1.442 + MOZ_ASSERT(constructorNative); 1.443 + MOZ_ASSERT(constructorProto == JS_GetFunctionPrototype(cx, global)); 1.444 + constructor = CreateConstructor(cx, global, name, constructorNative, 1.445 + ctorNargs); 1.446 + } 1.447 + if (!constructor) { 1.448 + return nullptr; 1.449 + } 1.450 + 1.451 + if (constructorClass) { 1.452 + // Have to shadow Function.prototype.toString, since that throws 1.453 + // on things that are not js::FunctionClass. 1.454 + JS::Rooted<JSFunction*> toString(cx, 1.455 + js::DefineFunctionWithReserved(cx, constructor, 1.456 + "toString", 1.457 + InterfaceObjectToString, 1.458 + 0, 0)); 1.459 + if (!toString) { 1.460 + return nullptr; 1.461 + } 1.462 + 1.463 + JSString *str = ::JS_InternString(cx, name); 1.464 + if (!str) { 1.465 + return nullptr; 1.466 + } 1.467 + JSObject* toStringObj = JS_GetFunctionObject(toString); 1.468 + js::SetFunctionNativeReserved(toStringObj, TOSTRING_CLASS_RESERVED_SLOT, 1.469 + PRIVATE_TO_JSVAL(const_cast<JSClass *>(constructorClass))); 1.470 + 1.471 + js::SetFunctionNativeReserved(toStringObj, TOSTRING_NAME_RESERVED_SLOT, 1.472 + STRING_TO_JSVAL(str)); 1.473 + 1.474 + if (!JS_DefineProperty(cx, constructor, "length", ctorNargs, 1.475 + JSPROP_READONLY | JSPROP_PERMANENT)) { 1.476 + return nullptr; 1.477 + } 1.478 + } 1.479 + 1.480 + if (properties) { 1.481 + if (properties->staticMethods && 1.482 + !DefinePrefable(cx, constructor, properties->staticMethods)) { 1.483 + return nullptr; 1.484 + } 1.485 + 1.486 + if (properties->staticAttributes && 1.487 + !DefinePrefable(cx, constructor, properties->staticAttributes)) { 1.488 + return nullptr; 1.489 + } 1.490 + 1.491 + if (properties->constants && 1.492 + !DefinePrefable(cx, constructor, properties->constants)) { 1.493 + return nullptr; 1.494 + } 1.495 + } 1.496 + 1.497 + if (chromeOnlyProperties) { 1.498 + if (chromeOnlyProperties->staticMethods && 1.499 + !DefinePrefable(cx, constructor, chromeOnlyProperties->staticMethods)) { 1.500 + return nullptr; 1.501 + } 1.502 + 1.503 + if (chromeOnlyProperties->staticAttributes && 1.504 + !DefinePrefable(cx, constructor, 1.505 + chromeOnlyProperties->staticAttributes)) { 1.506 + return nullptr; 1.507 + } 1.508 + 1.509 + if (chromeOnlyProperties->constants && 1.510 + !DefinePrefable(cx, constructor, chromeOnlyProperties->constants)) { 1.511 + return nullptr; 1.512 + } 1.513 + } 1.514 + 1.515 + if (proto && !JS_LinkConstructorAndPrototype(cx, constructor, proto)) { 1.516 + return nullptr; 1.517 + } 1.518 + 1.519 + if (defineOnGlobal && !DefineConstructor(cx, global, name, constructor)) { 1.520 + return nullptr; 1.521 + } 1.522 + 1.523 + if (namedConstructors) { 1.524 + int namedConstructorSlot = DOM_INTERFACE_SLOTS_BASE; 1.525 + while (namedConstructors->mName) { 1.526 + JS::Rooted<JSObject*> namedConstructor(cx, 1.527 + CreateConstructor(cx, global, namedConstructors->mName, 1.528 + &namedConstructors->mHolder, 1.529 + namedConstructors->mNargs)); 1.530 + if (!namedConstructor || 1.531 + !JS_DefineProperty(cx, namedConstructor, "prototype", 1.532 + proto, JSPROP_PERMANENT | JSPROP_READONLY, 1.533 + JS_PropertyStub, JS_StrictPropertyStub) || 1.534 + (defineOnGlobal && 1.535 + !DefineConstructor(cx, global, namedConstructors->mName, 1.536 + namedConstructor))) { 1.537 + return nullptr; 1.538 + } 1.539 + js::SetReservedSlot(constructor, namedConstructorSlot++, 1.540 + JS::ObjectValue(*namedConstructor)); 1.541 + ++namedConstructors; 1.542 + } 1.543 + } 1.544 + 1.545 + return constructor; 1.546 +} 1.547 + 1.548 +bool 1.549 +DefineWebIDLBindingPropertiesOnXPCObject(JSContext* cx, 1.550 + JS::Handle<JSObject*> obj, 1.551 + const NativeProperties* properties, 1.552 + bool defineUnforgeableAttributes) 1.553 +{ 1.554 + if (properties->methods && 1.555 + !DefinePrefable(cx, obj, properties->methods)) { 1.556 + return false; 1.557 + } 1.558 + 1.559 + if (properties->attributes && 1.560 + !DefinePrefable(cx, obj, properties->attributes)) { 1.561 + return false; 1.562 + } 1.563 + 1.564 + if (defineUnforgeableAttributes && properties->unforgeableAttributes && 1.565 + !DefinePrefable(cx, obj, properties->unforgeableAttributes)) { 1.566 + return false; 1.567 + } 1.568 + 1.569 + return true; 1.570 +} 1.571 + 1.572 +static JSObject* 1.573 +CreateInterfacePrototypeObject(JSContext* cx, JS::Handle<JSObject*> global, 1.574 + JS::Handle<JSObject*> parentProto, 1.575 + const JSClass* protoClass, 1.576 + const NativeProperties* properties, 1.577 + const NativeProperties* chromeOnlyProperties) 1.578 +{ 1.579 + JS::Rooted<JSObject*> ourProto(cx, 1.580 + JS_NewObjectWithUniqueType(cx, protoClass, parentProto, global)); 1.581 + if (!ourProto) { 1.582 + return nullptr; 1.583 + } 1.584 + 1.585 + if (properties) { 1.586 + if (properties->methods && 1.587 + !DefinePrefable(cx, ourProto, properties->methods)) { 1.588 + return nullptr; 1.589 + } 1.590 + 1.591 + if (properties->attributes && 1.592 + !DefinePrefable(cx, ourProto, properties->attributes)) { 1.593 + return nullptr; 1.594 + } 1.595 + 1.596 + if (properties->constants && 1.597 + !DefinePrefable(cx, ourProto, properties->constants)) { 1.598 + return nullptr; 1.599 + } 1.600 + } 1.601 + 1.602 + if (chromeOnlyProperties) { 1.603 + if (chromeOnlyProperties->methods && 1.604 + !DefinePrefable(cx, ourProto, chromeOnlyProperties->methods)) { 1.605 + return nullptr; 1.606 + } 1.607 + 1.608 + if (chromeOnlyProperties->attributes && 1.609 + !DefinePrefable(cx, ourProto, chromeOnlyProperties->attributes)) { 1.610 + return nullptr; 1.611 + } 1.612 + 1.613 + if (chromeOnlyProperties->constants && 1.614 + !DefinePrefable(cx, ourProto, chromeOnlyProperties->constants)) { 1.615 + return nullptr; 1.616 + } 1.617 + } 1.618 + 1.619 + return ourProto; 1.620 +} 1.621 + 1.622 +void 1.623 +CreateInterfaceObjects(JSContext* cx, JS::Handle<JSObject*> global, 1.624 + JS::Handle<JSObject*> protoProto, 1.625 + const JSClass* protoClass, JS::Heap<JSObject*>* protoCache, 1.626 + JS::Handle<JSObject*> constructorProto, 1.627 + const JSClass* constructorClass, const JSNativeHolder* constructor, 1.628 + unsigned ctorNargs, const NamedConstructor* namedConstructors, 1.629 + JS::Heap<JSObject*>* constructorCache, const DOMClass* domClass, 1.630 + const NativeProperties* properties, 1.631 + const NativeProperties* chromeOnlyProperties, 1.632 + const char* name, bool defineOnGlobal) 1.633 +{ 1.634 + MOZ_ASSERT(protoClass || constructorClass || constructor, 1.635 + "Need at least one class or a constructor!"); 1.636 + MOZ_ASSERT(!((properties && 1.637 + (properties->methods || properties->attributes)) || 1.638 + (chromeOnlyProperties && 1.639 + (chromeOnlyProperties->methods || 1.640 + chromeOnlyProperties->attributes))) || protoClass, 1.641 + "Methods or properties but no protoClass!"); 1.642 + MOZ_ASSERT(!((properties && 1.643 + (properties->staticMethods || properties->staticAttributes)) || 1.644 + (chromeOnlyProperties && 1.645 + (chromeOnlyProperties->staticMethods || 1.646 + chromeOnlyProperties->staticAttributes))) || 1.647 + constructorClass || constructor, 1.648 + "Static methods but no constructorClass or constructor!"); 1.649 + MOZ_ASSERT(bool(name) == bool(constructorClass || constructor), 1.650 + "Must have name precisely when we have an interface object"); 1.651 + MOZ_ASSERT(!constructorClass || !constructor); 1.652 + MOZ_ASSERT(!protoClass == !protoCache, 1.653 + "If, and only if, there is an interface prototype object we need " 1.654 + "to cache it"); 1.655 + MOZ_ASSERT(!(constructorClass || constructor) == !constructorCache, 1.656 + "If, and only if, there is an interface object we need to cache " 1.657 + "it"); 1.658 + 1.659 + JS::Rooted<JSObject*> proto(cx); 1.660 + if (protoClass) { 1.661 + proto = 1.662 + CreateInterfacePrototypeObject(cx, global, protoProto, protoClass, 1.663 + properties, chromeOnlyProperties); 1.664 + if (!proto) { 1.665 + return; 1.666 + } 1.667 + 1.668 + js::SetReservedSlot(proto, DOM_PROTO_INSTANCE_CLASS_SLOT, 1.669 + JS::PrivateValue(const_cast<DOMClass*>(domClass))); 1.670 + 1.671 + *protoCache = proto; 1.672 + } 1.673 + else { 1.674 + MOZ_ASSERT(!proto); 1.675 + } 1.676 + 1.677 + JSObject* interface; 1.678 + if (constructorClass || constructor) { 1.679 + interface = CreateInterfaceObject(cx, global, constructorProto, 1.680 + constructorClass, constructor, 1.681 + ctorNargs, namedConstructors, proto, 1.682 + properties, chromeOnlyProperties, name, 1.683 + defineOnGlobal); 1.684 + if (!interface) { 1.685 + if (protoCache) { 1.686 + // If we fail we need to make sure to clear the value of protoCache we 1.687 + // set above. 1.688 + *protoCache = nullptr; 1.689 + } 1.690 + return; 1.691 + } 1.692 + *constructorCache = interface; 1.693 + } 1.694 +} 1.695 + 1.696 +bool 1.697 +NativeInterface2JSObjectAndThrowIfFailed(JSContext* aCx, 1.698 + JS::Handle<JSObject*> aScope, 1.699 + JS::MutableHandle<JS::Value> aRetval, 1.700 + xpcObjectHelper& aHelper, 1.701 + const nsIID* aIID, 1.702 + bool aAllowNativeWrapper) 1.703 +{ 1.704 + js::AssertSameCompartment(aCx, aScope); 1.705 + nsresult rv; 1.706 + // Inline some logic from XPCConvert::NativeInterfaceToJSObject that we need 1.707 + // on all threads. 1.708 + nsWrapperCache *cache = aHelper.GetWrapperCache(); 1.709 + 1.710 + if (cache && cache->IsDOMBinding()) { 1.711 + JS::Rooted<JSObject*> obj(aCx, cache->GetWrapper()); 1.712 + if (!obj) { 1.713 + obj = cache->WrapObject(aCx); 1.714 + } 1.715 + 1.716 + if (obj && aAllowNativeWrapper && !JS_WrapObject(aCx, &obj)) { 1.717 + return false; 1.718 + } 1.719 + 1.720 + if (obj) { 1.721 + aRetval.setObject(*obj); 1.722 + return true; 1.723 + } 1.724 + } 1.725 + 1.726 + MOZ_ASSERT(NS_IsMainThread()); 1.727 + 1.728 + if (!XPCConvert::NativeInterface2JSObject(aRetval, nullptr, aHelper, aIID, 1.729 + nullptr, aAllowNativeWrapper, &rv)) { 1.730 + // I can't tell if NativeInterface2JSObject throws JS exceptions 1.731 + // or not. This is a sloppy stab at the right semantics; the 1.732 + // method really ought to be fixed to behave consistently. 1.733 + if (!JS_IsExceptionPending(aCx)) { 1.734 + Throw(aCx, NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED); 1.735 + } 1.736 + return false; 1.737 + } 1.738 + return true; 1.739 +} 1.740 + 1.741 +bool 1.742 +TryPreserveWrapper(JSObject* obj) 1.743 +{ 1.744 + MOZ_ASSERT(IsDOMObject(obj)); 1.745 + 1.746 + if (nsISupports* native = UnwrapDOMObjectToISupports(obj)) { 1.747 + nsWrapperCache* cache = nullptr; 1.748 + CallQueryInterface(native, &cache); 1.749 + if (cache) { 1.750 + cache->PreserveWrapper(native); 1.751 + } 1.752 + return true; 1.753 + } 1.754 + 1.755 + // If this DOMClass is not cycle collected, then it isn't wrappercached, 1.756 + // so it does not need to be preserved. If it is cycle collected, then 1.757 + // we can't tell if it is wrappercached or not, so we just return false. 1.758 + const DOMClass* domClass = GetDOMClass(obj); 1.759 + return domClass && !domClass->mParticipant; 1.760 +} 1.761 + 1.762 +// Can only be called with the immediate prototype of the instance object. Can 1.763 +// only be called on the prototype of an object known to be a DOM instance. 1.764 +bool 1.765 +InstanceClassHasProtoAtDepth(JSObject* protoObject, uint32_t protoID, 1.766 + uint32_t depth) 1.767 +{ 1.768 + const DOMClass* domClass = static_cast<const DOMClass*>( 1.769 + js::GetReservedSlot(protoObject, DOM_PROTO_INSTANCE_CLASS_SLOT).toPrivate()); 1.770 + return (uint32_t)domClass->mInterfaceChain[depth] == protoID; 1.771 +} 1.772 + 1.773 +// Only set allowNativeWrapper to false if you really know you need it, if in 1.774 +// doubt use true. Setting it to false disables security wrappers. 1.775 +bool 1.776 +XPCOMObjectToJsval(JSContext* cx, JS::Handle<JSObject*> scope, 1.777 + xpcObjectHelper& helper, const nsIID* iid, 1.778 + bool allowNativeWrapper, JS::MutableHandle<JS::Value> rval) 1.779 +{ 1.780 + if (!NativeInterface2JSObjectAndThrowIfFailed(cx, scope, rval, helper, iid, 1.781 + allowNativeWrapper)) { 1.782 + return false; 1.783 + } 1.784 + 1.785 +#ifdef DEBUG 1.786 + JSObject* jsobj = rval.toObjectOrNull(); 1.787 + if (jsobj && !js::GetObjectParent(jsobj)) 1.788 + NS_ASSERTION(js::GetObjectClass(jsobj)->flags & JSCLASS_IS_GLOBAL, 1.789 + "Why did we recreate this wrapper?"); 1.790 +#endif 1.791 + 1.792 + return true; 1.793 +} 1.794 + 1.795 +bool 1.796 +VariantToJsval(JSContext* aCx, nsIVariant* aVariant, 1.797 + JS::MutableHandle<JS::Value> aRetval) 1.798 +{ 1.799 + nsresult rv; 1.800 + if (!XPCVariant::VariantDataToJS(aVariant, &rv, aRetval)) { 1.801 + // Does it throw? Who knows 1.802 + if (!JS_IsExceptionPending(aCx)) { 1.803 + Throw(aCx, NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED); 1.804 + } 1.805 + return false; 1.806 + } 1.807 + 1.808 + return true; 1.809 +} 1.810 + 1.811 +bool 1.812 +QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp) 1.813 +{ 1.814 + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); 1.815 + JS::Rooted<JS::Value> thisv(cx, JS_THIS(cx, vp)); 1.816 + if (thisv.isNull()) 1.817 + return false; 1.818 + 1.819 + // Get the object. It might be a security wrapper, in which case we do a checked 1.820 + // unwrap. 1.821 + JS::Rooted<JSObject*> origObj(cx, &thisv.toObject()); 1.822 + JSObject* obj = js::CheckedUnwrap(origObj, /* stopAtOuter = */ false); 1.823 + if (!obj) { 1.824 + JS_ReportError(cx, "Permission denied to access object"); 1.825 + return false; 1.826 + } 1.827 + 1.828 + // Switch this to UnwrapDOMObjectToISupports once our global objects are 1.829 + // using new bindings. 1.830 + JS::Rooted<JS::Value> val(cx, JS::ObjectValue(*obj)); 1.831 + nsISupports* native = nullptr; 1.832 + nsCOMPtr<nsISupports> nativeRef; 1.833 + xpc_qsUnwrapArg<nsISupports>(cx, val, &native, 1.834 + static_cast<nsISupports**>(getter_AddRefs(nativeRef)), 1.835 + &val); 1.836 + if (!native) { 1.837 + return Throw(cx, NS_ERROR_FAILURE); 1.838 + } 1.839 + 1.840 + if (argc < 1) { 1.841 + return Throw(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS); 1.842 + } 1.843 + 1.844 + if (!args[0].isObject()) { 1.845 + return Throw(cx, NS_ERROR_XPC_BAD_CONVERT_JS); 1.846 + } 1.847 + 1.848 + nsIJSID* iid; 1.849 + SelfRef iidRef; 1.850 + if (NS_FAILED(xpc_qsUnwrapArg<nsIJSID>(cx, args[0], &iid, &iidRef.ptr, 1.851 + args[0]))) { 1.852 + return Throw(cx, NS_ERROR_XPC_BAD_CONVERT_JS); 1.853 + } 1.854 + MOZ_ASSERT(iid); 1.855 + 1.856 + if (iid->GetID()->Equals(NS_GET_IID(nsIClassInfo))) { 1.857 + nsresult rv; 1.858 + nsCOMPtr<nsIClassInfo> ci = do_QueryInterface(native, &rv); 1.859 + if (NS_FAILED(rv)) { 1.860 + return Throw(cx, rv); 1.861 + } 1.862 + 1.863 + return WrapObject(cx, ci, &NS_GET_IID(nsIClassInfo), args.rval()); 1.864 + } 1.865 + 1.866 + nsCOMPtr<nsISupports> unused; 1.867 + nsresult rv = native->QueryInterface(*iid->GetID(), getter_AddRefs(unused)); 1.868 + if (NS_FAILED(rv)) { 1.869 + return Throw(cx, rv); 1.870 + } 1.871 + 1.872 + *vp = thisv; 1.873 + return true; 1.874 +} 1.875 + 1.876 +void 1.877 +GetInterfaceImpl(JSContext* aCx, nsIInterfaceRequestor* aRequestor, 1.878 + nsWrapperCache* aCache, nsIJSID* aIID, 1.879 + JS::MutableHandle<JS::Value> aRetval, ErrorResult& aError) 1.880 +{ 1.881 + const nsID* iid = aIID->GetID(); 1.882 + 1.883 + nsRefPtr<nsISupports> result; 1.884 + aError = aRequestor->GetInterface(*iid, getter_AddRefs(result)); 1.885 + if (aError.Failed()) { 1.886 + return; 1.887 + } 1.888 + 1.889 + if (!WrapObject(aCx, result, iid, aRetval)) { 1.890 + aError.Throw(NS_ERROR_FAILURE); 1.891 + } 1.892 +} 1.893 + 1.894 +bool 1.895 +ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp) 1.896 +{ 1.897 + return ThrowErrorMessage(cx, MSG_ILLEGAL_CONSTRUCTOR); 1.898 +} 1.899 + 1.900 +bool 1.901 +ThrowConstructorWithoutNew(JSContext* cx, const char* name) 1.902 +{ 1.903 + return ThrowErrorMessage(cx, MSG_CONSTRUCTOR_WITHOUT_NEW, name); 1.904 +} 1.905 + 1.906 +inline const NativePropertyHooks* 1.907 +GetNativePropertyHooks(JSContext *cx, JS::Handle<JSObject*> obj, 1.908 + DOMObjectType& type) 1.909 +{ 1.910 + const DOMClass* domClass = GetDOMClass(obj); 1.911 + if (domClass) { 1.912 + type = eInstance; 1.913 + return domClass->mNativeHooks; 1.914 + } 1.915 + 1.916 + if (JS_ObjectIsFunction(cx, obj)) { 1.917 + MOZ_ASSERT(JS_IsNativeFunction(obj, Constructor)); 1.918 + type = eInterface; 1.919 + const JS::Value& v = 1.920 + js::GetFunctionNativeReserved(obj, 1.921 + CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT); 1.922 + const JSNativeHolder* nativeHolder = 1.923 + static_cast<const JSNativeHolder*>(v.toPrivate()); 1.924 + return nativeHolder->mPropertyHooks; 1.925 + } 1.926 + 1.927 + MOZ_ASSERT(IsDOMIfaceAndProtoClass(js::GetObjectClass(obj))); 1.928 + const DOMIfaceAndProtoJSClass* ifaceAndProtoJSClass = 1.929 + DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj)); 1.930 + type = ifaceAndProtoJSClass->mType; 1.931 + return ifaceAndProtoJSClass->mNativeHooks; 1.932 +} 1.933 + 1.934 +// Try to resolve a property as an unforgeable property from the given 1.935 +// NativeProperties, if it's there. nativeProperties is allowed to be null (in 1.936 +// which case we of course won't resolve anything). 1.937 +static bool 1.938 +XrayResolveUnforgeableProperty(JSContext* cx, JS::Handle<JSObject*> wrapper, 1.939 + JS::Handle<JSObject*> obj, JS::Handle<jsid> id, 1.940 + JS::MutableHandle<JSPropertyDescriptor> desc, 1.941 + const NativeProperties* nativeProperties); 1.942 + 1.943 +static bool 1.944 +XrayResolveNativeProperty(JSContext* cx, JS::Handle<JSObject*> wrapper, 1.945 + const NativePropertyHooks* nativePropertyHooks, 1.946 + DOMObjectType type, JS::Handle<JSObject*> obj, 1.947 + JS::Handle<jsid> id, 1.948 + JS::MutableHandle<JSPropertyDescriptor> desc); 1.949 + 1.950 +bool 1.951 +XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper, 1.952 + JS::Handle<JSObject*> obj, JS::Handle<jsid> id, 1.953 + JS::MutableHandle<JSPropertyDescriptor> desc) 1.954 +{ 1.955 + DOMObjectType type; 1.956 + const NativePropertyHooks *nativePropertyHooks = 1.957 + GetNativePropertyHooks(cx, obj, type); 1.958 + 1.959 + if (type != eInstance) { 1.960 + // For prototype objects and interface objects, just return their 1.961 + // normal set of properties. 1.962 + return XrayResolveNativeProperty(cx, wrapper, nativePropertyHooks, type, 1.963 + obj, id, desc); 1.964 + } 1.965 + 1.966 + // Check for unforgeable properties before doing mResolveOwnProperty weirdness 1.967 + const NativePropertiesHolder& nativeProperties = 1.968 + nativePropertyHooks->mNativeProperties; 1.969 + if (!XrayResolveUnforgeableProperty(cx, wrapper, obj, id, desc, 1.970 + nativeProperties.regular)) { 1.971 + return false; 1.972 + } 1.973 + if (desc.object()) { 1.974 + return true; 1.975 + } 1.976 + if (!XrayResolveUnforgeableProperty(cx, wrapper, obj, id, desc, 1.977 + nativeProperties.chromeOnly)) { 1.978 + return false; 1.979 + } 1.980 + if (desc.object()) { 1.981 + return true; 1.982 + } 1.983 + 1.984 + return !nativePropertyHooks->mResolveOwnProperty || 1.985 + nativePropertyHooks->mResolveOwnProperty(cx, wrapper, obj, id, desc); 1.986 +} 1.987 + 1.988 +static bool 1.989 +XrayResolveAttribute(JSContext* cx, JS::Handle<JSObject*> wrapper, 1.990 + JS::Handle<JSObject*> obj, JS::Handle<jsid> id, 1.991 + const Prefable<const JSPropertySpec>* attributes, jsid* attributeIds, 1.992 + const JSPropertySpec* attributeSpecs, JS::MutableHandle<JSPropertyDescriptor> desc) 1.993 +{ 1.994 + for (; attributes->specs; ++attributes) { 1.995 + if (attributes->isEnabled(cx, obj)) { 1.996 + // Set i to be the index into our full list of ids/specs that we're 1.997 + // looking at now. 1.998 + size_t i = attributes->specs - attributeSpecs; 1.999 + for ( ; attributeIds[i] != JSID_VOID; ++i) { 1.1000 + if (id == attributeIds[i]) { 1.1001 + const JSPropertySpec& attrSpec = attributeSpecs[i]; 1.1002 + // Because of centralization, we need to make sure we fault in the 1.1003 + // JitInfos as well. At present, until the JSAPI changes, the easiest 1.1004 + // way to do this is wrap them up as functions ourselves. 1.1005 + desc.setAttributes(attrSpec.flags & ~JSPROP_NATIVE_ACCESSORS); 1.1006 + // They all have getters, so we can just make it. 1.1007 + JS::Rooted<JSFunction*> fun(cx, 1.1008 + JS_NewFunctionById(cx, (JSNative)attrSpec.getter.propertyOp.op, 1.1009 + 0, 0, wrapper, id)); 1.1010 + if (!fun) 1.1011 + return false; 1.1012 + SET_JITINFO(fun, attrSpec.getter.propertyOp.info); 1.1013 + JSObject *funobj = JS_GetFunctionObject(fun); 1.1014 + desc.setGetterObject(funobj); 1.1015 + desc.attributesRef() |= JSPROP_GETTER; 1.1016 + if (attrSpec.setter.propertyOp.op) { 1.1017 + // We have a setter! Make it. 1.1018 + fun = JS_NewFunctionById(cx, (JSNative)attrSpec.setter.propertyOp.op, 1, 0, 1.1019 + wrapper, id); 1.1020 + if (!fun) 1.1021 + return false; 1.1022 + SET_JITINFO(fun, attrSpec.setter.propertyOp.info); 1.1023 + funobj = JS_GetFunctionObject(fun); 1.1024 + desc.setSetterObject(funobj); 1.1025 + desc.attributesRef() |= JSPROP_SETTER; 1.1026 + } else { 1.1027 + desc.setSetter(nullptr); 1.1028 + } 1.1029 + desc.object().set(wrapper); 1.1030 + return true; 1.1031 + } 1.1032 + } 1.1033 + } 1.1034 + } 1.1035 + return true; 1.1036 +} 1.1037 + 1.1038 +/* static */ bool 1.1039 +XrayResolveUnforgeableProperty(JSContext* cx, JS::Handle<JSObject*> wrapper, 1.1040 + JS::Handle<JSObject*> obj, JS::Handle<jsid> id, 1.1041 + JS::MutableHandle<JSPropertyDescriptor> desc, 1.1042 + const NativeProperties* nativeProperties) 1.1043 +{ 1.1044 + return !nativeProperties || !nativeProperties->unforgeableAttributes || 1.1045 + XrayResolveAttribute(cx, wrapper, obj, id, 1.1046 + nativeProperties->unforgeableAttributes, 1.1047 + nativeProperties->unforgeableAttributeIds, 1.1048 + nativeProperties->unforgeableAttributeSpecs, 1.1049 + desc); 1.1050 +} 1.1051 + 1.1052 +static bool 1.1053 +XrayResolveProperty(JSContext* cx, JS::Handle<JSObject*> wrapper, 1.1054 + JS::Handle<JSObject*> obj, JS::Handle<jsid> id, 1.1055 + JS::MutableHandle<JSPropertyDescriptor> desc, DOMObjectType type, 1.1056 + const NativeProperties* nativeProperties) 1.1057 +{ 1.1058 + const Prefable<const JSFunctionSpec>* methods; 1.1059 + jsid* methodIds; 1.1060 + const JSFunctionSpec* methodsSpecs; 1.1061 + if (type == eInterface) { 1.1062 + methods = nativeProperties->staticMethods; 1.1063 + methodIds = nativeProperties->staticMethodIds; 1.1064 + methodsSpecs = nativeProperties->staticMethodsSpecs; 1.1065 + } else { 1.1066 + methods = nativeProperties->methods; 1.1067 + methodIds = nativeProperties->methodIds; 1.1068 + methodsSpecs = nativeProperties->methodsSpecs; 1.1069 + } 1.1070 + if (methods) { 1.1071 + const Prefable<const JSFunctionSpec>* method; 1.1072 + for (method = methods; method->specs; ++method) { 1.1073 + if (method->isEnabled(cx, obj)) { 1.1074 + // Set i to be the index into our full list of ids/specs that we're 1.1075 + // looking at now. 1.1076 + size_t i = method->specs - methodsSpecs; 1.1077 + for ( ; methodIds[i] != JSID_VOID; ++i) { 1.1078 + if (id == methodIds[i]) { 1.1079 + const JSFunctionSpec& methodSpec = methodsSpecs[i]; 1.1080 + JSFunction *fun; 1.1081 + if (methodSpec.selfHostedName) { 1.1082 + fun = JS::GetSelfHostedFunction(cx, methodSpec.selfHostedName, id, methodSpec.nargs); 1.1083 + if (!fun) { 1.1084 + return false; 1.1085 + } 1.1086 + MOZ_ASSERT(!methodSpec.call.op, "Bad FunctionSpec declaration: non-null native"); 1.1087 + MOZ_ASSERT(!methodSpec.call.info, "Bad FunctionSpec declaration: non-null jitinfo"); 1.1088 + } else { 1.1089 + fun = JS_NewFunctionById(cx, methodSpec.call.op, methodSpec.nargs, 0, wrapper, id); 1.1090 + if (!fun) { 1.1091 + return false; 1.1092 + } 1.1093 + SET_JITINFO(fun, methodSpec.call.info); 1.1094 + } 1.1095 + JSObject *funobj = JS_GetFunctionObject(fun); 1.1096 + desc.value().setObject(*funobj); 1.1097 + desc.setAttributes(methodSpec.flags); 1.1098 + desc.object().set(wrapper); 1.1099 + desc.setSetter(nullptr); 1.1100 + desc.setGetter(nullptr); 1.1101 + return true; 1.1102 + } 1.1103 + } 1.1104 + } 1.1105 + } 1.1106 + } 1.1107 + 1.1108 + if (type == eInterface) { 1.1109 + if (nativeProperties->staticAttributes) { 1.1110 + if (!XrayResolveAttribute(cx, wrapper, obj, id, 1.1111 + nativeProperties->staticAttributes, 1.1112 + nativeProperties->staticAttributeIds, 1.1113 + nativeProperties->staticAttributeSpecs, desc)) { 1.1114 + return false; 1.1115 + } 1.1116 + if (desc.object()) { 1.1117 + return true; 1.1118 + } 1.1119 + } 1.1120 + } else { 1.1121 + if (nativeProperties->attributes) { 1.1122 + if (!XrayResolveAttribute(cx, wrapper, obj, id, 1.1123 + nativeProperties->attributes, 1.1124 + nativeProperties->attributeIds, 1.1125 + nativeProperties->attributeSpecs, desc)) { 1.1126 + return false; 1.1127 + } 1.1128 + if (desc.object()) { 1.1129 + return true; 1.1130 + } 1.1131 + } 1.1132 + } 1.1133 + 1.1134 + if (nativeProperties->constants) { 1.1135 + const Prefable<const ConstantSpec>* constant; 1.1136 + for (constant = nativeProperties->constants; constant->specs; ++constant) { 1.1137 + if (constant->isEnabled(cx, obj)) { 1.1138 + // Set i to be the index into our full list of ids/specs that we're 1.1139 + // looking at now. 1.1140 + size_t i = constant->specs - nativeProperties->constantSpecs; 1.1141 + for ( ; nativeProperties->constantIds[i] != JSID_VOID; ++i) { 1.1142 + if (id == nativeProperties->constantIds[i]) { 1.1143 + desc.setAttributes(JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); 1.1144 + desc.object().set(wrapper); 1.1145 + desc.value().set(nativeProperties->constantSpecs[i].value); 1.1146 + return true; 1.1147 + } 1.1148 + } 1.1149 + } 1.1150 + } 1.1151 + } 1.1152 + 1.1153 + return true; 1.1154 +} 1.1155 + 1.1156 +static bool 1.1157 +ResolvePrototypeOrConstructor(JSContext* cx, JS::Handle<JSObject*> wrapper, 1.1158 + JS::Handle<JSObject*> obj, 1.1159 + size_t protoAndIfaceCacheIndex, unsigned attrs, 1.1160 + JS::MutableHandle<JSPropertyDescriptor> desc) 1.1161 +{ 1.1162 + JS::Rooted<JSObject*> global(cx, js::GetGlobalForObjectCrossCompartment(obj)); 1.1163 + { 1.1164 + JSAutoCompartment ac(cx, global); 1.1165 + ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(global); 1.1166 + JSObject* protoOrIface = 1.1167 + protoAndIfaceCache.EntrySlotIfExists(protoAndIfaceCacheIndex); 1.1168 + if (!protoOrIface) { 1.1169 + return false; 1.1170 + } 1.1171 + desc.object().set(wrapper); 1.1172 + desc.setAttributes(attrs); 1.1173 + desc.setGetter(JS_PropertyStub); 1.1174 + desc.setSetter(JS_StrictPropertyStub); 1.1175 + desc.value().set(JS::ObjectValue(*protoOrIface)); 1.1176 + } 1.1177 + return JS_WrapPropertyDescriptor(cx, desc); 1.1178 +} 1.1179 + 1.1180 +/* static */ bool 1.1181 +XrayResolveNativeProperty(JSContext* cx, JS::Handle<JSObject*> wrapper, 1.1182 + const NativePropertyHooks* nativePropertyHooks, 1.1183 + DOMObjectType type, JS::Handle<JSObject*> obj, 1.1184 + JS::Handle<jsid> id, 1.1185 + JS::MutableHandle<JSPropertyDescriptor> desc) 1.1186 +{ 1.1187 + if (type == eInterface && IdEquals(id, "prototype")) { 1.1188 + return nativePropertyHooks->mPrototypeID == prototypes::id::_ID_Count || 1.1189 + ResolvePrototypeOrConstructor(cx, wrapper, obj, 1.1190 + nativePropertyHooks->mPrototypeID, 1.1191 + JSPROP_PERMANENT | JSPROP_READONLY, 1.1192 + desc); 1.1193 + } 1.1194 + 1.1195 + if (type == eInterfacePrototype && IdEquals(id, "constructor")) { 1.1196 + return nativePropertyHooks->mConstructorID == constructors::id::_ID_Count || 1.1197 + ResolvePrototypeOrConstructor(cx, wrapper, obj, 1.1198 + nativePropertyHooks->mConstructorID, 1.1199 + 0, desc); 1.1200 + } 1.1201 + 1.1202 + const NativePropertiesHolder& nativeProperties = 1.1203 + nativePropertyHooks->mNativeProperties; 1.1204 + 1.1205 + if (nativeProperties.regular && 1.1206 + !XrayResolveProperty(cx, wrapper, obj, id, desc, type, 1.1207 + nativeProperties.regular)) { 1.1208 + return false; 1.1209 + } 1.1210 + 1.1211 + if (!desc.object() && 1.1212 + nativeProperties.chromeOnly && 1.1213 + xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrapper)) && 1.1214 + !XrayResolveProperty(cx, wrapper, obj, id, desc, type, 1.1215 + nativeProperties.chromeOnly)) { 1.1216 + return false; 1.1217 + } 1.1218 + 1.1219 + return true; 1.1220 +} 1.1221 + 1.1222 +bool 1.1223 +XrayResolveNativeProperty(JSContext* cx, JS::Handle<JSObject*> wrapper, 1.1224 + JS::Handle<JSObject*> obj, 1.1225 + JS::Handle<jsid> id, JS::MutableHandle<JSPropertyDescriptor> desc) 1.1226 +{ 1.1227 + DOMObjectType type; 1.1228 + const NativePropertyHooks* nativePropertyHooks = 1.1229 + GetNativePropertyHooks(cx, obj, type); 1.1230 + 1.1231 + if (type == eInstance) { 1.1232 + // Force the type to be eInterfacePrototype, since we need to walk the 1.1233 + // prototype chain. 1.1234 + type = eInterfacePrototype; 1.1235 + } 1.1236 + 1.1237 + if (type == eInterfacePrototype) { 1.1238 + do { 1.1239 + if (!XrayResolveNativeProperty(cx, wrapper, nativePropertyHooks, type, 1.1240 + obj, id, desc)) { 1.1241 + return false; 1.1242 + } 1.1243 + 1.1244 + if (desc.object()) { 1.1245 + return true; 1.1246 + } 1.1247 + } while ((nativePropertyHooks = nativePropertyHooks->mProtoHooks)); 1.1248 + 1.1249 + return true; 1.1250 + } 1.1251 + 1.1252 + return XrayResolveNativeProperty(cx, wrapper, nativePropertyHooks, type, obj, 1.1253 + id, desc); 1.1254 +} 1.1255 + 1.1256 +bool 1.1257 +XrayDefineProperty(JSContext* cx, JS::Handle<JSObject*> wrapper, 1.1258 + JS::Handle<JSObject*> obj, JS::Handle<jsid> id, 1.1259 + JS::MutableHandle<JSPropertyDescriptor> desc, bool* defined) 1.1260 +{ 1.1261 + if (!js::IsProxy(obj)) 1.1262 + return true; 1.1263 + 1.1264 + MOZ_ASSERT(IsDOMProxy(obj), "What kind of proxy is this?"); 1.1265 + 1.1266 + DOMProxyHandler* handler = 1.1267 + static_cast<DOMProxyHandler*>(js::GetProxyHandler(obj)); 1.1268 + return handler->defineProperty(cx, wrapper, id, desc, defined); 1.1269 +} 1.1270 + 1.1271 +bool 1.1272 +XrayEnumerateAttributes(JSContext* cx, JS::Handle<JSObject*> wrapper, 1.1273 + JS::Handle<JSObject*> obj, 1.1274 + const Prefable<const JSPropertySpec>* attributes, 1.1275 + jsid* attributeIds, const JSPropertySpec* attributeSpecs, 1.1276 + unsigned flags, JS::AutoIdVector& props) 1.1277 +{ 1.1278 + for (; attributes->specs; ++attributes) { 1.1279 + if (attributes->isEnabled(cx, obj)) { 1.1280 + // Set i to be the index into our full list of ids/specs that we're 1.1281 + // looking at now. 1.1282 + size_t i = attributes->specs - attributeSpecs; 1.1283 + for ( ; attributeIds[i] != JSID_VOID; ++i) { 1.1284 + if (((flags & JSITER_HIDDEN) || 1.1285 + (attributeSpecs[i].flags & JSPROP_ENUMERATE)) && 1.1286 + !props.append(attributeIds[i])) { 1.1287 + return false; 1.1288 + } 1.1289 + } 1.1290 + } 1.1291 + } 1.1292 + return true; 1.1293 +} 1.1294 + 1.1295 +bool 1.1296 +XrayEnumerateProperties(JSContext* cx, JS::Handle<JSObject*> wrapper, 1.1297 + JS::Handle<JSObject*> obj, 1.1298 + unsigned flags, JS::AutoIdVector& props, 1.1299 + DOMObjectType type, 1.1300 + const NativeProperties* nativeProperties) 1.1301 +{ 1.1302 + const Prefable<const JSFunctionSpec>* methods; 1.1303 + jsid* methodIds; 1.1304 + const JSFunctionSpec* methodsSpecs; 1.1305 + if (type == eInterface) { 1.1306 + methods = nativeProperties->staticMethods; 1.1307 + methodIds = nativeProperties->staticMethodIds; 1.1308 + methodsSpecs = nativeProperties->staticMethodsSpecs; 1.1309 + } else { 1.1310 + methods = nativeProperties->methods; 1.1311 + methodIds = nativeProperties->methodIds; 1.1312 + methodsSpecs = nativeProperties->methodsSpecs; 1.1313 + } 1.1314 + if (methods) { 1.1315 + const Prefable<const JSFunctionSpec>* method; 1.1316 + for (method = methods; method->specs; ++method) { 1.1317 + if (method->isEnabled(cx, obj)) { 1.1318 + // Set i to be the index into our full list of ids/specs that we're 1.1319 + // looking at now. 1.1320 + size_t i = method->specs - methodsSpecs; 1.1321 + for ( ; methodIds[i] != JSID_VOID; ++i) { 1.1322 + if (((flags & JSITER_HIDDEN) || 1.1323 + (methodsSpecs[i].flags & JSPROP_ENUMERATE)) && 1.1324 + !props.append(methodIds[i])) { 1.1325 + return false; 1.1326 + } 1.1327 + } 1.1328 + } 1.1329 + } 1.1330 + } 1.1331 + 1.1332 + if (type == eInterface) { 1.1333 + if (nativeProperties->staticAttributes && 1.1334 + !XrayEnumerateAttributes(cx, wrapper, obj, 1.1335 + nativeProperties->staticAttributes, 1.1336 + nativeProperties->staticAttributeIds, 1.1337 + nativeProperties->staticAttributeSpecs, 1.1338 + flags, props)) { 1.1339 + return false; 1.1340 + } 1.1341 + } else { 1.1342 + if (nativeProperties->attributes && 1.1343 + !XrayEnumerateAttributes(cx, wrapper, obj, 1.1344 + nativeProperties->attributes, 1.1345 + nativeProperties->attributeIds, 1.1346 + nativeProperties->attributeSpecs, 1.1347 + flags, props)) { 1.1348 + return false; 1.1349 + } 1.1350 + if (nativeProperties->unforgeableAttributes && 1.1351 + !XrayEnumerateAttributes(cx, wrapper, obj, 1.1352 + nativeProperties->unforgeableAttributes, 1.1353 + nativeProperties->unforgeableAttributeIds, 1.1354 + nativeProperties->unforgeableAttributeSpecs, 1.1355 + flags, props)) { 1.1356 + return false; 1.1357 + } 1.1358 + } 1.1359 + 1.1360 + if (nativeProperties->constants) { 1.1361 + const Prefable<const ConstantSpec>* constant; 1.1362 + for (constant = nativeProperties->constants; constant->specs; ++constant) { 1.1363 + if (constant->isEnabled(cx, obj)) { 1.1364 + // Set i to be the index into our full list of ids/specs that we're 1.1365 + // looking at now. 1.1366 + size_t i = constant->specs - nativeProperties->constantSpecs; 1.1367 + for ( ; nativeProperties->constantIds[i] != JSID_VOID; ++i) { 1.1368 + if (!props.append(nativeProperties->constantIds[i])) { 1.1369 + return false; 1.1370 + } 1.1371 + } 1.1372 + } 1.1373 + } 1.1374 + } 1.1375 + 1.1376 + return true; 1.1377 +} 1.1378 + 1.1379 +bool 1.1380 +XrayEnumerateNativeProperties(JSContext* cx, JS::Handle<JSObject*> wrapper, 1.1381 + const NativePropertyHooks* nativePropertyHooks, 1.1382 + DOMObjectType type, JS::Handle<JSObject*> obj, 1.1383 + unsigned flags, JS::AutoIdVector& props) 1.1384 +{ 1.1385 + if (type == eInterface && 1.1386 + nativePropertyHooks->mPrototypeID != prototypes::id::_ID_Count && 1.1387 + !AddStringToIDVector(cx, props, "prototype")) { 1.1388 + return false; 1.1389 + } 1.1390 + 1.1391 + if (type == eInterfacePrototype && 1.1392 + nativePropertyHooks->mConstructorID != constructors::id::_ID_Count && 1.1393 + (flags & JSITER_HIDDEN) && 1.1394 + !AddStringToIDVector(cx, props, "constructor")) { 1.1395 + return false; 1.1396 + } 1.1397 + 1.1398 + const NativePropertiesHolder& nativeProperties = 1.1399 + nativePropertyHooks->mNativeProperties; 1.1400 + 1.1401 + if (nativeProperties.regular && 1.1402 + !XrayEnumerateProperties(cx, wrapper, obj, flags, props, type, 1.1403 + nativeProperties.regular)) { 1.1404 + return false; 1.1405 + } 1.1406 + 1.1407 + if (nativeProperties.chromeOnly && 1.1408 + xpc::AccessCheck::isChrome(js::GetObjectCompartment(wrapper)) && 1.1409 + !XrayEnumerateProperties(cx, wrapper, obj, flags, props, type, 1.1410 + nativeProperties.chromeOnly)) { 1.1411 + return false; 1.1412 + } 1.1413 + 1.1414 + return true; 1.1415 +} 1.1416 + 1.1417 +bool 1.1418 +XrayEnumerateProperties(JSContext* cx, JS::Handle<JSObject*> wrapper, 1.1419 + JS::Handle<JSObject*> obj, 1.1420 + unsigned flags, JS::AutoIdVector& props) 1.1421 +{ 1.1422 + DOMObjectType type; 1.1423 + const NativePropertyHooks* nativePropertyHooks = 1.1424 + GetNativePropertyHooks(cx, obj, type); 1.1425 + 1.1426 + if (type == eInstance) { 1.1427 + if (nativePropertyHooks->mEnumerateOwnProperties && 1.1428 + !nativePropertyHooks->mEnumerateOwnProperties(cx, wrapper, obj, 1.1429 + props)) { 1.1430 + return false; 1.1431 + } 1.1432 + 1.1433 + if (flags & JSITER_OWNONLY) { 1.1434 + return true; 1.1435 + } 1.1436 + 1.1437 + // Force the type to be eInterfacePrototype, since we need to walk the 1.1438 + // prototype chain. 1.1439 + type = eInterfacePrototype; 1.1440 + } 1.1441 + 1.1442 + if (type == eInterfacePrototype) { 1.1443 + do { 1.1444 + if (!XrayEnumerateNativeProperties(cx, wrapper, nativePropertyHooks, type, 1.1445 + obj, flags, props)) { 1.1446 + return false; 1.1447 + } 1.1448 + 1.1449 + if (flags & JSITER_OWNONLY) { 1.1450 + return true; 1.1451 + } 1.1452 + } while ((nativePropertyHooks = nativePropertyHooks->mProtoHooks)); 1.1453 + 1.1454 + return true; 1.1455 + } 1.1456 + 1.1457 + return XrayEnumerateNativeProperties(cx, wrapper, nativePropertyHooks, type, 1.1458 + obj, flags, props); 1.1459 +} 1.1460 + 1.1461 +NativePropertyHooks sWorkerNativePropertyHooks = { 1.1462 + nullptr, 1.1463 + nullptr, 1.1464 + { 1.1465 + nullptr, 1.1466 + nullptr 1.1467 + }, 1.1468 + prototypes::id::_ID_Count, 1.1469 + constructors::id::_ID_Count, 1.1470 + nullptr 1.1471 +}; 1.1472 + 1.1473 +bool 1.1474 +GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy, 1.1475 + JS::Handle<jsid> id, bool* found, 1.1476 + JS::Value* vp) 1.1477 +{ 1.1478 + JS::Rooted<JSObject*> proto(cx); 1.1479 + if (!js::GetObjectProto(cx, proxy, &proto)) { 1.1480 + return false; 1.1481 + } 1.1482 + if (!proto) { 1.1483 + *found = false; 1.1484 + return true; 1.1485 + } 1.1486 + 1.1487 + bool hasProp; 1.1488 + if (!JS_HasPropertyById(cx, proto, id, &hasProp)) { 1.1489 + return false; 1.1490 + } 1.1491 + 1.1492 + *found = hasProp; 1.1493 + if (!hasProp || !vp) { 1.1494 + return true; 1.1495 + } 1.1496 + 1.1497 + JS::Rooted<JS::Value> value(cx); 1.1498 + if (!JS_ForwardGetPropertyTo(cx, proto, id, proxy, &value)) { 1.1499 + return false; 1.1500 + } 1.1501 + 1.1502 + *vp = value; 1.1503 + return true; 1.1504 +} 1.1505 + 1.1506 +bool 1.1507 +HasPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy, 1.1508 + JS::Handle<jsid> id) 1.1509 +{ 1.1510 + JS::Rooted<JSObject*> obj(cx, proxy); 1.1511 + Maybe<JSAutoCompartment> ac; 1.1512 + if (xpc::WrapperFactory::IsXrayWrapper(obj)) { 1.1513 + obj = js::UncheckedUnwrap(obj); 1.1514 + ac.construct(cx, obj); 1.1515 + } 1.1516 + 1.1517 + bool found; 1.1518 + // We ignore an error from GetPropertyOnPrototype. We pass nullptr 1.1519 + // for vp so that GetPropertyOnPrototype won't actually do a get. 1.1520 + return !GetPropertyOnPrototype(cx, obj, id, &found, nullptr) || found; 1.1521 +} 1.1522 + 1.1523 +bool 1.1524 +AppendNamedPropertyIds(JSContext* cx, JS::Handle<JSObject*> proxy, 1.1525 + nsTArray<nsString>& names, 1.1526 + bool shadowPrototypeProperties, 1.1527 + JS::AutoIdVector& props) 1.1528 +{ 1.1529 + for (uint32_t i = 0; i < names.Length(); ++i) { 1.1530 + JS::Rooted<JS::Value> v(cx); 1.1531 + if (!xpc::NonVoidStringToJsval(cx, names[i], &v)) { 1.1532 + return false; 1.1533 + } 1.1534 + 1.1535 + JS::Rooted<jsid> id(cx); 1.1536 + if (!JS_ValueToId(cx, v, &id)) { 1.1537 + return false; 1.1538 + } 1.1539 + 1.1540 + if (shadowPrototypeProperties || !HasPropertyOnPrototype(cx, proxy, id)) { 1.1541 + if (!props.append(id)) { 1.1542 + return false; 1.1543 + } 1.1544 + } 1.1545 + } 1.1546 + 1.1547 + return true; 1.1548 +} 1.1549 + 1.1550 +bool 1.1551 +DictionaryBase::ParseJSON(JSContext* aCx, 1.1552 + const nsAString& aJSON, 1.1553 + JS::MutableHandle<JS::Value> aVal) 1.1554 +{ 1.1555 + if (aJSON.IsEmpty()) { 1.1556 + return true; 1.1557 + } 1.1558 + return JS_ParseJSON(aCx, 1.1559 + static_cast<const jschar*>(PromiseFlatString(aJSON).get()), 1.1560 + aJSON.Length(), aVal); 1.1561 +} 1.1562 + 1.1563 +static JSString* 1.1564 +ConcatJSString(JSContext* cx, const char* pre, JS::Handle<JSString*> str, const char* post) 1.1565 +{ 1.1566 + if (!str) { 1.1567 + return nullptr; 1.1568 + } 1.1569 + 1.1570 + JS::Rooted<JSString*> preString(cx, JS_NewStringCopyN(cx, pre, strlen(pre))); 1.1571 + JS::Rooted<JSString*> postString(cx, JS_NewStringCopyN(cx, post, strlen(post))); 1.1572 + if (!preString || !postString) { 1.1573 + return nullptr; 1.1574 + } 1.1575 + 1.1576 + preString = JS_ConcatStrings(cx, preString, str); 1.1577 + if (!preString) { 1.1578 + return nullptr; 1.1579 + } 1.1580 + 1.1581 + return JS_ConcatStrings(cx, preString, postString); 1.1582 +} 1.1583 + 1.1584 +bool 1.1585 +NativeToString(JSContext* cx, JS::Handle<JSObject*> wrapper, 1.1586 + JS::Handle<JSObject*> obj, const char* pre, 1.1587 + const char* post, 1.1588 + JS::MutableHandle<JS::Value> v) 1.1589 +{ 1.1590 + JS::Rooted<JSPropertyDescriptor> toStringDesc(cx); 1.1591 + toStringDesc.object().set(nullptr); 1.1592 + toStringDesc.setAttributes(0); 1.1593 + toStringDesc.setGetter(nullptr); 1.1594 + toStringDesc.setSetter(nullptr); 1.1595 + toStringDesc.value().set(JS::UndefinedValue()); 1.1596 + JS::Rooted<jsid> id(cx, 1.1597 + nsXPConnect::GetRuntimeInstance()->GetStringID(XPCJSRuntime::IDX_TO_STRING)); 1.1598 + if (!XrayResolveNativeProperty(cx, wrapper, obj, id, &toStringDesc)) { 1.1599 + return false; 1.1600 + } 1.1601 + 1.1602 + JS::Rooted<JSString*> str(cx); 1.1603 + { 1.1604 + JSAutoCompartment ac(cx, obj); 1.1605 + if (toStringDesc.object()) { 1.1606 + JS::Rooted<JS::Value> toString(cx, toStringDesc.value()); 1.1607 + if (!JS_WrapValue(cx, &toString)) { 1.1608 + return false; 1.1609 + } 1.1610 + MOZ_ASSERT(JS_ObjectIsCallable(cx, &toString.toObject())); 1.1611 + JS::Rooted<JS::Value> toStringResult(cx); 1.1612 + if (JS_CallFunctionValue(cx, obj, toString, JS::HandleValueArray::empty(), 1.1613 + &toStringResult)) { 1.1614 + str = toStringResult.toString(); 1.1615 + } else { 1.1616 + str = nullptr; 1.1617 + } 1.1618 + } else { 1.1619 + const js::Class* clasp = js::GetObjectClass(obj); 1.1620 + if (IsDOMClass(clasp)) { 1.1621 + str = JS_NewStringCopyZ(cx, clasp->name); 1.1622 + str = ConcatJSString(cx, "[object ", str, "]"); 1.1623 + } else if (IsDOMIfaceAndProtoClass(clasp)) { 1.1624 + const DOMIfaceAndProtoJSClass* ifaceAndProtoJSClass = 1.1625 + DOMIfaceAndProtoJSClass::FromJSClass(clasp); 1.1626 + str = JS_NewStringCopyZ(cx, ifaceAndProtoJSClass->mToString); 1.1627 + } else { 1.1628 + MOZ_ASSERT(JS_IsNativeFunction(obj, Constructor)); 1.1629 + JS::Rooted<JSFunction*> fun(cx, JS_GetObjectFunction(obj)); 1.1630 + str = JS_DecompileFunction(cx, fun, 0); 1.1631 + } 1.1632 + str = ConcatJSString(cx, pre, str, post); 1.1633 + } 1.1634 + } 1.1635 + 1.1636 + if (!str) { 1.1637 + return false; 1.1638 + } 1.1639 + 1.1640 + v.setString(str); 1.1641 + return JS_WrapValue(cx, v); 1.1642 +} 1.1643 + 1.1644 +// Dynamically ensure that two objects don't end up with the same reserved slot. 1.1645 +class MOZ_STACK_CLASS AutoCloneDOMObjectSlotGuard 1.1646 +{ 1.1647 +public: 1.1648 + AutoCloneDOMObjectSlotGuard(JSContext* aCx, JSObject* aOld, JSObject* aNew) 1.1649 + : mOldReflector(aCx, aOld), mNewReflector(aCx, aNew) 1.1650 + { 1.1651 + MOZ_ASSERT(js::GetReservedSlot(aOld, DOM_OBJECT_SLOT) == 1.1652 + js::GetReservedSlot(aNew, DOM_OBJECT_SLOT)); 1.1653 + } 1.1654 + 1.1655 + ~AutoCloneDOMObjectSlotGuard() 1.1656 + { 1.1657 + if (js::GetReservedSlot(mOldReflector, DOM_OBJECT_SLOT).toPrivate()) { 1.1658 + js::SetReservedSlot(mNewReflector, DOM_OBJECT_SLOT, 1.1659 + JS::PrivateValue(nullptr)); 1.1660 + } 1.1661 + } 1.1662 + 1.1663 +private: 1.1664 + JS::Rooted<JSObject*> mOldReflector; 1.1665 + JS::Rooted<JSObject*> mNewReflector; 1.1666 +}; 1.1667 + 1.1668 +nsresult 1.1669 +ReparentWrapper(JSContext* aCx, JS::Handle<JSObject*> aObjArg) 1.1670 +{ 1.1671 + js::AssertSameCompartment(aCx, aObjArg); 1.1672 + 1.1673 + // Check if we're near the stack limit before we get anywhere near the 1.1674 + // transplanting code. 1.1675 + JS_CHECK_RECURSION(aCx, return NS_ERROR_FAILURE); 1.1676 + 1.1677 + JS::Rooted<JSObject*> aObj(aCx, aObjArg); 1.1678 + const DOMClass* domClass = GetDOMClass(aObj); 1.1679 + 1.1680 + JS::Rooted<JSObject*> oldParent(aCx, JS_GetParent(aObj)); 1.1681 + JS::Rooted<JSObject*> newParent(aCx, domClass->mGetParent(aCx, aObj)); 1.1682 + 1.1683 + JSAutoCompartment oldAc(aCx, oldParent); 1.1684 + 1.1685 + JSCompartment* oldCompartment = js::GetObjectCompartment(oldParent); 1.1686 + JSCompartment* newCompartment = js::GetObjectCompartment(newParent); 1.1687 + if (oldCompartment == newCompartment) { 1.1688 + if (!JS_SetParent(aCx, aObj, newParent)) { 1.1689 + MOZ_CRASH(); 1.1690 + } 1.1691 + return NS_OK; 1.1692 + } 1.1693 + 1.1694 + // Telemetry. 1.1695 + xpc::RecordDonatedNode(oldCompartment); 1.1696 + xpc::RecordAdoptedNode(newCompartment); 1.1697 + 1.1698 + nsISupports* native = UnwrapDOMObjectToISupports(aObj); 1.1699 + if (!native) { 1.1700 + return NS_OK; 1.1701 + } 1.1702 + 1.1703 + bool isProxy = js::IsProxy(aObj); 1.1704 + JS::Rooted<JSObject*> expandoObject(aCx); 1.1705 + if (isProxy) { 1.1706 + expandoObject = DOMProxyHandler::GetAndClearExpandoObject(aObj); 1.1707 + } 1.1708 + 1.1709 + JSAutoCompartment newAc(aCx, newParent); 1.1710 + 1.1711 + // First we clone the reflector. We get a copy of its properties and clone its 1.1712 + // expando chain. The only part that is dangerous here is that if we have to 1.1713 + // return early we must avoid ending up with two reflectors pointing to the 1.1714 + // same native. Other than that, the objects we create will just go away. 1.1715 + 1.1716 + JS::Rooted<JSObject*> global(aCx, 1.1717 + js::GetGlobalForObjectCrossCompartment(newParent)); 1.1718 + JS::Handle<JSObject*> proto = (domClass->mGetProto)(aCx, global); 1.1719 + if (!proto) { 1.1720 + return NS_ERROR_FAILURE; 1.1721 + } 1.1722 + 1.1723 + JS::Rooted<JSObject*> newobj(aCx, JS_CloneObject(aCx, aObj, proto, newParent)); 1.1724 + if (!newobj) { 1.1725 + return NS_ERROR_FAILURE; 1.1726 + } 1.1727 + 1.1728 + js::SetReservedSlot(newobj, DOM_OBJECT_SLOT, 1.1729 + js::GetReservedSlot(aObj, DOM_OBJECT_SLOT)); 1.1730 + 1.1731 + // At this point, both |aObj| and |newobj| point to the same native 1.1732 + // which is bad, because one of them will end up being finalized with a 1.1733 + // native it does not own. |cloneGuard| ensures that if we exit before 1.1734 + // clearing |aObj|'s reserved slot the reserved slot of |newobj| will be 1.1735 + // set to null. |aObj| will go away soon, because we swap it with 1.1736 + // another object during the transplant and let that object die. 1.1737 + JS::Rooted<JSObject*> propertyHolder(aCx); 1.1738 + { 1.1739 + AutoCloneDOMObjectSlotGuard cloneGuard(aCx, aObj, newobj); 1.1740 + 1.1741 + JS::Rooted<JSObject*> copyFrom(aCx, isProxy ? expandoObject : aObj); 1.1742 + if (copyFrom) { 1.1743 + propertyHolder = JS_NewObjectWithGivenProto(aCx, nullptr, JS::NullPtr(), 1.1744 + newParent); 1.1745 + if (!propertyHolder) { 1.1746 + return NS_ERROR_OUT_OF_MEMORY; 1.1747 + } 1.1748 + 1.1749 + if (!JS_CopyPropertiesFrom(aCx, propertyHolder, copyFrom)) { 1.1750 + return NS_ERROR_FAILURE; 1.1751 + } 1.1752 + } else { 1.1753 + propertyHolder = nullptr; 1.1754 + } 1.1755 + 1.1756 + // Expandos from other compartments are attached to the target JS object. 1.1757 + // Copy them over, and let the old ones die a natural death. 1.1758 + if (!xpc::XrayUtils::CloneExpandoChain(aCx, newobj, aObj)) { 1.1759 + return NS_ERROR_FAILURE; 1.1760 + } 1.1761 + 1.1762 + // We've set up |newobj|, so we make it own the native by nulling 1.1763 + // out the reserved slot of |obj|. 1.1764 + // 1.1765 + // NB: It's important to do this _after_ copying the properties to 1.1766 + // propertyHolder. Otherwise, an object with |foo.x === foo| will 1.1767 + // crash when JS_CopyPropertiesFrom tries to call wrap() on foo.x. 1.1768 + js::SetReservedSlot(aObj, DOM_OBJECT_SLOT, JS::PrivateValue(nullptr)); 1.1769 + } 1.1770 + 1.1771 + aObj = xpc::TransplantObject(aCx, aObj, newobj); 1.1772 + if (!aObj) { 1.1773 + MOZ_CRASH(); 1.1774 + } 1.1775 + 1.1776 + nsWrapperCache* cache = nullptr; 1.1777 + CallQueryInterface(native, &cache); 1.1778 + bool preserving = cache->PreservingWrapper(); 1.1779 + cache->SetPreservingWrapper(false); 1.1780 + cache->SetWrapper(aObj); 1.1781 + cache->SetPreservingWrapper(preserving); 1.1782 + 1.1783 + if (propertyHolder) { 1.1784 + JS::Rooted<JSObject*> copyTo(aCx); 1.1785 + if (isProxy) { 1.1786 + copyTo = DOMProxyHandler::EnsureExpandoObject(aCx, aObj); 1.1787 + } else { 1.1788 + copyTo = aObj; 1.1789 + } 1.1790 + 1.1791 + if (!copyTo || !JS_CopyPropertiesFrom(aCx, copyTo, propertyHolder)) { 1.1792 + MOZ_CRASH(); 1.1793 + } 1.1794 + } 1.1795 + 1.1796 + nsObjectLoadingContent* htmlobject; 1.1797 + nsresult rv = UNWRAP_OBJECT(HTMLObjectElement, aObj, htmlobject); 1.1798 + if (NS_FAILED(rv)) { 1.1799 + rv = UnwrapObject<prototypes::id::HTMLEmbedElement, 1.1800 + HTMLSharedObjectElement>(aObj, htmlobject); 1.1801 + if (NS_FAILED(rv)) { 1.1802 + rv = UnwrapObject<prototypes::id::HTMLAppletElement, 1.1803 + HTMLSharedObjectElement>(aObj, htmlobject); 1.1804 + if (NS_FAILED(rv)) { 1.1805 + htmlobject = nullptr; 1.1806 + } 1.1807 + } 1.1808 + } 1.1809 + if (htmlobject) { 1.1810 + htmlobject->SetupProtoChain(aCx, aObj); 1.1811 + } 1.1812 + 1.1813 + // Now we can just fix up the parent and return the wrapper 1.1814 + 1.1815 + if (newParent && !JS_SetParent(aCx, aObj, newParent)) { 1.1816 + MOZ_CRASH(); 1.1817 + } 1.1818 + 1.1819 + return NS_OK; 1.1820 +} 1.1821 + 1.1822 +GlobalObject::GlobalObject(JSContext* aCx, JSObject* aObject) 1.1823 + : mGlobalJSObject(aCx), 1.1824 + mCx(aCx), 1.1825 + mGlobalObject(nullptr) 1.1826 +{ 1.1827 + JS::Rooted<JSObject*> obj(aCx, aObject); 1.1828 + if (js::IsWrapper(obj)) { 1.1829 + obj = js::CheckedUnwrap(obj, /* stopAtOuter = */ false); 1.1830 + if (!obj) { 1.1831 + // We should never end up here on a worker thread, since there shouldn't 1.1832 + // be any security wrappers to worry about. 1.1833 + if (!MOZ_LIKELY(NS_IsMainThread())) { 1.1834 + MOZ_CRASH(); 1.1835 + } 1.1836 + 1.1837 + Throw(aCx, NS_ERROR_XPC_SECURITY_MANAGER_VETO); 1.1838 + return; 1.1839 + } 1.1840 + } 1.1841 + 1.1842 + mGlobalJSObject = js::GetGlobalForObjectCrossCompartment(obj); 1.1843 +} 1.1844 + 1.1845 +nsISupports* 1.1846 +GlobalObject::GetAsSupports() const 1.1847 +{ 1.1848 + if (mGlobalObject) { 1.1849 + return mGlobalObject; 1.1850 + } 1.1851 + 1.1852 + if (!NS_IsMainThread()) { 1.1853 + mGlobalObject = UnwrapDOMObjectToISupports(mGlobalJSObject); 1.1854 + return mGlobalObject; 1.1855 + } 1.1856 + 1.1857 + JS::Rooted<JS::Value> val(mCx, JS::ObjectValue(*mGlobalJSObject)); 1.1858 + 1.1859 + // Switch this to UnwrapDOMObjectToISupports once our global objects are 1.1860 + // using new bindings. 1.1861 + nsresult rv = xpc_qsUnwrapArg<nsISupports>(mCx, val, &mGlobalObject, 1.1862 + static_cast<nsISupports**>(getter_AddRefs(mGlobalObjectRef)), 1.1863 + &val); 1.1864 + if (NS_FAILED(rv)) { 1.1865 + mGlobalObject = nullptr; 1.1866 + Throw(mCx, NS_ERROR_XPC_BAD_CONVERT_JS); 1.1867 + } 1.1868 + 1.1869 + return mGlobalObject; 1.1870 +} 1.1871 + 1.1872 +bool 1.1873 +InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj, 1.1874 + JS::Handle<JSObject*> instance, 1.1875 + bool* bp) 1.1876 +{ 1.1877 + const DOMIfaceAndProtoJSClass* clasp = 1.1878 + DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj)); 1.1879 + 1.1880 + const DOMClass* domClass = GetDOMClass(js::UncheckedUnwrap(instance)); 1.1881 + 1.1882 + MOZ_ASSERT(!domClass || clasp->mPrototypeID != prototypes::id::_ID_Count, 1.1883 + "Why do we have a hasInstance hook if we don't have a prototype " 1.1884 + "ID?"); 1.1885 + 1.1886 + if (domClass && 1.1887 + domClass->mInterfaceChain[clasp->mDepth] == clasp->mPrototypeID) { 1.1888 + *bp = true; 1.1889 + return true; 1.1890 + } 1.1891 + 1.1892 + JS::Rooted<JSObject*> unwrapped(cx, js::CheckedUnwrap(instance, true)); 1.1893 + if (unwrapped && jsipc::JavaScriptParent::IsCPOW(unwrapped)) { 1.1894 + bool boolp = false; 1.1895 + if (!jsipc::JavaScriptParent::DOMInstanceOf(cx, unwrapped, clasp->mPrototypeID, 1.1896 + clasp->mDepth, &boolp)) { 1.1897 + return false; 1.1898 + } 1.1899 + *bp = boolp; 1.1900 + return true; 1.1901 + } 1.1902 + 1.1903 + JS::Rooted<JS::Value> protov(cx); 1.1904 + DebugOnly<bool> ok = JS_GetProperty(cx, obj, "prototype", &protov); 1.1905 + MOZ_ASSERT(ok, "Someone messed with our prototype property?"); 1.1906 + 1.1907 + JS::Rooted<JSObject*> interfacePrototype(cx, &protov.toObject()); 1.1908 + MOZ_ASSERT(IsDOMIfaceAndProtoClass(js::GetObjectClass(interfacePrototype)), 1.1909 + "Someone messed with our prototype property?"); 1.1910 + 1.1911 + JS::Rooted<JSObject*> proto(cx); 1.1912 + if (!JS_GetPrototype(cx, instance, &proto)) { 1.1913 + return false; 1.1914 + } 1.1915 + 1.1916 + while (proto) { 1.1917 + if (proto == interfacePrototype) { 1.1918 + *bp = true; 1.1919 + return true; 1.1920 + } 1.1921 + 1.1922 + if (!JS_GetPrototype(cx, proto, &proto)) { 1.1923 + return false; 1.1924 + } 1.1925 + } 1.1926 + 1.1927 + *bp = false; 1.1928 + return true; 1.1929 +} 1.1930 + 1.1931 +bool 1.1932 +InterfaceHasInstance(JSContext* cx, JS::Handle<JSObject*> obj, JS::MutableHandle<JS::Value> vp, 1.1933 + bool* bp) 1.1934 +{ 1.1935 + if (!vp.isObject()) { 1.1936 + *bp = false; 1.1937 + return true; 1.1938 + } 1.1939 + 1.1940 + JS::Rooted<JSObject*> instanceObject(cx, &vp.toObject()); 1.1941 + return InterfaceHasInstance(cx, obj, instanceObject, bp); 1.1942 +} 1.1943 + 1.1944 +bool 1.1945 +InterfaceHasInstance(JSContext* cx, int prototypeID, int depth, 1.1946 + JS::Handle<JSObject*> instance, 1.1947 + bool* bp) 1.1948 +{ 1.1949 + const DOMClass* domClass = GetDOMClass(js::UncheckedUnwrap(instance)); 1.1950 + 1.1951 + MOZ_ASSERT(!domClass || prototypeID != prototypes::id::_ID_Count, 1.1952 + "Why do we have a hasInstance hook if we don't have a prototype " 1.1953 + "ID?"); 1.1954 + 1.1955 + *bp = (domClass && domClass->mInterfaceChain[depth] == prototypeID); 1.1956 + return true; 1.1957 +} 1.1958 + 1.1959 +bool 1.1960 +ReportLenientThisUnwrappingFailure(JSContext* cx, JSObject* obj) 1.1961 +{ 1.1962 + JS::Rooted<JSObject*> rootedObj(cx, obj); 1.1963 + GlobalObject global(cx, rootedObj); 1.1964 + if (global.Failed()) { 1.1965 + return false; 1.1966 + } 1.1967 + nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(global.GetAsSupports()); 1.1968 + if (window && window->GetDoc()) { 1.1969 + window->GetDoc()->WarnOnceAbout(nsIDocument::eLenientThis); 1.1970 + } 1.1971 + return true; 1.1972 +} 1.1973 + 1.1974 +bool 1.1975 +GetWindowForJSImplementedObject(JSContext* cx, JS::Handle<JSObject*> obj, 1.1976 + nsPIDOMWindow** window) 1.1977 +{ 1.1978 + // Be very careful to not get tricked here. 1.1979 + MOZ_ASSERT(NS_IsMainThread()); 1.1980 + if (!xpc::AccessCheck::isChrome(js::GetObjectCompartment(obj))) { 1.1981 + NS_RUNTIMEABORT("Should have a chrome object here"); 1.1982 + } 1.1983 + 1.1984 + // Look up the content-side object. 1.1985 + JS::Rooted<JS::Value> domImplVal(cx); 1.1986 + if (!JS_GetProperty(cx, obj, "__DOM_IMPL__", &domImplVal)) { 1.1987 + return false; 1.1988 + } 1.1989 + 1.1990 + if (!domImplVal.isObject()) { 1.1991 + ThrowErrorMessage(cx, MSG_NOT_OBJECT, "Value"); 1.1992 + return false; 1.1993 + } 1.1994 + 1.1995 + // Go ahead and get the global from it. GlobalObject will handle 1.1996 + // doing unwrapping as needed. 1.1997 + GlobalObject global(cx, &domImplVal.toObject()); 1.1998 + if (global.Failed()) { 1.1999 + return false; 1.2000 + } 1.2001 + 1.2002 + // It's OK if we have null here: that just means the content-side 1.2003 + // object really wasn't associated with any window. 1.2004 + nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(global.GetAsSupports())); 1.2005 + win.forget(window); 1.2006 + return true; 1.2007 +} 1.2008 + 1.2009 +already_AddRefed<nsPIDOMWindow> 1.2010 +ConstructJSImplementation(JSContext* aCx, const char* aContractId, 1.2011 + const GlobalObject& aGlobal, 1.2012 + JS::MutableHandle<JSObject*> aObject, 1.2013 + ErrorResult& aRv) 1.2014 +{ 1.2015 + // Get the window to use as a parent and for initialization. 1.2016 + nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports()); 1.2017 + if (!window) { 1.2018 + aRv.Throw(NS_ERROR_FAILURE); 1.2019 + return nullptr; 1.2020 + } 1.2021 + 1.2022 + ConstructJSImplementation(aCx, aContractId, window, aObject, aRv); 1.2023 + 1.2024 + if (aRv.Failed()) { 1.2025 + return nullptr; 1.2026 + } 1.2027 + return window.forget(); 1.2028 +} 1.2029 + 1.2030 +void 1.2031 +ConstructJSImplementation(JSContext* aCx, const char* aContractId, 1.2032 + nsPIDOMWindow* aWindow, 1.2033 + JS::MutableHandle<JSObject*> aObject, 1.2034 + ErrorResult& aRv) 1.2035 +{ 1.2036 + // Make sure to divorce ourselves from the calling JS while creating and 1.2037 + // initializing the object, so exceptions from that will get reported 1.2038 + // properly, since those are never exceptions that a spec wants to be thrown. 1.2039 + { 1.2040 + AutoNoJSAPI nojsapi; 1.2041 + 1.2042 + // Get the XPCOM component containing the JS implementation. 1.2043 + nsCOMPtr<nsISupports> implISupports = do_CreateInstance(aContractId); 1.2044 + if (!implISupports) { 1.2045 + NS_WARNING("Failed to get JS implementation for contract"); 1.2046 + aRv.Throw(NS_ERROR_FAILURE); 1.2047 + return; 1.2048 + } 1.2049 + // Initialize the object, if it implements nsIDOMGlobalPropertyInitializer. 1.2050 + nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi = 1.2051 + do_QueryInterface(implISupports); 1.2052 + if (gpi) { 1.2053 + JS::Rooted<JS::Value> initReturn(aCx); 1.2054 + nsresult rv = gpi->Init(aWindow, &initReturn); 1.2055 + if (NS_FAILED(rv)) { 1.2056 + aRv.Throw(rv); 1.2057 + return; 1.2058 + } 1.2059 + // With JS-implemented WebIDL, the return value of init() is not used to determine 1.2060 + // if init() failed, so init() should only return undefined. Any kind of permission 1.2061 + // or pref checking must happen by adding an attribute to the WebIDL interface. 1.2062 + if (!initReturn.isUndefined()) { 1.2063 + MOZ_ASSERT(false, "The init() method for JS-implemented WebIDL should not return anything"); 1.2064 + MOZ_CRASH(); 1.2065 + } 1.2066 + } 1.2067 + // Extract the JS implementation from the XPCOM object. 1.2068 + nsCOMPtr<nsIXPConnectWrappedJS> implWrapped = 1.2069 + do_QueryInterface(implISupports); 1.2070 + MOZ_ASSERT(implWrapped, "Failed to get wrapped JS from XPCOM component."); 1.2071 + if (!implWrapped) { 1.2072 + aRv.Throw(NS_ERROR_FAILURE); 1.2073 + return; 1.2074 + } 1.2075 + aObject.set(implWrapped->GetJSObject()); 1.2076 + if (!aObject) { 1.2077 + aRv.Throw(NS_ERROR_FAILURE); 1.2078 + } 1.2079 + } 1.2080 +} 1.2081 + 1.2082 +bool 1.2083 +NonVoidByteStringToJsval(JSContext *cx, const nsACString &str, 1.2084 + JS::MutableHandle<JS::Value> rval) 1.2085 +{ 1.2086 + // ByteStrings are not UTF-8 encoded. 1.2087 + JSString* jsStr = JS_NewStringCopyN(cx, str.Data(), str.Length()); 1.2088 + 1.2089 + if (!jsStr) 1.2090 + return false; 1.2091 + 1.2092 + rval.setString(jsStr); 1.2093 + return true; 1.2094 +} 1.2095 + 1.2096 +bool 1.2097 +ConvertJSValueToByteString(JSContext* cx, JS::Handle<JS::Value> v, 1.2098 + JS::MutableHandle<JS::Value> pval, bool nullable, 1.2099 + nsACString& result) 1.2100 +{ 1.2101 + JS::Rooted<JSString*> s(cx); 1.2102 + if (v.isString()) { 1.2103 + s = v.toString(); 1.2104 + } else { 1.2105 + 1.2106 + if (nullable && v.isNullOrUndefined()) { 1.2107 + result.SetIsVoid(true); 1.2108 + return true; 1.2109 + } 1.2110 + 1.2111 + s = JS::ToString(cx, v); 1.2112 + if (!s) { 1.2113 + return false; 1.2114 + } 1.2115 + pval.set(JS::StringValue(s)); // Root the new string. 1.2116 + } 1.2117 + 1.2118 + size_t length; 1.2119 + const jschar *chars = JS_GetStringCharsZAndLength(cx, s, &length); 1.2120 + if (!chars) { 1.2121 + return false; 1.2122 + } 1.2123 + 1.2124 + // Conversion from Javascript string to ByteString is only valid if all 1.2125 + // characters < 256. 1.2126 + for (size_t i = 0; i < length; i++) { 1.2127 + if (chars[i] > 255) { 1.2128 + // The largest unsigned 64 bit number (18,446,744,073,709,551,615) has 1.2129 + // 20 digits, plus one more for the null terminator. 1.2130 + char index[21]; 1.2131 + static_assert(sizeof(size_t) <= 8, "index array too small"); 1.2132 + PR_snprintf(index, sizeof(index), "%d", i); 1.2133 + // A jschar is 16 bits long. The biggest unsigned 16 bit 1.2134 + // number (65,535) has 5 digits, plus one more for the null 1.2135 + // terminator. 1.2136 + char badChar[6]; 1.2137 + static_assert(sizeof(jschar) <= 2, "badChar array too small"); 1.2138 + PR_snprintf(badChar, sizeof(badChar), "%d", chars[i]); 1.2139 + ThrowErrorMessage(cx, MSG_INVALID_BYTESTRING, index, badChar); 1.2140 + return false; 1.2141 + } 1.2142 + } 1.2143 + 1.2144 + if (length >= UINT32_MAX) { 1.2145 + return false; 1.2146 + } 1.2147 + result.SetCapacity(length+1); 1.2148 + JS_EncodeStringToBuffer(cx, s, result.BeginWriting(), length); 1.2149 + result.BeginWriting()[length] = '\0'; 1.2150 + result.SetLength(length); 1.2151 + 1.2152 + return true; 1.2153 +} 1.2154 + 1.2155 +bool 1.2156 +IsInPrivilegedApp(JSContext* aCx, JSObject* aObj) 1.2157 +{ 1.2158 + using mozilla::dom::workers::GetWorkerPrivateFromContext; 1.2159 + if (!NS_IsMainThread()) { 1.2160 + return GetWorkerPrivateFromContext(aCx)->IsInPrivilegedApp(); 1.2161 + } 1.2162 + 1.2163 + nsIPrincipal* principal = nsContentUtils::GetObjectPrincipal(aObj); 1.2164 + uint16_t appStatus = principal->GetAppStatus(); 1.2165 + return (appStatus == nsIPrincipal::APP_STATUS_CERTIFIED || 1.2166 + appStatus == nsIPrincipal::APP_STATUS_PRIVILEGED); 1.2167 +} 1.2168 + 1.2169 +bool 1.2170 +IsInCertifiedApp(JSContext* aCx, JSObject* aObj) 1.2171 +{ 1.2172 + using mozilla::dom::workers::GetWorkerPrivateFromContext; 1.2173 + if (!NS_IsMainThread()) { 1.2174 + return GetWorkerPrivateFromContext(aCx)->IsInCertifiedApp(); 1.2175 + } 1.2176 + 1.2177 + nsIPrincipal* principal = nsContentUtils::GetObjectPrincipal(aObj); 1.2178 + return principal->GetAppStatus() == nsIPrincipal::APP_STATUS_CERTIFIED; 1.2179 +} 1.2180 + 1.2181 +void 1.2182 +TraceGlobal(JSTracer* aTrc, JSObject* aObj) 1.2183 +{ 1.2184 + MOZ_ASSERT(js::GetObjectClass(aObj)->flags & JSCLASS_DOM_GLOBAL); 1.2185 + mozilla::dom::TraceProtoAndIfaceCache(aTrc, aObj); 1.2186 +} 1.2187 + 1.2188 +void 1.2189 +FinalizeGlobal(JSFreeOp* aFreeOp, JSObject* aObj) 1.2190 +{ 1.2191 + MOZ_ASSERT(js::GetObjectClass(aObj)->flags & JSCLASS_DOM_GLOBAL); 1.2192 + mozilla::dom::DestroyProtoAndIfaceCache(aObj); 1.2193 +} 1.2194 + 1.2195 +bool 1.2196 +ResolveGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj, 1.2197 + JS::Handle<jsid> aId, JS::MutableHandle<JSObject*> aObjp) 1.2198 +{ 1.2199 + bool resolved; 1.2200 + if (!JS_ResolveStandardClass(aCx, aObj, aId, &resolved)) { 1.2201 + return false; 1.2202 + } 1.2203 + 1.2204 + aObjp.set(resolved ? aObj.get() : nullptr); 1.2205 + return true; 1.2206 +} 1.2207 + 1.2208 +bool 1.2209 +EnumerateGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj) 1.2210 +{ 1.2211 + return JS_EnumerateStandardClasses(aCx, aObj); 1.2212 +} 1.2213 + 1.2214 +bool 1.2215 +GenericBindingGetter(JSContext* cx, unsigned argc, JS::Value* vp) 1.2216 +{ 1.2217 + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); 1.2218 + const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev()); 1.2219 + prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID); 1.2220 + if (!args.thisv().isObject()) { 1.2221 + return ThrowInvalidThis(cx, args, 1.2222 + MSG_GETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE, 1.2223 + protoID); 1.2224 + } 1.2225 + JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject()); 1.2226 + 1.2227 + void* self; 1.2228 + { 1.2229 + nsresult rv = UnwrapObject<void>(obj, self, protoID, info->depth); 1.2230 + if (NS_FAILED(rv)) { 1.2231 + return ThrowInvalidThis(cx, args, 1.2232 + GetInvalidThisErrorForGetter(rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO), 1.2233 + protoID); 1.2234 + } 1.2235 + } 1.2236 + 1.2237 + MOZ_ASSERT(info->type() == JSJitInfo::Getter); 1.2238 + JSJitGetterOp getter = info->getter; 1.2239 + return getter(cx, obj, self, JSJitGetterCallArgs(args)); 1.2240 +} 1.2241 + 1.2242 +bool 1.2243 +GenericBindingSetter(JSContext* cx, unsigned argc, JS::Value* vp) 1.2244 +{ 1.2245 + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); 1.2246 + const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev()); 1.2247 + prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID); 1.2248 + if (!args.thisv().isObject()) { 1.2249 + return ThrowInvalidThis(cx, args, 1.2250 + MSG_SETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE, 1.2251 + protoID); 1.2252 + } 1.2253 + JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject()); 1.2254 + 1.2255 + void* self; 1.2256 + { 1.2257 + nsresult rv = UnwrapObject<void>(obj, self, protoID, info->depth); 1.2258 + if (NS_FAILED(rv)) { 1.2259 + return ThrowInvalidThis(cx, args, 1.2260 + GetInvalidThisErrorForSetter(rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO), 1.2261 + protoID); 1.2262 + } 1.2263 + } 1.2264 + if (args.length() == 0) { 1.2265 + return ThrowNoSetterArg(cx, protoID); 1.2266 + } 1.2267 + MOZ_ASSERT(info->type() == JSJitInfo::Setter); 1.2268 + JSJitSetterOp setter = info->setter; 1.2269 + if (!setter(cx, obj, self, JSJitSetterCallArgs(args))) { 1.2270 + return false; 1.2271 + } 1.2272 + args.rval().set(JSVAL_VOID); 1.2273 + return true; 1.2274 +} 1.2275 + 1.2276 +bool 1.2277 +GenericBindingMethod(JSContext* cx, unsigned argc, JS::Value* vp) 1.2278 +{ 1.2279 + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); 1.2280 + const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev()); 1.2281 + prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID); 1.2282 + if (!args.thisv().isObject()) { 1.2283 + return ThrowInvalidThis(cx, args, 1.2284 + MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE, 1.2285 + protoID); 1.2286 + } 1.2287 + JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject()); 1.2288 + 1.2289 + void* self; 1.2290 + { 1.2291 + nsresult rv = UnwrapObject<void>(obj, self, protoID, info->depth); 1.2292 + if (NS_FAILED(rv)) { 1.2293 + return ThrowInvalidThis(cx, args, 1.2294 + GetInvalidThisErrorForMethod(rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO), 1.2295 + protoID); 1.2296 + } 1.2297 + } 1.2298 + MOZ_ASSERT(info->type() == JSJitInfo::Method); 1.2299 + JSJitMethodOp method = info->method; 1.2300 + return method(cx, obj, self, JSJitMethodCallArgs(args)); 1.2301 +} 1.2302 + 1.2303 +bool 1.2304 +GenericPromiseReturningBindingMethod(JSContext* cx, unsigned argc, JS::Value* vp) 1.2305 +{ 1.2306 + // Make sure to save the callee before someone maybe messes with rval(). 1.2307 + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); 1.2308 + JS::Rooted<JSObject*> callee(cx, &args.callee()); 1.2309 + 1.2310 + // We could invoke GenericBindingMethod here, but that involves an 1.2311 + // extra call. Manually inline it instead. 1.2312 + const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev()); 1.2313 + prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID); 1.2314 + if (!args.thisv().isObject()) { 1.2315 + ThrowInvalidThis(cx, args, 1.2316 + MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE, 1.2317 + protoID); 1.2318 + return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee), 1.2319 + args.rval()); 1.2320 + } 1.2321 + JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject()); 1.2322 + 1.2323 + void* self; 1.2324 + { 1.2325 + nsresult rv = UnwrapObject<void>(obj, self, protoID, info->depth); 1.2326 + if (NS_FAILED(rv)) { 1.2327 + ThrowInvalidThis(cx, args, 1.2328 + GetInvalidThisErrorForMethod(rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO), 1.2329 + protoID); 1.2330 + return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee), 1.2331 + args.rval()); 1.2332 + } 1.2333 + } 1.2334 + MOZ_ASSERT(info->type() == JSJitInfo::Method); 1.2335 + JSJitMethodOp method = info->method; 1.2336 + bool ok = method(cx, obj, self, JSJitMethodCallArgs(args)); 1.2337 + if (ok) { 1.2338 + return true; 1.2339 + } 1.2340 + 1.2341 + return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee), 1.2342 + args.rval()); 1.2343 +} 1.2344 + 1.2345 +bool 1.2346 +StaticMethodPromiseWrapper(JSContext* cx, unsigned argc, JS::Value* vp) 1.2347 +{ 1.2348 + // Make sure to save the callee before someone maybe messes with rval(). 1.2349 + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); 1.2350 + JS::Rooted<JSObject*> callee(cx, &args.callee()); 1.2351 + 1.2352 + const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev()); 1.2353 + MOZ_ASSERT(info); 1.2354 + MOZ_ASSERT(info->type() == JSJitInfo::StaticMethod); 1.2355 + 1.2356 + bool ok = info->staticMethod(cx, argc, vp); 1.2357 + if (ok) { 1.2358 + return true; 1.2359 + } 1.2360 + 1.2361 + return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee), 1.2362 + args.rval()); 1.2363 +} 1.2364 + 1.2365 +bool 1.2366 +ConvertExceptionToPromise(JSContext* cx, 1.2367 + JSObject* promiseScope, 1.2368 + JS::MutableHandle<JS::Value> rval) 1.2369 +{ 1.2370 + GlobalObject global(cx, promiseScope); 1.2371 + if (global.Failed()) { 1.2372 + return false; 1.2373 + } 1.2374 + 1.2375 + JS::Rooted<JS::Value> exn(cx); 1.2376 + if (!JS_GetPendingException(cx, &exn)) { 1.2377 + return false; 1.2378 + } 1.2379 + 1.2380 + JS_ClearPendingException(cx); 1.2381 + ErrorResult rv; 1.2382 + nsRefPtr<Promise> promise = Promise::Reject(global, cx, exn, rv); 1.2383 + if (rv.Failed()) { 1.2384 + // We just give up. Make sure to not leak memory on the 1.2385 + // ErrorResult, but then just put the original exception back. 1.2386 + ThrowMethodFailedWithDetails(cx, rv, "", ""); 1.2387 + JS_SetPendingException(cx, exn); 1.2388 + return false; 1.2389 + } 1.2390 + 1.2391 + return WrapNewBindingObject(cx, promise, rval); 1.2392 +} 1.2393 + 1.2394 +} // namespace dom 1.2395 +} // namespace mozilla