~ubuntu-branches/ubuntu/saucy/mozjs17/saucy

« back to all changes in this revision

Viewing changes to js/src/jsproxy.cpp

  • Committer: Package Import Robot
  • Author(s): Rico Tzschichholz
  • Date: 2013-05-25 12:24:23 UTC
  • Revision ID: package-import@ubuntu.com-20130525122423-zmxucrhtensw90xy
Tags: upstream-17.0.0
ImportĀ upstreamĀ versionĀ 17.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 * This Source Code Form is subject to the terms of the Mozilla Public
 
5
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 
6
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
7
 
 
8
#include <string.h>
 
9
#include "jsapi.h"
 
10
#include "jscntxt.h"
 
11
#include "jsfun.h"
 
12
#include "jsgc.h"
 
13
#include "jsprvtd.h"
 
14
#include "jsnum.h"
 
15
#include "jsproxy.h"
 
16
#include "jsscope.h"
 
17
 
 
18
#include "gc/Marking.h"
 
19
 
 
20
#include "jsatominlines.h"
 
21
#include "jsinferinlines.h"
 
22
#include "jsobjinlines.h"
 
23
 
 
24
#include "vm/RegExpObject-inl.h"
 
25
 
 
26
using namespace js;
 
27
using namespace js::gc;
 
28
 
 
29
static inline HeapSlot &
 
30
GetCall(JSObject *proxy)
 
31
{
 
32
    JS_ASSERT(IsFunctionProxy(proxy));
 
33
    return proxy->getSlotRef(JSSLOT_PROXY_CALL);
 
34
}
 
35
 
 
36
static inline Value
 
37
GetConstruct(JSObject *proxy)
 
38
{
 
39
    if (proxy->slotSpan() <= JSSLOT_PROXY_CONSTRUCT)
 
40
        return UndefinedValue();
 
41
    return proxy->getSlot(JSSLOT_PROXY_CONSTRUCT);
 
42
}
 
43
 
 
44
static inline HeapSlot &
 
45
GetFunctionProxyConstruct(JSObject *proxy)
 
46
{
 
47
    JS_ASSERT(IsFunctionProxy(proxy));
 
48
    JS_ASSERT(proxy->slotSpan() > JSSLOT_PROXY_CONSTRUCT);
 
49
    return proxy->getSlotRef(JSSLOT_PROXY_CONSTRUCT);
 
50
}
 
51
 
 
52
#ifdef DEBUG
 
53
static bool
 
54
OperationInProgress(JSContext *cx, JSObject *proxy)
 
55
{
 
56
    PendingProxyOperation *op = cx->runtime->pendingProxyOperation;
 
57
    while (op) {
 
58
        if (op->object == proxy)
 
59
            return true;
 
60
        op = op->next;
 
61
    }
 
62
    return false;
 
63
}
 
64
#endif
 
65
 
 
66
BaseProxyHandler::BaseProxyHandler(void *family)
 
67
  : mFamily(family),
 
68
    mHasPrototype(false)
 
69
{
 
70
}
 
71
 
 
72
BaseProxyHandler::~BaseProxyHandler()
 
73
{
 
74
}
 
75
 
 
76
bool
 
77
BaseProxyHandler::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
 
78
{
 
79
    JS_ASSERT(OperationInProgress(cx, proxy));
 
80
    AutoPropertyDescriptorRooter desc(cx);
 
81
    if (!getPropertyDescriptor(cx, proxy, id, false, &desc))
 
82
        return false;
 
83
    *bp = !!desc.obj;
 
84
    return true;
 
85
}
 
86
 
 
87
bool
 
88
BaseProxyHandler::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
 
89
{
 
90
    JS_ASSERT(OperationInProgress(cx, proxy));
 
91
    AutoPropertyDescriptorRooter desc(cx);
 
92
    if (!getOwnPropertyDescriptor(cx, proxy, id, false, &desc))
 
93
        return false;
 
94
    *bp = !!desc.obj;
 
95
    return true;
 
96
}
 
97
 
 
98
bool
 
99
BaseProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver_, jsid id_, Value *vp)
 
100
{
 
101
    RootedObject receiver(cx, receiver_);
 
102
    RootedId id(cx, id_);
 
103
 
 
104
    JS_ASSERT(OperationInProgress(cx, proxy));
 
105
    AutoPropertyDescriptorRooter desc(cx);
 
106
    if (!getPropertyDescriptor(cx, proxy, id, false, &desc))
 
107
        return false;
 
108
    if (!desc.obj) {
 
109
        vp->setUndefined();
 
110
        return true;
 
111
    }
 
112
    if (!desc.getter ||
 
113
        (!(desc.attrs & JSPROP_GETTER) && desc.getter == JS_PropertyStub)) {
 
114
        *vp = desc.value;
 
115
        return true;
 
116
    }
 
117
    if (desc.attrs & JSPROP_GETTER)
 
118
        return InvokeGetterOrSetter(cx, receiver, CastAsObjectJsval(desc.getter), 0, NULL, vp);
 
119
    if (!(desc.attrs & JSPROP_SHARED))
 
120
        *vp = desc.value;
 
121
    else
 
122
        vp->setUndefined();
 
123
    if (desc.attrs & JSPROP_SHORTID)
 
124
        id = INT_TO_JSID(desc.shortid);
 
125
 
 
126
    RootedValue value(cx, *vp);
 
127
    if (!CallJSPropertyOp(cx, desc.getter, receiver, id, &value))
 
128
        return false;
 
129
 
 
130
    *vp = value;
 
131
    return true;
 
132
}
 
133
 
 
134
bool
 
135
BaseProxyHandler::getElementIfPresent(JSContext *cx, JSObject *proxy_, JSObject *receiver_, uint32_t index, Value *vp, bool *present)
 
136
{
 
137
    RootedObject proxy(cx, proxy_);
 
138
    RootedObject receiver(cx, receiver_);
 
139
 
 
140
    jsid id;
 
141
    if (!IndexToId(cx, index, &id))
 
142
        return false;
 
143
 
 
144
    if (!has(cx, proxy, id, present))
 
145
        return false;
 
146
 
 
147
    if (!*present) {
 
148
        Debug_SetValueRangeToCrashOnTouch(vp, 1);
 
149
        return true;
 
150
    }
 
151
 
 
152
    return get(cx, proxy, receiver, id, vp);
 
153
}
 
154
 
 
155
bool
 
156
BaseProxyHandler::set(JSContext *cx, JSObject *proxy_, JSObject *receiver_, jsid id_, bool strict,
 
157
                      Value *vp)
 
158
{
 
159
    RootedObject proxy(cx, proxy_), receiver(cx, receiver_);
 
160
    RootedId id(cx, id_);
 
161
 
 
162
    JS_ASSERT(OperationInProgress(cx, proxy));
 
163
    AutoPropertyDescriptorRooter desc(cx);
 
164
    if (!getOwnPropertyDescriptor(cx, proxy, id, true, &desc))
 
165
        return false;
 
166
    /* The control-flow here differs from ::get() because of the fall-through case below. */
 
167
    if (desc.obj) {
 
168
        // Check for read-only properties.
 
169
        if (desc.attrs & JSPROP_READONLY)
 
170
            return strict ? Throw(cx, id, JSMSG_CANT_REDEFINE_PROP) : true;
 
171
        if (!desc.setter) {
 
172
            // Be wary of the odd explicit undefined setter case possible through
 
173
            // Object.defineProperty.
 
174
            if (!(desc.attrs & JSPROP_SETTER))
 
175
                desc.setter = JS_StrictPropertyStub;
 
176
        } else if ((desc.attrs & JSPROP_SETTER) || desc.setter != JS_StrictPropertyStub) {
 
177
            RootedValue value(cx, *vp);
 
178
            if (!CallSetter(cx, receiver, id, desc.setter, desc.attrs, desc.shortid, strict, &value))
 
179
                return false;
 
180
            *vp = value;
 
181
            if (!proxy->isProxy() || GetProxyHandler(proxy) != this)
 
182
                return true;
 
183
            if (desc.attrs & JSPROP_SHARED)
 
184
                return true;
 
185
        }
 
186
        if (!desc.getter) {
 
187
            // Same as above for the null setter case.
 
188
            if (!(desc.attrs & JSPROP_GETTER))
 
189
                desc.getter = JS_PropertyStub;
 
190
        }
 
191
        desc.value = *vp;
 
192
        return defineProperty(cx, receiver, id, &desc);
 
193
    }
 
194
    if (!getPropertyDescriptor(cx, proxy, id, true, &desc))
 
195
        return false;
 
196
    if (desc.obj) {
 
197
        // Check for read-only properties.
 
198
        if (desc.attrs & JSPROP_READONLY)
 
199
            return strict ? Throw(cx, id, JSMSG_CANT_REDEFINE_PROP) : true;
 
200
        if (!desc.setter) {
 
201
            // Be wary of the odd explicit undefined setter case possible through
 
202
            // Object.defineProperty.
 
203
            if (!(desc.attrs & JSPROP_SETTER))
 
204
                desc.setter = JS_StrictPropertyStub;
 
205
        } else if ((desc.attrs & JSPROP_SETTER) || desc.setter != JS_StrictPropertyStub) {
 
206
            RootedValue value(cx, *vp);
 
207
            if (!CallSetter(cx, receiver, id, desc.setter, desc.attrs, desc.shortid, strict, &value))
 
208
                return false;
 
209
            *vp = value;
 
210
            if (!proxy->isProxy() || GetProxyHandler(proxy) != this)
 
211
                return true;
 
212
            if (desc.attrs & JSPROP_SHARED)
 
213
                return true;
 
214
        }
 
215
        if (!desc.getter) {
 
216
            // Same as above for the null setter case.
 
217
            if (!(desc.attrs & JSPROP_GETTER))
 
218
                desc.getter = JS_PropertyStub;
 
219
        }
 
220
        desc.value = *vp;
 
221
        return defineProperty(cx, receiver, id, &desc);
 
222
    }
 
223
 
 
224
    desc.obj = receiver;
 
225
    desc.value = *vp;
 
226
    desc.attrs = JSPROP_ENUMERATE;
 
227
    desc.shortid = 0;
 
228
    desc.getter = NULL;
 
229
    desc.setter = NULL; // Pick up the class getter/setter.
 
230
    return defineProperty(cx, receiver, id, &desc);
 
231
}
 
232
 
 
233
bool
 
234
BaseProxyHandler::keys(JSContext *cx, JSObject *proxy, AutoIdVector &props)
 
235
{
 
236
    JS_ASSERT(OperationInProgress(cx, proxy));
 
237
    JS_ASSERT(props.length() == 0);
 
238
 
 
239
    if (!getOwnPropertyNames(cx, proxy, props))
 
240
        return false;
 
241
 
 
242
    /* Select only the enumerable properties through in-place iteration. */
 
243
    AutoPropertyDescriptorRooter desc(cx);
 
244
    size_t i = 0;
 
245
    for (size_t j = 0, len = props.length(); j < len; j++) {
 
246
        JS_ASSERT(i <= j);
 
247
        jsid id = props[j];
 
248
        if (!getOwnPropertyDescriptor(cx, proxy, id, false, &desc))
 
249
            return false;
 
250
        if (desc.obj && (desc.attrs & JSPROP_ENUMERATE))
 
251
            props[i++] = id;
 
252
    }
 
253
 
 
254
    JS_ASSERT(i <= props.length());
 
255
    props.resize(i);
 
256
 
 
257
    return true;
 
258
}
 
259
 
 
260
bool
 
261
BaseProxyHandler::iterate(JSContext *cx, JSObject *proxy_, unsigned flags, Value *vp)
 
262
{
 
263
    RootedObject proxy(cx, proxy_);
 
264
 
 
265
    JS_ASSERT(OperationInProgress(cx, proxy));
 
266
    AutoIdVector props(cx);
 
267
    if ((flags & JSITER_OWNONLY)
 
268
        ? !keys(cx, proxy, props)
 
269
        : !enumerate(cx, proxy, props)) {
 
270
        return false;
 
271
    }
 
272
 
 
273
    RootedValue value(cx);
 
274
    if (!EnumeratedIdVectorToIterator(cx, proxy, flags, props, &value))
 
275
        return false;
 
276
 
 
277
    *vp = value;
 
278
    return true;
 
279
}
 
