LCOV - code coverage report
Current view: directory - js/src - jsproxy.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 819 488 59.6 %
Date: 2012-04-07 Functions: 136 91 66.9 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * vim: set ts=4 sw=4 et tw=99:
       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 SpiderMonkey JavaScript 1.9 code, released
      18                 :  * May 28, 2008.
      19                 :  *
      20                 :  * The Initial Developer of the Original Code is
      21                 :  *   Mozilla Foundation
      22                 :  * Portions created by the Initial Developer are Copyright (C) 2009
      23                 :  * the Initial Developer. All Rights Reserved.
      24                 :  *
      25                 :  * Contributor(s):
      26                 :  *   Andreas Gal <gal@mozilla.com>
      27                 :  *
      28                 :  * Alternatively, the contents of this file may be used under the terms of
      29                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      30                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      31                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      32                 :  * of those above. If you wish to allow use of your version of this file only
      33                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      34                 :  * use your version of this file under the terms of the MPL, indicate your
      35                 :  * decision by deleting the provisions above and replace them with the notice
      36                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      37                 :  * the provisions above, a recipient may use your version of this file under
      38                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      39                 :  *
      40                 :  * ***** END LICENSE BLOCK ***** */
      41                 : 
      42                 : #include <string.h>
      43                 : #include "jsapi.h"
      44                 : #include "jscntxt.h"
      45                 : #include "jsgc.h"
      46                 : #include "jsgcmark.h"
      47                 : #include "jsprvtd.h"
      48                 : #include "jsnum.h"
      49                 : #include "jsobj.h"
      50                 : #include "jsproxy.h"
      51                 : #include "jsscope.h"
      52                 : 
      53                 : #include "vm/MethodGuard.h"
      54                 : 
      55                 : #include "jsatominlines.h"
      56                 : #include "jsinferinlines.h"
      57                 : #include "jsobjinlines.h"
      58                 : 
      59                 : using namespace js;
      60                 : using namespace js::gc;
      61                 : 
      62                 : static inline HeapSlot &
      63           33583 : GetCall(JSObject *proxy)
      64                 : {
      65           33583 :     JS_ASSERT(IsFunctionProxy(proxy));
      66           33583 :     return proxy->getSlotRef(JSSLOT_PROXY_CALL);
      67                 : }
      68                 : 
      69                 : static inline Value
      70             207 : GetConstruct(JSObject *proxy)
      71                 : {
      72             207 :     if (proxy->slotSpan() <= JSSLOT_PROXY_CONSTRUCT)
      73               0 :         return UndefinedValue();
      74             207 :     return proxy->getSlot(JSSLOT_PROXY_CONSTRUCT);
      75                 : }
      76                 : 
      77                 : static inline HeapSlot &
      78           12492 : GetFunctionProxyConstruct(JSObject *proxy)
      79                 : {
      80           12492 :     JS_ASSERT(IsFunctionProxy(proxy));
      81           12492 :     JS_ASSERT(proxy->slotSpan() > JSSLOT_PROXY_CONSTRUCT);
      82           12492 :     return proxy->getSlotRef(JSSLOT_PROXY_CONSTRUCT);
      83                 : }
      84                 : 
      85                 : static bool
      86           30551 : OperationInProgress(JSContext *cx, JSObject *proxy)
      87                 : {
      88           30551 :     PendingProxyOperation *op = cx->runtime->pendingProxyOperation;
      89           61102 :     while (op) {
      90           30515 :         if (op->object == proxy)
      91           30515 :             return true;
      92               0 :         op = op->next;
      93                 :     }
      94              36 :     return false;
      95                 : }
      96                 : 
      97                 : static bool
      98                 : FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp);
      99                 : 
     100           56002 : ProxyHandler::ProxyHandler(void *family) : mFamily(family)
     101                 : {
     102           56002 : }
     103                 : 
     104           56002 : ProxyHandler::~ProxyHandler()
     105                 : {
     106           56002 : }
     107                 : 
     108                 : bool
     109               0 : ProxyHandler::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
     110                 : {
     111               0 :     JS_ASSERT(OperationInProgress(cx, proxy));
     112               0 :     AutoPropertyDescriptorRooter desc(cx);
     113               0 :     if (!getPropertyDescriptor(cx, proxy, id, false, &desc))
     114               0 :         return false;
     115               0 :     *bp = !!desc.obj;
     116               0 :     return true;
     117                 : }
     118                 : 
     119                 : bool
     120               0 : ProxyHandler::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
     121                 : {
     122               0 :     JS_ASSERT(OperationInProgress(cx, proxy));
     123               0 :     AutoPropertyDescriptorRooter desc(cx);
     124               0 :     if (!getOwnPropertyDescriptor(cx, proxy, id, false, &desc))
     125               0 :         return false;
     126               0 :     *bp = !!desc.obj;
     127               0 :     return true;
     128                 : }
     129                 : 
     130                 : bool
     131             153 : ProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp)
     132                 : {
     133             153 :     JS_ASSERT(OperationInProgress(cx, proxy));
     134             306 :     AutoPropertyDescriptorRooter desc(cx);
     135             153 :     if (!getPropertyDescriptor(cx, proxy, id, false, &desc))
     136             135 :         return false;
     137              18 :     if (!desc.obj) {
     138              18 :         vp->setUndefined();
     139              18 :         return true;
     140                 :     }
     141               0 :     if (!desc.getter ||
     142               0 :         (!(desc.attrs & JSPROP_GETTER) && desc.getter == JS_PropertyStub)) {
     143               0 :         *vp = desc.value;
     144               0 :         return true;
     145                 :     }
     146               0 :     if (desc.attrs & JSPROP_GETTER)
     147               0 :         return InvokeGetterOrSetter(cx, receiver, CastAsObjectJsval(desc.getter), 0, NULL, vp);
     148               0 :     if (!(desc.attrs & JSPROP_SHARED))
     149               0 :         *vp = desc.value;
     150                 :     else
     151               0 :         vp->setUndefined();
     152               0 :     if (desc.attrs & JSPROP_SHORTID)
     153               0 :         id = INT_TO_JSID(desc.shortid);
     154               0 :     return CallJSPropertyOp(cx, desc.getter, receiver, id, vp);
     155                 : }
     156                 : 
     157                 : bool
     158             513 : ProxyHandler::getElementIfPresent(JSContext *cx, JSObject *proxy, JSObject *receiver, uint32_t index, Value *vp, bool *present)
     159                 : {
     160                 :     jsid id;
     161             513 :     if (!IndexToId(cx, index, &id))
     162               0 :         return false;
     163                 : 
     164             513 :     if (!has(cx, proxy, id, present))
     165              18 :         return false;
     166                 : 
     167             495 :     if (!*present) {
     168               9 :         Debug_SetValueRangeToCrashOnTouch(vp, 1);
     169               9 :         return true;
     170                 :     }
     171                 : 
     172             486 :     return get(cx, proxy, receiver, id, vp);
     173                 : }   
     174                 : 
     175                 : bool
     176             756 : ProxyHandler::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, bool strict,
     177                 :                   Value *vp)
     178                 : {
     179             756 :     JS_ASSERT(OperationInProgress(cx, proxy));
     180            1512 :     AutoPropertyDescriptorRooter desc(cx);
     181             756 :     if (!getOwnPropertyDescriptor(cx, proxy, id, true, &desc))
     182               0 :         return false;
     183                 :     /* The control-flow here differs from ::get() because of the fall-through case below. */
     184             756 :     if (desc.obj) {
     185                 :         // Check for read-only properties.
     186             756 :         if (desc.attrs & JSPROP_READONLY)
     187             756 :             return strict ? Throw(cx, id, JSMSG_CANT_REDEFINE_PROP) : true;
     188               0 :         if (!desc.setter) {
     189                 :             // Be wary of the odd explicit undefined setter case possible through
     190                 :             // Object.defineProperty.
     191               0 :             if (!(desc.attrs & JSPROP_SETTER))
     192               0 :                 desc.setter = JS_StrictPropertyStub;
     193               0 :         } else if ((desc.attrs & JSPROP_SETTER) || desc.setter != JS_StrictPropertyStub) {
     194               0 :             if (!CallSetter(cx, receiver, id, desc.setter, desc.attrs, desc.shortid, strict, vp))
     195               0 :                 return false;
     196               0 :             if (!proxy->isProxy() || GetProxyHandler(proxy) != this)
     197               0 :                 return true;
     198               0 :             if (desc.attrs & JSPROP_SHARED)
     199               0 :                 return true;
     200                 :         }
     201               0 :         if (!desc.getter) {
     202                 :             // Same as above for the null setter case.
     203               0 :             if (!(desc.attrs & JSPROP_GETTER))
     204               0 :                 desc.getter = JS_PropertyStub;
     205                 :         }
     206               0 :         desc.value = *vp;
     207               0 :         return defineProperty(cx, receiver, id, &desc);
     208                 :     }
     209               0 :     if (!getPropertyDescriptor(cx, proxy, id, true, &desc))
     210               0 :         return false;
     211               0 :     if (desc.obj) {
     212                 :         // Check for read-only properties.
     213               0 :         if (desc.attrs & JSPROP_READONLY)
     214               0 :             return strict ? Throw(cx, id, JSMSG_CANT_REDEFINE_PROP) : true;
     215               0 :         if (!desc.setter) {
     216                 :             // Be wary of the odd explicit undefined setter case possible through
     217                 :             // Object.defineProperty.
     218               0 :             if (!(desc.attrs & JSPROP_SETTER))
     219               0 :                 desc.setter = JS_StrictPropertyStub;
     220               0 :         } else if ((desc.attrs & JSPROP_SETTER) || desc.setter != JS_StrictPropertyStub) {
     221               0 :             if (!CallSetter(cx, receiver, id, desc.setter, desc.attrs, desc.shortid, strict, vp))
     222               0 :                 return false;
     223               0 :             if (!proxy->isProxy() || GetProxyHandler(proxy) != this)
     224               0 :                 return true;
     225               0 :             if (desc.attrs & JSPROP_SHARED)
     226               0 :                 return true;
     227                 :         }
     228               0 :         if (!desc.getter) {
     229                 :             // Same as above for the null setter case.
     230               0 :             if (!(desc.attrs & JSPROP_GETTER))
     231               0 :                 desc.getter = JS_PropertyStub;
     232                 :         }
     233               0 :         return defineProperty(cx, receiver, id, &desc);
     234                 :     }
     235                 : 
     236               0 :     desc.obj = receiver;
     237               0 :     desc.value = *vp;
     238               0 :     desc.attrs = JSPROP_ENUMERATE;
     239               0 :     desc.shortid = 0;
     240               0 :     desc.getter = NULL;
     241               0 :     desc.setter = NULL; // Pick up the class getter/setter.
     242               0 :     return defineProperty(cx, receiver, id, &desc);
     243                 : }
     244                 : 
     245                 : bool
     246               0 : ProxyHandler::keys(JSContext *cx, JSObject *proxy, AutoIdVector &props)
     247                 : {
     248               0 :     JS_ASSERT(OperationInProgress(cx, proxy));
     249               0 :     JS_ASSERT(props.length() == 0);
     250                 : 
     251               0 :     if (!getOwnPropertyNames(cx, proxy, props))
     252               0 :         return false;
     253                 : 
     254                 :     /* Select only the enumerable properties through in-place iteration. */
     255               0 :     AutoPropertyDescriptorRooter desc(cx);
     256               0 :     size_t i = 0;
     257               0 :     for (size_t j = 0, len = props.length(); j < len; j++) {
     258               0 :         JS_ASSERT(i <= j);
     259               0 :         jsid id = props[j];
     260               0 :         if (!getOwnPropertyDescriptor(cx, proxy, id, false, &desc))
     261               0 :             return false;
     262               0 :         if (desc.obj && (desc.attrs & JSPROP_ENUMERATE))
     263               0 :             props[i++] = id;
     264                 :     }
     265                 : 
     266               0 :     JS_ASSERT(i <= props.length());
     267               0 :     props.resize(i);
     268                 : 
     269               0 :     return true;
     270                 : }
     271                 : 
     272                 : bool
     273               0 : ProxyHandler::iterate(JSContext *cx, JSObject *proxy, unsigned flags, Value *vp)
     274                 : {
     275               0 :     JS_ASSERT(OperationInProgress(cx, proxy));
     276               0 :     AutoIdVector props(cx);
     277               0 :     if ((flags & JSITER_OWNONLY)
     278               0 :         ? !keys(cx, proxy, props)
     279               0 :         : !enumerate(cx, proxy, props)) {
     280               0 :         return false;
     281                 :     }
     282               0 :     return EnumeratedIdVectorToIterator(cx, proxy, flags, props, vp);
     283                 : }
     284                 : 
     285                 : JSString *
     286               0 : ProxyHandler::obj_toString(JSContext *cx, JSObject *proxy)
     287                 : {
     288               0 :     JS_ASSERT(proxy->isProxy());
     289                 : 
     290               0 :     return JS_NewStringCopyZ(cx, IsFunctionProxy(proxy)
     291                 :                                  ? "[object Function]"
     292               0 :                                  : "[object Object]");
     293                 : }
     294                 : 
     295                 : JSString *
     296               9 : ProxyHandler::fun_toString(JSContext *cx, JSObject *proxy, unsigned indent)
     297                 : {
     298               9 :     JS_ASSERT(proxy->isProxy());
     299               9 :     Value fval = GetCall(proxy);
     300              27 :     if (IsFunctionProxy(proxy) &&
     301              18 :         (fval.isPrimitive() || !fval.toObject().isFunction())) {
     302                 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
     303                 :                              JSMSG_INCOMPATIBLE_PROTO,
     304                 :                              js_Function_str, js_toString_str,
     305               0 :                              "object");
     306               0 :         return NULL;
     307                 :     }
     308               9 :     return fun_toStringHelper(cx, &fval.toObject(), indent);
     309                 : }
     310                 : 
     311                 : bool
     312               0 : ProxyHandler::regexp_toShared(JSContext *cx, JSObject *proxy, RegExpGuard *g)
     313                 : {
     314               0 :     JS_NOT_REACHED("This should have been a wrapped regexp");
     315                 :     return false;
     316                 : }
     317                 : 
     318                 : bool
     319             153 : ProxyHandler::defaultValue(JSContext *cx, JSObject *proxy, JSType hint, Value *vp)
     320                 : {
     321             153 :     return DefaultValue(cx, proxy, hint, vp);
     322                 : }
     323                 : 
     324                 : bool
     325               0 : ProxyHandler::iteratorNext(JSContext *cx, JSObject *proxy, Value *vp)
     326                 : {
     327               0 :     vp->setMagic(JS_NO_ITER_VALUE);
     328               0 :     return true;
     329                 : }
     330                 : 
     331                 : bool
     332           20902 : ProxyHandler::call(JSContext *cx, JSObject *proxy, unsigned argc, Value *vp)
     333                 : {
     334           20902 :     JS_ASSERT(OperationInProgress(cx, proxy));
     335           41804 :     AutoValueRooter rval(cx);
     336           20902 :     JSBool ok = Invoke(cx, vp[1], GetCall(proxy), argc, JS_ARGV(cx, vp), rval.addr());
     337           20902 :     if (ok)
     338           18562 :         JS_SET_RVAL(cx, vp, rval.value());
     339           20902 :     return ok;
     340                 : }
     341                 : 
     342                 : bool
     343             189 : ProxyHandler::construct(JSContext *cx, JSObject *proxy,
     344                 :                         unsigned argc, Value *argv, Value *rval)
     345                 : {
     346             189 :     JS_ASSERT(OperationInProgress(cx, proxy));
     347             189 :     Value fval = GetConstruct(proxy);
     348             189 :     if (fval.isUndefined())
     349             162 :         return InvokeConstructor(cx, GetCall(proxy), argc, argv, rval);
     350              27 :     return Invoke(cx, UndefinedValue(), fval, argc, argv, rval);
     351                 : }
     352                 : 
     353                 : bool
     354            1800 : ProxyHandler::nativeCall(JSContext *cx, JSObject *proxy, Class *clasp, Native native, CallArgs args)
     355                 : {
     356            1800 :     JS_ASSERT(OperationInProgress(cx, proxy));
     357            1800 :     ReportIncompatibleMethod(cx, args, clasp);
     358            1800 :     return false;
     359                 : }
     360                 : 
     361                 : bool
     362               0 : ProxyHandler::hasInstance(JSContext *cx, JSObject *proxy, const Value *vp, bool *bp)
     363                 : {
     364               0 :     JS_ASSERT(OperationInProgress(cx, proxy));
     365               0 :     js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
     366               0 :                         JSDVG_SEARCH_STACK, ObjectValue(*proxy), NULL);
     367               0 :     return false;
     368                 : }
     369                 : 
     370                 : JSType
     371               0 : ProxyHandler::typeOf(JSContext *cx, JSObject *proxy)
     372                 : {
     373               0 :     JS_ASSERT(OperationInProgress(cx, proxy));
     374               0 :     return IsFunctionProxy(proxy) ? JSTYPE_FUNCTION : JSTYPE_OBJECT;
     375                 : }
     376                 : 
     377                 : bool
     378             153 : ProxyHandler::objectClassIs(JSObject *proxy, ESClassValue classValue, JSContext *cx)
     379                 : {
     380             153 :     JS_ASSERT(OperationInProgress(cx, proxy));
     381             153 :     return false;
     382                 : }
     383                 : 
     384                 : void
     385           18687 : ProxyHandler::finalize(JSFreeOp *fop, JSObject *proxy)
     386                 : {
     387           18687 : }
     388                 : 
     389                 : void
     390              27 : ProxyHandler::trace(JSTracer *trc, JSObject *proxy)
     391                 : {
     392              27 : }
     393                 : 
     394                 : static bool
     395            6562 : GetTrap(JSContext *cx, JSObject *handler, JSAtom *atom, Value *fvalp)
     396                 : {
     397            6562 :     JS_CHECK_RECURSION(cx, return false);
     398                 : 
     399            6562 :     return handler->getGeneric(cx, ATOM_TO_JSID(atom), fvalp);
     400                 : }
     401                 : 
     402                 : static bool
     403            2801 : GetFundamentalTrap(JSContext *cx, JSObject *handler, JSAtom *atom, Value *fvalp)
     404                 : {
     405            2801 :     if (!GetTrap(cx, handler, atom, fvalp))
     406               0 :         return false;
     407                 : 
     408            2801 :     if (!js_IsCallable(*fvalp)) {
     409              18 :         JSAutoByteString bytes;
     410               9 :         if (js_AtomToPrintableString(cx, atom, &bytes))
     411               9 :             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_FUNCTION, bytes.ptr());
     412               9 :         return false;
     413                 :     }
     414                 : 
     415            2792 :     return true;
     416                 : }
     417                 : 
     418                 : static bool
     419            3761 : GetDerivedTrap(JSContext *cx, JSObject *handler, JSAtom *atom, Value *fvalp)
     420                 : {
     421               0 :     JS_ASSERT(atom == ATOM(has) ||
     422                 :               atom == ATOM(hasOwn) ||
     423                 :               atom == ATOM(get) ||
     424                 :               atom == ATOM(set) ||
     425                 :               atom == ATOM(keys) ||
     426            3761 :               atom == ATOM(iterate));
     427                 : 
     428            3761 :     return GetTrap(cx, handler, atom, fvalp);
     429                 : }
     430                 : 
     431                 : static bool
     432            5644 : Trap(JSContext *cx, JSObject *handler, Value fval, unsigned argc, Value* argv, Value *rval)
     433                 : {
     434            5644 :     return Invoke(cx, ObjectValue(*handler), fval, argc, argv, rval);
     435                 : }
     436                 : 
     437                 : static bool
     438            1723 : Trap1(JSContext *cx, JSObject *handler, Value fval, jsid id, Value *rval)
     439                 : {
     440            1723 :     JSString *str = ToString(cx, IdToValue(id));
     441            1723 :     if (!str)
     442               0 :         return false;
     443            1723 :     rval->setString(str);
     444            1723 :     return Trap(cx, handler, fval, 1, rval, rval);
     445                 : }
     446                 : 
     447                 : static bool
     448            1757 : Trap2(JSContext *cx, JSObject *handler, Value fval, jsid id, Value v, Value *rval)
     449                 : {
     450            1757 :     JSString *str = ToString(cx, IdToValue(id));
     451            1757 :     if (!str)
     452               0 :         return false;
     453            1757 :     rval->setString(str);
     454            1757 :     Value argv[2] = { *rval, v };
     455            1757 :     return Trap(cx, handler, fval, 2, argv, rval);
     456                 : }
     457                 : 
     458                 : static bool
     459            2558 : ParsePropertyDescriptorObject(JSContext *cx, JSObject *obj, jsid id, const Value &v,
     460                 :                               PropertyDescriptor *desc)
     461                 : {
     462            5116 :     AutoPropDescArrayRooter descs(cx);
     463            2558 :     PropDesc *d = descs.append();
     464            2558 :     if (!d || !d->initialize(cx, v))
     465               0 :         return false;
     466            2558 :     desc->obj = obj;
     467            2558 :     desc->value = d->value;
     468            2558 :     JS_ASSERT(!(d->attrs & JSPROP_SHORTID));
     469            2558 :     desc->attrs = d->attrs;
     470            2558 :     desc->getter = d->getter();
     471            2558 :     desc->setter = d->setter();
     472            2558 :     desc->shortid = 0;
     473            2558 :     return true;
     474                 : }
     475                 : 
     476                 : static bool
     477              18 : IndicatePropertyNotFound(JSContext *cx, PropertyDescriptor *desc)
     478                 : {
     479              18 :     desc->obj = NULL;
     480              18 :     return true;
     481                 : }
     482                 : 
     483                 : static bool
     484             751 : ValueToBool(JSContext *cx, const Value &v, bool *bp)
     485                 : {
     486             751 :     *bp = !!js_ValueToBoolean(v);
     487             751 :     return true;
     488                 : }
     489                 : 
     490                 : static bool
     491               9 : ArrayToIdVector(JSContext *cx, const Value &array, AutoIdVector &props)
     492                 : {
     493               9 :     JS_ASSERT(props.length() == 0);
     494                 : 
     495               9 :     if (array.isPrimitive())
     496               0 :         return true;
     497                 : 
     498               9 :     JSObject *obj = &array.toObject();
     499                 :     uint32_t length;
     500               9 :     if (!js_GetLengthProperty(cx, obj, &length))
     501               0 :         return false;
     502                 : 
     503              18 :     for (uint32_t n = 0; n < length; ++n) {
     504               9 :         if (!JS_CHECK_OPERATION_LIMIT(cx))
     505               0 :             return false;
     506                 :         Value v;
     507               9 :         if (!obj->getElement(cx, n, &v))
     508               0 :             return false;
     509                 :         jsid id;
     510               9 :         if (!ValueToId(cx, v, &id))
     511               0 :             return false;
     512               9 :         if (!props.append(js_CheckForStringIndex(id)))
     513               0 :             return false;
     514                 :     }
     515                 : 
     516               9 :     return true;
     517                 : }
     518                 : 
     519                 : /* Derived class for all scripted proxy handlers. */
     520                 : class ScriptedProxyHandler : public ProxyHandler {
     521                 :   public:
     522                 :     ScriptedProxyHandler();
     523                 :     virtual ~ScriptedProxyHandler();
     524                 : 
     525                 :     /* ES5 Harmony fundamental proxy traps. */
     526                 :     virtual bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
     527                 :                                        PropertyDescriptor *desc);
     528                 :     virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
     529                 :                                           PropertyDescriptor *desc);
     530                 :     virtual bool defineProperty(JSContext *cx, JSObject *proxy, jsid id,
     531                 :                                 PropertyDescriptor *desc);
     532                 :     virtual bool getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props);
     533                 :     virtual bool delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp);
     534                 :     virtual bool enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props);
     535                 :     virtual bool fix(JSContext *cx, JSObject *proxy, Value *vp);
     536                 : 
     537                 :     /* ES5 Harmony derived proxy traps. */
     538                 :     virtual bool has(JSContext *cx, JSObject *proxy, jsid id, bool *bp);
     539                 :     virtual bool hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp);
     540                 :     virtual bool get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp);
     541                 :     virtual bool set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, bool strict,
     542                 :                      Value *vp);
     543                 :     virtual bool keys(JSContext *cx, JSObject *proxy, AutoIdVector &props);
     544                 :     virtual bool iterate(JSContext *cx, JSObject *proxy, unsigned flags, Value *vp);
     545                 : 
     546                 :     static ScriptedProxyHandler singleton;
     547                 : };
     548                 : 
     549                 : static int sScriptedProxyHandlerFamily = 0;
     550                 : 
     551           18667 : ScriptedProxyHandler::ScriptedProxyHandler() : ProxyHandler(&sScriptedProxyHandlerFamily)
     552                 : {
     553           18667 : }
     554                 : 
     555           18667 : ScriptedProxyHandler::~ScriptedProxyHandler()
     556                 : {
     557           18667 : }
     558                 : 
     559                 : static bool
     560             801 : ReturnedValueMustNotBePrimitive(JSContext *cx, JSObject *proxy, JSAtom *atom, const Value &v)
     561                 : {
     562             801 :     if (v.isPrimitive()) {
     563               0 :         JSAutoByteString bytes;
     564               0 :         if (js_AtomToPrintableString(cx, atom, &bytes)) {
     565               0 :             js_ReportValueError2(cx, JSMSG_BAD_TRAP_RETURN_VALUE,
     566               0 :                                  JSDVG_SEARCH_STACK, ObjectOrNullValue(proxy), NULL, bytes.ptr());
     567                 :         }
     568               0 :         return false;
     569                 :     }
     570             801 :     return true;
     571                 : }
     572                 : 
     573                 : static JSObject *
     574            6562 : GetProxyHandlerObject(JSContext *cx, JSObject *proxy)
     575                 : {
     576            6562 :     JS_ASSERT(OperationInProgress(cx, proxy));
     577            6562 :     return GetProxyPrivate(proxy).toObjectOrNull();
     578                 : }
     579                 : 
     580                 : bool
     581             153 : ScriptedProxyHandler::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
     582                 :                                             PropertyDescriptor *desc)
     583                 : {
     584             153 :     JSObject *handler = GetProxyHandlerObject(cx, proxy);
     585             306 :     AutoValueRooter tvr(cx);
     586             153 :     return GetFundamentalTrap(cx, handler, ATOM(getPropertyDescriptor), tvr.addr()) &&
     587             144 :            Trap1(cx, handler, tvr.value(), id, tvr.addr()) &&
     588              36 :            ((tvr.value().isUndefined() && IndicatePropertyNotFound(cx, desc)) ||
     589               0 :             (ReturnedValueMustNotBePrimitive(cx, proxy, ATOM(getPropertyDescriptor), tvr.value()) &&
     590             333 :              ParsePropertyDescriptorObject(cx, proxy, id, tvr.value(), desc)));
     591                 : }
     592                 : 
     593                 : bool
     594             765 : ScriptedProxyHandler::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
     595                 :                                                PropertyDescriptor *desc)
     596                 : {
     597             765 :     JSObject *handler = GetProxyHandlerObject(cx, proxy);
     598            1530 :     AutoValueRooter tvr(cx);
     599             765 :     return GetFundamentalTrap(cx, handler, ATOM(getOwnPropertyDescriptor), tvr.addr()) &&
     600             765 :            Trap1(cx, handler, tvr.value(), id, tvr.addr()) &&
     601             765 :            ((tvr.value().isUndefined() && IndicatePropertyNotFound(cx, desc)) ||
     602             765 :             (ReturnedValueMustNotBePrimitive(cx, proxy, ATOM(getPropertyDescriptor), tvr.value()) &&
     603            3060 :              ParsePropertyDescriptorObject(cx, proxy, id, tvr.value(), desc)));
     604                 : }
     605                 : 
     606                 : bool
     607            1757 : ScriptedProxyHandler::defineProperty(JSContext *cx, JSObject *proxy, jsid id,
     608                 :                                      PropertyDescriptor *desc)
     609                 : {
     610            1757 :     JSObject *handler = GetProxyHandlerObject(cx, proxy);
     611            3514 :     AutoValueRooter tvr(cx);
     612            3514 :     AutoValueRooter fval(cx);
     613            1757 :     return GetFundamentalTrap(cx, handler, ATOM(defineProperty), fval.addr()) &&
     614            1757 :            NewPropertyDescriptorObject(cx, desc, tvr.addr()) &&
     615            3514 :            Trap2(cx, handler, fval.value(), id, tvr.value(), tvr.addr());
     616                 : }
     617                 : 
     618                 : bool
     619               9 : ScriptedProxyHandler::getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props)
     620                 : {
     621               9 :     JSObject *handler = GetProxyHandlerObject(cx, proxy);
     622              18 :     AutoValueRooter tvr(cx);
     623               9 :     return GetFundamentalTrap(cx, handler, ATOM(getOwnPropertyNames), tvr.addr()) &&
     624               9 :            Trap(cx, handler, tvr.value(), 0, NULL, tvr.addr()) &&
     625              18 :            ArrayToIdVector(cx, tvr.value(), props);
     626                 : }
     627                 : 
     628                 : bool
     629              81 : ScriptedProxyHandler::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
     630                 : {
     631              81 :     JSObject *handler = GetProxyHandlerObject(cx, proxy);
     632             162 :     AutoValueRooter tvr(cx);
     633              81 :     return GetFundamentalTrap(cx, handler, ATOM(delete), tvr.addr()) &&
     634              81 :            Trap1(cx, handler, tvr.value(), id, tvr.addr()) &&
     635             162 :            ValueToBool(cx, tvr.value(), bp);
     636                 : }
     637                 : 
     638                 : bool
     639               0 : ScriptedProxyHandler::enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props)
     640                 : {
     641               0 :     JSObject *handler = GetProxyHandlerObject(cx, proxy);
     642               0 :     AutoValueRooter tvr(cx);
     643               0 :     return GetFundamentalTrap(cx, handler, ATOM(enumerate), tvr.addr()) &&
     644               0 :            Trap(cx, handler, tvr.value(), 0, NULL, tvr.addr()) &&
     645               0 :            ArrayToIdVector(cx, tvr.value(), props);
     646                 : }
     647                 : 
     648                 : bool
     649              36 : ScriptedProxyHandler::fix(JSContext *cx, JSObject *proxy, Value *vp)
     650                 : {
     651              36 :     JSObject *handler = GetProxyHandlerObject(cx, proxy);
     652              36 :     return GetFundamentalTrap(cx, handler, ATOM(fix), vp) &&
     653              36 :            Trap(cx, handler, *vp, 0, NULL, vp);
     654                 : }
     655                 : 
     656                 : bool
     657             733 : ScriptedProxyHandler::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
     658                 : {
     659             733 :     JSObject *handler = GetProxyHandlerObject(cx, proxy);
     660            1466 :     AutoValueRooter tvr(cx);
     661             733 :     if (!GetDerivedTrap(cx, handler, ATOM(has), tvr.addr()))
     662               0 :         return false;
     663             733 :     if (!js_IsCallable(tvr.value()))
     664               0 :         return ProxyHandler::has(cx, proxy, id, bp);
     665             733 :     return Trap1(cx, handler, tvr.value(), id, tvr.addr()) &&
     666             733 :            ValueToBool(cx, tvr.value(), bp);
     667                 : }
     668                 : 
     669                 : bool
     670               0 : ScriptedProxyHandler::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
     671                 : {
     672               0 :     JSObject *handler = GetProxyHandlerObject(cx, proxy);
     673               0 :     AutoValueRooter tvr(cx);
     674               0 :     if (!GetDerivedTrap(cx, handler, ATOM(hasOwn), tvr.addr()))
     675               0 :         return false;
     676               0 :     if (!js_IsCallable(tvr.value()))
     677               0 :         return ProxyHandler::hasOwn(cx, proxy, id, bp);
     678               0 :     return Trap1(cx, handler, tvr.value(), id, tvr.addr()) &&
     679               0 :            ValueToBool(cx, tvr.value(), bp);
     680                 : }
     681                 : 
     682                 : bool
     683            1885 : ScriptedProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp)
     684                 : {
     685            1885 :     JSObject *handler = GetProxyHandlerObject(cx, proxy);
     686            1885 :     JSString *str = ToString(cx, IdToValue(id));
     687            1885 :     if (!str)
     688               0 :         return false;
     689            3770 :     AutoValueRooter tvr(cx, StringValue(str));
     690            1885 :     Value argv[] = { ObjectOrNullValue(receiver), tvr.value() };
     691            3770 :     AutoValueRooter fval(cx);
     692            1885 :     if (!GetDerivedTrap(cx, handler, ATOM(get), fval.addr()))
     693               0 :         return false;
     694            1885 :     if (!js_IsCallable(fval.value()))
     695             153 :         return ProxyHandler::get(cx, proxy, receiver, id, vp);
     696            1732 :     return Trap(cx, handler, fval.value(), 2, argv, vp);
     697                 : }
     698                 : 
     699                 : bool
     700            1098 : ScriptedProxyHandler::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, bool strict,
     701                 :                           Value *vp)
     702                 : {
     703            1098 :     JSObject *handler = GetProxyHandlerObject(cx, proxy);
     704            1098 :     JSString *str = ToString(cx, IdToValue(id));
     705            1098 :     if (!str)
     706               0 :         return false;
     707            2196 :     AutoValueRooter tvr(cx, StringValue(str));
     708            1098 :     Value argv[] = { ObjectOrNullValue(receiver), tvr.value(), *vp };
     709            2196 :     AutoValueRooter fval(cx);
     710            1098 :     if (!GetDerivedTrap(cx, handler, ATOM(set), fval.addr()))
     711               0 :         return false;
     712            1098 :     if (!js_IsCallable(fval.value()))
     713             756 :         return ProxyHandler::set(cx, proxy, receiver, id, strict, vp);
     714             342 :     return Trap(cx, handler, fval.value(), 3, argv, tvr.addr());
     715                 : }
     716                 : 
     717                 : bool
     718               0 : ScriptedProxyHandler::keys(JSContext *cx, JSObject *proxy, AutoIdVector &props)
     719                 : {
     720               0 :     JSObject *handler = GetProxyHandlerObject(cx, proxy);
     721               0 :     AutoValueRooter tvr(cx);
     722               0 :     if (!GetDerivedTrap(cx, handler, ATOM(keys), tvr.addr()))
     723               0 :         return false;
     724               0 :     if (!js_IsCallable(tvr.value()))
     725               0 :         return ProxyHandler::keys(cx, proxy, props);
     726               0 :     return Trap(cx, handler, tvr.value(), 0, NULL, tvr.addr()) &&
     727               0 :            ArrayToIdVector(cx, tvr.value(), props);
     728                 : }
     729                 : 
     730                 : bool
     731              45 : ScriptedProxyHandler::iterate(JSContext *cx, JSObject *proxy, unsigned flags, Value *vp)
     732                 : {
     733              45 :     JSObject *handler = GetProxyHandlerObject(cx, proxy);
     734              90 :     AutoValueRooter tvr(cx);
     735              45 :     if (!GetDerivedTrap(cx, handler, ATOM(iterate), tvr.addr()))
     736               0 :         return false;
     737              45 :     if (!js_IsCallable(tvr.value()))
     738               0 :         return ProxyHandler::iterate(cx, proxy, flags, vp);
     739              45 :     return Trap(cx, handler, tvr.value(), 0, NULL, vp) &&
     740              45 :            ReturnedValueMustNotBePrimitive(cx, proxy, ATOM(iterate), *vp);
     741                 : }
     742                 : 
     743           18667 : ScriptedProxyHandler ScriptedProxyHandler::singleton;
     744                 : 
     745                 : class AutoPendingProxyOperation {
     746                 :     JSRuntime               *rt;
     747                 :     PendingProxyOperation   op;
     748                 :   public:
     749          154371 :     AutoPendingProxyOperation(JSContext *cx, JSObject *proxy) : rt(cx->runtime) {
     750          154371 :         op.next = rt->pendingProxyOperation;
     751          154371 :         op.object = proxy;
     752          154371 :         rt->pendingProxyOperation = &op;
     753          154371 :     }
     754                 : 
     755          154371 :     ~AutoPendingProxyOperation() {
     756          154371 :         JS_ASSERT(rt->pendingProxyOperation == &op);
     757          154371 :         rt->pendingProxyOperation = op.next;
     758          154371 :     }
     759                 : };
     760                 : 
     761                 : bool
     762               0 : Proxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
     763                 :                              PropertyDescriptor *desc)
     764                 : {
     765               0 :     JS_CHECK_RECURSION(cx, return false);
     766               0 :     AutoPendingProxyOperation pending(cx, proxy);
     767               0 :     return GetProxyHandler(proxy)->getPropertyDescriptor(cx, proxy, id, set, desc);
     768                 : }
     769                 : 
     770                 : bool
     771               0 : Proxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set, Value *vp)
     772                 : {
     773               0 :     JS_CHECK_RECURSION(cx, return false);
     774               0 :     AutoPendingProxyOperation pending(cx, proxy);
     775               0 :     AutoPropertyDescriptorRooter desc(cx);
     776               0 :     return Proxy::getPropertyDescriptor(cx, proxy, id, set, &desc) &&
     777               0 :            NewPropertyDescriptorObject(cx, &desc, vp);
     778                 : }
     779                 : 
     780                 : bool
     781              45 : Proxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
     782                 :                                 PropertyDescriptor *desc)
     783                 : {
     784              45 :     JS_CHECK_RECURSION(cx, return false);
     785              90 :     AutoPendingProxyOperation pending(cx, proxy);
     786              45 :     return GetProxyHandler(proxy)->getOwnPropertyDescriptor(cx, proxy, id, set, desc);
     787                 : }
     788                 : 
     789                 : bool
     790               0 : Proxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set, Value *vp)
     791                 : {
     792               0 :     JS_CHECK_RECURSION(cx, return false);
     793               0 :     AutoPendingProxyOperation pending(cx, proxy);
     794               0 :     AutoPropertyDescriptorRooter desc(cx);
     795               0 :     return Proxy::getOwnPropertyDescriptor(cx, proxy, id, set, &desc) &&
     796               0 :            NewPropertyDescriptorObject(cx, &desc, vp);
     797                 : }
     798                 : 
     799                 : bool
     800            1793 : Proxy::defineProperty(JSContext *cx, JSObject *proxy, jsid id, PropertyDescriptor *desc)
     801                 : {
     802            1793 :     JS_CHECK_RECURSION(cx, return false);
     803            3586 :     AutoPendingProxyOperation pending(cx, proxy);
     804            1793 :     return GetProxyHandler(proxy)->defineProperty(cx, proxy, id, desc);
     805                 : }
     806                 : 
     807                 : bool
     808            1799 : Proxy::defineProperty(JSContext *cx, JSObject *proxy, jsid id, const Value &v)
     809                 : {
     810            1799 :     JS_CHECK_RECURSION(cx, return false);
     811            3586 :     AutoPendingProxyOperation pending(cx, proxy);
     812            3586 :     AutoPropertyDescriptorRooter desc(cx);
     813            1793 :     return ParsePropertyDescriptorObject(cx, proxy, id, v, &desc) &&
     814            1793 :            Proxy::defineProperty(cx, proxy, id, &desc);
     815                 : }
     816                 : 
     817                 : bool
     818               9 : Proxy::getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props)
     819                 : {
     820               9 :     JS_CHECK_RECURSION(cx, return false);
     821              18 :     AutoPendingProxyOperation pending(cx, proxy);
     822               9 :     return GetProxyHandler(proxy)->getOwnPropertyNames(cx, proxy, props);
     823                 : }
     824                 : 
     825                 : bool
     826              90 : Proxy::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
     827                 : {
     828              90 :     JS_CHECK_RECURSION(cx, return false);
     829             180 :     AutoPendingProxyOperation pending(cx, proxy);
     830              90 :     return GetProxyHandler(proxy)->delete_(cx, proxy, id, bp);
     831                 : }
     832                 : 
     833                 : bool
     834               0 : Proxy::enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props)
     835                 : {
     836               0 :     JS_CHECK_RECURSION(cx, return false);
     837               0 :     AutoPendingProxyOperation pending(cx, proxy);
     838               0 :     return GetProxyHandler(proxy)->enumerate(cx, proxy, props);
     839                 : }
     840                 : 
     841                 : bool
     842              36 : Proxy::fix(JSContext *cx, JSObject *proxy, Value *vp)
     843                 : {
     844              36 :     JS_CHECK_RECURSION(cx, return false);
     845              72 :     AutoPendingProxyOperation pending(cx, proxy);
     846              36 :     return GetProxyHandler(proxy)->fix(cx, proxy, vp);
     847                 : }
     848                 : 
     849                 : bool
     850           23971 : Proxy::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
     851                 : {
     852           23971 :     JS_CHECK_RECURSION(cx, return false);
     853           47942 :     AutoPendingProxyOperation pending(cx, proxy);
     854           23971 :     return GetProxyHandler(proxy)->has(cx, proxy, id, bp);
     855                 : }
     856                 : 
     857                 : bool
     858               0 : Proxy::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
     859                 : {
     860               0 :     JS_CHECK_RECURSION(cx, return false);
     861               0 :     AutoPendingProxyOperation pending(cx, proxy);
     862               0 :     return GetProxyHandler(proxy)->hasOwn(cx, proxy, id, bp);
     863                 : }
     864                 : 
     865                 : bool
     866           56640 : Proxy::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp)
     867                 : {
     868           56640 :     JS_CHECK_RECURSION(cx, return false);
     869          113280 :     AutoPendingProxyOperation pending(cx, proxy);
     870           56640 :     return GetProxyHandler(proxy)->get(cx, proxy, receiver, id, vp);
     871                 : }
     872                 : 
     873                 : bool
     874             513 : Proxy::getElementIfPresent(JSContext *cx, JSObject *proxy, JSObject *receiver, uint32_t index,
     875                 :                            Value *vp, bool *present)
     876                 : {
     877             513 :     JS_CHECK_RECURSION(cx, return false);
     878            1026 :     AutoPendingProxyOperation pending(cx, proxy);
     879             513 :     return GetProxyHandler(proxy)->getElementIfPresent(cx, proxy, receiver, index, vp, present);
     880                 : }
     881                 : 
     882                 : bool
     883           17888 : Proxy::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, bool strict, Value *vp)
     884                 : {
     885           17888 :     JS_CHECK_RECURSION(cx, return false);
     886           35776 :     AutoPendingProxyOperation pending(cx, proxy);
     887           17888 :     return GetProxyHandler(proxy)->set(cx, proxy, receiver, id, strict, vp);
     888                 : }
     889                 : 
     890                 : bool
     891           22419 : Proxy::keys(JSContext *cx, JSObject *proxy, AutoIdVector &props)
     892                 : {
     893           22419 :     JS_CHECK_RECURSION(cx, return false);
     894           44838 :     AutoPendingProxyOperation pending(cx, proxy);
     895           22419 :     return GetProxyHandler(proxy)->keys(cx, proxy, props);
     896                 : }
     897                 : 
     898                 : bool
     899              90 : Proxy::iterate(JSContext *cx, JSObject *proxy, unsigned flags, Value *vp)
     900                 : {
     901              90 :     JS_CHECK_RECURSION(cx, return false);
     902             180 :     AutoPendingProxyOperation pending(cx, proxy);
     903              90 :     return GetProxyHandler(proxy)->iterate(cx, proxy, flags, vp);
     904                 : }
     905                 : 
     906                 : bool
     907           20910 : Proxy::call(JSContext *cx, JSObject *proxy, unsigned argc, Value *vp)
     908                 : {
     909           20910 :     JS_CHECK_RECURSION(cx, return false);
     910           41804 :     AutoPendingProxyOperation pending(cx, proxy);
     911           20902 :     return GetProxyHandler(proxy)->call(cx, proxy, argc, vp);
     912                 : }
     913                 : 
     914                 : bool
     915             189 : Proxy::construct(JSContext *cx, JSObject *proxy, unsigned argc, Value *argv, Value *rval)
     916                 : {
     917             189 :     JS_CHECK_RECURSION(cx, return false);
     918             378 :     AutoPendingProxyOperation pending(cx, proxy);
     919             189 :     return GetProxyHandler(proxy)->construct(cx, proxy, argc, argv, rval);
     920                 : }
     921                 : 
     922                 : bool
     923            4500 : Proxy::nativeCall(JSContext *cx, JSObject *proxy, Class *clasp, Native native, CallArgs args)
     924                 : {
     925            4500 :     JS_CHECK_RECURSION(cx, return false);
     926            9000 :     AutoPendingProxyOperation pending(cx, proxy);
     927            4500 :     return GetProxyHandler(proxy)->nativeCall(cx, proxy, clasp, native, args);
     928                 : }
     929                 : 
     930                 : bool
     931               0 : Proxy::hasInstance(JSContext *cx, JSObject *proxy, const js::Value *vp, bool *bp)
     932                 : {
     933               0 :     JS_CHECK_RECURSION(cx, return false);
     934               0 :     AutoPendingProxyOperation pending(cx, proxy);
     935               0 :     return GetProxyHandler(proxy)->hasInstance(cx, proxy, vp, bp);
     936                 : }
     937                 : 
     938                 : JSType
     939             234 : Proxy::typeOf(JSContext *cx, JSObject *proxy)
     940                 : {
     941                 :     // FIXME: API doesn't allow us to report error (bug 618906).
     942             234 :     JS_CHECK_RECURSION(cx, return JSTYPE_OBJECT);
     943             468 :     AutoPendingProxyOperation pending(cx, proxy);
     944             234 :     return GetProxyHandler(proxy)->typeOf(cx, proxy);
     945                 : }
     946                 : 
     947                 : bool
     948             594 : Proxy::objectClassIs(JSObject *proxy, ESClassValue classValue, JSContext *cx)
     949                 : {
     950            1188 :     AutoPendingProxyOperation pending(cx, proxy);
     951             594 :     return GetProxyHandler(proxy)->objectClassIs(proxy, classValue, cx);
     952                 : }
     953                 : 
     954                 : JSString *
     955            1944 : Proxy::obj_toString(JSContext *cx, JSObject *proxy)
     956                 : {
     957            1944 :     JS_CHECK_RECURSION(cx, return NULL);
     958            3888 :     AutoPendingProxyOperation pending(cx, proxy);
     959            1944 :     return GetProxyHandler(proxy)->obj_toString(cx, proxy);
     960                 : }
     961                 : 
     962                 : JSString *
     963               9 : Proxy::fun_toString(JSContext *cx, JSObject *proxy, unsigned indent)
     964                 : {
     965               9 :     JS_CHECK_RECURSION(cx, return NULL);
     966              18 :     AutoPendingProxyOperation pending(cx, proxy);
     967               9 :     return GetProxyHandler(proxy)->fun_toString(cx, proxy, indent);
     968                 : }
     969                 : 
     970                 : bool
     971              54 : Proxy::regexp_toShared(JSContext *cx, JSObject *proxy, RegExpGuard *g)
     972                 : {
     973              54 :     JS_CHECK_RECURSION(cx, return NULL);
     974             108 :     AutoPendingProxyOperation pending(cx, proxy);
     975              54 :     return GetProxyHandler(proxy)->regexp_toShared(cx, proxy, g);
     976                 : }
     977                 : 
     978                 : bool
     979             568 : Proxy::defaultValue(JSContext *cx, JSObject *proxy, JSType hint, Value *vp)
     980                 : {
     981             568 :     JS_CHECK_RECURSION(cx, return NULL);
     982            1136 :     AutoPendingProxyOperation pending(cx, proxy);
     983             568 :     return GetProxyHandler(proxy)->defaultValue(cx, proxy, hint, vp);
     984                 : }
     985                 : 
     986                 : bool
     987              54 : Proxy::iteratorNext(JSContext *cx, JSObject *proxy, Value *vp)
     988                 : {
     989              54 :     JS_CHECK_RECURSION(cx, return NULL);
     990             108 :     AutoPendingProxyOperation pending(cx, proxy);
     991              54 :     return GetProxyHandler(proxy)->iteratorNext(cx, proxy, vp);
     992                 : }
     993                 : 
     994                 : static JSObject *
     995               0 : proxy_innerObject(JSContext *cx, JSObject *obj)
     996                 : {
     997               0 :     return GetProxyPrivate(obj).toObjectOrNull();
     998                 : }
     999                 : 
    1000                 : static JSBool
    1001           23971 : proxy_LookupGeneric(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
    1002                 :                     JSProperty **propp)
    1003                 : {
    1004           23971 :     id = js_CheckForStringIndex(id);
    1005                 : 
    1006                 :     bool found;
    1007           23971 :     if (!Proxy::has(cx, obj, id, &found))
    1008               9 :         return false;
    1009                 : 
    1010           23962 :     if (found) {
    1011           23805 :         *propp = (JSProperty *)0x1;
    1012           23805 :         *objp = obj;
    1013                 :     } else {
    1014             157 :         *objp = NULL;
    1015             157 :         *propp = NULL;
    1016                 :     }
    1017           23962 :     return true;
    1018                 : }
    1019                 : 
    1020                 : static JSBool
    1021               0 : proxy_LookupProperty(JSContext *cx, JSObject *obj, PropertyName *name, JSObject **objp,
    1022                 :                      JSProperty **propp)
    1023                 : {
    1024               0 :     return proxy_LookupGeneric(cx, obj, ATOM_TO_JSID(name), objp, propp);
    1025                 : }
    1026                 : 
    1027                 : static JSBool
    1028               0 : proxy_LookupElement(JSContext *cx, JSObject *obj, uint32_t index, JSObject **objp,
    1029                 :                     JSProperty **propp)
    1030                 : {
    1031                 :     jsid id;
    1032               0 :     if (!IndexToId(cx, index, &id))
    1033               0 :         return false;
    1034               0 :     return proxy_LookupGeneric(cx, obj, id, objp, propp);
    1035                 : }
    1036                 : 
    1037                 : static JSBool
    1038               0 : proxy_LookupSpecial(JSContext *cx, JSObject *obj, SpecialId sid, JSObject **objp, JSProperty **propp)
    1039                 : {
    1040               0 :     return proxy_LookupGeneric(cx, obj, SPECIALID_TO_JSID(sid), objp, propp);
    1041                 : }
    1042                 : 
    1043                 : static JSBool
    1044               0 : proxy_DefineGeneric(JSContext *cx, JSObject *obj, jsid id, const Value *value,
    1045                 :                     PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
    1046                 : {
    1047               0 :     id = js_CheckForStringIndex(id);
    1048                 : 
    1049               0 :     AutoPropertyDescriptorRooter desc(cx);
    1050               0 :     desc.obj = obj;
    1051               0 :     desc.value = *value;
    1052               0 :     desc.attrs = (attrs & (~JSPROP_SHORTID));
    1053               0 :     desc.getter = getter;
    1054               0 :     desc.setter = setter;
    1055               0 :     desc.shortid = 0;
    1056               0 :     return Proxy::defineProperty(cx, obj, id, &desc);
    1057                 : }
    1058                 : 
    1059                 : static JSBool
    1060               0 : proxy_DefineProperty(JSContext *cx, JSObject *obj, PropertyName *name, const Value *value,
    1061                 :                      PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
    1062                 : {
    1063               0 :     return proxy_DefineGeneric(cx, obj, ATOM_TO_JSID(name), value, getter, setter, attrs);
    1064                 : }
    1065                 : 
    1066                 : static JSBool
    1067               0 : proxy_DefineElement(JSContext *cx, JSObject *obj, uint32_t index, const Value *value,
    1068                 :                     PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
    1069                 : {
    1070                 :     jsid id;
    1071               0 :     if (!IndexToId(cx, index, &id))
    1072               0 :         return false;
    1073               0 :     return proxy_DefineGeneric(cx, obj, id, value, getter, setter, attrs);
    1074                 : }
    1075                 : 
    1076                 : static JSBool
    1077               0 : proxy_DefineSpecial(JSContext *cx, JSObject *obj, SpecialId sid, const Value *value,
    1078                 :                     PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
    1079                 : {
    1080               0 :     return proxy_DefineGeneric(cx, obj, SPECIALID_TO_JSID(sid), value, getter, setter, attrs);
    1081                 : }
    1082                 : 
    1083                 : static JSBool
    1084           56582 : proxy_GetGeneric(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, Value *vp)
    1085                 : {
    1086           56582 :     id = js_CheckForStringIndex(id);
    1087                 : 
    1088           56582 :     return Proxy::get(cx, obj, receiver, id, vp);
    1089                 : }
    1090                 : 
    1091                 : static JSBool
    1092               0 : proxy_GetProperty(JSContext *cx, JSObject *obj, JSObject *receiver, PropertyName *name, Value *vp)
    1093                 : {
    1094               0 :     return proxy_GetGeneric(cx, obj, receiver, ATOM_TO_JSID(name), vp);
    1095                 : }
    1096                 : 
    1097                 : static JSBool
    1098             285 : proxy_GetElement(JSContext *cx, JSObject *obj, JSObject *receiver, uint32_t index, Value *vp)
    1099                 : {
    1100                 :     jsid id;
    1101             285 :     if (!IndexToId(cx, index, &id))
    1102               0 :         return false;
    1103             285 :     return proxy_GetGeneric(cx, obj, receiver, id, vp);
    1104                 : }
    1105                 : 
    1106                 : static JSBool
    1107             513 : proxy_GetElementIfPresent(JSContext *cx, JSObject *obj, JSObject *receiver, uint32_t index,
    1108                 :                           Value *vp, bool *present)
    1109                 : {
    1110             513 :     return Proxy::getElementIfPresent(cx, obj, receiver, index, vp, present);
    1111                 : }
    1112                 : 
    1113                 : static JSBool
    1114               0 : proxy_GetSpecial(JSContext *cx, JSObject *obj, JSObject *receiver, SpecialId sid, Value *vp)
    1115                 : {
    1116               0 :     return proxy_GetGeneric(cx, obj, receiver, SPECIALID_TO_JSID(sid), vp);
    1117                 : }
    1118                 : 
    1119                 : static JSBool
    1120           17888 : proxy_SetGeneric(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
    1121                 : {
    1122           17888 :     id = js_CheckForStringIndex(id);
    1123                 : 
    1124           17888 :     return Proxy::set(cx, obj, obj, id, strict, vp);
    1125                 : }
    1126                 : 
    1127                 : static JSBool
    1128               0 : proxy_SetProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *vp, JSBool strict)
    1129                 : {
    1130               0 :     return proxy_SetGeneric(cx, obj, ATOM_TO_JSID(name), vp, strict);
    1131                 : }
    1132                 : 
    1133                 : static JSBool
    1134               0 : proxy_SetElement(JSContext *cx, JSObject *obj, uint32_t index, Value *vp, JSBool strict)
    1135                 : {
    1136                 :     jsid id;
    1137               0 :     if (!IndexToId(cx, index, &id))
    1138               0 :         return false;
    1139               0 :     return proxy_SetGeneric(cx, obj, id, vp, strict);
    1140                 : }
    1141                 : 
    1142                 : static JSBool
    1143               0 : proxy_SetSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *vp, JSBool strict)
    1144                 : {
    1145               0 :     return proxy_SetGeneric(cx, obj, SPECIALID_TO_JSID(sid), vp, strict);
    1146                 : }
    1147                 : 
    1148                 : static JSBool
    1149               0 : proxy_GetGenericAttributes(JSContext *cx, JSObject *obj, jsid id, unsigned *attrsp)
    1150                 : {
    1151               0 :     id = js_CheckForStringIndex(id);
    1152                 : 
    1153               0 :     AutoPropertyDescriptorRooter desc(cx);
    1154               0 :     if (!Proxy::getOwnPropertyDescriptor(cx, obj, id, false, &desc))
    1155               0 :         return false;
    1156               0 :     *attrsp = desc.attrs;
    1157               0 :     return true;
    1158                 : }
    1159                 : 
    1160                 : static JSBool
    1161               0 : proxy_GetPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, unsigned *attrsp)
    1162                 : {
    1163               0 :     return proxy_GetGenericAttributes(cx, obj, ATOM_TO_JSID(name), attrsp);
    1164                 : }
    1165                 : 
    1166                 : static JSBool
    1167               0 : proxy_GetElementAttributes(JSContext *cx, JSObject *obj, uint32_t index, unsigned *attrsp)
    1168                 : {
    1169                 :     jsid id;
    1170               0 :     if (!IndexToId(cx, index, &id))
    1171               0 :         return false;
    1172               0 :     return proxy_GetGenericAttributes(cx, obj, id, attrsp);
    1173                 : }
    1174                 : 
    1175                 : static JSBool
    1176               0 : proxy_GetSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, unsigned *attrsp)
    1177                 : {
    1178               0 :     return proxy_GetGenericAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp);
    1179                 : }
    1180                 : 
    1181                 : static JSBool
    1182               0 : proxy_SetGenericAttributes(JSContext *cx, JSObject *obj, jsid id, unsigned *attrsp)
    1183                 : {
    1184               0 :     id = js_CheckForStringIndex(id);
    1185                 : 
    1186                 :     /* Lookup the current property descriptor so we have setter/getter/value. */
    1187               0 :     AutoPropertyDescriptorRooter desc(cx);
    1188               0 :     if (!Proxy::getOwnPropertyDescriptor(cx, obj, id, true, &desc))
    1189               0 :         return false;
    1190               0 :     desc.attrs = (*attrsp & (~JSPROP_SHORTID));
    1191               0 :     return Proxy::defineProperty(cx, obj, id, &desc);
    1192                 : }
    1193                 : 
    1194                 : static JSBool
    1195               0 : proxy_SetPropertyAttributes(JSContext *cx, JSObject *obj, PropertyName *name, unsigned *attrsp)
    1196                 : {
    1197               0 :     return proxy_SetGenericAttributes(cx, obj, ATOM_TO_JSID(name), attrsp);
    1198                 : }
    1199                 : 
    1200                 : static JSBool
    1201               0 : proxy_SetElementAttributes(JSContext *cx, JSObject *obj, uint32_t index, unsigned *attrsp)
    1202                 : {
    1203                 :     jsid id;
    1204               0 :     if (!IndexToId(cx, index, &id))
    1205               0 :         return false;
    1206               0 :     return proxy_SetGenericAttributes(cx, obj, id, attrsp);
    1207                 : }
    1208                 : 
    1209                 : static JSBool
    1210               0 : proxy_SetSpecialAttributes(JSContext *cx, JSObject *obj, SpecialId sid, unsigned *attrsp)
    1211                 : {
    1212               0 :     return proxy_SetGenericAttributes(cx, obj, SPECIALID_TO_JSID(sid), attrsp);
    1213                 : }
    1214                 : 
    1215                 : static JSBool
    1216              90 : proxy_DeleteGeneric(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
    1217                 : {
    1218              90 :     JS_ASSERT(id == js_CheckForStringIndex(id));
    1219                 : 
    1220                 :     // TODO: throwing away strict
    1221                 :     bool deleted;
    1222              90 :     if (!Proxy::delete_(cx, obj, id, &deleted) || !js_SuppressDeletedProperty(cx, obj, id))
    1223              36 :         return false;
    1224              54 :     rval->setBoolean(deleted);
    1225              54 :     return true;
    1226                 : }
    1227                 : 
    1228                 : static JSBool
    1229              27 : proxy_DeleteProperty(JSContext *cx, JSObject *obj, PropertyName *name, Value *rval, JSBool strict)
    1230                 : {
    1231              27 :     return proxy_DeleteGeneric(cx, obj, js_CheckForStringIndex(ATOM_TO_JSID(name)), rval, strict);
    1232                 : }
    1233                 : 
    1234                 : static JSBool
    1235              63 : proxy_DeleteElement(JSContext *cx, JSObject *obj, uint32_t index, Value *rval, JSBool strict)
    1236                 : {
    1237                 :     jsid id;
    1238              63 :     if (!IndexToId(cx, index, &id))
    1239               0 :         return false;
    1240              63 :     return proxy_DeleteGeneric(cx, obj, id, rval, strict);
    1241                 : }
    1242                 : 
    1243                 : static JSBool
    1244               0 : proxy_DeleteSpecial(JSContext *cx, JSObject *obj, SpecialId sid, Value *rval, JSBool strict)
    1245                 : {
    1246               0 :     return proxy_DeleteGeneric(cx, obj, SPECIALID_TO_JSID(sid), rval, strict);
    1247                 : }
    1248                 : 
    1249                 : static void
    1250           36746 : proxy_TraceObject(JSTracer *trc, JSObject *obj)
    1251                 : {
    1252           36746 :     GetProxyHandler(obj)->trace(trc, obj);
    1253           36746 :     MarkCrossCompartmentSlot(trc, &obj->getReservedSlotRef(JSSLOT_PROXY_PRIVATE), "private");
    1254           36746 :     MarkCrossCompartmentSlot(trc, &obj->getReservedSlotRef(JSSLOT_PROXY_EXTRA + 0), "extra0");
    1255           36746 :     MarkCrossCompartmentSlot(trc, &obj->getReservedSlotRef(JSSLOT_PROXY_EXTRA + 1), "extra1");
    1256           36746 : }
    1257                 : 
    1258                 : static void
    1259           12492 : proxy_TraceFunction(JSTracer *trc, JSObject *obj)
    1260                 : {
    1261           12492 :     MarkCrossCompartmentSlot(trc, &GetCall(obj), "call");
    1262           12492 :     MarkCrossCompartmentSlot(trc, &GetFunctionProxyConstruct(obj), "construct");
    1263           12492 :     proxy_TraceObject(trc, obj);
    1264           12492 : }
    1265                 : 
    1266                 : static JSBool
    1267             568 : proxy_Convert(JSContext *cx, JSObject *proxy, JSType hint, Value *vp)
    1268                 : {
    1269             568 :     JS_ASSERT(proxy->isProxy());
    1270             568 :     return Proxy::defaultValue(cx, proxy, hint, vp);
    1271                 : }
    1272                 : 
    1273                 : static JSBool
    1274              27 : proxy_Fix(JSContext *cx, JSObject *obj, bool *fixed, AutoIdVector *props)
    1275                 : {
    1276              27 :     JS_ASSERT(obj->isProxy());
    1277                 :     JSBool isFixed;
    1278              27 :     bool ok = FixProxy(cx, obj, &isFixed);
    1279              27 :     if (ok) {
    1280              27 :         *fixed = isFixed;
    1281              27 :         return GetPropertyNames(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN, props);
    1282                 :     }
    1283               0 :     return false;
    1284                 : }
    1285                 : 
    1286                 : static void
    1287           18687 : proxy_Finalize(FreeOp *fop, JSObject *obj)
    1288                 : {
    1289           18687 :     JS_ASSERT(obj->isProxy());
    1290           18687 :     if (!obj->getSlot(JSSLOT_PROXY_HANDLER).isUndefined())
    1291           18687 :         GetProxyHandler(obj)->finalize(fop, obj);
    1292           18687 : }
    1293                 : 
    1294                 : static JSBool
    1295               0 : proxy_HasInstance(JSContext *cx, JSObject *proxy, const Value *v, JSBool *bp)
    1296                 : {
    1297               0 :     AutoPendingProxyOperation pending(cx, proxy);
    1298                 :     bool b;
    1299               0 :     if (!Proxy::hasInstance(cx, proxy, v, &b))
    1300               0 :         return false;
    1301               0 :     *bp = !!b;
    1302               0 :     return true;
    1303                 : }
    1304                 : 
    1305                 : static JSType
    1306             234 : proxy_TypeOf(JSContext *cx, JSObject *proxy)
    1307                 : {
    1308             234 :     JS_ASSERT(proxy->isProxy());
    1309             234 :     return Proxy::typeOf(cx, proxy);
    1310                 : }
    1311                 : 
    1312                 : JS_FRIEND_DATA(Class) js::ObjectProxyClass = {
    1313                 :     "Proxy",
    1314                 :     Class::NON_NATIVE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(4),
    1315                 :     JS_PropertyStub,         /* addProperty */
    1316                 :     JS_PropertyStub,         /* delProperty */
    1317                 :     JS_PropertyStub,         /* getProperty */
    1318                 :     JS_StrictPropertyStub,   /* setProperty */
    1319                 :     JS_EnumerateStub,
    1320                 :     JS_ResolveStub,
    1321                 :     proxy_Convert,
    1322                 :     proxy_Finalize,          /* finalize    */
    1323                 :     NULL,                    /* checkAccess */
    1324                 :     NULL,                    /* call        */
    1325                 :     NULL,                    /* construct   */
    1326                 :     proxy_HasInstance,       /* hasInstance */
    1327                 :     proxy_TraceObject,       /* trace       */
    1328                 :     JS_NULL_CLASS_EXT,
    1329                 :     {
    1330                 :         proxy_LookupGeneric,
    1331                 :         proxy_LookupProperty,
    1332                 :         proxy_LookupElement,
    1333                 :         proxy_LookupSpecial,
    1334                 :         proxy_DefineGeneric,
    1335                 :         proxy_DefineProperty,
    1336                 :         proxy_DefineElement,
    1337                 :         proxy_DefineSpecial,
    1338                 :         proxy_GetGeneric,
    1339                 :         proxy_GetProperty,
    1340                 :         proxy_GetElement,
    1341                 :         proxy_GetElementIfPresent,
    1342                 :         proxy_GetSpecial,
    1343                 :         proxy_SetGeneric,
    1344                 :         proxy_SetProperty,
    1345                 :         proxy_SetElement,
    1346                 :         proxy_SetSpecial,
    1347                 :         proxy_GetGenericAttributes,
    1348                 :         proxy_GetPropertyAttributes,
    1349                 :         proxy_GetElementAttributes,
    1350                 :         proxy_GetSpecialAttributes,
    1351                 :         proxy_SetGenericAttributes,
    1352                 :         proxy_SetPropertyAttributes,
    1353                 :         proxy_SetElementAttributes,
    1354                 :         proxy_SetSpecialAttributes,
    1355                 :         proxy_DeleteProperty,
    1356                 :         proxy_DeleteElement,
    1357                 :         proxy_DeleteSpecial,
    1358                 :         NULL,                /* enumerate       */
    1359                 :         proxy_TypeOf,
    1360                 :         proxy_Fix,           /* fix             */
    1361                 :         NULL,                /* thisObject      */
    1362                 :         NULL,                /* clear           */
    1363                 :     }
    1364                 : };
    1365                 : 
    1366                 : JS_FRIEND_DATA(Class) js::OuterWindowProxyClass = {
    1367                 :     "Proxy",
    1368                 :     Class::NON_NATIVE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(4),
    1369                 :     JS_PropertyStub,         /* addProperty */
    1370                 :     JS_PropertyStub,         /* delProperty */
    1371                 :     JS_PropertyStub,         /* getProperty */
    1372                 :     JS_StrictPropertyStub,   /* setProperty */
    1373                 :     JS_EnumerateStub,
    1374                 :     JS_ResolveStub,
    1375                 :     JS_ConvertStub,
    1376                 :     proxy_Finalize,          /* finalize    */
    1377                 :     NULL,                    /* checkAccess */
    1378                 :     NULL,                    /* call        */
    1379                 :     NULL,                    /* construct   */
    1380                 :     NULL,                    /* hasInstance */
    1381                 :     proxy_TraceObject,       /* trace       */
    1382                 :     {
    1383                 :         NULL,                /* equality    */
    1384                 :         NULL,                /* outerObject */
    1385                 :         proxy_innerObject,
    1386                 :         NULL                 /* unused */
    1387                 :     },
    1388                 :     {
    1389                 :         proxy_LookupGeneric,
    1390                 :         proxy_LookupProperty,
    1391                 :         proxy_LookupElement,
    1392                 :         proxy_LookupSpecial,
    1393                 :         proxy_DefineGeneric,
    1394                 :         proxy_DefineProperty,
    1395                 :         proxy_DefineElement,
    1396                 :         proxy_DefineSpecial,
    1397                 :         proxy_GetGeneric,
    1398                 :         proxy_GetProperty,
    1399                 :         proxy_GetElement,
    1400                 :         proxy_GetElementIfPresent,
    1401                 :         proxy_GetSpecial,
    1402                 :         proxy_SetGeneric,
    1403                 :         proxy_SetProperty,
    1404                 :         proxy_SetElement,
    1405                 :         proxy_SetSpecial,
    1406                 :         proxy_GetGenericAttributes,
    1407                 :         proxy_GetPropertyAttributes,
    1408                 :         proxy_GetElementAttributes,
    1409                 :         proxy_GetSpecialAttributes,
    1410                 :         proxy_SetGenericAttributes,
    1411                 :         proxy_SetPropertyAttributes,
    1412                 :         proxy_SetElementAttributes,
    1413                 :         proxy_SetSpecialAttributes,
    1414                 :         proxy_DeleteProperty,
    1415                 :         proxy_DeleteElement,
    1416                 :         proxy_DeleteSpecial,
    1417                 :         NULL,                /* enumerate       */
    1418                 :         NULL,                /* typeof          */
    1419                 :         NULL,                /* fix             */
    1420                 :         NULL,                /* thisObject      */
    1421                 :         NULL,                /* clear           */
    1422                 :     }
    1423                 : };
    1424                 : 
    1425                 : static JSBool
    1426           20910 : proxy_Call(JSContext *cx, unsigned argc, Value *vp)
    1427                 : {
    1428           20910 :     JSObject *proxy = &JS_CALLEE(cx, vp).toObject();
    1429           20910 :     JS_ASSERT(proxy->isProxy());
    1430           20910 :     return Proxy::call(cx, proxy, argc, vp);
    1431                 : }
    1432                 : 
    1433                 : static JSBool
    1434             189 : proxy_Construct(JSContext *cx, unsigned argc, Value *vp)
    1435                 : {
    1436             189 :     JSObject *proxy = &JS_CALLEE(cx, vp).toObject();
    1437             189 :     JS_ASSERT(proxy->isProxy());
    1438             189 :     bool ok = Proxy::construct(cx, proxy, argc, JS_ARGV(cx, vp), vp);
    1439             189 :     return ok;
    1440                 : }
    1441                 : 
    1442                 : JS_FRIEND_DATA(Class) js::FunctionProxyClass = {
    1443                 :     "Proxy",
    1444                 :     Class::NON_NATIVE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(6),
    1445                 :     JS_PropertyStub,         /* addProperty */
    1446                 :     JS_PropertyStub,         /* delProperty */
    1447                 :     JS_PropertyStub,         /* getProperty */
    1448                 :     JS_StrictPropertyStub,   /* setProperty */
    1449                 :     JS_EnumerateStub,
    1450                 :     JS_ResolveStub,
    1451                 :     JS_ConvertStub,
    1452                 :     NULL,                    /* finalize */
    1453                 :     NULL,                    /* checkAccess */
    1454                 :     proxy_Call,
    1455                 :     proxy_Construct,
    1456                 :     FunctionClass.hasInstance,
    1457                 :     proxy_TraceFunction,     /* trace       */
    1458                 :     JS_NULL_CLASS_EXT,
    1459                 :     {
    1460                 :         proxy_LookupGeneric,
    1461                 :         proxy_LookupProperty,
    1462                 :         proxy_LookupElement,
    1463                 :         proxy_LookupSpecial,
    1464                 :         proxy_DefineGeneric,
    1465                 :         proxy_DefineProperty,
    1466                 :         proxy_DefineElement,
    1467                 :         proxy_DefineSpecial,
    1468                 :         proxy_GetGeneric,
    1469                 :         proxy_GetProperty,
    1470                 :         proxy_GetElement,
    1471                 :         proxy_GetElementIfPresent,
    1472                 :         proxy_GetSpecial,
    1473                 :         proxy_SetGeneric,
    1474                 :         proxy_SetProperty,
    1475                 :         proxy_SetElement,
    1476                 :         proxy_SetSpecial,
    1477                 :         proxy_GetGenericAttributes,
    1478                 :         proxy_GetPropertyAttributes,
    1479                 :         proxy_GetElementAttributes,
    1480                 :         proxy_GetSpecialAttributes,
    1481                 :         proxy_SetGenericAttributes,
    1482                 :         proxy_SetPropertyAttributes,
    1483                 :         proxy_SetElementAttributes,
    1484                 :         proxy_SetSpecialAttributes,
    1485                 :         proxy_DeleteProperty,
    1486                 :         proxy_DeleteElement,
    1487                 :         proxy_DeleteSpecial,
    1488                 :         NULL,                /* enumerate       */
    1489                 :         proxy_TypeOf,
    1490                 :         proxy_Fix,           /* fix             */
    1491                 :         NULL,                /* thisObject      */
    1492                 :         NULL,                /* clear           */
    1493                 :     }
    1494           18667 : };
    1495                 : 
    1496                 : JS_FRIEND_API(JSObject *)
    1497           35007 : js::NewProxyObject(JSContext *cx, ProxyHandler *handler, const Value &priv, JSObject *proto,
    1498                 :                    JSObject *parent, JSObject *call, JSObject *construct)
    1499                 : {
    1500           35007 :     JS_ASSERT_IF(proto, cx->compartment == proto->compartment());
    1501           35007 :     JS_ASSERT_IF(parent, cx->compartment == parent->compartment());
    1502           35007 :     bool fun = call || construct;
    1503                 :     Class *clasp;
    1504           35007 :     if (fun)
    1505           16320 :         clasp = &FunctionProxyClass;
    1506                 :     else
    1507           18687 :         clasp = handler->isOuterWindow() ? &OuterWindowProxyClass : &ObjectProxyClass;
    1508                 : 
    1509                 :     /*
    1510                 :      * Eagerly mark properties unknown for proxies, so we don't try to track
    1511                 :      * their properties and so that we don't need to walk the compartment if
    1512                 :      * their prototype changes later.
    1513                 :      */
    1514           35007 :     if (proto && !proto->setNewTypeUnknown(cx))
    1515               0 :         return NULL;
    1516                 : 
    1517           35007 :     JSObject *obj = NewObjectWithGivenProto(cx, clasp, proto, parent);
    1518           35007 :     if (!obj)
    1519               0 :         return NULL;
    1520           35007 :     obj->setSlot(JSSLOT_PROXY_HANDLER, PrivateValue(handler));
    1521           35007 :     obj->setSlot(JSSLOT_PROXY_PRIVATE, priv);
    1522           35007 :     if (fun) {
    1523           16320 :         obj->setSlot(JSSLOT_PROXY_CALL, call ? ObjectValue(*call) : UndefinedValue());
    1524           16320 :         if (construct) {
    1525              45 :             obj->setSlot(JSSLOT_PROXY_CONSTRUCT, ObjectValue(*construct));
    1526                 :         }
    1527                 :     }
    1528                 : 
    1529                 :     /* Don't track types of properties of proxies. */
    1530           35007 :     MarkTypeObjectUnknownProperties(cx, obj->type());
    1531                 : 
    1532           35007 :     return obj;
    1533                 : }
    1534                 : 
    1535                 : static JSBool
    1536             342 : proxy_create(JSContext *cx, unsigned argc, Value *vp)
    1537                 : {
    1538             342 :     if (argc < 1) {
    1539                 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
    1540               0 :                              "create", "0", "s");
    1541               0 :         return false;
    1542                 :     }
    1543             342 :     JSObject *handler = NonNullObject(cx, vp[2]);
    1544             342 :     if (!handler)
    1545               0 :         return false;
    1546             342 :     JSObject *proto, *parent = NULL;
    1547             342 :     if (argc > 1 && vp[3].isObject()) {
    1548              27 :         proto = &vp[3].toObject();
    1549              27 :         parent = proto->getParent();
    1550                 :     } else {
    1551             315 :         JS_ASSERT(IsFunctionObject(vp[0]));
    1552             315 :         proto = NULL;
    1553                 :     }
    1554             342 :     if (!parent)
    1555             315 :         parent = vp[0].toObject().getParent();
    1556                 :     JSObject *proxy = NewProxyObject(cx, &ScriptedProxyHandler::singleton, ObjectValue(*handler),
    1557             342 :                                      proto, parent);
    1558             342 :     if (!proxy)
    1559               0 :         return false;
    1560                 : 
    1561             342 :     vp->setObject(*proxy);
    1562             342 :     return true;
    1563                 : }
    1564                 : 
    1565                 : static JSBool
    1566             135 : proxy_createFunction(JSContext *cx, unsigned argc, Value *vp)
    1567                 : {
    1568             135 :     if (argc < 2) {
    1569                 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
    1570               0 :                              "createFunction", "1", "");
    1571               0 :         return false;
    1572                 :     }
    1573             135 :     JSObject *handler = NonNullObject(cx, vp[2]);
    1574             135 :     if (!handler)
    1575               0 :         return false;
    1576                 :     JSObject *proto, *parent;
    1577             135 :     parent = vp[0].toObject().getParent();
    1578             135 :     proto = parent->global().getOrCreateFunctionPrototype(cx);
    1579             135 :     if (!proto)
    1580               0 :         return false;
    1581             135 :     parent = proto->getParent();
    1582                 : 
    1583             135 :     JSObject *call = js_ValueToCallableObject(cx, &vp[3], JSV2F_SEARCH_STACK);
    1584             135 :     if (!call)
    1585               0 :         return false;
    1586             135 :     JSObject *construct = NULL;
    1587             135 :     if (argc > 2) {
    1588              45 :         construct = js_ValueToCallableObject(cx, &vp[4], JSV2F_SEARCH_STACK);
    1589              45 :         if (!construct)
    1590               0 :             return false;
    1591                 :     }
    1592                 : 
    1593                 :     JSObject *proxy = NewProxyObject(cx, &ScriptedProxyHandler::singleton,
    1594                 :                                      ObjectValue(*handler),
    1595             135 :                                      proto, parent, call, construct);
    1596             135 :     if (!proxy)
    1597               0 :         return false;
    1598                 : 
    1599             135 :     vp->setObject(*proxy);
    1600             135 :     return true;
    1601                 : }
    1602                 : 
    1603                 : #ifdef DEBUG
    1604                 : 
    1605                 : static JSBool
    1606               0 : proxy_isTrapping(JSContext *cx, unsigned argc, Value *vp)
    1607                 : {
    1608               0 :     if (argc < 1) {
    1609                 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
    1610               0 :                              "isTrapping", "0", "s");
    1611               0 :         return false;
    1612                 :     }
    1613               0 :     JSObject *obj = NonNullObject(cx, vp[2]);
    1614               0 :     if (!obj)
    1615               0 :         return false;
    1616               0 :     vp->setBoolean(obj->isProxy());
    1617               0 :     return true;
    1618                 : }
    1619                 : 
    1620                 : static JSBool
    1621               9 : proxy_fix(JSContext *cx, unsigned argc, Value *vp)
    1622                 : {
    1623               9 :     if (argc < 1) {
    1624                 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
    1625               0 :                              "fix", "0", "s");
    1626               0 :         return false;
    1627                 :     }
    1628               9 :     JSObject *obj = NonNullObject(cx, vp[2]);
    1629               9 :     if (!obj)
    1630               0 :         return false;
    1631               9 :     if (obj->isProxy()) {
    1632                 :         JSBool flag;
    1633               9 :         if (!FixProxy(cx, obj, &flag))
    1634               0 :             return false;
    1635               9 :         vp->setBoolean(flag);
    1636                 :     } else {
    1637               0 :         vp->setBoolean(true);
    1638                 :     }
    1639               9 :     return true;
    1640                 : }
    1641                 : 
    1642                 : #endif
    1643                 : 
    1644                 : static JSFunctionSpec static_methods[] = {
    1645                 :     JS_FN("create",         proxy_create,          2, 0),
    1646                 :     JS_FN("createFunction", proxy_createFunction,  3, 0),
    1647                 : #ifdef DEBUG
    1648                 :     JS_FN("isTrapping",     proxy_isTrapping,      1, 0),
    1649                 :     JS_FN("fix",            proxy_fix,             1, 0),
    1650                 : #endif
    1651                 :     JS_FS_END
    1652                 : };
    1653                 : 
    1654                 : static const uint32_t JSSLOT_CALLABLE_CALL = 0;
    1655                 : static const uint32_t JSSLOT_CALLABLE_CONSTRUCT = 1;
    1656                 : 
    1657                 : static JSBool
    1658               9 : callable_Call(JSContext *cx, unsigned argc, Value *vp)
    1659                 : {
    1660               9 :     JSObject *callable = &JS_CALLEE(cx, vp).toObject();
    1661               9 :     JS_ASSERT(callable->getClass() == &CallableObjectClass);
    1662               9 :     const Value &fval = callable->getSlot(JSSLOT_CALLABLE_CALL);
    1663               9 :     const Value &thisval = vp[1];
    1664               9 :     bool ok = Invoke(cx, thisval, fval, argc, JS_ARGV(cx, vp), vp);
    1665               9 :     return ok;
    1666                 : }
    1667                 : 
    1668                 : JSBool
    1669              18 : callable_Construct(JSContext *cx, unsigned argc, Value *vp)
    1670                 : {
    1671              18 :     JSObject *callable = &vp[0].toObject();
    1672              18 :     JS_ASSERT(callable->getClass() == &CallableObjectClass);
    1673              18 :     Value fval = callable->getSlot(JSSLOT_CALLABLE_CONSTRUCT);
    1674              18 :     if (fval.isUndefined()) {
    1675                 :         /* We don't have an explicit constructor so allocate a new object and use the call. */
    1676               0 :         fval = callable->getSlot(JSSLOT_CALLABLE_CALL);
    1677               0 :         JS_ASSERT(fval.isObject());
    1678                 : 
    1679                 :         /* callable is the constructor, so get callable.prototype is the proto of the new object. */
    1680                 :         Value protov;
    1681               0 :         if (!callable->getProperty(cx, ATOM(classPrototype), &protov))
    1682               0 :             return false;
    1683                 : 
    1684                 :         JSObject *proto;
    1685               0 :         if (protov.isObject()) {
    1686               0 :             proto = &protov.toObject();
    1687                 :         } else {
    1688               0 :             proto = callable->global().getOrCreateObjectPrototype(cx);
    1689               0 :             if (!proto)
    1690               0 :                 return false;
    1691                 :         }
    1692                 : 
    1693               0 :         JSObject *newobj = NewObjectWithGivenProto(cx, &ObjectClass, proto, NULL);
    1694               0 :         if (!newobj)
    1695               0 :             return false;
    1696                 : 
    1697                 :         /* If the call returns an object, return that, otherwise the original newobj. */
    1698                 :         Value rval;
    1699               0 :         if (!Invoke(cx, ObjectValue(*newobj), callable->getSlot(JSSLOT_CALLABLE_CALL),
    1700               0 :                     argc, vp + 2, &rval)) {
    1701               0 :             return false;
    1702                 :         }
    1703               0 :         if (rval.isPrimitive())
    1704               0 :             vp->setObject(*newobj);
    1705                 :         else
    1706               0 :             *vp = rval;
    1707               0 :         return true;
    1708                 :     }
    1709                 : 
    1710              18 :     bool ok = Invoke(cx, UndefinedValue(), fval, argc, vp + 2, vp);
    1711              18 :     return ok;
    1712                 : }
    1713                 : 
    1714                 : Class js::CallableObjectClass = {
    1715                 :     "Function",
    1716                 :     JSCLASS_HAS_RESERVED_SLOTS(2),
    1717                 :     JS_PropertyStub,         /* addProperty */
    1718                 :     JS_PropertyStub,         /* delProperty */
    1719                 :     JS_PropertyStub,         /* getProperty */
    1720                 :     JS_StrictPropertyStub,   /* setProperty */
    1721                 :     JS_EnumerateStub,
    1722                 :     JS_ResolveStub,
    1723                 :     JS_ConvertStub,
    1724                 :     NULL,                    /* finalize    */
    1725                 :     NULL,                    /* checkAccess */
    1726                 :     callable_Call,
    1727                 :     callable_Construct,
    1728                 : };
    1729                 : 
    1730                 : static bool
    1731              36 : FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp)
    1732                 : {
    1733              36 :     if (OperationInProgress(cx, proxy)) {
    1734               0 :         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PROXY_FIX);
    1735               0 :         return false;
    1736                 :     }
    1737                 : 
    1738              72 :     AutoValueRooter tvr(cx);
    1739              36 :     if (!Proxy::fix(cx, proxy, tvr.addr()))
    1740               0 :         return false;
    1741              36 :     if (tvr.value().isUndefined()) {
    1742               0 :         *bp = false;
    1743               0 :         return true;
    1744                 :     }
    1745                 : 
    1746              36 :     JSObject *props = NonNullObject(cx, tvr.value());
    1747              36 :     if (!props)
    1748               0 :         return false;
    1749                 : 
    1750              36 :     JSObject *proto = proxy->getProto();
    1751              36 :     JSObject *parent = proxy->getParent();
    1752              36 :     Class *clasp = IsFunctionProxy(proxy) ? &CallableObjectClass : &ObjectClass;
    1753                 : 
    1754                 :     /*
    1755                 :      * Make a blank object from the recipe fix provided to us.  This must have
    1756                 :      * number of fixed slots as the proxy so that we can swap their contents.
    1757                 :      */
    1758              36 :     gc::AllocKind kind = proxy->getAllocKind();
    1759              36 :     JSObject *newborn = NewObjectWithGivenProto(cx, clasp, proto, parent, kind);
    1760              36 :     if (!newborn)
    1761               0 :         return false;
    1762                 : 
    1763              36 :     if (clasp == &CallableObjectClass) {
    1764              18 :         newborn->setSlot(JSSLOT_CALLABLE_CALL, GetCall(proxy));
    1765              18 :         newborn->setSlot(JSSLOT_CALLABLE_CONSTRUCT, GetConstruct(proxy));
    1766                 :     }
    1767                 : 
    1768                 :     {
    1769              72 :         AutoPendingProxyOperation pending(cx, proxy);
    1770              36 :         if (!js_PopulateObject(cx, newborn, props))
    1771               0 :             return false;
    1772                 :     }
    1773                 : 
    1774                 :     /* Trade contents between the newborn object and the proxy. */
    1775              36 :     if (!proxy->swap(cx, newborn))
    1776               0 :         return false;
    1777                 : 
    1778                 :     /* The GC will dispose of the proxy object. */
    1779                 : 
    1780              36 :     *bp = true;
    1781              36 :     return true;
    1782                 : }
    1783                 : 
    1784                 : Class js::ProxyClass = {
    1785                 :     "Proxy",
    1786                 :     JSCLASS_HAS_CACHED_PROTO(JSProto_Proxy),
    1787                 :     JS_PropertyStub,         /* addProperty */
    1788                 :     JS_PropertyStub,         /* delProperty */
    1789                 :     JS_PropertyStub,         /* getProperty */
    1790                 :     JS_StrictPropertyStub,   /* setProperty */
    1791                 :     JS_EnumerateStub,
    1792                 :     JS_ResolveStub,
    1793                 :     JS_ConvertStub
    1794                 : };
    1795                 : 
    1796                 : JS_FRIEND_API(JSObject *)
    1797             834 : js_InitProxyClass(JSContext *cx, JSObject *obj)
    1798                 : {
    1799             834 :     JSObject *module = NewObjectWithClassProto(cx, &ProxyClass, NULL, obj);
    1800             834 :     if (!module || !module->setSingletonType(cx))
    1801               0 :         return NULL;
    1802                 : 
    1803             834 :     if (!JS_DefineProperty(cx, obj, "Proxy", OBJECT_TO_JSVAL(module),
    1804             834 :                            JS_PropertyStub, JS_StrictPropertyStub, 0)) {
    1805               0 :         return NULL;
    1806                 :     }
    1807             834 :     if (!JS_DefineFunctions(cx, module, static_methods))
    1808               0 :         return NULL;
    1809                 : 
    1810             834 :     MarkStandardClassInitializedNoProto(obj, &ProxyClass);
    1811                 : 
    1812             834 :     return module;
    1813           56001 : }

Generated by: LCOV version 1.7