Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/js/ipc/JavaScriptShared.cpp
Line
Count
Source (jump to first uncovered line)
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 "JavaScriptShared.h"
9
#include "mozilla/dom/BindingUtils.h"
10
#include "mozilla/dom/CPOWManagerGetter.h"
11
#include "mozilla/dom/TabChild.h"
12
#include "jsfriendapi.h"
13
#include "xpcprivate.h"
14
#include "WrapperFactory.h"
15
#include "mozilla/Preferences.h"
16
17
using namespace js;
18
using namespace JS;
19
using namespace mozilla;
20
using namespace mozilla::jsipc;
21
22
IdToObjectMap::IdToObjectMap()
23
  : table_(SystemAllocPolicy(), 32)
24
0
{
25
0
}
26
27
void
28
IdToObjectMap::trace(JSTracer* trc, uint64_t minimumId)
29
0
{
30
0
    for (Table::Range r(table_.all()); !r.empty(); r.popFront()) {
31
0
        if (r.front().key().serialNumber() >= minimumId) {
32
0
            JS::TraceEdge(trc, &r.front().value(), "ipc-object");
33
0
        }
34
0
    }
35
0
}
36
37
void
38
IdToObjectMap::sweep()
39
0
{
40
0
    for (Table::Enum e(table_); !e.empty(); e.popFront()) {
41
0
        JS::Heap<JSObject*>* objp = &e.front().value();
42
0
        JS_UpdateWeakPointerAfterGC(objp);
43
0
        if (!*objp) {
44
0
            e.removeFront();
45
0
        }
46
0
    }
47
0
}
48
49
JSObject*
50
IdToObjectMap::find(ObjectId id)
51
0
{
52
0
    Table::Ptr p = table_.lookup(id);
53
0
    if (!p) {
54
0
        return nullptr;
55
0
    }
56
0
    return p->value();
57
0
}
58
59
JSObject*
60
IdToObjectMap::findPreserveColor(ObjectId id)
61
0
{
62
0
    Table::Ptr p = table_.lookup(id);
63
0
    if (!p) {
64
0
        return nullptr;
65
0
    }
66
0
    return p->value().unbarrieredGet();
67
0
}
68
69
bool
70
IdToObjectMap::add(ObjectId id, JSObject* obj)
71
0
{
72
0
    return table_.put(id, obj);
73
0
}
74
75
void
76
IdToObjectMap::remove(ObjectId id)
77
0
{
78
0
    table_.remove(id);
79
0
}
80
81
void
82
IdToObjectMap::clear()
83
0
{
84
0
    table_.clear();
85
0
}
86
87
bool
88
IdToObjectMap::empty() const
89
0
{
90
0
    return table_.empty();
91
0
}
92
93
#ifdef DEBUG
94
bool
95
IdToObjectMap::has(const ObjectId& id, const JSObject* obj) const
96
{
97
    auto p = table_.lookup(id);
98
    if (!p) {
99
        return false;
100
    }
101
    return p->value() == obj;
102
}
103
#endif
104
105
ObjectToIdMap::ObjectToIdMap()
106
  : table_(SystemAllocPolicy(), 32)
107
0
{
108
0
}
109
110
void
111
ObjectToIdMap::trace(JSTracer* trc)
112
0
{
113
0
    table_.trace(trc);
114
0
}
115
116
void
117
ObjectToIdMap::sweep()
118
0
{
119
0
    table_.sweep();
120
0
}
121
122
ObjectId
123
ObjectToIdMap::find(JSObject* obj)
124
0
{
125
0
    Table::Ptr p = table_.lookup(obj);
126
0
    if (!p) {
127
0
        return ObjectId::nullId();
128
0
    }
129
0
    return p->value();
130
0
}
131
132
bool
133
ObjectToIdMap::add(JSContext* cx, JSObject* obj, ObjectId id)
134
0
{
135
0
    return table_.put(obj, id);
136
0
}
137
138
void
139
ObjectToIdMap::remove(JSObject* obj)
140
0
{
141
0
    table_.remove(obj);
142
0
}
143
144
void
145
ObjectToIdMap::clear()
146
0
{
147
0
    table_.clear();
148
0
}
149
150
bool JavaScriptShared::sLoggingInitialized;
151
bool JavaScriptShared::sLoggingEnabled;
152
bool JavaScriptShared::sStackLoggingEnabled;
153
154
JavaScriptShared::JavaScriptShared()
155
  : refcount_(1),
