LCOV - code coverage report
Current view: directory - js/src - jsproxy.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 822 509 61.9 %
Date: 2012-06-02 Functions: 136 92 67.6 %

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

Generated by: LCOV version 1.7