WrapperAnswer.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. *
  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. #include "WrapperAnswer.h"
  7. #include "JavaScriptLogging.h"
  8. #include "mozilla/dom/ContentChild.h"
  9. #include "mozilla/dom/BindingUtils.h"
  10. #include "mozilla/dom/ScriptSettings.h"
  11. #include "xpcprivate.h"
  12. #include "js/Class.h"
  13. #include "jsfriendapi.h"
  14. using namespace JS;
  15. using namespace mozilla;
  16. using namespace mozilla::jsipc;
  17. // Note - Using AutoJSAPI (rather than AutoEntryScript) for a trap means
  18. // that we don't expect it to run script. For most of these traps that will only
  19. // happen if the target is a scripted proxy, which is probably something that we
  20. // don't want to support over CPOWs. When enough code is fixed up, the long-term
  21. // plan is to have the JS engine throw if it encounters script when it isn't
  22. // expecting it.
  23. using mozilla::dom::AutoJSAPI;
  24. using mozilla::dom::AutoEntryScript;
  25. static void
  26. MaybeForceDebugGC()
  27. {
  28. static bool sEnvVarInitialized = false;
  29. static bool sDebugGCs = false;
  30. if (!sEnvVarInitialized)
  31. sDebugGCs = !!PR_GetEnv("MOZ_DEBUG_DEAD_CPOWS");
  32. if (sDebugGCs) {
  33. JSContext* cx = nsXPConnect::GetContextInstance()->Context();
  34. PrepareForFullGC(cx);
  35. GCForReason(cx, GC_NORMAL, gcreason::COMPONENT_UTILS);
  36. }
  37. }
  38. bool
  39. WrapperAnswer::fail(AutoJSAPI& jsapi, ReturnStatus* rs)
  40. {
  41. // By default, we set |undefined| unless we can get a more meaningful
  42. // exception.
  43. *rs = ReturnStatus(ReturnException(JSVariant(UndefinedVariant())));
  44. // Note we always return true from this function, since this propagates
  45. // to the IPC code, and we don't want a JS failure to cause the death
  46. // of the child process.
  47. JSContext* cx = jsapi.cx();
  48. RootedValue exn(cx);
  49. if (!jsapi.HasException())
  50. return true;
  51. if (!jsapi.StealException(&exn))
  52. return true;
  53. if (JS_IsStopIteration(exn)) {
  54. *rs = ReturnStatus(ReturnStopIteration());
  55. return true;
  56. }
  57. // If this fails, we still don't want to exit. Just return an invalid
  58. // exception.
  59. (void) toVariant(cx, exn, &rs->get_ReturnException().exn());
  60. return true;
  61. }
  62. bool
  63. WrapperAnswer::ok(ReturnStatus* rs)
  64. {
  65. *rs = ReturnStatus(ReturnSuccess());
  66. return true;
  67. }
  68. bool
  69. WrapperAnswer::ok(ReturnStatus* rs, const JS::ObjectOpResult& result)
  70. {
  71. *rs = result
  72. ? ReturnStatus(ReturnSuccess())
  73. : ReturnStatus(ReturnObjectOpResult(result.failureCode()));
  74. return true;
  75. }
  76. bool
  77. WrapperAnswer::deadCPOW(AutoJSAPI& jsapi, ReturnStatus* rs)
  78. {
  79. JSContext* cx = jsapi.cx();
  80. JS_ClearPendingException(cx);
  81. *rs = ReturnStatus(ReturnDeadCPOW());
  82. return true;
  83. }
  84. bool
  85. WrapperAnswer::RecvPreventExtensions(const ObjectId& objId, ReturnStatus* rs)
  86. {
  87. MaybeForceDebugGC();
  88. AutoJSAPI jsapi;
  89. if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
  90. return false;
  91. JSContext* cx = jsapi.cx();
  92. RootedObject obj(cx, findObjectById(cx, objId));
  93. if (!obj)
  94. return deadCPOW(jsapi, rs);
  95. ObjectOpResult success;
  96. if (!JS_PreventExtensions(cx, obj, success))
  97. return fail(jsapi, rs);
  98. LOG("%s.preventExtensions()", ReceiverObj(objId));
  99. return ok(rs, success);
  100. }
  101. static void
  102. EmptyDesc(PPropertyDescriptor* desc)
  103. {
  104. desc->obj() = LocalObject(0);
  105. desc->attrs() = 0;
  106. desc->value() = UndefinedVariant();
  107. desc->getter() = 0;
  108. desc->setter() = 0;
  109. }
  110. bool
  111. WrapperAnswer::RecvGetPropertyDescriptor(const ObjectId& objId, const JSIDVariant& idVar,
  112. ReturnStatus* rs, PPropertyDescriptor* out)
  113. {
  114. MaybeForceDebugGC();
  115. AutoJSAPI jsapi;
  116. if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
  117. return false;
  118. JSContext* cx = jsapi.cx();
  119. EmptyDesc(out);
  120. RootedObject obj(cx, findObjectById(cx, objId));
  121. if (!obj)
  122. return deadCPOW(jsapi, rs);
  123. LOG("%s.getPropertyDescriptor(%s)", ReceiverObj(objId), Identifier(idVar));
  124. RootedId id(cx);
  125. if (!fromJSIDVariant(cx, idVar, &id))
  126. return fail(jsapi, rs);
  127. Rooted<PropertyDescriptor> desc(cx);
  128. if (!JS_GetPropertyDescriptorById(cx, obj, id, &desc))
  129. return fail(jsapi, rs);
  130. if (!fromDescriptor(cx, desc, out))
  131. return fail(jsapi, rs);
  132. return ok(rs);
  133. }
  134. bool
  135. WrapperAnswer::RecvGetOwnPropertyDescriptor(const ObjectId& objId, const JSIDVariant& idVar,
  136. ReturnStatus* rs, PPropertyDescriptor* out)
  137. {
  138. MaybeForceDebugGC();
  139. AutoJSAPI jsapi;
  140. if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
  141. return false;
  142. JSContext* cx = jsapi.cx();
  143. EmptyDesc(out);
  144. RootedObject obj(cx, findObjectById(cx, objId));
  145. if (!obj)
  146. return deadCPOW(jsapi, rs);
  147. LOG("%s.getOwnPropertyDescriptor(%s)", ReceiverObj(objId), Identifier(idVar));
  148. RootedId id(cx);
  149. if (!fromJSIDVariant(cx, idVar, &id))
  150. return fail(jsapi, rs);
  151. Rooted<PropertyDescriptor> desc(cx);
  152. if (!JS_GetOwnPropertyDescriptorById(cx, obj, id, &desc))
  153. return fail(jsapi, rs);
  154. if (!fromDescriptor(cx, desc, out))
  155. return fail(jsapi, rs);
  156. return ok(rs);
  157. }
  158. bool
  159. WrapperAnswer::RecvDefineProperty(const ObjectId& objId, const JSIDVariant& idVar,
  160. const PPropertyDescriptor& descriptor, ReturnStatus* rs)
  161. {
  162. MaybeForceDebugGC();
  163. AutoJSAPI jsapi;
  164. if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
  165. return false;
  166. JSContext* cx = jsapi.cx();
  167. RootedObject obj(cx, findObjectById(cx, objId));
  168. if (!obj)
  169. return deadCPOW(jsapi, rs);
  170. LOG("define %s[%s]", ReceiverObj(objId), Identifier(idVar));
  171. RootedId id(cx);
  172. if (!fromJSIDVariant(cx, idVar, &id))
  173. return fail(jsapi, rs);
  174. Rooted<PropertyDescriptor> desc(cx);
  175. if (!toDescriptor(cx, descriptor, &desc))
  176. return fail(jsapi, rs);
  177. ObjectOpResult success;
  178. if (!JS_DefinePropertyById(cx, obj, id, desc, success))
  179. return fail(jsapi, rs);
  180. return ok(rs, success);
  181. }
  182. bool
  183. WrapperAnswer::RecvDelete(const ObjectId& objId, const JSIDVariant& idVar, ReturnStatus* rs)
  184. {
  185. MaybeForceDebugGC();
  186. AutoJSAPI jsapi;
  187. if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
  188. return false;
  189. JSContext* cx = jsapi.cx();
  190. RootedObject obj(cx, findObjectById(cx, objId));
  191. if (!obj)
  192. return deadCPOW(jsapi, rs);
  193. LOG("delete %s[%s]", ReceiverObj(objId), Identifier(idVar));
  194. RootedId id(cx);
  195. if (!fromJSIDVariant(cx, idVar, &id))
  196. return fail(jsapi, rs);
  197. ObjectOpResult success;
  198. if (!JS_DeletePropertyById(cx, obj, id, success))
  199. return fail(jsapi, rs);
  200. return ok(rs, success);
  201. }
  202. bool
  203. WrapperAnswer::RecvHas(const ObjectId& objId, const JSIDVariant& idVar, ReturnStatus* rs,
  204. bool* foundp)
  205. {
  206. MaybeForceDebugGC();
  207. AutoJSAPI jsapi;
  208. if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
  209. return false;
  210. JSContext* cx = jsapi.cx();
  211. *foundp = false;
  212. RootedObject obj(cx, findObjectById(cx, objId));
  213. if (!obj)
  214. return deadCPOW(jsapi, rs);
  215. LOG("%s.has(%s)", ReceiverObj(objId), Identifier(idVar));
  216. RootedId id(cx);
  217. if (!fromJSIDVariant(cx, idVar, &id))
  218. return fail(jsapi, rs);
  219. if (!JS_HasPropertyById(cx, obj, id, foundp))
  220. return fail(jsapi, rs);
  221. return ok(rs);
  222. }
  223. bool
  224. WrapperAnswer::RecvHasOwn(const ObjectId& objId, const JSIDVariant& idVar, ReturnStatus* rs,
  225. bool* foundp)
  226. {
  227. MaybeForceDebugGC();
  228. AutoJSAPI jsapi;
  229. if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
  230. return false;
  231. JSContext* cx = jsapi.cx();
  232. *foundp = false;
  233. RootedObject obj(cx, findObjectById(cx, objId));
  234. if (!obj)
  235. return deadCPOW(jsapi, rs);
  236. LOG("%s.hasOwn(%s)", ReceiverObj(objId), Identifier(idVar));
  237. RootedId id(cx);
  238. if (!fromJSIDVariant(cx, idVar, &id))
  239. return fail(jsapi, rs);
  240. if (!JS_HasOwnPropertyById(cx, obj, id, foundp))
  241. return fail(jsapi, rs);
  242. return ok(rs);
  243. }
  244. bool
  245. WrapperAnswer::RecvGet(const ObjectId& objId, const JSVariant& receiverVar,
  246. const JSIDVariant& idVar, ReturnStatus* rs, JSVariant* result)
  247. {
  248. MaybeForceDebugGC();
  249. // We may run scripted getters.
  250. AutoEntryScript aes(scopeForTargetObjects(),
  251. "Cross-Process Object Wrapper 'get'");
  252. JSContext* cx = aes.cx();
  253. // The outparam will be written to the buffer, so it must be set even if
  254. // the parent won't read it.
  255. *result = UndefinedVariant();
  256. RootedObject obj(cx, findObjectById(cx, objId));
  257. if (!obj)
  258. return deadCPOW(aes, rs);
  259. RootedValue receiver(cx);
  260. if (!fromVariant(cx, receiverVar, &receiver))
  261. return fail(aes, rs);
  262. RootedId id(cx);
  263. if (!fromJSIDVariant(cx, idVar, &id))
  264. return fail(aes, rs);
  265. JS::RootedValue val(cx);
  266. if (!JS_ForwardGetPropertyTo(cx, obj, id, receiver, &val))
  267. return fail(aes, rs);
  268. if (!toVariant(cx, val, result))
  269. return fail(aes, rs);
  270. LOG("get %s.%s = %s", ReceiverObj(objId), Identifier(idVar), OutVariant(*result));
  271. return ok(rs);
  272. }
  273. bool
  274. WrapperAnswer::RecvSet(const ObjectId& objId, const JSIDVariant& idVar, const JSVariant& value,
  275. const JSVariant& receiverVar, ReturnStatus* rs)
  276. {
  277. MaybeForceDebugGC();
  278. // We may run scripted setters.
  279. AutoEntryScript aes(scopeForTargetObjects(),
  280. "Cross-Process Object Wrapper 'set'");
  281. JSContext* cx = aes.cx();
  282. RootedObject obj(cx, findObjectById(cx, objId));
  283. if (!obj)
  284. return deadCPOW(aes, rs);
  285. LOG("set %s[%s] = %s", ReceiverObj(objId), Identifier(idVar), InVariant(value));
  286. RootedId id(cx);
  287. if (!fromJSIDVariant(cx, idVar, &id))
  288. return fail(aes, rs);
  289. RootedValue val(cx);
  290. if (!fromVariant(cx, value, &val))
  291. return fail(aes, rs);
  292. RootedValue receiver(cx);
  293. if (!fromVariant(cx, receiverVar, &receiver))
  294. return fail(aes, rs);
  295. ObjectOpResult result;
  296. if (!JS_ForwardSetPropertyTo(cx, obj, id, val, receiver, result))
  297. return fail(aes, rs);
  298. return ok(rs, result);
  299. }
  300. bool
  301. WrapperAnswer::RecvIsExtensible(const ObjectId& objId, ReturnStatus* rs, bool* result)
  302. {
  303. MaybeForceDebugGC();
  304. AutoJSAPI jsapi;
  305. if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
  306. return false;
  307. JSContext* cx = jsapi.cx();
  308. *result = false;
  309. RootedObject obj(cx, findObjectById(cx, objId));
  310. if (!obj)
  311. return deadCPOW(jsapi, rs);
  312. LOG("%s.isExtensible()", ReceiverObj(objId));
  313. bool extensible;
  314. if (!JS_IsExtensible(cx, obj, &extensible))
  315. return fail(jsapi, rs);
  316. *result = !!extensible;
  317. return ok(rs);
  318. }
  319. bool
  320. WrapperAnswer::RecvCallOrConstruct(const ObjectId& objId,
  321. InfallibleTArray<JSParam>&& argv,
  322. const bool& construct,
  323. ReturnStatus* rs,
  324. JSVariant* result,
  325. nsTArray<JSParam>* outparams)
  326. {
  327. MaybeForceDebugGC();
  328. AutoEntryScript aes(scopeForTargetObjects(),
  329. "Cross-Process Object Wrapper call/construct");
  330. JSContext* cx = aes.cx();
  331. // The outparam will be written to the buffer, so it must be set even if
  332. // the parent won't read it.
  333. *result = UndefinedVariant();
  334. RootedObject obj(cx, findObjectById(cx, objId));
  335. if (!obj)
  336. return deadCPOW(aes, rs);
  337. MOZ_ASSERT(argv.Length() >= 2);
  338. RootedValue objv(cx);
  339. if (!fromVariant(cx, argv[0], &objv))
  340. return fail(aes, rs);
  341. *result = JSVariant(UndefinedVariant());
  342. AutoValueVector vals(cx);
  343. AutoValueVector outobjects(cx);
  344. for (size_t i = 0; i < argv.Length(); i++) {
  345. if (argv[i].type() == JSParam::Tvoid_t) {
  346. // This is an outparam.
  347. RootedObject obj(cx, xpc::NewOutObject(cx));
  348. if (!obj)
  349. return fail(aes, rs);
  350. if (!outobjects.append(ObjectValue(*obj)))
  351. return fail(aes, rs);
  352. if (!vals.append(ObjectValue(*obj)))
  353. return fail(aes, rs);
  354. } else {
  355. RootedValue v(cx);
  356. if (!fromVariant(cx, argv[i].get_JSVariant(), &v))
  357. return fail(aes, rs);
  358. if (!vals.append(v))
  359. return fail(aes, rs);
  360. }
  361. }
  362. RootedValue rval(cx);
  363. {
  364. HandleValueArray args = HandleValueArray::subarray(vals, 2, vals.length() - 2);
  365. if (construct) {
  366. RootedObject obj(cx);
  367. if (!JS::Construct(cx, vals[0], args, &obj))
  368. return fail(aes, rs);
  369. rval.setObject(*obj);
  370. } else {
  371. if(!JS::Call(cx, vals[1], vals[0], args, &rval))
  372. return fail(aes, rs);
  373. }
  374. }
  375. if (!toVariant(cx, rval, result))
  376. return fail(aes, rs);
  377. // Prefill everything with a dummy jsval.
  378. for (size_t i = 0; i < outobjects.length(); i++)
  379. outparams->AppendElement(JSParam(void_t()));
  380. // Go through each argument that was an outparam, retrieve the "value"
  381. // field, and add it to a temporary list. We need to do this separately
  382. // because the outparams vector is not rooted.
  383. vals.clear();
  384. for (size_t i = 0; i < outobjects.length(); i++) {
  385. RootedObject obj(cx, &outobjects[i].toObject());
  386. RootedValue v(cx);
  387. bool found;
  388. if (JS_HasProperty(cx, obj, "value", &found)) {
  389. if (!JS_GetProperty(cx, obj, "value", &v))
  390. return fail(aes, rs);
  391. } else {
  392. v = UndefinedValue();
  393. }
  394. if (!vals.append(v))
  395. return fail(aes, rs);
  396. }
  397. // Copy the outparams. If any outparam is already set to a void_t, we
  398. // treat this as the outparam never having been set.
  399. for (size_t i = 0; i < vals.length(); i++) {
  400. JSVariant variant;
  401. if (!toVariant(cx, vals[i], &variant))
  402. return fail(aes, rs);
  403. outparams->ReplaceElementAt(i, JSParam(variant));
  404. }
  405. LOG("%s.call(%s) = %s", ReceiverObj(objId), argv, OutVariant(*result));
  406. return ok(rs);
  407. }
  408. bool
  409. WrapperAnswer::RecvHasInstance(const ObjectId& objId, const JSVariant& vVar, ReturnStatus* rs, bool* bp)
  410. {
  411. MaybeForceDebugGC();
  412. AutoJSAPI jsapi;
  413. if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
  414. return false;
  415. JSContext* cx = jsapi.cx();
  416. RootedObject obj(cx, findObjectById(cx, objId));
  417. if (!obj)
  418. return deadCPOW(jsapi, rs);
  419. LOG("%s.hasInstance(%s)", ReceiverObj(objId), InVariant(vVar));
  420. RootedValue val(cx);
  421. if (!fromVariant(cx, vVar, &val))
  422. return fail(jsapi, rs);
  423. if (!JS_HasInstance(cx, obj, val, bp))
  424. return fail(jsapi, rs);
  425. return ok(rs);
  426. }
  427. bool
  428. WrapperAnswer::RecvGetBuiltinClass(const ObjectId& objId, ReturnStatus* rs,
  429. uint32_t* classValue)
  430. {
  431. MaybeForceDebugGC();
  432. *classValue = uint32_t(js::ESClass::Other);
  433. AutoJSAPI jsapi;
  434. if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
  435. return false;
  436. JSContext* cx = jsapi.cx();
  437. RootedObject obj(cx, findObjectById(cx, objId));
  438. if (!obj)
  439. return deadCPOW(jsapi, rs);
  440. LOG("%s.getBuiltinClass()", ReceiverObj(objId));
  441. js::ESClass cls;
  442. if (!js::GetBuiltinClass(cx, obj, &cls))
  443. return fail(jsapi, rs);
  444. *classValue = uint32_t(cls);
  445. return ok(rs);
  446. }
  447. bool
  448. WrapperAnswer::RecvIsArray(const ObjectId& objId, ReturnStatus* rs,
  449. uint32_t* ans)
  450. {
  451. MaybeForceDebugGC();
  452. *ans = uint32_t(IsArrayAnswer::NotArray);
  453. AutoJSAPI jsapi;
  454. if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
  455. return false;
  456. JSContext* cx = jsapi.cx();
  457. RootedObject obj(cx, findObjectById(cx, objId));
  458. if (!obj)
  459. return deadCPOW(jsapi, rs);
  460. LOG("%s.isArray()", ReceiverObj(objId));
  461. IsArrayAnswer answer;
  462. if (!JS::IsArray(cx, obj, &answer))
  463. return fail(jsapi, rs);
  464. *ans = uint32_t(answer);
  465. return ok(rs);
  466. }
  467. bool
  468. WrapperAnswer::RecvClassName(const ObjectId& objId, nsCString* name)
  469. {
  470. MaybeForceDebugGC();
  471. AutoJSAPI jsapi;
  472. if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
  473. return false;
  474. JSContext* cx = jsapi.cx();
  475. RootedObject obj(cx, findObjectById(cx, objId));
  476. if (!obj) {
  477. // This is very unfortunate, but we have no choice.
  478. *name = "<dead CPOW>";
  479. return true;
  480. }
  481. LOG("%s.className()", ReceiverObj(objId));
  482. *name = js::ObjectClassName(cx, obj);
  483. return true;
  484. }
  485. bool
  486. WrapperAnswer::RecvGetPrototype(const ObjectId& objId, ReturnStatus* rs, ObjectOrNullVariant* result)
  487. {
  488. MaybeForceDebugGC();
  489. *result = NullVariant();
  490. AutoJSAPI jsapi;
  491. if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
  492. return false;
  493. JSContext* cx = jsapi.cx();
  494. RootedObject obj(cx, findObjectById(cx, objId));
  495. if (!obj)
  496. return deadCPOW(jsapi, rs);
  497. JS::RootedObject proto(cx);
  498. if (!JS_GetPrototype(cx, obj, &proto))
  499. return fail(jsapi, rs);
  500. if (!toObjectOrNullVariant(cx, proto, result))
  501. return fail(jsapi, rs);
  502. LOG("getPrototype(%s)", ReceiverObj(objId));
  503. return ok(rs);
  504. }
  505. bool
  506. WrapperAnswer::RecvGetPrototypeIfOrdinary(const ObjectId& objId, ReturnStatus* rs, bool* isOrdinary,
  507. ObjectOrNullVariant* result)
  508. {
  509. MaybeForceDebugGC();
  510. *result = NullVariant();
  511. *isOrdinary = false;
  512. AutoJSAPI jsapi;
  513. if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
  514. return false;
  515. JSContext* cx = jsapi.cx();
  516. RootedObject obj(cx, findObjectById(cx, objId));
  517. if (!obj)
  518. return deadCPOW(jsapi, rs);
  519. JS::RootedObject proto(cx);
  520. if (!JS_GetPrototypeIfOrdinary(cx, obj, isOrdinary, &proto))
  521. return fail(jsapi, rs);
  522. if (!toObjectOrNullVariant(cx, proto, result))
  523. return fail(jsapi, rs);
  524. LOG("getPrototypeIfOrdinary(%s)", ReceiverObj(objId));
  525. return ok(rs);
  526. }
  527. bool
  528. WrapperAnswer::RecvRegExpToShared(const ObjectId& objId, ReturnStatus* rs,
  529. nsString* source, uint32_t* flags)
  530. {
  531. MaybeForceDebugGC();
  532. AutoJSAPI jsapi;
  533. if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
  534. return false;
  535. JSContext* cx = jsapi.cx();
  536. RootedObject obj(cx, findObjectById(cx, objId));
  537. if (!obj)
  538. return deadCPOW(jsapi, rs);
  539. RootedString sourceJSStr(cx, JS_GetRegExpSource(cx, obj));
  540. if (!sourceJSStr)
  541. return fail(jsapi, rs);
  542. nsAutoJSString sourceStr;
  543. if (!sourceStr.init(cx, sourceJSStr))
  544. return fail(jsapi, rs);
  545. source->Assign(sourceStr);
  546. *flags = JS_GetRegExpFlags(cx, obj);
  547. return ok(rs);
  548. }
  549. bool
  550. WrapperAnswer::RecvGetPropertyKeys(const ObjectId& objId, const uint32_t& flags,
  551. ReturnStatus* rs, nsTArray<JSIDVariant>* ids)
  552. {
  553. MaybeForceDebugGC();
  554. AutoJSAPI jsapi;
  555. if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
  556. return false;
  557. JSContext* cx = jsapi.cx();
  558. RootedObject obj(cx, findObjectById(cx, objId));
  559. if (!obj)
  560. return deadCPOW(jsapi, rs);
  561. LOG("%s.getPropertyKeys()", ReceiverObj(objId));
  562. AutoIdVector props(cx);
  563. if (!js::GetPropertyKeys(cx, obj, flags, &props))
  564. return fail(jsapi, rs);
  565. for (size_t i = 0; i < props.length(); i++) {
  566. JSIDVariant id;
  567. if (!toJSIDVariant(cx, props[i], &id))
  568. return fail(jsapi, rs);
  569. ids->AppendElement(id);
  570. }
  571. return ok(rs);
  572. }
  573. bool
  574. WrapperAnswer::RecvInstanceOf(const ObjectId& objId, const JSIID& iid, ReturnStatus* rs,
  575. bool* instanceof)
  576. {
  577. MaybeForceDebugGC();
  578. AutoJSAPI jsapi;
  579. if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
  580. return false;
  581. JSContext* cx = jsapi.cx();
  582. *instanceof = false;
  583. RootedObject obj(cx, findObjectById(cx, objId));
  584. if (!obj)
  585. return deadCPOW(jsapi, rs);
  586. LOG("%s.instanceOf()", ReceiverObj(objId));
  587. nsID nsiid;
  588. ConvertID(iid, &nsiid);
  589. nsresult rv = xpc::HasInstance(cx, obj, &nsiid, instanceof);
  590. if (rv != NS_OK)
  591. return fail(jsapi, rs);
  592. return ok(rs);
  593. }
  594. bool
  595. WrapperAnswer::RecvDOMInstanceOf(const ObjectId& objId, const int& prototypeID,
  596. const int& depth, ReturnStatus* rs, bool* instanceof)
  597. {
  598. MaybeForceDebugGC();
  599. AutoJSAPI jsapi;
  600. if (NS_WARN_IF(!jsapi.Init(scopeForTargetObjects())))
  601. return false;
  602. JSContext* cx = jsapi.cx();
  603. *instanceof = false;
  604. RootedObject obj(cx, findObjectById(cx, objId));
  605. if (!obj)
  606. return deadCPOW(jsapi, rs);
  607. LOG("%s.domInstanceOf()", ReceiverObj(objId));
  608. bool tmp;
  609. if (!mozilla::dom::InterfaceHasInstance(cx, prototypeID, depth, obj, &tmp))
  610. return fail(jsapi, rs);
  611. *instanceof = tmp;
  612. return ok(rs);
  613. }
  614. bool
  615. WrapperAnswer::RecvDropObject(const ObjectId& objId)
  616. {
  617. JSObject* obj = objects_.findPreserveColor(objId);
  618. if (obj) {
  619. objectIdMap(objId.hasXrayWaiver()).remove(obj);
  620. objects_.remove(objId);
  621. }
  622. return true;
  623. }