156
    nextSerialNumber_(1),
157
    nextCPOWNumber_(1)
158
0
{
159
0
    if (!sLoggingInitialized) {
160
0
        sLoggingInitialized = true;
161
0
162
0
        if (PR_GetEnv("MOZ_CPOW_LOG")) {
163
0
            sLoggingEnabled = true;
164
0
            sStackLoggingEnabled = strstr(PR_GetEnv("MOZ_CPOW_LOG"), "stacks");
165
0
        } else {
166
0
            Preferences::AddBoolVarCache(&sLoggingEnabled,
167
0
                                         "dom.ipc.cpows.log.enabled", false);
168
0
            Preferences::AddBoolVarCache(&sStackLoggingEnabled,
169
0
                                         "dom.ipc.cpows.log.stack", false);
170
0
        }
171
0
    }
172
0
}
173
174
JavaScriptShared::~JavaScriptShared()
175
0
{
176
0
    MOZ_RELEASE_ASSERT(cpows_.empty());
177
0
}
178
179
void
180
JavaScriptShared::decref()
181
0
{
182
0
    refcount_--;
183
0
    if (!refcount_) {
184
0
        delete this;
185
0
    }
186
0
}
187
188
void
189
JavaScriptShared::incref()
190
0
{
191
0
    refcount_++;
192
0
}
193
194
bool
195
JavaScriptShared::convertIdToGeckoString(JSContext* cx, JS::HandleId id, nsString* to)
196
0
{
197
0
    RootedValue idval(cx);
198
0
    if (!JS_IdToValue(cx, id, &idval)) {
199
0
        return false;
200
0
    }
201
0
202
0
    RootedString str(cx, ToString(cx, idval));
203
0
    if (!str) {
204
0
        return false;
205
0
    }
206
0
207
0
    return AssignJSString(cx, *to, str);
208
0
}
209
210
bool
211
JavaScriptShared::convertGeckoStringToId(JSContext* cx, const nsString& from, JS::MutableHandleId to)
212
0
{
213
0
    RootedString str(cx, JS_NewUCStringCopyN(cx, from.BeginReading(), from.Length()));
214
0
    if (!str) {
215
0
        return false;
216
0
    }
217
0
218
0
    return JS_StringToId(cx, str, to);
219
0
}
220
221
bool
222
JavaScriptShared::toVariant(JSContext* cx, JS::HandleValue from, JSVariant* to)
223
0
{
224
0
    switch (JS_TypeOfValue(cx, from)) {
225
0
      case JSTYPE_UNDEFINED:
226
0
        *to = UndefinedVariant();
227
0
        return true;
228
0
229
0
      case JSTYPE_OBJECT:
230
0
      case JSTYPE_FUNCTION:
231
0
      {
232
0
        RootedObject obj(cx, from.toObjectOrNull());
233
0
        if (!obj) {
234
0
            MOZ_ASSERT(from.isNull());
235
0
            *to = NullVariant();
236
0
            return true;
237
0
        }
238
0
239
0
        if (xpc_JSObjectIsID(cx, obj)) {
240
0
            JSIID iid;
241
0
            const nsID* id = xpc_JSObjectToID(cx, obj);
242
0
            ConvertID(*id, &iid);
243
0
            *to = iid;
244
0
            return true;
245
0
        }
246
0
247
0
        ObjectVariant objVar;
248
0
        if (!toObjectVariant(cx, obj, &objVar)) {
249
0
            return false;
250
0
        }
251
0
        *to = objVar;
252
0
        return true;
253
0
      }
254
0
255
0
      case JSTYPE_SYMBOL:
256
0
      {
257
0
        RootedSymbol sym(cx, from.toSymbol());
258
0
259
0
        SymbolVariant symVar;
260
0
        if (!toSymbolVariant(cx, sym, &symVar)) {
261
0
            return false;
262
0
        }
263
0
        *to = symVar;
264
0
        return true;
265
0
      }
266
0
267
0
      case JSTYPE_STRING:
268
0
      {
269
0
        nsAutoJSString autoStr;
270
0
        if (!autoStr.init(cx, from)) {
271
0
            return false;
272
0
        }
273
0
        *to = autoStr;
274
0
        return true;
275
0
      }
276
0
277
0
      case JSTYPE_NUMBER:
278
0
        if (from.isInt32()) {
279
0
            *to = double(from.toInt32());
280
0
        } else {
281
0
            *to = from.toDouble();
282
0
        }
283
0
        return true;
284
0
285
0
      case JSTYPE_BOOLEAN:
286
0
        *to = from.toBoolean();
287
0
        return true;
288
0
289
0
      default:
290
0
        MOZ_ASSERT(false);
291
0
        return false;
292
0
    }
293
0
}
294
295
bool
296
JavaScriptShared::fromVariant(JSContext* cx, const JSVariant& from, MutableHandleValue to)
297
0
{
298
0
    switch (from.type()) {
299
0
        case JSVariant::TUndefinedVariant:
300
0
          to.set(UndefinedValue());
301
0
          return true;
302
0
303
0
        case JSVariant::TNullVariant:
304
0
          to.set(NullValue());
305
0
          return true;
306
0
307
0
        case JSVariant::TObjectVariant:
308
0
        {
309
0
          JSObject* obj = fromObjectVariant(cx, from.get_ObjectVariant());
310
0
          if (!obj) {
311
0
              return false;
312
0
          }
313
0
          to.set(ObjectValue(*obj));
314
0
          return true;
315
0
        }
316
0
317
0
        case JSVariant::TSymbolVariant:
318
0
        {
319
0
          Symbol* sym = fromSymbolVariant(cx, from.get_SymbolVariant());
320
0
          if (!sym) {
321
0
              return false;
322
0
          }
323
0
          to.setSymbol(sym);
324
0
          return true;
325
0
        }
326
0
327
0
        case JSVariant::Tdouble:
328
0
          to.set(JS_NumberValue(from.get_double()));
329
0
          return true;
330
0
331
0
        case JSVariant::Tbool:
332
0
          to.setBoolean(from.get_bool());
333
0
          return true;
334
0
335
0
        case JSVariant::TnsString:
336
0
        {
337
0
          const nsString& old = from.get_nsString();
338
0
          JSString* str = JS_NewUCStringCopyN(cx, old.BeginReading(), old.Length());
339
0
          if (!str) {
340
0
              return false;
341
0
          }
342
0
          to.set(StringValue(str));
343
0
          return true;
344
0
        }
345
0
346
0
        case JSVariant::TJSIID:
347
0
        {
348
0
          nsID iid;
349
0
          const JSIID& id = from.get_JSIID();
350
0
          ConvertID(id, &iid);
351
0
352
0
          RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
353
0
          JSObject* obj = xpc_NewIDObject(cx, global, iid);
354
0
          if (!obj) {
355
0
              return false;
356
0
          }
357
0
          to.set(ObjectValue(*obj));
358
0
          return true;
359
0
        }
360
0
361
0
        default:
362
0
          MOZ_CRASH("NYI");
363
0
          return false;
364
0
    }
365
0
}
366
367
bool
368
JavaScriptShared::toJSIDVariant(JSContext* cx, HandleId from, JSIDVariant* to)
369
0
{
370
0
    if (JSID_IS_STRING(from)) {
371
0
        nsAutoJSString autoStr;
372
0
        if (!autoStr.init(cx, JSID_TO_STRING(from))) {
373
0
            return false;
374
0
        }
375
0
        *to = autoStr;
376
0
        return true;
377
0
    }
378
0
    if (JSID_IS_INT(from)) {
379
0
        *to = JSID_TO_INT(from);
380
0
        return true;
381
0
    }
382
0
    if (JSID_IS_SYMBOL(from)) {
383
0
        SymbolVariant symVar;
384
0
        if (!toSymbolVariant(cx, JSID_TO_SYMBOL(from), &symVar)) {
385
0
            return false;
386
0
        }
387
0
        *to = symVar;
388
0
        return true;
389
0
    }
390
0
    MOZ_ASSERT(false);
391
0
    return false;
392
0
}
393
394
bool
395
JavaScriptShared::fromJSIDVariant(JSContext* cx, const JSIDVariant& from, MutableHandleId to)
396
0
{
397
0
    switch (from.type()) {
398
0
      case JSIDVariant::TSymbolVariant: {
399
0
        Symbol* sym = fromSymbolVariant(cx, from.get_SymbolVariant());
400
0
        if (!sym) {
401
0
            return false;
402
0
        }
403
0
        to.set(SYMBOL_TO_JSID(sym));
404
0
        return true;
405
0
      }
406
0
407
0
      case JSIDVariant::TnsString:
408
0
        return convertGeckoStringToId(cx, from.get_nsString(), to);
409
0
410
0
      case JSIDVariant::Tint32_t:
411
0
        to.set(INT_TO_JSID(from.get_int32_t()));
412
0
        return true;
413
0
414
0
      default:
415
0
        return false;
416
0
    }
417
0
}
418
419
bool
420
JavaScriptShared::toSymbolVariant(JSContext* cx, JS::Symbol* symArg, SymbolVariant* symVarp)
421
0
{
422
0
    RootedSymbol sym(cx, symArg);
423
0
    MOZ_ASSERT(sym);
424
0
425
0
    SymbolCode code = GetSymbolCode(sym);
426
0
    if (static_cast<uint32_t>(code) < WellKnownSymbolLimit) {
427
0
        *symVarp = WellKnownSymbol(static_cast<uint32_t>(code));
428
0
        return true;
429
0
    }
430
0
    if (code == SymbolCode::InSymbolRegistry) {
431
0
        nsAutoJSString autoStr;
432
0
        if (!autoStr.init(cx, GetSymbolDescription(sym))) {
433
0
            return false;
434
0
        }
435
0
        *symVarp = RegisteredSymbol(autoStr);
436
0
        return true;
437
0
    }
438
0
439
0
    JS_ReportErrorASCII(cx, "unique symbol can't be used with CPOW");
440
0
    return false;
441
0
}
442
443
JS::Symbol*
444
JavaScriptShared::fromSymbolVariant(JSContext* cx, const SymbolVariant& symVar)
445
0
{
446
0
    switch (symVar.type()) {
447
0
      case SymbolVariant::TWellKnownSymbol: {
448
0
        uint32_t which = symVar.get_WellKnownSymbol().which();
449
0
        if (which < WellKnownSymbolLimit) {
450
0
            return GetWellKnownSymbol(cx, static_cast<SymbolCode>(which));
451
0
        }
452
0
        MOZ_ASSERT(false, "bad child data");
453
0
        return nullptr;
454
0
      }
455
0
456
0
      case SymbolVariant::TRegisteredSymbol: {
457
0
        nsString key = symVar.get_RegisteredSymbol().key();
458
0
        RootedString str(cx, JS_NewUCStringCopyN(cx, key.get(), key.Length()));
459
0
        if (!str) {
460
0
            return nullptr;
461
0
        }
462
0
        return GetSymbolFor(cx, str);
463
0
      }
464
0
465
0
      default:
466
0
        return nullptr;
467
0
    }
468
0
}
469
470
/* static */ void
471
JavaScriptShared::ConvertID(const nsID& from, JSIID* to)
472
0
{
473
0
    to->m0() = from.m0;
474
0
    to->m1() = from.m1;
475
0
    to->m2() = from.m2;
476
0
    to->m3_0() = from.m3[0];
477
0
    to->m3_1() = from.m3[1];
478
0
    to->m3_2() = from.m3[2];
479
0
    to->m3_3() = from.m3[3];
480
0
    to->m3_4() = from.m3[4];
481
0
    to->m3_5() = from.m3[5];
482
0
    to->m3_6() = from.m3[6];
483
0
    to->m3_7() = from.m3[7];
484
0
}
485
486
/* static */ void
487
JavaScriptShared::ConvertID(const JSIID& from, nsID* to)
488
0
{
489
0
    to->m0 = from.m0();
490
0
    to->m1 = from.m1();
491
0
    to->m2 = from.m2();
492
0
    to->m3[0] = from.m3_0();
493
0
    to->m3[1] = from.m3_1();
494
0
    to->m3[2] = from.m3_2();
495
0
    to->m3[3] = from.m3_3();
496
0
    to->m3[4] = from.m3_4();
497
0
    to->m3[5] = from.m3_5();
498
0
    to->m3[6] = from.m3_6();
499
0
    to->m3[7] = from.m3_7();
500
0
}
501
502
JSObject*
503
JavaScriptShared::findCPOWById(const ObjectId& objId)
504
0
{
505
0
    JSObject* obj = findCPOWByIdPreserveColor(objId);
506
0
    if (obj) {
507
0
        JS::ExposeObjectToActiveJS(obj);
508
0
    }
509
0
    return obj;
510
0
}
511
512
JSObject*
513
JavaScriptShared::findCPOWByIdPreserveColor(const ObjectId& objId)
514
0
{
515
0
    JSObject* obj = cpows_.findPreserveColor(objId);
516
0
    if (!obj) {
517
0
        return nullptr;
518
0
    }
519
0
520
0
    if (js::gc::EdgeNeedsSweepUnbarriered(&obj)) {
521
0
        cpows_.remove(objId);
522
0
        return nullptr;
523
0
    }
524
0
525
0
    return obj;
526
0
}
527
528
JSObject*
529
JavaScriptShared::findObjectById(JSContext* cx, const ObjectId& objId)
530
0
{
531
0
    RootedObject obj(cx, objects_.find(objId));
532
0
    if (!obj) {
533
0
        JS_ReportErrorASCII(cx, "operation not possible on dead CPOW");
534
0
        return nullptr;
535
0
    }
536
0
537
0
    // Each process has a dedicated compartment for CPOW targets. All CPOWs
538
0
    // from the other process point to objects in this scope. From there, they
539
0
    // can access objects in other compartments using cross-compartment
540
0
    // wrappers.
541
0
    JSAutoRealm ar(cx, scopeForTargetObjects());
542
0
    if (objId.hasXrayWaiver()) {
543
0
        obj = js::ToWindowProxyIfWindow(obj);
544
0
        MOZ_ASSERT(obj);
545
0
        if (!xpc::WrapperFactory::WaiveXrayAndWrap(cx, &obj)) {
546
0
            return nullptr;
547
0
        }
548
0
    } else {
549
0
        if (!JS_WrapObject(cx, &obj)) {
550
0
            return nullptr;
551
0
        }
552
0
    }
553
0
    return obj;
554
0
}
555
556
static const uint64_t UnknownPropertyOp = 1;
557
558
bool
559
JavaScriptShared::fromDescriptor(JSContext* cx, Handle<PropertyDescriptor> desc,
560
                                 PPropertyDescriptor* out)