280
 
 
281
bool
 
282
BaseProxyHandler::call(JSContext *cx, JSObject *proxy, unsigned argc,
 
283
                       Value *vp)
 
284
{
 
285
    return ReportIsNotFunction(cx, UndefinedValue());
 
286
}
 
287
 
 
288
bool
 
289
BaseProxyHandler::construct(JSContext *cx, JSObject *proxy, unsigned argc,
 
290
                            Value *argv, Value *rval)
 
291
{
 
292
    return ReportIsNotFunction(cx, UndefinedValue(), CONSTRUCT);
 
293
}
 
294
 
 
295
JSString *
 
296
BaseProxyHandler::obj_toString(JSContext *cx, JSObject *proxy)
 
297
{
 
298
    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
 
299
                         JSMSG_INCOMPATIBLE_PROTO,
 
300
                         js_Object_str, js_toString_str,
 
301
                         "object");
 
302
    return NULL;
 
303
}
 
304
 
 
305
JSString *
 
306
BaseProxyHandler::fun_toString(JSContext *cx, JSObject *proxy, unsigned indent)
 
307
{
 
308
    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
 
309
                         JSMSG_INCOMPATIBLE_PROTO,
 
310
                         js_Function_str, js_toString_str,
 
311
                         "object");
 
312
    return NULL;
 
313
}
 
314
 
 
315
bool
 
316
BaseProxyHandler::regexp_toShared(JSContext *cx, JSObject *proxy,
 
317
                                  RegExpGuard *g)
 
318
{
 
319
    JS_NOT_REACHED("This should have been a wrapped regexp");
 
320
    return false;
 
321
}
 
322
 
 
323
bool
 
324
BaseProxyHandler::defaultValue(JSContext *cx, JSObject *proxy, JSType hint,
 
325
                               Value *vp)
 
326
{
 
327
    Rooted<JSObject*> obj(cx, proxy);
 
328
    RootedValue value(cx);
 
329
    if (!DefaultValue(cx, obj, hint, &value))
 
330
        return false;
 
331
 
 
332
    *vp = value;
 
333
    return true;
 
334
}
 
335
 
 
336
bool
 
337
BaseProxyHandler::iteratorNext(JSContext *cx, JSObject *proxy, Value *vp)
 
338
{
 
339
    vp->setMagic(JS_NO_ITER_VALUE);
 
340
    return true;
 
341
}
 
342
 
 
343
bool
 
344
BaseProxyHandler::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args)
 
345
{
 
346
    JS_ASSERT(OperationInProgress(cx, &args.thisv().toObject()));
 
347
    ReportIncompatible(cx, args);
 
348
    return false;
 
349
}
 
350
 
 
351
bool
 
352
BaseProxyHandler::hasInstance(JSContext *cx, JSObject *proxy, const Value *vp, bool *bp)
 
353
{
 
354
    JS_ASSERT(OperationInProgress(cx, proxy));
 
355
 
 
356
    RootedValue val(cx, ObjectValue(*proxy));
 
357
    js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
 
358
                        JSDVG_SEARCH_STACK, val, NullPtr());
 
359
    return false;
 
360
}
 
361
 
 
362
JSType
 
363
BaseProxyHandler::typeOf(JSContext *cx, JSObject *proxy)
 
364
{
 
365
    JS_ASSERT(OperationInProgress(cx, proxy));
 
366
    return IsFunctionProxy(proxy) ? JSTYPE_FUNCTION : JSTYPE_OBJECT;
 
367
}
 
368
 
 
369
bool
 
370
BaseProxyHandler::objectClassIs(JSObject *proxy, ESClassValue classValue, JSContext *cx)
 
371
{
 
372
    JS_ASSERT(OperationInProgress(cx, proxy));
 
373
    return false;
 
374
}
 
375
 
 
376
void
 
377
BaseProxyHandler::finalize(JSFreeOp *fop, JSObject *proxy)
 
378
{
 
379
}
 
380
 
 
381
JSObject *
 
382
BaseProxyHandler::weakmapKeyDelegate(JSObject *proxy)
 
383
{
 
384
    return NULL;
 
385
}
 
386
 
 
387
bool
 
388
BaseProxyHandler::getPrototypeOf(JSContext *cx, JSObject *proxy, JSObject **proto)
 
389
{
 
390
    // The default implementation here just uses proto of the proxy object.
 
391
    JS_ASSERT(hasPrototype());
 
392
    *proto = proxy->getProto();
 
393
    return true;
 
394
}
 
395
 
 
396
IndirectProxyHandler::IndirectProxyHandler(void *family) : BaseProxyHandler(family)
 
397
{
 
398
}
 
399
 
 
400
bool
 
401
IndirectProxyHandler::getPropertyDescriptor(JSContext *cx, JSObject *proxy,
 
402
                                            jsid id, bool set,
 
403
                                            PropertyDescriptor *desc)
 
404
{
 
405
    RootedObject target(cx, GetProxyTargetObject(proxy));
 
406
    return JS_GetPropertyDescriptorById(cx, target, id, JSRESOLVE_QUALIFIED, desc);
 
407
}
 
408
 
 
409
static bool
 
410
GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, jsid id, unsigned flags,
 
411
                         JSPropertyDescriptor *desc)
 
412
{
 
413
    // If obj is a proxy, we can do better than just guessing. This is
 
414
    // important for certain types of wrappers that wrap other wrappers.
 
415
    if (obj->isProxy())
 
416
        return Proxy::getOwnPropertyDescriptor(cx, obj, id,
 
417
                                               flags & JSRESOLVE_ASSIGNING,
 
418
                                               desc);
 
419
 
 
420
    if (!JS_GetPropertyDescriptorById(cx, obj, id, flags, desc))
 
421
        return false;
 
422
    if (desc->obj != obj)
 
423
        desc->obj = NULL;
 
424
    return true;
 
425
}
 
426
 
 
427
bool
 
428
IndirectProxyHandler::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy,
 
429
                                               jsid id, bool set,
 
430
                                               PropertyDescriptor *desc)
 
431
{
 
432
    RootedObject target(cx, GetProxyTargetObject(proxy));
 
433
    return GetOwnPropertyDescriptor(cx, target, id, JSRESOLVE_QUALIFIED, desc);
 
434
}
 
435
 
 
436
bool
 
437
IndirectProxyHandler::defineProperty(JSContext *cx, JSObject *proxy, jsid id_,
 
438
                                     PropertyDescriptor *desc)
 
439
{
 
440
    RootedObject obj(cx, GetProxyTargetObject(proxy));
 
441
    Rooted<jsid> id(cx, id_);
 
442
    Rooted<Value> v(cx, desc->value);
 
443
    return CheckDefineProperty(cx, obj, id, v, desc->getter, desc->setter, desc->attrs) &&
 
444
           JS_DefinePropertyById(cx, obj, id, v, desc->getter, desc->setter, desc->attrs);
 
445
}
 
446
 
 
447
bool
 
448
IndirectProxyHandler::getOwnPropertyNames(JSContext *cx, JSObject *proxy,
 
449
                                          AutoIdVector &props)
 
450
{
 
451
    RootedObject target(cx, GetProxyTargetObject(proxy));
 
452
    return GetPropertyNames(cx, target, JSITER_OWNONLY | JSITER_HIDDEN, &props);
 
453
}
 
454
 
 
455
bool
 
456
IndirectProxyHandler::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
 
457
{
 
458
    Value v;
 
459
    RootedObject target(cx, GetProxyTargetObject(proxy));
 
460
    if (!JS_DeletePropertyById2(cx, target, id, &v))
 
461
        return false;
 
462
    JSBool b;
 
463
    if (!JS_ValueToBoolean(cx, v, &b))
 
464
        return false;
 
465
    *bp = !!b;
 
466
    return true;
 
467
}
 
468
 
 
469
bool
 
470
IndirectProxyHandler::enumerate(JSContext *cx, JSObject *proxy,
 
471
                                AutoIdVector &props)
 
472
{
 
473
    RootedObject target(cx, GetProxyTargetObject(proxy));
 
474
    return GetPropertyNames(cx, target, 0, &props);
 
475
}
 
476
 
 
477
bool
 
478
IndirectProxyHandler::call(JSContext *cx, JSObject *proxy, unsigned argc,
 
479
                   Value *vp)
 
480
{
 
481
    JS_ASSERT(OperationInProgress(cx, proxy));
 
482
    AutoValueRooter rval(cx);
 
483
    JSBool ok = Invoke(cx, vp[1], GetCall(proxy), argc, JS_ARGV(cx, vp), rval.addr());
 
484
    if (ok)
 
485
        JS_SET_RVAL(cx, vp, rval.value());
 
486
    return ok;
 
487
}
 
488
 
 
489
bool
 
490
IndirectProxyHandler::construct(JSContext *cx, JSObject *proxy, unsigned argc,
 
491
                                Value *argv, Value *rval)
 
492
{
 
493
    JS_ASSERT(OperationInProgress(cx, proxy));
 
494
    Value fval = GetConstruct(proxy);
 
495
    if (fval.isUndefined())
 
496
        fval = GetCall(proxy);
 
497
    return InvokeConstructor(cx, fval, argc, argv, rval);
 
498
}
 
499
 
 
500
bool
 
501
IndirectProxyHandler::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
 
502
                                    CallArgs args)
 
503
{
 
504
    args.setThis(ObjectValue(*GetProxyTargetObject(&args.thisv().toObject())));
 
505
    if (!test(args.thisv())) {
 
506
        ReportIncompatible(cx, args);
 
507
        return false;
 
508
    }
 
509
 
 
510
    return CallNativeImpl(cx, impl, args);
 
511
}
 
512
 
 
513
bool
 
514
IndirectProxyHandler::hasInstance(JSContext *cx, JSObject *proxy, const Value *vp,
 
515
                                  bool *bp)
 
516
{
 
517
    JSBool b;
 
518
    RootedObject target(cx, GetProxyTargetObject(proxy));
 
519
    if (!JS_HasInstance(cx, target, *vp, &b))
 
520
        return false;
 
521
    *bp = !!b;
 
522
    return true;
 
523
}
 
524
 
 
525
JSType
 
526
IndirectProxyHandler::typeOf(JSContext *cx, JSObject *proxy)
 
527
{
 
528
    return TypeOfValue(cx, ObjectValue(*GetProxyTargetObject(proxy)));
 
529
}
 
530
 
 
531
bool
 
532
IndirectProxyHandler::objectClassIs(JSObject *proxy, ESClassValue classValue,
 
533
                                    JSContext *cx)
 
534
{
 
535
    return ObjectClassIs(*GetProxyTargetObject(proxy), classValue, cx);
 
536
}
 
537
 
 
538
JSString *
 
539
IndirectProxyHandler::obj_toString(JSContext *cx, JSObject *proxy)
 
540
{
 
541
    return obj_toStringHelper(cx, GetProxyTargetObject(proxy));
 
542
}
 
543
 
 
544
JSString *
 
545
IndirectProxyHandler::fun_toString(JSContext *cx, JSObject *proxy,
 
546
                                   unsigned indent)
 
547
{
 
548
    return fun_toStringHelper(cx, GetProxyTargetObject(proxy), indent);
 
549
}
 
550
 
 
551
bool
 
552
IndirectProxyHandler::regexp_toShared(JSContext *cx, JSObject *proxy,
 
553
                                      RegExpGuard *g)
 
554
{
 
555
    return RegExpToShared(cx, *GetProxyTargetObject(proxy), g);
 
556
}
 
557
 
 
558
bool
 
559
IndirectProxyHandler::defaultValue(JSContext *cx, JSObject *proxy, JSType hint,
 
560
                                   Value *vp)
 
561
{
 
562
    *vp = ObjectValue(*GetProxyTargetObject(proxy));
 
563
    if (hint == JSTYPE_VOID)
 
564
        return ToPrimitive(cx, vp);
 
565
    return ToPrimitive(cx, hint, vp);
 
566
}
 
