PageRenderTime 152ms CodeModel.GetById 16ms app.highlight 126ms RepoModel.GetById 1ms app.codeStats 0ms

/js/src/jsproxy.cpp

http://github.com/zpao/v8monkey
C++ | 1821 lines | 1552 code | 200 blank | 69 comment | 173 complexity | 11c588c768d4872c0722d362edc57afc MD5 | raw file

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file