561
0
{
562
0
    out->attrs() = desc.attributes();
563
0
    if (!toVariant(cx, desc.value(), &out->value())) {
564
0
        return false;
565
0
    }
566
0
567
0
    if (!toObjectOrNullVariant(cx, desc.object(), &out->obj())) {
568
0
        return false;
569
0
    }
570
0
571
0
    if (!desc.getter()) {
572
0
        out->getter() = 0;
573
0
    } else if (desc.hasGetterObject()) {
574
0
        JSObject* getter = desc.getterObject();
575
0
        ObjectVariant objVar;
576
0
        if (!toObjectVariant(cx, getter, &objVar)) {
577
0
            return false;
578
0
        }
579
0
        out->getter() = objVar;
580
0
    } else {
581
0
        out->getter() = UnknownPropertyOp;
582
0
    }
583
0
584
0
    if (!desc.setter()) {
585
0
        out->setter() = 0;
586
0
    } else if (desc.hasSetterObject()) {
587
0
        JSObject* setter = desc.setterObject();
588
0
        ObjectVariant objVar;
589
0
        if (!toObjectVariant(cx, setter, &objVar)) {
590
0
            return false;
591
0
        }
592
0
        out->setter() = objVar;
593
0
    } else {
594
0
        out->setter() = UnknownPropertyOp;
595
0
    }
596
0
597
0
    return true;
598
0
}
599
600
bool
601
UnknownPropertyStub(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp)
602
0
{
603
0
    JS_ReportErrorASCII(cx, "getter could not be wrapped via CPOWs");
604
0
    return false;
605
0
}
606
607
bool
608
UnknownStrictPropertyStub(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
609
                          ObjectOpResult& result)