567
 
 
568
bool
 
569
IndirectProxyHandler::iteratorNext(JSContext *cx, JSObject *proxy, Value *vp)
 
570
{
 
571
    Rooted<JSObject*> target(cx, GetProxyTargetObject(proxy));
 
572
    RootedValue value(cx);
 
573
    if (!js_IteratorMore(cx, target, &value))
 
574
        return false;
 
575
    *vp = value;
 
576
    if (vp->toBoolean()) {
 
577
        *vp = cx->iterValue;
 
578
        cx->iterValue = UndefinedValue();
 
579
    } else {
 
580
        *vp = MagicValue(JS_NO_ITER_VALUE);
 
581
    }
 
582
    return true;
 
583
}
 
584
 
 
585
JSObject *
 
586
IndirectProxyHandler::weakmapKeyDelegate(JSObject *proxy)
 
587
{
 
588
    return UnwrapObject(proxy);
 
589
}
 
590
 
 
591
DirectProxyHandler::DirectProxyHandler(void *family)
 
592
  : IndirectProxyHandler(family)
 
593
{
 
594
}
 
595
 
 
596
bool
 
597
DirectProxyHandler::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
 
598
{
 
599
    JSBool found;
 
600
    RootedObject target(cx, GetProxyTargetObject(proxy));
 
601
    if (!JS_HasPropertyById(cx, target, id, &found))
 
602
        return false;
 
603
    *bp = !!found;
 
604
    return true;
 
605
}
 
606
 
 
607
bool
 
608
DirectProxyHandler::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
 
609
{
 
610
    RootedObject target(cx, GetProxyTargetObject(proxy));
 
611
    AutoPropertyDescriptorRooter desc(cx);
 
612
    if (!JS_GetPropertyDescriptorById(cx, target, id, JSRESOLVE_QUALIFIED, &desc))
 
613
        return false;
 
614
    *bp = (desc.obj == target);
 
615
    return true;
 
616
}
 
617
 
 
618
bool
 
619
DirectProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver_,
 
620
                        jsid id_, Value *vp)
 
621
{
 
622
    RootedObject receiver(cx, receiver_);
 
623
    RootedId id(cx, id_);
 
624
    RootedValue value(cx);
 
625
    RootedObject target(cx, GetProxyTargetObject(proxy));
 
626
    if (!JSObject::getGeneric(cx, target, receiver, id, &value))
 
627
        return false;
 
628
 
 
629
    *vp = value;
 
630
    return true;
 
631
}
 
632
 
 
633
bool
 
634
DirectProxyHandler::set(JSContext *cx, JSObject *proxy, JSObject *receiverArg,
 
635
                        jsid id_, bool strict, Value *vp)
 
636
{
 
637
    RootedId id(cx, id_);
 
638
    Rooted<JSObject*> receiver(cx, receiverArg);
 
639
    RootedValue value(cx, *vp);
 
640
    RootedObject target(cx, GetProxyTargetObject(proxy));
 
641
    if (!JSObject::setGeneric(cx, target, receiver, id, &value, strict))
 
642
        return false;
 
643
 
 
644
    *vp = value;
 
645
    return true;
 
646
}
 
647
 
 
648
bool
 
649
DirectProxyHandler::keys(JSContext *cx, JSObject *proxy, AutoIdVector &props)
 
650
{
 
651
    return GetPropertyNames(cx, GetProxyTargetObject(proxy), JSITER_OWNONLY, &props);
 
652
}
 
653
 
 
654
bool
 
655
DirectProxyHandler::iterate(JSContext *cx, JSObject *proxy, unsigned flags,
 
656
                            Value *vp)
 
657
{
 
658
    Rooted<JSObject*> target(cx, GetProxyTargetObject(proxy));
 
659
    RootedValue value(cx);
 
660
    if (!GetIterator(cx, target, flags, &value))
 
661
        return false;
 
662
 
 
663
    *vp = value;
 
664
    return true;
 
665
}
 
666
 
 
667
static bool
 
668
GetTrap(JSContext *cx, HandleObject handler, HandlePropertyName name, MutableHandleValue fvalp)
 
669
{
 
670
    JS_CHECK_RECURSION(cx, return false);
 
671
 
 
672
    return JSObject::getProperty(cx, handler, handler, name, fvalp);
 
673
}
 
674
 
 
675
static bool
 
676
GetFundamentalTrap(JSContext *cx, HandleObject handler, HandlePropertyName name, MutableHandleValue fvalp)
 
677
{
 
678
    if (!GetTrap(cx, handler, name, fvalp))
 
679
        return false;
 
680
 
 
681
    if (!js_IsCallable(fvalp)) {
 
682
        JSAutoByteString bytes;
 
683
        if (js_AtomToPrintableString(cx, name, &bytes))
 
684
            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_FUNCTION, bytes.ptr());
 
685
        return false;
 
686
    }
 
687
 
 
688
    return true;
 
689
}
 
690
 
 
691
static bool
 
692
GetDerivedTrap(JSContext *cx, HandleObject handler, HandlePropertyName name, MutableHandleValue fvalp)
 
693
{
 
694
    JS_ASSERT(name == ATOM(has) ||
 
695
              name == ATOM(hasOwn) ||
 
696
              name == ATOM(get) ||
 
697
              name == ATOM(set) ||
 
698
              name == ATOM(keys) ||
 
699
              name == ATOM(iterate));
 
700
 
 
701
    return GetTrap(cx, handler, name, fvalp);
 
702
}
 
703
 
 
704
static bool
 
705
Trap(JSContext *cx, HandleObject handler, HandleValue fval, unsigned argc, Value* argv, Value *rval)
 
706
{
 
707
    return Invoke(cx, ObjectValue(*handler), fval, argc, argv, rval);
 
708
}
 
709
 
 
710
static bool
 
711
Trap1(JSContext *cx, HandleObject handler, HandleValue fval, HandleId id, Value *rval)
 
712
{
 
713
    JSString *str = ToString(cx, IdToValue(id));
 
714
    if (!str)
 
715
        return false;
 
716
    rval->setString(str);
 
717
    return Trap(cx, handler, fval, 1, rval, rval);
 
718
}
 
719
 
 
720
static bool
 
721
Trap2(JSContext *cx, HandleObject handler, HandleValue fval, HandleId id, Value v_, Value *rval)
 
722
{
 
723
    RootedValue v(cx, v_);
 
724
    JSString *str = ToString(cx, IdToValue(id));
 
725
    if (!str)
 
726
        return false;
 
727
    rval->setString(str);
 
728
    Value argv[2] = { *rval, v };
 
729
    AutoValueArray ava(cx, argv, 2);
 
730
    return Trap(cx, handler, fval, 2, argv, rval);
 
731
}
 
732
 
 
733
static bool
 
734
ParsePropertyDescriptorObject(JSContext *cx, HandleObject obj, const Value &v,
 
735
                              PropertyDescriptor *desc)
 
736
{
 
737
    AutoPropDescArrayRooter descs(cx);
 
738
    PropDesc *d = descs.append();
 
739
    if (!d || !d->initialize(cx, v))
 
740
        return false;
 
741
    desc->obj = obj;
 
742
    desc->value = d->hasValue() ? d->value() : UndefinedValue();
 
743
    JS_ASSERT(!(d->attributes() & JSPROP_SHORTID));
 
744
    desc->attrs = d->attributes();
 
745
    desc->getter = d->getter();
 
746
    desc->setter = d->setter();
 
747
    desc->shortid = 0;
 
748
    return true;
 
749
}
 
750
 
 
751
static bool
 
752
IndicatePropertyNotFound(JSContext *cx, PropertyDescriptor *desc)
 
753
{
 
754
    desc->obj = NULL;
 
755
    return true;
 
756
}
 
757
 
 
758
static bool
 
759
ValueToBool(JSContext *cx, const Value &v, bool *bp)
 
760
{
 
761
    *bp = ToBoolean(v);
 
762
    return true;
 
763
}
 
764
 
 
765
static bool
 
766
ArrayToIdVector(JSContext *cx, const Value &array, AutoIdVector &props)
 
767
{
 
768
    JS_ASSERT(props.length() == 0);
 
769
 
 
770
    if (array.isPrimitive())
 
771
        return true;
 
772
 
 
773
    RootedObject obj(cx, &array.toObject());
 
774
    uint32_t length;
 
775
    if (!GetLengthProperty(cx, obj, &length))
 
776
        return false;
 
777
 
 
778
    RootedValue v(cx);
 
779
    for (uint32_t n = 0; n < length; ++n) {
 
780
        if (!JS_CHECK_OPERATION_LIMIT(cx))
 
781
            return false;
 
782
        if (!JSObject::getElement(cx, obj, obj, n, &v))
 
783
            return false;
 
784
        jsid id;
 
785
        if (!ValueToId(cx, v, &id))
 
786
            return false;
 
787
        if (!props.append(id))
 
788
            return false;
 
789
    }
 
790
 
 
791
    return true;
 
792
}
 
793
 
 
794
/* Derived class for all scripted proxy handlers. */
 
795
class ScriptedProxyHandler : public IndirectProxyHandler {
 
796
  public:
 
797
    ScriptedProxyHandler();
 
798
    virtual ~ScriptedProxyHandler();
 
799
 
 
800
    /* ES5 Harmony fundamental proxy traps. */
 
801
    virtual bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
 
802
                                       PropertyDescriptor *desc);
 
803
    virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
 
804
                                          PropertyDescriptor *desc);
 
805
    virtual bool defineProperty(JSContext *cx, JSObject *proxy, jsid id,
 
806
                                PropertyDescriptor *desc);
 
807
    virtual bool getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props);
 
808
    virtual bool delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp);
 
809
    virtual bool enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props);
 
810
 
 
811
    /* ES5 Harmony derived proxy traps. */
 
812
    virtual bool has(JSContext *cx, JSObject *proxy, jsid id, bool *bp);
 
813
    virtual bool hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp);
 
814
    virtual bool get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp);
 
815
    virtual bool set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, bool strict,
 
816
                     Value *vp);
 
817
    virtual bool keys(JSContext *cx, JSObject *proxy, AutoIdVector &props);
 
818
    virtual bool iterate(JSContext *cx, JSObject *proxy, unsigned flags, Value *vp);
 
819
 
 
820
    /* Spidermonkey extensions. */
 
821
    virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args) MOZ_OVERRIDE;
 
822
    virtual JSType typeOf(JSContext *cx, JSObject *proxy);
 
823
    virtual bool defaultValue(JSContext *cx, JSObject *obj, JSType hint, Value *vp);
 
824
 
 
825
    static ScriptedProxyHandler singleton;
 
826
};
 
827
 
 
828
static int sScriptedProxyHandlerFamily = 0;
 
829
 
 
830
ScriptedProxyHandler::ScriptedProxyHandler() : IndirectProxyHandler(&sScriptedProxyHandlerFamily)
 
831
{
 
832
}
 
833
 
 
834
ScriptedProxyHandler::~ScriptedProxyHandler()
 
835
{
 
836
}
 
837
 
 
838
static bool
 
839
ReturnedValueMustNotBePrimitive(JSContext *cx, JSObject *proxy, JSAtom *atom, const Value &v)
 
840
{
 
841
    if (v.isPrimitive()) {
 
842
        JSAutoByteString bytes;
 
843
        if (js_AtomToPrintableString(cx, atom, &bytes)) {
 
844
            RootedValue val(cx, ObjectOrNullValue(proxy));
 
845
            js_ReportValueError2(cx, JSMSG_BAD_TRAP_RETURN_VALUE,
 
846
                                 JSDVG_SEARCH_STACK, val, NullPtr(), bytes.ptr());
 
847
        }
 
848
        return false;
 
849
    }
 
850
    return true;
 
851
}
 
852
 
 
853
static JSObject *
 
854
GetProxyHandlerObject(JSContext *cx, JSObject *proxy)
 
855
{
 
856
    JS_ASSERT(OperationInProgress(cx, proxy));
 
857
    return GetProxyPrivate(proxy).toObjectOrNull();
 
858
}
 
859
 
 
860
bool
 
