Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
michael@0 | 2 | /* vim: set ts=8 sts=4 et sw=4 tw=99: */ |
michael@0 | 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | /* JavaScript JSClasses and JSOps for our Wrapped Native JS Objects. */ |
michael@0 | 8 | |
michael@0 | 9 | #include "xpcprivate.h" |
michael@0 | 10 | #include "jsprf.h" |
michael@0 | 11 | #include "mozilla/dom/BindingUtils.h" |
michael@0 | 12 | #include "mozilla/Preferences.h" |
michael@0 | 13 | |
michael@0 | 14 | using namespace mozilla; |
michael@0 | 15 | using namespace JS; |
michael@0 | 16 | |
michael@0 | 17 | /***************************************************************************/ |
michael@0 | 18 | |
michael@0 | 19 | // All of the exceptions thrown into JS from this file go through here. |
michael@0 | 20 | // That makes this a nice place to set a breakpoint. |
michael@0 | 21 | |
michael@0 | 22 | static bool Throw(nsresult errNum, JSContext* cx) |
michael@0 | 23 | { |
michael@0 | 24 | XPCThrower::Throw(errNum, cx); |
michael@0 | 25 | return false; |
michael@0 | 26 | } |
michael@0 | 27 | |
michael@0 | 28 | // Handy macro used in many callback stub below. |
michael@0 | 29 | |
michael@0 | 30 | #define THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper) \ |
michael@0 | 31 | PR_BEGIN_MACRO \ |
michael@0 | 32 | if (!wrapper) \ |
michael@0 | 33 | return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); \ |
michael@0 | 34 | if (!wrapper->IsValid()) \ |
michael@0 | 35 | return Throw(NS_ERROR_XPC_HAS_BEEN_SHUTDOWN, cx); \ |
michael@0 | 36 | PR_END_MACRO |
michael@0 | 37 | |
michael@0 | 38 | /***************************************************************************/ |
michael@0 | 39 | |
michael@0 | 40 | static bool |
michael@0 | 41 | ToStringGuts(XPCCallContext& ccx) |
michael@0 | 42 | { |
michael@0 | 43 | char* sz; |
michael@0 | 44 | XPCWrappedNative* wrapper = ccx.GetWrapper(); |
michael@0 | 45 | |
michael@0 | 46 | if (wrapper) |
michael@0 | 47 | sz = wrapper->ToString(ccx.GetTearOff()); |
michael@0 | 48 | else |
michael@0 | 49 | sz = JS_smprintf("[xpconnect wrapped native prototype]"); |
michael@0 | 50 | |
michael@0 | 51 | if (!sz) { |
michael@0 | 52 | JS_ReportOutOfMemory(ccx); |
michael@0 | 53 | return false; |
michael@0 | 54 | } |
michael@0 | 55 | |
michael@0 | 56 | JSString* str = JS_NewStringCopyZ(ccx, sz); |
michael@0 | 57 | JS_smprintf_free(sz); |
michael@0 | 58 | if (!str) |
michael@0 | 59 | return false; |
michael@0 | 60 | |
michael@0 | 61 | ccx.SetRetVal(STRING_TO_JSVAL(str)); |
michael@0 | 62 | return true; |
michael@0 | 63 | } |
michael@0 | 64 | |
michael@0 | 65 | /***************************************************************************/ |
michael@0 | 66 | |
michael@0 | 67 | static bool |
michael@0 | 68 | XPC_WN_Shared_ToString(JSContext *cx, unsigned argc, jsval *vp) |
michael@0 | 69 | { |
michael@0 | 70 | CallArgs args = CallArgsFromVp(argc, vp); |
michael@0 | 71 | RootedObject obj(cx, JS_THIS_OBJECT(cx, vp)); |
michael@0 | 72 | if (!obj) |
michael@0 | 73 | return false; |
michael@0 | 74 | |
michael@0 | 75 | XPCCallContext ccx(JS_CALLER, cx, obj); |
michael@0 | 76 | if (!ccx.IsValid()) |
michael@0 | 77 | return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); |
michael@0 | 78 | ccx.SetName(ccx.GetRuntime()->GetStringID(XPCJSRuntime::IDX_TO_STRING)); |
michael@0 | 79 | ccx.SetArgsAndResultPtr(args.length(), args.array(), vp); |
michael@0 | 80 | return ToStringGuts(ccx); |
michael@0 | 81 | } |
michael@0 | 82 | |
michael@0 | 83 | static bool |
michael@0 | 84 | XPC_WN_Shared_ToSource(JSContext *cx, unsigned argc, jsval *vp) |
michael@0 | 85 | { |
michael@0 | 86 | CallArgs args = CallArgsFromVp(argc, vp); |
michael@0 | 87 | static const char empty[] = "({})"; |
michael@0 | 88 | JSString *str = JS_NewStringCopyN(cx, empty, sizeof(empty)-1); |
michael@0 | 89 | if (!str) |
michael@0 | 90 | return false; |
michael@0 | 91 | args.rval().setString(str); |
michael@0 | 92 | |
michael@0 | 93 | return true; |
michael@0 | 94 | } |
michael@0 | 95 | |
michael@0 | 96 | /***************************************************************************/ |
michael@0 | 97 | |
michael@0 | 98 | // A "double wrapped object" is a user JSObject that has been wrapped as a |
michael@0 | 99 | // wrappedJS in order to be used by native code and then re-wrapped by a |
michael@0 | 100 | // wrappedNative wrapper to be used by JS code. One might think of it as: |
michael@0 | 101 | // wrappedNative(wrappedJS(underlying_JSObject)) |
michael@0 | 102 | // This is done (as opposed to just unwrapping the wrapped JS and automatically |
michael@0 | 103 | // returning the underlying JSObject) so that JS callers will see what looks |
michael@0 | 104 | // Like any other xpcom object - and be limited to use its interfaces. |
michael@0 | 105 | // |
michael@0 | 106 | // See the comment preceding nsIXPCWrappedJSObjectGetter in nsIXPConnect.idl. |
michael@0 | 107 | |
michael@0 | 108 | static JSObject* |
michael@0 | 109 | GetDoubleWrappedJSObject(XPCCallContext& ccx, XPCWrappedNative* wrapper) |
michael@0 | 110 | { |
michael@0 | 111 | RootedObject obj(ccx); |
michael@0 | 112 | nsCOMPtr<nsIXPConnectWrappedJS> |
michael@0 | 113 | underware = do_QueryInterface(wrapper->GetIdentityObject()); |
michael@0 | 114 | if (underware) { |
michael@0 | 115 | RootedObject mainObj(ccx, underware->GetJSObject()); |
michael@0 | 116 | if (mainObj) { |
michael@0 | 117 | RootedId id(ccx, ccx.GetRuntime()-> |
michael@0 | 118 | GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT)); |
michael@0 | 119 | |
michael@0 | 120 | JSAutoCompartment ac(ccx, mainObj); |
michael@0 | 121 | |
michael@0 | 122 | RootedValue val(ccx); |
michael@0 | 123 | if (JS_GetPropertyById(ccx, mainObj, id, &val) && |
michael@0 | 124 | !JSVAL_IS_PRIMITIVE(val)) { |
michael@0 | 125 | obj = JSVAL_TO_OBJECT(val); |
michael@0 | 126 | } |
michael@0 | 127 | } |
michael@0 | 128 | } |
michael@0 | 129 | return obj; |
michael@0 | 130 | } |
michael@0 | 131 | |
michael@0 | 132 | // This is the getter native function we use to handle 'wrappedJSObject' for |
michael@0 | 133 | // double wrapped JSObjects. |
michael@0 | 134 | |
michael@0 | 135 | static bool |
michael@0 | 136 | XPC_WN_DoubleWrappedGetter(JSContext *cx, unsigned argc, jsval *vp) |
michael@0 | 137 | { |
michael@0 | 138 | CallArgs args = CallArgsFromVp(argc, vp); |
michael@0 | 139 | |
michael@0 | 140 | RootedObject obj(cx, JS_THIS_OBJECT(cx, vp)); |
michael@0 | 141 | if (!obj) |
michael@0 | 142 | return false; |
michael@0 | 143 | |
michael@0 | 144 | XPCCallContext ccx(JS_CALLER, cx, obj); |
michael@0 | 145 | XPCWrappedNative* wrapper = ccx.GetWrapper(); |
michael@0 | 146 | THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); |
michael@0 | 147 | |
michael@0 | 148 | MOZ_ASSERT(JS_TypeOfValue(cx, args.calleev()) == JSTYPE_FUNCTION, "bad function"); |
michael@0 | 149 | |
michael@0 | 150 | RootedObject realObject(cx, GetDoubleWrappedJSObject(ccx, wrapper)); |
michael@0 | 151 | if (!realObject) { |
michael@0 | 152 | // This is pretty unexpected at this point. The object originally |
michael@0 | 153 | // responded to this get property call and now gives no object. |
michael@0 | 154 | // XXX Should this throw something at the caller? |
michael@0 | 155 | args.rval().setNull(); |
michael@0 | 156 | return true; |
michael@0 | 157 | } |
michael@0 | 158 | |
michael@0 | 159 | // It is a double wrapped object. This should really never appear in |
michael@0 | 160 | // content these days, but addons still do it - see bug 965921. |
michael@0 | 161 | if (MOZ_UNLIKELY(!nsContentUtils::IsCallerChrome())) { |
michael@0 | 162 | JS_ReportError(cx, "Attempt to use .wrappedJSObject in untrusted code"); |
michael@0 | 163 | return false; |
michael@0 | 164 | } |
michael@0 | 165 | args.rval().setObject(*realObject); |
michael@0 | 166 | return JS_WrapValue(cx, args.rval()); |
michael@0 | 167 | } |
michael@0 | 168 | |
michael@0 | 169 | /***************************************************************************/ |
michael@0 | 170 | |
michael@0 | 171 | // This is our shared function to define properties on our JSObjects. |
michael@0 | 172 | |
michael@0 | 173 | /* |
michael@0 | 174 | * NOTE: |
michael@0 | 175 | * We *never* set the tearoff names (e.g. nsIFoo) as JS_ENUMERATE. |
michael@0 | 176 | * We *never* set toString or toSource as JS_ENUMERATE. |
michael@0 | 177 | */ |
michael@0 | 178 | |
michael@0 | 179 | static bool |
michael@0 | 180 | DefinePropertyIfFound(XPCCallContext& ccx, |
michael@0 | 181 | HandleObject obj, |
michael@0 | 182 | HandleId idArg, |
michael@0 | 183 | XPCNativeSet* set, |
michael@0 | 184 | XPCNativeInterface* iface, |
michael@0 | 185 | XPCNativeMember* member, |
michael@0 | 186 | XPCWrappedNativeScope* scope, |
michael@0 | 187 | bool reflectToStringAndToSource, |
michael@0 | 188 | XPCWrappedNative* wrapperToReflectInterfaceNames, |
michael@0 | 189 | XPCWrappedNative* wrapperToReflectDoubleWrap, |
michael@0 | 190 | XPCNativeScriptableInfo* scriptableInfo, |
michael@0 | 191 | unsigned propFlags, |
michael@0 | 192 | bool* resolved) |
michael@0 | 193 | { |
michael@0 | 194 | RootedId id(ccx, idArg); |
michael@0 | 195 | XPCJSRuntime* rt = ccx.GetRuntime(); |
michael@0 | 196 | bool found; |
michael@0 | 197 | const char* name; |
michael@0 | 198 | |
michael@0 | 199 | if (set) { |
michael@0 | 200 | if (iface) |
michael@0 | 201 | found = true; |
michael@0 | 202 | else |
michael@0 | 203 | found = set->FindMember(id, &member, &iface); |
michael@0 | 204 | } else |
michael@0 | 205 | found = (nullptr != (member = iface->FindMember(id))); |
michael@0 | 206 | |
michael@0 | 207 | if (!found) { |
michael@0 | 208 | if (reflectToStringAndToSource) { |
michael@0 | 209 | JSNative call; |
michael@0 | 210 | uint32_t flags = 0; |
michael@0 | 211 | |
michael@0 | 212 | if (scriptableInfo) { |
michael@0 | 213 | nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface( |
michael@0 | 214 | scriptableInfo->GetCallback()); |
michael@0 | 215 | |
michael@0 | 216 | if (classInfo) { |
michael@0 | 217 | nsresult rv = classInfo->GetFlags(&flags); |
michael@0 | 218 | if (NS_FAILED(rv)) |
michael@0 | 219 | return Throw(rv, ccx); |
michael@0 | 220 | } |
michael@0 | 221 | } |
michael@0 | 222 | |
michael@0 | 223 | bool overwriteToString = !(flags & nsIClassInfo::DOM_OBJECT) |
michael@0 | 224 | || Preferences::GetBool("dom.XPCToStringForDOMClasses", false); |
michael@0 | 225 | |
michael@0 | 226 | if(id == rt->GetStringID(XPCJSRuntime::IDX_TO_STRING) |
michael@0 | 227 | && overwriteToString) |
michael@0 | 228 | { |
michael@0 | 229 | call = XPC_WN_Shared_ToString; |
michael@0 | 230 | name = rt->GetStringName(XPCJSRuntime::IDX_TO_STRING); |
michael@0 | 231 | id = rt->GetStringID(XPCJSRuntime::IDX_TO_STRING); |
michael@0 | 232 | } else if (id == rt->GetStringID(XPCJSRuntime::IDX_TO_SOURCE)) { |
michael@0 | 233 | call = XPC_WN_Shared_ToSource; |
michael@0 | 234 | name = rt->GetStringName(XPCJSRuntime::IDX_TO_SOURCE); |
michael@0 | 235 | id = rt->GetStringID(XPCJSRuntime::IDX_TO_SOURCE); |
michael@0 | 236 | } |
michael@0 | 237 | |
michael@0 | 238 | else |
michael@0 | 239 | call = nullptr; |
michael@0 | 240 | |
michael@0 | 241 | if (call) { |
michael@0 | 242 | RootedFunction fun(ccx, JS_NewFunction(ccx, call, 0, 0, obj, name)); |
michael@0 | 243 | if (!fun) { |
michael@0 | 244 | JS_ReportOutOfMemory(ccx); |
michael@0 | 245 | return false; |
michael@0 | 246 | } |
michael@0 | 247 | |
michael@0 | 248 | AutoResolveName arn(ccx, id); |
michael@0 | 249 | if (resolved) |
michael@0 | 250 | *resolved = true; |
michael@0 | 251 | return JS_DefinePropertyById(ccx, obj, id, |
michael@0 | 252 | OBJECT_TO_JSVAL(JS_GetFunctionObject(fun)), |
michael@0 | 253 | nullptr, nullptr, |
michael@0 | 254 | propFlags & ~JSPROP_ENUMERATE); |
michael@0 | 255 | } |
michael@0 | 256 | } |
michael@0 | 257 | // This *might* be a tearoff name that is not yet part of our |
michael@0 | 258 | // set. Let's lookup the name and see if it is the name of an |
michael@0 | 259 | // interface. Then we'll see if the object actually *does* this |
michael@0 | 260 | // interface and add a tearoff as necessary. |
michael@0 | 261 | |
michael@0 | 262 | if (wrapperToReflectInterfaceNames) { |
michael@0 | 263 | JSAutoByteString name; |
michael@0 | 264 | AutoMarkingNativeInterfacePtr iface2(ccx); |
michael@0 | 265 | XPCWrappedNativeTearOff* to; |
michael@0 | 266 | RootedObject jso(ccx); |
michael@0 | 267 | nsresult rv = NS_OK; |
michael@0 | 268 | |
michael@0 | 269 | if (JSID_IS_STRING(id) && |
michael@0 | 270 | name.encodeLatin1(ccx, JSID_TO_STRING(id)) && |
michael@0 | 271 | (iface2 = XPCNativeInterface::GetNewOrUsed(name.ptr()), iface2) && |
michael@0 | 272 | nullptr != (to = wrapperToReflectInterfaceNames-> |
michael@0 | 273 | FindTearOff(iface2, true, &rv)) && |
michael@0 | 274 | nullptr != (jso = to->GetJSObject())) |
michael@0 | 275 | |
michael@0 | 276 | { |
michael@0 | 277 | AutoResolveName arn(ccx, id); |
michael@0 | 278 | if (resolved) |
michael@0 | 279 | *resolved = true; |
michael@0 | 280 | return JS_DefinePropertyById(ccx, obj, id, OBJECT_TO_JSVAL(jso), |
michael@0 | 281 | nullptr, nullptr, |
michael@0 | 282 | propFlags & ~JSPROP_ENUMERATE); |
michael@0 | 283 | } else if (NS_FAILED(rv) && rv != NS_ERROR_NO_INTERFACE) { |
michael@0 | 284 | return Throw(rv, ccx); |
michael@0 | 285 | } |
michael@0 | 286 | } |
michael@0 | 287 | |
michael@0 | 288 | // This *might* be a double wrapped JSObject |
michael@0 | 289 | if (wrapperToReflectDoubleWrap && |
michael@0 | 290 | id == rt->GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT) && |
michael@0 | 291 | GetDoubleWrappedJSObject(ccx, wrapperToReflectDoubleWrap)) { |
michael@0 | 292 | // We build and add a getter function. |
michael@0 | 293 | // A security check is done on a per-get basis. |
michael@0 | 294 | |
michael@0 | 295 | JSFunction* fun; |
michael@0 | 296 | |
michael@0 | 297 | id = rt->GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT); |
michael@0 | 298 | name = rt->GetStringName(XPCJSRuntime::IDX_WRAPPED_JSOBJECT); |
michael@0 | 299 | |
michael@0 | 300 | fun = JS_NewFunction(ccx, XPC_WN_DoubleWrappedGetter, |
michael@0 | 301 | 0, 0, obj, name); |
michael@0 | 302 | |
michael@0 | 303 | if (!fun) |
michael@0 | 304 | return false; |
michael@0 | 305 | |
michael@0 | 306 | RootedObject funobj(ccx, JS_GetFunctionObject(fun)); |
michael@0 | 307 | if (!funobj) |
michael@0 | 308 | return false; |
michael@0 | 309 | |
michael@0 | 310 | propFlags |= JSPROP_GETTER | JSPROP_SHARED; |
michael@0 | 311 | propFlags &= ~JSPROP_ENUMERATE; |
michael@0 | 312 | |
michael@0 | 313 | AutoResolveName arn(ccx, id); |
michael@0 | 314 | if (resolved) |
michael@0 | 315 | *resolved = true; |
michael@0 | 316 | return JS_DefinePropertyById(ccx, obj, id, JSVAL_VOID, |
michael@0 | 317 | JS_DATA_TO_FUNC_PTR(JSPropertyOp, |
michael@0 | 318 | funobj.get()), |
michael@0 | 319 | nullptr, propFlags); |
michael@0 | 320 | } |
michael@0 | 321 | |
michael@0 | 322 | if (resolved) |
michael@0 | 323 | *resolved = false; |
michael@0 | 324 | return true; |
michael@0 | 325 | } |
michael@0 | 326 | |
michael@0 | 327 | if (!member) { |
michael@0 | 328 | if (wrapperToReflectInterfaceNames) { |
michael@0 | 329 | XPCWrappedNativeTearOff* to = |
michael@0 | 330 | wrapperToReflectInterfaceNames->FindTearOff(iface, true); |
michael@0 | 331 | |
michael@0 | 332 | if (!to) |
michael@0 | 333 | return false; |
michael@0 | 334 | RootedObject jso(ccx, to->GetJSObject()); |
michael@0 | 335 | if (!jso) |
michael@0 | 336 | return false; |
michael@0 | 337 | |
michael@0 | 338 | AutoResolveName arn(ccx, id); |
michael@0 | 339 | if (resolved) |
michael@0 | 340 | *resolved = true; |
michael@0 | 341 | return JS_DefinePropertyById(ccx, obj, id, OBJECT_TO_JSVAL(jso), |
michael@0 | 342 | nullptr, nullptr, |
michael@0 | 343 | propFlags & ~JSPROP_ENUMERATE); |
michael@0 | 344 | } |
michael@0 | 345 | if (resolved) |
michael@0 | 346 | *resolved = false; |
michael@0 | 347 | return true; |
michael@0 | 348 | } |
michael@0 | 349 | |
michael@0 | 350 | if (member->IsConstant()) { |
michael@0 | 351 | RootedValue val(ccx); |
michael@0 | 352 | AutoResolveName arn(ccx, id); |
michael@0 | 353 | if (resolved) |
michael@0 | 354 | *resolved = true; |
michael@0 | 355 | return member->GetConstantValue(ccx, iface, val.address()) && |
michael@0 | 356 | JS_DefinePropertyById(ccx, obj, id, val, nullptr, nullptr, |
michael@0 | 357 | propFlags); |
michael@0 | 358 | } |
michael@0 | 359 | |
michael@0 | 360 | if (id == rt->GetStringID(XPCJSRuntime::IDX_TO_STRING) || |
michael@0 | 361 | id == rt->GetStringID(XPCJSRuntime::IDX_TO_SOURCE) || |
michael@0 | 362 | (scriptableInfo && |
michael@0 | 363 | scriptableInfo->GetFlags().DontEnumQueryInterface() && |
michael@0 | 364 | id == rt->GetStringID(XPCJSRuntime::IDX_QUERY_INTERFACE))) |
michael@0 | 365 | propFlags &= ~JSPROP_ENUMERATE; |
michael@0 | 366 | |
michael@0 | 367 | RootedValue funval(ccx); |
michael@0 | 368 | if (!member->NewFunctionObject(ccx, iface, obj, funval.address())) |
michael@0 | 369 | return false; |
michael@0 | 370 | |
michael@0 | 371 | if (member->IsMethod()) { |
michael@0 | 372 | AutoResolveName arn(ccx, id); |
michael@0 | 373 | if (resolved) |
michael@0 | 374 | *resolved = true; |
michael@0 | 375 | return JS_DefinePropertyById(ccx, obj, id, funval, nullptr, nullptr, |
michael@0 | 376 | propFlags); |
michael@0 | 377 | } |
michael@0 | 378 | |
michael@0 | 379 | // else... |
michael@0 | 380 | |
michael@0 | 381 | MOZ_ASSERT(member->IsAttribute(), "way broken!"); |
michael@0 | 382 | |
michael@0 | 383 | propFlags |= JSPROP_GETTER | JSPROP_SHARED; |
michael@0 | 384 | JSObject* funobj = JSVAL_TO_OBJECT(funval); |
michael@0 | 385 | JSPropertyOp getter = JS_DATA_TO_FUNC_PTR(JSPropertyOp, funobj); |
michael@0 | 386 | JSStrictPropertyOp setter; |
michael@0 | 387 | if (member->IsWritableAttribute()) { |
michael@0 | 388 | propFlags |= JSPROP_SETTER; |
michael@0 | 389 | propFlags &= ~JSPROP_READONLY; |
michael@0 | 390 | setter = JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, funobj); |
michael@0 | 391 | } else { |
michael@0 | 392 | setter = js_GetterOnlyPropertyStub; |
michael@0 | 393 | } |
michael@0 | 394 | |
michael@0 | 395 | AutoResolveName arn(ccx, id); |
michael@0 | 396 | if (resolved) |
michael@0 | 397 | *resolved = true; |
michael@0 | 398 | |
michael@0 | 399 | return JS_DefinePropertyById(ccx, obj, id, JSVAL_VOID, getter, setter, |
michael@0 | 400 | propFlags); |
michael@0 | 401 | } |
michael@0 | 402 | |
michael@0 | 403 | /***************************************************************************/ |
michael@0 | 404 | /***************************************************************************/ |
michael@0 | 405 | |
michael@0 | 406 | static bool |
michael@0 | 407 | XPC_WN_OnlyIWrite_AddPropertyStub(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp) |
michael@0 | 408 | { |
michael@0 | 409 | XPCCallContext ccx(JS_CALLER, cx, obj, NullPtr(), id); |
michael@0 | 410 | XPCWrappedNative* wrapper = ccx.GetWrapper(); |
michael@0 | 411 | THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); |
michael@0 | 412 | |
michael@0 | 413 | // Allow only XPConnect to add/set the property |
michael@0 | 414 | if (ccx.GetResolveName() == id) |
michael@0 | 415 | return true; |
michael@0 | 416 | |
michael@0 | 417 | return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx); |
michael@0 | 418 | } |
michael@0 | 419 | |
michael@0 | 420 | static bool |
michael@0 | 421 | XPC_WN_OnlyIWrite_SetPropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool strict, |
michael@0 | 422 | MutableHandleValue vp) |
michael@0 | 423 | { |
michael@0 | 424 | return XPC_WN_OnlyIWrite_AddPropertyStub(cx, obj, id, vp); |
michael@0 | 425 | } |
michael@0 | 426 | |
michael@0 | 427 | static bool |
michael@0 | 428 | XPC_WN_CannotModifyPropertyStub(JSContext *cx, HandleObject obj, HandleId id, |
michael@0 | 429 | MutableHandleValue vp) |
michael@0 | 430 | { |
michael@0 | 431 | return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx); |
michael@0 | 432 | } |
michael@0 | 433 | |
michael@0 | 434 | static bool |
michael@0 | 435 | XPC_WN_CantDeletePropertyStub(JSContext *cx, HandleObject obj, HandleId id, |
michael@0 | 436 | bool *succeeded) |
michael@0 | 437 | { |
michael@0 | 438 | return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx); |
michael@0 | 439 | } |
michael@0 | 440 | |
michael@0 | 441 | static bool |
michael@0 | 442 | XPC_WN_CannotModifyStrictPropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool strict, |
michael@0 | 443 | MutableHandleValue vp) |
michael@0 | 444 | { |
michael@0 | 445 | return XPC_WN_CannotModifyPropertyStub(cx, obj, id, vp); |
michael@0 | 446 | } |
michael@0 | 447 | |
michael@0 | 448 | static bool |
michael@0 | 449 | XPC_WN_Shared_Convert(JSContext *cx, HandleObject obj, JSType type, MutableHandleValue vp) |
michael@0 | 450 | { |
michael@0 | 451 | if (type == JSTYPE_OBJECT) { |
michael@0 | 452 | vp.set(OBJECT_TO_JSVAL(obj)); |
michael@0 | 453 | return true; |
michael@0 | 454 | } |
michael@0 | 455 | |
michael@0 | 456 | XPCCallContext ccx(JS_CALLER, cx, obj); |
michael@0 | 457 | XPCWrappedNative* wrapper = ccx.GetWrapper(); |
michael@0 | 458 | THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); |
michael@0 | 459 | |
michael@0 | 460 | switch (type) { |
michael@0 | 461 | case JSTYPE_FUNCTION: |
michael@0 | 462 | { |
michael@0 | 463 | if (!ccx.GetTearOff()) { |
michael@0 | 464 | XPCNativeScriptableInfo* si = wrapper->GetScriptableInfo(); |
michael@0 | 465 | if (si && (si->GetFlags().WantCall() || |
michael@0 | 466 | si->GetFlags().WantConstruct())) { |
michael@0 | 467 | vp.set(OBJECT_TO_JSVAL(obj)); |
michael@0 | 468 | return true; |
michael@0 | 469 | } |
michael@0 | 470 | } |
michael@0 | 471 | } |
michael@0 | 472 | return Throw(NS_ERROR_XPC_CANT_CONVERT_WN_TO_FUN, cx); |
michael@0 | 473 | case JSTYPE_NUMBER: |
michael@0 | 474 | vp.set(JS_GetNaNValue(cx)); |
michael@0 | 475 | return true; |
michael@0 | 476 | case JSTYPE_BOOLEAN: |
michael@0 | 477 | vp.set(JSVAL_TRUE); |
michael@0 | 478 | return true; |
michael@0 | 479 | case JSTYPE_VOID: |
michael@0 | 480 | case JSTYPE_STRING: |
michael@0 | 481 | { |
michael@0 | 482 | ccx.SetName(ccx.GetRuntime()->GetStringID(XPCJSRuntime::IDX_TO_STRING)); |
michael@0 | 483 | ccx.SetArgsAndResultPtr(0, nullptr, vp.address()); |
michael@0 | 484 | |
michael@0 | 485 | XPCNativeMember* member = ccx.GetMember(); |
michael@0 | 486 | if (member && member->IsMethod()) { |
michael@0 | 487 | if (!XPCWrappedNative::CallMethod(ccx)) |
michael@0 | 488 | return false; |
michael@0 | 489 | |
michael@0 | 490 | if (JSVAL_IS_PRIMITIVE(vp)) |
michael@0 | 491 | return true; |
michael@0 | 492 | } |
michael@0 | 493 | |
michael@0 | 494 | // else... |
michael@0 | 495 | return ToStringGuts(ccx); |
michael@0 | 496 | } |
michael@0 | 497 | default: |
michael@0 | 498 | NS_ERROR("bad type in conversion"); |
michael@0 | 499 | return false; |
michael@0 | 500 | } |
michael@0 | 501 | NS_NOTREACHED("huh?"); |
michael@0 | 502 | return false; |
michael@0 | 503 | } |
michael@0 | 504 | |
michael@0 | 505 | static bool |
michael@0 | 506 | XPC_WN_Shared_Enumerate(JSContext *cx, HandleObject obj) |
michael@0 | 507 | { |
michael@0 | 508 | XPCCallContext ccx(JS_CALLER, cx, obj); |
michael@0 | 509 | XPCWrappedNative* wrapper = ccx.GetWrapper(); |
michael@0 | 510 | THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); |
michael@0 | 511 | |
michael@0 | 512 | // Since we aren't going to enumerate tearoff names and the prototype |
michael@0 | 513 | // handles non-mutated members, we can do this potential short-circuit. |
michael@0 | 514 | if (!wrapper->HasMutatedSet()) |
michael@0 | 515 | return true; |
michael@0 | 516 | |
michael@0 | 517 | XPCNativeSet* set = wrapper->GetSet(); |
michael@0 | 518 | XPCNativeSet* protoSet = wrapper->HasProto() ? |
michael@0 | 519 | wrapper->GetProto()->GetSet() : nullptr; |
michael@0 | 520 | |
michael@0 | 521 | uint16_t interface_count = set->GetInterfaceCount(); |
michael@0 | 522 | XPCNativeInterface** interfaceArray = set->GetInterfaceArray(); |
michael@0 | 523 | for (uint16_t i = 0; i < interface_count; i++) { |
michael@0 | 524 | XPCNativeInterface* iface = interfaceArray[i]; |
michael@0 | 525 | uint16_t member_count = iface->GetMemberCount(); |
michael@0 | 526 | for (uint16_t k = 0; k < member_count; k++) { |
michael@0 | 527 | XPCNativeMember* member = iface->GetMemberAt(k); |
michael@0 | 528 | jsid name = member->GetName(); |
michael@0 | 529 | |
michael@0 | 530 | // Skip if this member is going to come from the proto. |
michael@0 | 531 | uint16_t index; |
michael@0 | 532 | if (protoSet && |
michael@0 | 533 | protoSet->FindMember(name, nullptr, &index) && index == i) |
michael@0 | 534 | continue; |
michael@0 | 535 | if (!xpc_ForcePropertyResolve(cx, obj, name)) |
michael@0 | 536 | return false; |
michael@0 | 537 | } |
michael@0 | 538 | } |
michael@0 | 539 | return true; |
michael@0 | 540 | } |
michael@0 | 541 | |
michael@0 | 542 | /***************************************************************************/ |
michael@0 | 543 | |
michael@0 | 544 | enum WNHelperType { |
michael@0 | 545 | WN_NOHELPER, |
michael@0 | 546 | WN_HELPER |
michael@0 | 547 | }; |
michael@0 | 548 | |
michael@0 | 549 | static void |
michael@0 | 550 | WrappedNativeFinalize(js::FreeOp *fop, JSObject *obj, WNHelperType helperType) |
michael@0 | 551 | { |
michael@0 | 552 | const js::Class* clazz = js::GetObjectClass(obj); |
michael@0 | 553 | if (clazz->flags & JSCLASS_DOM_GLOBAL) { |
michael@0 | 554 | mozilla::dom::DestroyProtoAndIfaceCache(obj); |
michael@0 | 555 | } |
michael@0 | 556 | nsISupports* p = static_cast<nsISupports*>(xpc_GetJSPrivate(obj)); |
michael@0 | 557 | if (!p) |
michael@0 | 558 | return; |
michael@0 | 559 | |
michael@0 | 560 | XPCWrappedNative* wrapper = static_cast<XPCWrappedNative*>(p); |
michael@0 | 561 | if (helperType == WN_HELPER) |
michael@0 | 562 | wrapper->GetScriptableCallback()->Finalize(wrapper, js::CastToJSFreeOp(fop), obj); |
michael@0 | 563 | wrapper->FlatJSObjectFinalized(); |
michael@0 | 564 | } |
michael@0 | 565 | |
michael@0 | 566 | static void |
michael@0 | 567 | XPC_WN_NoHelper_Finalize(js::FreeOp *fop, JSObject *obj) |
michael@0 | 568 | { |
michael@0 | 569 | WrappedNativeFinalize(fop, obj, WN_NOHELPER); |
michael@0 | 570 | } |
michael@0 | 571 | |
michael@0 | 572 | /* |
michael@0 | 573 | * General comment about XPConnect tracing: Given a C++ object |wrapper| and its |
michael@0 | 574 | * corresponding JS object |obj|, calling |wrapper->TraceSelf| will ask the JS |
michael@0 | 575 | * engine to mark |obj|. Eventually, this will lead to the trace hook being |
michael@0 | 576 | * called for |obj|. The trace hook should call |wrapper->TraceInside|, which |
michael@0 | 577 | * should mark any JS objects held by |wrapper| as members. |
michael@0 | 578 | */ |
michael@0 | 579 | |
michael@0 | 580 | static void |
michael@0 | 581 | MarkWrappedNative(JSTracer *trc, JSObject *obj) |
michael@0 | 582 | { |
michael@0 | 583 | const js::Class* clazz = js::GetObjectClass(obj); |
michael@0 | 584 | if (clazz->flags & JSCLASS_DOM_GLOBAL) { |
michael@0 | 585 | mozilla::dom::TraceProtoAndIfaceCache(trc, obj); |
michael@0 | 586 | } |
michael@0 | 587 | MOZ_ASSERT(IS_WN_CLASS(clazz)); |
michael@0 | 588 | |
michael@0 | 589 | XPCWrappedNative *wrapper = XPCWrappedNative::Get(obj); |
michael@0 | 590 | if (wrapper && wrapper->IsValid()) |
michael@0 | 591 | wrapper->TraceInside(trc); |
michael@0 | 592 | } |
michael@0 | 593 | |
michael@0 | 594 | /* static */ void |
michael@0 | 595 | XPCWrappedNative::Trace(JSTracer *trc, JSObject *obj) |
michael@0 | 596 | { |
michael@0 | 597 | MarkWrappedNative(trc, obj); |
michael@0 | 598 | } |
michael@0 | 599 | |
michael@0 | 600 | static bool |
michael@0 | 601 | XPC_WN_NoHelper_Resolve(JSContext *cx, HandleObject obj, HandleId id) |
michael@0 | 602 | { |
michael@0 | 603 | XPCCallContext ccx(JS_CALLER, cx, obj, NullPtr(), id); |
michael@0 | 604 | XPCWrappedNative* wrapper = ccx.GetWrapper(); |
michael@0 | 605 | THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); |
michael@0 | 606 | |
michael@0 | 607 | XPCNativeSet* set = ccx.GetSet(); |
michael@0 | 608 | if (!set) |
michael@0 | 609 | return true; |
michael@0 | 610 | |
michael@0 | 611 | // Don't resolve properties that are on our prototype. |
michael@0 | 612 | if (ccx.GetInterface() && !ccx.GetStaticMemberIsLocal()) |
michael@0 | 613 | return true; |
michael@0 | 614 | |
michael@0 | 615 | return DefinePropertyIfFound(ccx, obj, id, |
michael@0 | 616 | set, nullptr, nullptr, wrapper->GetScope(), |
michael@0 | 617 | true, wrapper, wrapper, nullptr, |
michael@0 | 618 | JSPROP_ENUMERATE | |
michael@0 | 619 | JSPROP_READONLY | |
michael@0 | 620 | JSPROP_PERMANENT, nullptr); |
michael@0 | 621 | } |
michael@0 | 622 | |
michael@0 | 623 | static JSObject * |
michael@0 | 624 | XPC_WN_OuterObject(JSContext *cx, HandleObject objArg) |
michael@0 | 625 | { |
michael@0 | 626 | JSObject *obj = objArg; |
michael@0 | 627 | |
michael@0 | 628 | XPCWrappedNative *wrapper = XPCWrappedNative::Get(obj); |
michael@0 | 629 | if (!wrapper) { |
michael@0 | 630 | Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); |
michael@0 | 631 | |
michael@0 | 632 | return nullptr; |
michael@0 | 633 | } |
michael@0 | 634 | |
michael@0 | 635 | if (!wrapper->IsValid()) { |
michael@0 | 636 | Throw(NS_ERROR_XPC_HAS_BEEN_SHUTDOWN, cx); |
michael@0 | 637 | |
michael@0 | 638 | return nullptr; |
michael@0 | 639 | } |
michael@0 | 640 | |
michael@0 | 641 | XPCNativeScriptableInfo* si = wrapper->GetScriptableInfo(); |
michael@0 | 642 | if (si && si->GetFlags().WantOuterObject()) { |
michael@0 | 643 | RootedObject newThis(cx); |
michael@0 | 644 | nsresult rv = |
michael@0 | 645 | si->GetCallback()->OuterObject(wrapper, cx, obj, newThis.address()); |
michael@0 | 646 | |
michael@0 | 647 | if (NS_FAILED(rv)) { |
michael@0 | 648 | Throw(rv, cx); |
michael@0 | 649 | |
michael@0 | 650 | return nullptr; |
michael@0 | 651 | } |
michael@0 | 652 | |
michael@0 | 653 | obj = newThis; |
michael@0 | 654 | } |
michael@0 | 655 | |
michael@0 | 656 | return obj; |
michael@0 | 657 | } |
michael@0 | 658 | |
michael@0 | 659 | const XPCWrappedNativeJSClass XPC_WN_NoHelper_JSClass = { |
michael@0 | 660 | { // base |
michael@0 | 661 | "XPCWrappedNative_NoHelper", // name; |
michael@0 | 662 | WRAPPER_SLOTS | |
michael@0 | 663 | JSCLASS_PRIVATE_IS_NSISUPPORTS, // flags |
michael@0 | 664 | |
michael@0 | 665 | /* Mandatory non-null function pointer members. */ |
michael@0 | 666 | XPC_WN_OnlyIWrite_AddPropertyStub, // addProperty |
michael@0 | 667 | XPC_WN_CantDeletePropertyStub, // delProperty |
michael@0 | 668 | JS_PropertyStub, // getProperty |
michael@0 | 669 | XPC_WN_OnlyIWrite_SetPropertyStub, // setProperty |
michael@0 | 670 | |
michael@0 | 671 | XPC_WN_Shared_Enumerate, // enumerate |
michael@0 | 672 | XPC_WN_NoHelper_Resolve, // resolve |
michael@0 | 673 | XPC_WN_Shared_Convert, // convert |
michael@0 | 674 | XPC_WN_NoHelper_Finalize, // finalize |
michael@0 | 675 | |
michael@0 | 676 | /* Optionally non-null members start here. */ |
michael@0 | 677 | nullptr, // call |
michael@0 | 678 | nullptr, // construct |
michael@0 | 679 | nullptr, // hasInstance |
michael@0 | 680 | XPCWrappedNative::Trace, // trace |
michael@0 | 681 | JS_NULL_CLASS_SPEC, |
michael@0 | 682 | |
michael@0 | 683 | // ClassExtension |
michael@0 | 684 | { |
michael@0 | 685 | nullptr, // outerObject |
michael@0 | 686 | nullptr, // innerObject |
michael@0 | 687 | nullptr, // iteratorObject |
michael@0 | 688 | true, // isWrappedNative |
michael@0 | 689 | }, |
michael@0 | 690 | |
michael@0 | 691 | // ObjectOps |
michael@0 | 692 | { |
michael@0 | 693 | nullptr, // lookupGeneric |
michael@0 | 694 | nullptr, // lookupProperty |
michael@0 | 695 | nullptr, // lookupElement |
michael@0 | 696 | nullptr, // defineGeneric |
michael@0 | 697 | nullptr, // defineProperty |
michael@0 | 698 | nullptr, // defineElement |
michael@0 | 699 | nullptr, // getGeneric |
michael@0 | 700 | nullptr, // getProperty |
michael@0 | 701 | nullptr, // getElement |
michael@0 | 702 | nullptr, // setGeneric |
michael@0 | 703 | nullptr, // setProperty |
michael@0 | 704 | nullptr, // setElement |
michael@0 | 705 | nullptr, // getGenericAttributes |
michael@0 | 706 | nullptr, // setGenericAttributes |
michael@0 | 707 | nullptr, // deleteProperty |
michael@0 | 708 | nullptr, // deleteElement |
michael@0 | 709 | nullptr, nullptr, // watch/unwatch |
michael@0 | 710 | nullptr, // slice |
michael@0 | 711 | XPC_WN_JSOp_Enumerate, |
michael@0 | 712 | XPC_WN_JSOp_ThisObject, |
michael@0 | 713 | } |
michael@0 | 714 | }, |
michael@0 | 715 | 0 // interfacesBitmap |
michael@0 | 716 | }; |
michael@0 | 717 | |
michael@0 | 718 | |
michael@0 | 719 | /***************************************************************************/ |
michael@0 | 720 | |
michael@0 | 721 | static bool |
michael@0 | 722 | XPC_WN_MaybeResolvingPropertyStub(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp) |
michael@0 | 723 | { |
michael@0 | 724 | XPCCallContext ccx(JS_CALLER, cx, obj); |
michael@0 | 725 | XPCWrappedNative* wrapper = ccx.GetWrapper(); |
michael@0 | 726 | THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); |
michael@0 | 727 | |
michael@0 | 728 | if (ccx.GetResolvingWrapper() == wrapper) |
michael@0 | 729 | return true; |
michael@0 | 730 | return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx); |
michael@0 | 731 | } |
michael@0 | 732 | |
michael@0 | 733 | static bool |
michael@0 | 734 | XPC_WN_MaybeResolvingStrictPropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool strict, |
michael@0 | 735 | MutableHandleValue vp) |
michael@0 | 736 | { |
michael@0 | 737 | return XPC_WN_MaybeResolvingPropertyStub(cx, obj, id, vp); |
michael@0 | 738 | } |
michael@0 | 739 | |
michael@0 | 740 | static bool |
michael@0 | 741 | XPC_WN_MaybeResolvingDeletePropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded) |
michael@0 | 742 | { |
michael@0 | 743 | XPCCallContext ccx(JS_CALLER, cx, obj); |
michael@0 | 744 | XPCWrappedNative* wrapper = ccx.GetWrapper(); |
michael@0 | 745 | THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); |
michael@0 | 746 | |
michael@0 | 747 | if (ccx.GetResolvingWrapper() == wrapper) { |
michael@0 | 748 | *succeeded = true; |
michael@0 | 749 | return true; |
michael@0 | 750 | } |
michael@0 | 751 | return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx); |
michael@0 | 752 | } |
michael@0 | 753 | |
michael@0 | 754 | // macro fun! |
michael@0 | 755 | #define PRE_HELPER_STUB \ |
michael@0 | 756 | JSObject *unwrapped = js::CheckedUnwrap(obj, false); \ |
michael@0 | 757 | if (!unwrapped) { \ |
michael@0 | 758 | JS_ReportError(cx, "Permission denied to operate on object."); \ |
michael@0 | 759 | return false; \ |
michael@0 | 760 | } \ |
michael@0 | 761 | if (!IS_WN_REFLECTOR(unwrapped)) { \ |
michael@0 | 762 | return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); \ |
michael@0 | 763 | } \ |
michael@0 | 764 | XPCWrappedNative *wrapper = XPCWrappedNative::Get(unwrapped); \ |
michael@0 | 765 | THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); \ |
michael@0 | 766 | bool retval = true; \ |
michael@0 | 767 | nsresult rv = wrapper->GetScriptableCallback()-> |
michael@0 | 768 | |
michael@0 | 769 | #define POST_HELPER_STUB \ |
michael@0 | 770 | if (NS_FAILED(rv)) \ |
michael@0 | 771 | return Throw(rv, cx); \ |
michael@0 | 772 | return retval; |
michael@0 | 773 | |
michael@0 | 774 | static bool |
michael@0 | 775 | XPC_WN_Helper_AddProperty(JSContext *cx, HandleObject obj, HandleId id, |
michael@0 | 776 | MutableHandleValue vp) |
michael@0 | 777 | { |
michael@0 | 778 | PRE_HELPER_STUB |
michael@0 | 779 | AddProperty(wrapper, cx, obj, id, vp.address(), &retval); |
michael@0 | 780 | POST_HELPER_STUB |
michael@0 | 781 | } |
michael@0 | 782 | |
michael@0 | 783 | static bool |
michael@0 | 784 | XPC_WN_Helper_DelProperty(JSContext *cx, HandleObject obj, HandleId id, |
michael@0 | 785 | bool *succeeded) |
michael@0 | 786 | { |
michael@0 | 787 | *succeeded = true; |
michael@0 | 788 | PRE_HELPER_STUB |
michael@0 | 789 | DelProperty(wrapper, cx, obj, id, &retval); |
michael@0 | 790 | POST_HELPER_STUB |
michael@0 | 791 | } |
michael@0 | 792 | |
michael@0 | 793 | bool |
michael@0 | 794 | XPC_WN_Helper_GetProperty(JSContext *cx, HandleObject obj, HandleId id, |
michael@0 | 795 | MutableHandleValue vp) |
michael@0 | 796 | { |
michael@0 | 797 | PRE_HELPER_STUB |
michael@0 | 798 | GetProperty(wrapper, cx, obj, id, vp.address(), &retval); |
michael@0 | 799 | POST_HELPER_STUB |
michael@0 | 800 | } |
michael@0 | 801 | |
michael@0 | 802 | bool |
michael@0 | 803 | XPC_WN_Helper_SetProperty(JSContext *cx, HandleObject obj, HandleId id, bool strict, |
michael@0 | 804 | MutableHandleValue vp) |
michael@0 | 805 | { |
michael@0 | 806 | PRE_HELPER_STUB |
michael@0 | 807 | SetProperty(wrapper, cx, obj, id, vp.address(), &retval); |
michael@0 | 808 | POST_HELPER_STUB |
michael@0 | 809 | } |
michael@0 | 810 | |
michael@0 | 811 | static bool |
michael@0 | 812 | XPC_WN_Helper_Convert(JSContext *cx, HandleObject obj, JSType type, MutableHandleValue vp) |
michael@0 | 813 | { |
michael@0 | 814 | PRE_HELPER_STUB |
michael@0 | 815 | Convert(wrapper, cx, obj, type, vp.address(), &retval); |
michael@0 | 816 | POST_HELPER_STUB |
michael@0 | 817 | } |
michael@0 | 818 | |
michael@0 | 819 | static bool |
michael@0 | 820 | XPC_WN_Helper_Call(JSContext *cx, unsigned argc, jsval *vp) |
michael@0 | 821 | { |
michael@0 | 822 | JS::CallArgs args = JS::CallArgsFromVp(argc, vp); |
michael@0 | 823 | // N.B. we want obj to be the callee, not JS_THIS(cx, vp) |
michael@0 | 824 | RootedObject obj(cx, &args.callee()); |
michael@0 | 825 | |
michael@0 | 826 | XPCCallContext ccx(JS_CALLER, cx, obj, NullPtr(), JSID_VOIDHANDLE, args.length(), |
michael@0 | 827 | args.array(), args.rval().address()); |
michael@0 | 828 | if (!ccx.IsValid()) |
michael@0 | 829 | return false; |
michael@0 | 830 | |
michael@0 | 831 | MOZ_ASSERT(obj == ccx.GetFlattenedJSObject()); |
michael@0 | 832 | |
michael@0 | 833 | PRE_HELPER_STUB |
michael@0 | 834 | Call(wrapper, cx, obj, args, &retval); |
michael@0 | 835 | POST_HELPER_STUB |
michael@0 | 836 | } |
michael@0 | 837 | |
michael@0 | 838 | static bool |
michael@0 | 839 | XPC_WN_Helper_Construct(JSContext *cx, unsigned argc, jsval *vp) |
michael@0 | 840 | { |
michael@0 | 841 | JS::CallArgs args = JS::CallArgsFromVp(argc, vp); |
michael@0 | 842 | RootedObject obj(cx, &args.callee()); |
michael@0 | 843 | if (!obj) |
michael@0 | 844 | return false; |
michael@0 | 845 | |
michael@0 | 846 | XPCCallContext ccx(JS_CALLER, cx, obj, NullPtr(), JSID_VOIDHANDLE, args.length(), |
michael@0 | 847 | args.array(), args.rval().address()); |
michael@0 | 848 | if (!ccx.IsValid()) |
michael@0 | 849 | return false; |
michael@0 | 850 | |
michael@0 | 851 | MOZ_ASSERT(obj == ccx.GetFlattenedJSObject()); |
michael@0 | 852 | |
michael@0 | 853 | PRE_HELPER_STUB |
michael@0 | 854 | Construct(wrapper, cx, obj, args, &retval); |
michael@0 | 855 | POST_HELPER_STUB |
michael@0 | 856 | } |
michael@0 | 857 | |
michael@0 | 858 | static bool |
michael@0 | 859 | XPC_WN_Helper_HasInstance(JSContext *cx, HandleObject obj, MutableHandleValue valp, bool *bp) |
michael@0 | 860 | { |
michael@0 | 861 | bool retval2; |
michael@0 | 862 | PRE_HELPER_STUB |
michael@0 | 863 | HasInstance(wrapper, cx, obj, valp, &retval2, &retval); |
michael@0 | 864 | *bp = retval2; |
michael@0 | 865 | POST_HELPER_STUB |
michael@0 | 866 | } |
michael@0 | 867 | |
michael@0 | 868 | static void |
michael@0 | 869 | XPC_WN_Helper_Finalize(js::FreeOp *fop, JSObject *obj) |
michael@0 | 870 | { |
michael@0 | 871 | WrappedNativeFinalize(fop, obj, WN_HELPER); |
michael@0 | 872 | } |
michael@0 | 873 | |
michael@0 | 874 | static bool |
michael@0 | 875 | XPC_WN_Helper_NewResolve(JSContext *cx, HandleObject obj, HandleId id, |
michael@0 | 876 | MutableHandleObject objp) |
michael@0 | 877 | { |
michael@0 | 878 | nsresult rv = NS_OK; |
michael@0 | 879 | bool retval = true; |
michael@0 | 880 | RootedObject obj2FromScriptable(cx); |
michael@0 | 881 | XPCCallContext ccx(JS_CALLER, cx, obj); |
michael@0 | 882 | XPCWrappedNative* wrapper = ccx.GetWrapper(); |
michael@0 | 883 | THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); |
michael@0 | 884 | |
michael@0 | 885 | RootedId old(cx, ccx.SetResolveName(id)); |
michael@0 | 886 | |
michael@0 | 887 | XPCNativeScriptableInfo* si = wrapper->GetScriptableInfo(); |
michael@0 | 888 | if (si && si->GetFlags().WantNewResolve()) { |
michael@0 | 889 | XPCWrappedNative* oldResolvingWrapper; |
michael@0 | 890 | bool allowPropMods = si->GetFlags().AllowPropModsDuringResolve(); |
michael@0 | 891 | |
michael@0 | 892 | if (allowPropMods) |
michael@0 | 893 | oldResolvingWrapper = ccx.SetResolvingWrapper(wrapper); |
michael@0 | 894 | |
michael@0 | 895 | rv = si->GetCallback()->NewResolve(wrapper, cx, obj, id, |
michael@0 | 896 | obj2FromScriptable.address(), &retval); |
michael@0 | 897 | |
michael@0 | 898 | if (allowPropMods) |
michael@0 | 899 | (void)ccx.SetResolvingWrapper(oldResolvingWrapper); |
michael@0 | 900 | } |
michael@0 | 901 | |
michael@0 | 902 | old = ccx.SetResolveName(old); |
michael@0 | 903 | MOZ_ASSERT(old == id, "bad nest"); |
michael@0 | 904 | |
michael@0 | 905 | if (NS_FAILED(rv)) { |
michael@0 | 906 | return Throw(rv, cx); |
michael@0 | 907 | } |
michael@0 | 908 | |
michael@0 | 909 | if (obj2FromScriptable) { |
michael@0 | 910 | objp.set(obj2FromScriptable); |
michael@0 | 911 | } else if (wrapper->HasMutatedSet()) { |
michael@0 | 912 | // We are here if scriptable did not resolve this property and |
michael@0 | 913 | // it *might* be in the instance set but not the proto set. |
michael@0 | 914 | |
michael@0 | 915 | XPCNativeSet* set = wrapper->GetSet(); |
michael@0 | 916 | XPCNativeSet* protoSet = wrapper->HasProto() ? |
michael@0 | 917 | wrapper->GetProto()->GetSet() : nullptr; |
michael@0 | 918 | XPCNativeMember* member; |
michael@0 | 919 | XPCNativeInterface* iface; |
michael@0 | 920 | bool IsLocal; |
michael@0 | 921 | |
michael@0 | 922 | if (set->FindMember(id, &member, &iface, protoSet, &IsLocal) && |
michael@0 | 923 | IsLocal) { |
michael@0 | 924 | XPCWrappedNative* oldResolvingWrapper; |
michael@0 | 925 | |
michael@0 | 926 | XPCNativeScriptableFlags siFlags(0); |
michael@0 | 927 | if (si) |
michael@0 | 928 | siFlags = si->GetFlags(); |
michael@0 | 929 | |
michael@0 | 930 | unsigned enumFlag = |
michael@0 | 931 | siFlags.DontEnumStaticProps() ? 0 : JSPROP_ENUMERATE; |
michael@0 | 932 | |
michael@0 | 933 | XPCWrappedNative* wrapperForInterfaceNames = |
michael@0 | 934 | siFlags.DontReflectInterfaceNames() ? nullptr : wrapper; |
michael@0 | 935 | |
michael@0 | 936 | bool resolved; |
michael@0 | 937 | oldResolvingWrapper = ccx.SetResolvingWrapper(wrapper); |
michael@0 | 938 | retval = DefinePropertyIfFound(ccx, obj, id, |
michael@0 | 939 | set, iface, member, |
michael@0 | 940 | wrapper->GetScope(), |
michael@0 | 941 | false, |
michael@0 | 942 | wrapperForInterfaceNames, |
michael@0 | 943 | nullptr, si, |
michael@0 | 944 | enumFlag, &resolved); |
michael@0 | 945 | (void)ccx.SetResolvingWrapper(oldResolvingWrapper); |
michael@0 | 946 | if (retval && resolved) |
michael@0 | 947 | objp.set(obj); |
michael@0 | 948 | } |
michael@0 | 949 | } |
michael@0 | 950 | |
michael@0 | 951 | return retval; |
michael@0 | 952 | } |
michael@0 | 953 | |
michael@0 | 954 | /***************************************************************************/ |
michael@0 | 955 | |
michael@0 | 956 | /* |
michael@0 | 957 | Here are the enumerator cases: |
michael@0 | 958 | |
michael@0 | 959 | set jsclass enumerate to stub (unless noted otherwise) |
michael@0 | 960 | |
michael@0 | 961 | if ( helper wants new enumerate ) |
michael@0 | 962 | if ( DONT_ENUM_STATICS ) |
michael@0 | 963 | forward to scriptable enumerate |
michael@0 | 964 | else |
michael@0 | 965 | if ( set not mutated ) |
michael@0 | 966 | forward to scriptable enumerate |
michael@0 | 967 | else |
michael@0 | 968 | call shared enumerate |
michael@0 | 969 | forward to scriptable enumerate |
michael@0 | 970 | else if ( helper wants old enumerate ) |
michael@0 | 971 | use this JSOp |
michael@0 | 972 | if ( DONT_ENUM_STATICS ) |
michael@0 | 973 | call scriptable enumerate |
michael@0 | 974 | call stub |
michael@0 | 975 | else |
michael@0 | 976 | if ( set not mutated ) |
michael@0 | 977 | call scriptable enumerate |
michael@0 | 978 | call stub |
michael@0 | 979 | else |
michael@0 | 980 | call shared enumerate |
michael@0 | 981 | call scriptable enumerate |
michael@0 | 982 | call stub |
michael@0 | 983 | |
michael@0 | 984 | else //... if ( helper wants NO enumerate ) |
michael@0 | 985 | if ( DONT_ENUM_STATICS ) |
michael@0 | 986 | use enumerate stub - don't use this JSOp thing at all |
michael@0 | 987 | else |
michael@0 | 988 | do shared enumerate - don't use this JSOp thing at all |
michael@0 | 989 | */ |
michael@0 | 990 | |
michael@0 | 991 | bool |
michael@0 | 992 | XPC_WN_JSOp_Enumerate(JSContext *cx, HandleObject obj, JSIterateOp enum_op, |
michael@0 | 993 | MutableHandleValue statep, MutableHandleId idp) |
michael@0 | 994 | { |
michael@0 | 995 | const js::Class *clazz = js::GetObjectClass(obj); |
michael@0 | 996 | if (!IS_WN_CLASS(clazz) || clazz == &XPC_WN_NoHelper_JSClass.base) { |
michael@0 | 997 | // obj must be a prototype object or a wrapper w/o a |
michael@0 | 998 | // helper. Short circuit this call to the default |
michael@0 | 999 | // implementation. |
michael@0 | 1000 | |
michael@0 | 1001 | return JS_EnumerateState(cx, obj, enum_op, statep, idp); |
michael@0 | 1002 | } |
michael@0 | 1003 | |
michael@0 | 1004 | XPCCallContext ccx(JS_CALLER, cx, obj); |
michael@0 | 1005 | XPCWrappedNative* wrapper = ccx.GetWrapper(); |
michael@0 | 1006 | THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); |
michael@0 | 1007 | |
michael@0 | 1008 | XPCNativeScriptableInfo* si = wrapper->GetScriptableInfo(); |
michael@0 | 1009 | if (!si) |
michael@0 | 1010 | return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); |
michael@0 | 1011 | |
michael@0 | 1012 | bool retval = true; |
michael@0 | 1013 | nsresult rv; |
michael@0 | 1014 | |
michael@0 | 1015 | if (si->GetFlags().WantNewEnumerate()) { |
michael@0 | 1016 | if (((enum_op == JSENUMERATE_INIT && |
michael@0 | 1017 | !si->GetFlags().DontEnumStaticProps()) || |
michael@0 | 1018 | enum_op == JSENUMERATE_INIT_ALL) && |
michael@0 | 1019 | wrapper->HasMutatedSet() && |
michael@0 | 1020 | !XPC_WN_Shared_Enumerate(cx, obj)) { |
michael@0 | 1021 | statep.set(JSVAL_NULL); |
michael@0 | 1022 | return false; |
michael@0 | 1023 | } |
michael@0 | 1024 | |
michael@0 | 1025 | // XXX Might we really need to wrap this call and *also* call |
michael@0 | 1026 | // js_ObjectOps.enumerate ??? |
michael@0 | 1027 | |
michael@0 | 1028 | rv = si->GetCallback()-> |
michael@0 | 1029 | NewEnumerate(wrapper, cx, obj, enum_op, statep.address(), idp.address(), &retval); |
michael@0 | 1030 | |
michael@0 | 1031 | if ((enum_op == JSENUMERATE_INIT || enum_op == JSENUMERATE_INIT_ALL) && |
michael@0 | 1032 | (NS_FAILED(rv) || !retval)) { |
michael@0 | 1033 | statep.set(JSVAL_NULL); |
michael@0 | 1034 | } |
michael@0 | 1035 | |
michael@0 | 1036 | if (NS_FAILED(rv)) |
michael@0 | 1037 | return Throw(rv, cx); |
michael@0 | 1038 | return retval; |
michael@0 | 1039 | } |
michael@0 | 1040 | |
michael@0 | 1041 | if (si->GetFlags().WantEnumerate()) { |
michael@0 | 1042 | if (enum_op == JSENUMERATE_INIT || enum_op == JSENUMERATE_INIT_ALL) { |
michael@0 | 1043 | if ((enum_op == JSENUMERATE_INIT_ALL || |
michael@0 | 1044 | !si->GetFlags().DontEnumStaticProps()) && |
michael@0 | 1045 | wrapper->HasMutatedSet() && |
michael@0 | 1046 | !XPC_WN_Shared_Enumerate(cx, obj)) { |
michael@0 | 1047 | statep.set(JSVAL_NULL); |
michael@0 | 1048 | return false; |
michael@0 | 1049 | } |
michael@0 | 1050 | rv = si->GetCallback()-> |
michael@0 | 1051 | Enumerate(wrapper, cx, obj, &retval); |
michael@0 | 1052 | |
michael@0 | 1053 | if (NS_FAILED(rv) || !retval) |
michael@0 | 1054 | statep.set(JSVAL_NULL); |
michael@0 | 1055 | |
michael@0 | 1056 | if (NS_FAILED(rv)) |
michael@0 | 1057 | return Throw(rv, cx); |
michael@0 | 1058 | if (!retval) |
michael@0 | 1059 | return false; |
michael@0 | 1060 | // Then fall through and call the default implementation... |
michael@0 | 1061 | } |
michael@0 | 1062 | } |
michael@0 | 1063 | |
michael@0 | 1064 | // else call js_ObjectOps.enumerate... |
michael@0 | 1065 | |
michael@0 | 1066 | return JS_EnumerateState(cx, obj, enum_op, statep, idp); |
michael@0 | 1067 | } |
michael@0 | 1068 | |
michael@0 | 1069 | JSObject* |
michael@0 | 1070 | XPC_WN_JSOp_ThisObject(JSContext *cx, HandleObject obj) |
michael@0 | 1071 | { |
michael@0 | 1072 | return JS_ObjectToOuterObject(cx, obj); |
michael@0 | 1073 | } |
michael@0 | 1074 | |
michael@0 | 1075 | /***************************************************************************/ |
michael@0 | 1076 | |
michael@0 | 1077 | // static |
michael@0 | 1078 | XPCNativeScriptableInfo* |
michael@0 | 1079 | XPCNativeScriptableInfo::Construct(const XPCNativeScriptableCreateInfo* sci) |
michael@0 | 1080 | { |
michael@0 | 1081 | MOZ_ASSERT(sci, "bad param"); |
michael@0 | 1082 | MOZ_ASSERT(sci->GetCallback(), "bad param"); |
michael@0 | 1083 | |
michael@0 | 1084 | XPCNativeScriptableInfo* newObj = |
michael@0 | 1085 | new XPCNativeScriptableInfo(sci->GetCallback()); |
michael@0 | 1086 | if (!newObj) |
michael@0 | 1087 | return nullptr; |
michael@0 | 1088 | |
michael@0 | 1089 | char* name = nullptr; |
michael@0 | 1090 | if (NS_FAILED(sci->GetCallback()->GetClassName(&name)) || !name) { |
michael@0 | 1091 | delete newObj; |
michael@0 | 1092 | return nullptr; |
michael@0 | 1093 | } |
michael@0 | 1094 | |
michael@0 | 1095 | bool success; |
michael@0 | 1096 | |
michael@0 | 1097 | XPCJSRuntime* rt = XPCJSRuntime::Get(); |
michael@0 | 1098 | XPCNativeScriptableSharedMap* map = rt->GetNativeScriptableSharedMap(); |
michael@0 | 1099 | success = map->GetNewOrUsed(sci->GetFlags(), name, |
michael@0 | 1100 | sci->GetInterfacesBitmap(), newObj); |
michael@0 | 1101 | |
michael@0 | 1102 | if (!success) { |
michael@0 | 1103 | delete newObj; |
michael@0 | 1104 | return nullptr; |
michael@0 | 1105 | } |
michael@0 | 1106 | |
michael@0 | 1107 | return newObj; |
michael@0 | 1108 | } |
michael@0 | 1109 | |
michael@0 | 1110 | void |
michael@0 | 1111 | XPCNativeScriptableShared::PopulateJSClass() |
michael@0 | 1112 | { |
michael@0 | 1113 | MOZ_ASSERT(mJSClass.base.name, "bad state!"); |
michael@0 | 1114 | |
michael@0 | 1115 | mJSClass.base.flags = WRAPPER_SLOTS | |
michael@0 | 1116 | JSCLASS_PRIVATE_IS_NSISUPPORTS | |
michael@0 | 1117 | JSCLASS_NEW_RESOLVE; |
michael@0 | 1118 | |
michael@0 | 1119 | if (mFlags.IsGlobalObject()) |
michael@0 | 1120 | mJSClass.base.flags |= XPCONNECT_GLOBAL_FLAGS; |
michael@0 | 1121 | |
michael@0 | 1122 | JSPropertyOp addProperty; |
michael@0 | 1123 | if (mFlags.WantAddProperty()) |
michael@0 | 1124 | addProperty = XPC_WN_Helper_AddProperty; |
michael@0 | 1125 | else if (mFlags.UseJSStubForAddProperty()) |
michael@0 | 1126 | addProperty = JS_PropertyStub; |
michael@0 | 1127 | else if (mFlags.AllowPropModsDuringResolve()) |
michael@0 | 1128 | addProperty = XPC_WN_MaybeResolvingPropertyStub; |
michael@0 | 1129 | else |
michael@0 | 1130 | addProperty = XPC_WN_CannotModifyPropertyStub; |
michael@0 | 1131 | mJSClass.base.addProperty = addProperty; |
michael@0 | 1132 | |
michael@0 | 1133 | JSDeletePropertyOp delProperty; |
michael@0 | 1134 | if (mFlags.WantDelProperty()) |
michael@0 | 1135 | delProperty = XPC_WN_Helper_DelProperty; |
michael@0 | 1136 | else if (mFlags.UseJSStubForDelProperty()) |
michael@0 | 1137 | delProperty = JS_DeletePropertyStub; |
michael@0 | 1138 | else if (mFlags.AllowPropModsDuringResolve()) |
michael@0 | 1139 | delProperty = XPC_WN_MaybeResolvingDeletePropertyStub; |
michael@0 | 1140 | else |
michael@0 | 1141 | delProperty = XPC_WN_CantDeletePropertyStub; |
michael@0 | 1142 | mJSClass.base.delProperty = delProperty; |
michael@0 | 1143 | |
michael@0 | 1144 | if (mFlags.WantGetProperty()) |
michael@0 | 1145 | mJSClass.base.getProperty = XPC_WN_Helper_GetProperty; |
michael@0 | 1146 | else |
michael@0 | 1147 | mJSClass.base.getProperty = JS_PropertyStub; |
michael@0 | 1148 | |
michael@0 | 1149 | JSStrictPropertyOp setProperty; |
michael@0 | 1150 | if (mFlags.WantSetProperty()) |
michael@0 | 1151 | setProperty = XPC_WN_Helper_SetProperty; |
michael@0 | 1152 | else if (mFlags.UseJSStubForSetProperty()) |
michael@0 | 1153 | setProperty = JS_StrictPropertyStub; |
michael@0 | 1154 | else if (mFlags.AllowPropModsDuringResolve()) |
michael@0 | 1155 | setProperty = XPC_WN_MaybeResolvingStrictPropertyStub; |
michael@0 | 1156 | else |
michael@0 | 1157 | setProperty = XPC_WN_CannotModifyStrictPropertyStub; |
michael@0 | 1158 | mJSClass.base.setProperty = setProperty; |
michael@0 | 1159 | |
michael@0 | 1160 | // We figure out most of the enumerate strategy at call time. |
michael@0 | 1161 | |
michael@0 | 1162 | if (mFlags.WantNewEnumerate() || mFlags.WantEnumerate() || |
michael@0 | 1163 | mFlags.DontEnumStaticProps()) |
michael@0 | 1164 | mJSClass.base.enumerate = JS_EnumerateStub; |
michael@0 | 1165 | else |
michael@0 | 1166 | mJSClass.base.enumerate = XPC_WN_Shared_Enumerate; |
michael@0 | 1167 | |
michael@0 | 1168 | // We have to figure out resolve strategy at call time |
michael@0 | 1169 | mJSClass.base.resolve = (JSResolveOp) XPC_WN_Helper_NewResolve; |
michael@0 | 1170 | |
michael@0 | 1171 | // We need to respect content-defined toString() hooks on Window objects. |
michael@0 | 1172 | // In particular, js::DefaultValue checks for a convert stub, and the one |
michael@0 | 1173 | // we would install below ignores anything implemented in JS. |
michael@0 | 1174 | // |
michael@0 | 1175 | // We've always had this behavior for most XPCWrappedNative-implemented |
michael@0 | 1176 | // objects. However, Window was special, because the outer-window proxy |
michael@0 | 1177 | // had a null convert hook, which means that we'd end up with the default |
michael@0 | 1178 | // JS-engine behavior (which respects toString() overrides). We've fixed |
michael@0 | 1179 | // the convert hook on the outer-window proxy to invoke the defaultValue |
michael@0 | 1180 | // hook on the proxy, which in this case invokes js::DefaultValue on the |
michael@0 | 1181 | // target. So now we need to special-case this for Window to maintain |
michael@0 | 1182 | // consistent behavior. This can go away once Window is on WebIDL bindings. |
michael@0 | 1183 | // |
michael@0 | 1184 | // Note that WantOuterObject() is true if and only if this is a Window object. |
michael@0 | 1185 | if (mFlags.WantConvert()) |
michael@0 | 1186 | mJSClass.base.convert = XPC_WN_Helper_Convert; |
michael@0 | 1187 | else if (mFlags.WantOuterObject()) |
michael@0 | 1188 | mJSClass.base.convert = JS_ConvertStub; |
michael@0 | 1189 | else |
michael@0 | 1190 | mJSClass.base.convert = XPC_WN_Shared_Convert; |
michael@0 | 1191 | |
michael@0 | 1192 | if (mFlags.WantFinalize()) |
michael@0 | 1193 | mJSClass.base.finalize = XPC_WN_Helper_Finalize; |
michael@0 | 1194 | else |
michael@0 | 1195 | mJSClass.base.finalize = XPC_WN_NoHelper_Finalize; |
michael@0 | 1196 | |
michael@0 | 1197 | js::ObjectOps *ops = &mJSClass.base.ops; |
michael@0 | 1198 | ops->enumerate = XPC_WN_JSOp_Enumerate; |
michael@0 | 1199 | ops->thisObject = XPC_WN_JSOp_ThisObject; |
michael@0 | 1200 | |
michael@0 | 1201 | |
michael@0 | 1202 | if (mFlags.WantCall()) |
michael@0 | 1203 | mJSClass.base.call = XPC_WN_Helper_Call; |
michael@0 | 1204 | if (mFlags.WantConstruct()) |
michael@0 | 1205 | mJSClass.base.construct = XPC_WN_Helper_Construct; |
michael@0 | 1206 | |
michael@0 | 1207 | if (mFlags.WantHasInstance()) |
michael@0 | 1208 | mJSClass.base.hasInstance = XPC_WN_Helper_HasInstance; |
michael@0 | 1209 | |
michael@0 | 1210 | if (mFlags.IsGlobalObject()) |
michael@0 | 1211 | mJSClass.base.trace = JS_GlobalObjectTraceHook; |
michael@0 | 1212 | else |
michael@0 | 1213 | mJSClass.base.trace = XPCWrappedNative::Trace; |
michael@0 | 1214 | |
michael@0 | 1215 | if (mFlags.WantOuterObject()) |
michael@0 | 1216 | mJSClass.base.ext.outerObject = XPC_WN_OuterObject; |
michael@0 | 1217 | |
michael@0 | 1218 | mJSClass.base.ext.isWrappedNative = true; |
michael@0 | 1219 | } |
michael@0 | 1220 | |
michael@0 | 1221 | /***************************************************************************/ |
michael@0 | 1222 | /***************************************************************************/ |
michael@0 | 1223 | |
michael@0 | 1224 | // Compatibility hack. |
michael@0 | 1225 | // |
michael@0 | 1226 | // XPConnect used to do all sorts of funny tricks to find the "correct" |
michael@0 | 1227 | // |this| object for a given method (often to the detriment of proper |
michael@0 | 1228 | // call/apply). When these tricks were removed, a fair amount of chrome |
michael@0 | 1229 | // code broke, because it was relying on being able to grab methods off |
michael@0 | 1230 | // some XPCOM object (like the nsITelemetry service) and invoke them without |
michael@0 | 1231 | // a proper |this|. So, if it's quite clear that we're in this situation and |
michael@0 | 1232 | // about to use a |this| argument that just won't work, fix things up. |
michael@0 | 1233 | // |
michael@0 | 1234 | // This hack is only useful for getters/setters if someone sets an XPCOM object |
michael@0 | 1235 | // as the prototype for a vanilla JS object and expects the XPCOM attributes to |
michael@0 | 1236 | // work on the derived object, which we really don't want to support. But we |
michael@0 | 1237 | // handle it anyway, for now, to minimize regression risk on an already-risky |
michael@0 | 1238 | // landing. |
michael@0 | 1239 | // |
michael@0 | 1240 | // This hack is mainly useful for the NoHelper JSClass. We also fix up |
michael@0 | 1241 | // Components.utils because it implements nsIXPCScriptable (giving it a custom |
michael@0 | 1242 | // JSClass) but not nsIClassInfo (which would put the methods on a prototype). |
michael@0 | 1243 | |
michael@0 | 1244 | #define IS_NOHELPER_CLASS(clasp) (clasp == &XPC_WN_NoHelper_JSClass.base) |
michael@0 | 1245 | #define IS_CU_CLASS(clasp) (clasp->name[0] == 'n' && !strcmp(clasp->name, "nsXPCComponents_Utils")) |
michael@0 | 1246 | |
michael@0 | 1247 | MOZ_ALWAYS_INLINE JSObject* |
michael@0 | 1248 | FixUpThisIfBroken(JSObject *obj, JSObject *funobj) |
michael@0 | 1249 | { |
michael@0 | 1250 | if (funobj) { |
michael@0 | 1251 | const js::Class *parentClass = js::GetObjectClass(js::GetObjectParent(funobj)); |
michael@0 | 1252 | if (MOZ_UNLIKELY((IS_NOHELPER_CLASS(parentClass) || IS_CU_CLASS(parentClass)) && |
michael@0 | 1253 | (js::GetObjectClass(obj) != parentClass))) |
michael@0 | 1254 | { |
michael@0 | 1255 | return js::GetObjectParent(funobj); |
michael@0 | 1256 | } |
michael@0 | 1257 | } |
michael@0 | 1258 | return obj; |
michael@0 | 1259 | } |
michael@0 | 1260 | |
michael@0 | 1261 | bool |
michael@0 | 1262 | XPC_WN_CallMethod(JSContext *cx, unsigned argc, jsval *vp) |
michael@0 | 1263 | { |
michael@0 | 1264 | JS::CallArgs args = JS::CallArgsFromVp(argc, vp); |
michael@0 | 1265 | MOZ_ASSERT(JS_TypeOfValue(cx, args.calleev()) == JSTYPE_FUNCTION, "bad function"); |
michael@0 | 1266 | RootedObject funobj(cx, &args.callee()); |
michael@0 | 1267 | |
michael@0 | 1268 | RootedObject obj(cx, JS_THIS_OBJECT(cx, vp)); |
michael@0 | 1269 | if (!obj) |
michael@0 | 1270 | return false; |
michael@0 | 1271 | |
michael@0 | 1272 | obj = FixUpThisIfBroken(obj, funobj); |
michael@0 | 1273 | XPCCallContext ccx(JS_CALLER, cx, obj, funobj, JSID_VOIDHANDLE, args.length(), |
michael@0 | 1274 | args.array(), vp); |
michael@0 | 1275 | XPCWrappedNative* wrapper = ccx.GetWrapper(); |
michael@0 | 1276 | THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); |
michael@0 | 1277 | |
michael@0 | 1278 | XPCNativeInterface* iface; |
michael@0 | 1279 | XPCNativeMember* member; |
michael@0 | 1280 | |
michael@0 | 1281 | if (!XPCNativeMember::GetCallInfo(funobj, &iface, &member)) |
michael@0 | 1282 | return Throw(NS_ERROR_XPC_CANT_GET_METHOD_INFO, cx); |
michael@0 | 1283 | ccx.SetCallInfo(iface, member, false); |
michael@0 | 1284 | return XPCWrappedNative::CallMethod(ccx); |
michael@0 | 1285 | } |
michael@0 | 1286 | |
michael@0 | 1287 | bool |
michael@0 | 1288 | XPC_WN_GetterSetter(JSContext *cx, unsigned argc, jsval *vp) |
michael@0 | 1289 | { |
michael@0 | 1290 | JS::CallArgs args = JS::CallArgsFromVp(argc, vp); |
michael@0 | 1291 | MOZ_ASSERT(JS_TypeOfValue(cx, args.calleev()) == JSTYPE_FUNCTION, "bad function"); |
michael@0 | 1292 | RootedObject funobj(cx, &args.callee()); |
michael@0 | 1293 | |
michael@0 | 1294 | RootedObject obj(cx, JS_THIS_OBJECT(cx, vp)); |
michael@0 | 1295 | if (!obj) |
michael@0 | 1296 | return false; |
michael@0 | 1297 | |
michael@0 | 1298 | obj = FixUpThisIfBroken(obj, funobj); |
michael@0 | 1299 | XPCCallContext ccx(JS_CALLER, cx, obj, funobj, JSID_VOIDHANDLE, args.length(), |
michael@0 | 1300 | args.array(), vp); |
michael@0 | 1301 | XPCWrappedNative* wrapper = ccx.GetWrapper(); |
michael@0 | 1302 | THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); |
michael@0 | 1303 | |
michael@0 | 1304 | XPCNativeInterface* iface; |
michael@0 | 1305 | XPCNativeMember* member; |
michael@0 | 1306 | |
michael@0 | 1307 | if (!XPCNativeMember::GetCallInfo(funobj, &iface, &member)) |
michael@0 | 1308 | return Throw(NS_ERROR_XPC_CANT_GET_METHOD_INFO, cx); |
michael@0 | 1309 | |
michael@0 | 1310 | if (args.length() != 0 && member->IsWritableAttribute()) { |
michael@0 | 1311 | ccx.SetCallInfo(iface, member, true); |
michael@0 | 1312 | bool retval = XPCWrappedNative::SetAttribute(ccx); |
michael@0 | 1313 | if (retval) |
michael@0 | 1314 | args.rval().set(args[0]); |
michael@0 | 1315 | return retval; |
michael@0 | 1316 | } |
michael@0 | 1317 | // else... |
michael@0 | 1318 | |
michael@0 | 1319 | ccx.SetCallInfo(iface, member, false); |
michael@0 | 1320 | return XPCWrappedNative::GetAttribute(ccx); |
michael@0 | 1321 | } |
michael@0 | 1322 | |
michael@0 | 1323 | /***************************************************************************/ |
michael@0 | 1324 | |
michael@0 | 1325 | static bool |
michael@0 | 1326 | XPC_WN_Shared_Proto_Enumerate(JSContext *cx, HandleObject obj) |
michael@0 | 1327 | { |
michael@0 | 1328 | MOZ_ASSERT(js::GetObjectClass(obj) == &XPC_WN_ModsAllowed_WithCall_Proto_JSClass || |
michael@0 | 1329 | js::GetObjectClass(obj) == &XPC_WN_ModsAllowed_NoCall_Proto_JSClass || |
michael@0 | 1330 | js::GetObjectClass(obj) == &XPC_WN_NoMods_WithCall_Proto_JSClass || |
michael@0 | 1331 | js::GetObjectClass(obj) == &XPC_WN_NoMods_NoCall_Proto_JSClass, |
michael@0 | 1332 | "bad proto"); |
michael@0 | 1333 | XPCWrappedNativeProto* self = |
michael@0 | 1334 | (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj); |
michael@0 | 1335 | if (!self) |
michael@0 | 1336 | return false; |
michael@0 | 1337 | |
michael@0 | 1338 | if (self->GetScriptableInfo() && |
michael@0 | 1339 | self->GetScriptableInfo()->GetFlags().DontEnumStaticProps()) |
michael@0 | 1340 | return true; |
michael@0 | 1341 | |
michael@0 | 1342 | XPCNativeSet* set = self->GetSet(); |
michael@0 | 1343 | if (!set) |
michael@0 | 1344 | return false; |
michael@0 | 1345 | |
michael@0 | 1346 | XPCCallContext ccx(JS_CALLER, cx); |
michael@0 | 1347 | if (!ccx.IsValid()) |
michael@0 | 1348 | return false; |
michael@0 | 1349 | |
michael@0 | 1350 | uint16_t interface_count = set->GetInterfaceCount(); |
michael@0 | 1351 | XPCNativeInterface** interfaceArray = set->GetInterfaceArray(); |
michael@0 | 1352 | for (uint16_t i = 0; i < interface_count; i++) { |
michael@0 | 1353 | XPCNativeInterface* iface = interfaceArray[i]; |
michael@0 | 1354 | uint16_t member_count = iface->GetMemberCount(); |
michael@0 | 1355 | |
michael@0 | 1356 | for (uint16_t k = 0; k < member_count; k++) { |
michael@0 | 1357 | if (!xpc_ForcePropertyResolve(cx, obj, iface->GetMemberAt(k)->GetName())) |
michael@0 | 1358 | return false; |
michael@0 | 1359 | } |
michael@0 | 1360 | } |
michael@0 | 1361 | |
michael@0 | 1362 | return true; |
michael@0 | 1363 | } |
michael@0 | 1364 | |
michael@0 | 1365 | static void |
michael@0 | 1366 | XPC_WN_Shared_Proto_Finalize(js::FreeOp *fop, JSObject *obj) |
michael@0 | 1367 | { |
michael@0 | 1368 | // This can be null if xpc shutdown has already happened |
michael@0 | 1369 | XPCWrappedNativeProto* p = (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj); |
michael@0 | 1370 | if (p) |
michael@0 | 1371 | p->JSProtoObjectFinalized(fop, obj); |
michael@0 | 1372 | } |
michael@0 | 1373 | |
michael@0 | 1374 | static void |
michael@0 | 1375 | XPC_WN_Shared_Proto_Trace(JSTracer *trc, JSObject *obj) |
michael@0 | 1376 | { |
michael@0 | 1377 | // This can be null if xpc shutdown has already happened |
michael@0 | 1378 | XPCWrappedNativeProto* p = |
michael@0 | 1379 | (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj); |
michael@0 | 1380 | if (p) |
michael@0 | 1381 | p->TraceInside(trc); |
michael@0 | 1382 | } |
michael@0 | 1383 | |
michael@0 | 1384 | /*****************************************************/ |
michael@0 | 1385 | |
michael@0 | 1386 | static bool |
michael@0 | 1387 | XPC_WN_ModsAllowed_Proto_Resolve(JSContext *cx, HandleObject obj, HandleId id) |
michael@0 | 1388 | { |
michael@0 | 1389 | MOZ_ASSERT(js::GetObjectClass(obj) == &XPC_WN_ModsAllowed_WithCall_Proto_JSClass || |
michael@0 | 1390 | js::GetObjectClass(obj) == &XPC_WN_ModsAllowed_NoCall_Proto_JSClass, |
michael@0 | 1391 | "bad proto"); |
michael@0 | 1392 | |
michael@0 | 1393 | XPCWrappedNativeProto* self = |
michael@0 | 1394 | (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj); |
michael@0 | 1395 | if (!self) |
michael@0 | 1396 | return false; |
michael@0 | 1397 | |
michael@0 | 1398 | XPCCallContext ccx(JS_CALLER, cx); |
michael@0 | 1399 | if (!ccx.IsValid()) |
michael@0 | 1400 | return false; |
michael@0 | 1401 | |
michael@0 | 1402 | XPCNativeScriptableInfo* si = self->GetScriptableInfo(); |
michael@0 | 1403 | unsigned enumFlag = (si && si->GetFlags().DontEnumStaticProps()) ? |
michael@0 | 1404 | 0 : JSPROP_ENUMERATE; |
michael@0 | 1405 | |
michael@0 | 1406 | return DefinePropertyIfFound(ccx, obj, id, |
michael@0 | 1407 | self->GetSet(), nullptr, nullptr, |
michael@0 | 1408 | self->GetScope(), |
michael@0 | 1409 | true, nullptr, nullptr, si, |
michael@0 | 1410 | enumFlag, nullptr); |
michael@0 | 1411 | } |
michael@0 | 1412 | |
michael@0 | 1413 | const js::Class XPC_WN_ModsAllowed_WithCall_Proto_JSClass = { |
michael@0 | 1414 | "XPC_WN_ModsAllowed_WithCall_Proto_JSClass", // name; |
michael@0 | 1415 | WRAPPER_SLOTS, // flags; |
michael@0 | 1416 | |
michael@0 | 1417 | /* Mandatory non-null function pointer members. */ |
michael@0 | 1418 | JS_PropertyStub, // addProperty; |
michael@0 | 1419 | JS_DeletePropertyStub, // delProperty; |
michael@0 | 1420 | JS_PropertyStub, // getProperty; |
michael@0 | 1421 | JS_StrictPropertyStub, // setProperty; |
michael@0 | 1422 | XPC_WN_Shared_Proto_Enumerate, // enumerate; |
michael@0 | 1423 | XPC_WN_ModsAllowed_Proto_Resolve, // resolve; |
michael@0 | 1424 | JS_ConvertStub, // convert; |
michael@0 | 1425 | XPC_WN_Shared_Proto_Finalize, // finalize; |
michael@0 | 1426 | |
michael@0 | 1427 | /* Optionally non-null members start here. */ |
michael@0 | 1428 | nullptr, // call; |
michael@0 | 1429 | nullptr, // construct; |
michael@0 | 1430 | nullptr, // hasInstance; |
michael@0 | 1431 | XPC_WN_Shared_Proto_Trace, // trace; |
michael@0 | 1432 | |
michael@0 | 1433 | JS_NULL_CLASS_SPEC, |
michael@0 | 1434 | JS_NULL_CLASS_EXT, |
michael@0 | 1435 | XPC_WN_WithCall_ObjectOps |
michael@0 | 1436 | }; |
michael@0 | 1437 | |
michael@0 | 1438 | const js::Class XPC_WN_ModsAllowed_NoCall_Proto_JSClass = { |
michael@0 | 1439 | "XPC_WN_ModsAllowed_NoCall_Proto_JSClass", // name; |
michael@0 | 1440 | WRAPPER_SLOTS, // flags; |
michael@0 | 1441 | |
michael@0 | 1442 | /* Mandatory non-null function pointer members. */ |
michael@0 | 1443 | JS_PropertyStub, // addProperty; |
michael@0 | 1444 | JS_DeletePropertyStub, // delProperty; |
michael@0 | 1445 | JS_PropertyStub, // getProperty; |
michael@0 | 1446 | JS_StrictPropertyStub, // setProperty; |
michael@0 | 1447 | XPC_WN_Shared_Proto_Enumerate, // enumerate; |
michael@0 | 1448 | XPC_WN_ModsAllowed_Proto_Resolve, // resolve; |
michael@0 | 1449 | JS_ConvertStub, // convert; |
michael@0 | 1450 | XPC_WN_Shared_Proto_Finalize, // finalize; |
michael@0 | 1451 | |
michael@0 | 1452 | /* Optionally non-null members start here. */ |
michael@0 | 1453 | nullptr, // call; |
michael@0 | 1454 | nullptr, // construct; |
michael@0 | 1455 | nullptr, // hasInstance; |
michael@0 | 1456 | XPC_WN_Shared_Proto_Trace, // trace; |
michael@0 | 1457 | |
michael@0 | 1458 | JS_NULL_CLASS_SPEC, |
michael@0 | 1459 | JS_NULL_CLASS_EXT, |
michael@0 | 1460 | XPC_WN_NoCall_ObjectOps |
michael@0 | 1461 | }; |
michael@0 | 1462 | |
michael@0 | 1463 | /***************************************************************************/ |
michael@0 | 1464 | |
michael@0 | 1465 | static bool |
michael@0 | 1466 | XPC_WN_OnlyIWrite_Proto_AddPropertyStub(JSContext *cx, HandleObject obj, HandleId id, |
michael@0 | 1467 | MutableHandleValue vp) |
michael@0 | 1468 | { |
michael@0 | 1469 | MOZ_ASSERT(js::GetObjectClass(obj) == &XPC_WN_NoMods_WithCall_Proto_JSClass || |
michael@0 | 1470 | js::GetObjectClass(obj) == &XPC_WN_NoMods_NoCall_Proto_JSClass, |
michael@0 | 1471 | "bad proto"); |
michael@0 | 1472 | |
michael@0 | 1473 | XPCWrappedNativeProto* self = |
michael@0 | 1474 | (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj); |
michael@0 | 1475 | if (!self) |
michael@0 | 1476 | return false; |
michael@0 | 1477 | |
michael@0 | 1478 | XPCCallContext ccx(JS_CALLER, cx); |
michael@0 | 1479 | if (!ccx.IsValid()) |
michael@0 | 1480 | return false; |
michael@0 | 1481 | |
michael@0 | 1482 | // Allow XPConnect to add the property only |
michael@0 | 1483 | if (ccx.GetResolveName() == id) |
michael@0 | 1484 | return true; |
michael@0 | 1485 | |
michael@0 | 1486 | return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); |
michael@0 | 1487 | } |
michael@0 | 1488 | |
michael@0 | 1489 | static bool |
michael@0 | 1490 | XPC_WN_OnlyIWrite_Proto_SetPropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool strict, |
michael@0 | 1491 | MutableHandleValue vp) |
michael@0 | 1492 | { |
michael@0 | 1493 | return XPC_WN_OnlyIWrite_Proto_AddPropertyStub(cx, obj, id, vp); |
michael@0 | 1494 | } |
michael@0 | 1495 | |
michael@0 | 1496 | static bool |
michael@0 | 1497 | XPC_WN_NoMods_Proto_Resolve(JSContext *cx, HandleObject obj, HandleId id) |
michael@0 | 1498 | { |
michael@0 | 1499 | MOZ_ASSERT(js::GetObjectClass(obj) == &XPC_WN_NoMods_WithCall_Proto_JSClass || |
michael@0 | 1500 | js::GetObjectClass(obj) == &XPC_WN_NoMods_NoCall_Proto_JSClass, |
michael@0 | 1501 | "bad proto"); |
michael@0 | 1502 | |
michael@0 | 1503 | XPCWrappedNativeProto* self = |
michael@0 | 1504 | (XPCWrappedNativeProto*) xpc_GetJSPrivate(obj); |
michael@0 | 1505 | if (!self) |
michael@0 | 1506 | return false; |
michael@0 | 1507 | |
michael@0 | 1508 | XPCCallContext ccx(JS_CALLER, cx); |
michael@0 | 1509 | if (!ccx.IsValid()) |
michael@0 | 1510 | return false; |
michael@0 | 1511 | |
michael@0 | 1512 | XPCNativeScriptableInfo* si = self->GetScriptableInfo(); |
michael@0 | 1513 | unsigned enumFlag = (si && si->GetFlags().DontEnumStaticProps()) ? |
michael@0 | 1514 | 0 : JSPROP_ENUMERATE; |
michael@0 | 1515 | |
michael@0 | 1516 | return DefinePropertyIfFound(ccx, obj, id, |
michael@0 | 1517 | self->GetSet(), nullptr, nullptr, |
michael@0 | 1518 | self->GetScope(), |
michael@0 | 1519 | true, nullptr, nullptr, si, |
michael@0 | 1520 | JSPROP_READONLY | |
michael@0 | 1521 | JSPROP_PERMANENT | |
michael@0 | 1522 | enumFlag, nullptr); |
michael@0 | 1523 | } |
michael@0 | 1524 | |
michael@0 | 1525 | const js::Class XPC_WN_NoMods_WithCall_Proto_JSClass = { |
michael@0 | 1526 | "XPC_WN_NoMods_WithCall_Proto_JSClass", // name; |
michael@0 | 1527 | WRAPPER_SLOTS, // flags; |
michael@0 | 1528 | |
michael@0 | 1529 | /* Mandatory non-null function pointer members. */ |
michael@0 | 1530 | XPC_WN_OnlyIWrite_Proto_AddPropertyStub, // addProperty; |
michael@0 | 1531 | XPC_WN_CantDeletePropertyStub, // delProperty; |
michael@0 | 1532 | JS_PropertyStub, // getProperty; |
michael@0 | 1533 | XPC_WN_OnlyIWrite_Proto_SetPropertyStub, // setProperty; |
michael@0 | 1534 | XPC_WN_Shared_Proto_Enumerate, // enumerate; |
michael@0 | 1535 | XPC_WN_NoMods_Proto_Resolve, // resolve; |
michael@0 | 1536 | JS_ConvertStub, // convert; |
michael@0 | 1537 | XPC_WN_Shared_Proto_Finalize, // finalize; |
michael@0 | 1538 | |
michael@0 | 1539 | /* Optionally non-null members start here. */ |
michael@0 | 1540 | nullptr, // call; |
michael@0 | 1541 | nullptr, // construct; |
michael@0 | 1542 | nullptr, // hasInstance; |
michael@0 | 1543 | XPC_WN_Shared_Proto_Trace, // trace; |
michael@0 | 1544 | |
michael@0 | 1545 | JS_NULL_CLASS_SPEC, |
michael@0 | 1546 | JS_NULL_CLASS_EXT, |
michael@0 | 1547 | XPC_WN_WithCall_ObjectOps |
michael@0 | 1548 | }; |
michael@0 | 1549 | |
michael@0 | 1550 | const js::Class XPC_WN_NoMods_NoCall_Proto_JSClass = { |
michael@0 | 1551 | "XPC_WN_NoMods_NoCall_Proto_JSClass", // name; |
michael@0 | 1552 | WRAPPER_SLOTS, // flags; |
michael@0 | 1553 | |
michael@0 | 1554 | /* Mandatory non-null function pointer members. */ |
michael@0 | 1555 | XPC_WN_OnlyIWrite_Proto_AddPropertyStub, // addProperty; |
michael@0 | 1556 | XPC_WN_CantDeletePropertyStub, // delProperty; |
michael@0 | 1557 | JS_PropertyStub, // getProperty; |
michael@0 | 1558 | XPC_WN_OnlyIWrite_Proto_SetPropertyStub, // setProperty; |
michael@0 | 1559 | XPC_WN_Shared_Proto_Enumerate, // enumerate; |
michael@0 | 1560 | XPC_WN_NoMods_Proto_Resolve, // resolve; |
michael@0 | 1561 | JS_ConvertStub, // convert; |
michael@0 | 1562 | XPC_WN_Shared_Proto_Finalize, // finalize; |
michael@0 | 1563 | |
michael@0 | 1564 | /* Optionally non-null members start here. */ |
michael@0 | 1565 | nullptr, // call; |
michael@0 | 1566 | nullptr, // construct; |
michael@0 | 1567 | nullptr, // hasInstance; |
michael@0 | 1568 | XPC_WN_Shared_Proto_Trace, // trace; |
michael@0 | 1569 | |
michael@0 | 1570 | JS_NULL_CLASS_SPEC, |
michael@0 | 1571 | JS_NULL_CLASS_EXT, |
michael@0 | 1572 | XPC_WN_NoCall_ObjectOps |
michael@0 | 1573 | }; |
michael@0 | 1574 | |
michael@0 | 1575 | /***************************************************************************/ |
michael@0 | 1576 | |
michael@0 | 1577 | static bool |
michael@0 | 1578 | XPC_WN_TearOff_Enumerate(JSContext *cx, HandleObject obj) |
michael@0 | 1579 | { |
michael@0 | 1580 | XPCCallContext ccx(JS_CALLER, cx, obj); |
michael@0 | 1581 | XPCWrappedNative* wrapper = ccx.GetWrapper(); |
michael@0 | 1582 | THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); |
michael@0 | 1583 | |
michael@0 | 1584 | XPCWrappedNativeTearOff* to = ccx.GetTearOff(); |
michael@0 | 1585 | XPCNativeInterface* iface; |
michael@0 | 1586 | |
michael@0 | 1587 | if (!to || nullptr == (iface = to->GetInterface())) |
michael@0 | 1588 | return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); |
michael@0 | 1589 | |
michael@0 | 1590 | uint16_t member_count = iface->GetMemberCount(); |
michael@0 | 1591 | for (uint16_t k = 0; k < member_count; k++) { |
michael@0 | 1592 | if (!xpc_ForcePropertyResolve(cx, obj, iface->GetMemberAt(k)->GetName())) |
michael@0 | 1593 | return false; |
michael@0 | 1594 | } |
michael@0 | 1595 | |
michael@0 | 1596 | return true; |
michael@0 | 1597 | } |
michael@0 | 1598 | |
michael@0 | 1599 | static bool |
michael@0 | 1600 | XPC_WN_TearOff_Resolve(JSContext *cx, HandleObject obj, HandleId id) |
michael@0 | 1601 | { |
michael@0 | 1602 | XPCCallContext ccx(JS_CALLER, cx, obj); |
michael@0 | 1603 | XPCWrappedNative* wrapper = ccx.GetWrapper(); |
michael@0 | 1604 | THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); |
michael@0 | 1605 | |
michael@0 | 1606 | XPCWrappedNativeTearOff* to = ccx.GetTearOff(); |
michael@0 | 1607 | XPCNativeInterface* iface; |
michael@0 | 1608 | |
michael@0 | 1609 | if (!to || nullptr == (iface = to->GetInterface())) |
michael@0 | 1610 | return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); |
michael@0 | 1611 | |
michael@0 | 1612 | return DefinePropertyIfFound(ccx, obj, id, nullptr, iface, nullptr, |
michael@0 | 1613 | wrapper->GetScope(), |
michael@0 | 1614 | true, nullptr, nullptr, nullptr, |
michael@0 | 1615 | JSPROP_READONLY | |
michael@0 | 1616 | JSPROP_PERMANENT | |
michael@0 | 1617 | JSPROP_ENUMERATE, nullptr); |
michael@0 | 1618 | } |
michael@0 | 1619 | |
michael@0 | 1620 | static void |
michael@0 | 1621 | XPC_WN_TearOff_Finalize(js::FreeOp *fop, JSObject *obj) |
michael@0 | 1622 | { |
michael@0 | 1623 | XPCWrappedNativeTearOff* p = (XPCWrappedNativeTearOff*) |
michael@0 | 1624 | xpc_GetJSPrivate(obj); |
michael@0 | 1625 | if (!p) |
michael@0 | 1626 | return; |
michael@0 | 1627 | p->JSObjectFinalized(); |
michael@0 | 1628 | } |
michael@0 | 1629 | |
michael@0 | 1630 | const js::Class XPC_WN_Tearoff_JSClass = { |
michael@0 | 1631 | "WrappedNative_TearOff", // name; |
michael@0 | 1632 | WRAPPER_SLOTS, // flags; |
michael@0 | 1633 | |
michael@0 | 1634 | XPC_WN_OnlyIWrite_AddPropertyStub, // addProperty; |
michael@0 | 1635 | XPC_WN_CantDeletePropertyStub, // delProperty; |
michael@0 | 1636 | JS_PropertyStub, // getProperty; |
michael@0 | 1637 | XPC_WN_OnlyIWrite_SetPropertyStub, // setProperty; |
michael@0 | 1638 | XPC_WN_TearOff_Enumerate, // enumerate; |
michael@0 | 1639 | XPC_WN_TearOff_Resolve, // resolve; |
michael@0 | 1640 | XPC_WN_Shared_Convert, // convert; |
michael@0 | 1641 | XPC_WN_TearOff_Finalize // finalize; |
michael@0 | 1642 | }; |