LCOV - app.info - js/src/jsproxy.cpp

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

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

Generated by: LCOV version 1.7