861
ScriptedProxyHandler::getPropertyDescriptor(JSContext *cx, JSObject *proxy_, jsid id_, bool set,
 
862
                                            PropertyDescriptor *desc)
 
863
{
 
864
    RootedId id(cx, id_);
 
865
    RootedObject proxy(cx, proxy_);
 
866
    RootedObject handler(cx, GetProxyHandlerObject(cx, proxy));
 
867
    RootedValue fval(cx), value(cx);
 
868
    return GetFundamentalTrap(cx, handler, ATOM(getPropertyDescriptor), &fval) &&
 
869
           Trap1(cx, handler, fval, id, value.address()) &&
 
870
           ((value.get().isUndefined() && IndicatePropertyNotFound(cx, desc)) ||
 
871
            (ReturnedValueMustNotBePrimitive(cx, proxy, ATOM(getPropertyDescriptor), value) &&
 
872
             ParsePropertyDescriptorObject(cx, proxy, value, desc)));
 
873
}
 
874
 
 
875
bool
 
876
ScriptedProxyHandler::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy_, jsid id_, bool set,
 
877
                                               PropertyDescriptor *desc)
 
878
{
 
879
    RootedId id(cx, id_);
 
880
    RootedObject proxy(cx, proxy_);
 
881
    RootedObject handler(cx, GetProxyHandlerObject(cx, proxy));
 
882
    RootedValue fval(cx), value(cx);
 
883
    return GetFundamentalTrap(cx, handler, ATOM(getOwnPropertyDescriptor), &fval) &&
 
884
           Trap1(cx, handler, fval, id, value.address()) &&
 
885
           ((value.get().isUndefined() && IndicatePropertyNotFound(cx, desc)) ||
 
886
            (ReturnedValueMustNotBePrimitive(cx, proxy, ATOM(getPropertyDescriptor), value) &&
 
887
             ParsePropertyDescriptorObject(cx, proxy, value, desc)));
 
888
}
 
889
 
 
890
bool
 
891
ScriptedProxyHandler::defineProperty(JSContext *cx, JSObject *proxy, jsid id_,
 
892
                                     PropertyDescriptor *desc)
 
893
{
 
894
    RootedObject handler(cx, GetProxyHandlerObject(cx, proxy));
 
895
    RootedValue fval(cx), value(cx);
 
896
    RootedId id(cx, id_);
 
897
    return GetFundamentalTrap(cx, handler, ATOM(defineProperty), &fval) &&
 
898
           NewPropertyDescriptorObject(cx, desc, value.address()) &&
 
899
           Trap2(cx, handler, fval, id, value, value.address());
 
900
}
 
901
 
 
902
bool
 
903
ScriptedProxyHandler::getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props)
 
904
{
 
905
    RootedObject handler(cx, GetProxyHandlerObject(cx, proxy));
 
906
    RootedValue fval(cx), value(cx);
 
907
    return GetFundamentalTrap(cx, handler, ATOM(getOwnPropertyNames), &fval) &&
 
908
           Trap(cx, handler, fval, 0, NULL, value.address()) &&
 
909
           ArrayToIdVector(cx, value, props);
 
910
}
 
911
 
 
912
bool
 
913
ScriptedProxyHandler::delete_(JSContext *cx, JSObject *proxy, jsid id_, bool *bp)
 
914
{
 
915
    RootedObject handler(cx, GetProxyHandlerObject(cx, proxy));
 
916
    RootedId id(cx, id_);
 
917
    RootedValue fval(cx), value(cx);
 
918
    return GetFundamentalTrap(cx, handler, ATOM(delete), &fval) &&
 
919
           Trap1(cx, handler, fval, id, value.address()) &&
 
920
           ValueToBool(cx, value, bp);
 
921
}
 
922
 
 
923
bool
 
924
ScriptedProxyHandler::enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props)
 
925
{
 
926
    RootedObject handler(cx, GetProxyHandlerObject(cx, proxy));
 
927
    RootedValue fval(cx), value(cx);
 
928
    return GetFundamentalTrap(cx, handler, ATOM(enumerate), &fval) &&
 
929
           Trap(cx, handler, fval, 0, NULL, value.address()) &&
 
930
           ArrayToIdVector(cx, value, props);
 
931
}
 
932
 
 
933
bool
 
934
ScriptedProxyHandler::has(JSContext *cx, JSObject *proxy_, jsid id_, bool *bp)
 
935
{
 
936
    RootedObject proxy(cx, proxy_);
 
937
    RootedId id(cx, id_);
 
938
    RootedObject handler(cx, GetProxyHandlerObject(cx, proxy));
 
939
    RootedValue fval(cx), value(cx);
 
940
    if (!GetDerivedTrap(cx, handler, ATOM(has), &fval))
 
941
        return false;
 
942
    if (!js_IsCallable(fval))
 
943
        return BaseProxyHandler::has(cx, proxy, id, bp);
 
944
    return Trap1(cx, handler, fval, id, value.address()) &&
 
945
           ValueToBool(cx, value, bp);
 
946
}
 
947
 
 
948
bool
 
949
ScriptedProxyHandler::hasOwn(JSContext *cx, JSObject *proxy_, jsid id_, bool *bp)
 
950
{
 
951
    RootedObject proxy(cx, proxy_);
 
952
    RootedId id(cx, id_);
 
953
    RootedObject handler(cx, GetProxyHandlerObject(cx, proxy));
 
954
    RootedValue fval(cx), value(cx);
 
955
    if (!GetDerivedTrap(cx, handler, ATOM(hasOwn), &fval))
 
956
        return false;
 
957
    if (!js_IsCallable(fval))
 
958
        return BaseProxyHandler::hasOwn(cx, proxy, id, bp);
 
959
    return Trap1(cx, handler, fval, id, value.address()) &&
 
960
           ValueToBool(cx, value, bp);
 
961
}
 
962
 
 
963
bool
 
964
ScriptedProxyHandler::get(JSContext *cx, JSObject *proxy_, JSObject *receiver_, jsid id_, Value *vp)
 
965
{
 
966
    RootedId id(cx, id_);
 
967
    RootedObject proxy(cx, proxy_), receiver(cx, receiver_);
 
968
    RootedObject handler(cx, GetProxyHandlerObject(cx, proxy));
 
969
    JSString *str = ToString(cx, IdToValue(id));
 
970
    if (!str)
 
971
        return false;
 
972
    RootedValue value(cx, StringValue(str));
 
973
    Value argv[] = { ObjectOrNullValue(receiver), value };
 
974
    AutoValueArray ava(cx, argv, 2);
 
975
    RootedValue fval(cx);
 
976
    if (!GetDerivedTrap(cx, handler, ATOM(get), &fval))
 
977
        return false;
 
978
    if (!js_IsCallable(fval))
 
979
        return BaseProxyHandler::get(cx, proxy, receiver, id, vp);
 
980
    return Trap(cx, handler, fval, 2, argv, vp);
 
981
}
 
982
 
 
983
bool
 
984
ScriptedProxyHandler::set(JSContext *cx, JSObject *proxy_, JSObject *receiver_, jsid id_, bool strict,
 
985
                          Value *vp)
 
986
{
 
987
    RootedId id(cx, id_);
 
988
    RootedObject proxy(cx, proxy_), receiver(cx, receiver_);
 
989
    RootedObject handler(cx, GetProxyHandlerObject(cx, proxy));
 
990
    JSString *str = ToString(cx, IdToValue(id));
 
991
    if (!str)
 
992
        return false;
 
993
    RootedValue value(cx, StringValue(str));
 
994
    Value argv[] = { ObjectOrNullValue(receiver), value, *vp };
 
995
    AutoValueArray ava(cx, argv, 3);
 
996
    RootedValue fval(cx);
 
997
    if (!GetDerivedTrap(cx, handler, ATOM(set), &fval))
 
998
        return false;
 
999
    if (!js_IsCallable(fval))
 
1000
        return BaseProxyHandler::set(cx, proxy, receiver, id, strict, vp);
 
1001
    return Trap(cx, handler, fval, 3, argv, value.address());
 
1002
}
 
1003
 
 
1004
bool
 
1005
ScriptedProxyHandler::keys(JSContext *cx, JSObject *proxy_, AutoIdVector &props)
 
1006
{
 
1007
    RootedObject proxy(cx, proxy_);
 
1008
    RootedObject handler(cx, GetProxyHandlerObject(cx, proxy));
 
1009
    RootedValue value(cx);
 
1010
    if (!GetDerivedTrap(cx, handler, ATOM(keys), &value))
 
1011
        return false;
 
1012
    if (!js_IsCallable(value))
 
1013
        return BaseProxyHandler::keys(cx, proxy, props);
 
1014
    return Trap(cx, handler, value, 0, NULL, value.address()) &&
 
1015
           ArrayToIdVector(cx, value, props);
 
1016
}
 
1017
 
 
1018
bool
 
1019
ScriptedProxyHandler::iterate(JSContext *cx, JSObject *proxy_, unsigned flags, Value *vp)
 
1020
{
 
1021
    RootedObject proxy(cx, proxy_);
 
1022
    RootedObject handler(cx, GetProxyHandlerObject(cx, proxy));
 
1023
    RootedValue value(cx);
 
1024
    if (!GetDerivedTrap(cx, handler, ATOM(iterate), &value))
 
1025
        return false;
 
1026
    if (!js_IsCallable(value))
 
1027
        return BaseProxyHandler::iterate(cx, proxy, flags, vp);
 
1028
    return Trap(cx, handler, value, 0, NULL, vp) &&
 
1029
           ReturnedValueMustNotBePrimitive(cx, proxy, ATOM(iterate), *vp);
 
1030
}
 
1031
 
 
1032
bool
 
1033
ScriptedProxyHandler::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
 
1034
                                 CallArgs args)
 
1035
{
 
1036
    return BaseProxyHandler::nativeCall(cx, test, impl, args);
 
1037
}
 
1038
 
 
1039
 
 
1040
JSType
 
1041
ScriptedProxyHandler::typeOf(JSContext *cx, JSObject *proxy)
 
1042
{
 
1043
    /*
 
1044
     * This function is only here to prevent a regression in
 
1045
     * js1_8_5/extensions/scripted-proxies.js. It will be removed when the
 
1046
     * direct proxy refactor is complete.
 
1047
     */
 
1048
    return BaseProxyHandler::typeOf(cx, proxy);
 
1049
}
 
1050
 
 
1051
bool
 
1052
ScriptedProxyHandler::defaultValue(JSContext *cx, JSObject *proxy, JSType hint,
 
1053
                                   Value *vp)
 
1054
{
 
1055
    /*
 
1056
     * This function is only here to prevent bug 757063. It will be removed when
 
1057
     * the direct proxy refactor is complete.
 
1058
     */
 
1059
    return BaseProxyHandler::defaultValue(cx, proxy, hint, vp);
 
1060
}
 
1061
 
 
1062
ScriptedProxyHandler ScriptedProxyHandler::singleton;
 
1063
 
 
1064
class AutoPendingProxyOperation {
 
1065
    JSRuntime               *rt;
 
1066
    PendingProxyOperation   op;
 
1067
  public:
 
1068
    AutoPendingProxyOperation(JSContext *cx, JSObject *proxy)
 
1069
        : rt(cx->runtime), op(cx, proxy)
 
1070
    {
 
1071
        op.next = rt->pendingProxyOperation;
 
1072
        rt->pendingProxyOperation = &op;
 
1073
    }
 
1074
 
 
1075
    ~AutoPendingProxyOperation() {
 
1076
        JS_ASSERT(rt->pendingProxyOperation == &op);
 
1077
        rt->pendingProxyOperation = op.next;
 
1078
    }
 
1079
};
 
1080
 
 
1081
#define INVOKE_ON_PROTOTYPE(cx, handler, proxy, protoCall)                   \
 
1082
    JS_BEGIN_MACRO                                                           \
 
1083
        RootedObject proto(cx);                                              \
 
1084
        if (!handler->getPrototypeOf(cx, proxy, proto.address()))            \
 
1085
            return false;                                                    \
 
1086
        if (!proto)                                                          \
 
1087
            return true;                                                     \
 
