1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1642 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* vim: set ts=8 sts=4 et sw=4 tw=99: */ 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 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* JavaScript JSClasses and JSOps for our Wrapped Native JS Objects. */ 1.11 + 1.12 +#include "xpcprivate.h" 1.13 +#include "jsprf.h" 1.14 +#include "mozilla/dom/BindingUtils.h" 1.15 +#include "mozilla/Preferences.h" 1.16 + 1.17 +using namespace mozilla; 1.18 +using namespace JS; 1.19 + 1.20 +/***************************************************************************/ 1.21 + 1.22 +// All of the exceptions thrown into JS from this file go through here. 1.23 +// That makes this a nice place to set a breakpoint. 1.24 + 1.25 +static bool Throw(nsresult errNum, JSContext* cx) 1.26 +{ 1.27 + XPCThrower::Throw(errNum, cx); 1.28 + return false; 1.29 +} 1.30 + 1.31 +// Handy macro used in many callback stub below. 1.32 + 1.33 +#define THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper) \ 1.34 + PR_BEGIN_MACRO \ 1.35 + if (!wrapper) \ 1.36 + return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); \ 1.37 + if (!wrapper->IsValid()) \ 1.38 + return Throw(NS_ERROR_XPC_HAS_BEEN_SHUTDOWN, cx); \ 1.39 + PR_END_MACRO 1.40 + 1.41 +/***************************************************************************/ 1.42 + 1.43 +static bool 1.44 +ToStringGuts(XPCCallContext& ccx) 1.45 +{ 1.46 + char* sz; 1.47 + XPCWrappedNative* wrapper = ccx.GetWrapper(); 1.48 + 1.49 + if (wrapper) 1.50 + sz = wrapper->ToString(ccx.GetTearOff()); 1.51 + else 1.52 + sz = JS_smprintf("[xpconnect wrapped native prototype]"); 1.53 + 1.54 + if (!sz) { 1.55 + JS_ReportOutOfMemory(ccx); 1.56 + return false; 1.57 + } 1.58 + 1.59 + JSString* str = JS_NewStringCopyZ(ccx, sz); 1.60 + JS_smprintf_free(sz); 1.61 + if (!str) 1.62 + return false; 1.63 + 1.64 + ccx.SetRetVal(STRING_TO_JSVAL(str)); 1.65 + return true; 1.66 +} 1.67 + 1.68 +/***************************************************************************/ 1.69 + 1.70 +static bool 1.71 +XPC_WN_Shared_ToString(JSContext *cx, unsigned argc, jsval *vp) 1.72 +{ 1.73 + CallArgs args = CallArgsFromVp(argc, vp); 1.74 + RootedObject obj(cx, JS_THIS_OBJECT(cx, vp)); 1.75 + if (!obj) 1.76 + return false; 1.77 + 1.78 + XPCCallContext ccx(JS_CALLER, cx, obj); 1.79 + if (!ccx.IsValid()) 1.80 + return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); 1.81 + ccx.SetName(ccx.GetRuntime()->GetStringID(XPCJSRuntime::IDX_TO_STRING)); 1.82 + ccx.SetArgsAndResultPtr(args.length(), args.array(), vp); 1.83 + return ToStringGuts(ccx); 1.84 +} 1.85 + 1.86 +static bool 1.87 +XPC_WN_Shared_ToSource(JSContext *cx, unsigned argc, jsval *vp) 1.88 +{ 1.89 + CallArgs args = CallArgsFromVp(argc, vp); 1.90 + static const char empty[] = "({})"; 1.91 + JSString *str = JS_NewStringCopyN(cx, empty, sizeof(empty)-1); 1.92 + if (!str) 1.93 + return false; 1.94 + args.rval().setString(str); 1.95 + 1.96 + return true; 1.97 +} 1.98 + 1.99 +/***************************************************************************/ 1.100 + 1.101 +// A "double wrapped object" is a user JSObject that has been wrapped as a 1.102 +// wrappedJS in order to be used by native code and then re-wrapped by a 1.103 +// wrappedNative wrapper to be used by JS code. One might think of it as: 1.104 +// wrappedNative(wrappedJS(underlying_JSObject)) 1.105 +// This is done (as opposed to just unwrapping the wrapped JS and automatically 1.106 +// returning the underlying JSObject) so that JS callers will see what looks 1.107 +// Like any other xpcom object - and be limited to use its interfaces. 1.108 +// 1.109 +// See the comment preceding nsIXPCWrappedJSObjectGetter in nsIXPConnect.idl. 1.110 + 1.111 +static JSObject* 1.112 +GetDoubleWrappedJSObject(XPCCallContext& ccx, XPCWrappedNative* wrapper) 1.113 +{ 1.114 + RootedObject obj(ccx); 1.115 + nsCOMPtr<nsIXPConnectWrappedJS> 1.116 + underware = do_QueryInterface(wrapper->GetIdentityObject()); 1.117 + if (underware) { 1.118 + RootedObject mainObj(ccx, underware->GetJSObject()); 1.119 + if (mainObj) { 1.120 + RootedId id(ccx, ccx.GetRuntime()-> 1.121 + GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT)); 1.122 + 1.123 + JSAutoCompartment ac(ccx, mainObj); 1.124 + 1.125 + RootedValue val(ccx); 1.126 + if (JS_GetPropertyById(ccx, mainObj, id, &val) && 1.127 + !JSVAL_IS_PRIMITIVE(val)) { 1.128 + obj = JSVAL_TO_OBJECT(val); 1.129 + } 1.130 + } 1.131 + } 1.132 + return obj; 1.133 +} 1.134 + 1.135 +// This is the getter native function we use to handle 'wrappedJSObject' for 1.136 +// double wrapped JSObjects. 1.137 + 1.138 +static bool 1.139 +XPC_WN_DoubleWrappedGetter(JSContext *cx, unsigned argc, jsval *vp) 1.140 +{ 1.141 + CallArgs args = CallArgsFromVp(argc, vp); 1.142 + 1.143 + RootedObject obj(cx, JS_THIS_OBJECT(cx, vp)); 1.144 + if (!obj) 1.145 + return false; 1.146 + 1.147 + XPCCallContext ccx(JS_CALLER, cx, obj); 1.148 + XPCWrappedNative* wrapper = ccx.GetWrapper(); 1.149 + THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); 1.150 + 1.151 + MOZ_ASSERT(JS_TypeOfValue(cx, args.calleev()) == JSTYPE_FUNCTION, "bad function"); 1.152 + 1.153 + RootedObject realObject(cx, GetDoubleWrappedJSObject(ccx, wrapper)); 1.154 + if (!realObject) { 1.155 + // This is pretty unexpected at this point. The object originally 1.156 + // responded to this get property call and now gives no object. 1.157 + // XXX Should this throw something at the caller? 1.158 + args.rval().setNull(); 1.159 + return true; 1.160 + } 1.161 + 1.162 + // It is a double wrapped object. This should really never appear in 1.163 + // content these days, but addons still do it - see bug 965921. 1.164 + if (MOZ_UNLIKELY(!nsContentUtils::IsCallerChrome())) { 1.165 + JS_ReportError(cx, "Attempt to use .wrappedJSObject in untrusted code"); 1.166 + return false; 1.167 + } 1.168 + args.rval().setObject(*realObject); 1.169 + return JS_WrapValue(cx, args.rval()); 1.170 +} 1.171 + 1.172 +/***************************************************************************/ 1.173 + 1.174 +// This is our shared function to define properties on our JSObjects. 1.175 + 1.176 +/* 1.177 + * NOTE: 1.178 + * We *never* set the tearoff names (e.g. nsIFoo) as JS_ENUMERATE. 1.179 + * We *never* set toString or toSource as JS_ENUMERATE. 1.180 + */ 1.181 + 1.182 +static bool 1.183 +DefinePropertyIfFound(XPCCallContext& ccx, 1.184 + HandleObject obj, 1.185 + HandleId idArg, 1.186 + XPCNativeSet* set, 1.187 + XPCNativeInterface* iface, 1.188 + XPCNativeMember* member, 1.189 + XPCWrappedNativeScope* scope, 1.190 + bool reflectToStringAndToSource, 1.191 + XPCWrappedNative* wrapperToReflectInterfaceNames, 1.192 + XPCWrappedNative* wrapperToReflectDoubleWrap, 1.193 + XPCNativeScriptableInfo* scriptableInfo, 1.194 + unsigned propFlags, 1.195 + bool* resolved) 1.196 +{ 1.197 + RootedId id(ccx, idArg); 1.198 + XPCJSRuntime* rt = ccx.GetRuntime(); 1.199 + bool found; 1.200 + const char* name; 1.201 + 1.202 + if (set) { 1.203 + if (iface) 1.204 + found = true; 1.205 + else 1.206 + found = set->FindMember(id, &member, &iface); 1.207 + } else 1.208 + found = (nullptr != (member = iface->FindMember(id))); 1.209 + 1.210 + if (!found) { 1.211 + if (reflectToStringAndToSource) { 1.212 + JSNative call; 1.213 + uint32_t flags = 0; 1.214 + 1.215 + if (scriptableInfo) { 1.216 + nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface( 1.217 + scriptableInfo->GetCallback()); 1.218 + 1.219 + if (classInfo) { 1.220 + nsresult rv = classInfo->GetFlags(&flags); 1.221 + if (NS_FAILED(rv)) 1.222 + return Throw(rv, ccx); 1.223 + } 1.224 + } 1.225 + 1.226 + bool overwriteToString = !(flags & nsIClassInfo::DOM_OBJECT) 1.227 + || Preferences::GetBool("dom.XPCToStringForDOMClasses", false); 1.228 + 1.229 + if(id == rt->GetStringID(XPCJSRuntime::IDX_TO_STRING) 1.230 + && overwriteToString) 1.231 + { 1.232 + call = XPC_WN_Shared_ToString; 1.233 + name = rt->GetStringName(XPCJSRuntime::IDX_TO_STRING); 1.234 + id = rt->GetStringID(XPCJSRuntime::IDX_TO_STRING); 1.235 + } else if (id == rt->GetStringID(XPCJSRuntime::IDX_TO_SOURCE)) { 1.236 + call = XPC_WN_Shared_ToSource; 1.237 + name = rt->GetStringName(XPCJSRuntime::IDX_TO_SOURCE); 1.238 + id = rt->GetStringID(XPCJSRuntime::IDX_TO_SOURCE); 1.239 + } 1.240 + 1.241 + else 1.242 + call = nullptr; 1.243 + 1.244 + if (call) { 1.245 + RootedFunction fun(ccx, JS_NewFunction(ccx, call, 0, 0, obj, name)); 1.246 + if (!fun) { 1.247 + JS_ReportOutOfMemory(ccx); 1.248 + return false; 1.249 + } 1.250 + 1.251 + AutoResolveName arn(ccx, id); 1.252 + if (resolved) 1.253 + *resolved = true; 1.254 + return JS_DefinePropertyById(ccx, obj, id, 1.255 + OBJECT_TO_JSVAL(JS_GetFunctionObject(fun)), 1.256 + nullptr, nullptr, 1.257 + propFlags & ~JSPROP_ENUMERATE); 1.258 + } 1.259 + } 1.260 + // This *might* be a tearoff name that is not yet part of our 1.261 + // set. Let's lookup the name and see if it is the name of an 1.262 + // interface. Then we'll see if the object actually *does* this 1.263 + // interface and add a tearoff as necessary. 1.264 + 1.265 + if (wrapperToReflectInterfaceNames) { 1.266 + JSAutoByteString name; 1.267 + AutoMarkingNativeInterfacePtr iface2(ccx); 1.268 + XPCWrappedNativeTearOff* to; 1.269 + RootedObject jso(ccx); 1.270 + nsresult rv = NS_OK; 1.271 + 1.272 + if (JSID_IS_STRING(id) && 1.273 + name.encodeLatin1(ccx, JSID_TO_STRING(id)) && 1.274 + (iface2 = XPCNativeInterface::GetNewOrUsed(name.ptr()), iface2) && 1.275 + nullptr != (to = wrapperToReflectInterfaceNames-> 1.276 + FindTearOff(iface2, true, &rv)) && 1.277 + nullptr != (jso = to->GetJSObject())) 1.278 + 1.279 + { 1.280 + AutoResolveName arn(ccx, id); 1.281 + if (resolved) 1.282 + *resolved = true; 1.283 + return JS_DefinePropertyById(ccx, obj, id, OBJECT_TO_JSVAL(jso), 1.284 + nullptr, nullptr, 1.285 + propFlags & ~JSPROP_ENUMERATE); 1.286 + } else if (NS_FAILED(rv) && rv != NS_ERROR_NO_INTERFACE) { 1.287 + return Throw(rv, ccx); 1.288 + } 1.289 + } 1.290 + 1.291 + // This *might* be a double wrapped JSObject 1.292 + if (wrapperToReflectDoubleWrap && 1.293 + id == rt->GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT) && 1.294 + GetDoubleWrappedJSObject(ccx, wrapperToReflectDoubleWrap)) { 1.295 + // We build and add a getter function. 1.296 + // A security check is done on a per-get basis. 1.297 + 1.298 + JSFunction* fun; 1.299 + 1.300 + id = rt->GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT); 1.301 + name = rt->GetStringName(XPCJSRuntime::IDX_WRAPPED_JSOBJECT); 1.302 + 1.303 + fun = JS_NewFunction(ccx, XPC_WN_DoubleWrappedGetter, 1.304 + 0, 0, obj, name); 1.305 + 1.306 + if (!fun) 1.307 + return false; 1.308 + 1.309 + RootedObject funobj(ccx, JS_GetFunctionObject(fun)); 1.310 + if (!funobj) 1.311 + return false; 1.312 + 1.313 + propFlags |= JSPROP_GETTER | JSPROP_SHARED; 1.314 + propFlags &= ~JSPROP_ENUMERATE; 1.315 + 1.316 + AutoResolveName arn(ccx, id); 1.317 + if (resolved) 1.318 + *resolved = true; 1.319 + return JS_DefinePropertyById(ccx, obj, id, JSVAL_VOID, 1.320 + JS_DATA_TO_FUNC_PTR(JSPropertyOp, 1.321 + funobj.get()), 1.322 + nullptr, propFlags); 1.323 + } 1.324 + 1.325 + if (resolved) 1.326 + *resolved = false; 1.327 + return true; 1.328 + } 1.329 + 1.330 + if (!member) { 1.331 + if (wrapperToReflectInterfaceNames) { 1.332 + XPCWrappedNativeTearOff* to = 1.333 + wrapperToReflectInterfaceNames->FindTearOff(iface, true); 1.334 + 1.335 + if (!to) 1.336 + return false; 1.337 + RootedObject jso(ccx, to->GetJSObject()); 1.338 + if (!jso) 1.339 + return false; 1.340 + 1.341 + AutoResolveName arn(ccx, id); 1.342 + if (resolved) 1.343 + *resolved = true; 1.344 + return JS_DefinePropertyById(ccx, obj, id, OBJECT_TO_JSVAL(jso), 1.345 + nullptr, nullptr, 1.346 + propFlags & ~JSPROP_ENUMERATE); 1.347 + } 1.348 + if (resolved) 1.349 + *resolved = false; 1.350 + return true; 1.351 + } 1.352 + 1.353 + if (member->IsConstant()) { 1.354 + RootedValue val(ccx); 1.355 + AutoResolveName arn(ccx, id); 1.356 + if (resolved) 1.357 + *resolved = true; 1.358 + return member->GetConstantValue(ccx, iface, val.address()) && 1.359 + JS_DefinePropertyById(ccx, obj, id, val, nullptr, nullptr, 1.360 + propFlags); 1.361 + } 1.362 + 1.363 + if (id == rt->GetStringID(XPCJSRuntime::IDX_TO_STRING) || 1.364 + id == rt->GetStringID(XPCJSRuntime::IDX_TO_SOURCE) || 1.365 + (scriptableInfo && 1.366 + scriptableInfo->GetFlags().DontEnumQueryInterface() && 1.367 + id == rt->GetStringID(XPCJSRuntime::IDX_QUERY_INTERFACE))) 1.368 + propFlags &= ~JSPROP_ENUMERATE; 1.369 + 1.370 + RootedValue funval(ccx); 1.371 + if (!member->NewFunctionObject(ccx, iface, obj, funval.address())) 1.372 + return false; 1.373 + 1.374 + if (member->IsMethod()) { 1.375 + AutoResolveName arn(ccx, id); 1.376 + if (resolved) 1.377 + *resolved = true; 1.378 + return JS_DefinePropertyById(ccx, obj, id, funval, nullptr, nullptr, 1.379 + propFlags); 1.380 + } 1.381 + 1.382 + // else... 1.383 + 1.384 + MOZ_ASSERT(member->IsAttribute(), "way broken!"); 1.385 + 1.386 + propFlags |= JSPROP_GETTER | JSPROP_SHARED; 1.387 + JSObject* funobj = JSVAL_TO_OBJECT(funval); 1.388 + JSPropertyOp getter = JS_DATA_TO_FUNC_PTR(JSPropertyOp, funobj); 1.389 + JSStrictPropertyOp setter; 1.390 + if (member->IsWritableAttribute()) { 1.391 + propFlags |= JSPROP_SETTER; 1.392 + propFlags &= ~JSPROP_READONLY; 1.393 + setter = JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, funobj); 1.394 + } else { 1.395 + setter = js_GetterOnlyPropertyStub; 1.396 + } 1.397 + 1.398 + AutoResolveName arn(ccx, id); 1.399 + if (resolved) 1.400 + *resolved = true; 1.401 + 1.402 + return JS_DefinePropertyById(ccx, obj, id, JSVAL_VOID, getter, setter, 1.403 + propFlags); 1.404 +} 1.405 + 1.406 +/***************************************************************************/ 1.407 +/***************************************************************************/ 1.408 + 1.409 +static bool 1.410 +XPC_WN_OnlyIWrite_AddPropertyStub(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp) 1.411 +{ 1.412 + XPCCallContext ccx(JS_CALLER, cx, obj, NullPtr(), id); 1.413 + XPCWrappedNative* wrapper = ccx.GetWrapper(); 1.414 + THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); 1.415 + 1.416 + // Allow only XPConnect to add/set the property 1.417 + if (ccx.GetResolveName() == id) 1.418 + return true; 1.419 + 1.420 + return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx); 1.421 +} 1.422 + 1.423 +static bool 1.424 +XPC_WN_OnlyIWrite_SetPropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool strict, 1.425 + MutableHandleValue vp) 1.426 +{ 1.427 + return XPC_WN_OnlyIWrite_AddPropertyStub(cx, obj, id, vp); 1.428 +} 1.429 + 1.430 +static bool 1.431 +XPC_WN_CannotModifyPropertyStub(JSContext *cx, HandleObject obj, HandleId id, 1.432 + MutableHandleValue vp) 1.433 +{ 1.434 + return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx); 1.435 +} 1.436 + 1.437 +static bool 1.438 +XPC_WN_CantDeletePropertyStub(JSContext *cx, HandleObject obj, HandleId id, 1.439 + bool *succeeded) 1.440 +{ 1.441 + return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx); 1.442 +} 1.443 + 1.444 +static bool 1.445 +XPC_WN_CannotModifyStrictPropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool strict, 1.446 + MutableHandleValue vp) 1.447 +{ 1.448 + return XPC_WN_CannotModifyPropertyStub(cx, obj, id, vp); 1.449 +} 1.450 + 1.451 +static bool 1.452 +XPC_WN_Shared_Convert(JSContext *cx, HandleObject obj, JSType type, MutableHandleValue vp) 1.453 +{ 1.454 + if (type == JSTYPE_OBJECT) { 1.455 + vp.set(OBJECT_TO_JSVAL(obj)); 1.456 + return true; 1.457 + } 1.458 + 1.459 + XPCCallContext ccx(JS_CALLER, cx, obj); 1.460 + XPCWrappedNative* wrapper = ccx.GetWrapper(); 1.461 + THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); 1.462 + 1.463 + switch (type) { 1.464 + case JSTYPE_FUNCTION: 1.465 + { 1.466 + if (!ccx.GetTearOff()) { 1.467 + XPCNativeScriptableInfo* si = wrapper->GetScriptableInfo(); 1.468 + if (si && (si->GetFlags().WantCall() || 1.469 + si->GetFlags().WantConstruct())) { 1.470 + vp.set(OBJECT_TO_JSVAL(obj)); 1.471 + return true; 1.472 + } 1.473 + } 1.474 + } 1.475 + return Throw(NS_ERROR_XPC_CANT_CONVERT_WN_TO_FUN, cx); 1.476 + case JSTYPE_NUMBER: 1.477 + vp.set(JS_GetNaNValue(cx)); 1.478 + return true; 1.479 + case JSTYPE_BOOLEAN: 1.480 + vp.set(JSVAL_TRUE); 1.481 + return true; 1.482 + case JSTYPE_VOID: 1.483 + case JSTYPE_STRING: 1.484 + { 1.485 + ccx.SetName(ccx.GetRuntime()->GetStringID(XPCJSRuntime::IDX_TO_STRING)); 1.486 + ccx.SetArgsAndResultPtr(0, nullptr, vp.address()); 1.487 + 1.488 + XPCNativeMember* member = ccx.GetMember(); 1.489 + if (member && member->IsMethod()) { 1.490 + if (!XPCWrappedNative::CallMethod(ccx)) 1.491 + return false; 1.492 + 1.493 + if (JSVAL_IS_PRIMITIVE(vp)) 1.494 + return true; 1.495 + } 1.496 + 1.497 + // else... 1.498 + return ToStringGuts(ccx); 1.499 + } 1.500 + default: 1.501 + NS_ERROR("bad type in conversion"); 1.502 + return false; 1.503 + } 1.504 + NS_NOTREACHED("huh?"); 1.505 + return false; 1.506 +} 1.507 + 1.508 +static bool 1.509 +XPC_WN_Shared_Enumerate(JSContext *cx, HandleObject obj) 1.510 +{ 1.511 + XPCCallContext ccx(JS_CALLER, cx, obj); 1.512 + XPCWrappedNative* wrapper = ccx.GetWrapper(); 1.513 + THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); 1.514 + 1.515 + // Since we aren't going to enumerate tearoff names and the prototype 1.516 + // handles non-mutated members, we can do this potential short-circuit. 1.517 + if (!wrapper->HasMutatedSet()) 1.518 + return true; 1.519 + 1.520 + XPCNativeSet* set = wrapper->GetSet(); 1.521 + XPCNativeSet* protoSet = wrapper->HasProto() ? 1.522 + wrapper->GetProto()->GetSet() : nullptr; 1.523 + 1.524 + uint16_t interface_count = set->GetInterfaceCount(); 1.525 + XPCNativeInterface** interfaceArray = set->GetInterfaceArray(); 1.526 + for (uint16_t i = 0; i < interface_count; i++) { 1.527 + XPCNativeInterface* iface = interfaceArray[i]; 1.528 + uint16_t member_count = iface->GetMemberCount(); 1.529 + for (uint16_t k = 0; k < member_count; k++) { 1.530 + XPCNativeMember* member = iface->GetMemberAt(k); 1.531 + jsid name = member->GetName(); 1.532 + 1.533 + // Skip if this member is going to come from the proto. 1.534 + uint16_t index; 1.535 + if (protoSet && 1.536 + protoSet->FindMember(name, nullptr, &index) && index == i) 1.537 + continue; 1.538 + if (!xpc_ForcePropertyResolve(cx, obj, name)) 1.539 + return false; 1.540 + } 1.541 + } 1.542 + return true; 1.543 +} 1.544 + 1.545 +/***************************************************************************/ 1.546 + 1.547 +enum WNHelperType { 1.548 + WN_NOHELPER, 1.549 + WN_HELPER 1.550 +}; 1.551 + 1.552 +static void 1.553 +WrappedNativeFinalize(js::FreeOp *fop, JSObject *obj, WNHelperType helperType) 1.554 +{ 1.555 + const js::Class* clazz = js::GetObjectClass(obj); 1.556 + if (clazz->flags & JSCLASS_DOM_GLOBAL) { 1.557 + mozilla::dom::DestroyProtoAndIfaceCache(obj); 1.558 + } 1.559 + nsISupports* p = static_cast<nsISupports*>(xpc_GetJSPrivate(obj)); 1.560 + if (!p) 1.561 + return; 1.562 + 1.563 + XPCWrappedNative* wrapper = static_cast<XPCWrappedNative*>(p); 1.564 + if (helperType == WN_HELPER) 1.565 + wrapper->GetScriptableCallback()->Finalize(wrapper, js::CastToJSFreeOp(fop), obj); 1.566 + wrapper->FlatJSObjectFinalized(); 1.567 +} 1.568 + 1.569 +static void 1.570 +XPC_WN_NoHelper_Finalize(js::FreeOp *fop, JSObject *obj) 1.571 +{ 1.572 + WrappedNativeFinalize(fop, obj, WN_NOHELPER); 1.573 +} 1.574 + 1.575 +/* 1.576 + * General comment about XPConnect tracing: Given a C++ object |wrapper| and its 1.577 + * corresponding JS object |obj|, calling |wrapper->TraceSelf| will ask the JS 1.578 + * engine to mark |obj|. Eventually, this will lead to the trace hook being 1.579 + * called for |obj|. The trace hook should call |wrapper->TraceInside|, which 1.580 + * should mark any JS objects held by |wrapper| as members. 1.581 + */ 1.582 + 1.583 +static void 1.584 +MarkWrappedNative(JSTracer *trc, JSObject *obj) 1.585 +{ 1.586 + const js::Class* clazz = js::GetObjectClass(obj); 1.587 + if (clazz->flags & JSCLASS_DOM_GLOBAL) { 1.588 + mozilla::dom::TraceProtoAndIfaceCache(trc, obj); 1.589 + } 1.590 + MOZ_ASSERT(IS_WN_CLASS(clazz)); 1.591 + 1.592 + XPCWrappedNative *wrapper = XPCWrappedNative::Get(obj); 1.593 + if (wrapper && wrapper->IsValid()) 1.594 + wrapper->TraceInside(trc); 1.595 +} 1.596 + 1.597 +/* static */ void 1.598 +XPCWrappedNative::Trace(JSTracer *trc, JSObject *obj) 1.599 +{ 1.600 + MarkWrappedNative(trc, obj); 1.601 +} 1.602 + 1.603 +static bool 1.604 +XPC_WN_NoHelper_Resolve(JSContext *cx, HandleObject obj, HandleId id) 1.605 +{ 1.606 + XPCCallContext ccx(JS_CALLER, cx, obj, NullPtr(), id); 1.607 + XPCWrappedNative* wrapper = ccx.GetWrapper(); 1.608 + THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); 1.609 + 1.610 + XPCNativeSet* set = ccx.GetSet(); 1.611 + if (!set) 1.612 + return true; 1.613 + 1.614 + // Don't resolve properties that are on our prototype. 1.615 + if (ccx.GetInterface() && !ccx.GetStaticMemberIsLocal()) 1.616 + return true; 1.617 + 1.618 + return DefinePropertyIfFound(ccx, obj, id, 1.619 + set, nullptr, nullptr, wrapper->GetScope(), 1.620 + true, wrapper, wrapper, nullptr, 1.621 + JSPROP_ENUMERATE | 1.622 + JSPROP_READONLY | 1.623 + JSPROP_PERMANENT, nullptr); 1.624 +} 1.625 + 1.626 +static JSObject * 1.627 +XPC_WN_OuterObject(JSContext *cx, HandleObject objArg) 1.628 +{ 1.629 + JSObject *obj = objArg; 1.630 + 1.631 + XPCWrappedNative *wrapper = XPCWrappedNative::Get(obj); 1.632 + if (!wrapper) { 1.633 + Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); 1.634 + 1.635 + return nullptr; 1.636 + } 1.637 + 1.638 + if (!wrapper->IsValid()) { 1.639 + Throw(NS_ERROR_XPC_HAS_BEEN_SHUTDOWN, cx); 1.640 + 1.641 + return nullptr; 1.642 + } 1.643 + 1.644 + XPCNativeScriptableInfo* si = wrapper->GetScriptableInfo(); 1.645 + if (si && si->GetFlags().WantOuterObject()) { 1.646 + RootedObject newThis(cx); 1.647 + nsresult rv = 1.648 + si->GetCallback()->OuterObject(wrapper, cx, obj, newThis.address()); 1.649 + 1.650 + if (NS_FAILED(rv)) { 1.651 + Throw(rv, cx); 1.652 + 1.653 + return nullptr; 1.654 + } 1.655 + 1.656 + obj = newThis; 1.657 + } 1.658 + 1.659 + return obj; 1.660 +} 1.661 + 1.662 +const XPCWrappedNativeJSClass XPC_WN_NoHelper_JSClass = { 1.663 + { // base 1.664 + "XPCWrappedNative_NoHelper", // name; 1.665 + WRAPPER_SLOTS | 1.666 + JSCLASS_PRIVATE_IS_NSISUPPORTS, // flags 1.667 + 1.668 + /* Mandatory non-null function pointer members. */ 1.669 + XPC_WN_OnlyIWrite_AddPropertyStub, // addProperty 1.670 + XPC_WN_CantDeletePropertyStub, // delProperty 1.671 + JS_PropertyStub, // getProperty 1.672 + XPC_WN_OnlyIWrite_SetPropertyStub, // setProperty 1.673 + 1.674 + XPC_WN_Shared_Enumerate, // enumerate 1.675 + XPC_WN_NoHelper_Resolve, // resolve 1.676 + XPC_WN_Shared_Convert, // convert 1.677 + XPC_WN_NoHelper_Finalize, // finalize 1.678 + 1.679 + /* Optionally non-null members start here. */ 1.680 + nullptr, // call 1.681 + nullptr, // construct 1.682 + nullptr, // hasInstance 1.683 + XPCWrappedNative::Trace, // trace 1.684 + JS_NULL_CLASS_SPEC, 1.685 + 1.686 + // ClassExtension 1.687 + { 1.688 + nullptr, // outerObject 1.689 + nullptr, // innerObject 1.690 + nullptr, // iteratorObject 1.691 + true, // isWrappedNative 1.692 + }, 1.693 + 1.694 + // ObjectOps 1.695 + { 1.696 + nullptr, // lookupGeneric 1.697 + nullptr, // lookupProperty 1.698 + nullptr, // lookupElement 1.699 + nullptr, // defineGeneric 1.700 + nullptr, // defineProperty 1.701 + nullptr, // defineElement 1.702 + nullptr, // getGeneric 1.703 + nullptr, // getProperty 1.704 + nullptr, // getElement 1.705 + nullptr, // setGeneric 1.706 + nullptr, // setProperty 1.707 + nullptr, // setElement 1.708 + nullptr, // getGenericAttributes 1.709 + nullptr, // setGenericAttributes 1.710 + nullptr, // deleteProperty 1.711 + nullptr, // deleteElement 1.712 + nullptr, nullptr, // watch/unwatch 1.713 + nullptr, // slice 1.714 + XPC_WN_JSOp_Enumerate, 1.715 + XPC_WN_JSOp_ThisObject, 1.716 + } 1.717 + }, 1.718 + 0 // interfacesBitmap 1.719 +}; 1.720 + 1.721 + 1.722 +/***************************************************************************/ 1.723 + 1.724 +static bool 1.725 +XPC_WN_MaybeResolvingPropertyStub(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp) 1.726 +{ 1.727 + XPCCallContext ccx(JS_CALLER, cx, obj); 1.728 + XPCWrappedNative* wrapper = ccx.GetWrapper(); 1.729 + THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); 1.730 + 1.731 + if (ccx.GetResolvingWrapper() == wrapper) 1.732 + return true; 1.733 + return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx); 1.734 +} 1.735 + 1.736 +static bool 1.737 +XPC_WN_MaybeResolvingStrictPropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool strict, 1.738 + MutableHandleValue vp) 1.739 +{ 1.740 + return XPC_WN_MaybeResolvingPropertyStub(cx, obj, id, vp); 1.741 +} 1.742 + 1.743 +static bool 1.744 +XPC_WN_MaybeResolvingDeletePropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded) 1.745 +{ 1.746 + XPCCallContext ccx(JS_CALLER, cx, obj); 1.747 + XPCWrappedNative* wrapper = ccx.GetWrapper(); 1.748 + THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); 1.749 + 1.750 + if (ccx.GetResolvingWrapper() == wrapper) { 1.751 + *succeeded = true; 1.752 + return true; 1.753 + } 1.754 + return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx); 1.755 +} 1.756 + 1.757 +// macro fun! 1.758 +#define PRE_HELPER_STUB \ 1.759 + JSObject *unwrapped = js::CheckedUnwrap(obj, false); \ 1.760 + if (!unwrapped) { \ 1.761 + JS_ReportError(cx, "Permission denied to operate on object."); \ 1.762 + return false; \ 1.763 + } \ 1.764 + if (!IS_WN_REFLECTOR(unwrapped)) { \ 1.765 + return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); \ 1.766 + } \ 1.767 + XPCWrappedNative *wrapper = XPCWrappedNative::Get(unwrapped); \ 1.768 + THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); \ 1.769 + bool retval = true; \ 1.770 + nsresult rv = wrapper->GetScriptableCallback()-> 1.771 + 1.772 +#define POST_HELPER_STUB \ 1.773 + if (NS_FAILED(rv)) \ 1.774 + return Throw(rv, cx); \ 1.775 + return retval; 1.776 + 1.777 +static bool 1.778 +XPC_WN_Helper_AddProperty(JSContext *cx, HandleObject obj, HandleId id, 1.779 + MutableHandleValue vp) 1.780 +{ 1.781 + PRE_HELPER_STUB 1.782 + AddProperty(wrapper, cx, obj, id, vp.address(), &retval); 1.783 + POST_HELPER_STUB 1.784 +} 1.785 + 1.786 +static bool 1.787 +XPC_WN_Helper_DelProperty(JSContext *cx, HandleObject obj, HandleId id, 1.788 + bool *succeeded) 1.789 +{ 1.790 + *succeeded = true; 1.791 + PRE_HELPER_STUB 1.792 + DelProperty(wrapper, cx, obj, id, &retval); 1.793 + POST_HELPER_STUB 1.794 +} 1.795 + 1.796 +bool 1.797 +XPC_WN_Helper_GetProperty(JSContext *cx, HandleObject obj, HandleId id, 1.798 + MutableHandleValue vp) 1.799 +{ 1.800 + PRE_HELPER_STUB 1.801 + GetProperty(wrapper, cx, obj, id, vp.address(), &retval); 1.802 + POST_HELPER_STUB 1.803 +} 1.804 + 1.805 +bool 1.806 +XPC_WN_Helper_SetProperty(JSContext *cx, HandleObject obj, HandleId id, bool strict, 1.807 + MutableHandleValue vp) 1.808 +{ 1.809 + PRE_HELPER_STUB 1.810 + SetProperty(wrapper, cx, obj, id, vp.address(), &retval); 1.811 + POST_HELPER_STUB 1.812 +} 1.813 + 1.814 +static bool 1.815 +XPC_WN_Helper_Convert(JSContext *cx, HandleObject obj, JSType type, MutableHandleValue vp) 1.816 +{ 1.817 + PRE_HELPER_STUB 1.818 + Convert(wrapper, cx, obj, type, vp.address(), &retval); 1.819 + POST_HELPER_STUB 1.820 +} 1.821 + 1.822 +static bool 1.823 +XPC_WN_Helper_Call(JSContext *cx, unsigned argc, jsval *vp) 1.824 +{ 1.825 + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); 1.826 + // N.B. we want obj to be the callee, not JS_THIS(cx, vp) 1.827 + RootedObject obj(cx, &args.callee()); 1.828 + 1.829 + XPCCallContext ccx(JS_CALLER, cx, obj, NullPtr(), JSID_VOIDHANDLE, args.length(), 1.830 + args.array(), args.rval().address()); 1.831 + if (!ccx.IsValid()) 1.832 + return false; 1.833 + 1.834 + MOZ_ASSERT(obj == ccx.GetFlattenedJSObject()); 1.835 + 1.836 + PRE_HELPER_STUB 1.837 + Call(wrapper, cx, obj, args, &retval); 1.838 + POST_HELPER_STUB 1.839 +} 1.840 + 1.841 +static bool 1.842 +XPC_WN_Helper_Construct(JSContext *cx, unsigned argc, jsval *vp) 1.843 +{ 1.844 + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); 1.845 + RootedObject obj(cx, &args.callee()); 1.846 + if (!obj) 1.847 + return false; 1.848 + 1.849 + XPCCallContext ccx(JS_CALLER, cx, obj, NullPtr(), JSID_VOIDHANDLE, args.length(), 1.850 + args.array(), args.rval().address()); 1.851 + if (!ccx.IsValid()) 1.852 + return false; 1.853 + 1.854 + MOZ_ASSERT(obj == ccx.GetFlattenedJSObject()); 1.855 + 1.856 + PRE_HELPER_STUB 1.857 + Construct(wrapper, cx, obj, args, &retval); 1.858 + POST_HELPER_STUB 1.859 +} 1.860 + 1.861 +static bool 1.862 +XPC_WN_Helper_HasInstance(JSContext *cx, HandleObject obj, MutableHandleValue valp, bool *bp) 1.863 +{ 1.864 + bool retval2; 1.865 + PRE_HELPER_STUB 1.866 + HasInstance(wrapper, cx, obj, valp, &retval2, &retval); 1.867 + *bp = retval2; 1.868 + POST_HELPER_STUB 1.869 +} 1.870 + 1.871 +static void 1.872 +XPC_WN_Helper_Finalize(js::FreeOp *fop, JSObject *obj) 1.873 +{ 1.874 + WrappedNativeFinalize(fop, obj, WN_HELPER); 1.875 +} 1.876 + 1.877 +static bool 1.878 +XPC_WN_Helper_NewResolve(JSContext *cx, HandleObject obj, HandleId id, 1.879 + MutableHandleObject objp) 1.880 +{ 1.881 + nsresult rv = NS_OK; 1.882 + bool retval = true; 1.883 + RootedObject obj2FromScriptable(cx); 1.884 + XPCCallContext ccx(JS_CALLER, cx, obj); 1.885 + XPCWrappedNative* wrapper = ccx.GetWrapper(); 1.886 + THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); 1.887 + 1.888 + RootedId old(cx, ccx.SetResolveName(id)); 1.889 + 1.890 + XPCNativeScriptableInfo* si = wrapper->GetScriptableInfo(); 1.891 + if (si && si->GetFlags().WantNewResolve()) { 1.892 + XPCWrappedNative* oldResolvingWrapper; 1.893 + bool allowPropMods = si->GetFlags().AllowPropModsDuringResolve(); 1.894 + 1.895 + if (allowPropMods) 1.896 + oldResolvingWrapper = ccx.SetResolvingWrapper(wrapper); 1.897 + 1.898 + rv = si->GetCallback()->NewResolve(wrapper, cx, obj, id, 1.899 + obj2FromScriptable.address(), &retval); 1.900 + 1.901 + if (allowPropMods) 1.902 + (void)ccx.SetResolvingWrapper(oldResolvingWrapper); 1.903 + } 1.904 + 1.905 + old = ccx.SetResolveName(old); 1.906 + MOZ_ASSERT(old == id, "bad nest"); 1.907 + 1.908 + if (NS_FAILED(rv)) { 1.909 + return Throw(rv, cx); 1.910 + } 1.911 + 1.912 + if (obj2FromScriptable) { 1.913 + objp.set(obj2FromScriptable); 1.914 + } else if (wrapper->HasMutatedSet()) { 1.915 + // We are here if scriptable did not resolve this property and 1.916 + // it *might* be in the instance set but not the proto set. 1.917 + 1.918 + XPCNativeSet* set = wrapper->GetSet(); 1.919 + XPCNativeSet* protoSet = wrapper->HasProto() ? 1.920 + wrapper->GetProto()->GetSet() : nullptr; 1.921 + XPCNativeMember* member; 1.922 + XPCNativeInterface* iface; 1.923 + bool IsLocal; 1.924 + 1.925 + if (set->FindMember(id, &member, &iface, protoSet, &IsLocal) && 1.926 + IsLocal) { 1.927 + XPCWrappedNative* oldResolvingWrapper; 1.928 + 1.929 + XPCNativeScriptableFlags siFlags(0); 1.930 + if (si) 1.931 + siFlags = si->GetFlags(); 1.932 + 1.933 + unsigned enumFlag = 1.934 + siFlags.DontEnumStaticProps() ? 0 : JSPROP_ENUMERATE; 1.935 + 1.936 + XPCWrappedNative* wrapperForInterfaceNames = 1.937 + siFlags.DontReflectInterfaceNames() ? nullptr : wrapper; 1.938 + 1.939 + bool resolved; 1.940 + oldResolvingWrapper = ccx.SetResolvingWrapper(wrapper); 1.941 + retval = DefinePropertyIfFound(ccx, obj, id, 1.942 + set, iface, member, 1.943 + wrapper->GetScope(), 1.944 + false, 1.945 + wrapperForInterfaceNames, 1.946 + nullptr, si, 1.947 + enumFlag, &resolved); 1.948 + (void)ccx.SetResolvingWrapper(oldResolvingWrapper); 1.949 + if (retval && resolved) 1.950 + objp.set(obj); 1.951 + } 1.952 + } 1.953 + 1.954 + return retval; 1.955 +} 1.956 + 1.957 +/***************************************************************************/ 1.958 + 1.959 +/* 1.960 + Here are the enumerator cases: 1.961 + 1.962 + set jsclass enumerate to stub (unless noted otherwise) 1.963 + 1.964 + if ( helper wants new enumerate ) 1.965 + if ( DONT_ENUM_STATICS ) 1.966 + forward to scriptable enumerate 1.967 + else 1.968 + if ( set not mutated ) 1.969 + forward to scriptable enumerate 1.970 + else 1.971 + call shared enumerate 1.972 + forward to scriptable enumerate 1.973 + else if ( helper wants old enumerate ) 1.974 + use this JSOp 1.975 + if ( DONT_ENUM_STATICS ) 1.976 + call scriptable enumerate 1.977 + call stub 1.978 + else 1.979 + if ( set not mutated ) 1.980 + call scriptable enumerate 1.981 + call stub 1.982 + else 1.983 + call shared enumerate 1.984 + call scriptable enumerate 1.985 + call stub 1.986 + 1.987 + else //... if ( helper wants NO enumerate ) 1.988 + if ( DONT_ENUM_STATICS ) 1.989 + use enumerate stub - don't use this JSOp thing at all 1.990 + else 1.991 + do shared enumerate - don't use this JSOp thing at all 1.992 +*/ 1.993 + 1.994 +bool 1.995 +XPC_WN_JSOp_Enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op, 1.996 + MutableHandleValue statep, MutableHandleId idp) 1.997 +{ 1.998 + const js::Class *clazz = js::GetObjectClass(obj); 1.999 + if (!IS_WN_CLASS(clazz) || clazz == &XPC_WN_NoHelper_JSClass.base) { 1.1000 + // obj must be a prototype object or a wrapper w/o a 1.1001 + // helper. Short circuit this call to the default 1.1002 + // implementation. 1.1003 + 1.1004 + return JS_EnumerateState(cx, obj, enum_op, statep, idp); 1.1005 + } 1.1006 + 1.1007 + XPCCallContext ccx(JS_CALLER, cx, obj); 1.1008 + XPCWrappedNative* wrapper = ccx.GetWrapper(); 1.1009 + THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); 1.1010 + 1.1011 + XPCNativeScriptableInfo* si = wrapper->GetScriptableInfo(); 1.1012 + if (!si) 1.1013 + return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); 1.1014 + 1.1015 + bool retval = true; 1.1016 + nsresult rv; 1.1017 + 1.1018 + if (si->GetFlags().WantNewEnumerate()) { 1.1019 + if (((enum_op == JSENUMERATE_INIT && 1.1020 + !si->GetFlags().DontEnumStaticProps()) || 1.1021 + enum_op == JSENUMERATE_INIT_ALL) && 1.1022 + wrapper->HasMutatedSet() && 1.1023 + !XPC_WN_Shared_Enumerate(cx, obj)) { 1.1024 + statep.set(JSVAL_NULL); 1.1025 + return false; 1.1026 + } 1.1027 + 1.1028 + // XXX Might we really need to wrap this call and *also* call 1.1029 + // js_ObjectOps.enumerate ??? 1.1030 + 1.1031 + rv = si->GetCallback()-> 1.1032 + NewEnumerate(wrapper, cx, obj, enum_op, statep.address(), idp.address(), &retval); 1.1033 + 1.1034 + if ((enum_op == JSENUMERATE_INIT || enum_op == JSENUMERATE_INIT_ALL) && 1.1035 + (NS_FAILED(rv) || !retval)) { 1.1036 + statep.set(JSVAL_NULL); 1.1037 + } 1.1038 + 1.1039 + if (NS_FAILED(rv)) 1.1040 + return Throw(rv, cx); 1.1041 + return retval; 1.1042 + } 1.1043 + 1.1044 + if (si->GetFlags().WantEnumerate()) { 1.1045 + if (enum_op == JSENUMERATE_INIT || enum_op == JSENUMERATE_INIT_ALL) { 1.1046 + if ((enum_op == JSENUMERATE_INIT_ALL || 1.1047 + !si->GetFlags().DontEnumStaticProps()) && 1.1048 + wrapper->HasMutatedSet() && 1.1049 + !XPC_WN_Shared_Enumerate(cx, obj)) { 1.1050 + statep.set(JSVAL_NULL); 1.1051 + return false; 1.1052 + } 1.1053 + rv = si->GetCallback()-> 1.1054 + Enumerate(wrapper, cx, obj, &retval); 1.1055 + 1.1056 + if (NS_FAILED(rv) || !retval) 1.1057 + statep.set(JSVAL_NULL); 1.1058 + 1.1059 + if (NS_FAILED(rv)) 1.1060 + return Throw(rv, cx); 1.1061 + if (!retval) 1.1062 + return false; 1.1063 + // Then fall through and call the default implementation... 1.1064 + } 1.1065 + } 1.1066 + 1.1067 + // else call js_ObjectOps.enumerate... 1.1068 + 1.1069 + return JS_EnumerateState(cx, obj, enum_op, statep, idp); 1.1070 +} 1.1071 + 1.1072 +JSObject* 1.1073 +XPC_WN_JSOp_ThisObject(JSContext *cx, HandleObject obj) 1.1074 +{ 1.1075 + return JS_ObjectToOuterObject(cx, obj); 1.1076 +} 1.1077 + 1.1078 +/***************************************************************************/ 1.1079 + 1.1080 +// static 1.1081 +XPCNativeScriptableInfo* 1.1082 +XPCNativeScriptableInfo::Construct(const XPCNativeScriptableCreateInfo* sci) 1.1083 +{ 1.1084 + MOZ_ASSERT(sci, "bad param"); 1.1085 + MOZ_ASSERT(sci->GetCallback(), "bad param"); 1.1086 + 1.1087 + XPCNativeScriptableInfo* newObj = 1.1088 + new XPCNativeScriptableInfo(sci->GetCallback()); 1.1089 + if (!newObj) 1.1090 + return nullptr; 1.1091 + 1.1092 + char* name = nullptr; 1.1093 + if (NS_FAILED(sci->GetCallback()->GetClassName(&name)) || !name) { 1.1094 + delete newObj; 1.1095 + return nullptr; 1.1096 + } 1.1097 + 1.1098 + bool success; 1.1099 + 1.1100 + XPCJSRuntime* rt = XPCJSRuntime::Get(); 1.1101 + XPCNativeScriptableSharedMap* map = rt->GetNativeScriptableSharedMap(); 1.1102 + success = map->GetNewOrUsed(sci->GetFlags(), name, 1.1103 + sci->GetInterfacesBitmap(), newObj); 1.1104 + 1.1105 + if (!success) { 1.1106 + delete newObj; 1.1107 + return nullptr; 1.1108 + } 1.1109 + 1.1110 + return newObj; 1.1111 +} 1.1112 + 1.1113 +void 1.1114 +XPCNativeScriptableShared::PopulateJSClass() 1.1115 +{ 1.1116 + MOZ_ASSERT(mJSClass.base.name, "bad state!"); 1.1117 + 1.1118 + mJSClass.base.flags = WRAPPER_SLOTS | 1.1119 + JSCLASS_PRIVATE_IS_NSISUPPORTS | 1.1120 + JSCLASS_NEW_RESOLVE; 1.1121 + 1.1122 + if (mFlags.IsGlobalObject()) 1.1123 + mJSClass.base.flags |= XPCONNECT_GLOBAL_FLAGS; 1.1124 + 1.1125 + JSPropertyOp addProperty; 1.1126 + if (mFlags.WantAddProperty()) 1.1127 + addProperty = XPC_WN_Helper_AddProperty; 1.1128 + else if (mFlags.UseJSStubForAddProperty()) 1.1129 + addProperty = JS_PropertyStub; 1.1130 + else if (mFlags.AllowPropModsDuringResolve()) 1.1131 + addProperty = XPC_WN_MaybeResolvingPropertyStub; 1.1132 + else 1.1133 + addProperty = XPC_WN_CannotModifyPropertyStub; 1.1134 + mJSClass.base.addProperty = addProperty; 1.1135 + 1.1136 + JSDeletePropertyOp delProperty; 1.1137 + if (mFlags.WantDelProperty()) 1.1138 + delProperty = XPC_WN_Helper_DelProperty; 1.1139 + else if (mFlags.UseJSStubForDelProperty()) 1.1140 + delProperty = JS_DeletePropertyStub; 1.1141 + else if (mFlags.AllowPropModsDuringResolve()) 1.1142 + delProperty = XPC_WN_MaybeResolvingDeletePropertyStub; 1.1143 + else 1.1144 + delProperty = XPC_WN_CantDeletePropertyStub; 1.1145 + mJSClass.base.delProperty = delProperty; 1.1146 + 1.1147 + if (mFlags.WantGetProperty()) 1.1148 + mJSClass.base.getProperty = XPC_WN_Helper_GetProperty; 1.1149 + else 1.1150 + mJSClass.base.getProperty = JS_PropertyStub; 1.1151 + 1.1152 + JSStrictPropertyOp setProperty; 1.1153 + if (mFlags.WantSetProperty()) 1.1154 + setProperty = XPC_WN_Helper_SetProperty; 1.1155 + else if (mFlags.UseJSStubForSetProperty()) 1.1156 + setProperty = JS_StrictPropertyStub; 1.1157 + else if (mFlags.AllowPropModsDuringResolve()) 1.1158 + setProperty = XPC_WN_MaybeResolvingStrictPropertyStub; 1.1159 + else 1.1160 + setProperty = XPC_WN_CannotModifyStrictPropertyStub; 1.1161 + mJSClass.base.setProperty = setProperty; 1.1162 + 1.1163 + // We figure out most of the enumerate strategy at call time. 1.1164 + 1.1165 + if (mFlags.WantNewEnumerate() || mFlags.WantEnumerate() || 1.1166 + mFlags.DontEnumStaticProps()) 1.1167 + mJSClass.base.enumerate = JS_EnumerateStub; 1.1168 + else 1.1169 + mJSClass.base.enumerate = XPC_WN_Shared_Enumerate; 1.1170 + 1.1171 + // We have to figure out resolve strategy at call time 1.1172 + mJSClass.base.resolve = (JSResolveOp) XPC_WN_Helper_NewResolve; 1.1173 + 1.1174 + // We need to respect content-defined toString() hooks on Window objects. 1.1175 + // In particular, js::DefaultValue checks for a convert stub, and the one 1.1176 + // we would install below ignores anything implemented in JS. 1.1177 + // 1.1178 + // We've always had this behavior for most XPCWrappedNative-implemented 1.1179 + // objects. However, Window was special, because the outer-window proxy 1.1180 + // had a null convert hook, which means that we'd end up with the default 1.1181 + // JS-engine behavior (which respects toString() overrides). We've fixed 1.1182 + // the convert hook on the outer-window proxy to invoke the defaultValue 1.1183 + // hook on the proxy, which in this case invokes js::DefaultValue on the 1.1184 + // target. So now we need to special-case this for Window to maintain 1.1185 + // consistent behavior. This can go away once Window is on WebIDL bindings. 1.1186 + // 1.1187 + // Note that WantOuterObject() is true if and only if this is a Window object. 1.1188 + if (mFlags.WantConvert()) 1.1189 + mJSClass.base.convert = XPC_WN_Helper_Convert; 1.1190 + else if (mFlags.WantOuterObject()) 1.1191 + mJSClass.base.convert = JS_ConvertStub; 1.1192 + else 1.1193 + mJSClass.base.convert = XPC_WN_Shared_Convert; 1.1194 + 1.1195 + if (mFlags.WantFinalize()) 1.1196 + mJSClass.base.finalize = XPC_WN_Helper_Finalize; 1.1197 + else 1.1198 + mJSClass.base.finalize = XPC_WN_NoHelper_Finalize; 1.1199 + 1.1200 + js::ObjectOps *ops = &mJSClass.base.ops; 1.1201 + ops->enumerate = XPC_WN_JSOp_Enumerate; 1.1202 + ops->thisObject = XPC_WN_JSOp_ThisObject; 1.1203 + 1.1204 + 1.1205 + if (mFlags.WantCall()) 1.1206 + mJSClass.base.call = XPC_WN_Helper_Call; 1.1207 + if (mFlags.WantConstruct()) 1.1208 + mJSClass.base.construct = XPC_WN_Helper_Construct; 1.1209 + 1.1210 + if (mFlags.WantHasInstance()) 1.1211 + mJSClass.base.hasInstance = XPC_WN_Helper_HasInstance; 1.1212 + 1.1213 + if (mFlags.IsGlobalObject()) 1.1214 + mJSClass.base.trace = JS_GlobalObjectTraceHook; 1.1215 + else 1.1216 + mJSClass.base.trace = XPCWrappedNative::Trace; 1.1217 + 1.1218 + if (mFlags.WantOuterObject()) 1.1219 + mJSClass.base.ext.outerObject = XPC_WN_OuterObject; 1.1220 + 1.1221 + mJSClass.base.ext.isWrappedNative = true; 1.1222 +} 1.1223 + 1.1224 +/***************************************************************************/ 1.1225 +/***************************************************************************/ 1.1226 + 1.1227 +// Compatibility hack. 1.1228 +// 1.1229 +// XPConnect used to do all sorts of funny tricks to find the "correct" 1.1230 +// |this| object for a given method (often to the detriment of proper 1.1231 +// call/apply). When these tricks were removed, a fair amount of chrome 1.1232 +// code broke, because it was relying on being able to grab methods off 1.1233 +// some XPCOM object (like the nsITelemetry service) and invoke them without 1.1234 +// a proper |this|. So, if it's quite clear that we're in this situation and 1.1235 +// about to use a |this| argument that just won't work, fix things up. 1.1236 +// 1.1237 +// This hack is only useful for getters/setters if someone sets an XPCOM object 1.1238 +// as the prototype for a vanilla JS object and expects the XPCOM attributes to 1.1239 +// work on the derived object, which we really don't want to support. But we 1.1240 +// handle it anyway, for now, to minimize regression risk on an already-risky 1.1241 +// landing. 1.1242 +// 1.1243 +// This hack is mainly useful for the NoHelper JSClass. We also fix up 1.1244 +// Components.utils because it implements nsIXPCScriptable (giving it a custom 1.1245 +// JSClass) but not nsIClassInfo (which would put the methods on a prototype). 1.1246 + 1.1247 +#define IS_NOHELPER_CLASS(clasp) (clasp == &XPC_WN_NoHelper_JSClass.base) 1.1248 +#define IS_CU_CLASS(clasp) (clasp->name[0] == 'n' && !strcmp(clasp->name, "nsXPCComponents_Utils")) 1.1249 + 1.1250 +MOZ_ALWAYS_INLINE JSObject* 1.1251 +FixUpThisIfBroken(JSObject *obj, JSObject *funobj) 1.1252 +{ 1.1253 + if (funobj) { 1.1254 + const js::Class *parentClass = js::GetObjectClass(js::GetObjectParent(funobj)); 1.1255 + if (MOZ_UNLIKELY((IS_NOHELPER_CLASS(parentClass) || IS_CU_CLASS(parentClass)) && 1.1256 + (js::GetObjectClass(obj) != parentClass))) 1.1257 + { 1.1258 + return js::GetObjectParent(funobj); 1.1259 + } 1.1260 + } 1.1261 + return obj; 1.1262 +} 1.1263 + 1.1264 +bool 1.1265 +XPC_WN_CallMethod(JSContext *cx, unsigned argc, jsval *vp) 1.1266 +{ 1.1267 + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); 1.1268 + MOZ_ASSERT(JS_TypeOfValue(cx, args.calleev()) == JSTYPE_FUNCTION, "bad function"); 1.1269 + RootedObject funobj(cx, &args.callee()); 1.1270 + 1.1271 + RootedObject obj(cx, JS_THIS_OBJECT(cx, vp)); 1.1272 + if (!obj) 1.1273 + return false; 1.1274 + 1.1275 + obj = FixUpThisIfBroken(obj, funobj); 1.1276 + XPCCallContext ccx(JS_CALLER, cx, obj, funobj, JSID_VOIDHANDLE, args.length(), 1.1277 + args.array(), vp); 1.1278 + XPCWrappedNative* wrapper = ccx.GetWrapper(); 1.1279 + THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); 1.1280 + 1.1281 + XPCNativeInterface* iface; 1.1282 + XPCNativeMember* member; 1.1283 + 1.1284 + if (!XPCNativeMember::GetCallInfo(funobj, &iface, &member)) 1.1285 + return Throw(NS_ERROR_XPC_CANT_GET_METHOD_INFO, cx); 1.1286 + ccx.SetCallInfo(iface, member, false); 1.1287 + return XPCWrappedNative::CallMethod(ccx); 1.1288 +} 1.1289 + 1.1290 +bool 1.1291 +XPC_WN_GetterSetter(JSContext *cx, unsigned argc, jsval *vp) 1.1292 +{ 1.1293 + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); 1.1294 + MOZ_ASSERT(JS_TypeOfValue(cx, args.calleev()) == JSTYPE_FUNCTION, "bad function"); 1.1295 + RootedObject funobj(cx, &args.callee()); 1.1296 + 1.1297 + RootedObject obj(cx, JS_THIS_OBJECT(cx, vp)); 1.1298 + if (!obj) 1.1299 + return false; 1.1300 + 1.1301 + obj = FixUpThisIfBroken(obj, funobj); 1.1302 + XPCCallContext ccx(JS_CALLER, cx, obj, funobj, JSID_VOIDHANDLE, args.length(), 1.1303 + args.array(), vp); 1.1304 + XPCWrappedNative* wrapper = ccx.GetWrapper(); 1.1305 + THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); 1.1306 + 1.1307 + XPCNativeInterface* iface; 1.1308 + XPCNativeMember* member; 1.1309 + 1.1310 + if (!XPCNativeMember::GetCallInfo(funobj, &iface, &member)) 1.1311 + return Throw(NS_ERROR_XPC_CANT_GET_METHOD_INFO, cx); 1.1312 + 1.1313 + if (args.length() != 0 && member->IsWritableAttribute()) { 1.1314 + ccx.SetCallInfo(iface, member, true); 1.1315 + bool retval = XPCWrappedNative::SetAttribute(ccx); 1.1316 + if (retval) 1.1317 + args.rval().set(args[0]); 1.1318 + return retval; 1.1319 + } 1.1320 + // else... 1.1321 + 1.1322 + ccx.SetCallInfo(iface, member, false); 1.1323 + return XPCWrappedNative::GetAttribute(ccx); 1.1324 +} 1.1325 + 1.1326 +/***************************************************************************/ 1.1327 + 1.1328 +static bool 1.1329 +XPC_WN_Shared_Proto_Enumerate(JSContext *cx, HandleObject obj) 1.1330 +{ 1.1331 + MOZ_ASSERT(js::GetObjectClass(obj) == &XPC_WN_ModsAllowed_WithCall_Proto_JSClass || 1.1332 + js::GetObjectClass(obj) == &XPC_WN_ModsAllowed_NoCall_Proto_JSClass || 1.1333 + js::GetObjectClass(obj) == &XPC_WN_NoMods_WithCall_Proto_JSClass || 1.1334 + js::GetObjectClass(obj) == &XPC_WN_NoMods_NoCall_Proto_JSClass, 1.1335 + "bad proto"); 1.1336 + XPCWrappedNativeProto* self = 1.1337 + (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj); 1.1338 + if (!self) 1.1339 + return false; 1.1340 + 1.1341 + if (self->GetScriptableInfo() && 1.1342 + self->GetScriptableInfo()->GetFlags().DontEnumStaticProps()) 1.1343 + return true; 1.1344 + 1.1345 + XPCNativeSet* set = self->GetSet(); 1.1346 + if (!set) 1.1347 + return false; 1.1348 + 1.1349 + XPCCallContext ccx(JS_CALLER, cx); 1.1350 + if (!ccx.IsValid()) 1.1351 + return false; 1.1352 + 1.1353 + uint16_t interface_count = set->GetInterfaceCount(); 1.1354 + XPCNativeInterface** interfaceArray = set->GetInterfaceArray(); 1.1355 + for (uint16_t i = 0; i < interface_count; i++) { 1.1356 + XPCNativeInterface* iface = interfaceArray[i]; 1.1357 + uint16_t member_count = iface->GetMemberCount(); 1.1358 + 1.1359 + for (uint16_t k = 0; k < member_count; k++) { 1.1360 + if (!xpc_ForcePropertyResolve(cx, obj, iface->GetMemberAt(k)->GetName())) 1.1361 + return false; 1.1362 + } 1.1363 + } 1.1364 + 1.1365 + return true; 1.1366 +} 1.1367 + 1.1368 +static void 1.1369 +XPC_WN_Shared_Proto_Finalize(js::FreeOp *fop, JSObject *obj) 1.1370 +{ 1.1371 + // This can be null if xpc shutdown has already happened 1.1372 + XPCWrappedNativeProto* p = (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj); 1.1373 + if (p) 1.1374 + p->JSProtoObjectFinalized(fop, obj); 1.1375 +} 1.1376 + 1.1377 +static void 1.1378 +XPC_WN_Shared_Proto_Trace(JSTracer *trc, JSObject *obj) 1.1379 +{ 1.1380 + // This can be null if xpc shutdown has already happened 1.1381 + XPCWrappedNativeProto* p = 1.1382 + (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj); 1.1383 + if (p) 1.1384 + p->TraceInside(trc); 1.1385 +} 1.1386 + 1.1387 +/*****************************************************/ 1.1388 + 1.1389 +static bool 1.1390 +XPC_WN_ModsAllowed_Proto_Resolve(JSContext *cx, HandleObject obj, HandleId id) 1.1391 +{ 1.1392 + MOZ_ASSERT(js::GetObjectClass(obj) == &XPC_WN_ModsAllowed_WithCall_Proto_JSClass || 1.1393 + js::GetObjectClass(obj) == &XPC_WN_ModsAllowed_NoCall_Proto_JSClass, 1.1394 + "bad proto"); 1.1395 + 1.1396 + XPCWrappedNativeProto* self = 1.1397 + (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj); 1.1398 + if (!self) 1.1399 + return false; 1.1400 + 1.1401 + XPCCallContext ccx(JS_CALLER, cx); 1.1402 + if (!ccx.IsValid()) 1.1403 + return false; 1.1404 + 1.1405 + XPCNativeScriptableInfo* si = self->GetScriptableInfo(); 1.1406 + unsigned enumFlag = (si && si->GetFlags().DontEnumStaticProps()) ? 1.1407 + 0 : JSPROP_ENUMERATE; 1.1408 + 1.1409 + return DefinePropertyIfFound(ccx, obj, id, 1.1410 + self->GetSet(), nullptr, nullptr, 1.1411 + self->GetScope(), 1.1412 + true, nullptr, nullptr, si, 1.1413 + enumFlag, nullptr); 1.1414 +} 1.1415 + 1.1416 +const js::Class XPC_WN_ModsAllowed_WithCall_Proto_JSClass = { 1.1417 + "XPC_WN_ModsAllowed_WithCall_Proto_JSClass", // name; 1.1418 + WRAPPER_SLOTS, // flags; 1.1419 + 1.1420 + /* Mandatory non-null function pointer members. */ 1.1421 + JS_PropertyStub, // addProperty; 1.1422 + JS_DeletePropertyStub, // delProperty; 1.1423 + JS_PropertyStub, // getProperty; 1.1424 + JS_StrictPropertyStub, // setProperty; 1.1425 + XPC_WN_Shared_Proto_Enumerate, // enumerate; 1.1426 + XPC_WN_ModsAllowed_Proto_Resolve, // resolve; 1.1427 + JS_ConvertStub, // convert; 1.1428 + XPC_WN_Shared_Proto_Finalize, // finalize; 1.1429 + 1.1430 + /* Optionally non-null members start here. */ 1.1431 + nullptr, // call; 1.1432 + nullptr, // construct; 1.1433 + nullptr, // hasInstance; 1.1434 + XPC_WN_Shared_Proto_Trace, // trace; 1.1435 + 1.1436 + JS_NULL_CLASS_SPEC, 1.1437 + JS_NULL_CLASS_EXT, 1.1438 + XPC_WN_WithCall_ObjectOps 1.1439 +}; 1.1440 + 1.1441 +const js::Class XPC_WN_ModsAllowed_NoCall_Proto_JSClass = { 1.1442 + "XPC_WN_ModsAllowed_NoCall_Proto_JSClass", // name; 1.1443 + WRAPPER_SLOTS, // flags; 1.1444 + 1.1445 + /* Mandatory non-null function pointer members. */ 1.1446 + JS_PropertyStub, // addProperty; 1.1447 + JS_DeletePropertyStub, // delProperty; 1.1448 + JS_PropertyStub, // getProperty; 1.1449 + JS_StrictPropertyStub, // setProperty; 1.1450 + XPC_WN_Shared_Proto_Enumerate, // enumerate; 1.1451 + XPC_WN_ModsAllowed_Proto_Resolve, // resolve; 1.1452 + JS_ConvertStub, // convert; 1.1453 + XPC_WN_Shared_Proto_Finalize, // finalize; 1.1454 + 1.1455 + /* Optionally non-null members start here. */ 1.1456 + nullptr, // call; 1.1457 + nullptr, // construct; 1.1458 + nullptr, // hasInstance; 1.1459 + XPC_WN_Shared_Proto_Trace, // trace; 1.1460 + 1.1461 + JS_NULL_CLASS_SPEC, 1.1462 + JS_NULL_CLASS_EXT, 1.1463 + XPC_WN_NoCall_ObjectOps 1.1464 +}; 1.1465 + 1.1466 +/***************************************************************************/ 1.1467 + 1.1468 +static bool 1.1469 +XPC_WN_OnlyIWrite_Proto_AddPropertyStub(JSContext *cx, HandleObject obj, HandleId id, 1.1470 + MutableHandleValue vp) 1.1471 +{ 1.1472 + MOZ_ASSERT(js::GetObjectClass(obj) == &XPC_WN_NoMods_WithCall_Proto_JSClass || 1.1473 + js::GetObjectClass(obj) == &XPC_WN_NoMods_NoCall_Proto_JSClass, 1.1474 + "bad proto"); 1.1475 + 1.1476 + XPCWrappedNativeProto* self = 1.1477 + (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj); 1.1478 + if (!self) 1.1479 + return false; 1.1480 + 1.1481 + XPCCallContext ccx(JS_CALLER, cx); 1.1482 + if (!ccx.IsValid()) 1.1483 + return false; 1.1484 + 1.1485 + // Allow XPConnect to add the property only 1.1486 + if (ccx.GetResolveName() == id) 1.1487 + return true; 1.1488 + 1.1489 + return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); 1.1490 +} 1.1491 + 1.1492 +static bool 1.1493 +XPC_WN_OnlyIWrite_Proto_SetPropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool strict, 1.1494 + MutableHandleValue vp) 1.1495 +{ 1.1496 + return XPC_WN_OnlyIWrite_Proto_AddPropertyStub(cx, obj, id, vp); 1.1497 +} 1.1498 + 1.1499 +static bool 1.1500 +XPC_WN_NoMods_Proto_Resolve(JSContext *cx, HandleObject obj, HandleId id) 1.1501 +{ 1.1502 + MOZ_ASSERT(js::GetObjectClass(obj) == &XPC_WN_NoMods_WithCall_Proto_JSClass || 1.1503 + js::GetObjectClass(obj) == &XPC_WN_NoMods_NoCall_Proto_JSClass, 1.1504 + "bad proto"); 1.1505 + 1.1506 + XPCWrappedNativeProto* self = 1.1507 + (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj); 1.1508 + if (!self) 1.1509 + return false; 1.1510 + 1.1511 + XPCCallContext ccx(JS_CALLER, cx); 1.1512 + if (!ccx.IsValid()) 1.1513 + return false; 1.1514 + 1.1515 + XPCNativeScriptableInfo* si = self->GetScriptableInfo(); 1.1516 + unsigned enumFlag = (si && si->GetFlags().DontEnumStaticProps()) ? 1.1517 + 0 : JSPROP_ENUMERATE; 1.1518 + 1.1519 + return DefinePropertyIfFound(ccx, obj, id, 1.1520 + self->GetSet(), nullptr, nullptr, 1.1521 + self->GetScope(), 1.1522 + true, nullptr, nullptr, si, 1.1523 + JSPROP_READONLY | 1.1524 + JSPROP_PERMANENT | 1.1525 + enumFlag, nullptr); 1.1526 +} 1.1527 + 1.1528 +const js::Class XPC_WN_NoMods_WithCall_Proto_JSClass = { 1.1529 + "XPC_WN_NoMods_WithCall_Proto_JSClass", // name; 1.1530 + WRAPPER_SLOTS, // flags; 1.1531 + 1.1532 + /* Mandatory non-null function pointer members. */ 1.1533 + XPC_WN_OnlyIWrite_Proto_AddPropertyStub, // addProperty; 1.1534 + XPC_WN_CantDeletePropertyStub, // delProperty; 1.1535 + JS_PropertyStub, // getProperty; 1.1536 + XPC_WN_OnlyIWrite_Proto_SetPropertyStub, // setProperty; 1.1537 + XPC_WN_Shared_Proto_Enumerate, // enumerate; 1.1538 + XPC_WN_NoMods_Proto_Resolve, // resolve; 1.1539 + JS_ConvertStub, // convert; 1.1540 + XPC_WN_Shared_Proto_Finalize, // finalize; 1.1541 + 1.1542 + /* Optionally non-null members start here. */ 1.1543 + nullptr, // call; 1.1544 + nullptr, // construct; 1.1545 + nullptr, // hasInstance; 1.1546 + XPC_WN_Shared_Proto_Trace, // trace; 1.1547 + 1.1548 + JS_NULL_CLASS_SPEC, 1.1549 + JS_NULL_CLASS_EXT, 1.1550 + XPC_WN_WithCall_ObjectOps 1.1551 +}; 1.1552 + 1.1553 +const js::Class XPC_WN_NoMods_NoCall_Proto_JSClass = { 1.1554 + "XPC_WN_NoMods_NoCall_Proto_JSClass", // name; 1.1555 + WRAPPER_SLOTS, // flags; 1.1556 + 1.1557 + /* Mandatory non-null function pointer members. */ 1.1558 + XPC_WN_OnlyIWrite_Proto_AddPropertyStub, // addProperty; 1.1559 + XPC_WN_CantDeletePropertyStub, // delProperty; 1.1560 + JS_PropertyStub, // getProperty; 1.1561 + XPC_WN_OnlyIWrite_Proto_SetPropertyStub, // setProperty; 1.1562 + XPC_WN_Shared_Proto_Enumerate, // enumerate; 1.1563 + XPC_WN_NoMods_Proto_Resolve, // resolve; 1.1564 + JS_ConvertStub, // convert; 1.1565 + XPC_WN_Shared_Proto_Finalize, // finalize; 1.1566 + 1.1567 + /* Optionally non-null members start here. */ 1.1568 + nullptr, // call; 1.1569 + nullptr, // construct; 1.1570 + nullptr, // hasInstance; 1.1571 + XPC_WN_Shared_Proto_Trace, // trace; 1.1572 + 1.1573 + JS_NULL_CLASS_SPEC, 1.1574 + JS_NULL_CLASS_EXT, 1.1575 + XPC_WN_NoCall_ObjectOps 1.1576 +}; 1.1577 + 1.1578 +/***************************************************************************/ 1.1579 + 1.1580 +static bool 1.1581 +XPC_WN_TearOff_Enumerate(JSContext *cx, HandleObject obj) 1.1582 +{ 1.1583 + XPCCallContext ccx(JS_CALLER, cx, obj); 1.1584 + XPCWrappedNative* wrapper = ccx.GetWrapper(); 1.1585 + THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); 1.1586 + 1.1587 + XPCWrappedNativeTearOff* to = ccx.GetTearOff(); 1.1588 + XPCNativeInterface* iface; 1.1589 + 1.1590 + if (!to || nullptr == (iface = to->GetInterface())) 1.1591 + return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); 1.1592 + 1.1593 + uint16_t member_count = iface->GetMemberCount(); 1.1594 + for (uint16_t k = 0; k < member_count; k++) { 1.1595 + if (!xpc_ForcePropertyResolve(cx, obj, iface->GetMemberAt(k)->GetName())) 1.1596 + return false; 1.1597 + } 1.1598 + 1.1599 + return true; 1.1600 +} 1.1601 + 1.1602 +static bool 1.1603 +XPC_WN_TearOff_Resolve(JSContext *cx, HandleObject obj, HandleId id) 1.1604 +{ 1.1605 + XPCCallContext ccx(JS_CALLER, cx, obj); 1.1606 + XPCWrappedNative* wrapper = ccx.GetWrapper(); 1.1607 + THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); 1.1608 + 1.1609 + XPCWrappedNativeTearOff* to = ccx.GetTearOff(); 1.1610 + XPCNativeInterface* iface; 1.1611 + 1.1612 + if (!to || nullptr == (iface = to->GetInterface())) 1.1613 + return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); 1.1614 + 1.1615 + return DefinePropertyIfFound(ccx, obj, id, nullptr, iface, nullptr, 1.1616 + wrapper->GetScope(), 1.1617 + true, nullptr, nullptr, nullptr, 1.1618 + JSPROP_READONLY | 1.1619 + JSPROP_PERMANENT | 1.1620 + JSPROP_ENUMERATE, nullptr); 1.1621 +} 1.1622 + 1.1623 +static void 1.1624 +XPC_WN_TearOff_Finalize(js::FreeOp *fop, JSObject *obj) 1.1625 +{ 1.1626 + XPCWrappedNativeTearOff* p = (XPCWrappedNativeTearOff*) 1.1627 + xpc_GetJSPrivate(obj); 1.1628 + if (!p) 1.1629 + return; 1.1630 + p->JSObjectFinalized(); 1.1631 +} 1.1632 + 1.1633 +const js::Class XPC_WN_Tearoff_JSClass = { 1.1634 + "WrappedNative_TearOff", // name; 1.1635 + WRAPPER_SLOTS, // flags; 1.1636 + 1.1637 + XPC_WN_OnlyIWrite_AddPropertyStub, // addProperty; 1.1638 + XPC_WN_CantDeletePropertyStub, // delProperty; 1.1639 + JS_PropertyStub, // getProperty; 1.1640 + XPC_WN_OnlyIWrite_SetPropertyStub, // setProperty; 1.1641 + XPC_WN_TearOff_Enumerate, // enumerate; 1.1642 + XPC_WN_TearOff_Resolve, // resolve; 1.1643 + XPC_WN_Shared_Convert, // convert; 1.1644 + XPC_WN_TearOff_Finalize // finalize; 1.1645 +};