js/ipc/JavaScriptShared.cpp

branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
equal deleted inserted replaced
-1:000000000000 0:975ba6ae278f
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 "jsfriendapi.h"
11 #include "xpcprivate.h"
12
13 using namespace js;
14 using namespace JS;
15 using namespace mozilla;
16 using namespace mozilla::jsipc;
17
18 ObjectStore::ObjectStore()
19 : table_(SystemAllocPolicy())
20 {
21 }
22
23 bool
24 ObjectStore::init()
25 {
26 return table_.init(32);
27 }
28
29 void
30 ObjectStore::trace(JSTracer *trc)
31 {
32 for (ObjectTable::Range r(table_.all()); !r.empty(); r.popFront()) {
33 DebugOnly<JSObject *> prior = r.front().value().get();
34 JS_CallHeapObjectTracer(trc, &r.front().value(), "ipc-object");
35 MOZ_ASSERT(r.front().value() == prior);
36 }
37 }
38
39 JSObject *
40 ObjectStore::find(ObjectId id)
41 {
42 ObjectTable::Ptr p = table_.lookup(id);
43 if (!p)
44 return nullptr;
45 return p->value();
46 }
47
48 bool
49 ObjectStore::add(ObjectId id, JSObject *obj)
50 {
51 return table_.put(id, obj);
52 }
53
54 void
55 ObjectStore::remove(ObjectId id)
56 {
57 table_.remove(id);
58 }
59
60 ObjectIdCache::ObjectIdCache()
61 : table_(nullptr)
62 {
63 }
64
65 ObjectIdCache::~ObjectIdCache()
66 {
67 if (table_) {
68 dom::AddForDeferredFinalization<ObjectIdTable, nsAutoPtr>(table_);
69 table_ = nullptr;
70 }
71 }
72
73 bool
74 ObjectIdCache::init()
75 {
76 MOZ_ASSERT(!table_);
77 table_ = new ObjectIdTable(SystemAllocPolicy());
78 return table_ && table_->init(32);
79 }
80
81 void
82 ObjectIdCache::trace(JSTracer *trc)
83 {
84 for (ObjectIdTable::Range r(table_->all()); !r.empty(); r.popFront()) {
85 JSObject *obj = r.front().key();
86 JS_CallObjectTracer(trc, &obj, "ipc-id");
87 MOZ_ASSERT(obj == r.front().key());
88 }
89 }
90
91 ObjectId
92 ObjectIdCache::find(JSObject *obj)
93 {
94 ObjectIdTable::Ptr p = table_->lookup(obj);
95 if (!p)
96 return 0;
97 return p->value();
98 }
99
100 bool
101 ObjectIdCache::add(JSContext *cx, JSObject *obj, ObjectId id)
102 {
103 if (!table_->put(obj, id))
104 return false;
105 JS_StoreObjectPostBarrierCallback(cx, keyMarkCallback, obj, table_);
106 return true;
107 }
108
109 /*
110 * This function is called during minor GCs for each key in the HashMap that has
111 * been moved.
112 */
113 /* static */ void
114 ObjectIdCache::keyMarkCallback(JSTracer *trc, JSObject *key, void *data) {
115 ObjectIdTable* table = static_cast<ObjectIdTable*>(data);
116 JSObject *prior = key;
117 JS_CallObjectTracer(trc, &key, "ObjectIdCache::table_ key");
118 table->rekeyIfMoved(prior, key);
119 }
120
121 void
122 ObjectIdCache::remove(JSObject *obj)
123 {
124 table_->remove(obj);
125 }
126
127 bool
128 JavaScriptShared::init()
129 {
130 if (!objects_.init())
131 return false;
132 return true;
133 }
134
135 bool
136 JavaScriptShared::convertIdToGeckoString(JSContext *cx, JS::HandleId id, nsString *to)
137 {
138 RootedValue idval(cx);
139 if (!JS_IdToValue(cx, id, &idval))
140 return false;
141
142 RootedString str(cx, ToString(cx, idval));
143 if (!str)
144 return false;
145
146 const jschar *chars = JS_GetStringCharsZ(cx, str);
147 if (!chars)
148 return false;
149
150 *to = chars;
151 return true;
152 }
153
154 bool
155 JavaScriptShared::convertGeckoStringToId(JSContext *cx, const nsString &from, JS::MutableHandleId to)
156 {
157 RootedString str(cx, JS_NewUCStringCopyN(cx, from.BeginReading(), from.Length()));
158 if (!str)
159 return false;
160
161 return JS_StringToId(cx, str, to);
162 }
163
164 bool
165 JavaScriptShared::toVariant(JSContext *cx, JS::HandleValue from, JSVariant *to)
166 {
167 switch (JS_TypeOfValue(cx, from)) {
168 case JSTYPE_VOID:
169 *to = void_t();
170 return true;
171
172 case JSTYPE_NULL:
173 {
174 *to = uint64_t(0);
175 return true;
176 }
177
178 case JSTYPE_OBJECT:
179 case JSTYPE_FUNCTION:
180 {
181 RootedObject obj(cx, from.toObjectOrNull());
182 if (!obj) {
183 MOZ_ASSERT(from == JSVAL_NULL);
184 *to = uint64_t(0);
185 return true;
186 }
187
188 if (xpc_JSObjectIsID(cx, obj)) {
189 JSIID iid;
190 const nsID *id = xpc_JSObjectToID(cx, obj);
191 ConvertID(*id, &iid);
192 *to = iid;
193 return true;
194 }
195
196 ObjectId id;
197 if (!makeId(cx, obj, &id))
198 return false;
199 *to = uint64_t(id);
200 return true;
201 }
202
203 case JSTYPE_STRING:
204 {
205 nsDependentJSString dep;
206 if (!dep.init(cx, from))
207 return false;
208 *to = dep;
209 return true;
210 }
211
212 case JSTYPE_NUMBER:
213 if (JSVAL_IS_INT(from))
214 *to = double(from.toInt32());
215 else
216 *to = from.toDouble();
217 return true;
218
219 case JSTYPE_BOOLEAN:
220 *to = from.toBoolean();
221 return true;
222
223 default:
224 MOZ_ASSERT(false);
225 return false;
226 }
227 }
228
229 bool
230 JavaScriptShared::toValue(JSContext *cx, const JSVariant &from, MutableHandleValue to)
231 {
232 switch (from.type()) {
233 case JSVariant::Tvoid_t:
234 to.set(UndefinedValue());
235 return true;
236
237 case JSVariant::Tuint64_t:
238 {
239 ObjectId id = from.get_uint64_t();
240 if (id) {
241 JSObject *obj = unwrap(cx, id);
242 if (!obj)
243 return false;
244 to.set(ObjectValue(*obj));
245 } else {
246 to.set(JSVAL_NULL);
247 }
248 return true;
249 }
250
251 case JSVariant::Tdouble:
252 to.set(JS_NumberValue(from.get_double()));
253 return true;
254
255 case JSVariant::Tbool:
256 to.set(BOOLEAN_TO_JSVAL(from.get_bool()));
257 return true;
258
259 case JSVariant::TnsString:
260 {
261 const nsString &old = from.get_nsString();
262 JSString *str = JS_NewUCStringCopyN(cx, old.BeginReading(), old.Length());
263 if (!str)
264 return false;
265 to.set(StringValue(str));
266 return true;
267 }
268
269 case JSVariant::TJSIID:
270 {
271 nsID iid;
272 const JSIID &id = from.get_JSIID();
273 ConvertID(id, &iid);
274
275 JSCompartment *compartment = GetContextCompartment(cx);
276 RootedObject global(cx, JS_GetGlobalForCompartmentOrNull(cx, compartment));
277 JSObject *obj = xpc_NewIDObject(cx, global, iid);
278 if (!obj)
279 return false;
280 to.set(ObjectValue(*obj));
281 return true;
282 }
283
284 default:
285 return false;
286 }
287 }
288
289 /* static */ void
290 JavaScriptShared::ConvertID(const nsID &from, JSIID *to)
291 {
292 to->m0() = from.m0;
293 to->m1() = from.m1;
294 to->m2() = from.m2;
295 to->m3_0() = from.m3[0];
296 to->m3_1() = from.m3[1];
297 to->m3_2() = from.m3[2];
298 to->m3_3() = from.m3[3];
299 to->m3_4() = from.m3[4];
300 to->m3_5() = from.m3[5];
301 to->m3_6() = from.m3[6];
302 to->m3_7() = from.m3[7];
303 }
304
305 /* static */ void
306 JavaScriptShared::ConvertID(const JSIID &from, nsID *to)
307 {
308 to->m0 = from.m0();
309 to->m1 = from.m1();
310 to->m2 = from.m2();
311 to->m3[0] = from.m3_0();
312 to->m3[1] = from.m3_1();
313 to->m3[2] = from.m3_2();
314 to->m3[3] = from.m3_3();
315 to->m3[4] = from.m3_4();
316 to->m3[5] = from.m3_5();
317 to->m3[6] = from.m3_6();
318 to->m3[7] = from.m3_7();
319 }
320
321 static const uint32_t DefaultPropertyOp = 1;
322 static const uint32_t GetterOnlyPropertyStub = 2;
323 static const uint32_t UnknownPropertyOp = 3;
324
325 bool
326 JavaScriptShared::fromDescriptor(JSContext *cx, Handle<JSPropertyDescriptor> desc,
327 PPropertyDescriptor *out)
328 {
329 out->attrs() = desc.attributes();
330 if (!toVariant(cx, desc.value(), &out->value()))
331 return false;
332
333 if (!makeId(cx, desc.object(), &out->objId()))
334 return false;
335
336 if (!desc.getter()) {
337 out->getter() = 0;
338 } else if (desc.hasGetterObject()) {
339 JSObject *getter = desc.getterObject();
340 if (!makeId(cx, getter, &out->getter()))
341 return false;
342 } else {
343 if (desc.getter() == JS_PropertyStub)
344 out->getter() = DefaultPropertyOp;
345 else
346 out->getter() = UnknownPropertyOp;
347 }
348
349 if (!desc.setter()) {
350 out->setter() = 0;
351 } else if (desc.hasSetterObject()) {
352 JSObject *setter = desc.setterObject();
353 if (!makeId(cx, setter, &out->setter()))
354 return false;
355 } else {
356 if (desc.setter() == JS_StrictPropertyStub)
357 out->setter() = DefaultPropertyOp;
358 else if (desc.setter() == js_GetterOnlyPropertyStub)
359 out->setter() = GetterOnlyPropertyStub;
360 else
361 out->setter() = UnknownPropertyOp;
362 }
363
364 return true;
365 }
366
367 bool
368 UnknownPropertyStub(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp)
369 {
370 JS_ReportError(cx, "getter could not be wrapped via CPOWs");
371 return false;
372 }
373
374 bool
375 UnknownStrictPropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool strict, MutableHandleValue vp)
376 {
377 JS_ReportError(cx, "setter could not be wrapped via CPOWs");
378 return false;
379 }
380
381 bool
382 JavaScriptShared::toDescriptor(JSContext *cx, const PPropertyDescriptor &in,
383 MutableHandle<JSPropertyDescriptor> out)
384 {
385 out.setAttributes(in.attrs());
386 if (!toValue(cx, in.value(), out.value()))
387 return false;
388 Rooted<JSObject*> obj(cx);
389 if (!unwrap(cx, in.objId(), &obj))
390 return false;
391 out.object().set(obj);
392
393 if (!in.getter()) {
394 out.setGetter(nullptr);
395 } else if (in.attrs() & JSPROP_GETTER) {
396 Rooted<JSObject*> getter(cx);
397 if (!unwrap(cx, in.getter(), &getter))
398 return false;
399 out.setGetter(JS_DATA_TO_FUNC_PTR(JSPropertyOp, getter.get()));
400 } else {
401 if (in.getter() == DefaultPropertyOp)
402 out.setGetter(JS_PropertyStub);
403 else
404 out.setGetter(UnknownPropertyStub);
405 }
406
407 if (!in.setter()) {
408 out.setSetter(nullptr);
409 } else if (in.attrs() & JSPROP_SETTER) {
410 Rooted<JSObject*> setter(cx);
411 if (!unwrap(cx, in.setter(), &setter))
412 return false;
413 out.setSetter(JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, setter.get()));
414 } else {
415 if (in.setter() == DefaultPropertyOp)
416 out.setSetter(JS_StrictPropertyStub);
417 else if (in.setter() == GetterOnlyPropertyStub)
418 out.setSetter(js_GetterOnlyPropertyStub);
419 else
420 out.setSetter(UnknownStrictPropertyStub);
421 }
422
423 return true;
424 }
425
426 bool
427 CpowIdHolder::ToObject(JSContext *cx, JS::MutableHandleObject objp)
428 {
429 return js_->Unwrap(cx, cpows_, objp);
430 }
431
432 bool
433 JavaScriptShared::Unwrap(JSContext *cx, const InfallibleTArray<CpowEntry> &aCpows,
434 JS::MutableHandleObject objp)
435 {
436 objp.set(nullptr);
437
438 if (!aCpows.Length())
439 return true;
440
441 RootedObject obj(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
442 if (!obj)
443 return false;
444
445 RootedValue v(cx);
446 RootedString str(cx);
447 for (size_t i = 0; i < aCpows.Length(); i++) {
448 const nsString &name = aCpows[i].name();
449
450 if (!toValue(cx, aCpows[i].value(), &v))
451 return false;
452
453 if (!JS_DefineUCProperty(cx,
454 obj,
455 name.BeginReading(),
456 name.Length(),
457 v,
458 nullptr,
459 nullptr,
460 JSPROP_ENUMERATE))
461 {
462 return false;
463 }
464 }
465
466 objp.set(obj);
467 return true;
468 }
469
470 bool
471 JavaScriptShared::Wrap(JSContext *cx, HandleObject aObj, InfallibleTArray<CpowEntry> *outCpows)
472 {
473 if (!aObj)
474 return true;
475
476 AutoIdArray ids(cx, JS_Enumerate(cx, aObj));
477 if (!ids)
478 return false;
479
480 RootedId id(cx);
481 RootedValue v(cx);
482 for (size_t i = 0; i < ids.length(); i++) {
483 id = ids[i];
484
485 nsString str;
486 if (!convertIdToGeckoString(cx, id, &str))
487 return false;
488
489 if (!JS_GetPropertyById(cx, aObj, id, &v))
490 return false;
491
492 JSVariant var;
493 if (!toVariant(cx, v, &var))
494 return false;
495
496 outCpows->AppendElement(CpowEntry(str, var));
497 }
498
499 return true;
500 }
501

mercurial