1088
        assertSameCompartment(cx, proxy, proto);                             \
 
1089
        return protoCall;                                                    \
 
1090
    JS_END_MACRO                                                             \
 
1091
 
 
1092
 
 
1093
bool
 
1094
Proxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy_, jsid id_, bool set,
 
1095
                             PropertyDescriptor *desc)
 
1096
{
 
1097
    JS_CHECK_RECURSION(cx, return false);
 
1098
    RootedObject proxy(cx, proxy_);
 
1099
    RootedId id(cx, id_);
 
1100
    AutoPendingProxyOperation pending(cx, proxy);
 
1101
    BaseProxyHandler *handler = GetProxyHandler(proxy);
 
1102
    if (!handler->hasPrototype())
 
1103
        return handler->getPropertyDescriptor(cx, proxy, id, set, desc);
 
1104
    if (!handler->getOwnPropertyDescriptor(cx, proxy, id, set, desc))
 
1105
        return false;
 
1106
    if (desc->obj)
 
1107
        return true;
 
1108
    INVOKE_ON_PROTOTYPE(cx, handler, proxy,
 
1109
                        JS_GetPropertyDescriptorById(cx, proto, id,
 
1110
                                                     JSRESOLVE_QUALIFIED, desc));
 
1111
}
 
1112
 
 
1113
bool
 
1114
Proxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set, Value *vp)
 
1115
{
 
1116
    JS_CHECK_RECURSION(cx, return false);
 
1117
    AutoPendingProxyOperation pending(cx, proxy);
 
1118
    AutoPropertyDescriptorRooter desc(cx);
 
1119
    return Proxy::getPropertyDescriptor(cx, proxy, id, set, &desc) &&
 
1120
           NewPropertyDescriptorObject(cx, &desc, vp);
 
1121
}
 
1122
 
 
1123
bool
 
1124
Proxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
 
1125
                                PropertyDescriptor *desc)
 
1126
{
 
1127
    JS_CHECK_RECURSION(cx, return false);
 
1128
    AutoPendingProxyOperation pending(cx, proxy);
 
1129
    return GetProxyHandler(proxy)->getOwnPropertyDescriptor(cx, proxy, id, set, desc);
 
1130
}
 
1131
 
 
1132
bool
 
1133
Proxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set, Value *vp)
 
1134
{
 
1135
    JS_CHECK_RECURSION(cx, return false);
 
1136
    AutoPendingProxyOperation pending(cx, proxy);
 
1137
    AutoPropertyDescriptorRooter desc(cx);
 
1138
    return Proxy::getOwnPropertyDescriptor(cx, proxy, id, set, &desc) &&
 
1139
           NewPropertyDescriptorObject(cx, &desc, vp);
 
1140
}
 
1141
 
 
1142
bool
 
1143
Proxy::defineProperty(JSContext *cx, JSObject *proxy, jsid id, PropertyDescriptor *desc)
 
1144
{
 
1145
    JS_CHECK_RECURSION(cx, return false);
 
1146
    AutoPendingProxyOperation pending(cx, proxy);
 
1147
    return GetProxyHandler(proxy)->defineProperty(cx, proxy, id, desc);
 
1148
}
 
1149
 
 
1150
bool
 
1151
Proxy::defineProperty(JSContext *cx, JSObject *proxy_, jsid id_, const Value &v)
 
1152
{
 
1153
    JS_CHECK_RECURSION(cx, return false);
 
1154
    RootedObject proxy(cx, proxy_);
 
1155
    RootedId id(cx, id_);
 
1156
    AutoPendingProxyOperation pending(cx, proxy);
 
1157
    AutoPropertyDescriptorRooter desc(cx);
 
1158
    return ParsePropertyDescriptorObject(cx, proxy, v, &desc) &&
 
1159
           Proxy::defineProperty(cx, proxy, id, &desc);
 
1160
}
 
1161
 
 
1162
bool
 
1163
Proxy::getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props)
 
1164
{
 
1165
    JS_CHECK_RECURSION(cx, return false);
 
1166
    AutoPendingProxyOperation pending(cx, proxy);
 
1167
    return GetProxyHandler(proxy)->getOwnPropertyNames(cx, proxy, props);
 
1168
}
 
1169
 
 
1170
bool
 
1171
Proxy::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
 
1172
{
 
1173
    JS_CHECK_RECURSION(cx, return false);
 
1174
    AutoPendingProxyOperation pending(cx, proxy);
 
1175
    return GetProxyHandler(proxy)->delete_(cx, proxy, id, bp);
 
1176
}
 
1177
 
 
1178
static bool
 
1179
AppendUnique(JSContext *cx, AutoIdVector &base, AutoIdVector &others)
 
1180
{
 
1181
    AutoIdVector uniqueOthers(cx);
 
1182
    if (!uniqueOthers.reserve(others.length()))
 
1183
        return false;
 
1184
    for (size_t i = 0; i < others.length(); ++i) {
 
1185
        bool unique = true;
 
1186
        for (size_t j = 0; j < base.length(); ++j) {
 
1187
            if (others[i] == base[j]) {
 
1188
                unique = false;
 
1189
                break;
 
1190
            }
 
1191
        }
 
1192
        if (unique)
 
1193
            uniqueOthers.append(others[i]);
 
1194
    }
 
1195
    return base.append(uniqueOthers);
 
1196
}
 
1197
 
 
1198
bool
 
1199
Proxy::enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props)
 
1200
{
 
1201
    JS_CHECK_RECURSION(cx, return false);
 
1202
    AutoPendingProxyOperation pending(cx, proxy);
 
1203
    BaseProxyHandler *handler = GetProxyHandler(proxy);
 
1204
    if (!handler->hasPrototype())
 
1205
        return GetProxyHandler(proxy)->enumerate(cx, proxy, props);
 
1206
    if (!handler->keys(cx, proxy, props))
 
1207
        return false;
 
1208
    AutoIdVector protoProps(cx);
 
1209
    INVOKE_ON_PROTOTYPE(cx, handler, proxy,
 
1210
                        GetPropertyNames(cx, proto, 0, &protoProps) &&
 
1211
                        AppendUnique(cx, props, protoProps));
 
1212
}
 
1213
 
 
1214
bool
 
1215
Proxy::has(JSContext *cx, JSObject *proxy_, jsid id_, bool *bp)
 
1216
{
 
1217
    JS_CHECK_RECURSION(cx, return false);
 
1218
    RootedObject proxy(cx, proxy_);
 
1219
    RootedId id(cx, id_);
 
1220
    AutoPendingProxyOperation pending(cx, proxy);
 
1221
    BaseProxyHandler *handler = GetProxyHandler(proxy);
 
1222
    if (!handler->hasPrototype())
 
1223
        return handler->has(cx, proxy, id, bp);
 
1224
    if (!handler->hasOwn(cx, proxy, id, bp))
 
1225
        return false;
 
1226
    if (*bp)
 
1227
        return true;
 
1228
    JSBool Bp;
 
1229
    INVOKE_ON_PROTOTYPE(cx, handler, proxy,
 
1230
                        JS_HasPropertyById(cx, proto, id, &Bp) &&
 
1231
                        ((*bp = Bp) || true));
 
1232
}
 
1233
 
 
1234
bool
 
1235
Proxy::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
 
1236
{
 
1237
    JS_CHECK_RECURSION(cx, return false);
 
1238
    AutoPendingProxyOperation pending(cx, proxy);
 
1239
    return GetProxyHandler(proxy)->hasOwn(cx, proxy, id, bp);
 
1240
}
 
1241
 
 
1242
bool
 
1243
Proxy::get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
 
1244
           MutableHandleValue vp)
 
1245
{
 
1246
    JS_CHECK_RECURSION(cx, return false);
 
1247
    AutoPendingProxyOperation pending(cx, proxy);
 
1248
    BaseProxyHandler *handler = GetProxyHandler(proxy);
 
1249
    bool own = false;
 
1250
    if (!handler->hasPrototype() || (handler->hasOwn(cx, proxy, id, &own) && own))
 
1251
        return handler->get(cx, proxy, receiver, id, vp.address());
 
1252
    INVOKE_ON_PROTOTYPE(cx, handler, proxy, JSObject::getGeneric(cx, proto, receiver, id, vp));
 
1253
}
 
1254
 
 
1255
bool
 
1256
Proxy::getElementIfPresent(JSContext *cx, HandleObject proxy, HandleObject receiver, uint32_t index,
 
1257
                           MutableHandleValue vp, bool *present)
 
1258
{
 
1259
    JS_CHECK_RECURSION(cx, return false);
 
1260
    AutoPendingProxyOperation pending(cx, proxy);
 
1261
    BaseProxyHandler *handler = GetProxyHandler(proxy);
 
1262
    bool hasOwn, status = true;
 
1263
    if (!handler->hasPrototype() ||
 
1264
        ((status = handler->hasOwn(cx, proxy, INT_TO_JSID(index), &hasOwn)) && hasOwn))
 
1265
    {
 
1266
        return GetProxyHandler(proxy)->getElementIfPresent(cx, proxy, receiver,
 
1267
                                                           index, vp.address(), present);
 
1268
    } else if (!status) {
 
1269
        return false;
 
1270
    }
 
1271
    INVOKE_ON_PROTOTYPE(cx, handler, proxy,
 
1272
                        JSObject::getElementIfPresent(cx, proto, receiver, index, vp, present));
 
1273
}
 
1274
 
 
1275
bool
 
1276
Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, bool strict,
 
1277
           MutableHandleValue vp)
 
1278
{
 
1279
    JS_CHECK_RECURSION(cx, return false);
 
1280
    AutoPendingProxyOperation pending(cx, proxy);
 
1281
    BaseProxyHandler *handler = GetProxyHandler(proxy);
 
1282
    RootedObject proto(cx);
 
1283
    if (handler->hasPrototype()) {
 
1284
        // If we're using a prototype, we still want to use the proxy trap unless
 
1285
        // we have a non-own property with a setter.
 
1286
        bool hasOwn;
 
1287
        AutoPropertyDescriptorRooter desc(cx);
 
1288
        if (handler->hasOwn(cx, proxy, id, &hasOwn) && !hasOwn &&
 
1289
            handler->getPrototypeOf(cx, proxy, proto.address()) && proto &&
 
1290
            JS_GetPropertyDescriptorById(cx, proto, id, JSRESOLVE_QUALIFIED, &desc) &&
 
1291
            desc.obj && desc.setter)
 
1292
        {
 
1293
            return JSObject::setGeneric(cx, proto, receiver, id, vp, strict);
 
1294
        } else if (cx->isExceptionPending()) {
 
1295
            return false;
 
1296
        }
 
1297
    }
 
1298
    return handler->set(cx, proxy, receiver, id, strict, vp.address());
 
1299
}
 
1300
 
 
1301
bool
 
1302
Proxy::keys(JSContext *cx, JSObject *proxy, AutoIdVector &props)
 
1303
{
 
1304
    JS_CHECK_RECURSION(cx, return false);
 
1305
    AutoPendingProxyOperation pending(cx, proxy);
 
1306
    return GetProxyHandler(proxy)->keys(cx, proxy, props);
 
1307
}
 
1308
 
 
1309
bool
 
1310
Proxy::iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleValue vp)
 
1311
{
 
1312
    JS_CHECK_RECURSION(cx, return false);
 
1313
    AutoPendingProxyOperation pending(cx, proxy);
 
1314
    BaseProxyHandler *handler = GetProxyHandler(proxy);
 
1315
    if (!handler->hasPrototype())
 
1316
        return GetProxyHandler(proxy)->iterate(cx, proxy, flags, vp.address());
 
1317
    AutoIdVector props(cx);
 
1318
    // The other Proxy::foo methods do the prototype-aware work for us here.
 
1319
    if ((flags & JSITER_OWNONLY)
 
1320
        ? !Proxy::keys(cx, proxy, props)
 
1321
        : !Proxy::enumerate(cx, proxy, props)) {
 
1322
        return false;
 
1323
    }
 
1324
    return EnumeratedIdVectorToIterator(cx, proxy, flags, props, vp);
 
1325
}
 
1326
 
 
1327
bool
 
