js/ipc/JavaScriptShared.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial