js/xpconnect/src/XPCQuickStubs.h

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rw-r--r--

Back out 97036ab72558 which inappropriately compared turds to third parties.

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 #ifndef xpcquickstubs_h___
michael@0 8 #define xpcquickstubs_h___
michael@0 9
michael@0 10 #include "XPCForwards.h"
michael@0 11
michael@0 12 class qsObjectHelper;
michael@0 13 namespace mozilla {
michael@0 14 namespace dom {
michael@0 15 class NativePropertiesHolder;
michael@0 16 }
michael@0 17 }
michael@0 18
michael@0 19 /* XPCQuickStubs.h - Support functions used only by quick stubs. */
michael@0 20
michael@0 21 class XPCCallContext;
michael@0 22
michael@0 23 #define XPC_QS_NULL_INDEX ((uint16_t) -1)
michael@0 24
michael@0 25 struct xpc_qsPropertySpec {
michael@0 26 uint16_t name_index;
michael@0 27 JSNative getter;
michael@0 28 JSNative setter;
michael@0 29 };
michael@0 30
michael@0 31 struct xpc_qsFunctionSpec {
michael@0 32 uint16_t name_index;
michael@0 33 uint16_t arity;
michael@0 34 JSNative native;
michael@0 35 };
michael@0 36
michael@0 37 /** A table mapping interfaces to quick stubs. */
michael@0 38 struct xpc_qsHashEntry {
michael@0 39 nsID iid;
michael@0 40 uint16_t prop_index;
michael@0 41 uint16_t n_props;
michael@0 42 uint16_t func_index;
michael@0 43 uint16_t n_funcs;
michael@0 44 const mozilla::dom::NativePropertiesHolder* newBindingProperties;
michael@0 45 // These last two fields index to other entries in the same table.
michael@0 46 // XPC_QS_NULL_ENTRY indicates there are no more entries in the chain.
michael@0 47 uint16_t parentInterface;
michael@0 48 uint16_t chain;
michael@0 49 };
michael@0 50
michael@0 51 bool
michael@0 52 xpc_qsDefineQuickStubs(JSContext *cx, JSObject *proto, unsigned extraFlags,
michael@0 53 uint32_t ifacec, const nsIID **interfaces,
michael@0 54 uint32_t tableSize, const xpc_qsHashEntry *table,
michael@0 55 const xpc_qsPropertySpec *propspecs,
michael@0 56 const xpc_qsFunctionSpec *funcspecs,
michael@0 57 const char *stringTable);
michael@0 58
michael@0 59 /** Raise an exception on @a cx and return false. */
michael@0 60 bool
michael@0 61 xpc_qsThrow(JSContext *cx, nsresult rv);
michael@0 62
michael@0 63 /**
michael@0 64 * Fail after an XPCOM getter or setter returned rv.
michael@0 65 *
michael@0 66 * NOTE: Here @a obj must be the JSObject whose private data field points to an
michael@0 67 * XPCWrappedNative, not merely an object that has an XPCWrappedNative
michael@0 68 * somewhere along the prototype chain! The same applies to @a obj in
michael@0 69 * xpc_qsThrowBadSetterValue and <code>vp[1]</code> in xpc_qsThrowMethodFailed
michael@0 70 * and xpc_qsThrowBadArg.
michael@0 71 *
michael@0 72 * This is one reason the UnwrapThis functions below have an out parameter that
michael@0 73 * receives the wrapper JSObject. (The other reason is to help the caller keep
michael@0 74 * that JSObject GC-reachable.)
michael@0 75 */
michael@0 76 bool
michael@0 77 xpc_qsThrowGetterSetterFailed(JSContext *cx, nsresult rv,
michael@0 78 JSObject *obj, jsid memberId);
michael@0 79 // And variants using strings and string tables
michael@0 80 bool
michael@0 81 xpc_qsThrowGetterSetterFailed(JSContext *cx, nsresult rv,
michael@0 82 JSObject *obj, const char* memberName);
michael@0 83 bool
michael@0 84 xpc_qsThrowGetterSetterFailed(JSContext *cx, nsresult rv,
michael@0 85 JSObject *obj, uint16_t memberIndex);
michael@0 86
michael@0 87 /**
michael@0 88 * Fail after an XPCOM method returned rv.
michael@0 89 *
michael@0 90 * See NOTE at xpc_qsThrowGetterSetterFailed.
michael@0 91 */
michael@0 92 bool
michael@0 93 xpc_qsThrowMethodFailed(JSContext *cx, nsresult rv, jsval *vp);
michael@0 94
michael@0 95 /**
michael@0 96 * Fail after converting a method argument fails.
michael@0 97 *
michael@0 98 * See NOTE at xpc_qsThrowGetterSetterFailed.
michael@0 99 */
michael@0 100 void
michael@0 101 xpc_qsThrowBadArg(JSContext *cx, nsresult rv, jsval *vp, unsigned paramnum);
michael@0 102
michael@0 103 void
michael@0 104 xpc_qsThrowBadArgWithCcx(XPCCallContext &ccx, nsresult rv, unsigned paramnum);
michael@0 105
michael@0 106 void
michael@0 107 xpc_qsThrowBadArgWithDetails(JSContext *cx, nsresult rv, unsigned paramnum,
michael@0 108 const char *ifaceName, const char *memberName);
michael@0 109
michael@0 110 /**
michael@0 111 * Fail after converting a setter argument fails.
michael@0 112 *
michael@0 113 * See NOTE at xpc_qsThrowGetterSetterFailed.
michael@0 114 */
michael@0 115 void
michael@0 116 xpc_qsThrowBadSetterValue(JSContext *cx, nsresult rv, JSObject *obj,
michael@0 117 jsid propId);
michael@0 118 // And variants using strings and string tables
michael@0 119 void
michael@0 120 xpc_qsThrowBadSetterValue(JSContext *cx, nsresult rv, JSObject *obj,
michael@0 121 const char* propName);
michael@0 122 void
michael@0 123 xpc_qsThrowBadSetterValue(JSContext *cx, nsresult rv, JSObject *obj,
michael@0 124 uint16_t name_index);
michael@0 125
michael@0 126
michael@0 127 bool
michael@0 128 xpc_qsGetterOnlyPropertyStub(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
michael@0 129 bool strict, JS::MutableHandleValue vp);
michael@0 130
michael@0 131 bool
michael@0 132 xpc_qsGetterOnlyNativeStub(JSContext *cx, unsigned argc, jsval *vp);
michael@0 133
michael@0 134 /* Functions for converting values between COM and JS. */
michael@0 135
michael@0 136 inline bool
michael@0 137 xpc_qsInt64ToJsval(JSContext *cx, int64_t i, JS::MutableHandleValue rv)
michael@0 138 {
michael@0 139 rv.setNumber(static_cast<double>(i));
michael@0 140 return true;
michael@0 141 }
michael@0 142
michael@0 143 inline bool
michael@0 144 xpc_qsUint64ToJsval(JSContext *cx, uint64_t u, JS::MutableHandleValue rv)
michael@0 145 {
michael@0 146 rv.setNumber(static_cast<double>(u));
michael@0 147 return true;
michael@0 148 }
michael@0 149
michael@0 150
michael@0 151 /* Classes for converting jsvals to string types. */
michael@0 152
michael@0 153 template <class S, class T>
michael@0 154 class xpc_qsBasicString
michael@0 155 {
michael@0 156 public:
michael@0 157 typedef S interface_type;
michael@0 158 typedef T implementation_type;
michael@0 159
michael@0 160 ~xpc_qsBasicString()
michael@0 161 {
michael@0 162 if (mValid)
michael@0 163 Ptr()->~implementation_type();
michael@0 164 }
michael@0 165
michael@0 166 bool IsValid() const { return mValid; }
michael@0 167
michael@0 168 implementation_type *Ptr()
michael@0 169 {
michael@0 170 MOZ_ASSERT(mValid);
michael@0 171 return reinterpret_cast<implementation_type *>(mBuf);
michael@0 172 }
michael@0 173
michael@0 174 const implementation_type *Ptr() const
michael@0 175 {
michael@0 176 MOZ_ASSERT(mValid);
michael@0 177 return reinterpret_cast<const implementation_type *>(mBuf);
michael@0 178 }
michael@0 179
michael@0 180 operator interface_type &()
michael@0 181 {
michael@0 182 MOZ_ASSERT(mValid);
michael@0 183 return *Ptr();
michael@0 184 }
michael@0 185
michael@0 186 operator const interface_type &() const
michael@0 187 {
michael@0 188 MOZ_ASSERT(mValid);
michael@0 189 return *Ptr();
michael@0 190 }
michael@0 191
michael@0 192 /* Enum that defines how JS |null| and |undefined| should be treated. See
michael@0 193 * the WebIDL specification. eStringify means convert to the string "null"
michael@0 194 * or "undefined" respectively, via the standard JS ToString() operation;
michael@0 195 * eEmpty means convert to the string ""; eNull means convert to an empty
michael@0 196 * string with the void bit set.
michael@0 197 *
michael@0 198 * Per webidl the default behavior of an unannotated interface is
michael@0 199 * eStringify, but our de-facto behavior has been eNull for |null| and
michael@0 200 * eStringify for |undefined|, so leaving it that way for now. If we ever
michael@0 201 * get to a point where we go through and annotate our interfaces as
michael@0 202 * needed, we can change that.
michael@0 203 */
michael@0 204 enum StringificationBehavior {
michael@0 205 eStringify,
michael@0 206 eEmpty,
michael@0 207 eNull,
michael@0 208 eDefaultNullBehavior = eNull,
michael@0 209 eDefaultUndefinedBehavior = eStringify
michael@0 210 };
michael@0 211
michael@0 212 protected:
michael@0 213 /*
michael@0 214 * Neither field is initialized; that is left to the derived class
michael@0 215 * constructor. However, the destructor destroys the string object
michael@0 216 * stored in mBuf, if mValid is true.
michael@0 217 */
michael@0 218 void *mBuf[JS_HOWMANY(sizeof(implementation_type), sizeof(void *))];
michael@0 219 bool mValid;
michael@0 220
michael@0 221 /*
michael@0 222 * If null is returned, then we either failed or fully initialized
michael@0 223 * |this|; in either case the caller should return immediately
michael@0 224 * without doing anything else. Otherwise, the JSString* created
michael@0 225 * from |v| will be returned. It'll be rooted, as needed, in
michael@0 226 * *pval. nullBehavior and undefinedBehavior control what happens
michael@0 227 * when |v| is JSVAL_IS_NULL and JSVAL_IS_VOID respectively.
michael@0 228 */
michael@0 229 template<class traits>
michael@0 230 JSString* InitOrStringify(JSContext* cx, JS::HandleValue v,
michael@0 231 JS::MutableHandleValue pval,
michael@0 232 bool notpassed,
michael@0 233 StringificationBehavior nullBehavior,
michael@0 234 StringificationBehavior undefinedBehavior) {
michael@0 235 JSString *s;
michael@0 236 if (JSVAL_IS_STRING(v)) {
michael@0 237 s = JSVAL_TO_STRING(v);
michael@0 238 } else {
michael@0 239 StringificationBehavior behavior = eStringify;
michael@0 240 if (JSVAL_IS_NULL(v)) {
michael@0 241 behavior = nullBehavior;
michael@0 242 } else if (JSVAL_IS_VOID(v)) {
michael@0 243 behavior = undefinedBehavior;
michael@0 244 }
michael@0 245
michael@0 246 // If pval is null, that means the argument was optional and
michael@0 247 // not passed; turn those into void strings if they're
michael@0 248 // supposed to be stringified.
michael@0 249 if (behavior != eStringify || notpassed) {
michael@0 250 // Here behavior == eStringify implies notpassed, so both eNull and
michael@0 251 // eStringify should end up with void strings.
michael@0 252 (new(mBuf) implementation_type(traits::sEmptyBuffer, uint32_t(0)))->
michael@0 253 SetIsVoid(behavior != eEmpty);
michael@0 254 mValid = true;
michael@0 255 return nullptr;
michael@0 256 }
michael@0 257
michael@0 258 s = JS::ToString(cx, v);
michael@0 259 if (!s) {
michael@0 260 mValid = false;
michael@0 261 return nullptr;
michael@0 262 }
michael@0 263 pval.setString(s); // Root the new string.
michael@0 264 }
michael@0 265
michael@0 266 return s;
michael@0 267 }
michael@0 268 };
michael@0 269
michael@0 270 /**
michael@0 271 * Class for converting a jsval to DOMString.
michael@0 272 *
michael@0 273 * xpc_qsDOMString arg0(cx, &argv[0]);
michael@0 274 * if (!arg0.IsValid())
michael@0 275 * return false;
michael@0 276 *
michael@0 277 * The second argument to the constructor is an in-out parameter. It must
michael@0 278 * point to a rooted jsval, such as a JSNative argument or return value slot.
michael@0 279 * The value in the jsval on entry is converted to a string. The constructor
michael@0 280 * may overwrite that jsval with a string value, to protect the characters of
michael@0 281 * the string from garbage collection. The caller must leave the jsval alone
michael@0 282 * for the lifetime of the xpc_qsDOMString.
michael@0 283 */
michael@0 284 class xpc_qsDOMString : public xpc_qsBasicString<nsAString, nsDependentString>
michael@0 285 {
michael@0 286 public:
michael@0 287 xpc_qsDOMString(JSContext *cx, JS::HandleValue v,
michael@0 288 JS::MutableHandleValue pval, bool notpassed,
michael@0 289 StringificationBehavior nullBehavior,
michael@0 290 StringificationBehavior undefinedBehavior);
michael@0 291 };
michael@0 292
michael@0 293 /**
michael@0 294 * The same as xpc_qsDOMString, but with slightly different conversion behavior,
michael@0 295 * corresponding to the [astring] magic XPIDL annotation rather than [domstring].
michael@0 296 */
michael@0 297 class xpc_qsAString : public xpc_qsDOMString
michael@0 298 {
michael@0 299 public:
michael@0 300 xpc_qsAString(JSContext *cx, JS::HandleValue v,
michael@0 301 JS::MutableHandleValue pval, bool notpassed)
michael@0 302 : xpc_qsDOMString(cx, v, pval, notpassed, eNull, eNull)
michael@0 303 {}
michael@0 304 };
michael@0 305
michael@0 306 /**
michael@0 307 * Like xpc_qsDOMString and xpc_qsAString, but for XPIDL native types annotated
michael@0 308 * with [cstring] rather than [domstring] or [astring].
michael@0 309 */
michael@0 310 class xpc_qsACString : public xpc_qsBasicString<nsACString, nsCString>
michael@0 311 {
michael@0 312 public:
michael@0 313 xpc_qsACString(JSContext *cx, JS::HandleValue v,
michael@0 314 JS::MutableHandleValue pval, bool notpassed,
michael@0 315 StringificationBehavior nullBehavior = eNull,
michael@0 316 StringificationBehavior undefinedBehavior = eNull);
michael@0 317 };
michael@0 318
michael@0 319 /**
michael@0 320 * And similar for AUTF8String.
michael@0 321 */
michael@0 322 class xpc_qsAUTF8String :
michael@0 323 public xpc_qsBasicString<nsACString, NS_ConvertUTF16toUTF8>
michael@0 324 {
michael@0 325 public:
michael@0 326 xpc_qsAUTF8String(JSContext* cx, JS::HandleValue v,
michael@0 327 JS::MutableHandleValue pval, bool notpassed);
michael@0 328 };
michael@0 329
michael@0 330 struct xpc_qsSelfRef
michael@0 331 {
michael@0 332 xpc_qsSelfRef() : ptr(nullptr) {}
michael@0 333 explicit xpc_qsSelfRef(nsISupports *p) : ptr(p) {}
michael@0 334 ~xpc_qsSelfRef() { NS_IF_RELEASE(ptr); }
michael@0 335
michael@0 336 nsISupports* ptr;
michael@0 337 };
michael@0 338
michael@0 339 /**
michael@0 340 * Convert a jsval to char*, returning true on success.
michael@0 341 *
michael@0 342 * @param cx
michael@0 343 * A context.
michael@0 344 * @param v
michael@0 345 * A value to convert.
michael@0 346 * @param bytes
michael@0 347 * Out. On success it receives the converted string unless v is null or
michael@0 348 * undefinedin which case bytes->ptr() remains null.
michael@0 349 */
michael@0 350 bool
michael@0 351 xpc_qsJsvalToCharStr(JSContext *cx, jsval v, JSAutoByteString *bytes);
michael@0 352
michael@0 353 bool
michael@0 354 xpc_qsJsvalToWcharStr(JSContext *cx, jsval v, JS::MutableHandleValue pval, const char16_t **pstr);
michael@0 355
michael@0 356
michael@0 357 nsresult
michael@0 358 getWrapper(JSContext *cx,
michael@0 359 JSObject *obj,
michael@0 360 XPCWrappedNative **wrapper,
michael@0 361 JSObject **cur,
michael@0 362 XPCWrappedNativeTearOff **tearoff);
michael@0 363
michael@0 364 nsresult
michael@0 365 castNative(JSContext *cx,
michael@0 366 XPCWrappedNative *wrapper,
michael@0 367 JSObject *cur,
michael@0 368 XPCWrappedNativeTearOff *tearoff,
michael@0 369 const nsIID &iid,
michael@0 370 void **ppThis,
michael@0 371 nsISupports **ppThisRef,
michael@0 372 JS::MutableHandleValue vp);
michael@0 373
michael@0 374 /**
michael@0 375 * Search @a obj and its prototype chain for an XPCOM object that implements
michael@0 376 * the interface T.
michael@0 377 *
michael@0 378 * If an object implementing T is found, store a reference to the wrapper
michael@0 379 * JSObject in @a *pThisVal, store a pointer to the T in @a *ppThis, and return
michael@0 380 * true. Otherwise, raise an exception on @a cx and return false.
michael@0 381 *
michael@0 382 * @a *pThisRef receives the same pointer as *ppThis if the T was AddRefed.
michael@0 383 * Otherwise it receives null (even on error).
michael@0 384 *
michael@0 385 * This supports split objects and XPConnect tear-offs and it sees through
michael@0 386 * XOWs, XPCNativeWrappers, and SafeJSObjectWrappers.
michael@0 387 *
michael@0 388 * Requires a request on @a cx.
michael@0 389 */
michael@0 390 template <class T>
michael@0 391 inline bool
michael@0 392 xpc_qsUnwrapThis(JSContext *cx,
michael@0 393 JS::HandleObject obj,
michael@0 394 T **ppThis,
michael@0 395 nsISupports **pThisRef,
michael@0 396 JS::MutableHandleValue pThisVal,
michael@0 397 bool failureFatal = true)
michael@0 398 {
michael@0 399 XPCWrappedNative *wrapper;
michael@0 400 XPCWrappedNativeTearOff *tearoff;
michael@0 401 JS::RootedObject current(cx);
michael@0 402 nsresult rv = getWrapper(cx, obj, &wrapper, current.address(), &tearoff);
michael@0 403 if (NS_SUCCEEDED(rv))
michael@0 404 rv = castNative(cx, wrapper, current, tearoff, NS_GET_TEMPLATE_IID(T),
michael@0 405 reinterpret_cast<void **>(ppThis), pThisRef, pThisVal);
michael@0 406
michael@0 407 if (failureFatal)
michael@0 408 return NS_SUCCEEDED(rv) || xpc_qsThrow(cx, rv);
michael@0 409
michael@0 410 if (NS_FAILED(rv))
michael@0 411 *ppThis = nullptr;
michael@0 412 return true;
michael@0 413 }
michael@0 414
michael@0 415 nsISupports*
michael@0 416 castNativeFromWrapper(JSContext *cx,
michael@0 417 JSObject *obj,
michael@0 418 uint32_t interfaceBit,
michael@0 419 uint32_t protoID,
michael@0 420 int32_t protoDepth,
michael@0 421 nsISupports **pRef,
michael@0 422 JS::MutableHandleValue pVal,
michael@0 423 nsresult *rv);
michael@0 424
michael@0 425 bool
michael@0 426 xpc_qsUnwrapThisFromCcxImpl(XPCCallContext &ccx,
michael@0 427 const nsIID &iid,
michael@0 428 void **ppThis,
michael@0 429 nsISupports **pThisRef,
michael@0 430 JS::MutableHandleValue vp);
michael@0 431
michael@0 432 /**
michael@0 433 * Alternate implementation of xpc_qsUnwrapThis using information already
michael@0 434 * present in the given XPCCallContext.
michael@0 435 */
michael@0 436 template <class T>
michael@0 437 inline bool
michael@0 438 xpc_qsUnwrapThisFromCcx(XPCCallContext &ccx,
michael@0 439 T **ppThis,
michael@0 440 nsISupports **pThisRef,
michael@0 441 JS::MutableHandleValue pThisVal)
michael@0 442 {
michael@0 443 return xpc_qsUnwrapThisFromCcxImpl(ccx,
michael@0 444 NS_GET_TEMPLATE_IID(T),
michael@0 445 reinterpret_cast<void **>(ppThis),
michael@0 446 pThisRef,
michael@0 447 pThisVal);
michael@0 448 }
michael@0 449
michael@0 450 MOZ_ALWAYS_INLINE JSObject*
michael@0 451 xpc_qsUnwrapObj(jsval v, nsISupports **ppArgRef, nsresult *rv)
michael@0 452 {
michael@0 453 *rv = NS_OK;
michael@0 454 if (v.isObject()) {
michael@0 455 return &v.toObject();
michael@0 456 }
michael@0 457
michael@0 458 if (!v.isNullOrUndefined()) {
michael@0 459 *rv = ((v.isInt32() && v.toInt32() == 0)
michael@0 460 ? NS_ERROR_XPC_BAD_CONVERT_JS_ZERO_ISNOT_NULL
michael@0 461 : NS_ERROR_XPC_BAD_CONVERT_JS);
michael@0 462 }
michael@0 463
michael@0 464 *ppArgRef = nullptr;
michael@0 465 return nullptr;
michael@0 466 }
michael@0 467
michael@0 468 nsresult
michael@0 469 xpc_qsUnwrapArgImpl(JSContext *cx, JS::HandleValue v, const nsIID &iid, void **ppArg,
michael@0 470 nsISupports **ppArgRef, JS::MutableHandleValue vp);
michael@0 471
michael@0 472 /** Convert a jsval to an XPCOM pointer. */
michael@0 473 template <class Interface, class StrongRefType>
michael@0 474 inline nsresult
michael@0 475 xpc_qsUnwrapArg(JSContext *cx, JS::HandleValue v, Interface **ppArg,
michael@0 476 StrongRefType **ppArgRef, JS::MutableHandleValue vp)
michael@0 477 {
michael@0 478 nsISupports* argRef = *ppArgRef;
michael@0 479 nsresult rv = xpc_qsUnwrapArgImpl(cx, v, NS_GET_TEMPLATE_IID(Interface),
michael@0 480 reinterpret_cast<void **>(ppArg), &argRef,
michael@0 481 vp);
michael@0 482 *ppArgRef = static_cast<StrongRefType*>(argRef);
michael@0 483 return rv;
michael@0 484 }
michael@0 485
michael@0 486 MOZ_ALWAYS_INLINE nsISupports*
michael@0 487 castNativeArgFromWrapper(JSContext *cx,
michael@0 488 jsval v,
michael@0 489 uint32_t bit,
michael@0 490 uint32_t protoID,
michael@0 491 int32_t protoDepth,
michael@0 492 nsISupports **pArgRef,
michael@0 493 JS::MutableHandleValue vp,
michael@0 494 nsresult *rv)
michael@0 495 {
michael@0 496 JSObject *src = xpc_qsUnwrapObj(v, pArgRef, rv);
michael@0 497 if (!src)
michael@0 498 return nullptr;
michael@0 499
michael@0 500 return castNativeFromWrapper(cx, src, bit, protoID, protoDepth, pArgRef, vp, rv);
michael@0 501 }
michael@0 502
michael@0 503 inline nsWrapperCache*
michael@0 504 xpc_qsGetWrapperCache(nsWrapperCache *cache)
michael@0 505 {
michael@0 506 return cache;
michael@0 507 }
michael@0 508
michael@0 509 inline nsWrapperCache*
michael@0 510 xpc_qsGetWrapperCache(void *p)
michael@0 511 {
michael@0 512 return nullptr;
michael@0 513 }
michael@0 514
michael@0 515 /** Convert an XPCOM pointer to jsval. Return true on success.
michael@0 516 * aIdentity is a performance optimization. Set it to true,
michael@0 517 * only if p is the identity pointer.
michael@0 518 */
michael@0 519 bool
michael@0 520 xpc_qsXPCOMObjectToJsval(JSContext *aCx,
michael@0 521 qsObjectHelper &aHelper,
michael@0 522 const nsIID *iid,
michael@0 523 XPCNativeInterface **iface,
michael@0 524 JS::MutableHandleValue rval);
michael@0 525
michael@0 526 /**
michael@0 527 * Convert a variant to jsval. Return true on success.
michael@0 528 */
michael@0 529 bool
michael@0 530 xpc_qsVariantToJsval(JSContext *cx,
michael@0 531 nsIVariant *p,
michael@0 532 JS::MutableHandleValue rval);
michael@0 533
michael@0 534 #ifdef DEBUG
michael@0 535 void
michael@0 536 xpc_qsAssertContextOK(JSContext *cx);
michael@0 537
michael@0 538 inline bool
michael@0 539 xpc_qsSameResult(nsISupports *result1, nsISupports *result2)
michael@0 540 {
michael@0 541 return SameCOMIdentity(result1, result2);
michael@0 542 }
michael@0 543
michael@0 544 inline bool
michael@0 545 xpc_qsSameResult(const nsString &result1, const nsString &result2)
michael@0 546 {
michael@0 547 return result1.Equals(result2);
michael@0 548 }
michael@0 549
michael@0 550 inline bool
michael@0 551 xpc_qsSameResult(int32_t result1, int32_t result2)
michael@0 552 {
michael@0 553 return result1 == result2;
michael@0 554 }
michael@0 555
michael@0 556 #define XPC_QS_ASSERT_CONTEXT_OK(cx) xpc_qsAssertContextOK(cx)
michael@0 557 #else
michael@0 558 #define XPC_QS_ASSERT_CONTEXT_OK(cx) ((void) 0)
michael@0 559 #endif
michael@0 560
michael@0 561 // Apply |op| to |obj|, |id|, and |vp|. If |op| is a setter, treat the assignment as lenient.
michael@0 562 template<typename Op>
michael@0 563 inline bool ApplyPropertyOp(JSContext *cx, Op op, JS::HandleObject obj, JS::HandleId id,
michael@0 564 JS::MutableHandleValue vp);
michael@0 565
michael@0 566 template<>
michael@0 567 inline bool
michael@0 568 ApplyPropertyOp<JSPropertyOp>(JSContext *cx, JSPropertyOp op, JS::HandleObject obj, JS::HandleId id,
michael@0 569 JS::MutableHandleValue vp)
michael@0 570 {
michael@0 571 return op(cx, obj, id, vp);
michael@0 572 }
michael@0 573
michael@0 574 template<>
michael@0 575 inline bool
michael@0 576 ApplyPropertyOp<JSStrictPropertyOp>(JSContext *cx, JSStrictPropertyOp op, JS::HandleObject obj,
michael@0 577 JS::HandleId id, JS::MutableHandleValue vp)
michael@0 578 {
michael@0 579 return op(cx, obj, id, true, vp);
michael@0 580 }
michael@0 581
michael@0 582 template<typename Op>
michael@0 583 bool
michael@0 584 PropertyOpForwarder(JSContext *cx, unsigned argc, jsval *vp)
michael@0 585 {
michael@0 586 // Layout:
michael@0 587 // this = our this
michael@0 588 // property op to call = callee reserved slot 0
michael@0 589 // name of the property = callee reserved slot 1
michael@0 590
michael@0 591 JS::CallArgs args = CallArgsFromVp(argc, vp);
michael@0 592
michael@0 593 JS::RootedObject callee(cx, &args.callee());
michael@0 594 JS::RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));
michael@0 595 if (!obj)
michael@0 596 return false;
michael@0 597
michael@0 598 JS::RootedValue v(cx, js::GetFunctionNativeReserved(callee, 0));
michael@0 599
michael@0 600 JSObject *ptrobj = JSVAL_TO_OBJECT(v);
michael@0 601 Op *popp = static_cast<Op *>(JS_GetPrivate(ptrobj));
michael@0 602
michael@0 603 v = js::GetFunctionNativeReserved(callee, 1);
michael@0 604
michael@0 605 JS::RootedValue argval(cx, args.get(0));
michael@0 606 JS::RootedId id(cx);
michael@0 607 if (!JS_ValueToId(cx, v, &id))
michael@0 608 return false;
michael@0 609 args.rval().set(argval);
michael@0 610 return ApplyPropertyOp<Op>(cx, *popp, obj, id, args.rval());
michael@0 611 }
michael@0 612
michael@0 613 extern const JSClass PointerHolderClass;
michael@0 614
michael@0 615 template<typename Op>
michael@0 616 JSObject *
michael@0 617 GeneratePropertyOp(JSContext *cx, JS::HandleObject obj, JS::HandleId id, unsigned argc, Op pop)
michael@0 618 {
michael@0 619 // The JS engine provides two reserved slots on function objects for
michael@0 620 // XPConnect to use. Use them to stick the necessary info here.
michael@0 621 JSFunction *fun =
michael@0 622 js::NewFunctionByIdWithReserved(cx, PropertyOpForwarder<Op>, argc, 0, obj, id);
michael@0 623 if (!fun)
michael@0 624 return nullptr;
michael@0 625
michael@0 626 JS::RootedObject funobj(cx, JS_GetFunctionObject(fun));
michael@0 627
michael@0 628 // Unfortunately, we cannot guarantee that Op is aligned. Use a
michael@0 629 // second object to work around this.
michael@0 630 JSObject *ptrobj = JS_NewObject(cx, &PointerHolderClass, JS::NullPtr(), funobj);
michael@0 631 if (!ptrobj)
michael@0 632 return nullptr;
michael@0 633 Op *popp = new Op;
michael@0 634 if (!popp)
michael@0 635 return nullptr;
michael@0 636 *popp = pop;
michael@0 637 JS_SetPrivate(ptrobj, popp);
michael@0 638
michael@0 639 js::SetFunctionNativeReserved(funobj, 0, OBJECT_TO_JSVAL(ptrobj));
michael@0 640 js::SetFunctionNativeReserved(funobj, 1, js::IdToValue(id));
michael@0 641 return funobj;
michael@0 642 }
michael@0 643
michael@0 644 #endif /* xpcquickstubs_h___ */

mercurial