1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2
* vim: set ts=4 sw=4 et tw=99:
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/. */
18
#include "gc/Marking.h"
20
#include "jsatominlines.h"
21
#include "jsinferinlines.h"
22
#include "jsobjinlines.h"
24
#include "vm/RegExpObject-inl.h"
27
using namespace js::gc;
29
static inline HeapSlot &
30
GetCall(JSObject *proxy)
32
JS_ASSERT(IsFunctionProxy(proxy));
33
return proxy->getSlotRef(JSSLOT_PROXY_CALL);
37
GetConstruct(JSObject *proxy)
39
if (proxy->slotSpan() <= JSSLOT_PROXY_CONSTRUCT)
40
return UndefinedValue();
41
return proxy->getSlot(JSSLOT_PROXY_CONSTRUCT);
44
static inline HeapSlot &
45
GetFunctionProxyConstruct(JSObject *proxy)
47
JS_ASSERT(IsFunctionProxy(proxy));
48
JS_ASSERT(proxy->slotSpan() > JSSLOT_PROXY_CONSTRUCT);
49
return proxy->getSlotRef(JSSLOT_PROXY_CONSTRUCT);
54
OperationInProgress(JSContext *cx, JSObject *proxy)
56
PendingProxyOperation *op = cx->runtime->pendingProxyOperation;
58
if (op->object == proxy)
66
BaseProxyHandler::BaseProxyHandler(void *family)
72
BaseProxyHandler::~BaseProxyHandler()
77
BaseProxyHandler::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
79
JS_ASSERT(OperationInProgress(cx, proxy));
80
AutoPropertyDescriptorRooter desc(cx);
81
if (!getPropertyDescriptor(cx, proxy, id, false, &desc))
88
BaseProxyHandler::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
90
JS_ASSERT(OperationInProgress(cx, proxy));
91
AutoPropertyDescriptorRooter desc(cx);
92
if (!getOwnPropertyDescriptor(cx, proxy, id, false, &desc))
99
BaseProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver_, jsid id_, Value *vp)
101
RootedObject receiver(cx, receiver_);
102
RootedId id(cx, id_);
104
JS_ASSERT(OperationInProgress(cx, proxy));
105
AutoPropertyDescriptorRooter desc(cx);
106
if (!getPropertyDescriptor(cx, proxy, id, false, &desc))
113
(!(desc.attrs & JSPROP_GETTER) && desc.getter == JS_PropertyStub)) {
117
if (desc.attrs & JSPROP_GETTER)
118
return InvokeGetterOrSetter(cx, receiver, CastAsObjectJsval(desc.getter), 0, NULL, vp);
119
if (!(desc.attrs & JSPROP_SHARED))
123
if (desc.attrs & JSPROP_SHORTID)
124
id = INT_TO_JSID(desc.shortid);
126
RootedValue value(cx, *vp);
127
if (!CallJSPropertyOp(cx, desc.getter, receiver, id, &value))
135
BaseProxyHandler::getElementIfPresent(JSContext *cx, JSObject *proxy_, JSObject *receiver_, uint32_t index, Value *vp, bool *present)
137
RootedObject proxy(cx, proxy_);
138
RootedObject receiver(cx, receiver_);
141
if (!IndexToId(cx, index, &id))
144
if (!has(cx, proxy, id, present))
148
Debug_SetValueRangeToCrashOnTouch(vp, 1);
152
return get(cx, proxy, receiver, id, vp);
156
BaseProxyHandler::set(JSContext *cx, JSObject *proxy_, JSObject *receiver_, jsid id_, bool strict,
159
RootedObject proxy(cx, proxy_), receiver(cx, receiver_);
160
RootedId id(cx, id_);
162
JS_ASSERT(OperationInProgress(cx, proxy));
163
AutoPropertyDescriptorRooter desc(cx);
164
if (!getOwnPropertyDescriptor(cx, proxy, id, true, &desc))
166
/* The control-flow here differs from ::get() because of the fall-through case below. */
168
// Check for read-only properties.
169
if (desc.attrs & JSPROP_READONLY)
170
return strict ? Throw(cx, id, JSMSG_CANT_REDEFINE_PROP) : true;
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))
181
if (!proxy->isProxy() || GetProxyHandler(proxy) != this)
183
if (desc.attrs & JSPROP_SHARED)
187
// Same as above for the null setter case.
188
if (!(desc.attrs & JSPROP_GETTER))
189
desc.getter = JS_PropertyStub;
192
return defineProperty(cx, receiver, id, &desc);
194
if (!getPropertyDescriptor(cx, proxy, id, true, &desc))
197
// Check for read-only properties.
198
if (desc.attrs & JSPROP_READONLY)
199
return strict ? Throw(cx, id, JSMSG_CANT_REDEFINE_PROP) : true;
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))
210
if (!proxy->isProxy() || GetProxyHandler(proxy) != this)
212
if (desc.attrs & JSPROP_SHARED)
216
// Same as above for the null setter case.
217
if (!(desc.attrs & JSPROP_GETTER))
218
desc.getter = JS_PropertyStub;
221
return defineProperty(cx, receiver, id, &desc);
226
desc.attrs = JSPROP_ENUMERATE;
229
desc.setter = NULL; // Pick up the class getter/setter.
230
return defineProperty(cx, receiver, id, &desc);
234
BaseProxyHandler::keys(JSContext *cx, JSObject *proxy, AutoIdVector &props)
236
JS_ASSERT(OperationInProgress(cx, proxy));
237
JS_ASSERT(props.length() == 0);
239
if (!getOwnPropertyNames(cx, proxy, props))
242
/* Select only the enumerable properties through in-place iteration. */
243
AutoPropertyDescriptorRooter desc(cx);
245
for (size_t j = 0, len = props.length(); j < len; j++) {
248
if (!getOwnPropertyDescriptor(cx, proxy, id, false, &desc))
250
if (desc.obj && (desc.attrs & JSPROP_ENUMERATE))
254
JS_ASSERT(i <= props.length());
261
BaseProxyHandler::iterate(JSContext *cx, JSObject *proxy_, unsigned flags, Value *vp)
263
RootedObject proxy(cx, proxy_);
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)) {
273
RootedValue value(cx);
274
if (!EnumeratedIdVectorToIterator(cx, proxy, flags, props, &value))
282
BaseProxyHandler::call(JSContext *cx, JSObject *proxy, unsigned argc,
285
return ReportIsNotFunction(cx, UndefinedValue());
289
BaseProxyHandler::construct(JSContext *cx, JSObject *proxy, unsigned argc,
290
Value *argv, Value *rval)
292
return ReportIsNotFunction(cx, UndefinedValue(), CONSTRUCT);
296
BaseProxyHandler::obj_toString(JSContext *cx, JSObject *proxy)
298
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
299
JSMSG_INCOMPATIBLE_PROTO,
300
js_Object_str, js_toString_str,
306
BaseProxyHandler::fun_toString(JSContext *cx, JSObject *proxy, unsigned indent)
308
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
309
JSMSG_INCOMPATIBLE_PROTO,
310
js_Function_str, js_toString_str,
316
BaseProxyHandler::regexp_toShared(JSContext *cx, JSObject *proxy,
319
JS_NOT_REACHED("This should have been a wrapped regexp");
324
BaseProxyHandler::defaultValue(JSContext *cx, JSObject *proxy, JSType hint,
327
Rooted<JSObject*> obj(cx, proxy);
328
RootedValue value(cx);
329
if (!DefaultValue(cx, obj, hint, &value))
337
BaseProxyHandler::iteratorNext(JSContext *cx, JSObject *proxy, Value *vp)
339
vp->setMagic(JS_NO_ITER_VALUE);
344
BaseProxyHandler::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args)
346
JS_ASSERT(OperationInProgress(cx, &args.thisv().toObject()));
347
ReportIncompatible(cx, args);
352
BaseProxyHandler::hasInstance(JSContext *cx, JSObject *proxy, const Value *vp, bool *bp)
354
JS_ASSERT(OperationInProgress(cx, proxy));
356
RootedValue val(cx, ObjectValue(*proxy));
357
js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
358
JSDVG_SEARCH_STACK, val, NullPtr());
363
BaseProxyHandler::typeOf(JSContext *cx, JSObject *proxy)
365
JS_ASSERT(OperationInProgress(cx, proxy));
366
return IsFunctionProxy(proxy) ? JSTYPE_FUNCTION : JSTYPE_OBJECT;
370
BaseProxyHandler::objectClassIs(JSObject *proxy, ESClassValue classValue, JSContext *cx)
372
JS_ASSERT(OperationInProgress(cx, proxy));
377
BaseProxyHandler::finalize(JSFreeOp *fop, JSObject *proxy)
382
BaseProxyHandler::weakmapKeyDelegate(JSObject *proxy)
388
BaseProxyHandler::getPrototypeOf(JSContext *cx, JSObject *proxy, JSObject **proto)
390
// The default implementation here just uses proto of the proxy object.
391
JS_ASSERT(hasPrototype());
392
*proto = proxy->getProto();
396
IndirectProxyHandler::IndirectProxyHandler(void *family) : BaseProxyHandler(family)
401
IndirectProxyHandler::getPropertyDescriptor(JSContext *cx, JSObject *proxy,
403
PropertyDescriptor *desc)
405
RootedObject target(cx, GetProxyTargetObject(proxy));
406
return JS_GetPropertyDescriptorById(cx, target, id, JSRESOLVE_QUALIFIED, desc);
410
GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, jsid id, unsigned flags,
411
JSPropertyDescriptor *desc)
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.
416
return Proxy::getOwnPropertyDescriptor(cx, obj, id,
417
flags & JSRESOLVE_ASSIGNING,
420
if (!JS_GetPropertyDescriptorById(cx, obj, id, flags, desc))
422
if (desc->obj != obj)
428
IndirectProxyHandler::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy,
430
PropertyDescriptor *desc)
432
RootedObject target(cx, GetProxyTargetObject(proxy));
433
return GetOwnPropertyDescriptor(cx, target, id, JSRESOLVE_QUALIFIED, desc);
437
IndirectProxyHandler::defineProperty(JSContext *cx, JSObject *proxy, jsid id_,
438
PropertyDescriptor *desc)
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);
448
IndirectProxyHandler::getOwnPropertyNames(JSContext *cx, JSObject *proxy,
451
RootedObject target(cx, GetProxyTargetObject(proxy));
452
return GetPropertyNames(cx, target, JSITER_OWNONLY | JSITER_HIDDEN, &props);
456
IndirectProxyHandler::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
459
RootedObject target(cx, GetProxyTargetObject(proxy));
460
if (!JS_DeletePropertyById2(cx, target, id, &v))
463
if (!JS_ValueToBoolean(cx, v, &b))
470
IndirectProxyHandler::enumerate(JSContext *cx, JSObject *proxy,
473
RootedObject target(cx, GetProxyTargetObject(proxy));
474
return GetPropertyNames(cx, target, 0, &props);
478
IndirectProxyHandler::call(JSContext *cx, JSObject *proxy, unsigned argc,
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());
485
JS_SET_RVAL(cx, vp, rval.value());
490
IndirectProxyHandler::construct(JSContext *cx, JSObject *proxy, unsigned argc,
491
Value *argv, Value *rval)
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);
501
IndirectProxyHandler::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
504
args.setThis(ObjectValue(*GetProxyTargetObject(&args.thisv().toObject())));
505
if (!test(args.thisv())) {
506
ReportIncompatible(cx, args);
510
return CallNativeImpl(cx, impl, args);
514
IndirectProxyHandler::hasInstance(JSContext *cx, JSObject *proxy, const Value *vp,
518
RootedObject target(cx, GetProxyTargetObject(proxy));
519
if (!JS_HasInstance(cx, target, *vp, &b))
526
IndirectProxyHandler::typeOf(JSContext *cx, JSObject *proxy)
528
return TypeOfValue(cx, ObjectValue(*GetProxyTargetObject(proxy)));
532
IndirectProxyHandler::objectClassIs(JSObject *proxy, ESClassValue classValue,
535
return ObjectClassIs(*GetProxyTargetObject(proxy), classValue, cx);
539
IndirectProxyHandler::obj_toString(JSContext *cx, JSObject *proxy)
541
return obj_toStringHelper(cx, GetProxyTargetObject(proxy));
545
IndirectProxyHandler::fun_toString(JSContext *cx, JSObject *proxy,
548
return fun_toStringHelper(cx, GetProxyTargetObject(proxy), indent);
552
IndirectProxyHandler::regexp_toShared(JSContext *cx, JSObject *proxy,
555
return RegExpToShared(cx, *GetProxyTargetObject(proxy), g);
559
IndirectProxyHandler::defaultValue(JSContext *cx, JSObject *proxy, JSType hint,
562
*vp = ObjectValue(*GetProxyTargetObject(proxy));
563
if (hint == JSTYPE_VOID)
564
return ToPrimitive(cx, vp);
565
return ToPrimitive(cx, hint, vp);
569
IndirectProxyHandler::iteratorNext(JSContext *cx, JSObject *proxy, Value *vp)
571
Rooted<JSObject*> target(cx, GetProxyTargetObject(proxy));
572
RootedValue value(cx);
573
if (!js_IteratorMore(cx, target, &value))
576
if (vp->toBoolean()) {
578
cx->iterValue = UndefinedValue();
580
*vp = MagicValue(JS_NO_ITER_VALUE);
586
IndirectProxyHandler::weakmapKeyDelegate(JSObject *proxy)
588
return UnwrapObject(proxy);
591
DirectProxyHandler::DirectProxyHandler(void *family)
592
: IndirectProxyHandler(family)
597
DirectProxyHandler::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
600
RootedObject target(cx, GetProxyTargetObject(proxy));
601
if (!JS_HasPropertyById(cx, target, id, &found))
608
DirectProxyHandler::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
610
RootedObject target(cx, GetProxyTargetObject(proxy));
611
AutoPropertyDescriptorRooter desc(cx);
612
if (!JS_GetPropertyDescriptorById(cx, target, id, JSRESOLVE_QUALIFIED, &desc))
614
*bp = (desc.obj == target);
619
DirectProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver_,
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))
634
DirectProxyHandler::set(JSContext *cx, JSObject *proxy, JSObject *receiverArg,
635
jsid id_, bool strict, Value *vp)
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))
649
DirectProxyHandler::keys(JSContext *cx, JSObject *proxy, AutoIdVector &props)
651
return GetPropertyNames(cx, GetProxyTargetObject(proxy), JSITER_OWNONLY, &props);
655
DirectProxyHandler::iterate(JSContext *cx, JSObject *proxy, unsigned flags,
658
Rooted<JSObject*> target(cx, GetProxyTargetObject(proxy));
659
RootedValue value(cx);
660
if (!GetIterator(cx, target, flags, &value))
668
GetTrap(JSContext *cx, HandleObject handler, HandlePropertyName name, MutableHandleValue fvalp)
670
JS_CHECK_RECURSION(cx, return false);
672
return JSObject::getProperty(cx, handler, handler, name, fvalp);
676
GetFundamentalTrap(JSContext *cx, HandleObject handler, HandlePropertyName name, MutableHandleValue fvalp)
678
if (!GetTrap(cx, handler, name, fvalp))
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());
692
GetDerivedTrap(JSContext *cx, HandleObject handler, HandlePropertyName name, MutableHandleValue fvalp)
694
JS_ASSERT(name == ATOM(has) ||
695
name == ATOM(hasOwn) ||
698
name == ATOM(keys) ||
699
name == ATOM(iterate));
701
return GetTrap(cx, handler, name, fvalp);
705
Trap(JSContext *cx, HandleObject handler, HandleValue fval, unsigned argc, Value* argv, Value *rval)
707
return Invoke(cx, ObjectValue(*handler), fval, argc, argv, rval);
711
Trap1(JSContext *cx, HandleObject handler, HandleValue fval, HandleId id, Value *rval)
713
JSString *str = ToString(cx, IdToValue(id));
716
rval->setString(str);
717
return Trap(cx, handler, fval, 1, rval, rval);
721
Trap2(JSContext *cx, HandleObject handler, HandleValue fval, HandleId id, Value v_, Value *rval)
723
RootedValue v(cx, v_);
724
JSString *str = ToString(cx, IdToValue(id));
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);
734
ParsePropertyDescriptorObject(JSContext *cx, HandleObject obj, const Value &v,
735
PropertyDescriptor *desc)
737
AutoPropDescArrayRooter descs(cx);
738
PropDesc *d = descs.append();
739
if (!d || !d->initialize(cx, v))
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();
752
IndicatePropertyNotFound(JSContext *cx, PropertyDescriptor *desc)
759
ValueToBool(JSContext *cx, const Value &v, bool *bp)
766
ArrayToIdVector(JSContext *cx, const Value &array, AutoIdVector &props)
768
JS_ASSERT(props.length() == 0);
770
if (array.isPrimitive())
773
RootedObject obj(cx, &array.toObject());
775
if (!GetLengthProperty(cx, obj, &length))
779
for (uint32_t n = 0; n < length; ++n) {
780
if (!JS_CHECK_OPERATION_LIMIT(cx))
782
if (!JSObject::getElement(cx, obj, obj, n, &v))
785
if (!ValueToId(cx, v, &id))
787
if (!props.append(id))
794
/* Derived class for all scripted proxy handlers. */
795
class ScriptedProxyHandler : public IndirectProxyHandler {
797
ScriptedProxyHandler();
798
virtual ~ScriptedProxyHandler();
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);
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,
817
virtual bool keys(JSContext *cx, JSObject *proxy, AutoIdVector &props);
818
virtual bool iterate(JSContext *cx, JSObject *proxy, unsigned flags, Value *vp);
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);
825
static ScriptedProxyHandler singleton;
828
static int sScriptedProxyHandlerFamily = 0;
830
ScriptedProxyHandler::ScriptedProxyHandler() : IndirectProxyHandler(&sScriptedProxyHandlerFamily)
834
ScriptedProxyHandler::~ScriptedProxyHandler()
839
ReturnedValueMustNotBePrimitive(JSContext *cx, JSObject *proxy, JSAtom *atom, const Value &v)
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());
854
GetProxyHandlerObject(JSContext *cx, JSObject *proxy)
856
JS_ASSERT(OperationInProgress(cx, proxy));
857
return GetProxyPrivate(proxy).toObjectOrNull();
861
ScriptedProxyHandler::getPropertyDescriptor(JSContext *cx, JSObject *proxy_, jsid id_, bool set,
862
PropertyDescriptor *desc)
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)));
876
ScriptedProxyHandler::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy_, jsid id_, bool set,
877
PropertyDescriptor *desc)
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)));
891
ScriptedProxyHandler::defineProperty(JSContext *cx, JSObject *proxy, jsid id_,
892
PropertyDescriptor *desc)
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());
903
ScriptedProxyHandler::getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props)
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);
913
ScriptedProxyHandler::delete_(JSContext *cx, JSObject *proxy, jsid id_, bool *bp)
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);
924
ScriptedProxyHandler::enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props)
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);
934
ScriptedProxyHandler::has(JSContext *cx, JSObject *proxy_, jsid id_, bool *bp)
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))
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);
949
ScriptedProxyHandler::hasOwn(JSContext *cx, JSObject *proxy_, jsid id_, bool *bp)
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))
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);
964
ScriptedProxyHandler::get(JSContext *cx, JSObject *proxy_, JSObject *receiver_, jsid id_, Value *vp)
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));
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))
978
if (!js_IsCallable(fval))
979
return BaseProxyHandler::get(cx, proxy, receiver, id, vp);
980
return Trap(cx, handler, fval, 2, argv, vp);
984
ScriptedProxyHandler::set(JSContext *cx, JSObject *proxy_, JSObject *receiver_, jsid id_, bool strict,
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));
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))
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());
1005
ScriptedProxyHandler::keys(JSContext *cx, JSObject *proxy_, AutoIdVector &props)
1007
RootedObject proxy(cx, proxy_);
1008
RootedObject handler(cx, GetProxyHandlerObject(cx, proxy));
1009
RootedValue value(cx);
1010
if (!GetDerivedTrap(cx, handler, ATOM(keys), &value))
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);
1019
ScriptedProxyHandler::iterate(JSContext *cx, JSObject *proxy_, unsigned flags, Value *vp)
1021
RootedObject proxy(cx, proxy_);
1022
RootedObject handler(cx, GetProxyHandlerObject(cx, proxy));
1023
RootedValue value(cx);
1024
if (!GetDerivedTrap(cx, handler, ATOM(iterate), &value))
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);
1033
ScriptedProxyHandler::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
1036
return BaseProxyHandler::nativeCall(cx, test, impl, args);
1041
ScriptedProxyHandler::typeOf(JSContext *cx, JSObject *proxy)
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.
1048
return BaseProxyHandler::typeOf(cx, proxy);
1052
ScriptedProxyHandler::defaultValue(JSContext *cx, JSObject *proxy, JSType hint,
1056
* This function is only here to prevent bug 757063. It will be removed when
1057
* the direct proxy refactor is complete.
1059
return BaseProxyHandler::defaultValue(cx, proxy, hint, vp);
1062
ScriptedProxyHandler ScriptedProxyHandler::singleton;
1064
class AutoPendingProxyOperation {
1066
PendingProxyOperation op;
1068
AutoPendingProxyOperation(JSContext *cx, JSObject *proxy)
1069
: rt(cx->runtime), op(cx, proxy)
1071
op.next = rt->pendingProxyOperation;
1072
rt->pendingProxyOperation = &op;
1075
~AutoPendingProxyOperation() {
1076
JS_ASSERT(rt->pendingProxyOperation == &op);
1077
rt->pendingProxyOperation = op.next;
1081
#define INVOKE_ON_PROTOTYPE(cx, handler, proxy, protoCall) \
1083
RootedObject proto(cx); \
1084
if (!handler->getPrototypeOf(cx, proxy, proto.address())) \
1088
assertSameCompartment(cx, proxy, proto); \
1094
Proxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy_, jsid id_, bool set,
1095
PropertyDescriptor *desc)
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))
1108
INVOKE_ON_PROTOTYPE(cx, handler, proxy,
1109
JS_GetPropertyDescriptorById(cx, proto, id,
1110
JSRESOLVE_QUALIFIED, desc));
1114
Proxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set, Value *vp)
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);
1124
Proxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set,
1125
PropertyDescriptor *desc)
1127
JS_CHECK_RECURSION(cx, return false);
1128
AutoPendingProxyOperation pending(cx, proxy);
1129
return GetProxyHandler(proxy)->getOwnPropertyDescriptor(cx, proxy, id, set, desc);
1133
Proxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, bool set, Value *vp)
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);
1143
Proxy::defineProperty(JSContext *cx, JSObject *proxy, jsid id, PropertyDescriptor *desc)
1145
JS_CHECK_RECURSION(cx, return false);
1146
AutoPendingProxyOperation pending(cx, proxy);
1147
return GetProxyHandler(proxy)->defineProperty(cx, proxy, id, desc);
1151
Proxy::defineProperty(JSContext *cx, JSObject *proxy_, jsid id_, const Value &v)
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);
1163
Proxy::getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props)
1165
JS_CHECK_RECURSION(cx, return false);
1166
AutoPendingProxyOperation pending(cx, proxy);
1167
return GetProxyHandler(proxy)->getOwnPropertyNames(cx, proxy, props);
1171
Proxy::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
1173
JS_CHECK_RECURSION(cx, return false);
1174
AutoPendingProxyOperation pending(cx, proxy);
1175
return GetProxyHandler(proxy)->delete_(cx, proxy, id, bp);
1179
AppendUnique(JSContext *cx, AutoIdVector &base, AutoIdVector &others)
1181
AutoIdVector uniqueOthers(cx);
1182
if (!uniqueOthers.reserve(others.length()))
1184
for (size_t i = 0; i < others.length(); ++i) {
1186
for (size_t j = 0; j < base.length(); ++j) {
1187
if (others[i] == base[j]) {
1193
uniqueOthers.append(others[i]);
1195
return base.append(uniqueOthers);
1199
Proxy::enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props)
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))
1208
AutoIdVector protoProps(cx);
1209
INVOKE_ON_PROTOTYPE(cx, handler, proxy,
1210
GetPropertyNames(cx, proto, 0, &protoProps) &&
1211
AppendUnique(cx, props, protoProps));
1215
Proxy::has(JSContext *cx, JSObject *proxy_, jsid id_, bool *bp)
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))
1229
INVOKE_ON_PROTOTYPE(cx, handler, proxy,
1230
JS_HasPropertyById(cx, proto, id, &Bp) &&
1231
((*bp = Bp) || true));
1235
Proxy::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp)
1237
JS_CHECK_RECURSION(cx, return false);
1238
AutoPendingProxyOperation pending(cx, proxy);
1239
return GetProxyHandler(proxy)->hasOwn(cx, proxy, id, bp);
1243
Proxy::get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
1244
MutableHandleValue vp)
1246
JS_CHECK_RECURSION(cx, return false);
1247
AutoPendingProxyOperation pending(cx, proxy);
1248
BaseProxyHandler *handler = GetProxyHandler(proxy);
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));
1256
Proxy::getElementIfPresent(JSContext *cx, HandleObject proxy, HandleObject receiver, uint32_t index,
1257
MutableHandleValue vp, bool *present)
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))
1266
return GetProxyHandler(proxy)->getElementIfPresent(cx, proxy, receiver,
1267
index, vp.address(), present);
1268
} else if (!status) {
1271
INVOKE_ON_PROTOTYPE(cx, handler, proxy,
1272
JSObject::getElementIfPresent(cx, proto, receiver, index, vp, present));
1276
Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, bool strict,
1277
MutableHandleValue vp)
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.
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)
1293
return JSObject::setGeneric(cx, proto, receiver, id, vp, strict);
1294
} else if (cx->isExceptionPending()) {
1298
return handler->set(cx, proxy, receiver, id, strict, vp.address());
1302
Proxy::keys(JSContext *cx, JSObject *proxy, AutoIdVector &props)
1304
JS_CHECK_RECURSION(cx, return false);
1305
AutoPendingProxyOperation pending(cx, proxy);
1306
return GetProxyHandler(proxy)->keys(cx, proxy, props);
1310
Proxy::iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleValue vp)
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)) {
1324
return EnumeratedIdVectorToIterator(cx, proxy, flags, props, vp);
1328
Proxy::call(JSContext *cx, JSObject *proxy, unsigned argc, Value *vp)
1330
JS_CHECK_RECURSION(cx, return false);
1331
AutoPendingProxyOperation pending(cx, proxy);
1332
return GetProxyHandler(proxy)->call(cx, proxy, argc, vp);
1336
Proxy::construct(JSContext *cx, JSObject *proxy, unsigned argc, Value *argv, Value *rval)
1338
JS_CHECK_RECURSION(cx, return false);
1339
AutoPendingProxyOperation pending(cx, proxy);
1340
return GetProxyHandler(proxy)->construct(cx, proxy, argc, argv, rval);
1344
Proxy::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args)
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);
1353
Proxy::hasInstance(JSContext *cx, JSObject *proxy, const js::Value *vp, bool *bp)
1355
JS_CHECK_RECURSION(cx, return false);
1356
AutoPendingProxyOperation pending(cx, proxy);
1357
return GetProxyHandler(proxy)->hasInstance(cx, proxy, vp, bp);
1361
Proxy::typeOf(JSContext *cx, JSObject *proxy)
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);
1370
Proxy::objectClassIs(JSObject *proxy, ESClassValue classValue, JSContext *cx)
1372
AutoPendingProxyOperation pending(cx, proxy);
1373
return GetProxyHandler(proxy)->objectClassIs(proxy, classValue, cx);
1377
Proxy::obj_toString(JSContext *cx, JSObject *proxy)
1379
JS_CHECK_RECURSION(cx, return NULL);
1380
AutoPendingProxyOperation pending(cx, proxy);
1381
return GetProxyHandler(proxy)->obj_toString(cx, proxy);
1385
Proxy::fun_toString(JSContext *cx, JSObject *proxy, unsigned indent)
1387
JS_CHECK_RECURSION(cx, return NULL);
1388
AutoPendingProxyOperation pending(cx, proxy);
1389
return GetProxyHandler(proxy)->fun_toString(cx, proxy, indent);
1393
Proxy::regexp_toShared(JSContext *cx, JSObject *proxy, RegExpGuard *g)
1395
JS_CHECK_RECURSION(cx, return false);
1396
AutoPendingProxyOperation pending(cx, proxy);
1397
return GetProxyHandler(proxy)->regexp_toShared(cx, proxy, g);
1401
Proxy::defaultValue(JSContext *cx, JSObject *proxy, JSType hint, Value *vp)
1403
JS_CHECK_RECURSION(cx, return false);
1404
AutoPendingProxyOperation pending(cx, proxy);
1405
return GetProxyHandler(proxy)->defaultValue(cx, proxy, hint, vp);
1409
Proxy::iteratorNext(JSContext *cx, JSObject *proxy, Value *vp)
1411
JS_CHECK_RECURSION(cx, return false);
1412
AutoPendingProxyOperation pending(cx, proxy);
1413
return GetProxyHandler(proxy)->iteratorNext(cx, proxy, vp);
1417
proxy_innerObject(JSContext *cx, HandleObject obj)
1419
return GetProxyPrivate(obj).toObjectOrNull();
1423
proxy_LookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
1424
MutableHandleObject objp, MutableHandleShape propp)
1427
if (!Proxy::has(cx, obj, id, &found))
1431
MarkNonNativePropertyFound(obj, propp);
1441
proxy_LookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
1442
MutableHandleObject objp, MutableHandleShape propp)
1444
Rooted<jsid> id(cx, NameToId(name));
1445
return proxy_LookupGeneric(cx, obj, id, objp, propp);
1449
proxy_LookupElement(JSContext *cx, HandleObject obj, uint32_t index,
1450
MutableHandleObject objp, MutableHandleShape propp)
1453
if (!IndexToId(cx, index, id.address()))
1455
return proxy_LookupGeneric(cx, obj, id, objp, propp);
1459
proxy_LookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
1460
MutableHandleObject objp, MutableHandleShape propp)
1462
Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
1463
return proxy_LookupGeneric(cx, obj, id, objp, propp);
1467
proxy_DefineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue value,
1468
PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
1470
AutoPropertyDescriptorRooter desc(cx);
1473
desc.attrs = (attrs & (~JSPROP_SHORTID));
1474
desc.getter = getter;
1475
desc.setter = setter;
1477
return Proxy::defineProperty(cx, obj, id, &desc);
1481
proxy_DefineProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value,
1482
PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
1484
Rooted<jsid> id(cx, NameToId(name));
1485
return proxy_DefineGeneric(cx, obj, id, value, getter, setter, attrs);
1489
proxy_DefineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue value,
1490
PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
1493
if (!IndexToId(cx, index, id.address()))
1495
return proxy_DefineGeneric(cx, obj, id, value, getter, setter, attrs);
1499
proxy_DefineSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, HandleValue value,
1500
PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
1502
Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
1503
return proxy_DefineGeneric(cx, obj, id, value, getter, setter, attrs);
1507
proxy_GetGeneric(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
1508
MutableHandleValue vp)
1510
return Proxy::get(cx, obj, receiver, id, vp);
1514
proxy_GetProperty(JSContext *cx, HandleObject obj, HandleObject receiver, HandlePropertyName name,
1515
MutableHandleValue vp)
1517
Rooted<jsid> id(cx, NameToId(name));
1518
return proxy_GetGeneric(cx, obj, receiver, id, vp);
1522
proxy_GetElement(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index,
1523
MutableHandleValue vp)
1526
if (!IndexToId(cx, index, id.address()))
1528
return proxy_GetGeneric(cx, obj, receiver, id, vp);
1532
proxy_GetElementIfPresent(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index,
1533
MutableHandleValue vp, bool *present)
1535
return Proxy::getElementIfPresent(cx, obj, receiver, index, vp, present);
1539
proxy_GetSpecial(JSContext *cx, HandleObject obj, HandleObject receiver, HandleSpecialId sid,
1540
MutableHandleValue vp)
1542
Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
1543
return proxy_GetGeneric(cx, obj, receiver, id, vp);
1547
proxy_SetGeneric(JSContext *cx, HandleObject obj, HandleId id,
1548
MutableHandleValue vp, JSBool strict)
1550
return Proxy::set(cx, obj, obj, id, strict, vp);
1554
proxy_SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
1555
MutableHandleValue vp, JSBool strict)
1557
Rooted<jsid> id(cx, NameToId(name));
1558
return proxy_SetGeneric(cx, obj, id, vp, strict);
1562
proxy_SetElement(JSContext *cx, HandleObject obj, uint32_t index,
1563
MutableHandleValue vp, JSBool strict)
1566
if (!IndexToId(cx, index, id.address()))
1568
return proxy_SetGeneric(cx, obj, id, vp, strict);
1572
proxy_SetSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
1573
MutableHandleValue vp, JSBool strict)
1575
Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
1576
return proxy_SetGeneric(cx, obj, id, vp, strict);
1580
proxy_GetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
1582
AutoPropertyDescriptorRooter desc(cx);
1583
if (!Proxy::getOwnPropertyDescriptor(cx, obj, id, false, &desc))
1585
*attrsp = desc.attrs;
1590
proxy_GetPropertyAttributes(JSContext *cx, HandleObject obj, HandlePropertyName name, unsigned *attrsp)
1592
Rooted<jsid> id(cx, NameToId(name));
1593
return proxy_GetGenericAttributes(cx, obj, id, attrsp);
1597
proxy_GetElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp)
1600
if (!IndexToId(cx, index, id.address()))
1602
return proxy_GetGenericAttributes(cx, obj, id, attrsp);
1606
proxy_GetSpecialAttributes(JSContext *cx, HandleObject obj, HandleSpecialId sid, unsigned *attrsp)
1608
Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
1609
return proxy_GetGenericAttributes(cx, obj, id, attrsp);
1613
proxy_SetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
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))
1619
desc.attrs = (*attrsp & (~JSPROP_SHORTID));
1620
return Proxy::defineProperty(cx, obj, id, &desc);
1624
proxy_SetPropertyAttributes(JSContext *cx, HandleObject obj, HandlePropertyName name, unsigned *attrsp)
1626
Rooted<jsid> id(cx, NameToId(name));
1627
return proxy_SetGenericAttributes(cx, obj, id, attrsp);
1631
proxy_SetElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp)
1634
if (!IndexToId(cx, index, id.address()))
1636
return proxy_SetGenericAttributes(cx, obj, id, attrsp);
1640
proxy_SetSpecialAttributes(JSContext *cx, HandleObject obj, HandleSpecialId sid, unsigned *attrsp)
1642
Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
1643
return proxy_SetGenericAttributes(cx, obj, id, attrsp);
1647
proxy_DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id,
1648
MutableHandleValue rval, JSBool strict)
1650
// TODO: throwing away strict
1652
if (!Proxy::delete_(cx, obj, id, &deleted) || !js_SuppressDeletedProperty(cx, obj, id))
1654
rval.setBoolean(deleted);
1659
proxy_DeleteProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
1660
MutableHandleValue rval, JSBool strict)
1662
Rooted<jsid> id(cx, NameToId(name));
1663
return proxy_DeleteGeneric(cx, obj, id, rval, strict);
1667
proxy_DeleteElement(JSContext *cx, HandleObject obj, uint32_t index,
1668
MutableHandleValue rval, JSBool strict)
1671
if (!IndexToId(cx, index, id.address()))
1673
return proxy_DeleteGeneric(cx, obj, id, rval, strict);
1677
proxy_DeleteSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
1678
MutableHandleValue rval, JSBool strict)
1680
Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
1681
return proxy_DeleteGeneric(cx, obj, id, rval, strict);
1685
proxy_TraceObject(JSTracer *trc, JSObject *obj)
1688
if (!trc->runtime->gcDisableStrictProxyCheckingCount && obj->isWrapper()) {
1689
JSObject *referent = &GetProxyPrivate(obj).toObject();
1690
if (referent->compartment() != obj->compartment()) {
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.
1695
Value key = ObjectValue(*referent);
1696
WrapperMap::Ptr p = obj->compartment()->crossCompartmentWrappers.lookup(key);
1697
JS_ASSERT(*p->value.unsafeGet() == ObjectValue(*obj));
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");
1710
proxy_TraceFunction(JSTracer *trc, JSObject *obj)
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);
1720
proxy_WeakmapKeyDelegate(RawObject obj)
1722
JS_ASSERT(obj->isProxy());
1723
return GetProxyHandler(obj)->weakmapKeyDelegate(obj);
1727
proxy_Convert(JSContext *cx, HandleObject proxy, JSType hint, MutableHandleValue vp)
1729
JS_ASSERT(proxy->isProxy());
1730
return Proxy::defaultValue(cx, proxy, hint, vp.address());
1734
proxy_Finalize(FreeOp *fop, JSObject *obj)
1736
JS_ASSERT(obj->isProxy());
1737
GetProxyHandler(obj)->finalize(fop, obj);
1741
proxy_HasInstance(JSContext *cx, HandleObject proxy, const Value *v, JSBool *bp)
1743
AutoPendingProxyOperation pending(cx, proxy);
1745
if (!Proxy::hasInstance(cx, proxy, v, &b))
1752
proxy_TypeOf(JSContext *cx, HandleObject proxy)
1754
JS_ASSERT(proxy->isProxy());
1755
return Proxy::typeOf(cx, proxy);
1758
#define PROXY_CLASS_EXT \
1760
NULL, /* equality */ \
1761
NULL, /* outerObject */ \
1762
NULL, /* innerObject */ \
1763
NULL, /* iteratorObject */ \
1764
NULL, /* unused */ \
1765
false, /* isWrappedNative */ \
1766
proxy_WeakmapKeyDelegate \
1769
JS_FRIEND_DATA(Class) js::ObjectProxyClass = {
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 */
1779
proxy_Finalize, /* finalize */
1780
NULL, /* checkAccess */
1782
proxy_HasInstance, /* hasInstance */
1783
NULL, /* construct */
1784
proxy_TraceObject, /* trace */
1787
proxy_LookupGeneric,
1788
proxy_LookupProperty,
1789
proxy_LookupElement,
1790
proxy_LookupSpecial,
1791
proxy_DefineGeneric,
1792
proxy_DefineProperty,
1793
proxy_DefineElement,
1794
proxy_DefineSpecial,
1798
proxy_GetElementIfPresent,
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 */
1817
NULL, /* thisObject */
1822
JS_FRIEND_DATA(Class) js::OuterWindowProxyClass = {
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 */
1832
proxy_Finalize, /* finalize */
1833
NULL, /* checkAccess */
1835
NULL, /* construct */
1836
NULL, /* hasInstance */
1837
proxy_TraceObject, /* trace */
1839
NULL, /* equality */
1840
NULL, /* outerObject */
1842
NULL, /* iteratorObject */
1844
false, /* isWrappedNative */
1845
proxy_WeakmapKeyDelegate
1848
proxy_LookupGeneric,
1849
proxy_LookupProperty,
1850
proxy_LookupElement,
1851
proxy_LookupSpecial,
1852
proxy_DefineGeneric,
1853
proxy_DefineProperty,
1854
proxy_DefineElement,
1855
proxy_DefineSpecial,
1859
proxy_GetElementIfPresent,
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 */
1878
NULL, /* thisObject */
1884
proxy_Call(JSContext *cx, unsigned argc, Value *vp)
1886
JSObject *proxy = &JS_CALLEE(cx, vp).toObject();
1887
JS_ASSERT(proxy->isProxy());
1888
return Proxy::call(cx, proxy, argc, vp);
1892
proxy_Construct(JSContext *cx, unsigned argc, Value *vp)
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);
1900
JS_FRIEND_DATA(Class) js::FunctionProxyClass = {
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 */
1910
proxy_Finalize, /* finalize */
1911
NULL, /* checkAccess */
1913
FunctionClass.hasInstance,
1915
proxy_TraceFunction, /* trace */
1918
proxy_LookupGeneric,
1919
proxy_LookupProperty,
1920
proxy_LookupElement,
1921
proxy_LookupSpecial,
1922
proxy_DefineGeneric,
1923
proxy_DefineProperty,
1924
proxy_DefineElement,
1925
proxy_DefineSpecial,
1929
proxy_GetElementIfPresent,
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 */
1948
NULL, /* thisObject */
1953
JS_FRIEND_API(JSObject *)
1954
js::NewProxyObject(JSContext *cx, BaseProxyHandler *handler, const Value &priv_, JSObject *proto_,
1955
JSObject *parent_, JSObject *call_, JSObject *construct_)
1957
RootedValue priv(cx, priv_);
1958
RootedObject proto(cx, proto_), parent(cx, parent_), call(cx, call_), construct(cx, construct_);
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;
1966
clasp = &FunctionProxyClass;
1968
clasp = handler->isOuterWindow() ? &OuterWindowProxyClass : &ObjectProxyClass;
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.
1975
if (proto && !proto->setNewTypeUnknown(cx))
1978
RootedObject obj(cx, NewObjectWithGivenProto(cx, clasp, proto, parent));
1981
obj->initSlot(JSSLOT_PROXY_HANDLER, PrivateValue(handler));
1982
obj->initCrossCompartmentSlot(JSSLOT_PROXY_PRIVATE, priv);
1984
obj->initCrossCompartmentSlot(JSSLOT_PROXY_CALL, call ? ObjectValue(*call) : UndefinedValue());
1986
obj->initSlot(JSSLOT_PROXY_CONSTRUCT, ObjectValue(*construct));
1990
/* Don't track types of properties of proxies. */
1991
MarkTypeObjectUnknownProperties(cx, obj->type());
1993
/* Mark the new proxy as having singleton type. */
1994
if (clasp == &OuterWindowProxyClass && !JSObject::setSingletonType(cx, obj))
2001
proxy_create(JSContext *cx, unsigned argc, Value *vp)
2004
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
2005
"create", "0", "s");
2008
JSObject *handler = NonNullObject(cx, vp[2]);
2011
JSObject *proto, *parent = NULL;
2012
if (argc > 1 && vp[3].isObject()) {
2013
proto = &vp[3].toObject();
2014
parent = proto->getParent();
2016
JS_ASSERT(IsFunctionObject(vp[0]));
2020
parent = vp[0].toObject().getParent();
2021
JSObject *proxy = NewProxyObject(cx, &ScriptedProxyHandler::singleton, ObjectValue(*handler),
2026
vp->setObject(*proxy);
2031
proxy_createFunction(JSContext *cx, unsigned argc, Value *vp)
2034
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
2035
"createFunction", "1", "");
2038
JSObject *handler = NonNullObject(cx, vp[2]);
2041
JSObject *proto, *parent;
2042
parent = vp[0].toObject().getParent();
2043
proto = parent->global().getOrCreateFunctionPrototype(cx);
2046
parent = proto->getParent();
2048
JSObject *call = ValueToCallable(cx, &vp[3]);
2051
JSObject *construct = NULL;
2053
construct = ValueToCallable(cx, &vp[4]);
2058
JSObject *proxy = NewProxyObject(cx, &ScriptedProxyHandler::singleton,
2059
ObjectValue(*handler),
2060
proto, parent, call, construct);
2064
vp->setObject(*proxy);
2068
static JSFunctionSpec static_methods[] = {
2069
JS_FN("create", proxy_create, 2, 0),
2070
JS_FN("createFunction", proxy_createFunction, 3, 0),
2074
Class js::CallableObjectClass = {
2076
JSCLASS_HAS_RESERVED_SLOTS(2),
2077
JS_PropertyStub, /* addProperty */
2078
JS_PropertyStub, /* delProperty */
2079
JS_PropertyStub, /* getProperty */
2080
JS_StrictPropertyStub, /* setProperty */
2084
NULL, /* finalize */
2085
NULL, /* checkAccess */
2087
NULL /* construct */
2090
Class js::ProxyClass = {
2092
JSCLASS_HAS_CACHED_PROTO(JSProto_Proxy),
2093
JS_PropertyStub, /* addProperty */
2094
JS_PropertyStub, /* delProperty */
2095
JS_PropertyStub, /* getProperty */
2096
JS_StrictPropertyStub, /* setProperty */
2102
JS_FRIEND_API(JSObject *)
2103
js_InitProxyClass(JSContext *cx, JSObject *obj_)
2105
RootedObject obj(cx, obj_);
2106
RootedObject module(cx, NewObjectWithClassProto(cx, &ProxyClass, NULL, obj));
2107
if (!module || !JSObject::setSingletonType(cx, module))
2110
if (!JS_DefineProperty(cx, obj, "Proxy", OBJECT_TO_JSVAL(module),
2111
JS_PropertyStub, JS_StrictPropertyStub, 0)) {
2114
if (!JS_DefineFunctions(cx, module, static_methods))
2117
MarkStandardClassInitializedNoProto(obj, &ProxyClass);