610
0
{
611
0
    JS_ReportErrorASCII(cx, "setter could not be wrapped via CPOWs");
612
0
    return false;
613
0
}
614
615
bool
616
JavaScriptShared::toDescriptor(JSContext* cx, const PPropertyDescriptor& in,
617
                               MutableHandle<PropertyDescriptor> out)
618
0
{
619
0
    out.setAttributes(in.attrs());
620
0
    if (!fromVariant(cx, in.value(), out.value())) {
621
0
        return false;
622
0
    }
623
0
    out.object().set(fromObjectOrNullVariant(cx, in.obj()));
624
0
625
0
    if (in.getter().type() == GetterSetter::Tuint64_t && !in.getter().get_uint64_t()) {
626
0
        out.setGetter(nullptr);
627
0
    } else if (in.attrs() & JSPROP_GETTER) {
628
0
        Rooted<JSObject*> getter(cx);
629
0
        getter = fromObjectVariant(cx, in.getter().get_ObjectVariant());
630
0
        if (!getter) {
631
0
            return false;
632
0
        }
633
0
        out.setGetter(JS_DATA_TO_FUNC_PTR(JSGetterOp, getter.get()));
634
0
    } else {
635
0
        out.setGetter(UnknownPropertyStub);
636
0
    }
637
0
638
0
    if (in.setter().type() == GetterSetter::Tuint64_t && !in.setter().get_uint64_t()) {
639
0
        out.setSetter(nullptr);
640
0
    } else if (in.attrs() & JSPROP_SETTER) {
641
0
        Rooted<JSObject*> setter(cx);
642
0
        setter = fromObjectVariant(cx, in.setter().get_ObjectVariant());
643
0
        if (!setter) {
644
0
            return false;
645
0
        }
646
0
        out.setSetter(JS_DATA_TO_FUNC_PTR(JSSetterOp, setter.get()));
647
0
    } else {
648
0
        out.setSetter(UnknownStrictPropertyStub);
649
0
    }
650
0
651
0
    return true;
652
0
}
653
654
bool
655
JavaScriptShared::toObjectOrNullVariant(JSContext* cx, JSObject* obj, ObjectOrNullVariant* objVarp)
656
0
{
657
0
    if (!obj) {
658
0
        *objVarp = NullVariant();
659
0
        return true;
660
0
    }
661
0
662
0
    ObjectVariant objVar;
663
0
    if (!toObjectVariant(cx, obj, &objVar)) {
664
0
        return false;
665
0
    }
666
0
667
0
    *objVarp = objVar;
668
0
    return true;
669
0
}
670
671
JSObject*
672
JavaScriptShared::fromObjectOrNullVariant(JSContext* cx, const ObjectOrNullVariant& objVar)
673
0
{
674
0
    if (objVar.type() == ObjectOrNullVariant::TNullVariant) {
675
0
        return nullptr;
676
0
    }
677
0
678
0
    return fromObjectVariant(cx, objVar.get_ObjectVariant());
679
0
}
680
681
CrossProcessCpowHolder::CrossProcessCpowHolder(dom::CPOWManagerGetter* managerGetter,
682
                                               const InfallibleTArray<CpowEntry>& cpows)