1328
Proxy::call(JSContext *cx, JSObject *proxy, unsigned argc, Value *vp)
 
1329
{
 
1330
    JS_CHECK_RECURSION(cx, return false);
 
1331
    AutoPendingProxyOperation pending(cx, proxy);
 
1332
    return GetProxyHandler(proxy)->call(cx, proxy, argc, vp);
 
1333
}
 
1334
 
 
1335
bool
 
1336
Proxy::construct(JSContext *cx, JSObject *proxy, unsigned argc, Value *argv, Value *rval)
 
1337
{
 
1338
    JS_CHECK_RECURSION(cx, return false);
 
1339
    AutoPendingProxyOperation pending(cx, proxy);
 
1340
    return GetProxyHandler(proxy)->construct(cx, proxy, argc, argv, rval);
 
1341
}
 
1342
 
 
1343
bool
 
1344
Proxy::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args)
 
1345
{
 
1346
    JS_CHECK_RECURSION(cx, return false);
 
1347
    Rooted<JSObject*> proxy(cx, &args.thisv().toObject());
 
1348
    AutoPendingProxyOperation pending(cx, proxy);
 
1349
    return GetProxyHandler(proxy)->nativeCall(cx, test, impl, args);
 
1350
}
 
1351
 
 
1352
bool
 
1353
Proxy::hasInstance(JSContext *cx, JSObject *proxy, const js::Value *vp, bool *bp)
 
1354
{
 
1355
    JS_CHECK_RECURSION(cx, return false);
 
1356
    AutoPendingProxyOperation pending(cx, proxy);
 
1357
    return GetProxyHandler(proxy)->hasInstance(cx, proxy, vp, bp);
 
1358
}
 
1359
 
 
1360
JSType
 
1361
Proxy::typeOf(JSContext *cx, JSObject *proxy)
 
1362
{
 
1363
    // FIXME: API doesn't allow us to report error (bug 618906).
 
1364
    JS_CHECK_RECURSION(cx, return JSTYPE_OBJECT);
 
1365
    AutoPendingProxyOperation pending(cx, proxy);
 
1366
    return GetProxyHandler(proxy)->typeOf(cx, proxy);
 
1367
}
 
1368
 
 
1369
bool
 
1370
Proxy::objectClassIs(JSObject *proxy, ESClassValue classValue, JSContext *cx)
 
1371
{
 
1372
    AutoPendingProxyOperation pending(cx, proxy);
 
1373
    return GetProxyHandler(proxy)->objectClassIs(proxy, classValue, cx);
 
1374
}
 
1375
 
 
1376
JSString *
 
1377
Proxy::obj_toString(JSContext *cx, JSObject *proxy)
 
1378
{
 
1379
    JS_CHECK_RECURSION(cx, return NULL);
 
1380
    AutoPendingProxyOperation pending(cx, proxy);
 
1381
    return GetProxyHandler(proxy)->obj_toString(cx, proxy);
 
1382
}
 
1383
 
 
1384
JSString *
 
1385
Proxy::fun_toString(JSContext *cx, JSObject *proxy, unsigned indent)
 
1386
{
 
1387
    JS_CHECK_RECURSION(cx, return NULL);
 
1388
    AutoPendingProxyOperation pending(cx, proxy);
 
1389
    return GetProxyHandler(proxy)->fun_toString(cx, proxy, indent);
 
1390
}
 
1391
 
 
1392
bool
 
1393
Proxy::regexp_toShared(JSContext *cx, JSObject *proxy, RegExpGuard *g)
 
1394
{
 
1395
    JS_CHECK_RECURSION(cx, return false);
 
1396
    AutoPendingProxyOperation pending(cx, proxy);
 
1397
    return GetProxyHandler(proxy)->regexp_toShared(cx, proxy, g);
 
1398
}
 
1399
 
 
1400
bool
 
1401
Proxy::defaultValue(JSContext *cx, JSObject *proxy, JSType hint, Value *vp)
 
1402
{
 
1403
    JS_CHECK_RECURSION(cx, return false);
 
1404
    AutoPendingProxyOperation pending(cx, proxy);
 
1405
    return GetProxyHandler(proxy)->defaultValue(cx, proxy, hint, vp);
 
1406
}
 
1407
 
 
1408
bool
 
1409
Proxy::iteratorNext(JSContext *cx, JSObject *proxy, Value *vp)
 
1410
{
 
1411
    JS_CHECK_RECURSION(cx, return false);
 
1412
    AutoPendingProxyOperation pending(cx, proxy);
 
1413
    return GetProxyHandler(proxy)->iteratorNext(cx, proxy, vp);
 
1414
}
 
1415
 
 
1416
static JSObject *
 
1417
proxy_innerObject(JSContext *cx, HandleObject obj)
 
1418
{
 
1419
    return GetProxyPrivate(obj).toObjectOrNull();
 
1420
}
 
1421
 
 
1422
static JSBool
 
1423
proxy_LookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
 
1424
                    MutableHandleObject objp, MutableHandleShape propp)
 
1425
{
 
1426
    bool found;
 
1427
    if (!Proxy::has(cx, obj, id, &found))
 
1428
        return false;
 
1429
 
 
1430
    if (found) {
 
1431
        MarkNonNativePropertyFound(obj, propp);
 
1432
        objp.set(obj);
 
1433
    } else {
 
1434
        objp.set(NULL);
 
1435
        propp.set(NULL);
 
1436
    }
 
1437
    return true;
 
1438
}
 
1439
 
 
1440
static JSBool
 
1441
proxy_LookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
 
1442
                     MutableHandleObject objp, MutableHandleShape propp)
 
1443
{
 
1444
    Rooted<jsid> id(cx, NameToId(name));
 
1445
    return proxy_LookupGeneric(cx, obj, id, objp, propp);
 
1446
}
 
1447
 
 
1448
static JSBool
 
1449
proxy_LookupElement(JSContext *cx, HandleObject obj, uint32_t index,
 
1450
                    MutableHandleObject objp, MutableHandleShape propp)
 
1451
{
 
1452
    RootedId id(cx);
 
1453
    if (!IndexToId(cx, index, id.address()))
 
1454
        return false;
 
1455
    return proxy_LookupGeneric(cx, obj, id, objp, propp);
 
1456
}
 
1457
 
 
1458
static JSBool
 
1459
proxy_LookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
 
1460
                    MutableHandleObject objp, MutableHandleShape propp)
 
1461
{
 
1462
    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
 
1463
    return proxy_LookupGeneric(cx, obj, id, objp, propp);
 
1464
}
 
1465
 
 
1466
static JSBool
 
1467
proxy_DefineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue value,
 
1468
                    PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
 
1469
{
 
1470
    AutoPropertyDescriptorRooter desc(cx);
 
1471
    desc.obj = obj;
 
1472
    desc.value = value;
 
1473
    desc.attrs = (attrs & (~JSPROP_SHORTID));
 
1474
    desc.getter = getter;
 
1475
    desc.setter = setter;
 
1476
    desc.shortid = 0;
 
1477
    return Proxy::defineProperty(cx, obj, id, &desc);
 
1478
}
 
1479
 
 
1480
static JSBool
 
1481
proxy_DefineProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value,
 
1482
                     PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
 
1483
{
 
1484
    Rooted<jsid> id(cx, NameToId(name));
 
1485
    return proxy_DefineGeneric(cx, obj, id, value, getter, setter, attrs);
 
1486
}
 
1487
 
 
1488
static JSBool
 
1489
proxy_DefineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue value,
 
1490
                    PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
 
1491
{
 
1492
    RootedId id(cx);
 
1493
    if (!IndexToId(cx, index, id.address()))
 
1494
        return false;
 
1495
    return proxy_DefineGeneric(cx, obj, id, value, getter, setter, attrs);
 
1496
}
 
1497
 
 
1498
static JSBool
 
1499
proxy_DefineSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, HandleValue value,
 
1500
                    PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
 
1501
{
 
1502
    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
 
1503
    return proxy_DefineGeneric(cx, obj, id, value, getter, setter, attrs);
 
1504
}
 
1505
 
 
1506
static JSBool
 
1507
proxy_GetGeneric(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
 
1508
                 MutableHandleValue vp)
 
1509
{
 
1510
    return Proxy::get(cx, obj, receiver, id, vp);
 
1511
}
 
1512
 
 
1513
static JSBool
 
1514
proxy_GetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandlePropertyName name,
 
1515
                  MutableHandleValue vp)
 
1516
{
 
1517
    Rooted<jsid> id(cx, NameToId(name));
 
1518
    return proxy_GetGeneric(cx, obj, receiver, id, vp);
 
1519
}
 
1520
 
 
1521
static JSBool
 
1522
proxy_GetElement(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index,
 
1523
                 MutableHandleValue vp)
 
1524
{
 
1525
    RootedId id(cx);
 
1526
    if (!IndexToId(cx, index, id.address()))
 
1527
        return false;
 
1528
    return proxy_GetGeneric(cx, obj, receiver, id, vp);
 
1529
}
 
1530
 
 
1531
static JSBool
 
1532
proxy_GetElementIfPresent(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index,
 
1533
                          MutableHandleValue vp, bool *present)
 
1534
{
 
1535
    return Proxy::getElementIfPresent(cx, obj, receiver, index, vp, present);
 
1536
}
 
1537
 
 
1538
static JSBool
 
1539
proxy_GetSpecial(JSContext *cx, HandleObject obj, HandleObject receiver, HandleSpecialId sid,
 
1540
                 MutableHandleValue vp)
 
1541
{
 
1542
    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
 
1543
    return proxy_GetGeneric(cx, obj, receiver, id, vp);
 
1544
}
 
1545
 
 
1546
static JSBool
 
1547
proxy_SetGeneric(JSContext *cx, HandleObject obj, HandleId id,
 
1548
                 MutableHandleValue vp, JSBool strict)
 
1549
{
 
1550
    return Proxy::set(cx, obj, obj, id, strict, vp);
 
1551
}
 
1552
 
 
1553
static JSBool
 
1554
proxy_SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
 
1555
                  MutableHandleValue vp, JSBool strict)
 
1556
{
 
1557
    Rooted<jsid> id(cx, NameToId(name));
 
1558
    return proxy_SetGeneric(cx, obj, id, vp, strict);
 
1559
}
 
1560
 
 
1561
static JSBool
 
1562
proxy_SetElement(JSContext *cx, HandleObject obj, uint32_t index,
 
1563
                 MutableHandleValue vp, JSBool strict)
 
1564
{
 
1565
    RootedId id(cx);
 
1566
    if (!IndexToId(cx, index, id.address()))
 
1567
        return false;
 
1568
    return proxy_SetGeneric(cx, obj, id, vp, strict);
 
1569
}
 
1570
 
 
1571
static JSBool
 
1572
proxy_SetSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
 
1573
                 MutableHandleValue vp, JSBool strict)
 
1574
{
 
1575
    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
 
1576
    return proxy_SetGeneric(cx, obj, id, vp, strict);
 
1577
}
 
1578
 
 
1579
static JSBool
 
1580
proxy_GetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
 
1581
{
 
1582
    AutoPropertyDescriptorRooter desc(cx);
 
1583
    if (!Proxy::getOwnPropertyDescriptor(cx, obj, id, false, &desc))
 
1584
        return false;
 
1585
    *attrsp = desc.attrs;
 
1586
    return true;
 
1587
}
 
1588
 
 
1589
static JSBool
 
1590
proxy_GetPropertyAttributes(JSContext *cx, HandleObject obj, HandlePropertyName name, unsigned *attrsp)
 
1591
{
 
1592
    Rooted<jsid> id(cx, NameToId(name));
 
1593
    return proxy_GetGenericAttributes(cx, obj, id, attrsp);
 
1594
}
 
1595
 
 
1596
static JSBool
 
1597
proxy_GetElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp)
 
1598
{
 
1599
    RootedId id(cx);
 
1600
    if (!IndexToId(cx, index, id.address()))
 
1601
        return false;
 
1602
    return proxy_GetGenericAttributes(cx, obj, id, attrsp);
 
1603
}
 
1604
 
 
1605
static JSBool
 
