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.

     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/. */
     8 #include "JavaScriptShared.h"
     9 #include "mozilla/dom/BindingUtils.h"
    10 #include "jsfriendapi.h"
    11 #include "xpcprivate.h"
    13 using namespace js;
    14 using namespace JS;
    15 using namespace mozilla;
    16 using namespace mozilla::jsipc;
    18 ObjectStore::ObjectStore()
    19   : table_(SystemAllocPolicy())
    20 {
    21 }
    23 bool
    24 ObjectStore::init()
    25 {
    26     return table_.init(32);
    27 }
    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 }
    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 }
    48 bool
    49 ObjectStore::add(ObjectId id, JSObject *obj)
    50 {
    51     return table_.put(id, obj);
    52 }
    54 void
    55 ObjectStore::remove(ObjectId id)
    56 {
    57     table_.remove(id);
    58 }
    60 ObjectIdCache::ObjectIdCache()
    61   : table_(nullptr)
    62 {
    63 }
    65 ObjectIdCache::~ObjectIdCache()
    66 {
    67     if (table_) {
    68         dom::AddForDeferredFinalization<ObjectIdTable, nsAutoPtr>(table_);
    69         table_ = nullptr;
    70     }
    71 }
    73 bool
    74 ObjectIdCache::init()
    75 {
    76     MOZ_ASSERT(!table_);
    77     table_ = new ObjectIdTable(SystemAllocPolicy());
    78     return table_ && table_->init(32);
    79 }
    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 }
    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 }
   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 }
   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 }
   121 void
   122 ObjectIdCache::remove(JSObject *obj)
   123 {
   124     table_->remove(obj);
   125 }
   127 bool
   128 JavaScriptShared::init()
   129 {
   130     if (!objects_.init())
   131         return false;
   132     return true;
   133 }
   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;
   142     RootedString str(cx, ToString(cx, idval));
   143     if (!str)
   144         return false;
   146     const jschar *chars = JS_GetStringCharsZ(cx, str);
   147     if (!chars)
   148         return false;
   150     *to = chars;
   151     return true;
   152 }
   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;
   161     return JS_StringToId(cx, str, to);
   162 }
   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;
   172       case JSTYPE_NULL:
   173       {
   174         *to = uint64_t(0);
   175         return true;
   176       }
   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         }
   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         }
   196         ObjectId id;
   197         if (!makeId(cx, obj, &id))
   198             return false;
   199         *to = uint64_t(id);
   200         return true;
   201       }
   203       case JSTYPE_STRING:
   204       {
   205         nsDependentJSString dep;
   206         if (!dep.init(cx, from))
   207             return false;
   208         *to = dep;
   209         return true;
   210       }
   212       case JSTYPE_NUMBER:
   213         if (JSVAL_IS_INT(from))
   214             *to = double(from.toInt32());
   215         else
   216             *to = from.toDouble();
   217         return true;
   219       case JSTYPE_BOOLEAN:
   220         *to = from.toBoolean();
   221         return true;
   223       default:
   224         MOZ_ASSERT(false);
   225         return false;
   226     }
   227 }
   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;
   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         }
   251         case JSVariant::Tdouble:
   252           to.set(JS_NumberValue(from.get_double()));
   253           return true;
   255         case JSVariant::Tbool:
   256           to.set(BOOLEAN_TO_JSVAL(from.get_bool()));
   257           return true;
   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         }
   269         case JSVariant::TJSIID:
   270         {
   271           nsID iid;
   272           const JSIID &id = from.get_JSIID();
   273           ConvertID(id, &iid);
   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         }
   284         default:
   285           return false;
   286     }
   287 }
   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 }
   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 }
   321 static const uint32_t DefaultPropertyOp = 1;
   322 static const uint32_t GetterOnlyPropertyStub = 2;
   323 static const uint32_t UnknownPropertyOp = 3;
   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;
   333     if (!makeId(cx, desc.object(), &out->objId()))
   334         return false;
   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     }
   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     }
   364     return true;
   365 }
   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 }
   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 }
   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);
   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     }
   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     }
   423     return true;
   424 }
   426 bool
   427 CpowIdHolder::ToObject(JSContext *cx, JS::MutableHandleObject objp)
   428 {
   429     return js_->Unwrap(cx, cpows_, objp);
   430 }
   432 bool
   433 JavaScriptShared::Unwrap(JSContext *cx, const InfallibleTArray<CpowEntry> &aCpows,
   434                          JS::MutableHandleObject objp)
   435 {
   436     objp.set(nullptr);
   438     if (!aCpows.Length())
   439         return true;
   441     RootedObject obj(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr()));
   442     if (!obj)
   443         return false;
   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();
   450         if (!toValue(cx, aCpows[i].value(), &v))
   451             return false;
   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     }
   466     objp.set(obj);
   467     return true;
   468 }
   470 bool
   471 JavaScriptShared::Wrap(JSContext *cx, HandleObject aObj, InfallibleTArray<CpowEntry> *outCpows)
   472 {
   473     if (!aObj)
   474         return true;
   476     AutoIdArray ids(cx, JS_Enumerate(cx, aObj));
   477     if (!ids)
   478         return false;
   480     RootedId id(cx);
   481     RootedValue v(cx);
   482     for (size_t i = 0; i < ids.length(); i++) {
   483         id = ids[i];
   485         nsString str;
   486         if (!convertIdToGeckoString(cx, id, &str))
   487             return false;
   489         if (!JS_GetPropertyById(cx, aObj, id, &v))
   490             return false;
   492         JSVariant var;
   493         if (!toVariant(cx, v, &var))
   494             return false;
   496         outCpows->AppendElement(CpowEntry(str, var));
   497     }
   499     return true;
   500 }

mercurial