683
  : js_(nullptr),
684
    cpows_(cpows),
685
    unwrapped_(false)
686
0
{
687
0
    // Only instantiate the CPOW manager if we might need it later.
688
0
    if (cpows.Length()) {
689
0
        js_ = managerGetter->GetCPOWManager();
690
0
    }
691
0
}
692
693
CrossProcessCpowHolder::~CrossProcessCpowHolder()
694
0
{
695
0
    if (cpows_.Length() && !unwrapped_) {
696
0
        // This should only happen if a message manager message
697
0
        // containing CPOWs gets ignored for some reason. We need to
698
0
        // unwrap every incoming CPOW in this process to ensure that
699
0
        // the corresponding part of the CPOW in the other process
700
0
        // will eventually be collected. The scope for this object
701
0
        // doesn't really matter, because it immediately becomes
702
0
        // garbage. Ignore this for middleman processes used when
703
0
        // recording or replaying, as they do not have a CPOW manager
704
0
        // and the message will also be received in the recording
705
0
        // process.
706
0
        if (recordreplay::IsMiddleman()) {
707
0
            return;
708
0
        }
709
0
        AutoJSAPI jsapi;
710
0
        if (!jsapi.Init(xpc::PrivilegedJunkScope())) {
711
0
            return;
712
0
        }
713
0
        JSContext* cx = jsapi.cx();
714
0
        JS::Rooted<JSObject*> cpows(cx);
715
0
        js_->Unwrap(cx, cpows_, &cpows);
716
0
    }
717
0
}
718
719
bool
720
CrossProcessCpowHolder::ToObject(JSContext* cx, JS::MutableHandleObject objp)
721
0
{
722
0
    unwrapped_ = true;
723
0
724
0
    if (!cpows_.Length()) {
725
0
        return true;
726
0
    }
727
0
728
0
    return js_->Unwrap(cx, cpows_, objp);
729
0
}
730
731
bool
732
JavaScriptShared::Unwrap(JSContext* cx, const InfallibleTArray<CpowEntry>& aCpows,
733
                         JS::MutableHandleObject objp)
734
0
{
735
0
    // Middleman processes never operate on CPOWs.
736
0
    MOZ_ASSERT(!recordreplay::IsMiddleman());
737
0
738
0
    objp.set(nullptr);
739
0
740
0
    if (!aCpows.Length()) {
741
0
        return true;
742
0
    }
743
0
744
0
    RootedObject obj(cx, JS_NewPlainObject(cx));
745
0
    if (!obj) {
746
0
        return false;
747
0
    }
748
0
749
0
    RootedValue v(cx);
750
0
    RootedString str(cx);
751
0
    for (size_t i = 0; i < aCpows.Length(); i++) {
752
0
        const nsString& name = aCpows[i].name();
753
0
754
0
        if (!fromVariant(cx, aCpows[i].value(), &v)) {
755
0
            return false;
756
0
        }
757
0
758
0
        if (!JS_DefineUCProperty(cx,
759
0
                                 obj,
760
0
                                 name.BeginReading(),
761
0
                                 name.Length(),
762
0
                                 v,
763
0
                                 JSPROP_ENUMERATE))
764
0
        {
765
0
            return false;
766
0
        }
767
0
    }
768
0
769
0
    objp.set(obj);
770
0
    return true;
771
0
}
772
773
bool
774
JavaScriptShared::Wrap(JSContext* cx, HandleObject aObj, InfallibleTArray<CpowEntry>* outCpows)
775
0
{
776
0
    if (!aObj) {
777
0
        return true;
778
0
    }
779
0
780
0
    Rooted<IdVector> ids(cx, IdVector(cx));
781
0
    if (!JS_Enumerate(cx, aObj, &ids)) {
782
0
        return false;
783
0
    }
784
0
785
0
    RootedId id(cx);
786
0
    RootedValue v(cx);
787
0
    for (size_t i = 0; i < ids.length(); i++) {
788
0
        id = ids[i];
789
0
790
0
        nsString str;
791
0
        if (!convertIdToGeckoString(cx, id, &str)) {
792
0
            return false;
793
0
        }
794
0
795
0
        if (!JS_GetPropertyById(cx, aObj, id, &v)) {
796
0
            return false;
797
0
        }
798
0
799
0
        JSVariant var;
800
0
        if (!toVariant(cx, v, &var)) {
801
0
            return false;
802
0
        }
803
0
804
0
        outCpows->AppendElement(CpowEntry(str, var));
805
0
    }
806
0
807
0
    return true;
808
0
}
809
810
CPOWManager*
811
mozilla::jsipc::CPOWManagerFor(PJavaScriptParent* aParent)
812
0
{
813
0
    return static_cast<JavaScriptParent*>(aParent);
814
0
}
815
816
CPOWManager*
817
mozilla::jsipc::CPOWManagerFor(PJavaScriptChild* aChild)
818
0
{
819
0
    return static_cast<JavaScriptChild*>(aChild);
820
0
}