1606
proxy_GetSpecialAttributes(JSContext *cx, HandleObject obj, HandleSpecialId sid, unsigned *attrsp)
 
1607
{
 
1608
    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
 
1609
    return proxy_GetGenericAttributes(cx, obj, id, attrsp);
 
1610
}
 
1611
 
 
1612
static JSBool
 
1613
proxy_SetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
 
1614
{
 
1615
    /* Lookup the current property descriptor so we have setter/getter/value. */
 
1616
    AutoPropertyDescriptorRooter desc(cx);
 
1617
    if (!Proxy::getOwnPropertyDescriptor(cx, obj, id, true, &desc))
 
1618
        return false;
 
1619
    desc.attrs = (*attrsp & (~JSPROP_SHORTID));
 
1620
    return Proxy::defineProperty(cx, obj, id, &desc);
 
1621
}
 
1622
 
 
1623
static JSBool
 
1624
proxy_SetPropertyAttributes(JSContext *cx, HandleObject obj, HandlePropertyName name, unsigned *attrsp)
 
1625
{
 
1626
    Rooted<jsid> id(cx, NameToId(name));
 
1627
    return proxy_SetGenericAttributes(cx, obj, id, attrsp);
 
1628
}
 
1629
 
 
1630
static JSBool
 
1631
proxy_SetElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp)
 
1632
{
 
1633
    RootedId id(cx);
 
1634
    if (!IndexToId(cx, index, id.address()))
 
1635
        return false;
 
1636
    return proxy_SetGenericAttributes(cx, obj, id, attrsp);
 
1637
}
 
1638
 
 
1639
static JSBool
 
1640
proxy_SetSpecialAttributes(JSContext *cx, HandleObject obj, HandleSpecialId sid, unsigned *attrsp)
 
1641
{
 
1642
    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
 
1643
    return proxy_SetGenericAttributes(cx, obj, id, attrsp);
 
1644
}
 
1645
 
 
1646
static JSBool
 
1647
proxy_DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id,
 
1648
                    MutableHandleValue rval, JSBool strict)
 
1649
{
 
1650
    // TODO: throwing away strict
 
1651
    bool deleted;
 
1652
    if (!Proxy::delete_(cx, obj, id, &deleted) || !js_SuppressDeletedProperty(cx, obj, id))
 
1653
        return false;
 
1654
    rval.setBoolean(deleted);
 
1655
    return true;
 
1656
}
 
1657
 
 
1658
static JSBool
 
1659
proxy_DeleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
 
1660
                     MutableHandleValue rval, JSBool strict)
 
1661
{
 
1662
    Rooted<jsid> id(cx, NameToId(name));
 
1663
    return proxy_DeleteGeneric(cx, obj, id, rval, strict);
 
1664
}
 
1665
 
 
1666
static JSBool
 
1667
proxy_DeleteElement(JSContext *cx, HandleObject obj, uint32_t index,
 
1668
                    MutableHandleValue rval, JSBool strict)
 
1669
{
 
1670
    RootedId id(cx);
 
1671
    if (!IndexToId(cx, index, id.address()))
 
1672
        return false;
 
1673
    return proxy_DeleteGeneric(cx, obj, id, rval, strict);
 
1674
}
 
1675
 
 
1676
static JSBool
 
1677
proxy_DeleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
 
1678
                    MutableHandleValue rval, JSBool strict)
 
1679
{
 
1680
    Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
 
1681
    return proxy_DeleteGeneric(cx, obj, id, rval, strict);
 
1682
}
 
1683
 
 
1684
static void
 
1685
proxy_TraceObject(JSTracer *trc, JSObject *obj)
 
1686
{
 
1687
#ifdef DEBUG
 
1688
    if (!trc->runtime->gcDisableStrictProxyCheckingCount && obj->isWrapper()) {
 
1689
        JSObject *referent = &GetProxyPrivate(obj).toObject();
 
1690
        if (referent->compartment() != obj->compartment()) {
 
1691
            /*
 
1692
             * Assert that this proxy is tracked in the wrapper map. We maintain
 
1693
             * the invariant that the wrapped object is the key in the wrapper map.
 
1694
             */
 
1695
            Value key = ObjectValue(*referent);
 
1696
            WrapperMap::Ptr p = obj->compartment()->crossCompartmentWrappers.lookup(key);
 
1697
            JS_ASSERT(*p->value.unsafeGet() == ObjectValue(*obj));
 
1698
        }
 
1699
    }
 
1700
#endif
 
1701
 
 
1702
    // NB: If you add new slots here, make sure to change
 
1703
    // js::NukeChromeCrossCompartmentWrappers to cope.
 
1704
    MarkCrossCompartmentSlot(trc, &obj->getReservedSlotRef(JSSLOT_PROXY_PRIVATE), "private");
 
1705
    MarkSlot(trc, &obj->getReservedSlotRef(JSSLOT_PROXY_EXTRA + 0), "extra0");
 
1706
    MarkSlot(trc, &obj->getReservedSlotRef(JSSLOT_PROXY_EXTRA + 1), "extra1");
 
1707
}
 
1708
 
 
1709
static void
 
1710
proxy_TraceFunction(JSTracer *trc, JSObject *obj)
 
1711
{
 
1712
    // NB: If you add new slots here, make sure to change
 
1713
    // js::NukeChromeCrossCompartmentWrappers to cope.
 
1714
    MarkCrossCompartmentSlot(trc, &GetCall(obj), "call");
 
1715
    MarkSlot(trc, &GetFunctionProxyConstruct(obj), "construct");
 
1716
    proxy_TraceObject(trc, obj);
 
1717
}
 
1718
 
 
1719
static JSObject *
 
1720
proxy_WeakmapKeyDelegate(RawObject obj)
 
1721
{
 
1722
    JS_ASSERT(obj->isProxy());
 
1723
    return GetProxyHandler(obj)->weakmapKeyDelegate(obj);
 
1724
}
 
1725
 
 
1726
static JSBool
 
1727
proxy_Convert(JSContext *cx, HandleObject proxy, JSType hint, MutableHandleValue vp)
 
1728
{
 
1729
    JS_ASSERT(proxy->isProxy());
 
1730
    return Proxy::defaultValue(cx, proxy, hint, vp.address());
 
1731
}
 
1732
 
 
1733
static void
 
1734
proxy_Finalize(FreeOp *fop, JSObject *obj)
 
1735
{
 
1736
    JS_ASSERT(obj->isProxy());
 
1737
    GetProxyHandler(obj)->finalize(fop, obj);
 
1738
}
 
1739
 
 
1740
static JSBool
 
1741
proxy_HasInstance(JSContext *cx, HandleObject proxy, const Value *v, JSBool *bp)
 
1742
{
 
1743
    AutoPendingProxyOperation pending(cx, proxy);
 
1744
    bool b;
 
1745
    if (!Proxy::hasInstance(cx, proxy, v, &b))
 
1746
        return false;
 
1747
    *bp = !!b;
 
1748
    return true;
 
1749
}
 
1750
 
 
1751
static JSType
 
1752
proxy_TypeOf(JSContext *cx, HandleObject proxy)
 
1753
{
 
1754
    JS_ASSERT(proxy->isProxy());
 
1755
    return Proxy::typeOf(cx, proxy);
 
1756
}
 
1757
 
 
1758
#define PROXY_CLASS_EXT                             \
 
1759
    {                                               \
 
1760
        NULL,                /* equality */         \
 
1761
        NULL,                /* outerObject */      \
 
1762
        NULL,                /* innerObject */      \
 
1763
        NULL,                /* iteratorObject */   \
 
1764
        NULL,                /* unused */           \
 
1765
        false,               /* isWrappedNative */  \
 
1766
        proxy_WeakmapKeyDelegate                    \
 
1767
    }
 
1768
 
 
1769
JS_FRIEND_DATA(Class) js::ObjectProxyClass = {
 
1770
    "Proxy",
 
1771
    Class::NON_NATIVE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(4),
 
1772
    JS_PropertyStub,         /* addProperty */
 
1773
    JS_PropertyStub,         /* delProperty */
 
1774
    JS_PropertyStub,         /* getProperty */
 
1775
    JS_StrictPropertyStub,   /* setProperty */
 
1776
    JS_EnumerateStub,
 
1777
    JS_ResolveStub,
 
1778
    proxy_Convert,
 
1779
    proxy_Finalize,          /* finalize    */
 
1780
    NULL,                    /* checkAccess */
 
1781
    NULL,                    /* call        */
 
1782
    proxy_HasInstance,       /* hasInstance */
 
1783
    NULL,                    /* construct   */
 
1784
    proxy_TraceObject,       /* trace       */
 
1785
    PROXY_CLASS_EXT,
 
1786
    {
 
1787
        proxy_LookupGeneric,
 
1788
        proxy_LookupProperty,
 
1789
        proxy_LookupElement,
 
1790
        proxy_LookupSpecial,
 
1791
        proxy_DefineGeneric,
 
1792
        proxy_DefineProperty,
 
1793
        proxy_DefineElement,
 
1794
        proxy_DefineSpecial,
 
1795
        proxy_GetGeneric,
 
1796
        proxy_GetProperty,
 
1797
        proxy_GetElement,
 
1798
        proxy_GetElementIfPresent,
 
1799
        proxy_GetSpecial,
 
1800
        proxy_SetGeneric,
 
1801
        proxy_SetProperty,
 
1802
        proxy_SetElement,
 
1803
        proxy_SetSpecial,
 
1804
        proxy_GetGenericAttributes,
 
1805
        proxy_GetPropertyAttributes,
 
1806
        proxy_GetElementAttributes,
 
1807
        proxy_GetSpecialAttributes,
 
1808
        proxy_SetGenericAttributes,
 
1809
        proxy_SetPropertyAttributes,
 
1810
        proxy_SetElementAttributes,
 
1811
        proxy_SetSpecialAttributes,
 
1812
        proxy_DeleteProperty,
 
1813
        proxy_DeleteElement,
 
1814
        proxy_DeleteSpecial,
 
1815
        NULL,                /* enumerate       */
 
1816
        proxy_TypeOf,
 
1817
        NULL,                /* thisObject      */
 
1818
        NULL,                /* clear           */
 
1819
    }
 
1820
};
 
1821
 
 
1822
JS_FRIEND_DATA(Class) js::OuterWindowProxyClass = {
 
1823
    "Proxy",
 
1824
    Class::NON_NATIVE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(4),
 
1825
    JS_PropertyStub,         /* addProperty */
 
1826
    JS_PropertyStub,         /* delProperty */
 
1827
    JS_PropertyStub,         /* getProperty */
 
1828
    JS_StrictPropertyStub,   /* setProperty */
 
1829
    JS_EnumerateStub,
 
1830
    JS_ResolveStub,
 
1831
    JS_ConvertStub,
 
1832
    proxy_Finalize,          /* finalize    */
 
1833
    NULL,                    /* checkAccess */
 
1834
    NULL,                    /* call        */
 
1835
    NULL,                    /* construct   */
 
1836
    NULL,                    /* hasInstance */
 
1837
    proxy_TraceObject,       /* trace       */
 
1838
    {
 
1839
        NULL,                /* equality    */
 
1840
        NULL,                /* outerObject */
 
1841
        proxy_innerObject,
 
1842
        NULL,                /* iteratorObject */
 
1843
        NULL,                /* unused */
 
1844
        false,               /* isWrappedNative */
 
1845
        proxy_WeakmapKeyDelegate
 
1846
    },
 
1847
    {
 
1848
        proxy_LookupGeneric,
 
1849
        proxy_LookupProperty,
 
1850
        proxy_LookupElement,
 
1851
        proxy_LookupSpecial,
 
1852
        proxy_DefineGeneric,
 
1853
        proxy_DefineProperty,
 
1854
        proxy_DefineElement,
 
1855
        proxy_DefineSpecial,
 
1856
        proxy_GetGeneric,
 
1857
        proxy_GetProperty,
 
1858
        proxy_GetElement,
 
1859
        proxy_GetElementIfPresent,
 
1860
        proxy_GetSpecial,
 
1861
        proxy_SetGeneric,
 
1862
        proxy_SetProperty,
 
1863
        proxy_SetElement,
 
1864
        proxy_SetSpecial,
 
1865
        proxy_GetGenericAttributes,
 
1866
        proxy_GetPropertyAttributes,
 
1867
        proxy_GetElementAttributes,
 
1868
        proxy_GetSpecialAttributes,
 
1869
        proxy_SetGenericAttributes,
 
1870
        proxy_SetPropertyAttributes,
 
1871
        proxy_SetElementAttributes,
 
1872
        proxy_SetSpecialAttributes,
 
1873
        proxy_DeleteProperty,
 
1874
        proxy_DeleteElement,
 
1875
        proxy_DeleteSpecial,
 
1876
        NULL,                /* enumerate       */
 
1877
        NULL,                /* typeof          */
 
1878
        NULL,                /* thisObject      */
 
1879
        NULL,                /* clear           */
 
1880
    }
 
1881
};
 
