LCOV - app.info - js/xpconnect/src/XPCQuickStubs.cpp

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-04-21 | 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           14810 : LookupEntry(PRUint32 tableSize, const xpc_qsHashEntry *table, const nsID &iid)
          73                 : {
          74                 :     size_t i;
          75                 :     const xpc_qsHashEntry *p;
          76                 :
          77           14810 :     i = iid.m0 % tableSize;
          78            9200 :     do
          79                 :     {
          80           17432 :         p = table + i;
          81           17432 :         if (p->iid.Equals(iid))
          82            8232 :             return p;
          83            9200 :         i = p->chain;
          84                 :     } while (i != XPC_QS_NULL_INDEX);
          85            6578 :     return nsnull;
          86                 : }
          87                 :
          88                 : static const xpc_qsHashEntry *
          89           11086 : LookupInterfaceOrAncestor(PRUint32 tableSize, const xpc_qsHashEntry *table,
          90                 :                           const nsID &iid)
          91                 : {
          92           11086 :     const xpc_qsHashEntry *entry = LookupEntry(tableSize, table, iid);
          93           11086 :     if (!entry) {
          94                 :         /*
          95                 :          * On a miss, we have to search for every interface the object
          96                 :          * supports, including ancestors.
          97                 :          */
          98            7444 :         nsCOMPtr<nsIInterfaceInfo> info;
          99            3722 :         if (NS_FAILED(nsXPConnect::GetXPConnect()->GetInfoForIID(&iid, getter_AddRefs(info))))
         100               0 :             return nsnull;
         101                 :
         102                 :         const nsIID *piid;
         103            2856 :         for (;;) {
         104           13156 :             nsCOMPtr<nsIInterfaceInfo> parent;
         105           16880 :             if (NS_FAILED(info->GetParent(getter_AddRefs(parent))) ||
         106            6578 :                 !parent ||
         107            3724 :                 NS_FAILED(parent->GetIIDShared(&piid))) {
         108                 :                 break;
         109                 :             }
         110            3724 :             entry = LookupEntry(tableSize, table, *piid);
         111            3724 :             if (entry)
         112                 :                 break;
         113            9434 :             info.swap(parent);
         114                 :         }
         115                 :     }
         116           11086 :     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            2782 : 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            2782 :     bool definedProperty = false;
         406           16650 :     for (uint32_t i = ifacec; i-- != 0;) {
         407           11086 :         const nsID &iid = *interfaces[i];
         408                 :         const xpc_qsHashEntry *entry =
         409           11086 :             LookupInterfaceOrAncestor(tableSize, table, iid);
         410                 :
         411           11086 :         if (entry) {
         412            2632 :             for (;;) {
         413                 :                 // Define quick stubs for attributes.
         414           10864 :                 const xpc_qsPropertySpec *ps = propspecs + entry->prop_index;
         415           10864 :                 const xpc_qsPropertySpec *ps_end = ps + entry->n_props;
         416           80906 :                 for ( ; ps < ps_end; ++ps) {
         417           70042 :                     definedProperty = true;
         418           70042 :                     if (!JS_DefineProperty(cx, proto,
         419                 :                                            stringTable + ps->name_index,
         420                 :                                            JSVAL_VOID, ps->getter, ps->setter,
         421           70042 :                                            flags | JSPROP_SHARED))
         422               0 :                         return false;
         423                 :                 }
         424                 :
         425                 :                 // Define quick stubs for methods.
         426           10864 :                 const xpc_qsFunctionSpec *fs = funcspecs + entry->func_index;
         427           10864 :                 const xpc_qsFunctionSpec *fs_end = fs + entry->n_funcs;
         428           87419 :                 for ( ; fs < fs_end; ++fs) {
         429           76555 :                     if (!JS_DefineFunction(cx, proto,
         430                 :                                            stringTable + fs->name_index,
         431                 :                                            reinterpret_cast<JSNative>(fs->native),
         432           76555 :                                            fs->arity, flags))
         433               0 :                         return false;
         434                 :                 }
         435                 :
         436                 :                 // Next.
         437           10864 :                 size_t j = entry->parentInterface;
         438           10864 :                 if (j == XPC_QS_NULL_INDEX)
         439                 :                     break;
         440            2632 :                 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            2782 :     if (definedProperty && !JS_DefineFunctions(cx, proto, getterfns))
         454               0 :         return false;
         455                 :
         456            2782 :     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           17509 : xpc_qsDOMString::xpc_qsDOMString(JSContext *cx, jsval v, jsval *pval,
         674                 :                                  StringificationBehavior nullBehavior,
         675           17509 :                                  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           17509 :                                           undefinedBehavior);
         681           17509 :     if (!s)
         682            1734 :         return;
         683                 :
         684                 :     size_t len;
         685           15775 :     const jschar *chars = JS_GetStringCharsZAndLength(cx, s, &len);
         686           15775 :     if (!chars) {
         687               0 :         mValid = false;
         688               0 :         return;
         689                 :     }
         690                 :
         691           15775 :     new(mBuf) implementation_type(chars, len);
         692           15775 :     mValid = true;
         693                 : }
         694                 :
         695            7829 : xpc_qsACString::xpc_qsACString(JSContext *cx, jsval v, jsval *pval,
         696                 :                                StringificationBehavior nullBehavior,
         697            7829 :                                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            7829 :                                           undefinedBehavior);
         703            7829 :     if (!s)
         704               0 :         return;
         705                 :
         706            7829 :     size_t len = JS_GetStringEncodingLength(cx, s);
         707            7829 :     if (len == size_t(-1)) {
         708               0 :         mValid = false;
         709               0 :         return;
         710                 :     }
         711                 :
         712           15658 :     JSAutoByteString bytes(cx, s);
         713            7829 :     if (!bytes) {
         714               0 :         mValid = false;
         715                 :         return;
         716                 :     }
         717                 :
         718            7829 :     new(mBuf) implementation_type(bytes.ptr(), len);
         719            7829 :     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           34995 : 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           34995 :     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           28131 :     nsresult rv = idobj->QueryInterface(iid, ppThis);
         763           28131 :     *pThisRef = static_cast<nsISupports*>(*ppThis);
         764           28131 :     if (NS_SUCCEEDED(rv))
         765           28131 :         *vp = OBJECT_TO_JSVAL(obj);
         766           28131 :     return rv;
         767                 : }
         768                 :
         769                 : inline nsresult
         770           32115 : 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           32115 :                      wrapper->GetFlatJSObject(), iid, ppThis, pThisRef, vp);
         779                 : }
         780                 :
         781                 :
         782                 : nsresult
         783           42858 : getWrapper(JSContext *cx,
         784                 :            JSObject *obj,
         785                 :            JSObject *callee,
         786                 :            XPCWrappedNative **wrapper,
         787                 :            JSObject **cur,
         788                 :            XPCWrappedNativeTearOff **tearoff)
         789                 : {
         790           42858 :     if (XPCWrapper::IsSecurityWrapper(obj) &&
         791                 :         !(obj = XPCWrapper::Unwrap(cx, obj, false))) {
         792               0 :         return NS_ERROR_XPC_SECURITY_MANAGER_VETO;
         793                 :     }
         794                 :
         795           42858 :     *cur = obj;
         796           42858 :     *tearoff = nsnull;
         797                 :
         798                 :     *wrapper =
         799                 :         XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj, callee, cur,
         800           42858 :                                                      tearoff);
         801                 :
         802           42858 :     return NS_OK;
         803                 : }
         804                 :
         805                 : nsresult
         806           34399 : 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           34399 :     if (wrapper) {
         817                 :         nsresult rv = getNativeFromWrapper(cx,wrapper, iid, ppThis, pThisRef,
         818           32115 :                                            vp);
         819                 :
         820           32115 :         if (lccx && NS_SUCCEEDED(rv))
         821           12874 :             lccx->SetWrapper(wrapper, tearoff);
         822                 :
         823           32115 :         if (rv != NS_ERROR_NO_INTERFACE)
         824           32115 :             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            6654 : xpc_qsUnwrapObj(jsval v, nsISupports **ppArgRef, nsresult *rv)
         876                 : {
         877            6654 :     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            6567 :     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            6567 :     *rv = NS_OK;
         892            6567 :     return JSVAL_TO_OBJECT(v);
         893                 : }
         894                 :
         895                 : nsresult
         896            5143 : 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            5143 :     JSObject *src = xpc_qsUnwrapObj(v, ppArgRef, &rv);
         905            5143 :     if (!src) {
         906              87 :         *ppArg = nsnull;
         907                 :
         908              87 :         return rv;
         909                 :     }
         910                 :
         911                 :     XPCWrappedNative *wrapper;
         912                 :     XPCWrappedNativeTearOff *tearoff;
         913                 :     JSObject *obj2;
         914            5056 :     if (mozilla::dom::binding::instanceIsProxy(src)) {
         915               0 :         wrapper = nsnull;
         916               0 :         obj2 = src;
         917                 :     } else {
         918            5056 :         rv = getWrapper(cx, src, nsnull, &wrapper, &obj2, &tearoff);
         919            5056 :         NS_ENSURE_SUCCESS(rv, rv);
         920                 :     }
         921                 :
         922            5056 :     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            4945 :     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            4945 :     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            9890 :     XPCCallContext ccx(JS_CALLER, cx);
         953            4945 :     if (!ccx.IsValid()) {
         954               0 :         *ppArgRef = nsnull;
         955               0 :         return NS_ERROR_XPC_BAD_CONVERT_JS;
         956                 :     }
         957                 :
         958            9890 :     nsRefPtr<nsXPCWrappedJS> wrappedJS;
         959                 :     rv = nsXPCWrappedJS::GetNewOrUsed(ccx, src, iid, nsnull,
         960            4945 :                                       getter_AddRefs(wrappedJS));
         961            4945 :     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            4945 :     rv = wrappedJS->QueryInterface(iid, ppArg);
         971            4945 :     if (NS_SUCCEEDED(rv)) {
         972            4945 :         *ppArgRef = static_cast<nsISupports*>(*ppArg);
         973            4945 :         *vp = OBJECT_TO_JSVAL(wrappedJS->GetJSObject());
         974                 :     }
         975            4945 :     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           15922 : StringToJsval(JSContext *cx, nsAString &str, JS::Value *rval)
        1023                 : {
        1024                 :     // From the T_DOMSTRING case in XPCConvert::NativeData2JS.
        1025           15922 :     if (str.IsVoid()) {
        1026            1128 :         *rval = JSVAL_NULL;
        1027            1128 :         return true;
        1028                 :     }
        1029           14794 :     return NonVoidStringToJsval(cx, str, rval);
        1030                 : }
        1031                 :
        1032                 : bool
        1033           14794 : NonVoidStringToJsval(JSContext *cx, nsAString &str, JS::Value *rval)
        1034                 : {
        1035           14794 :     MOZ_ASSERT(!str.IsVoid());
        1036                 :     nsStringBuffer* sharedBuffer;
        1037           14794 :     jsval jsstr = XPCStringConvert::ReadableToJSVal(cx, str, &sharedBuffer);
        1038           14794 :     if (JSVAL_IS_NULL(jsstr))
        1039               0 :         return false;
        1040           14794 :     *rval = jsstr;
        1041           14794 :     if (sharedBuffer) {
        1042                 :         // The string was shared but ReadableToJSVal didn't addref it.
        1043                 :         // Move the ownership from str to jsstr.
        1044           14754 :         str.ForgetSharedBuffer();
        1045                 :     }
        1046           14794 :     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           24338 : xpc_qsXPCOMObjectToJsval(XPCLazyCallContext &lccx, qsObjectHelper &aHelper,
        1075                 :                          const nsIID *iid, XPCNativeInterface **iface,
        1076                 :                          jsval *rval)
        1077                 : {
        1078           24338 :     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           24338 :     JSContext *cx = lccx.GetJSContext();
        1084                 :
        1085                 :     nsresult rv;
        1086           24338 :     if (!XPCConvert::NativeInterface2JSObject(lccx, rval, nsnull,
        1087                 :                                               aHelper, iid, iface,
        1088           24338 :                                               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           24338 :     JSObject* jsobj = JSVAL_TO_OBJECT(*rval);
        1099           24338 :     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           24338 :     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           71620 : xpc_qsAssertContextOK(JSContext *cx)
        1128                 : {
        1129           71620 :     XPCPerThreadData *thread = XPCPerThreadData::GetData(cx);
        1130           71620 :     XPCJSContextStack* stack = thread->GetJSContextStack();
        1131                 :
        1132           71620 :     JSContext *topJSContext = stack->Peek();
        1133                 :
        1134                 :     // This is what we're actually trying to assert here.
        1135           71620 :     NS_ASSERTION(cx == topJSContext, "wrong context on XPCJSContextStack!");
        1136                 :
        1137           71620 :     NS_ASSERTION(XPCPerThreadData::IsMainThread(cx),
        1138                 :                  "XPConnect quick stub called on non-main thread");
        1139           71620 : }
        1140                 : #endif

Generated by: LCOV version 1.7