LCOV - code coverage report
Current view: directory - js/xpconnect/src - XPCQuickStubs.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 478 228 47.7 %
Date: 2012-06-02 Functions: 51 25 49.0 %

       1                 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  *   Mozilla Foundation
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2008
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Jason Orendorff <jorendorff@mozilla.com>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      27                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "mozilla/Util.h"
      40                 : 
      41                 : #include "jsapi.h"
      42                 : #include "jsatom.h"
      43                 : #include "jsfriendapi.h"
      44                 : #include "nsCOMPtr.h"
      45                 : #include "xpcprivate.h"
      46                 : #include "XPCInlines.h"
      47                 : #include "XPCQuickStubs.h"
      48                 : #include "XPCWrapper.h"
      49                 : 
      50                 : using namespace mozilla;
      51                 : 
      52                 : static inline QITableEntry *
      53            2880 : GetOffsets(nsISupports *identity, XPCWrappedNativeProto* proto)
      54                 : {
      55            2880 :     QITableEntry* offsets = proto ? proto->GetOffsets() : nsnull;
      56            2880 :     if (!offsets) {
      57                 :         static NS_DEFINE_IID(kThisPtrOffsetsSID, NS_THISPTROFFSETS_SID);
      58             743 :         identity->QueryInterface(kThisPtrOffsetsSID, (void**)&offsets);
      59                 :     }
      60            2880 :     return offsets;
      61                 : }
      62                 : 
      63                 : static inline QITableEntry *
      64            2284 : GetOffsetsFromSlimWrapper(JSObject *obj)
      65                 : {
      66            2284 :     NS_ASSERTION(IS_SLIM_WRAPPER(obj), "What kind of object is this?");
      67            2284 :     return GetOffsets(static_cast<nsISupports*>(xpc_GetJSPrivate(obj)),
      68            4568 :                       GetSlimWrapperProto(obj));
      69                 : }
      70                 : 
      71                 : static const xpc_qsHashEntry *
      72           14846 : LookupEntry(PRUint32 tableSize, const xpc_qsHashEntry *table, const nsID &iid)
      73                 : {
      74                 :     size_t i;
      75                 :     const xpc_qsHashEntry *p;
      76                 : 
      77           14846 :     i = iid.m0 % tableSize;
      78            9239 :     do
      79                 :     {
      80           17474 :         p = table + i;
      81           17474 :         if (p->iid.Equals(iid))
      82            8235 :             return p;
      83            9239 :         i = p->chain;
      84                 :     } while (i != XPC_QS_NULL_INDEX);
      85            6611 :     return nsnull;
      86                 : }
      87                 : 
      88                 : static const xpc_qsHashEntry *
      89           11102 : LookupInterfaceOrAncestor(PRUint32 tableSize, const xpc_qsHashEntry *table,
      90                 :                           const nsID &iid)
      91                 : {
      92           11102 :     const xpc_qsHashEntry *entry = LookupEntry(tableSize, table, iid);
      93           11102 :     if (!entry) {
      94                 :         /*
      95                 :          * On a miss, we have to search for every interface the object
      96                 :          * supports, including ancestors.
      97                 :          */
      98            7484 :         nsCOMPtr<nsIInterfaceInfo> info;
      99            3742 :         if (NS_FAILED(nsXPConnect::GetXPConnect()->GetInfoForIID(&iid, getter_AddRefs(info))))
     100               0 :             return nsnull;
     101                 : 
     102                 :         const nsIID *piid;
     103            2869 :         for (;;) {
     104           13222 :             nsCOMPtr<nsIInterfaceInfo> parent;
     105           16966 :             if (NS_FAILED(info->GetParent(getter_AddRefs(parent))) ||
     106            6611 :                 !parent ||
     107            3744 :                 NS_FAILED(parent->GetIIDShared(&piid))) {
     108                 :                 break;
     109                 :             }
     110            3744 :             entry = LookupEntry(tableSize, table, *piid);
     111            3744 :             if (entry)
     112                 :                 break;
     113            9480 :             info.swap(parent);
     114                 :         }
     115                 :     }
     116           11102 :     return entry;
     117                 : }
     118                 : 
     119                 : // Apply |op| to |obj|, |id|, and |vp|. If |op| is a setter, treat the assignment as lenient.
     120                 : template<typename Op>
     121                 : static inline JSBool ApplyPropertyOp(JSContext *cx, Op op, JSObject *obj, jsid id, jsval *vp);
     122                 : 
     123                 : template<>
     124                 : inline JSBool
     125               0 : ApplyPropertyOp<JSPropertyOp>(JSContext *cx, JSPropertyOp op, JSObject *obj, jsid id, jsval *vp)
     126                 : {
     127               0 :     return op(cx, obj, id, vp);
     128                 : }
     129                 : 
     130                 : template<>
     131                 : inline JSBool
     132               0 : ApplyPropertyOp<JSStrictPropertyOp>(JSContext *cx, JSStrictPropertyOp op, JSObject *obj,
     133                 :                                     jsid id, jsval *vp)
     134                 : {
     135               0 :     return op(cx, obj, id, true, vp);
     136                 : }
     137                 : 
     138                 : template<typename Op>
     139                 : static JSBool
     140               0 : PropertyOpForwarder(JSContext *cx, unsigned argc, jsval *vp)
     141                 : {
     142                 :     // Layout:
     143                 :     //   this = our this
     144                 :     //   property op to call = callee reserved slot 0
     145                 :     //   name of the property = callee reserved slot 1
     146                 : 
     147               0 :     JSObject *callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));
     148               0 :     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     149               0 :     if (!obj)
     150               0 :         return false;
     151                 : 
     152               0 :     jsval v = js::GetFunctionNativeReserved(callee, 0);
     153                 : 
     154               0 :     JSObject *ptrobj = JSVAL_TO_OBJECT(v);
     155               0 :     Op *popp = static_cast<Op *>(JS_GetPrivate(ptrobj));
     156                 : 
     157               0 :     v = js::GetFunctionNativeReserved(callee, 1);
     158                 : 
     159               0 :     jsval argval = (argc > 0) ? JS_ARGV(cx, vp)[0] : JSVAL_VOID;
     160                 :     jsid id;
     161               0 :     if (!JS_ValueToId(cx, argval, &id))
     162               0 :         return false;
     163               0 :     JS_SET_RVAL(cx, vp, argval);
     164               0 :     return ApplyPropertyOp<Op>(cx, *popp, obj, id, vp);
     165                 : }
     166                 : 
     167                 : static void
     168               0 : PointerFinalize(JSContext *cx, JSObject *obj)
     169                 : {
     170               0 :     JSPropertyOp *popp = static_cast<JSPropertyOp *>(JS_GetPrivate(obj));
     171                 :     delete popp;
     172               0 : }
     173                 : 
     174                 : static JSClass
     175                 : PointerHolderClass = {
     176                 :     "Pointer", JSCLASS_HAS_PRIVATE,
     177                 :     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
     178                 :     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, PointerFinalize,
     179                 :     JSCLASS_NO_OPTIONAL_MEMBERS
     180                 : };
     181                 : 
     182                 : template<typename Op>
     183                 : static JSObject *
     184               0 : GeneratePropertyOp(JSContext *cx, JSObject *obj, jsid id, unsigned argc, Op pop)
     185                 : {
     186                 :     // The JS engine provides two reserved slots on function objects for
     187                 :     // XPConnect to use. Use them to stick the necessary info here.
     188                 :     JSFunction *fun =
     189               0 :         js::NewFunctionByIdWithReserved(cx, PropertyOpForwarder<Op>, argc, 0, obj, id);
     190               0 :     if (!fun)
     191               0 :         return nsnull;
     192                 : 
     193               0 :     JSObject *funobj = JS_GetFunctionObject(fun);
     194                 : 
     195               0 :     JS::AutoObjectRooter tvr(cx, funobj);
     196                 : 
     197                 :     // Unfortunately, we cannot guarantee that Op is aligned. Use a
     198                 :     // second object to work around this.
     199               0 :     JSObject *ptrobj = JS_NewObject(cx, &PointerHolderClass, nsnull, funobj);
     200               0 :     if (!ptrobj)
     201               0 :         return nsnull;
     202               0 :     Op *popp = new Op;
     203               0 :     if (!popp)
     204               0 :         return nsnull;
     205               0 :     *popp = pop;
     206               0 :     JS_SetPrivate(ptrobj, popp);
     207                 : 
     208               0 :     js::SetFunctionNativeReserved(funobj, 0, OBJECT_TO_JSVAL(ptrobj));
     209               0 :     js::SetFunctionNativeReserved(funobj, 1, js::IdToJsval(id));
     210               0 :     return funobj;
     211                 : }
     212                 : 
     213                 : static JSBool
     214               0 : ReifyPropertyOps(JSContext *cx, JSObject *obj, jsid id, unsigned orig_attrs,
     215                 :                  JSPropertyOp getter, JSStrictPropertyOp setter,
     216                 :                  JSObject **getterobjp, JSObject **setterobjp)
     217                 : {
     218                 :     // Generate both getter and setter and stash them in the prototype.
     219               0 :     jsval roots[2] = { JSVAL_NULL, JSVAL_NULL };
     220               0 :     JS::AutoArrayRooter tvr(cx, ArrayLength(roots), roots);
     221                 : 
     222               0 :     unsigned attrs = JSPROP_SHARED | (orig_attrs & JSPROP_ENUMERATE);
     223                 :     JSObject *getterobj;
     224               0 :     if (getter) {
     225               0 :         getterobj = GeneratePropertyOp(cx, obj, id, 0, getter);
     226               0 :         if (!getterobj)
     227               0 :             return false;
     228               0 :         roots[0] = OBJECT_TO_JSVAL(getterobj);
     229               0 :         attrs |= JSPROP_GETTER;
     230                 :     } else
     231               0 :         getterobj = nsnull;
     232                 : 
     233                 :     JSObject *setterobj;
     234               0 :     if (setter) {
     235               0 :         setterobj = GeneratePropertyOp(cx, obj, id, 1, setter);
     236               0 :         if (!setterobj)
     237               0 :             return false;
     238               0 :         roots[1] = OBJECT_TO_JSVAL(setterobj);
     239               0 :         attrs |= JSPROP_SETTER;
     240                 :     } else
     241               0 :         setterobj = nsnull;
     242                 : 
     243               0 :     if (getterobjp)
     244               0 :         *getterobjp = getterobj;
     245               0 :     if (setterobjp)
     246               0 :         *setterobjp = setterobj;
     247                 :     return JS_DefinePropertyById(cx, obj, id, JSVAL_VOID,
     248                 :                                  JS_DATA_TO_FUNC_PTR(JSPropertyOp, getterobj),
     249                 :                                  JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, setterobj),
     250               0 :                                  attrs);
     251                 : }
     252                 : 
     253                 : static JSBool
     254               0 : LookupGetterOrSetter(JSContext *cx, JSBool wantGetter, unsigned argc, jsval *vp)
     255                 : {
     256               0 :     XPC_QS_ASSERT_CONTEXT_OK(cx);
     257                 : 
     258               0 :     if (argc == 0) {
     259               0 :         JS_SET_RVAL(cx, vp, JSVAL_VOID);
     260               0 :         return true;
     261                 :     }
     262                 : 
     263               0 :     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     264               0 :     if (!obj)
     265               0 :         return false;
     266                 : 
     267               0 :     jsval idval = JS_ARGV(cx, vp)[0];
     268                 :     jsid id;
     269                 :     JSPropertyDescriptor desc;
     270               0 :     if (!JS_ValueToId(cx, idval, &id) ||
     271               0 :         !JS_GetPropertyDescriptorById(cx, obj, id, JSRESOLVE_QUALIFIED, &desc))
     272               0 :         return false;
     273                 : 
     274                 :     // No property at all means no getters or setters possible.
     275               0 :     if (!desc.obj) {
     276               0 :         JS_SET_RVAL(cx, vp, JSVAL_VOID);
     277               0 :         return true;
     278                 :     }
     279                 : 
     280                 :     // Inline obj_lookup[GS]etter here.
     281               0 :     if (wantGetter) {
     282               0 :         if (desc.attrs & JSPROP_GETTER) {
     283               0 :             JS_SET_RVAL(cx, vp,
     284               0 :                         OBJECT_TO_JSVAL(JS_FUNC_TO_DATA_PTR(JSObject *, desc.getter)));
     285               0 :             return true;
     286                 :         }
     287                 :     } else {
     288               0 :         if (desc.attrs & JSPROP_SETTER) {
     289               0 :             JS_SET_RVAL(cx, vp,
     290               0 :                         OBJECT_TO_JSVAL(JS_FUNC_TO_DATA_PTR(JSObject *, desc.setter)));
     291               0 :             return true;
     292                 :         }
     293                 :     }
     294                 : 
     295                 :     // Since XPConnect doesn't use JSPropertyOps in any other contexts,
     296                 :     // ensuring that we have an XPConnect prototype object ensures that
     297                 :     // we are only going to expose quickstubbed properties to script.
     298                 :     // Also be careful not to overwrite existing properties!
     299                 : 
     300               0 :     if (!JSID_IS_STRING(id) ||
     301               0 :         !IS_PROTO_CLASS(js::GetObjectClass(desc.obj)) ||
     302                 :         (desc.attrs & (JSPROP_GETTER | JSPROP_SETTER)) ||
     303               0 :         !(desc.getter || desc.setter) ||
     304               0 :         desc.setter == js::GetObjectJSClass(desc.obj)->setProperty) {
     305               0 :         JS_SET_RVAL(cx, vp, JSVAL_VOID);
     306               0 :         return true;
     307                 :     }
     308                 : 
     309                 :     JSObject *getterobj, *setterobj;
     310               0 :     if (!ReifyPropertyOps(cx, desc.obj, id, desc.attrs, desc.getter, desc.setter,
     311               0 :                           &getterobj, &setterobj)) {
     312               0 :         return false;
     313                 :     }
     314                 : 
     315               0 :     JSObject *wantedobj = wantGetter ? getterobj : setterobj;
     316               0 :     jsval v = wantedobj ? OBJECT_TO_JSVAL(wantedobj) : JSVAL_VOID;
     317               0 :     JS_SET_RVAL(cx, vp, v);
     318               0 :     return true;
     319                 : }
     320                 : 
     321                 : static JSBool
     322               0 : SharedLookupGetter(JSContext *cx, unsigned argc, jsval *vp)
     323                 : {
     324               0 :     return LookupGetterOrSetter(cx, true, argc, vp);
     325                 : }
     326                 : 
     327                 : static JSBool
     328               0 : SharedLookupSetter(JSContext *cx, unsigned argc, jsval *vp)
     329                 : {
     330               0 :     return LookupGetterOrSetter(cx, false, argc, vp);
     331                 : }
     332                 : 
     333                 : static JSBool
     334               0 : DefineGetterOrSetter(JSContext *cx, unsigned argc, JSBool wantGetter, jsval *vp)
     335                 : {
     336                 :     unsigned attrs;
     337                 :     JSBool found;
     338                 :     JSPropertyOp getter;
     339                 :     JSStrictPropertyOp setter;
     340                 :     JSObject *obj2;
     341                 :     jsval v;
     342                 :     jsid id;
     343                 : 
     344               0 :     XPC_QS_ASSERT_CONTEXT_OK(cx);
     345               0 :     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     346               0 :     if (!obj)
     347               0 :         return false;
     348               0 :     JSNative forward = wantGetter ? js::obj_defineGetter : js::obj_defineSetter;
     349               0 :     jsval idval = (argc >= 1) ? JS_ARGV(cx, vp)[0] : JSVAL_VOID;
     350               0 :     if (!JSVAL_IS_STRING(idval))
     351               0 :         return forward(cx, argc, vp);
     352                 : 
     353               0 :     if (!JS_ValueToId(cx, idval, &id) ||
     354                 :         !JS_LookupPropertyWithFlagsById(cx, obj, id,
     355               0 :                                         JSRESOLVE_QUALIFIED, &obj2, &v) ||
     356                 :         (obj2 &&
     357                 :          !JS_GetPropertyAttrsGetterAndSetterById(cx, obj2, id, &attrs,
     358               0 :                                                  &found, &getter, &setter)))
     359               0 :         return false;
     360                 : 
     361                 :     // The property didn't exist, already has a getter or setter, or is not
     362                 :     // our property, then just forward now.
     363               0 :     if (!obj2 ||
     364                 :         (attrs & (JSPROP_GETTER | JSPROP_SETTER)) ||
     365               0 :         !(getter || setter) ||
     366               0 :         !IS_PROTO_CLASS(js::GetObjectClass(obj2)))
     367               0 :         return forward(cx, argc, vp);
     368                 : 
     369                 :     // Reify the getter and setter...
     370               0 :     if (!ReifyPropertyOps(cx, obj2, id, attrs, getter, setter, nsnull, nsnull))
     371               0 :         return false;
     372                 : 
     373               0 :     return forward(cx, argc, vp);
     374                 : }
     375                 : 
     376                 : static JSBool
     377               0 : SharedDefineGetter(JSContext *cx, unsigned argc, jsval *vp)
     378                 : {
     379               0 :     return DefineGetterOrSetter(cx, argc, true, vp);
     380                 : }
     381                 : 
     382                 : static JSBool
     383               0 : SharedDefineSetter(JSContext *cx, unsigned argc, jsval *vp)
     384                 : {
     385               0 :     return DefineGetterOrSetter(cx, argc, false, vp);
     386                 : }
     387                 : 
     388                 : 
     389                 : JSBool
     390            2781 : xpc_qsDefineQuickStubs(JSContext *cx, JSObject *proto, unsigned flags,
     391                 :                        PRUint32 ifacec, const nsIID **interfaces,
     392                 :                        PRUint32 tableSize, const xpc_qsHashEntry *table,
     393                 :                        const xpc_qsPropertySpec *propspecs,
     394                 :                        const xpc_qsFunctionSpec *funcspecs,
     395                 :                        const char *stringTable)
     396                 : {
     397                 :     /*
     398                 :      * Walk interfaces in reverse order to behave like XPConnect when a
     399                 :      * feature is defined in more than one of the interfaces.
     400                 :      *
     401                 :      * XPCNativeSet::FindMethod returns the first matching feature it finds,
     402                 :      * searching the interfaces forward.  Here, definitions toward the
     403                 :      * front of 'interfaces' overwrite those toward the back.
     404                 :      */
     405            2781 :     bool definedProperty = false;
     406           16664 :     for (uint32_t i = ifacec; i-- != 0;) {
     407           11102 :         const nsID &iid = *interfaces[i];
     408                 :         const xpc_qsHashEntry *entry =
     409           11102 :             LookupInterfaceOrAncestor(tableSize, table, iid);
     410                 : 
     411           11102 :         if (entry) {
     412            2627 :             for (;;) {
     413                 :                 // Define quick stubs for attributes.
     414           10862 :                 const xpc_qsPropertySpec *ps = propspecs + entry->prop_index;
     415           10862 :                 const xpc_qsPropertySpec *ps_end = ps + entry->n_props;
     416           80876 :                 for ( ; ps < ps_end; ++ps) {
     417           70014 :                     definedProperty = true;
     418           70014 :                     if (!JS_DefineProperty(cx, proto,
     419                 :                                            stringTable + ps->name_index,
     420                 :                                            JSVAL_VOID, ps->getter, ps->setter,
     421           70014 :                                            flags | JSPROP_SHARED)) 
     422               0 :                         return false;
     423                 :                 }
     424                 : 
     425                 :                 // Define quick stubs for methods.
     426           10862 :                 const xpc_qsFunctionSpec *fs = funcspecs + entry->func_index;
     427           10862 :                 const xpc_qsFunctionSpec *fs_end = fs + entry->n_funcs;
     428           87438 :                 for ( ; fs < fs_end; ++fs) {
     429           76576 :                     if (!JS_DefineFunction(cx, proto,
     430                 :                                            stringTable + fs->name_index,
     431                 :                                            reinterpret_cast<JSNative>(fs->native),
     432           76576 :                                            fs->arity, flags))
     433               0 :                         return false;
     434                 :                 }
     435                 : 
     436                 :                 // Next.
     437           10862 :                 size_t j = entry->parentInterface;
     438           10862 :                 if (j == XPC_QS_NULL_INDEX)
     439                 :                     break;
     440            2627 :                 entry = table + j;
     441                 :             }
     442                 :         }
     443                 :     }
     444                 : 
     445                 :     static JSFunctionSpec getterfns[] = {
     446                 :         JS_FN("__lookupGetter__", SharedLookupGetter, 1, 0),
     447                 :         JS_FN("__lookupSetter__", SharedLookupSetter, 1, 0),
     448                 :         JS_FN("__defineGetter__", SharedDefineGetter, 2, 0),
     449                 :         JS_FN("__defineSetter__", SharedDefineSetter, 2, 0),
     450                 :         JS_FS_END
     451                 :     };
     452                 : 
     453            2781 :     if (definedProperty && !JS_DefineFunctions(cx, proto, getterfns))
     454               0 :         return false;
     455                 : 
     456            2781 :     return true;
     457                 : }
     458                 : 
     459                 : JSBool
     460              10 : xpc_qsThrow(JSContext *cx, nsresult rv)
     461                 : {
     462              10 :     XPCThrower::Throw(rv, cx);
     463              10 :     return false;
     464                 : }
     465                 : 
     466                 : /**
     467                 :  * Get the interface name and member name (for error messages).
     468                 :  *
     469                 :  * We could instead have each quick stub pass its name to the error-handling
     470                 :  * functions, as that name is statically known.  But that would be redundant;
     471                 :  * the information is handy at runtime anyway.  Also, this code often produces
     472                 :  * a more specific error message, e.g. "[nsIDOMHTMLDocument.appendChild]"
     473                 :  * rather than "[nsIDOMNode.appendChild]".
     474                 :  */
     475                 : static void
     476             229 : GetMemberInfo(JSObject *obj, jsid memberId, const char **ifaceName)
     477                 : {
     478                 :     // Get the interface name.  From DefinePropertyIfFound (in
     479                 :     // xpcwrappednativejsops.cpp) and XPCThrower::Verbosify.
     480                 :     //
     481                 :     // We could instead make the quick stub could pass in its interface name,
     482                 :     // but this code often produces a more specific error message, e.g.
     483             229 :     *ifaceName = "Unknown";
     484                 : 
     485             229 :     NS_ASSERTION(IS_WRAPPER_CLASS(js::GetObjectClass(obj)) ||
     486                 :                  js::GetObjectClass(obj) == &XPC_WN_Tearoff_JSClass,
     487                 :                  "obj must be a wrapper");
     488                 :     XPCWrappedNativeProto *proto;
     489             229 :     if (IS_SLIM_WRAPPER(obj)) {
     490               0 :         proto = GetSlimWrapperProto(obj);
     491                 :     } else {
     492             229 :         XPCWrappedNative *wrapper = (XPCWrappedNative *) js::GetObjectPrivate(obj);
     493             229 :         proto = wrapper->GetProto();
     494                 :     }
     495             229 :     if (proto) {
     496             229 :         XPCNativeSet *set = proto->GetSet();
     497             229 :         if (set) {
     498                 :             XPCNativeMember *member;
     499                 :             XPCNativeInterface *iface;
     500                 : 
     501             229 :             if (set->FindMember(memberId, &member, &iface))
     502             229 :                 *ifaceName = iface->GetNameString();
     503                 :         }
     504                 :     }
     505             229 : }
     506                 : 
     507                 : static void
     508             228 : GetMethodInfo(JSContext *cx, jsval *vp, const char **ifaceNamep, jsid *memberIdp)
     509                 : {
     510             228 :     JSObject *funobj = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp));
     511             228 :     NS_ASSERTION(JS_ObjectIsFunction(cx, funobj),
     512                 :                  "JSNative callee should be Function object");
     513             228 :     JSString *str = JS_GetFunctionId(JS_GetObjectFunction(funobj));
     514             228 :     jsid methodId = str ? INTERNED_STRING_TO_JSID(cx, str) : JSID_VOID;
     515             228 :     GetMemberInfo(JSVAL_TO_OBJECT(vp[1]), methodId, ifaceNamep);
     516             228 :     *memberIdp = methodId;
     517             228 : }
     518                 : 
     519                 : static bool
     520             229 : ThrowCallFailed(JSContext *cx, nsresult rv,
     521                 :                 const char *ifaceName, jsid memberId, const char *memberName)
     522                 : {
     523                 :     /* Only one of memberId or memberName should be given. */
     524             229 :     JS_ASSERT(JSID_IS_VOID(memberId) != !memberName);
     525                 : 
     526                 :     // From XPCThrower::ThrowBadResult.
     527                 :     char* sz;
     528                 :     const char* format;
     529                 :     const char* name;
     530                 : 
     531                 :     /*
     532                 :      *  If there is a pending exception when the native call returns and
     533                 :      *  it has the same error result as returned by the native call, then
     534                 :      *  the native call may be passing through an error from a previous JS
     535                 :      *  call. So we'll just throw that exception into our JS.
     536                 :      */
     537             229 :     if (XPCThrower::CheckForPendingException(rv, cx))
     538               0 :         return false;
     539                 : 
     540                 :     // else...
     541                 : 
     542             458 :     if (!nsXPCException::NameAndFormatForNSResult(NS_ERROR_XPC_NATIVE_RETURNED_FAILURE, nsnull, &format) ||
     543             229 :         !format) {
     544               0 :         format = "";
     545                 :     }
     546                 : 
     547             458 :     JSAutoByteString memberNameBytes;
     548             229 :     if (!memberName) {
     549             229 :         memberName = JSID_IS_STRING(memberId)
     550             229 :                      ? memberNameBytes.encode(cx, JSID_TO_STRING(memberId))
     551             458 :                      : "unknown";
     552                 :     }
     553             229 :     if (nsXPCException::NameAndFormatForNSResult(rv, &name, nsnull)
     554                 :         && name) {
     555                 :         sz = JS_smprintf("%s 0x%x (%s) [%s.%s]",
     556               3 :                          format, rv, name, ifaceName, memberName);
     557                 :     } else {
     558                 :         sz = JS_smprintf("%s 0x%x [%s.%s]",
     559             226 :                          format, rv, ifaceName, memberName);
     560                 :     }
     561                 : 
     562             229 :     XPCThrower::BuildAndThrowException(cx, rv, sz);
     563                 : 
     564             229 :     if (sz)
     565             229 :         JS_smprintf_free(sz);
     566                 : 
     567             229 :     return false;
     568                 : }
     569                 : 
     570                 : JSBool
     571               1 : xpc_qsThrowGetterSetterFailed(JSContext *cx, nsresult rv, JSObject *obj,
     572                 :                               jsid memberId)
     573                 : {
     574                 :     const char *ifaceName;
     575               1 :     GetMemberInfo(obj, memberId, &ifaceName);
     576               1 :     return ThrowCallFailed(cx, rv, ifaceName, memberId, NULL);
     577                 : }
     578                 : 
     579                 : JSBool
     580             228 : xpc_qsThrowMethodFailed(JSContext *cx, nsresult rv, jsval *vp)
     581                 : {
     582                 :     const char *ifaceName;
     583                 :     jsid memberId;
     584             228 :     GetMethodInfo(cx, vp, &ifaceName, &memberId);
     585             228 :     return ThrowCallFailed(cx, rv, ifaceName, memberId, NULL);
     586                 : }
     587                 : 
     588                 : JSBool
     589               0 : xpc_qsThrowMethodFailedWithCcx(XPCCallContext &ccx, nsresult rv)
     590                 : {
     591               0 :     ThrowBadResult(rv, ccx);
     592               0 :     return false;
     593                 : }
     594                 : 
     595                 : bool
     596               0 : xpc_qsThrowMethodFailedWithDetails(JSContext *cx, nsresult rv,
     597                 :                                    const char *ifaceName,
     598                 :                                    const char *memberName)
     599                 : {
     600               0 :     return ThrowCallFailed(cx, rv, ifaceName, JSID_VOID, memberName);
     601                 : }
     602                 : 
     603                 : static void
     604               0 : ThrowBadArg(JSContext *cx, nsresult rv, const char *ifaceName,
     605                 :             jsid memberId, const char *memberName, unsigned paramnum)
     606                 : {
     607                 :     /* Only one memberId or memberName should be given. */
     608               0 :     JS_ASSERT(JSID_IS_VOID(memberId) != !memberName);
     609                 : 
     610                 :     // From XPCThrower::ThrowBadParam.
     611                 :     char* sz;
     612                 :     const char* format;
     613                 : 
     614               0 :     if (!nsXPCException::NameAndFormatForNSResult(rv, nsnull, &format))
     615               0 :         format = "";
     616                 : 
     617               0 :     JSAutoByteString memberNameBytes;
     618               0 :     if (!memberName) {
     619               0 :         memberName = JSID_IS_STRING(memberId)
     620               0 :                      ? memberNameBytes.encode(cx, JSID_TO_STRING(memberId))
     621               0 :                      : "unknown";
     622                 :     }
     623                 :     sz = JS_smprintf("%s arg %u [%s.%s]",
     624               0 :                      format, (unsigned int) paramnum, ifaceName, memberName);
     625                 : 
     626               0 :     XPCThrower::BuildAndThrowException(cx, rv, sz);
     627                 : 
     628               0 :     if (sz)
     629               0 :         JS_smprintf_free(sz);
     630               0 : }
     631                 : 
     632                 : void
     633               0 : xpc_qsThrowBadArg(JSContext *cx, nsresult rv, jsval *vp, unsigned paramnum)
     634                 : {
     635                 :     const char *ifaceName;
     636                 :     jsid memberId;
     637               0 :     GetMethodInfo(cx, vp, &ifaceName, &memberId);
     638               0 :     ThrowBadArg(cx, rv, ifaceName, memberId, NULL, paramnum);
     639               0 : }
     640                 : 
     641                 : void
     642               0 : xpc_qsThrowBadArgWithCcx(XPCCallContext &ccx, nsresult rv, unsigned paramnum)
     643                 : {
     644               0 :     XPCThrower::ThrowBadParam(rv, paramnum, ccx);
     645               0 : }
     646                 : 
     647                 : void
     648               0 : xpc_qsThrowBadArgWithDetails(JSContext *cx, nsresult rv, unsigned paramnum,
     649                 :                              const char *ifaceName, const char *memberName)
     650                 : {
     651               0 :     ThrowBadArg(cx, rv, ifaceName, JSID_VOID, memberName, paramnum);
     652               0 : }
     653                 : 
     654                 : void
     655               0 : xpc_qsThrowBadSetterValue(JSContext *cx, nsresult rv,
     656                 :                           JSObject *obj, jsid propId)
     657                 : {
     658                 :     const char *ifaceName;
     659               0 :     GetMemberInfo(obj, propId, &ifaceName);
     660               0 :     ThrowBadArg(cx, rv, ifaceName, propId, NULL, 0);
     661               0 : }
     662                 : 
     663                 : JSBool
     664               0 : xpc_qsGetterOnlyPropertyStub(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
     665                 : {
     666                 :     return JS_ReportErrorFlagsAndNumber(cx,
     667                 :                                         JSREPORT_WARNING | JSREPORT_STRICT |
     668                 :                                         JSREPORT_STRICT_MODE_ERROR,
     669                 :                                         js_GetErrorMessage, NULL,
     670               0 :                                         JSMSG_GETTER_ONLY);
     671                 : }
     672                 : 
     673           17378 : xpc_qsDOMString::xpc_qsDOMString(JSContext *cx, jsval v, jsval *pval,
     674                 :                                  StringificationBehavior nullBehavior,
     675           17378 :                                  StringificationBehavior undefinedBehavior)
     676                 : {
     677                 :     typedef implementation_type::char_traits traits;
     678                 :     // From the T_DOMSTRING case in XPCConvert::JSData2Native.
     679                 :     JSString *s = InitOrStringify<traits>(cx, v, pval, nullBehavior,
     680           17378 :                                           undefinedBehavior);
     681           17378 :     if (!s)
     682            1554 :         return;
     683                 : 
     684                 :     size_t len;
     685           15824 :     const jschar *chars = JS_GetStringCharsZAndLength(cx, s, &len);
     686           15824 :     if (!chars) {
     687               0 :         mValid = false;
     688               0 :         return;
     689                 :     }
     690                 : 
     691           15824 :     new(mBuf) implementation_type(chars, len);
     692           15824 :     mValid = true;
     693                 : }
     694                 : 
     695            7833 : xpc_qsACString::xpc_qsACString(JSContext *cx, jsval v, jsval *pval,
     696                 :                                StringificationBehavior nullBehavior,
     697            7833 :                                StringificationBehavior undefinedBehavior)
     698                 : {
     699                 :     typedef implementation_type::char_traits traits;
     700                 :     // From the T_CSTRING case in XPCConvert::JSData2Native.
     701                 :     JSString *s = InitOrStringify<traits>(cx, v, pval, nullBehavior,
     702            7833 :                                           undefinedBehavior);
     703            7833 :     if (!s)
     704               0 :         return;
     705                 : 
     706            7833 :     size_t len = JS_GetStringEncodingLength(cx, s);
     707            7833 :     if (len == size_t(-1)) {
     708               0 :         mValid = false;
     709               0 :         return;
     710                 :     }
     711                 : 
     712           15666 :     JSAutoByteString bytes(cx, s);
     713            7833 :     if (!bytes) {
     714               0 :         mValid = false;
     715                 :         return;
     716                 :     }
     717                 : 
     718            7833 :     new(mBuf) implementation_type(bytes.ptr(), len);
     719            7833 :     mValid = true;
     720                 : }
     721                 : 
     722            1194 : xpc_qsAUTF8String::xpc_qsAUTF8String(JSContext *cx, jsval v, jsval *pval)
     723                 : {
     724                 :     typedef nsCharTraits<PRUnichar> traits;
     725                 :     // From the T_UTF8STRING  case in XPCConvert::JSData2Native.
     726            1194 :     JSString *s = InitOrStringify<traits>(cx, v, pval, eNull, eNull);
     727            1194 :     if (!s)
     728               0 :         return;
     729                 : 
     730                 :     size_t len;
     731            1194 :     const PRUnichar *chars = JS_GetStringCharsZAndLength(cx, s, &len);
     732            1194 :     if (!chars) {
     733               0 :         mValid = false;
     734               0 :         return;
     735                 :     }
     736                 : 
     737            1194 :     new(mBuf) implementation_type(chars, len);
     738            1194 :     mValid = true;
     739                 : }
     740                 : 
     741                 : static nsresult
     742           33559 : getNative(nsISupports *idobj,
     743                 :           QITableEntry* entries,
     744                 :           JSObject *obj,
     745                 :           const nsIID &iid,
     746                 :           void **ppThis,
     747                 :           nsISupports **pThisRef,
     748                 :           jsval *vp)
     749                 : {
     750                 :     // Try using the QITableEntry to avoid the extra AddRef and Release.
     751           33559 :     if (entries) {
     752           18803 :         for (QITableEntry* e = entries; e->iid; e++) {
     753           18759 :             if (e->iid->Equals(iid)) {
     754            6864 :                 *ppThis = (char*) idobj + e->offset - entries[0].offset;
     755            6864 :                 *vp = OBJECT_TO_JSVAL(obj);
     756            6864 :                 *pThisRef = nsnull;
     757            6864 :                 return NS_OK;
     758                 :             }
     759                 :         }
     760                 :     }
     761                 : 
     762           26695 :     nsresult rv = idobj->QueryInterface(iid, ppThis);
     763           26695 :     *pThisRef = static_cast<nsISupports*>(*ppThis);
     764           26695 :     if (NS_SUCCEEDED(rv))
     765           26695 :         *vp = OBJECT_TO_JSVAL(obj);
     766           26695 :     return rv;
     767                 : }
     768                 : 
     769                 : inline nsresult
     770           30679 : getNativeFromWrapper(JSContext *cx,
     771                 :                      XPCWrappedNative *wrapper,
     772                 :                      const nsIID &iid,
     773                 :                      void **ppThis,
     774                 :                      nsISupports **pThisRef,
     775                 :                      jsval *vp)
     776                 : {
     777                 :     return getNative(wrapper->GetIdentityObject(), wrapper->GetOffsets(),
     778           30679 :                      wrapper->GetFlatJSObject(), iid, ppThis, pThisRef, vp);
     779                 : }
     780                 : 
     781                 : 
     782                 : nsresult
     783           41085 : getWrapper(JSContext *cx,
     784                 :            JSObject *obj,
     785                 :            JSObject *callee,
     786                 :            XPCWrappedNative **wrapper,
     787                 :            JSObject **cur,
     788                 :            XPCWrappedNativeTearOff **tearoff)
     789                 : {
     790           41085 :     if (XPCWrapper::IsSecurityWrapper(obj) &&
     791                 :         !(obj = XPCWrapper::Unwrap(cx, obj, false))) {
     792               0 :         return NS_ERROR_XPC_SECURITY_MANAGER_VETO;
     793                 :     }
     794                 : 
     795           41085 :     *cur = obj;
     796           41085 :     *tearoff = nsnull;
     797                 : 
     798                 :     *wrapper =
     799                 :         XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj, callee, cur,
     800           41085 :                                                      tearoff);
     801                 : 
     802           41085 :     return NS_OK;
     803                 : }
     804                 : 
     805                 : nsresult
     806           32963 : castNative(JSContext *cx,
     807                 :            XPCWrappedNative *wrapper,
     808                 :            JSObject *cur,
     809                 :            XPCWrappedNativeTearOff *tearoff,
     810                 :            const nsIID &iid,
     811                 :            void **ppThis,
     812                 :            nsISupports **pThisRef,
     813                 :            jsval *vp,
     814                 :            XPCLazyCallContext *lccx)
     815                 : {
     816           32963 :     if (wrapper) {
     817                 :         nsresult rv = getNativeFromWrapper(cx,wrapper, iid, ppThis, pThisRef,
     818           30679 :                                            vp);
     819                 : 
     820           30679 :         if (lccx && NS_SUCCEEDED(rv))
     821           11976 :             lccx->SetWrapper(wrapper, tearoff);
     822                 : 
     823           30679 :         if (rv != NS_ERROR_NO_INTERFACE)
     824           30679 :             return rv;
     825            2284 :     } else if (cur) {
     826                 :         nsISupports *native;
     827                 :         QITableEntry *entries;
     828            2284 :         if (IS_SLIM_WRAPPER(cur)) {
     829            2284 :             native = static_cast<nsISupports*>(xpc_GetJSPrivate(cur));
     830            2284 :             entries = GetOffsetsFromSlimWrapper(cur);
     831                 :         } else {
     832               0 :             NS_ABORT_IF_FALSE(mozilla::dom::binding::instanceIsProxy(cur),
     833                 :                               "what kind of wrapper is this?");
     834               0 :             native = static_cast<nsISupports*>(js::GetProxyPrivate(cur).toPrivate());
     835               0 :             entries = nsnull;
     836                 :         }
     837                 : 
     838            2284 :         if (NS_SUCCEEDED(getNative(native, entries, cur, iid, ppThis, pThisRef, vp))) {
     839            2284 :             if (lccx) {
     840                 :                 // This only matters for unwrapping of this objects, so we
     841                 :                 // shouldn't end up here for the new DOM bindings.
     842             412 :                 NS_ABORT_IF_FALSE(IS_SLIM_WRAPPER(cur),
     843                 :                                   "what kind of wrapper is this?");
     844             412 :                 lccx->SetWrapper(cur);
     845                 :             }
     846                 : 
     847            2284 :             return NS_OK;
     848                 :         }
     849                 :     }
     850                 : 
     851               0 :     *pThisRef = nsnull;
     852               0 :     return NS_ERROR_XPC_BAD_OP_ON_WN_PROTO;
     853                 : }
     854                 : 
     855                 : JSBool
     856             596 : xpc_qsUnwrapThisFromCcxImpl(XPCCallContext &ccx,
     857                 :                             const nsIID &iid,
     858                 :                             void **ppThis,
     859                 :                             nsISupports **pThisRef,
     860                 :                             jsval *vp)
     861                 : {
     862             596 :     nsISupports *native = ccx.GetIdentityObject();
     863             596 :     if (!native)
     864               0 :         return xpc_qsThrow(ccx.GetJSContext(), NS_ERROR_XPC_HAS_BEEN_SHUTDOWN);
     865                 : 
     866                 :     nsresult rv = getNative(native, GetOffsets(native, ccx.GetProto()),
     867                 :                             ccx.GetFlattenedJSObject(), iid, ppThis, pThisRef,
     868             596 :                             vp);
     869             596 :     if (NS_FAILED(rv))
     870               0 :         return xpc_qsThrow(ccx.GetJSContext(), rv);
     871             596 :     return true;
     872                 : }
     873                 : 
     874                 : JSObject*
     875            6308 : xpc_qsUnwrapObj(jsval v, nsISupports **ppArgRef, nsresult *rv)
     876                 : {
     877            6308 :     if (JSVAL_IS_VOID(v) || JSVAL_IS_NULL(v)) {
     878              87 :         *ppArgRef = nsnull;
     879              87 :         *rv = NS_OK;
     880              87 :         return nsnull;
     881                 :     }
     882                 : 
     883            6221 :     if (!JSVAL_IS_OBJECT(v)) {
     884               0 :         *ppArgRef = nsnull;
     885               0 :         *rv = ((JSVAL_IS_INT(v) && JSVAL_TO_INT(v) == 0)
     886                 :                ? NS_ERROR_XPC_BAD_CONVERT_JS_ZERO_ISNOT_NULL
     887               0 :                : NS_ERROR_XPC_BAD_CONVERT_JS);
     888               0 :         return nsnull;
     889                 :     }
     890                 : 
     891            6221 :     *rv = NS_OK;
     892            6221 :     return JSVAL_TO_OBJECT(v);
     893                 : }
     894                 : 
     895                 : nsresult
     896            4785 : xpc_qsUnwrapArgImpl(JSContext *cx,
     897                 :                     jsval v,
     898                 :                     const nsIID &iid,
     899                 :                     void **ppArg,
     900                 :                     nsISupports **ppArgRef,
     901                 :                     jsval *vp)
     902                 : {
     903                 :     nsresult rv;
     904            4785 :     JSObject *src = xpc_qsUnwrapObj(v, ppArgRef, &rv);
     905            4785 :     if (!src) {
     906              87 :         *ppArg = nsnull;
     907                 : 
     908              87 :         return rv;
     909                 :     }
     910                 : 
     911                 :     XPCWrappedNative *wrapper;
     912                 :     XPCWrappedNativeTearOff *tearoff;
     913                 :     JSObject *obj2;
     914            4698 :     if (mozilla::dom::binding::instanceIsProxy(src)) {
     915               0 :         wrapper = nsnull;
     916               0 :         obj2 = src;
     917                 :     } else {
     918            4698 :         rv = getWrapper(cx, src, nsnull, &wrapper, &obj2, &tearoff);
     919            4698 :         NS_ENSURE_SUCCESS(rv, rv);
     920                 :     }
     921                 : 
     922            4698 :     if (wrapper || obj2) {
     923             111 :         if (NS_FAILED(castNative(cx, wrapper, obj2, tearoff, iid, ppArg,
     924                 :                                  ppArgRef, vp, nsnull)))
     925               0 :             return NS_ERROR_XPC_BAD_CONVERT_JS;
     926             111 :         return NS_OK;
     927                 :     }
     928                 :     // else...
     929                 :     // Slow path.
     930                 : 
     931                 :     // XXX E4X breaks the world. Don't try wrapping E4X objects!
     932                 :     // This hack can be removed (or changed accordingly) when the
     933                 :     // DOM <-> E4X bindings are complete, see bug 270553
     934            4587 :     if (JS_TypeOfValue(cx, OBJECT_TO_JSVAL(src)) == JSTYPE_XML) {
     935               0 :         *ppArgRef = nsnull;
     936               0 :         return NS_ERROR_XPC_BAD_CONVERT_JS;
     937                 :     }
     938                 : 
     939                 :     // Try to unwrap a slim wrapper.
     940                 :     nsISupports *iface;
     941            4587 :     if (XPCConvert::GetISupportsFromJSObject(src, &iface)) {
     942               0 :         if (!iface || NS_FAILED(iface->QueryInterface(iid, ppArg))) {
     943               0 :             *ppArgRef = nsnull;
     944               0 :             return NS_ERROR_XPC_BAD_CONVERT_JS;
     945                 :         }
     946                 : 
     947               0 :         *ppArgRef = static_cast<nsISupports*>(*ppArg);
     948               0 :         return NS_OK;
     949                 :     }
     950                 : 
     951                 :     // Create the ccx needed for quick stubs.
     952            9174 :     XPCCallContext ccx(JS_CALLER, cx);
     953            4587 :     if (!ccx.IsValid()) {
     954               0 :         *ppArgRef = nsnull;
     955               0 :         return NS_ERROR_XPC_BAD_CONVERT_JS;
     956                 :     }
     957                 : 
     958            9174 :     nsRefPtr<nsXPCWrappedJS> wrappedJS;
     959                 :     rv = nsXPCWrappedJS::GetNewOrUsed(ccx, src, iid, nsnull,
     960            4587 :                                       getter_AddRefs(wrappedJS));
     961            4587 :     if (NS_FAILED(rv) || !wrappedJS) {
     962               0 :         *ppArgRef = nsnull;
     963               0 :         return rv;
     964                 :     }
     965                 : 
     966                 :     // We need to go through the QueryInterface logic to make this return
     967                 :     // the right thing for the various 'special' interfaces; e.g.
     968                 :     // nsIPropertyBag. We must use AggregatedQueryInterface in cases where
     969                 :     // there is an outer to avoid nasty recursion.
     970            4587 :     rv = wrappedJS->QueryInterface(iid, ppArg);
     971            4587 :     if (NS_SUCCEEDED(rv)) {
     972            4587 :         *ppArgRef = static_cast<nsISupports*>(*ppArg);
     973            4587 :         *vp = OBJECT_TO_JSVAL(wrappedJS->GetJSObject());
     974                 :     }
     975            4587 :     return rv;
     976                 : }
     977                 : 
     978                 : JSBool
     979               0 : xpc_qsJsvalToCharStr(JSContext *cx, jsval v, JSAutoByteString *bytes)
     980                 : {
     981                 :     JSString *str;
     982                 : 
     983               0 :     JS_ASSERT(!bytes->ptr());
     984               0 :     if (JSVAL_IS_STRING(v)) {
     985               0 :         str = JSVAL_TO_STRING(v);
     986               0 :     } else if (JSVAL_IS_VOID(v) || JSVAL_IS_NULL(v)) {
     987               0 :         return true;
     988                 :     } else {
     989               0 :         if (!(str = JS_ValueToString(cx, v)))
     990               0 :             return false;
     991                 :     }
     992               0 :     return !!bytes->encode(cx, str);
     993                 : }
     994                 : 
     995                 : JSBool
     996               0 : xpc_qsJsvalToWcharStr(JSContext *cx, jsval v, jsval *pval, const PRUnichar **pstr)
     997                 : {
     998                 :     JSString *str;
     999                 : 
    1000               0 :     if (JSVAL_IS_STRING(v)) {
    1001               0 :         str = JSVAL_TO_STRING(v);
    1002               0 :     } else if (JSVAL_IS_VOID(v) || JSVAL_IS_NULL(v)) {
    1003               0 :         *pstr = NULL;
    1004               0 :         return true;
    1005                 :     } else {
    1006               0 :         if (!(str = JS_ValueToString(cx, v)))
    1007               0 :             return false;
    1008               0 :         *pval = STRING_TO_JSVAL(str);  // Root the new string.
    1009                 :     }
    1010                 : 
    1011               0 :     const jschar *chars = JS_GetStringCharsZ(cx, str);
    1012               0 :     if (!chars)
    1013               0 :         return false;
    1014                 : 
    1015               0 :     *pstr = static_cast<const PRUnichar *>(chars);
    1016               0 :     return true;
    1017                 : }
    1018                 : 
    1019                 : namespace xpc {
    1020                 : 
    1021                 : bool
    1022           15742 : StringToJsval(JSContext *cx, nsAString &str, JS::Value *rval)
    1023                 : {
    1024                 :     // From the T_DOMSTRING case in XPCConvert::NativeData2JS.
    1025           15742 :     if (str.IsVoid()) {
    1026            1128 :         *rval = JSVAL_NULL;
    1027            1128 :         return true;
    1028                 :     }
    1029           14614 :     return NonVoidStringToJsval(cx, str, rval);
    1030                 : }
    1031                 : 
    1032                 : bool
    1033           14614 : NonVoidStringToJsval(JSContext *cx, nsAString &str, JS::Value *rval)
    1034                 : {
    1035           14614 :     MOZ_ASSERT(!str.IsVoid());
    1036                 :     nsStringBuffer* sharedBuffer;
    1037           14614 :     jsval jsstr = XPCStringConvert::ReadableToJSVal(cx, str, &sharedBuffer);
    1038           14614 :     if (JSVAL_IS_NULL(jsstr))
    1039               0 :         return false;
    1040           14614 :     *rval = jsstr;
    1041           14614 :     if (sharedBuffer) {
    1042                 :         // The string was shared but ReadableToJSVal didn't addref it.
    1043                 :         // Move the ownership from str to jsstr.
    1044           14574 :         str.ForgetSharedBuffer();
    1045                 :     }
    1046           14614 :     return true;
    1047                 : }
    1048                 : 
    1049                 : } // namespace xpc
    1050                 : 
    1051                 : JSBool
    1052               0 : xpc_qsStringToJsstring(JSContext *cx, nsString &str, JSString **rval)
    1053                 : {
    1054                 :     // From the T_DOMSTRING case in XPCConvert::NativeData2JS.
    1055               0 :     if (str.IsVoid()) {
    1056               0 :         *rval = nsnull;
    1057               0 :         return true;
    1058                 :     }
    1059                 : 
    1060                 :     nsStringBuffer* sharedBuffer;
    1061               0 :     jsval jsstr = XPCStringConvert::ReadableToJSVal(cx, str, &sharedBuffer);
    1062               0 :     if (JSVAL_IS_NULL(jsstr))
    1063               0 :         return false;
    1064               0 :     *rval = JSVAL_TO_STRING(jsstr);
    1065               0 :     if (sharedBuffer) {
    1066                 :         // The string was shared but ReadableToJSVal didn't addref it.
    1067                 :         // Move the ownership from str to jsstr.
    1068               0 :         str.ForgetSharedBuffer();
    1069                 :     }
    1070               0 :     return true;
    1071                 : }
    1072                 : 
    1073                 : JSBool
    1074           23458 : xpc_qsXPCOMObjectToJsval(XPCLazyCallContext &lccx, qsObjectHelper &aHelper,
    1075                 :                          const nsIID *iid, XPCNativeInterface **iface,
    1076                 :                          jsval *rval)
    1077                 : {
    1078           23458 :     NS_PRECONDITION(iface, "Who did that and why?");
    1079                 : 
    1080                 :     // From the T_INTERFACE case in XPCConvert::NativeData2JS.
    1081                 :     // This is one of the slowest things quick stubs do.
    1082                 : 
    1083           23458 :     JSContext *cx = lccx.GetJSContext();
    1084                 : 
    1085                 :     nsresult rv;
    1086           23458 :     if (!XPCConvert::NativeInterface2JSObject(lccx, rval, nsnull,
    1087                 :                                               aHelper, iid, iface,
    1088           23458 :                                               true, &rv)) {
    1089                 :         // I can't tell if NativeInterface2JSObject throws JS exceptions
    1090                 :         // or not.  This is a sloppy stab at the right semantics; the
    1091                 :         // method really ought to be fixed to behave consistently.
    1092               0 :         if (!JS_IsExceptionPending(cx))
    1093               0 :             xpc_qsThrow(cx, NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED);
    1094               0 :         return false;
    1095                 :     }
    1096                 : 
    1097                 : #ifdef DEBUG
    1098           23458 :     JSObject* jsobj = JSVAL_TO_OBJECT(*rval);
    1099           23458 :     if (jsobj && !js::GetObjectParent(jsobj))
    1100               0 :         NS_ASSERTION(js::GetObjectClass(jsobj)->flags & JSCLASS_IS_GLOBAL,
    1101                 :                      "Why did we recreate this wrapper?");
    1102                 : #endif
    1103                 : 
    1104           23458 :     return true;
    1105                 : }
    1106                 : 
    1107                 : JSBool
    1108               0 : xpc_qsVariantToJsval(XPCLazyCallContext &lccx,
    1109                 :                      nsIVariant *p,
    1110                 :                      jsval *rval)
    1111                 : {
    1112                 :     // From the T_INTERFACE case in XPCConvert::NativeData2JS.
    1113                 :     // Error handling is in XPCWrappedNative::CallMethod.
    1114               0 :     if (p) {
    1115                 :         nsresult rv;
    1116               0 :         JSBool ok = XPCVariant::VariantDataToJS(lccx, p, &rv, rval);
    1117               0 :         if (!ok)
    1118               0 :             xpc_qsThrow(lccx.GetJSContext(), rv);
    1119               0 :         return ok;
    1120                 :     }
    1121               0 :     *rval = JSVAL_NULL;
    1122               0 :     return true;
    1123                 : }
    1124                 : 
    1125                 : #ifdef DEBUG
    1126                 : void
    1127           70319 : xpc_qsAssertContextOK(JSContext *cx)
    1128                 : {
    1129           70319 :     XPCPerThreadData *thread = XPCPerThreadData::GetData(cx);
    1130           70319 :     XPCJSContextStack* stack = thread->GetJSContextStack();
    1131                 : 
    1132           70319 :     JSContext *topJSContext = stack->Peek();
    1133                 : 
    1134                 :     // This is what we're actually trying to assert here.
    1135           70319 :     NS_ASSERTION(cx == topJSContext, "wrong context on XPCJSContextStack!");
    1136                 : 
    1137           70319 :     NS_ASSERTION(XPCPerThreadData::IsMainThread(cx),
    1138                 :                  "XPConnect quick stub called on non-main thread");
    1139           70319 : }
    1140                 : #endif

Generated by: LCOV version 1.7