1882
 
 
1883
static JSBool
 
1884
proxy_Call(JSContext *cx, unsigned argc, Value *vp)
 
1885
{
 
1886
    JSObject *proxy = &JS_CALLEE(cx, vp).toObject();
 
1887
    JS_ASSERT(proxy->isProxy());
 
1888
    return Proxy::call(cx, proxy, argc, vp);
 
1889
}
 
1890
 
 
1891
static JSBool
 
1892
proxy_Construct(JSContext *cx, unsigned argc, Value *vp)
 
1893
{
 
1894
    JSObject *proxy = &JS_CALLEE(cx, vp).toObject();
 
1895
    JS_ASSERT(proxy->isProxy());
 
1896
    bool ok = Proxy::construct(cx, proxy, argc, JS_ARGV(cx, vp), vp);
 
1897
    return ok;
 
1898
}
 
1899
 
 
1900
JS_FRIEND_DATA(Class) js::FunctionProxyClass = {
 
1901
    "Proxy",
 
1902
    Class::NON_NATIVE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(6),
 
1903
    JS_PropertyStub,         /* addProperty */
 
1904
    JS_PropertyStub,         /* delProperty */
 
1905
    JS_PropertyStub,         /* getProperty */
 
1906
    JS_StrictPropertyStub,   /* setProperty */
 
1907
    JS_EnumerateStub,
 
1908
    JS_ResolveStub,
 
1909
    JS_ConvertStub,
 
1910
    proxy_Finalize,          /* finalize */
 
1911
    NULL,                    /* checkAccess */
 
1912
    proxy_Call,
 
1913
    FunctionClass.hasInstance,
 
1914
    proxy_Construct,
 
1915
    proxy_TraceFunction,     /* trace       */
 
1916
    PROXY_CLASS_EXT,
 
1917
    {
 
1918
        proxy_LookupGeneric,
 
1919
        proxy_LookupProperty,
 
1920
        proxy_LookupElement,
 
1921
        proxy_LookupSpecial,
 
1922
        proxy_DefineGeneric,
 
1923
        proxy_DefineProperty,
 
1924
        proxy_DefineElement,
 
1925
        proxy_DefineSpecial,
 
1926
        proxy_GetGeneric,
 
1927
        proxy_GetProperty,
 
1928
        proxy_GetElement,
 
1929
        proxy_GetElementIfPresent,
 
1930
        proxy_GetSpecial,
 
1931
        proxy_SetGeneric,
 
1932
        proxy_SetProperty,
 
1933
        proxy_SetElement,
 
1934
        proxy_SetSpecial,
 
1935
        proxy_GetGenericAttributes,
 
1936
        proxy_GetPropertyAttributes,
 
1937
        proxy_GetElementAttributes,
 
1938
        proxy_GetSpecialAttributes,
 
1939
        proxy_SetGenericAttributes,
 
1940
        proxy_SetPropertyAttributes,
 
1941
        proxy_SetElementAttributes,
 
1942
        proxy_SetSpecialAttributes,
 
1943
        proxy_DeleteProperty,
 
1944
        proxy_DeleteElement,
 
1945
        proxy_DeleteSpecial,
 
1946
        NULL,                /* enumerate       */
 
1947
        proxy_TypeOf,
 
1948
        NULL,                /* thisObject      */
 
1949
        NULL,                /* clear           */
 
1950
    }
 
1951
};
 
1952
 
 
1953
JS_FRIEND_API(JSObject *)
 
1954
js::NewProxyObject(JSContext *cx, BaseProxyHandler *handler, const Value &priv_, JSObject *proto_,
 
1955
                   JSObject *parent_, JSObject *call_, JSObject *construct_)
 
1956
{
 
1957
    RootedValue priv(cx, priv_);
 
1958
    RootedObject proto(cx, proto_), parent(cx, parent_), call(cx, call_), construct(cx, construct_);
 
1959
 
 
1960
    JS_ASSERT_IF(proto, cx->compartment == proto->compartment());
 
1961
    JS_ASSERT_IF(parent, cx->compartment == parent->compartment());
 
1962
    JS_ASSERT_IF(construct, cx->compartment == construct->compartment());
 
1963
    bool fun = call || construct;
 
1964
    Class *clasp;
 
1965
    if (fun)
 
1966
        clasp = &FunctionProxyClass;
 
1967
    else
 
1968
        clasp = handler->isOuterWindow() ? &OuterWindowProxyClass : &ObjectProxyClass;
 
1969
 
 
1970
    /*
 
1971
     * Eagerly mark properties unknown for proxies, so we don't try to track
 
1972
     * their properties and so that we don't need to walk the compartment if
 
1973
     * their prototype changes later.
 
1974
     */
 
1975
    if (proto && !proto->setNewTypeUnknown(cx))
 
1976
        return NULL;
 
1977
 
 
1978
    RootedObject obj(cx, NewObjectWithGivenProto(cx, clasp, proto, parent));
 
1979
    if (!obj)
 
1980
        return NULL;
 
1981
    obj->initSlot(JSSLOT_PROXY_HANDLER, PrivateValue(handler));
 
1982
    obj->initCrossCompartmentSlot(JSSLOT_PROXY_PRIVATE, priv);
 
1983
    if (fun) {
 
1984
        obj->initCrossCompartmentSlot(JSSLOT_PROXY_CALL, call ? ObjectValue(*call) : UndefinedValue());
 
1985
        if (construct) {
 
1986
            obj->initSlot(JSSLOT_PROXY_CONSTRUCT, ObjectValue(*construct));
 
1987
        }
 
1988
    }
 
1989
 
 
1990
    /* Don't track types of properties of proxies. */
 
1991
    MarkTypeObjectUnknownProperties(cx, obj->type());
 
1992
 
 
1993
    /* Mark the new proxy as having singleton type. */
 
1994
    if (clasp == &OuterWindowProxyClass && !JSObject::setSingletonType(cx, obj))
 
1995
        return NULL;
 
1996
 
 
1997
    return obj;
 
1998
}
 
1999
 
 
2000
static JSBool
 
2001
proxy_create(JSContext *cx, unsigned argc, Value *vp)
 
2002
{
 
2003
    if (argc < 1) {
 
2004
        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
 
2005
                             "create", "0", "s");
 
2006
        return false;
 
2007
    }
 
2008
    JSObject *handler = NonNullObject(cx, vp[2]);
 
2009
    if (!handler)
 
2010
        return false;
 
2011
    JSObject *proto, *parent = NULL;
 
2012
    if (argc > 1 && vp[3].isObject()) {
 
2013
        proto = &vp[3].toObject();
 
2014
        parent = proto->getParent();
 
2015
    } else {
 
2016
        JS_ASSERT(IsFunctionObject(vp[0]));
 
2017
        proto = NULL;
 
2018
    }
 
2019
    if (!parent)
 
2020
        parent = vp[0].toObject().getParent();
 
2021
    JSObject *proxy = NewProxyObject(cx, &ScriptedProxyHandler::singleton, ObjectValue(*handler),
 
2022
                                     proto, parent);
 
2023
    if (!proxy)
 
2024
        return false;
 
2025
 
 
2026
    vp->setObject(*proxy);
 
2027
    return true;
 
2028
}
 
2029
 
 
2030
static JSBool
 
2031
proxy_createFunction(JSContext *cx, unsigned argc, Value *vp)
 
2032
{
 
2033
    if (argc < 2) {
 
2034
        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
 
2035
                             "createFunction", "1", "");
 
2036
        return false;
 
2037
    }
 
2038
    JSObject *handler = NonNullObject(cx, vp[2]);
 
2039
    if (!handler)
 
2040
        return false;
 
2041
    JSObject *proto, *parent;
 
2042
    parent = vp[0].toObject().getParent();
 
2043
    proto = parent->global().getOrCreateFunctionPrototype(cx);
 
2044
    if (!proto)
 
2045
        return false;
 
2046
    parent = proto->getParent();
 
2047
 
 
2048
    JSObject *call = ValueToCallable(cx, &vp[3]);
 
2049
    if (!call)
 
2050
        return false;
 
2051
    JSObject *construct = NULL;
 
2052
    if (argc > 2) {
 
2053
        construct = ValueToCallable(cx, &vp[4]);
 
2054
        if (!construct)
 
2055
            return false;
 
2056
    }
 
2057
 
 
2058
    JSObject *proxy = NewProxyObject(cx, &ScriptedProxyHandler::singleton,
 
2059
                                     ObjectValue(*handler),
 
2060
                                     proto, parent, call, construct);
 
2061
    if (!proxy)
 
2062
        return false;
 
2063
 
 
2064
    vp->setObject(*proxy);
 
2065
    return true;
 
2066
}
 
2067
 
 
2068
static JSFunctionSpec static_methods[] = {
 
2069
    JS_FN("create",         proxy_create,          2, 0),
 
2070
    JS_FN("createFunction", proxy_createFunction,  3, 0),
 
2071
    JS_FS_END
 
2072
};
 
2073
 
 
2074
Class js::CallableObjectClass = {
 
2075
    "Function",
 
2076
    JSCLASS_HAS_RESERVED_SLOTS(2),
 
2077
    JS_PropertyStub,         /* addProperty */
 
2078
    JS_PropertyStub,         /* delProperty */
 
2079
    JS_PropertyStub,         /* getProperty */
 
2080
    JS_StrictPropertyStub,   /* setProperty */
 
2081
    JS_EnumerateStub,
 
2082
    JS_ResolveStub,
 
2083
    JS_ConvertStub,
 
2084
    NULL,                    /* finalize    */
 
2085
    NULL,                    /* checkAccess */
 
2086
    NULL,                    /* call        */
 
2087
    NULL                     /* construct   */
 
2088
};
 
2089
 
 
2090
Class js::ProxyClass = {
 
2091
    "Proxy",
 
2092
    JSCLASS_HAS_CACHED_PROTO(JSProto_Proxy),
 
2093
    JS_PropertyStub,         /* addProperty */
 
2094
    JS_PropertyStub,         /* delProperty */
 
2095
    JS_PropertyStub,         /* getProperty */
 
2096
    JS_StrictPropertyStub,   /* setProperty */
 
2097
    JS_EnumerateStub,
 
2098
    JS_ResolveStub,
 
2099
    JS_ConvertStub
 
2100
};
 
2101
 
 
2102
JS_FRIEND_API(JSObject *)
 
2103
js_InitProxyClass(JSContext *cx, JSObject *obj_)
 
2104
{
 
2105
    RootedObject obj(cx, obj_);
 
2106
    RootedObject module(cx, NewObjectWithClassProto(cx, &ProxyClass, NULL, obj));
 
2107
    if (!module || !JSObject::setSingletonType(cx, module))
 
2108
        return NULL;
 
2109
 
 
2110
    if (!JS_DefineProperty(cx, obj, "Proxy", OBJECT_TO_JSVAL(module),
 
2111
                           JS_PropertyStub, JS_StrictPropertyStub, 0)) {
 
2112
        return NULL;
 
2113
    }
 
2114
    if (!JS_DefineFunctions(cx, module, static_methods))
 
2115
        return NULL;
 
2116
 
 
2117
    MarkStandardClassInitializedNoProto(obj, &ProxyClass);
 
2118
 
 
2119
    return module;
 
2120
}