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