LCOV - code coverage report
Current view: directory - js/xpconnect/src - dombindings.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 569 221 38.8 %
Date: 2012-06-02 Functions: 508 38 7.5 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * vim: set ts=4 sw=4 et tw=99 ft=cpp:
       3                 :  *
       4                 :  * ***** BEGIN LICENSE BLOCK *****
       5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       6                 :  *
       7                 :  * The contents of this file are subject to the Mozilla Public License Version
       8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       9                 :  * the License. You may obtain a copy of the License at
      10                 :  * http://www.mozilla.org/MPL/
      11                 :  *
      12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      14                 :  * for the specific language governing rights and limitations under the
      15                 :  * License.
      16                 :  *
      17                 :  * The Original Code is mozilla.org code, released
      18                 :  * June 24, 2010.
      19                 :  *
      20                 :  * The Initial Developer of the Original Code is
      21                 :  *    The Mozilla Foundation
      22                 :  *
      23                 :  * Contributor(s):
      24                 :  *    Andreas Gal <gal@mozilla.com>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : #include "mozilla/Util.h"
      41                 : 
      42                 : #include "dombindings.h"
      43                 : #include "xpcpublic.h"
      44                 : #include "xpcprivate.h"
      45                 : #include "XPCQuickStubs.h"
      46                 : #include "XPCWrapper.h"
      47                 : #include "WrapperFactory.h"
      48                 : #include "nsDOMClassInfo.h"
      49                 : #include "nsGlobalWindow.h"
      50                 : #include "nsWrapperCacheInlines.h"
      51                 : 
      52                 : #include "jsapi.h"
      53                 : #include "jsatom.h"
      54                 : 
      55                 : using namespace JS;
      56                 : 
      57                 : namespace mozilla {
      58                 : namespace dom {
      59                 : namespace binding {
      60                 : 
      61                 : 
      62            1464 : static jsid s_prototype_id = JSID_VOID;
      63                 : 
      64            1464 : static jsid s_length_id = JSID_VOID;
      65                 : 
      66            1464 : static jsid s_VOID_id = JSID_VOID;
      67                 : 
      68                 : bool
      69           32292 : DefineStaticJSVal(JSContext *cx, jsid &id, const char *string)
      70                 : {
      71           32292 :     if (JSString *str = ::JS_InternString(cx, string)) {
      72           32292 :         id = INTERNED_STRING_TO_JSID(cx, str);
      73           32292 :         return true;
      74                 :     }
      75               0 :     return false;
      76                 : }
      77                 : 
      78                 : #define SET_JSID_TO_STRING(_cx, _string)                                      \
      79                 :     DefineStaticJSVal(_cx, s_##_string##_id, #_string)
      80                 : 
      81                 : bool
      82            1404 : DefineStaticJSVals(JSContext *cx)
      83                 : {
      84            2808 :     JSAutoRequest ar(cx);
      85                 : 
      86            1404 :     return SET_JSID_TO_STRING(cx, prototype) &&
      87            1404 :            SET_JSID_TO_STRING(cx, length) &&
      88            2808 :            DefinePropertyStaticJSVals(cx);
      89                 : }
      90                 : 
      91                 : 
      92                 : int HandlerFamily;
      93                 : 
      94                 : 
      95                 : JSBool
      96               0 : Throw(JSContext *cx, nsresult rv)
      97                 : {
      98               0 :     XPCThrower::Throw(rv, cx);
      99               0 :     return false;
     100                 : }
     101                 : 
     102                 : 
     103                 : // Only set allowNativeWrapper to false if you really know you need it, if in
     104                 : // doubt use true. Setting it to false disables security wrappers.
     105                 : static bool
     106           11532 : XPCOMObjectToJsval(JSContext *cx, JSObject *scope, xpcObjectHelper &helper,
     107                 :                    bool allowNativeWrapper, jsval *rval)
     108                 : {
     109           23064 :     XPCLazyCallContext lccx(JS_CALLER, cx, scope);
     110                 : 
     111                 :     nsresult rv;
     112           11532 :     if (!XPCConvert::NativeInterface2JSObject(lccx, rval, NULL, helper, NULL, NULL,
     113           11532 :                                               allowNativeWrapper, &rv)) {
     114                 :         // I can't tell if NativeInterface2JSObject throws JS exceptions
     115                 :         // or not.  This is a sloppy stab at the right semantics; the
     116                 :         // method really ought to be fixed to behave consistently.
     117               0 :         if (!JS_IsExceptionPending(cx))
     118               0 :             Throw(cx, NS_FAILED(rv) ? rv : NS_ERROR_UNEXPECTED);
     119               0 :         return false;
     120                 :     }
     121                 : 
     122                 : #ifdef DEBUG
     123           11532 :     JSObject* jsobj = JSVAL_TO_OBJECT(*rval);
     124           11532 :     if (jsobj && !js::GetObjectParent(jsobj))
     125               0 :         NS_ASSERTION(js::GetObjectClass(jsobj)->flags & JSCLASS_IS_GLOBAL,
     126                 :                      "Why did we recreate this wrapper?");
     127                 : #endif
     128                 : 
     129           11532 :     return true;
     130                 : }
     131                 : 
     132                 : template<class T>
     133                 : static inline JSObject*
     134            4321 : WrapNativeParent(JSContext *cx, JSObject *scope, T *p)
     135                 : {
     136            4321 :     if (!p)
     137               0 :         return NULL;
     138                 : 
     139            4321 :     nsWrapperCache *cache = GetWrapperCache(p);
     140                 :     JSObject* obj;
     141            4321 :     if (cache && (obj = cache->GetWrapper())) {
     142                 : #ifdef DEBUG
     143            8642 :         qsObjectHelper helper(p, cache);
     144                 :         jsval debugVal;
     145                 : 
     146            4321 :         bool ok = XPCOMObjectToJsval(cx, scope, helper, false, &debugVal);
     147            4321 :         NS_ASSERTION(ok && JSVAL_TO_OBJECT(debugVal) == obj,
     148                 :                      "Unexpected object in nsWrapperCache");
     149                 : #endif
     150            4321 :         return obj;
     151                 :     }
     152                 : 
     153               0 :     qsObjectHelper helper(p, cache);
     154                 :     jsval v;
     155               0 :     return XPCOMObjectToJsval(cx, scope, helper, false, &v) ? JSVAL_TO_OBJECT(v) : NULL;
     156                 : }
     157                 : 
     158                 : template<class T>
     159                 : static bool
     160            7638 : Wrap(JSContext *cx, JSObject *scope, T *p, nsWrapperCache *cache, jsval *vp)
     161                 : {
     162            7638 :     if (xpc_FastGetCachedWrapper(cache, scope, vp))
     163             427 :         return true;
     164           14422 :     qsObjectHelper helper(p, cache);
     165            7211 :     return XPCOMObjectToJsval(cx, scope, helper, true, vp);
     166                 : }
     167                 : 
     168                 : template<class T>
     169                 : static inline bool
     170            7638 : Wrap(JSContext *cx, JSObject *scope, T *p, jsval *vp)
     171                 : {
     172            7638 :     return Wrap(cx, scope, p, GetWrapperCache(p), vp);
     173                 : }
     174                 : 
     175                 : template<>
     176                 : inline bool
     177                 : Wrap(JSContext *cx, JSObject *scope, NoType *p, jsval *vp)
     178                 : {
     179                 :     NS_RUNTIMEABORT("We try to wrap the result from calling a noop?");
     180                 :     return false;
     181                 : }
     182                 : 
     183                 : template<class T>
     184                 : inline bool
     185               0 : Wrap(JSContext *cx, JSObject *scope, nsCOMPtr<T> &p, jsval *vp)
     186                 : {
     187               0 :     return Wrap(cx, scope, p.get(), vp);
     188                 : }
     189                 : 
     190                 : static inline bool
     191               0 : Wrap(JSContext *cx, JSObject *scope, nsISupportsResult &result, jsval *vp)
     192                 : {
     193               0 :     return Wrap(cx, scope, result.mResult, result.mCache, vp);
     194                 : }
     195                 : 
     196                 : static inline bool
     197               0 : Wrap(JSContext *cx, JSObject *scope, nsString &result, jsval *vp)
     198                 : {
     199               0 :     return xpc::StringToJsval(cx, result, vp);
     200                 : }
     201                 : 
     202                 : template<class T>
     203                 : bool
     204               0 : Unwrap(JSContext *cx, jsval v, T **ppArg, nsISupports **ppArgRef, jsval *vp)
     205                 : {
     206               0 :     nsresult rv = xpc_qsUnwrapArg(cx, v, ppArg, ppArgRef, vp);
     207               0 :     if (NS_FAILED(rv))
     208               0 :         return Throw(cx, rv);
     209               0 :     return true;
     210                 : }
     211                 : 
     212                 : template<>
     213                 : bool
     214               0 : Unwrap(JSContext *cx, jsval v, NoType **ppArg, nsISupports **ppArgRef, jsval *vp)
     215                 : {
     216               0 :     NS_RUNTIMEABORT("We try to unwrap an argument for a noop?");
     217               0 :     return false;
     218                 : }
     219                 : 
     220                 : 
     221                 : // Because we use proxies for wrapping DOM list objects we don't get the benefits of the property
     222                 : // cache. To improve performance when using a property that lives on the prototype chain we
     223                 : // implemented a cheap caching mechanism. Every DOM list proxy object stores a pointer to a shape
     224                 : // in an extra slot. The first time we access a property on the object that lives on the prototype
     225                 : // we check if all the DOM properties on the prototype chain are the real DOM properties and in
     226                 : // that case we store a pointer to the shape of the object's prototype in the extra slot. From
     227                 : // then on, every time we access a DOM property that lives on the prototype we check that the
     228                 : // shape of the prototype is still identical to the cached shape and we do a fast lookup of the
     229                 : // property. If the shape has changed, we recheck all the DOM properties on the prototype chain
     230                 : // and we update the shape pointer if they are still the real DOM properties. This mechanism
     231                 : // covers addition/removal of properties, changes in getters/setters, changes in the prototype
     232                 : // chain, ... It does not cover changes in the values of the properties. For those we store an
     233                 : // enum value in a reserved slot in every DOM prototype object. The value starts off as USE_CACHE.
     234                 : // If a property of a DOM prototype object is set to a different value, we set the value to
     235                 : // CHECK_CACHE. The next time we try to access the value of a property on that DOM prototype
     236                 : // object we check if all the DOM properties on that DOM prototype object still match the real DOM
     237                 : // properties. If they do we set the value to USE_CACHE again, if they're not we set the value to
     238                 : // DONT_USE_CACHE. If the value is USE_CACHE we do the fast lookup.
     239                 : 
     240                 : template<class LC>
     241                 : typename ListBase<LC>::Properties ListBase<LC>::sProtoProperties[] = {
     242                 :     { s_VOID_id, NULL, NULL }
     243                 : };
     244                 : template<class LC>
     245                 : size_t ListBase<LC>::sProtoPropertiesCount = 0;
     246                 : 
     247                 : template<class LC>
     248                 : typename ListBase<LC>::Methods ListBase<LC>::sProtoMethods[] = {
     249                 :     { s_VOID_id, NULL, 0 }
     250                 : };
     251                 : template<class LC>
     252                 : size_t ListBase<LC>::sProtoMethodsCount = 0;
     253                 : 
     254                 : template<class LC>
     255           19032 : ListBase<LC> ListBase<LC>::instance;
     256                 : 
     257                 : bool
     258               0 : DefineConstructor(JSContext *cx, JSObject *obj, DefineInterface aDefine, nsresult *aResult)
     259                 : {
     260                 :     bool enabled;
     261               0 :     bool defined = !!aDefine(cx, XPCWrappedNativeScope::FindInJSObjectScope(cx, obj), &enabled);
     262               0 :     NS_ASSERTION(!defined || enabled,
     263                 :                  "We defined a constructor but the new bindings are disabled?");
     264               0 :     *aResult = defined ? NS_OK : NS_ERROR_FAILURE;
     265               0 :     return enabled;
     266                 : }
     267                 : 
     268                 : template<class LC>
     269                 : typename ListBase<LC>::ListType*
     270           11835 : ListBase<LC>::getNative(JSObject *obj)
     271                 : {
     272           11835 :     return static_cast<ListType*>(js::GetProxyPrivate(obj).toPrivate());
     273                 : }
     274                 : 
     275                 : template<class LC>
     276                 : typename ListBase<LC>::ListType*
     277           20938 : ListBase<LC>::getListObject(JSObject *obj)
     278                 : {
     279           20938 :     if (xpc::WrapperFactory::IsXrayWrapper(obj))
     280               0 :         obj = js::UnwrapObject(obj);
     281           20938 :     JS_ASSERT(objIsList(obj));
     282           20938 :     return getNative(obj);
     283                 : }
     284                 : 
     285                 : template<class LC>
     286                 : js::Shape *
     287           12691 : ListBase<LC>::getProtoShape(JSObject *obj)
     288                 : {
     289           12691 :     JS_ASSERT(objIsList(obj));
     290           12691 :     return (js::Shape *) js::GetProxyExtra(obj, JSPROXYSLOT_PROTOSHAPE).toPrivate();
     291                 : }
     292                 : 
     293                 : template<class LC>
     294                 : void
     295            8636 : ListBase<LC>::setProtoShape(JSObject *obj, js::Shape *shape)
     296                 : {
     297            8636 :     JS_ASSERT(objIsList(obj));
     298            8636 :     js::SetProxyExtra(obj, JSPROXYSLOT_PROTOSHAPE, PrivateValue(shape));
     299            8636 : }
     300                 : 
     301                 : static JSBool
     302               0 : UnwrapSecurityWrapper(JSContext *cx, JSObject *obj, JSObject *callee, JSObject **unwrapped)
     303                 : {
     304               0 :     JS_ASSERT(XPCWrapper::IsSecurityWrapper(obj));
     305                 : 
     306               0 :     if (callee && JS_GetGlobalForObject(cx, obj) == JS_GetGlobalForObject(cx, callee)) {
     307               0 :         *unwrapped = js::UnwrapObject(obj);
     308                 :     } else {
     309               0 :         *unwrapped = XPCWrapper::Unwrap(cx, obj);
     310               0 :         if (!*unwrapped)
     311               0 :             return Throw(cx, NS_ERROR_XPC_SECURITY_MANAGER_VETO);
     312                 :     }
     313               0 :     return true;
     314                 : }
     315                 : 
     316                 : template<class LC>
     317                 : bool
     318            3704 : ListBase<LC>::instanceIsListObject(JSContext *cx, JSObject *obj, JSObject *callee)
     319                 : {
     320            3704 :     if (XPCWrapper::IsSecurityWrapper(obj) && !UnwrapSecurityWrapper(cx, obj, callee, &obj))
     321               0 :         return false;
     322                 : 
     323            3704 :     if (!objIsList(obj)) {
     324                 :         // FIXME: Throw a proper DOM exception.
     325               0 :         JS_ReportError(cx, "type error: wrong object");
     326               0 :         return false;
     327                 :     }
     328            3704 :     return true;
     329                 : }
     330                 : 
     331                 : template<class LC>
     332                 : JSBool
     333               0 : ListBase<LC>::length_getter(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
     334                 : {
     335               0 :     if (!instanceIsListObject(cx, obj, NULL))
     336               0 :         return false;
     337                 :     PRUint32 length;
     338               0 :     getListObject(obj)->GetLength(&length);
     339               0 :     JS_ASSERT(int32_t(length) >= 0);
     340               0 :     *vp = UINT_TO_JSVAL(length);
     341               0 :     return true;
     342                 : }
     343                 : 
     344                 : template<class LC>
     345                 : bool
     346                 : ListBase<LC>::getItemAt(ListType *list, uint32_t i, IndexGetterType &item)
     347                 : {
     348                 :     JS_STATIC_ASSERT(!hasIndexGetter);
     349                 :     return false;
     350                 : }
     351                 : 
     352                 : template<class LC>
     353                 : bool
     354               0 : ListBase<LC>::setItemAt(JSContext *cx, ListType *list, uint32_t i, IndexSetterType item)
     355                 : {
     356                 :     JS_STATIC_ASSERT(!hasIndexSetter);
     357               0 :     return false;
     358                 : }
     359                 : 
     360                 : template<class LC>
     361                 : bool
     362               0 : ListBase<LC>::getNamedItem(ListType *list, const nsAString& aName, NameGetterType &item)
     363                 : {
     364                 :     JS_STATIC_ASSERT(!hasNameGetter);
     365               0 :     return false;
     366                 : }
     367                 : 
     368                 : template<class LC>
     369                 : bool
     370               0 : ListBase<LC>::setNamedItem(JSContext *cx, ListType *list, const nsAString& aName,
     371                 :                            NameSetterType item)
     372                 : {
     373                 :     JS_STATIC_ASSERT(!hasNameSetter);
     374               0 :     return false;
     375                 : }
     376                 : 
     377                 : template<class LC>
     378                 : bool
     379               0 : ListBase<LC>::namedItem(JSContext *cx, JSObject *obj, jsval *name, NameGetterType &result,
     380                 :                         bool *hasResult)
     381                 : {
     382                 :     xpc_qsDOMString nameString(cx, *name, name,
     383                 :                                xpc_qsDOMString::eDefaultNullBehavior,
     384               0 :                                xpc_qsDOMString::eDefaultUndefinedBehavior);
     385               0 :     if (!nameString.IsValid())
     386               0 :         return false;
     387               0 :     *hasResult = getNamedItem(getListObject(obj), nameString, result);
     388               0 :     return true;
     389                 : }
     390                 : 
     391                 : JSBool
     392               0 : interface_hasInstance(JSContext *cx, JSObject *obj, const JS::Value *vp, JSBool *bp)
     393                 : {
     394               0 :     if (vp->isObject()) {
     395                 :         jsval prototype;
     396               0 :         if (!JS_GetPropertyById(cx, obj, s_prototype_id, &prototype) ||
     397               0 :             JSVAL_IS_PRIMITIVE(prototype)) {
     398                 :             JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL,
     399               0 :                                          JSMSG_THROW_TYPE_ERROR);
     400               0 :             return false;
     401                 :         }
     402                 : 
     403               0 :         JSObject *other = &vp->toObject();
     404               0 :         if (instanceIsProxy(other)) {
     405               0 :             ProxyHandler *handler = static_cast<ProxyHandler*>(js::GetProxyHandler(other));
     406               0 :             if (handler->isInstanceOf(JSVAL_TO_OBJECT(prototype))) {
     407               0 :                 *bp = true;
     408                 :             } else {
     409               0 :                 JSObject *protoObj = JSVAL_TO_OBJECT(prototype);
     410               0 :                 JSObject *proto = other;
     411               0 :                 while ((proto = JS_GetPrototype(proto))) {
     412               0 :                     if (proto == protoObj) {
     413               0 :                         *bp = true;
     414               0 :                         return true;
     415                 :                     }
     416                 :                 }
     417               0 :                 *bp = false;
     418                 :             }
     419                 : 
     420               0 :             return true;
     421                 :         }
     422                 :     }
     423                 : 
     424               0 :     *bp = false;
     425               0 :     return true;
     426                 : }
     427                 : 
     428                 : enum {
     429                 :     USE_CACHE = 0,
     430                 :     CHECK_CACHE = 1,
     431                 :     DONT_USE_CACHE = 2
     432                 : };
     433                 : 
     434                 : static JSBool
     435                 : InvalidateProtoShape_add(JSContext *cx, JSObject *obj, jsid id, jsval *vp);
     436                 : static JSBool
     437                 : InvalidateProtoShape_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp);
     438                 : 
     439                 : js::Class sInterfacePrototypeClass = {
     440                 :     "Object",
     441                 :     JSCLASS_HAS_RESERVED_SLOTS(1),
     442                 :     InvalidateProtoShape_add,   /* addProperty */
     443                 :     JS_PropertyStub,            /* delProperty */
     444                 :     JS_PropertyStub,            /* getProperty */
     445                 :     InvalidateProtoShape_set,   /* setProperty */
     446                 :     JS_EnumerateStub,
     447                 :     JS_ResolveStub,
     448                 :     JS_ConvertStub
     449                 : };
     450                 : 
     451                 : static JSBool
     452             852 : InvalidateProtoShape_add(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
     453                 : {
     454             852 :     if (JSID_IS_STRING(id) && JS_InstanceOf(cx, obj, Jsvalify(&sInterfacePrototypeClass), NULL))
     455             852 :         js::SetReservedSlot(obj, 0, PrivateUint32Value(CHECK_CACHE));
     456             852 :     return JS_TRUE;
     457                 : }
     458                 : 
     459                 : static JSBool
     460               0 : InvalidateProtoShape_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
     461                 : {
     462               0 :     return InvalidateProtoShape_add(cx, obj, id, vp);
     463                 : }
     464                 : 
     465                 : template<class LC>
     466                 : JSObject *
     467            4321 : ListBase<LC>::getPrototype(JSContext *cx, XPCWrappedNativeScope *scope)
     468                 : {
     469                 :     nsDataHashtable<nsDepCharHashKey, JSObject*> &cache =
     470            4321 :         scope->GetCachedDOMPrototypes();
     471                 : 
     472                 :     JSObject *interfacePrototype;
     473            4321 :     if (cache.IsInitialized()) {
     474            4062 :         if (cache.Get(sInterfaceClass.name, &interfacePrototype)) {
     475            4047 :             xpc_UnmarkGrayObject(interfacePrototype);
     476            4047 :             return interfacePrototype;
     477                 :         }
     478             259 :     } else if (!cache.Init()) {
     479               0 :         return NULL;
     480                 :     }
     481                 : 
     482             274 :     JSObject* proto = Base::getPrototype(cx, scope);
     483             274 :     if (!proto)
     484               0 :         return NULL;
     485                 : 
     486             274 :     JSObject *global = scope->GetGlobalJSObject();
     487             274 :     interfacePrototype = JS_NewObject(cx, Jsvalify(&sInterfacePrototypeClass), proto, global);
     488             274 :     if (!interfacePrototype)
     489               0 :         return NULL;
     490                 : 
     491             548 :     for (size_t n = 0; n < sProtoPropertiesCount; ++n) {
     492             274 :         JS_ASSERT(sProtoProperties[n].getter);
     493             274 :         jsid id = sProtoProperties[n].id;
     494             274 :         unsigned attrs = JSPROP_ENUMERATE | JSPROP_SHARED;
     495             274 :         if (!sProtoProperties[n].setter)
     496             274 :             attrs |= JSPROP_READONLY;
     497             274 :         if (!JS_DefinePropertyById(cx, interfacePrototype, id, JSVAL_VOID,
     498                 :                                    sProtoProperties[n].getter, sProtoProperties[n].setter, attrs))
     499               0 :             return NULL;
     500                 :     }
     501                 : 
     502             578 :     for (size_t n = 0; n < sProtoMethodsCount; ++n) {
     503             304 :         jsid id = sProtoMethods[n].id;
     504                 :         JSFunction *fun = JS_NewFunctionById(cx, sProtoMethods[n].native, sProtoMethods[n].nargs,
     505             304 :                                              0, js::GetObjectParent(interfacePrototype), id);
     506             304 :         if (!fun)
     507               0 :             return NULL;
     508             304 :         JSObject *funobj = JS_GetFunctionObject(fun);
     509             304 :         if (!JS_DefinePropertyById(cx, interfacePrototype, id, OBJECT_TO_JSVAL(funobj),
     510                 :                                    NULL, NULL, JSPROP_ENUMERATE))
     511               0 :             return NULL;
     512                 :     }
     513                 : 
     514             274 :     JSObject *interface = JS_NewObject(cx, Jsvalify(&sInterfaceClass), NULL, global);
     515             274 :     if (!interface)
     516               0 :         return NULL;
     517                 : 
     518             274 :     if (!JS_LinkConstructorAndPrototype(cx, interface, interfacePrototype))
     519               0 :         return NULL;
     520                 : 
     521             274 :     if (!JS_DefineProperty(cx, global, sInterfaceClass.name, OBJECT_TO_JSVAL(interface), NULL,
     522                 :                            NULL, 0))
     523               0 :         return NULL;
     524                 : 
     525                 :     // This needs to happen after we've set all our own properties on interfacePrototype, to
     526                 :     // overwrite the value set by InvalidateProtoShape_add when we set our own properties.
     527             274 :     js::SetReservedSlot(interfacePrototype, 0, PrivateUint32Value(USE_CACHE));
     528                 : 
     529             274 :     if (!cache.Put(sInterfaceClass.name, interfacePrototype))
     530               0 :         return NULL;
     531                 : 
     532             274 :     return interfacePrototype;
     533                 : }
     534                 : 
     535                 : template<class LC>
     536                 : JSObject *
     537            4321 : ListBase<LC>::create(JSContext *cx, XPCWrappedNativeScope *scope, ListType *aList,
     538                 :                      nsWrapperCache* aWrapperCache, bool *triedToWrap)
     539                 : {
     540            4321 :     *triedToWrap = true;
     541                 : 
     542            4321 :     JSObject *parent = WrapNativeParent(cx, scope->GetGlobalJSObject(), aList->GetParentObject());
     543            4321 :     if (!parent)
     544               0 :         return NULL;
     545                 : 
     546            8642 :     JSAutoEnterCompartment ac;
     547            4321 :     if (js::GetGlobalForObjectCrossCompartment(parent) != scope->GetGlobalJSObject()) {
     548               0 :         if (!ac.enter(cx, parent))
     549               0 :             return NULL;
     550                 : 
     551               0 :         scope = XPCWrappedNativeScope::FindInJSObjectScope(cx, parent);
     552                 :     }
     553                 : 
     554            4321 :     JSObject *proto = getPrototype(cx, scope, triedToWrap);
     555            4321 :     if (!proto && !*triedToWrap)
     556               0 :         aWrapperCache->ClearIsProxy();
     557            4321 :     if (!proto)
     558               0 :         return NULL;
     559                 :     JSObject *obj = NewProxyObject(cx, &ListBase<LC>::instance,
     560            4321 :                                    PrivateValue(aList), proto, parent);
     561            4321 :     if (!obj)
     562               0 :         return NULL;
     563                 : 
     564            4321 :     NS_ADDREF(aList);
     565            4321 :     setProtoShape(obj, NULL);
     566                 : 
     567            4321 :     aWrapperCache->SetWrapper(obj);
     568                 : 
     569            4321 :     return obj;
     570                 : }
     571                 : 
     572                 : static JSObject *
     573           12691 : getExpandoObject(JSObject *obj)
     574                 : {
     575           12691 :     NS_ASSERTION(instanceIsProxy(obj), "expected a DOM proxy object");
     576           12691 :     Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO);
     577           12691 :     return v.isUndefined() ? NULL : v.toObjectOrNull();
     578                 : }
     579                 : 
     580                 : static int32_t
     581               0 : IdToInt32(JSContext *cx, jsid id)
     582                 : {
     583               0 :     JSAutoRequest ar(cx);
     584                 : 
     585                 :     jsval idval;
     586                 :     double array_index;
     587                 :     int32_t i;
     588               0 :     if (!::JS_IdToValue(cx, id, &idval) ||
     589               0 :         !::JS_ValueToNumber(cx, idval, &array_index) ||
     590               0 :         !::JS_DoubleIsInt32(array_index, &i)) {
     591               0 :         return -1;
     592                 :     }
     593                 : 
     594               0 :     return i;
     595                 : }
     596                 : 
     597                 : static inline int32_t
     598           15490 : GetArrayIndexFromId(JSContext *cx, jsid id)
     599                 : {
     600           15490 :     if (NS_LIKELY(JSID_IS_INT(id)))
     601            2799 :         return JSID_TO_INT(id);
     602           12691 :     if (NS_LIKELY(id == s_length_id))
     603            8979 :         return -1;
     604            3712 :     if (NS_LIKELY(JSID_IS_ATOM(id))) {
     605            3712 :         JSAtom *atom = JSID_TO_ATOM(id);
     606            3712 :         jschar s = *js::GetAtomChars(atom);
     607            3712 :         if (NS_LIKELY((unsigned)s >= 'a' && (unsigned)s <= 'z'))
     608            3712 :             return -1;
     609                 : 
     610                 :         uint32_t i;
     611               0 :         JSLinearString *str = js::AtomToLinearString(JSID_TO_ATOM(id));
     612               0 :         return js::StringIsArrayIndex(str, &i) ? i : -1;
     613                 :     }
     614               0 :     return IdToInt32(cx, id);
     615                 : }
     616                 : 
     617                 : static void
     618               0 : FillPropertyDescriptor(JSPropertyDescriptor *desc, JSObject *obj, jsval v, bool readonly)
     619                 : {
     620               0 :     desc->obj = obj;
     621               0 :     desc->value = v;
     622               0 :     desc->attrs = (readonly ? JSPROP_READONLY : 0) | JSPROP_ENUMERATE;
     623               0 :     desc->getter = NULL;
     624               0 :     desc->setter = NULL;
     625               0 :     desc->shortid = 0;
     626               0 : }
     627                 : 
     628                 : template<class LC>
     629                 : bool
     630               0 : ListBase<LC>::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
     631                 :                                        JSPropertyDescriptor *desc)
     632                 : {
     633               0 :     if (set) {
     634                 :         if (hasIndexSetter) {
     635               0 :             int32_t index = GetArrayIndexFromId(cx, id);
     636               0 :             if (index >= 0) {
     637               0 :                 FillPropertyDescriptor(desc, proxy, JSVAL_VOID, false);
     638               0 :                 return true;
     639                 :             }
     640                 :         }
     641                 : 
     642                 :         if (hasNameSetter && JSID_IS_STRING(id)) {
     643                 :             FillPropertyDescriptor(desc, proxy, JSVAL_VOID, false);
     644                 :             return true;
     645                 :         }
     646                 :     } else {
     647                 :         if (hasIndexGetter) {
     648               0 :             int32_t index = GetArrayIndexFromId(cx, id);
     649               0 :             if (index >= 0) {
     650               0 :                 IndexGetterType result;
     651               0 :                 if (!getItemAt(getListObject(proxy), PRUint32(index), result))
     652               0 :                     return true;
     653                 : 
     654                 :                 jsval v;
     655               0 :                 if (!Wrap(cx, proxy, result, &v))
     656               0 :                     return false;
     657               0 :                 FillPropertyDescriptor(desc, proxy, v, !hasIndexSetter);
     658               0 :                 return true;
     659                 :             }
     660                 :         }
     661                 :     }
     662                 : 
     663                 :     JSObject *expando;
     664               0 :     if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = getExpandoObject(proxy))) {
     665               0 :         unsigned flags = (set ? JSRESOLVE_ASSIGNING : 0) | JSRESOLVE_QUALIFIED;
     666               0 :         if (!JS_GetPropertyDescriptorById(cx, expando, id, flags, desc))
     667               0 :             return false;
     668               0 :         if (desc->obj) {
     669                 :             // Pretend the property lives on the wrapper.
     670               0 :             desc->obj = proxy;
     671               0 :             return true;
     672                 :         }
     673                 :     }
     674                 : 
     675               0 :     if (hasNameGetter && !set && JSID_IS_STRING(id) && !hasPropertyOnPrototype(cx, proxy, id)) {
     676               0 :         jsval name = STRING_TO_JSVAL(JSID_TO_STRING(id));
     677                 :         bool hasResult;
     678               0 :         NameGetterType result;
     679               0 :         if (!namedItem(cx, proxy, &name, result, &hasResult))
     680               0 :             return false;
     681               0 :         if (hasResult) {
     682                 :             jsval v;
     683               0 :             if (!Wrap(cx, proxy, result, &v))
     684               0 :                 return false;
     685               0 :             FillPropertyDescriptor(desc, proxy, v, !hasNameSetter);
     686               0 :             return true;
     687                 :         }
     688                 :     }
     689                 : 
     690               0 :     desc->obj = NULL;
     691               0 :     return true;
     692                 : }
     693                 : 
     694                 : template<class LC>
     695                 : bool
     696               0 : ListBase<LC>::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
     697                 :                                     JSPropertyDescriptor *desc)
     698                 : {
     699               0 :     if (!getOwnPropertyDescriptor(cx, proxy, id, set, desc))
     700               0 :         return false;
     701               0 :     if (desc->obj)
     702               0 :         return true;
     703               0 :     if (xpc::WrapperFactory::IsXrayWrapper(proxy))
     704               0 :         return resolveNativeName(cx, proxy, id, desc);
     705               0 :     JSObject *proto = js::GetObjectProto(proxy);
     706               0 :     if (!proto) {
     707               0 :         desc->obj = NULL;
     708               0 :         return true;
     709                 :     }
     710               0 :     return JS_GetPropertyDescriptorById(cx, proto, id, JSRESOLVE_QUALIFIED, desc);
     711                 : }
     712                 : 
     713                 : JSClass ExpandoClass = {
     714                 :     "DOM proxy binding expando object",
     715                 :     JSCLASS_HAS_PRIVATE,
     716                 :     JS_PropertyStub,
     717                 :     JS_PropertyStub,
     718                 :     JS_PropertyStub,
     719                 :     JS_StrictPropertyStub,
     720                 :     JS_EnumerateStub,
     721                 :     JS_ResolveStub,
     722                 :     JS_ConvertStub
     723                 : };
     724                 : 
     725                 : template<class LC>
     726                 : JSObject *
     727               0 : ListBase<LC>::ensureExpandoObject(JSContext *cx, JSObject *obj)
     728                 : {
     729               0 :     NS_ASSERTION(instanceIsProxy(obj), "expected a DOM proxy object");
     730               0 :     JSObject *expando = getExpandoObject(obj);
     731               0 :     if (!expando) {
     732               0 :         expando = JS_NewObjectWithGivenProto(cx, &ExpandoClass, nsnull,
     733                 :                                              js::GetObjectParent(obj));
     734               0 :         if (!expando)
     735               0 :             return NULL;
     736                 : 
     737               0 :         JSCompartment *compartment = js::GetObjectCompartment(obj);
     738                 :         xpc::CompartmentPrivate *priv =
     739               0 :             static_cast<xpc::CompartmentPrivate *>(JS_GetCompartmentPrivate(compartment));
     740               0 :         if (!priv->RegisterDOMExpandoObject(expando))
     741               0 :             return NULL;
     742                 : 
     743               0 :         js::SetProxyExtra(obj, JSPROXYSLOT_EXPANDO, ObjectValue(*expando));
     744               0 :         JS_SetPrivate(expando, js::GetProxyPrivate(obj).toPrivate());
     745                 :     }
     746               0 :     return expando;
     747                 : }
     748                 : 
     749                 : template<class LC>
     750                 : bool
     751               0 : ListBase<LC>::defineProperty(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc)
     752                 : {
     753                 :     if (hasIndexSetter) {
     754               0 :         int32_t index = GetArrayIndexFromId(cx, id);
     755               0 :         if (index >= 0) {
     756               0 :             nsCOMPtr<nsISupports> ref;
     757                 :             IndexSetterType value;
     758                 :             jsval v;
     759                 :             return Unwrap(cx, desc->value, &value, getter_AddRefs(ref), &v) &&
     760               0 :                    setItemAt(cx, getListObject(proxy), index, value);
     761                 :         }
     762                 :     }
     763                 : 
     764                 :     if (hasNameSetter && JSID_IS_STRING(id)) {
     765                 :         jsval name = STRING_TO_JSVAL(JSID_TO_STRING(id));
     766                 :         xpc_qsDOMString nameString(cx, name, &name,
     767                 :                                    xpc_qsDOMString::eDefaultNullBehavior,
     768                 :                                    xpc_qsDOMString::eDefaultUndefinedBehavior);
     769                 :         if (!nameString.IsValid())
     770                 :             return false;
     771                 : 
     772                 :         nsCOMPtr<nsISupports> ref;
     773                 :         NameSetterType value;
     774                 :         jsval v;
     775                 :         if (!Unwrap(cx, desc->value, &value, getter_AddRefs(ref), &v))
     776                 :             return false;
     777                 :         return setNamedItem(cx, getListObject(proxy), nameString, value);
     778                 :     }
     779                 : 
     780               0 :     if (xpc::WrapperFactory::IsXrayWrapper(proxy))
     781               0 :         return true;
     782                 : 
     783               0 :     JSObject *expando = ensureExpandoObject(cx, proxy);
     784               0 :     if (!expando)
     785               0 :         return false;
     786                 : 
     787                 :     return JS_DefinePropertyById(cx, expando, id, desc->value, desc->getter, desc->setter,
     788               0 :                                  desc->attrs);
     789                 : }
     790                 : 
     791                 : template<class LC>
     792                 : bool
     793               0 : ListBase<LC>::getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props)
     794                 : {
     795                 :     PRUint32 length;
     796               0 :     getListObject(proxy)->GetLength(&length);
     797               0 :     JS_ASSERT(int32_t(length) >= 0);
     798               0 :     for (int32_t i = 0; i < int32_t(length); ++i) {
     799               0 :         if (!props.append(INT_TO_JSID(i)))
     800               0 :             return false;
     801                 :     }
     802                 : 
     803                 :     JSObject *expando;
     804               0 :     if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = getExpandoObject(proxy)) &&
     805                 :         !js::GetPropertyNames(cx, expando, JSITER_OWNONLY | JSITER_HIDDEN, &props))
     806               0 :         return false;
     807                 : 
     808                 :     // FIXME: Add named items
     809               0 :     return true;
     810                 : }
     811                 : 
     812                 : template<class LC>
     813                 : bool
     814               0 : ListBase<LC>::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
     815                 : {
     816               0 :     JSBool b = true;
     817                 : 
     818                 :     JSObject *expando;
     819               0 :     if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = getExpandoObject(proxy))) {
     820                 :         jsval v;
     821               0 :         if (!JS_DeletePropertyById2(cx, expando, id, &v) ||
     822                 :             !JS_ValueToBoolean(cx, v, &b)) {
     823               0 :             return false;
     824                 :         }
     825                 :     }
     826                 : 
     827               0 :     *bp = !!b;
     828               0 :     return true;
     829                 : }
     830                 : 
     831                 : template<class LC>
     832                 : bool
     833               0 : ListBase<LC>::enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props)
     834                 : {
     835               0 :     JSObject *proto = JS_GetPrototype(proxy);
     836                 :     return getOwnPropertyNames(cx, proxy, props) &&
     837               0 :            (!proto || js::GetPropertyNames(cx, proto, 0, &props));
     838                 : }
     839                 : 
     840                 : template<class LC>
     841                 : bool
     842               0 : ListBase<LC>::fix(JSContext *cx, JSObject *proxy, Value *vp)
     843                 : {
     844               0 :     vp->setUndefined();
     845               0 :     return true;
     846                 : }
     847                 : 
     848                 : template<class LC>
     849                 : bool
     850               0 : ListBase<LC>::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
     851                 : {
     852                 :     if (hasIndexGetter) {
     853               0 :         int32_t index = GetArrayIndexFromId(cx, id);
     854               0 :         if (index >= 0) {
     855               0 :             IndexGetterType result;
     856               0 :             *bp = getItemAt(getListObject(proxy), PRUint32(index), result);
     857               0 :             return true;
     858                 :         }
     859                 :     }
     860                 : 
     861               0 :     JSObject *expando = getExpandoObject(proxy);
     862               0 :     if (expando) {
     863               0 :         JSBool b = true;
     864               0 :         JSBool ok = JS_HasPropertyById(cx, expando, id, &b);
     865               0 :         *bp = !!b;
     866               0 :         if (!ok || *bp)
     867               0 :             return ok;
     868                 :     }
     869                 : 
     870               0 :     if (hasNameGetter && JSID_IS_STRING(id) && !hasPropertyOnPrototype(cx, proxy, id)) {
     871               0 :         jsval name = STRING_TO_JSVAL(JSID_TO_STRING(id));
     872               0 :         NameGetterType result;
     873               0 :         return namedItem(cx, proxy, &name, result, bp);
     874                 :     }
     875                 : 
     876               0 :     *bp = false;
     877               0 :     return true;
     878                 : }
     879                 : 
     880                 : template<class LC>
     881                 : bool
     882               0 : ListBase<LC>::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
     883                 : {
     884               0 :     if (!hasOwn(cx, proxy, id, bp))
     885               0 :         return false;
     886                 :     // We have the property ourselves; no need to worry about our
     887                 :     // prototype chain.
     888               0 :     if (*bp)
     889               0 :         return true;
     890                 : 
     891                 :     // OK, now we have to look at the proto
     892               0 :     JSObject *proto = js::GetObjectProto(proxy);
     893               0 :     if (!proto)
     894               0 :         return true;
     895                 : 
     896                 :     JSBool protoHasProp;
     897               0 :     bool ok = JS_HasPropertyById(cx, proto, id, &protoHasProp);
     898               0 :     if (ok)
     899               0 :         *bp = protoHasProp;
     900               0 :     return ok;
     901                 : }
     902                 : 
     903                 : template<class LC>
     904                 : bool
     905            8027 : ListBase<LC>::protoIsClean(JSContext *cx, JSObject *proto, bool *isClean)
     906                 : {
     907                 :     JSPropertyDescriptor desc;
     908           16054 :     for (size_t n = 0; n < sProtoPropertiesCount; ++n) {
     909            8027 :         jsid id = sProtoProperties[n].id;
     910            8027 :         if (!JS_GetPropertyDescriptorById(cx, proto, id, JSRESOLVE_QUALIFIED, &desc))
     911               0 :             return false;
     912                 :         JSStrictPropertyOp setter =
     913            8027 :             sProtoProperties[n].setter ? sProtoProperties[n].setter : InvalidateProtoShape_set;
     914            8027 :         if (desc.obj != proto || desc.getter != sProtoProperties[n].getter ||
     915                 :             desc.setter != setter) {
     916               0 :             *isClean = false;
     917               0 :             return true;
     918                 :         }
     919                 :     }
     920                 : 
     921           18854 :     for (size_t n = 0; n < sProtoMethodsCount; ++n) {
     922           10827 :         jsid id = sProtoMethods[n].id;
     923           10827 :         if (!JS_GetPropertyDescriptorById(cx, proto, id, JSRESOLVE_QUALIFIED, &desc))
     924               0 :             return false;
     925           10827 :         if (desc.obj != proto || desc.getter || JSVAL_IS_PRIMITIVE(desc.value) ||
     926                 :             n >= js::GetObjectSlotSpan(proto) || js::GetObjectSlot(proto, n + 1) != desc.value ||
     927                 :             !JS_IsNativeFunction(JSVAL_TO_OBJECT(desc.value), sProtoMethods[n].native)) {
     928               0 :             *isClean = false;
     929               0 :             return true;
     930                 :         }
     931                 :     }
     932                 : 
     933            8027 :     *isClean = true;
     934            8027 :     return true;
     935                 : }
     936                 : 
     937                 : template<class LC>
     938                 : bool
     939            4315 : ListBase<LC>::shouldCacheProtoShape(JSContext *cx, JSObject *proto, bool *shouldCache)
     940                 : {
     941            4315 :     bool ok = protoIsClean(cx, proto, shouldCache);
     942            4315 :     if (!ok || !*shouldCache)
     943               0 :         return ok;
     944                 : 
     945            4315 :     js::SetReservedSlot(proto, 0, PrivateUint32Value(USE_CACHE));
     946                 : 
     947            4315 :     JSObject *protoProto = js::GetObjectProto(proto);
     948            4315 :     if (!protoProto) {
     949               0 :         *shouldCache = false;
     950               0 :         return true;
     951                 :     }
     952                 : 
     953            4315 :     return Base::shouldCacheProtoShape(cx, protoProto, shouldCache);
     954                 : }
     955                 : 
     956                 : template<class LC>
     957                 : bool
     958               0 : ListBase<LC>::resolveNativeName(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc)
     959                 : {
     960               0 :     JS_ASSERT(xpc::WrapperFactory::IsXrayWrapper(proxy));
     961                 : 
     962               0 :     for (size_t n = 0; n < sProtoPropertiesCount; ++n) {
     963               0 :         if (id == sProtoProperties[n].id) {
     964               0 :             desc->attrs = JSPROP_ENUMERATE | JSPROP_SHARED;
     965               0 :             if (!sProtoProperties[n].setter)
     966               0 :                 desc->attrs |= JSPROP_READONLY;
     967               0 :             desc->obj = proxy;
     968               0 :             desc->setter = sProtoProperties[n].setter;
     969               0 :             desc->getter = sProtoProperties[n].getter;
     970               0 :             return true;
     971                 :         }
     972                 :     }
     973                 : 
     974               0 :     for (size_t n = 0; n < sProtoMethodsCount; ++n) {
     975               0 :         if (id == sProtoMethods[n].id) {
     976                 :             JSFunction *fun = JS_NewFunctionById(cx, sProtoMethods[n].native,
     977               0 :                                                  sProtoMethods[n].nargs, 0, proxy, id);
     978               0 :             if (!fun)
     979               0 :                 return false;
     980               0 :             JSObject *funobj = JS_GetFunctionObject(fun);
     981               0 :             desc->value.setObject(*funobj);
     982               0 :             desc->attrs = JSPROP_ENUMERATE;
     983               0 :             desc->obj = proxy;
     984               0 :             desc->setter = nsnull;
     985               0 :             desc->getter = nsnull;
     986               0 :             return true;
     987                 :         }
     988                 :     }
     989                 : 
     990               0 :     return Base::resolveNativeName(cx, proxy, id, desc);
     991                 : }
     992                 : 
     993                 : template<class LC>
     994                 : bool
     995            3712 : ListBase<LC>::nativeGet(JSContext *cx, JSObject *proxy, JSObject *proto, jsid id, bool *found, Value *vp)
     996                 : {
     997            3712 :     uint32_t cache = js::GetReservedSlot(proto, 0).toPrivateUint32();
     998            3712 :     if (cache == CHECK_CACHE) {
     999                 :         bool isClean;
    1000               0 :         if (!protoIsClean(cx, proto, &isClean))
    1001               0 :             return false;
    1002               0 :         if (!isClean) {
    1003               0 :             js::SetReservedSlot(proto, 0, PrivateUint32Value(DONT_USE_CACHE));
    1004               0 :             return true;
    1005                 :         }
    1006               0 :         js::SetReservedSlot(proto, 0, PrivateUint32Value(USE_CACHE));
    1007                 :     }
    1008            3712 :     else if (cache == DONT_USE_CACHE) {
    1009               0 :         return true;
    1010                 :     }
    1011                 :     else {
    1012                 : #ifdef DEBUG
    1013                 :         bool isClean;
    1014            3712 :         JS_ASSERT(protoIsClean(cx, proto, &isClean) && isClean);
    1015                 : #endif
    1016                 :     }
    1017                 : 
    1018            7424 :     for (size_t n = 0; n < sProtoPropertiesCount; ++n) {
    1019            3712 :         if (id == sProtoProperties[n].id) {
    1020               0 :             *found = true;
    1021               0 :             if (!vp)
    1022               0 :                 return true;
    1023                 : 
    1024               0 :             return sProtoProperties[n].getter(cx, proxy, id, vp);
    1025                 :         }
    1026                 :     }
    1027            3728 :     for (size_t n = 0; n < sProtoMethodsCount; ++n) {
    1028            3720 :         if (id == sProtoMethods[n].id) {
    1029            3704 :             *found = true;
    1030            3704 :             if (!vp)
    1031               0 :                 return true;
    1032                 : 
    1033            3704 :             *vp = js::GetObjectSlot(proto, n + 1);
    1034            3704 :             JS_ASSERT(JS_IsNativeFunction(&vp->toObject(), sProtoMethods[n].native));
    1035            3704 :             return true;
    1036                 :         }
    1037                 :     }
    1038                 : 
    1039               8 :     JSObject *protoProto = js::GetObjectProto(proto);
    1040               8 :     if (!protoProto) {
    1041               0 :         *found = false;
    1042               0 :         return true;
    1043                 :     }
    1044                 : 
    1045               8 :     return Base::nativeGet(cx, proxy, protoProto, id, found, vp);
    1046                 : }
    1047                 : 
    1048                 : template<class LC>
    1049                 : bool
    1050           12691 : ListBase<LC>::getPropertyOnPrototype(JSContext *cx, JSObject *proxy, jsid id, bool *found,
    1051                 :                                      JS::Value *vp)
    1052                 : {
    1053           12691 :     JSObject *proto = js::GetObjectProto(proxy);
    1054           12691 :     if (!proto)
    1055               0 :         return true;
    1056                 : 
    1057                 :     bool hit;
    1058           12691 :     if (getProtoShape(proxy) != js::GetObjectShape(proto)) {
    1059            4315 :         if (!shouldCacheProtoShape(cx, proto, &hit))
    1060               0 :             return false;
    1061            4315 :         if (hit)
    1062            4315 :             setProtoShape(proxy, js::GetObjectShape(proto));
    1063                 :     } else {
    1064            8376 :         hit = true;
    1065                 :     }
    1066                 : 
    1067           12691 :     if (hit) {
    1068           12691 :         if (id == s_length_id) {
    1069            8979 :             if (vp) {
    1070                 :                 PRUint32 length;
    1071            8979 :                 getListObject(proxy)->GetLength(&length);
    1072            8979 :                 JS_ASSERT(int32_t(length) >= 0);
    1073            8979 :                 vp->setInt32(length);
    1074                 :             }
    1075            8979 :             *found = true;
    1076            8979 :             return true;
    1077                 :         }
    1078            3712 :         if (!nativeGet(cx, proxy, proto, id, found, vp))
    1079               0 :             return false;
    1080            3712 :         if (*found)
    1081            3704 :             return true;
    1082                 :     }
    1083                 : 
    1084                 :     JSBool hasProp;
    1085               8 :     if (!JS_HasPropertyById(cx, proto, id, &hasProp))
    1086               0 :         return false;
    1087                 : 
    1088               8 :     *found = hasProp;
    1089               8 :     if (!hasProp || !vp)
    1090               0 :         return true;
    1091                 : 
    1092               8 :     return JS_ForwardGetPropertyTo(cx, proto, id, proxy, vp);
    1093                 : }
    1094                 : 
    1095                 : template<class LC>
    1096                 : bool
    1097               0 : ListBase<LC>::hasPropertyOnPrototype(JSContext *cx, JSObject *proxy, jsid id)
    1098                 : {
    1099               0 :     JSAutoEnterCompartment ac;
    1100               0 :     if (xpc::WrapperFactory::IsXrayWrapper(proxy)) {
    1101               0 :         proxy = js::UnwrapObject(proxy);
    1102               0 :         if (!ac.enter(cx, proxy))
    1103               0 :             return false;
    1104                 :     }
    1105               0 :     JS_ASSERT(objIsList(proxy));
    1106                 : 
    1107                 :     bool found;
    1108                 :     // We ignore an error from getPropertyOnPrototype.
    1109               0 :     return !getPropertyOnPrototype(cx, proxy, id, &found, NULL) || found;
    1110                 : }
    1111                 : 
    1112                 : template<class LC>
    1113                 : bool
    1114           15490 : ListBase<LC>::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp)
    1115                 : {
    1116           15490 :     NS_ASSERTION(!xpc::WrapperFactory::IsXrayWrapper(proxy),
    1117                 :                  "Should not have a XrayWrapper here");
    1118                 : 
    1119           15490 :     bool getFromExpandoObject = true;
    1120                 : 
    1121                 :     if (hasIndexGetter) {
    1122           15490 :         int32_t index = GetArrayIndexFromId(cx, id);
    1123           15490 :         if (index >= 0) {
    1124               0 :             IndexGetterType result;
    1125            2799 :             if (getItemAt(getListObject(proxy), PRUint32(index), result))
    1126            2799 :                 return Wrap(cx, proxy, result, vp);
    1127                 : 
    1128                 :             // Even if we don't have this index, we don't forward the
    1129                 :             // get on to our expando object.
    1130               0 :             getFromExpandoObject = false;
    1131                 :         }
    1132                 :     }
    1133                 : 
    1134           12691 :     if (getFromExpandoObject) {
    1135           12691 :         JSObject *expando = getExpandoObject(proxy);
    1136           12691 :         if (expando) {
    1137                 :             JSBool hasProp;
    1138               0 :             if (!JS_HasPropertyById(cx, expando, id, &hasProp))
    1139               0 :                 return false;
    1140                 : 
    1141               0 :             if (hasProp)
    1142               0 :                 return JS_GetPropertyById(cx, expando, id, vp);
    1143                 :         }
    1144                 :     }
    1145                 : 
    1146                 :     bool found;
    1147           12691 :     if (!getPropertyOnPrototype(cx, proxy, id, &found, vp))
    1148               0 :         return false;
    1149                 : 
    1150           12691 :     if (found)
    1151           12691 :         return true;
    1152                 : 
    1153               0 :     if (hasNameGetter && JSID_IS_STRING(id)) {
    1154               0 :         jsval name = STRING_TO_JSVAL(JSID_TO_STRING(id));
    1155                 :         bool hasResult;
    1156               0 :         NameGetterType result;
    1157               0 :         if (!namedItem(cx, proxy, &name, result, &hasResult))
    1158               0 :             return false;
    1159               0 :         if (hasResult)
    1160               0 :             return Wrap(cx, proxy, result, vp);
    1161                 :     }
    1162                 : 
    1163               0 :     vp->setUndefined();
    1164               0 :     return true;
    1165                 : }
    1166                 : 
    1167                 : template<class LC>
    1168                 : bool
    1169            1135 : ListBase<LC>::getElementIfPresent(JSContext *cx, JSObject *proxy, JSObject *receiver,
    1170                 :                                   uint32_t index, Value *vp, bool *present)
    1171                 : {
    1172            1135 :     NS_ASSERTION(!xpc::WrapperFactory::IsXrayWrapper(proxy),
    1173                 :                  "Should not have a XrayWrapper here");
    1174                 : 
    1175                 :     if (hasIndexGetter) {
    1176               0 :         IndexGetterType result;
    1177            1135 :         *present = getItemAt(getListObject(proxy), index, result);
    1178            1135 :         if (*present)
    1179            1135 :             return Wrap(cx, proxy, result, vp);
    1180                 :     }
    1181                 : 
    1182                 :     jsid id;
    1183               0 :     if (!JS_IndexToId(cx, index, &id))
    1184               0 :         return false;
    1185                 : 
    1186                 :     // if hasIndexGetter, we skip the expando object
    1187                 :     if (!hasIndexGetter) {
    1188                 :         JSObject *expando = getExpandoObject(proxy);
    1189                 :         if (expando) {
    1190                 :             JSBool isPresent;
    1191                 :             if (!JS_GetElementIfPresent(cx, expando, index, expando, vp, &isPresent))
    1192                 :                 return false;
    1193                 :             if (isPresent) {
    1194                 :                 *present = true;
    1195                 :                 return true;
    1196                 :             }
    1197                 :         }
    1198                 :     }
    1199                 : 
    1200                 :     // No need to worry about name getters here, so just check the proto.
    1201                 : 
    1202               0 :     JSObject *proto = js::GetObjectProto(proxy);
    1203               0 :     if (proto) {
    1204                 :         JSBool isPresent;
    1205               0 :         if (!JS_GetElementIfPresent(cx, proto, index, proxy, vp, &isPresent))
    1206               0 :             return false;
    1207               0 :         *present = isPresent;
    1208               0 :         return true;
    1209                 :     }
    1210                 : 
    1211               0 :     *present = false;
    1212                 :     // Can't Debug_SetValueRangeToCrashOnTouch because it's not public
    1213               0 :     return true;
    1214                 : }
    1215                 : 
    1216                 : template<class LC>
    1217                 : bool
    1218               0 : ListBase<LC>::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, bool strict,
    1219                 :                   Value *vp)
    1220                 : {
    1221               0 :     return ProxyHandler::set(cx, proxy, proxy, id, strict, vp);
    1222                 : }
    1223                 : 
    1224                 : template<class LC>
    1225                 : bool
    1226               0 : ListBase<LC>::keys(JSContext *cx, JSObject *proxy, AutoIdVector &props)
    1227                 : {
    1228               0 :     return ProxyHandler::keys(cx, proxy, props);
    1229                 : }
    1230                 : 
    1231                 : template<class LC>
    1232                 : bool
    1233               0 : ListBase<LC>::iterate(JSContext *cx, JSObject *proxy, unsigned flags, Value *vp)
    1234                 : {
    1235               0 :     if (flags == JSITER_FOR_OF) {
    1236               0 :         JSObject *iterobj = JS_NewElementIterator(cx, proxy);
    1237               0 :         if (!iterobj)
    1238               0 :             return false;
    1239               0 :         vp->setObject(*iterobj);
    1240               0 :         return true;
    1241                 :     }
    1242               0 :     return ProxyHandler::iterate(cx, proxy, flags, vp);
    1243                 : }
    1244                 : 
    1245                 : template<class LC>
    1246                 : bool
    1247               0 : ListBase<LC>::hasInstance(JSContext *cx, JSObject *proxy, const Value *vp, bool *bp)
    1248                 : {
    1249               0 :     *bp = vp->isObject() && js::GetObjectClass(&vp->toObject()) == &sInterfaceClass;
    1250               0 :     return true;
    1251                 : }
    1252                 : 
    1253                 : template<class LC>
    1254                 : JSString *
    1255               4 : ListBase<LC>::obj_toString(JSContext *cx, JSObject *proxy)
    1256                 : {
    1257               4 :     const char *clazz = sInterfaceClass.name;
    1258               4 :     size_t nchars = 9 + strlen(clazz); /* 9 for "[object ]" */
    1259               4 :     jschar *chars = (jschar *)JS_malloc(cx, (nchars + 1) * sizeof(jschar));
    1260               4 :     if (!chars)
    1261               0 :         return NULL;
    1262                 : 
    1263               4 :     const char *prefix = "[object ";
    1264               4 :     nchars = 0;
    1265              40 :     while ((chars[nchars] = (jschar)*prefix) != 0)
    1266              32 :         nchars++, prefix++;
    1267              64 :     while ((chars[nchars] = (jschar)*clazz) != 0)
    1268              56 :         nchars++, clazz++;
    1269               4 :     chars[nchars++] = ']';
    1270               4 :     chars[nchars] = 0;
    1271                 : 
    1272               4 :     JSString *str = JS_NewUCString(cx, chars, nchars);
    1273               4 :     if (!str)
    1274               0 :         JS_free(cx, chars);
    1275               4 :     return str;
    1276                 : }
    1277                 : 
    1278                 : template<class LC>
    1279                 : void
    1280            4321 : ListBase<LC>::finalize(JSContext *cx, JSObject *proxy)
    1281                 : {
    1282            4321 :     ListType *list = getListObject(proxy);
    1283                 :     nsWrapperCache *cache;
    1284            4321 :     CallQueryInterface(list, &cache);
    1285            4321 :     if (cache) {
    1286            4321 :         cache->ClearWrapper();
    1287                 :     }
    1288            4321 :     XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance();
    1289            4321 :     if (rt) {
    1290            4321 :         rt->DeferredRelease(nativeToSupports(list));
    1291                 :     }
    1292                 :     else {
    1293               0 :         NS_RELEASE(list);
    1294                 :     }
    1295            4321 : }
    1296                 : 
    1297                 : 
    1298                 : JSObject*
    1299             274 : NoBase::getPrototype(JSContext *cx, XPCWrappedNativeScope *scope)
    1300                 : {
    1301                 :     // We need to pass the object prototype to JS_NewObject. If we pass NULL then the JS engine
    1302                 :     // will look up a prototype on the global by using the class' name and we'll recurse into
    1303                 :     // getPrototype.
    1304             274 :     return JS_GetObjectPrototype(cx, scope->GetGlobalJSObject());
    1305                 : }
    1306                 : 
    1307                 : 
    1308                 : }
    1309                 : }
    1310                 : }
    1311                 : #include "dombindings_gen.cpp"

Generated by: LCOV version 1.7