XPCJSID.cpp (22029B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* An xpcom implementation of the JavaScript nsIID and nsCID objects. */ 8 9 #include "xpcprivate.h" 10 #include "mozilla/dom/BindingUtils.h" 11 #include "js/Object.h" // JS::GetClass, JS::GetReservedSlot 12 #include "js/PropertyAndElement.h" // JS_DefineFunction, JS_DefineFunctionById, JS_DefineProperty, JS_DefinePropertyById 13 #include "js/Symbol.h" 14 #include "nsContentUtils.h" 15 16 using namespace mozilla; 17 using namespace mozilla::dom; 18 using namespace JS; 19 20 namespace xpc { 21 22 /****************************************************************************** 23 * # Generic IDs # 24 * 25 * Generic IDs are the type of JS object created by most code which passes nsID 26 * objects to JavaScript code. They provide no special methods, and only store 27 * the raw nsID value. 28 * 29 * The nsID value is stored in 4 reserved slots, with 32 bits of the 128-bit 30 * value stored in each slot. Getter code extracts this data, and combines them 31 * back into the nsID value. 32 */ 33 static bool ID_Equals(JSContext* aCx, unsigned aArgc, Value* aVp); 34 static bool ID_GetNumber(JSContext* aCx, unsigned aArgc, Value* aVp); 35 36 // Generic ID objects contain 4 reserved slots, each containing a uint32_t with 37 // 1/4 of the representation of the nsID value. This allows us to avoid an extra 38 // allocation for the nsID object, and eliminates the need for a finalizer. 39 enum { kID_Slot0, kID_Slot1, kID_Slot2, kID_Slot3, kID_SlotCount }; 40 static const JSClass sID_Class = { 41 "nsJSID", JSCLASS_HAS_RESERVED_SLOTS(kID_SlotCount), JS_NULL_CLASS_OPS}; 42 43 /****************************************************************************** 44 * # Interface IDs # 45 * 46 * In addition to the properties exposed by Generic ID objects, IID supports 47 * 'instanceof', exposes constant properties defined on the class, and exposes 48 * the interface name as the 'name' and 'toString()' values. 49 */ 50 static bool IID_HasInstance(JSContext* aCx, unsigned aArgc, Value* aVp); 51 static bool IID_GetName(JSContext* aCx, unsigned aArgc, Value* aVp); 52 53 static bool IID_NewEnumerate(JSContext* cx, HandleObject obj, 54 MutableHandleIdVector properties, 55 bool enumerableOnly); 56 static bool IID_Resolve(JSContext* cx, HandleObject obj, HandleId id, 57 bool* resolvedp); 58 static bool IID_MayResolve(const JSAtomState& names, jsid id, 59 JSObject* maybeObj); 60 61 static const JSClassOps sIID_ClassOps = { 62 nullptr, // addProperty 63 nullptr, // delProperty 64 nullptr, // enumerate 65 IID_NewEnumerate, // newEnumerate 66 IID_Resolve, // resolve 67 IID_MayResolve, // mayResolve 68 nullptr, // finalize 69 nullptr, // call 70 nullptr, // construct 71 nullptr, // trace 72 }; 73 74 // Interface ID objects use a single reserved slot containing a pointer to the 75 // nsXPTInterfaceInfo object for the interface in question. 76 enum { kIID_InfoSlot, kIID_SlotCount }; 77 static const JSClass sIID_Class = { 78 "nsJSIID", JSCLASS_HAS_RESERVED_SLOTS(kIID_SlotCount), &sIID_ClassOps}; 79 80 /****************************************************************************** 81 * # Contract IDs # 82 * 83 * In addition to the properties exposed by Generic ID objects, Contract IDs 84 * expose 'getService' and 'createInstance' methods, and expose the contractID 85 * string as '.name' and '.toString()'. 86 */ 87 static bool CID_CreateInstance(JSContext* aCx, unsigned aArgc, Value* aVp); 88 static bool CID_GetService(JSContext* aCx, unsigned aArgc, Value* aVp); 89 static bool CID_GetName(JSContext* aCx, unsigned aArgc, Value* aVp); 90 91 // ContractID objects use a single reserved slot, containing the ContractID. The 92 // nsCID value for this object is looked up when the object is being unwrapped. 93 enum { kCID_ContractSlot, kCID_SlotCount }; 94 static const JSClass sCID_Class = { 95 "nsJSCID", JSCLASS_HAS_RESERVED_SLOTS(kCID_SlotCount), JS_NULL_CLASS_OPS}; 96 97 /** 98 * Ensure that the nsID prototype objects have been created for the current 99 * global, and extract the prototype values. 100 */ 101 static JSObject* GetIDPrototype(JSContext* aCx, const JSClass* aClass) { 102 XPCWrappedNativeScope* scope = ObjectScope(CurrentGlobalOrNull(aCx)); 103 if (NS_WARN_IF(!scope)) { 104 return nullptr; 105 } 106 107 // Create prototype objects for the JSID objects if they haven't been 108 // created for this scope yet. 109 if (!scope->mIDProto) { 110 MOZ_ASSERT(!scope->mIIDProto && !scope->mCIDProto); 111 112 RootedObject idProto(aCx, JS_NewPlainObject(aCx)); 113 RootedObject iidProto(aCx, 114 JS_NewObjectWithGivenProto(aCx, nullptr, idProto)); 115 RootedObject cidProto(aCx, 116 JS_NewObjectWithGivenProto(aCx, nullptr, idProto)); 117 RootedId hasInstance(aCx, 118 GetWellKnownSymbolKey(aCx, SymbolCode::hasInstance)); 119 120 const uint32_t kFlags = 121 JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT; 122 const uint32_t kNoEnum = JSPROP_READONLY | JSPROP_PERMANENT; 123 124 bool ok = 125 idProto && iidProto && cidProto && 126 // Methods and properties on all ID Objects: 127 JS_DefineFunction(aCx, idProto, "equals", ID_Equals, 1, kFlags) && 128 JS_DefineProperty(aCx, idProto, "number", ID_GetNumber, nullptr, 129 kFlags) && 130 131 // Methods for IfaceID objects, which also inherit ID properties: 132 JS_DefineFunctionById(aCx, iidProto, hasInstance, IID_HasInstance, 1, 133 kNoEnum) && 134 JS_DefineProperty(aCx, iidProto, "name", IID_GetName, nullptr, 135 kFlags) && 136 137 // Methods for ContractID objects, which also inherit ID properties: 138 JS_DefineFunction(aCx, cidProto, "createInstance", CID_CreateInstance, 139 1, kFlags) && 140 JS_DefineFunction(aCx, cidProto, "getService", CID_GetService, 1, 141 kFlags) && 142 JS_DefineProperty(aCx, cidProto, "name", CID_GetName, nullptr, 143 kFlags) && 144 145 // ToString returns '.number' on generic IDs, while returning 146 // '.name' on other ID types. 147 JS_DefineFunction(aCx, idProto, "toString", ID_GetNumber, 0, kFlags) && 148 JS_DefineFunction(aCx, iidProto, "toString", IID_GetName, 0, kFlags) && 149 JS_DefineFunction(aCx, cidProto, "toString", CID_GetName, 0, kFlags); 150 if (!ok) { 151 return nullptr; 152 } 153 154 scope->mIDProto = idProto; 155 scope->mIIDProto = iidProto; 156 scope->mCIDProto = cidProto; 157 } 158 159 if (aClass == &sID_Class) { 160 return scope->mIDProto; 161 } else if (aClass == &sIID_Class) { 162 return scope->mIIDProto; 163 } else if (aClass == &sCID_Class) { 164 return scope->mCIDProto; 165 } 166 167 MOZ_CRASH("Unrecognized ID Object Class"); 168 } 169 170 // Unwrap the given value to an object with the correct class, or nullptr. 171 static JSObject* GetIDObject(HandleValue aVal, const JSClass* aClass) { 172 if (aVal.isObject()) { 173 // We care only about IID/CID objects here, so CheckedUnwrapStatic is fine. 174 JSObject* obj = js::CheckedUnwrapStatic(&aVal.toObject()); 175 if (obj && JS::GetClass(obj) == aClass) { 176 return obj; 177 } 178 } 179 return nullptr; 180 } 181 182 static const nsXPTInterfaceInfo* GetInterfaceInfo(JSObject* obj) { 183 MOZ_ASSERT(JS::GetClass(obj) == &sIID_Class); 184 return static_cast<const nsXPTInterfaceInfo*>( 185 JS::GetReservedSlot(obj, kIID_InfoSlot).toPrivate()); 186 } 187 188 /** 189 * Unwrap an nsID object from a JSValue. 190 * 191 * For Generic ID objects, this function will extract the nsID from reserved 192 * slots. For IfaceID objects, it will be extracted from the nsXPTInterfaceInfo, 193 * and for ContractID objects, the ContractID's corresponding CID will be looked 194 * up. 195 */ 196 Maybe<nsID> JSValue2ID(JSContext* aCx, HandleValue aVal) { 197 if (!aVal.isObject()) { 198 return Nothing(); 199 } 200 201 // We only care about ID objects here, so CheckedUnwrapStatic is fine. 202 RootedObject obj(aCx, js::CheckedUnwrapStatic(&aVal.toObject())); 203 if (!obj) { 204 return Nothing(); 205 } 206 207 mozilla::Maybe<nsID> id; 208 if (JS::GetClass(obj) == &sID_Class) { 209 // Extract the raw bytes of the nsID from reserved slots. 210 uint32_t rawid[] = {JS::GetReservedSlot(obj, kID_Slot0).toPrivateUint32(), 211 JS::GetReservedSlot(obj, kID_Slot1).toPrivateUint32(), 212 JS::GetReservedSlot(obj, kID_Slot2).toPrivateUint32(), 213 JS::GetReservedSlot(obj, kID_Slot3).toPrivateUint32()}; 214 215 // Construct a nsID inside the Maybe, and copy the rawid into it. 216 id.emplace(); 217 memcpy(id.ptr(), &rawid, sizeof(nsID)); 218 } else if (JS::GetClass(obj) == &sIID_Class) { 219 // IfaceID objects store a nsXPTInterfaceInfo* pointer. 220 const nsXPTInterfaceInfo* info = GetInterfaceInfo(obj); 221 id.emplace(info->IID()); 222 } else if (JS::GetClass(obj) == &sCID_Class) { 223 // ContractID objects store a ContractID string. 224 JS::UniqueChars contractId = JS_EncodeStringToLatin1( 225 aCx, JS::GetReservedSlot(obj, kCID_ContractSlot).toString()); 226 227 // NOTE(nika): If we directly access the nsComponentManager, we can do 228 // this with a more-basic pointer lookup: 229 // nsFactoryEntry* entry = nsComponentManagerImpl::gComponentManager-> 230 // GetFactoryEntry(contractId.ptr(), contractId.length()); 231 // if (entry) id.emplace(entry->mCIDEntry->cid); 232 233 nsCOMPtr<nsIComponentRegistrar> registrar; 234 nsresult rv = NS_GetComponentRegistrar(getter_AddRefs(registrar)); 235 if (NS_FAILED(rv) || !registrar) { 236 return Nothing(); 237 } 238 239 nsCID* cid = nullptr; 240 if (NS_SUCCEEDED(registrar->ContractIDToCID(contractId.get(), &cid))) { 241 id.emplace(*cid); 242 free(cid); 243 } 244 } 245 return id; 246 } 247 248 /** 249 * Public ID Object Constructor Methods 250 */ 251 static JSObject* NewIDObjectHelper(JSContext* aCx, const JSClass* aClass) { 252 RootedObject proto(aCx, GetIDPrototype(aCx, aClass)); 253 if (proto) { 254 return JS_NewObjectWithGivenProto(aCx, aClass, proto); 255 } 256 return nullptr; 257 } 258 259 bool ID2JSValue(JSContext* aCx, const nsID& aId, MutableHandleValue aVal) { 260 RootedObject obj(aCx, NewIDObjectHelper(aCx, &sID_Class)); 261 if (!obj) { 262 return false; 263 } 264 265 // Get the data in nsID as 4 uint32_ts, and store them in slots. 266 uint32_t rawid[4]; 267 memcpy(&rawid, &aId, sizeof(nsID)); 268 static_assert(sizeof(nsID) == sizeof(rawid), "Wrong size of nsID"); 269 JS::SetReservedSlot(obj, kID_Slot0, PrivateUint32Value(rawid[0])); 270 JS::SetReservedSlot(obj, kID_Slot1, PrivateUint32Value(rawid[1])); 271 JS::SetReservedSlot(obj, kID_Slot2, PrivateUint32Value(rawid[2])); 272 JS::SetReservedSlot(obj, kID_Slot3, PrivateUint32Value(rawid[3])); 273 274 aVal.setObject(*obj); 275 return true; 276 } 277 278 bool IfaceID2JSValue(JSContext* aCx, const nsXPTInterfaceInfo& aInfo, 279 MutableHandleValue aVal) { 280 RootedObject obj(aCx, NewIDObjectHelper(aCx, &sIID_Class)); 281 if (!obj) { 282 return false; 283 } 284 285 // The InterfaceInfo is stored in a reserved slot. 286 JS::SetReservedSlot(obj, kIID_InfoSlot, PrivateValue((void*)&aInfo)); 287 aVal.setObject(*obj); 288 return true; 289 } 290 291 bool ContractID2JSValue(JSContext* aCx, JSString* aContract, 292 MutableHandleValue aVal) { 293 RootedString jsContract(aCx, aContract); 294 295 { 296 // It is perfectly safe to have a ContractID object with an invalid 297 // ContractID, but is usually a bug. 298 nsCOMPtr<nsIComponentRegistrar> registrar; 299 NS_GetComponentRegistrar(getter_AddRefs(registrar)); 300 if (!registrar) { 301 return false; 302 } 303 304 bool registered = false; 305 JS::UniqueChars contract = JS_EncodeStringToLatin1(aCx, jsContract); 306 registrar->IsContractIDRegistered(contract.get(), ®istered); 307 if (!registered) { 308 return false; 309 } 310 } 311 312 RootedObject obj(aCx, NewIDObjectHelper(aCx, &sCID_Class)); 313 if (!obj) { 314 return false; 315 } 316 317 // The Contract is stored in a reserved slot. 318 JS::SetReservedSlot(obj, kCID_ContractSlot, StringValue(jsContract)); 319 aVal.setObject(*obj); 320 return true; 321 } 322 323 /****************************************************************************** 324 * # Method & Property Getter Implementations # 325 */ 326 327 // NOTE: This method is used both for 'get ID.prototype.number' and 328 // 'ID.prototype.toString'. 329 static bool ID_GetNumber(JSContext* aCx, unsigned aArgc, Value* aVp) { 330 CallArgs args = CallArgsFromVp(aArgc, aVp); 331 332 Maybe<nsID> id = JSValue2ID(aCx, args.thisv()); 333 if (!id) { 334 return Throw(aCx, NS_ERROR_XPC_BAD_CONVERT_JS); 335 } 336 337 char buf[NSID_LENGTH]; 338 id->ToProvidedString(buf); 339 JSString* jsnum = JS_NewStringCopyZ(aCx, buf); 340 if (!jsnum) { 341 return Throw(aCx, NS_ERROR_OUT_OF_MEMORY); 342 } 343 344 args.rval().setString(jsnum); 345 return true; 346 } 347 348 static bool ID_Equals(JSContext* aCx, unsigned aArgc, Value* aVp) { 349 CallArgs args = CallArgsFromVp(aArgc, aVp); 350 if (!args.requireAtLeast(aCx, "nsID.equals", 1)) { 351 return false; 352 } 353 354 Maybe<nsID> id = JSValue2ID(aCx, args.thisv()); 355 Maybe<nsID> id2 = JSValue2ID(aCx, args[0]); 356 if (!id || !id2) { 357 return Throw(aCx, NS_ERROR_XPC_BAD_CONVERT_JS); 358 } 359 360 args.rval().setBoolean(id->Equals(*id2)); 361 return true; 362 } 363 364 /* 365 * HasInstance hooks need to find an appropriate reflector in order to function 366 * properly. There are two complexities that we need to handle: 367 * 368 * 1 - Cross-compartment wrappers. Chrome uses over 100 compartments, all with 369 * system principal. The success of an instanceof check should not depend 370 * on which compartment an object comes from. At the same time, we want to 371 * make sure we don't unwrap important security wrappers. 372 * CheckedUnwrap does the right thing here. 373 * 374 * 2 - Prototype chains. Suppose someone creates a vanilla JS object |a| and 375 * sets its __proto__ to some WN |b|. If |b instanceof nsIFoo| returns true, 376 * one would expect |a instanceof nsIFoo| to return true as well, since 377 * instanceof is transitive up the prototype chain in ECMAScript. Moreover, 378 * there's chrome code that relies on this. 379 * 380 * This static method handles both complexities, returning either an XPCWN, a 381 * DOM object, or null. The object may well be cross-compartment from |cx|. 382 */ 383 static nsresult FindObjectForHasInstance(JSContext* cx, HandleObject objArg, 384 MutableHandleObject target) { 385 RootedObject obj(cx, objArg), proto(cx); 386 while (true) { 387 // Try the object, or the wrappee if allowed. We want CheckedUnwrapDynamic 388 // here, because we might in fact be looking for a Window. "cx" represents 389 // our current global. 390 JSObject* o = 391 js::IsWrapper(obj) ? js::CheckedUnwrapDynamic(obj, cx, false) : obj; 392 if (o && (IsWrappedNativeReflector(o) || IsDOMObject(o))) { 393 target.set(o); 394 return NS_OK; 395 } 396 397 // Walk the prototype chain from the perspective of the callee (i.e. 398 // respecting Xrays if they exist). 399 if (!js::GetObjectProto(cx, obj, &proto)) { 400 return NS_ERROR_FAILURE; 401 } 402 if (!proto) { 403 target.set(nullptr); 404 return NS_OK; 405 } 406 obj = proto; 407 } 408 } 409 410 nsresult HasInstance(JSContext* cx, HandleObject objArg, const nsID* iid, 411 bool* bp) { 412 *bp = false; 413 414 RootedObject obj(cx); 415 nsresult rv = FindObjectForHasInstance(cx, objArg, &obj); 416 if (NS_WARN_IF(NS_FAILED(rv))) { 417 return rv; 418 } 419 420 if (!obj) { 421 return NS_OK; 422 } 423 424 // Need to unwrap Window correctly here, so use ReflectorToISupportsDynamic. 425 nsCOMPtr<nsISupports> identity = ReflectorToISupportsDynamic(obj, cx); 426 if (!identity) { 427 return NS_OK; 428 } 429 430 nsCOMPtr<nsISupports> supp; 431 identity->QueryInterface(*iid, getter_AddRefs(supp)); 432 *bp = supp; 433 434 // Our old HasInstance implementation operated by invoking FindTearOff on 435 // XPCWrappedNatives, and various bits of chrome JS came to depend on 436 // |instanceof| doing an implicit QI if it succeeds. Do a drive-by QI to 437 // preserve that behavior. This is just a compatibility hack, so we don't 438 // really care if it fails. 439 if (IsWrappedNativeReflector(obj)) { 440 (void)XPCWrappedNative::Get(obj)->FindTearOff(cx, *iid); 441 } 442 443 return NS_OK; 444 } 445 446 static bool IID_HasInstance(JSContext* aCx, unsigned aArgc, Value* aVp) { 447 CallArgs args = CallArgsFromVp(aArgc, aVp); 448 if (!args.requireAtLeast(aCx, "nsIID[Symbol.hasInstance]", 1)) { 449 return false; 450 } 451 452 Maybe<nsID> id = JSValue2ID(aCx, args.thisv()); 453 if (!id) { 454 return Throw(aCx, NS_ERROR_XPC_BAD_CONVERT_JS); 455 } 456 457 bool hasInstance = false; 458 if (args[0].isObject()) { 459 RootedObject target(aCx, &args[0].toObject()); 460 nsresult rv = HasInstance(aCx, target, id.ptr(), &hasInstance); 461 if (NS_FAILED(rv)) { 462 return Throw(aCx, rv); 463 } 464 } 465 args.rval().setBoolean(hasInstance); 466 return true; 467 } 468 469 // NOTE: This method is used both for 'get IID.prototype.name' and 470 // 'IID.prototype.toString'. 471 static bool IID_GetName(JSContext* aCx, unsigned aArgc, Value* aVp) { 472 CallArgs args = CallArgsFromVp(aArgc, aVp); 473 474 RootedObject obj(aCx, GetIDObject(args.thisv(), &sIID_Class)); 475 if (!obj) { 476 return Throw(aCx, NS_ERROR_XPC_BAD_CONVERT_JS); 477 } 478 479 const nsXPTInterfaceInfo* info = GetInterfaceInfo(obj); 480 481 // Name property is the name of the interface this nsIID was created from. 482 JSString* name = JS_NewStringCopyZ(aCx, info->Name()); 483 if (!name) { 484 return Throw(aCx, NS_ERROR_OUT_OF_MEMORY); 485 } 486 487 args.rval().setString(name); 488 return true; 489 } 490 491 static bool IID_NewEnumerate(JSContext* cx, HandleObject obj, 492 MutableHandleIdVector properties, 493 bool enumerableOnly) { 494 const nsXPTInterfaceInfo* info = GetInterfaceInfo(obj); 495 496 if (!properties.reserve(info->ConstantCount())) { 497 JS_ReportOutOfMemory(cx); 498 return false; 499 } 500 501 RootedId id(cx); 502 RootedString name(cx); 503 for (uint16_t i = 0; i < info->ConstantCount(); ++i) { 504 name = JS_AtomizeString(cx, info->Constant(i).Name()); 505 if (!name || !JS_StringToId(cx, name, &id)) { 506 return false; 507 } 508 properties.infallibleAppend(id); 509 } 510 511 return true; 512 } 513 514 static bool IID_Resolve(JSContext* cx, HandleObject obj, HandleId id, 515 bool* resolvedp) { 516 *resolvedp = false; 517 if (!id.isString()) { 518 return true; 519 } 520 521 JSLinearString* name = id.toLinearString(); 522 const nsXPTInterfaceInfo* info = GetInterfaceInfo(obj); 523 for (uint16_t i = 0; i < info->ConstantCount(); ++i) { 524 if (JS_LinearStringEqualsAscii(name, info->Constant(i).Name())) { 525 *resolvedp = true; 526 527 RootedValue constant(cx, info->Constant(i).JSValue()); 528 return JS_DefinePropertyById( 529 cx, obj, id, constant, 530 JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT); 531 } 532 } 533 return true; 534 } 535 536 static bool IID_MayResolve(const JSAtomState& names, jsid id, 537 JSObject* maybeObj) { 538 if (!id.isString()) { 539 return false; 540 } 541 542 if (!maybeObj) { 543 // Each interface object has its own set of constants, so if we don't know 544 // the object, assume any string property may be resolved. 545 return true; 546 } 547 548 JSLinearString* name = id.toLinearString(); 549 const nsXPTInterfaceInfo* info = GetInterfaceInfo(maybeObj); 550 for (uint16_t i = 0; i < info->ConstantCount(); ++i) { 551 if (JS_LinearStringEqualsAscii(name, info->Constant(i).Name())) { 552 return true; 553 } 554 } 555 return false; 556 } 557 558 // Common code for CID_CreateInstance and CID_GetService 559 static bool CIGSHelper(JSContext* aCx, unsigned aArgc, Value* aVp, 560 bool aGetService) { 561 CallArgs args = CallArgsFromVp(aArgc, aVp); 562 563 // Extract the ContractID string from our reserved slot. Don't use 564 // JSValue2ID as this method should only be defined on Contract ID objects, 565 // and it allows us to avoid a duplicate hashtable lookup. 566 RootedObject obj(aCx, GetIDObject(args.thisv(), &sCID_Class)); 567 if (!obj) { 568 return Throw(aCx, NS_ERROR_XPC_BAD_CONVERT_JS); 569 } 570 JS::UniqueChars contractID = JS_EncodeStringToLatin1( 571 aCx, JS::GetReservedSlot(obj, kCID_ContractSlot).toString()); 572 573 // Extract the IID from the first argument, if passed. Default: nsISupports. 574 Maybe<nsIID> iid = args.length() >= 1 ? JSValue2ID(aCx, args[0]) 575 : Some(NS_GET_IID(nsISupports)); 576 if (!iid) { 577 return Throw(aCx, NS_ERROR_XPC_BAD_CONVERT_JS); 578 } 579 580 // Invoke CreateInstance or GetService with our ContractID. 581 nsresult rv; 582 nsCOMPtr<nsISupports> result; 583 if (aGetService) { 584 rv = CallGetService(contractID.get(), *iid, getter_AddRefs(result)); 585 if (NS_FAILED(rv) || !result) { 586 return Throw(aCx, NS_ERROR_XPC_GS_RETURNED_FAILURE); 587 } 588 } else { 589 rv = CallCreateInstance(contractID.get(), *iid, getter_AddRefs(result)); 590 if (NS_FAILED(rv) || !result) { 591 return Throw(aCx, NS_ERROR_XPC_CI_RETURNED_FAILURE); 592 } 593 } 594 595 // Wrap the created object and return it. 596 rv = nsContentUtils::WrapNative(aCx, result, iid.ptr(), args.rval()); 597 if (NS_FAILED(rv) || args.rval().isPrimitive()) { 598 return Throw(aCx, NS_ERROR_XPC_CANT_CREATE_WN); 599 } 600 return true; 601 } 602 603 static bool CID_CreateInstance(JSContext* aCx, unsigned aArgc, Value* aVp) { 604 return CIGSHelper(aCx, aArgc, aVp, /* aGetService = */ false); 605 } 606 607 static bool CID_GetService(JSContext* aCx, unsigned aArgc, Value* aVp) { 608 return CIGSHelper(aCx, aArgc, aVp, /* aGetService = */ true); 609 } 610 611 // NOTE: This method is used both for 'get CID.prototype.name' and 612 // 'CID.prototype.toString'. 613 static bool CID_GetName(JSContext* aCx, unsigned aArgc, Value* aVp) { 614 CallArgs args = CallArgsFromVp(aArgc, aVp); 615 RootedObject obj(aCx, GetIDObject(args.thisv(), &sCID_Class)); 616 if (!obj) { 617 return Throw(aCx, NS_ERROR_XPC_BAD_CONVERT_JS); 618 } 619 620 // Return the string stored in our reserved ContractID slot. 621 args.rval().set(JS::GetReservedSlot(obj, kCID_ContractSlot)); 622 return true; 623 } 624 625 } // namespace xpc