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 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
17 * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
20 * The Initial Developer of the Original Code is
22 * Portions created by the Initial Developer are Copyright (C) 2009
23 * the Initial Developer. All Rights Reserved.
26 * Andreas Gal <gal@mozilla.com>
28 * Alternatively, the contents of this file may be used under the terms of
29 * either of the GNU General Public License Version 2 or later (the "GPL"),
30 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 * in which case the provisions of the GPL or the LGPL are applicable instead
32 * of those above. If you wish to allow use of your version of this file only
33 * under the terms of either the GPL or the LGPL, and not to allow others to
34 * use your version of this file under the terms of the MPL, indicate your
35 * decision by deleting the provisions above and replace them with the notice
36 * and other provisions required by the GPL or the LGPL. If you do not delete
37 * the provisions above, a recipient may use your version of this file under
38 * the terms of any one of the MPL, the GPL or the LGPL.
40 * ***** END LICENSE BLOCK ***** */
51 #include "jsobjinlines.h"
54 using namespace js::gc
;
58 static inline const Value
&
59 GetCall(JSObject
*proxy
) {
60 JS_ASSERT(proxy
->isFunctionProxy());
61 return proxy
->getSlot(JSSLOT_PROXY_CALL
);
65 GetConstruct(JSObject
*proxy
) {
66 if (proxy
->numSlots() <= JSSLOT_PROXY_CONSTRUCT
)
67 return UndefinedValue();
68 return proxy
->getSlot(JSSLOT_PROXY_CONSTRUCT
);
72 OperationInProgress(JSContext
*cx
, JSObject
*proxy
)
74 JSPendingProxyOperation
*op
= JS_THREAD_DATA(cx
)->pendingProxyOperation
;
76 if (op
->object
== proxy
)
83 JSProxyHandler::JSProxyHandler(void *family
) : mFamily(family
)
87 JSProxyHandler::~JSProxyHandler()
92 JSProxyHandler::has(JSContext
*cx
, JSObject
*proxy
, jsid id
, bool *bp
)
94 JS_ASSERT(OperationInProgress(cx
, proxy
));
95 AutoPropertyDescriptorRooter
desc(cx
);
96 if (!getPropertyDescriptor(cx
, proxy
, id
, false, &desc
))
103 JSProxyHandler::hasOwn(JSContext
*cx
, JSObject
*proxy
, jsid id
, bool *bp
)
105 JS_ASSERT(OperationInProgress(cx
, proxy
));
106 AutoPropertyDescriptorRooter
desc(cx
);
107 if (!getOwnPropertyDescriptor(cx
, proxy
, id
, false, &desc
))
114 JSProxyHandler::get(JSContext
*cx
, JSObject
*proxy
, JSObject
*receiver
, jsid id
, Value
*vp
)
116 JS_ASSERT(OperationInProgress(cx
, proxy
));
117 AutoPropertyDescriptorRooter
desc(cx
);
118 if (!getPropertyDescriptor(cx
, proxy
, id
, false, &desc
))
125 (!(desc
.attrs
& JSPROP_GETTER
) && desc
.getter
== PropertyStub
)) {
129 if (desc
.attrs
& JSPROP_GETTER
) {
130 return ExternalGetOrSet(cx
, receiver
, id
, CastAsObjectJsval(desc
.getter
),
131 JSACC_READ
, 0, NULL
, vp
);
133 if (!(desc
.attrs
& JSPROP_SHARED
))
137 if (desc
.attrs
& JSPROP_SHORTID
)
138 id
= INT_TO_JSID(desc
.shortid
);
139 return CallJSPropertyOp(cx
, desc
.getter
, receiver
, id
, vp
);
143 JSProxyHandler::set(JSContext
*cx
, JSObject
*proxy
, JSObject
*receiver
, jsid id
, bool strict
,
146 JS_ASSERT(OperationInProgress(cx
, proxy
));
147 AutoPropertyDescriptorRooter
desc(cx
);
148 if (!getOwnPropertyDescriptor(cx
, proxy
, id
, true, &desc
))
150 /* The control-flow here differs from ::get() because of the fall-through case below. */
152 if (desc
.attrs
& JSPROP_READONLY
)
154 if (desc
.setter
&& ((desc
.attrs
& JSPROP_SETTER
) || desc
.setter
!= StrictPropertyStub
)) {
155 if (!CallSetter(cx
, receiver
, id
, desc
.setter
, desc
.attrs
, desc
.shortid
, strict
, vp
))
157 if (desc
.attrs
& JSPROP_SHARED
)
161 desc
.getter
= PropertyStub
;
163 desc
.setter
= StrictPropertyStub
;
165 return defineProperty(cx
, receiver
, id
, &desc
);
167 if (!getPropertyDescriptor(cx
, proxy
, id
, true, &desc
))
170 if (desc
.attrs
& JSPROP_READONLY
)
172 if (desc
.setter
&& ((desc
.attrs
& JSPROP_SETTER
) || desc
.setter
!= StrictPropertyStub
)) {
173 if (!CallSetter(cx
, receiver
, id
, desc
.setter
, desc
.attrs
, desc
.shortid
, strict
, vp
))
175 if (desc
.attrs
& JSPROP_SHARED
)
179 desc
.getter
= PropertyStub
;
181 desc
.setter
= StrictPropertyStub
;
182 return defineProperty(cx
, receiver
, id
, &desc
);
187 desc
.attrs
= JSPROP_ENUMERATE
;
190 desc
.setter
= NULL
; // Pick up the class getter/setter.
191 return defineProperty(cx
, receiver
, id
, &desc
);
195 JSProxyHandler::keys(JSContext
*cx
, JSObject
*proxy
, AutoIdVector
&props
)
197 JS_ASSERT(OperationInProgress(cx
, proxy
));
198 JS_ASSERT(props
.length() == 0);
200 if (!getOwnPropertyNames(cx
, proxy
, props
))
203 /* Select only the enumerable properties through in-place iteration. */
204 AutoPropertyDescriptorRooter
desc(cx
);
206 for (size_t j
= 0, len
= props
.length(); j
< len
; j
++) {
209 if (!getOwnPropertyDescriptor(cx
, proxy
, id
, false, &desc
))
211 if (desc
.obj
&& (desc
.attrs
& JSPROP_ENUMERATE
))
215 JS_ASSERT(i
<= props
.length());
222 JSProxyHandler::iterate(JSContext
*cx
, JSObject
*proxy
, uintN flags
, Value
*vp
)
224 JS_ASSERT(OperationInProgress(cx
, proxy
));
225 AutoIdVector
props(cx
);
226 if ((flags
& JSITER_OWNONLY
)
227 ? !keys(cx
, proxy
, props
)
228 : !enumerate(cx
, proxy
, props
)) {
231 return EnumeratedIdVectorToIterator(cx
, proxy
, flags
, props
, vp
);
235 JSProxyHandler::obj_toString(JSContext
*cx
, JSObject
*proxy
)
237 JS_ASSERT(proxy
->isProxy());
239 return JS_NewStringCopyZ(cx
, proxy
->isFunctionProxy()
240 ? "[object Function]"
241 : "[object Object]");
245 JSProxyHandler::fun_toString(JSContext
*cx
, JSObject
*proxy
, uintN indent
)
247 JS_ASSERT(proxy
->isProxy());
248 Value fval
= GetCall(proxy
);
249 if (proxy
->isFunctionProxy() &&
250 (fval
.isPrimitive() || !fval
.toObject().isFunction())) {
251 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
,
252 JSMSG_INCOMPATIBLE_PROTO
,
253 js_Function_str
, js_toString_str
,
257 return fun_toStringHelper(cx
, &fval
.toObject(), indent
);
261 JSProxyHandler::call(JSContext
*cx
, JSObject
*proxy
, uintN argc
, Value
*vp
)
263 JS_ASSERT(OperationInProgress(cx
, proxy
));
264 AutoValueRooter
rval(cx
);
265 JSBool ok
= ExternalInvoke(cx
, vp
[1], GetCall(proxy
), argc
, JS_ARGV(cx
, vp
),
268 JS_SET_RVAL(cx
, vp
, rval
.value());
273 JSProxyHandler::construct(JSContext
*cx
, JSObject
*proxy
,
274 uintN argc
, Value
*argv
, Value
*rval
)
276 JS_ASSERT(OperationInProgress(cx
, proxy
));
277 Value fval
= GetConstruct(proxy
);
278 if (fval
.isUndefined())
279 return ExternalInvokeConstructor(cx
, GetCall(proxy
), argc
, argv
, rval
);
280 return ExternalInvoke(cx
, UndefinedValue(), fval
, argc
, argv
, rval
);
284 JSProxyHandler::hasInstance(JSContext
*cx
, JSObject
*proxy
, const Value
*vp
, bool *bp
)
286 JS_ASSERT(OperationInProgress(cx
, proxy
));
287 js_ReportValueError(cx
, JSMSG_BAD_INSTANCEOF_RHS
,
288 JSDVG_SEARCH_STACK
, ObjectValue(*proxy
), NULL
);
293 JSProxyHandler::typeOf(JSContext
*cx
, JSObject
*proxy
)
295 JS_ASSERT(OperationInProgress(cx
, proxy
));
296 return proxy
->isFunctionProxy() ? JSTYPE_FUNCTION
: JSTYPE_OBJECT
;
300 JSProxyHandler::finalize(JSContext
*cx
, JSObject
*proxy
)
305 JSProxyHandler::trace(JSTracer
*trc
, JSObject
*proxy
)
310 GetTrap(JSContext
*cx
, JSObject
*handler
, JSAtom
*atom
, Value
*fvalp
)
312 JS_CHECK_RECURSION(cx
, return false);
314 return handler
->getProperty(cx
, ATOM_TO_JSID(atom
), fvalp
);
318 GetFundamentalTrap(JSContext
*cx
, JSObject
*handler
, JSAtom
*atom
, Value
*fvalp
)
320 if (!GetTrap(cx
, handler
, atom
, fvalp
))
323 if (!js_IsCallable(*fvalp
)) {
324 JSAutoByteString bytes
;
325 if (js_AtomToPrintableString(cx
, atom
, &bytes
))
326 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_NOT_FUNCTION
, bytes
.ptr());
334 GetDerivedTrap(JSContext
*cx
, JSObject
*handler
, JSAtom
*atom
, Value
*fvalp
)
336 JS_ASSERT(atom
== ATOM(has
) ||
337 atom
== ATOM(hasOwn
) ||
340 atom
== ATOM(keys
) ||
341 atom
== ATOM(iterate
));
343 return GetTrap(cx
, handler
, atom
, fvalp
);
347 Trap(JSContext
*cx
, JSObject
*handler
, Value fval
, uintN argc
, Value
* argv
, Value
*rval
)
349 return ExternalInvoke(cx
, ObjectValue(*handler
), fval
, argc
, argv
, rval
);
353 Trap1(JSContext
*cx
, JSObject
*handler
, Value fval
, jsid id
, Value
*rval
)
355 JSString
*str
= js_ValueToString(cx
, IdToValue(id
));
358 rval
->setString(str
);
359 return Trap(cx
, handler
, fval
, 1, rval
, rval
);
363 Trap2(JSContext
*cx
, JSObject
*handler
, Value fval
, jsid id
, Value v
, Value
*rval
)
365 JSString
*str
= js_ValueToString(cx
, IdToValue(id
));
368 rval
->setString(str
);
369 Value argv
[2] = { *rval
, v
};
370 return Trap(cx
, handler
, fval
, 2, argv
, rval
);
374 ParsePropertyDescriptorObject(JSContext
*cx
, JSObject
*obj
, jsid id
, const Value
&v
,
375 PropertyDescriptor
*desc
)
377 AutoPropDescArrayRooter
descs(cx
);
378 PropDesc
*d
= descs
.append();
379 if (!d
|| !d
->initialize(cx
, id
, v
))
382 desc
->value
= d
->value
;
383 JS_ASSERT(!(d
->attrs
& JSPROP_SHORTID
));
384 desc
->attrs
= d
->attrs
;
385 desc
->getter
= d
->getter();
386 desc
->setter
= d
->setter();
392 IndicatePropertyNotFound(JSContext
*cx
, PropertyDescriptor
*desc
)
399 MakePropertyDescriptorObject(JSContext
*cx
, jsid id
, PropertyDescriptor
*desc
, Value
*vp
)
405 uintN attrs
= desc
->attrs
;
406 Value getter
= (attrs
& JSPROP_GETTER
) ? CastAsObjectJsval(desc
->getter
) : UndefinedValue();
407 Value setter
= (attrs
& JSPROP_SETTER
) ? CastAsObjectJsval(desc
->setter
) : UndefinedValue();
408 return js_NewPropertyDescriptorObject(cx
, id
, attrs
, getter
, setter
, desc
->value
, vp
);
412 ValueToBool(JSContext
*cx
, const Value
&v
, bool *bp
)
414 *bp
= !!js_ValueToBoolean(v
);
419 ArrayToIdVector(JSContext
*cx
, const Value
&array
, AutoIdVector
&props
)
421 JS_ASSERT(props
.length() == 0);
423 if (array
.isPrimitive())
426 JSObject
*obj
= &array
.toObject();
428 if (!js_GetLengthProperty(cx
, obj
, &length
))
431 AutoIdRooter
idr(cx
);
432 AutoValueRooter
tvr(cx
);
433 for (jsuint n
= 0; n
< length
; ++n
) {
434 if (!JS_CHECK_OPERATION_LIMIT(cx
))
436 if (!js_IndexToId(cx
, n
, idr
.addr()))
438 if (!obj
->getProperty(cx
, idr
.id(), tvr
.addr()))
440 if (!ValueToId(cx
, tvr
.value(), idr
.addr()))
442 if (!props
.append(js_CheckForStringIndex(idr
.id())))
449 /* Derived class for all scripted proxy handlers. */
450 class JSScriptedProxyHandler
: public JSProxyHandler
{
452 JSScriptedProxyHandler();
453 virtual ~JSScriptedProxyHandler();
455 /* ES5 Harmony fundamental proxy traps. */
456 virtual bool getPropertyDescriptor(JSContext
*cx
, JSObject
*proxy
, jsid id
, bool set
,
457 PropertyDescriptor
*desc
);
458 virtual bool getOwnPropertyDescriptor(JSContext
*cx
, JSObject
*proxy
, jsid id
, bool set
,
459 PropertyDescriptor
*desc
);
460 virtual bool defineProperty(JSContext
*cx
, JSObject
*proxy
, jsid id
,
461 PropertyDescriptor
*desc
);
462 virtual bool getOwnPropertyNames(JSContext
*cx
, JSObject
*proxy
, AutoIdVector
&props
);
463 virtual bool delete_(JSContext
*cx
, JSObject
*proxy
, jsid id
, bool *bp
);
464 virtual bool enumerate(JSContext
*cx
, JSObject
*proxy
, AutoIdVector
&props
);
465 virtual bool fix(JSContext
*cx
, JSObject
*proxy
, Value
*vp
);
467 /* ES5 Harmony derived proxy traps. */
468 virtual bool has(JSContext
*cx
, JSObject
*proxy
, jsid id
, bool *bp
);
469 virtual bool hasOwn(JSContext
*cx
, JSObject
*proxy
, jsid id
, bool *bp
);
470 virtual bool get(JSContext
*cx
, JSObject
*proxy
, JSObject
*receiver
, jsid id
, Value
*vp
);
471 virtual bool set(JSContext
*cx
, JSObject
*proxy
, JSObject
*receiver
, jsid id
, bool strict
,
473 virtual bool keys(JSContext
*cx
, JSObject
*proxy
, AutoIdVector
&props
);
474 virtual bool iterate(JSContext
*cx
, JSObject
*proxy
, uintN flags
, Value
*vp
);
476 static JSScriptedProxyHandler singleton
;
479 static int sScriptedProxyHandlerFamily
= 0;
481 JSScriptedProxyHandler::JSScriptedProxyHandler() : JSProxyHandler(&sScriptedProxyHandlerFamily
)
485 JSScriptedProxyHandler::~JSScriptedProxyHandler()
490 ReturnedValueMustNotBePrimitive(JSContext
*cx
, JSObject
*proxy
, JSAtom
*atom
, const Value
&v
)
492 if (v
.isPrimitive()) {
493 JSAutoByteString bytes
;
494 if (js_AtomToPrintableString(cx
, atom
, &bytes
)) {
495 js_ReportValueError2(cx
, JSMSG_BAD_TRAP_RETURN_VALUE
,
496 JSDVG_SEARCH_STACK
, ObjectOrNullValue(proxy
), NULL
, bytes
.ptr());
504 GetProxyHandlerObject(JSContext
*cx
, JSObject
*proxy
)
506 JS_ASSERT(OperationInProgress(cx
, proxy
));
507 return proxy
->getProxyPrivate().toObjectOrNull();
511 JSScriptedProxyHandler::getPropertyDescriptor(JSContext
*cx
, JSObject
*proxy
, jsid id
, bool set
,
512 PropertyDescriptor
*desc
)
514 JSObject
*handler
= GetProxyHandlerObject(cx
, proxy
);
515 AutoValueRooter
tvr(cx
);
516 return GetFundamentalTrap(cx
, handler
, ATOM(getPropertyDescriptor
), tvr
.addr()) &&
517 Trap1(cx
, handler
, tvr
.value(), id
, tvr
.addr()) &&
518 ((tvr
.value().isUndefined() && IndicatePropertyNotFound(cx
, desc
)) ||
519 (ReturnedValueMustNotBePrimitive(cx
, proxy
, ATOM(getPropertyDescriptor
), tvr
.value()) &&
520 ParsePropertyDescriptorObject(cx
, proxy
, id
, tvr
.value(), desc
)));
524 JSScriptedProxyHandler::getOwnPropertyDescriptor(JSContext
*cx
, JSObject
*proxy
, jsid id
, bool set
,
525 PropertyDescriptor
*desc
)
527 JSObject
*handler
= GetProxyHandlerObject(cx
, proxy
);
528 AutoValueRooter
tvr(cx
);
529 return GetFundamentalTrap(cx
, handler
, ATOM(getOwnPropertyDescriptor
), tvr
.addr()) &&
530 Trap1(cx
, handler
, tvr
.value(), id
, tvr
.addr()) &&
531 ((tvr
.value().isUndefined() && IndicatePropertyNotFound(cx
, desc
)) ||
532 (ReturnedValueMustNotBePrimitive(cx
, proxy
, ATOM(getPropertyDescriptor
), tvr
.value()) &&
533 ParsePropertyDescriptorObject(cx
, proxy
, id
, tvr
.value(), desc
)));
537 JSScriptedProxyHandler::defineProperty(JSContext
*cx
, JSObject
*proxy
, jsid id
,
538 PropertyDescriptor
*desc
)
540 JSObject
*handler
= GetProxyHandlerObject(cx
, proxy
);
541 AutoValueRooter
tvr(cx
);
542 AutoValueRooter
fval(cx
);
543 return GetFundamentalTrap(cx
, handler
, ATOM(defineProperty
), fval
.addr()) &&
544 MakePropertyDescriptorObject(cx
, id
, desc
, tvr
.addr()) &&
545 Trap2(cx
, handler
, fval
.value(), id
, tvr
.value(), tvr
.addr());
549 JSScriptedProxyHandler::getOwnPropertyNames(JSContext
*cx
, JSObject
*proxy
, AutoIdVector
&props
)
551 JSObject
*handler
= GetProxyHandlerObject(cx
, proxy
);
552 AutoValueRooter
tvr(cx
);
553 return GetFundamentalTrap(cx
, handler
, ATOM(getOwnPropertyNames
), tvr
.addr()) &&
554 Trap(cx
, handler
, tvr
.value(), 0, NULL
, tvr
.addr()) &&
555 ArrayToIdVector(cx
, tvr
.value(), props
);
559 JSScriptedProxyHandler::delete_(JSContext
*cx
, JSObject
*proxy
, jsid id
, bool *bp
)
561 JSObject
*handler
= GetProxyHandlerObject(cx
, proxy
);
562 AutoValueRooter
tvr(cx
);
563 return GetFundamentalTrap(cx
, handler
, ATOM(delete), tvr
.addr()) &&
564 Trap1(cx
, handler
, tvr
.value(), id
, tvr
.addr()) &&
565 ValueToBool(cx
, tvr
.value(), bp
);
569 JSScriptedProxyHandler::enumerate(JSContext
*cx
, JSObject
*proxy
, AutoIdVector
&props
)
571 JSObject
*handler
= GetProxyHandlerObject(cx
, proxy
);
572 AutoValueRooter
tvr(cx
);
573 return GetFundamentalTrap(cx
, handler
, ATOM(enumerate
), tvr
.addr()) &&
574 Trap(cx
, handler
, tvr
.value(), 0, NULL
, tvr
.addr()) &&
575 ArrayToIdVector(cx
, tvr
.value(), props
);
579 JSScriptedProxyHandler::fix(JSContext
*cx
, JSObject
*proxy
, Value
*vp
)
581 JSObject
*handler
= GetProxyHandlerObject(cx
, proxy
);
582 return GetFundamentalTrap(cx
, handler
, ATOM(fix
), vp
) &&
583 Trap(cx
, handler
, *vp
, 0, NULL
, vp
);
587 JSScriptedProxyHandler::has(JSContext
*cx
, JSObject
*proxy
, jsid id
, bool *bp
)
589 JSObject
*handler
= GetProxyHandlerObject(cx
, proxy
);
590 AutoValueRooter
tvr(cx
);
591 if (!GetDerivedTrap(cx
, handler
, ATOM(has
), tvr
.addr()))
593 if (!js_IsCallable(tvr
.value()))
594 return JSProxyHandler::has(cx
, proxy
, id
, bp
);
595 return Trap1(cx
, handler
, tvr
.value(), id
, tvr
.addr()) &&
596 ValueToBool(cx
, tvr
.value(), bp
);
600 JSScriptedProxyHandler::hasOwn(JSContext
*cx
, JSObject
*proxy
, jsid id
, bool *bp
)
602 JSObject
*handler
= GetProxyHandlerObject(cx
, proxy
);
603 AutoValueRooter
tvr(cx
);
604 if (!GetDerivedTrap(cx
, handler
, ATOM(hasOwn
), tvr
.addr()))
606 if (!js_IsCallable(tvr
.value()))
607 return JSProxyHandler::hasOwn(cx
, proxy
, id
, bp
);
608 return Trap1(cx
, handler
, tvr
.value(), id
, tvr
.addr()) &&
609 ValueToBool(cx
, tvr
.value(), bp
);
613 JSScriptedProxyHandler::get(JSContext
*cx
, JSObject
*proxy
, JSObject
*receiver
, jsid id
, Value
*vp
)
615 JSObject
*handler
= GetProxyHandlerObject(cx
, proxy
);
616 JSString
*str
= js_ValueToString(cx
, IdToValue(id
));
619 AutoValueRooter
tvr(cx
, StringValue(str
));
620 Value argv
[] = { ObjectOrNullValue(receiver
), tvr
.value() };
621 AutoValueRooter
fval(cx
);
622 if (!GetDerivedTrap(cx
, handler
, ATOM(get
), fval
.addr()))
624 if (!js_IsCallable(fval
.value()))
625 return JSProxyHandler::get(cx
, proxy
, receiver
, id
, vp
);
626 return Trap(cx
, handler
, fval
.value(), 2, argv
, vp
);
630 JSScriptedProxyHandler::set(JSContext
*cx
, JSObject
*proxy
, JSObject
*receiver
, jsid id
, bool strict
,
633 JSObject
*handler
= GetProxyHandlerObject(cx
, proxy
);
634 JSString
*str
= js_ValueToString(cx
, IdToValue(id
));
637 AutoValueRooter
tvr(cx
, StringValue(str
));
638 Value argv
[] = { ObjectOrNullValue(receiver
), tvr
.value(), *vp
};
639 AutoValueRooter
fval(cx
);
640 if (!GetDerivedTrap(cx
, handler
, ATOM(set
), fval
.addr()))
642 if (!js_IsCallable(fval
.value()))
643 return JSProxyHandler::set(cx
, proxy
, receiver
, id
, strict
, vp
);
644 return Trap(cx
, handler
, fval
.value(), 3, argv
, tvr
.addr());
648 JSScriptedProxyHandler::keys(JSContext
*cx
, JSObject
*proxy
, AutoIdVector
&props
)
650 JSObject
*handler
= GetProxyHandlerObject(cx
, proxy
);
651 AutoValueRooter
tvr(cx
);
652 if (!GetDerivedTrap(cx
, handler
, ATOM(keys
), tvr
.addr()))
654 if (!js_IsCallable(tvr
.value()))
655 return JSProxyHandler::keys(cx
, proxy
, props
);
656 return Trap(cx
, handler
, tvr
.value(), 0, NULL
, tvr
.addr()) &&
657 ArrayToIdVector(cx
, tvr
.value(), props
);
661 JSScriptedProxyHandler::iterate(JSContext
*cx
, JSObject
*proxy
, uintN flags
, Value
*vp
)
663 JSObject
*handler
= GetProxyHandlerObject(cx
, proxy
);
664 AutoValueRooter
tvr(cx
);
665 if (!GetDerivedTrap(cx
, handler
, ATOM(iterate
), tvr
.addr()))
667 if (!js_IsCallable(tvr
.value()))
668 return JSProxyHandler::iterate(cx
, proxy
, flags
, vp
);
669 return Trap(cx
, handler
, tvr
.value(), 0, NULL
, vp
) &&
670 ReturnedValueMustNotBePrimitive(cx
, proxy
, ATOM(iterate
), *vp
);
673 JSScriptedProxyHandler
JSScriptedProxyHandler::singleton
;
675 class AutoPendingProxyOperation
{
677 JSPendingProxyOperation op
;
679 AutoPendingProxyOperation(JSContext
*cx
, JSObject
*proxy
) : data(JS_THREAD_DATA(cx
)) {
680 op
.next
= data
->pendingProxyOperation
;
682 data
->pendingProxyOperation
= &op
;
685 ~AutoPendingProxyOperation() {
686 JS_ASSERT(data
->pendingProxyOperation
== &op
);
687 data
->pendingProxyOperation
= op
.next
;
692 JSProxy::getPropertyDescriptor(JSContext
*cx
, JSObject
*proxy
, jsid id
, bool set
,
693 PropertyDescriptor
*desc
)
695 JS_CHECK_RECURSION(cx
, return false);
696 AutoPendingProxyOperation
pending(cx
, proxy
);
697 return proxy
->getProxyHandler()->getPropertyDescriptor(cx
, proxy
, id
, set
, desc
);
701 JSProxy::getPropertyDescriptor(JSContext
*cx
, JSObject
*proxy
, jsid id
, bool set
, Value
*vp
)
703 JS_CHECK_RECURSION(cx
, return false);
704 AutoPendingProxyOperation
pending(cx
, proxy
);
705 AutoPropertyDescriptorRooter
desc(cx
);
706 return JSProxy::getPropertyDescriptor(cx
, proxy
, id
, set
, &desc
) &&
707 MakePropertyDescriptorObject(cx
, id
, &desc
, vp
);
711 JSProxy::getOwnPropertyDescriptor(JSContext
*cx
, JSObject
*proxy
, jsid id
, bool set
,
712 PropertyDescriptor
*desc
)
714 JS_CHECK_RECURSION(cx
, return false);
715 AutoPendingProxyOperation
pending(cx
, proxy
);
716 return proxy
->getProxyHandler()->getOwnPropertyDescriptor(cx
, proxy
, id
, set
, desc
);
720 JSProxy::getOwnPropertyDescriptor(JSContext
*cx
, JSObject
*proxy
, jsid id
, bool set
, Value
*vp
)
722 JS_CHECK_RECURSION(cx
, return false);
723 AutoPendingProxyOperation
pending(cx
, proxy
);
724 AutoPropertyDescriptorRooter
desc(cx
);
725 return JSProxy::getOwnPropertyDescriptor(cx
, proxy
, id
, set
, &desc
) &&
726 MakePropertyDescriptorObject(cx
, id
, &desc
, vp
);
730 JSProxy::defineProperty(JSContext
*cx
, JSObject
*proxy
, jsid id
, PropertyDescriptor
*desc
)
732 JS_CHECK_RECURSION(cx
, return false);
733 AutoPendingProxyOperation
pending(cx
, proxy
);
734 return proxy
->getProxyHandler()->defineProperty(cx
, proxy
, id
, desc
);
738 JSProxy::defineProperty(JSContext
*cx
, JSObject
*proxy
, jsid id
, const Value
&v
)
740 JS_CHECK_RECURSION(cx
, return false);
741 AutoPendingProxyOperation
pending(cx
, proxy
);
742 AutoPropertyDescriptorRooter
desc(cx
);
743 return ParsePropertyDescriptorObject(cx
, proxy
, id
, v
, &desc
) &&
744 JSProxy::defineProperty(cx
, proxy
, id
, &desc
);
748 JSProxy::getOwnPropertyNames(JSContext
*cx
, JSObject
*proxy
, AutoIdVector
&props
)
750 JS_CHECK_RECURSION(cx
, return false);
751 AutoPendingProxyOperation
pending(cx
, proxy
);
752 return proxy
->getProxyHandler()->getOwnPropertyNames(cx
, proxy
, props
);
756 JSProxy::delete_(JSContext
*cx
, JSObject
*proxy
, jsid id
, bool *bp
)
758 JS_CHECK_RECURSION(cx
, return false);
759 AutoPendingProxyOperation
pending(cx
, proxy
);
760 return proxy
->getProxyHandler()->delete_(cx
, proxy
, id
, bp
);
764 JSProxy::enumerate(JSContext
*cx
, JSObject
*proxy
, AutoIdVector
&props
)
766 JS_CHECK_RECURSION(cx
, return false);
767 AutoPendingProxyOperation
pending(cx
, proxy
);
768 return proxy
->getProxyHandler()->enumerate(cx
, proxy
, props
);
772 JSProxy::fix(JSContext
*cx
, JSObject
*proxy
, Value
*vp
)
774 JS_CHECK_RECURSION(cx
, return false);
775 AutoPendingProxyOperation
pending(cx
, proxy
);
776 return proxy
->getProxyHandler()->fix(cx
, proxy
, vp
);
780 JSProxy::has(JSContext
*cx
, JSObject
*proxy
, jsid id
, bool *bp
)
782 JS_CHECK_RECURSION(cx
, return false);
783 AutoPendingProxyOperation
pending(cx
, proxy
);
784 return proxy
->getProxyHandler()->has(cx
, proxy
, id
, bp
);
788 JSProxy::hasOwn(JSContext
*cx
, JSObject
*proxy
, jsid id
, bool *bp
)
790 JS_CHECK_RECURSION(cx
, return false);
791 AutoPendingProxyOperation
pending(cx
, proxy
);
792 return proxy
->getProxyHandler()->hasOwn(cx
, proxy
, id
, bp
);
796 JSProxy::get(JSContext
*cx
, JSObject
*proxy
, JSObject
*receiver
, jsid id
, Value
*vp
)
798 JS_CHECK_RECURSION(cx
, return false);
799 AutoPendingProxyOperation
pending(cx
, proxy
);
800 return proxy
->getProxyHandler()->get(cx
, proxy
, receiver
, id
, vp
);
804 JSProxy::set(JSContext
*cx
, JSObject
*proxy
, JSObject
*receiver
, jsid id
, bool strict
, Value
*vp
)
806 JS_CHECK_RECURSION(cx
, return false);
807 AutoPendingProxyOperation
pending(cx
, proxy
);
808 return proxy
->getProxyHandler()->set(cx
, proxy
, receiver
, id
, strict
, vp
);
812 JSProxy::keys(JSContext
*cx
, JSObject
*proxy
, AutoIdVector
&props
)
814 JS_CHECK_RECURSION(cx
, return false);
815 AutoPendingProxyOperation
pending(cx
, proxy
);
816 return proxy
->getProxyHandler()->keys(cx
, proxy
, props
);
820 JSProxy::iterate(JSContext
*cx
, JSObject
*proxy
, uintN flags
, Value
*vp
)
822 JS_CHECK_RECURSION(cx
, return false);
823 AutoPendingProxyOperation
pending(cx
, proxy
);
824 return proxy
->getProxyHandler()->iterate(cx
, proxy
, flags
, vp
);
828 JSProxy::call(JSContext
*cx
, JSObject
*proxy
, uintN argc
, Value
*vp
)
830 JS_CHECK_RECURSION(cx
, return false);
831 AutoPendingProxyOperation
pending(cx
, proxy
);
832 return proxy
->getProxyHandler()->call(cx
, proxy
, argc
, vp
);
836 JSProxy::construct(JSContext
*cx
, JSObject
*proxy
, uintN argc
, Value
*argv
, Value
*rval
)
838 JS_CHECK_RECURSION(cx
, return false);
839 AutoPendingProxyOperation
pending(cx
, proxy
);
840 return proxy
->getProxyHandler()->construct(cx
, proxy
, argc
, argv
, rval
);
844 JSProxy::hasInstance(JSContext
*cx
, JSObject
*proxy
, const js::Value
*vp
, bool *bp
)
846 JS_CHECK_RECURSION(cx
, return false);
847 AutoPendingProxyOperation
pending(cx
, proxy
);
848 return proxy
->getProxyHandler()->hasInstance(cx
, proxy
, vp
, bp
);
852 JSProxy::typeOf(JSContext
*cx
, JSObject
*proxy
)
854 // FIXME: API doesn't allow us to report error (bug 618906).
855 JS_CHECK_RECURSION(cx
, return JSTYPE_OBJECT
);
856 AutoPendingProxyOperation
pending(cx
, proxy
);
857 return proxy
->getProxyHandler()->typeOf(cx
, proxy
);
861 JSProxy::obj_toString(JSContext
*cx
, JSObject
*proxy
)
863 JS_CHECK_RECURSION(cx
, return NULL
);
864 AutoPendingProxyOperation
pending(cx
, proxy
);
865 return proxy
->getProxyHandler()->obj_toString(cx
, proxy
);
869 JSProxy::fun_toString(JSContext
*cx
, JSObject
*proxy
, uintN indent
)
871 JS_CHECK_RECURSION(cx
, return NULL
);
872 AutoPendingProxyOperation
pending(cx
, proxy
);
873 return proxy
->getProxyHandler()->fun_toString(cx
, proxy
, indent
);
877 proxy_innerObject(JSContext
*cx
, JSObject
*obj
)
879 return obj
->getProxyPrivate().toObjectOrNull();
883 proxy_LookupProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, JSObject
**objp
,
887 if (!JSProxy::has(cx
, obj
, id
, &found
))
891 *propp
= (JSProperty
*)0x1;
901 proxy_DefineProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, const Value
*value
,
902 PropertyOp getter
, StrictPropertyOp setter
, uintN attrs
)
904 AutoPropertyDescriptorRooter
desc(cx
);
907 desc
.attrs
= (attrs
& (~JSPROP_SHORTID
));
908 desc
.getter
= getter
;
909 desc
.setter
= setter
;
911 return JSProxy::defineProperty(cx
, obj
, id
, &desc
);
915 proxy_GetProperty(JSContext
*cx
, JSObject
*obj
, JSObject
*receiver
, jsid id
, Value
*vp
)
917 return JSProxy::get(cx
, obj
, receiver
, id
, vp
);
921 proxy_SetProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*vp
, JSBool strict
)
923 return JSProxy::set(cx
, obj
, obj
, id
, strict
, vp
);
927 proxy_GetAttributes(JSContext
*cx
, JSObject
*obj
, jsid id
, uintN
*attrsp
)
929 AutoPropertyDescriptorRooter
desc(cx
);
930 if (!JSProxy::getOwnPropertyDescriptor(cx
, obj
, id
, false, &desc
))
932 *attrsp
= desc
.attrs
;
937 proxy_SetAttributes(JSContext
*cx
, JSObject
*obj
, jsid id
, uintN
*attrsp
)
939 /* Lookup the current property descriptor so we have setter/getter/value. */
940 AutoPropertyDescriptorRooter
desc(cx
);
941 if (!JSProxy::getOwnPropertyDescriptor(cx
, obj
, id
, true, &desc
))
943 desc
.attrs
= (*attrsp
& (~JSPROP_SHORTID
));
944 return JSProxy::defineProperty(cx
, obj
, id
, &desc
);
948 proxy_DeleteProperty(JSContext
*cx
, JSObject
*obj
, jsid id
, Value
*rval
, JSBool strict
)
950 // TODO: throwing away strict
952 if (!JSProxy::delete_(cx
, obj
, id
, &deleted
))
954 rval
->setBoolean(deleted
);
959 proxy_TraceObject(JSTracer
*trc
, JSObject
*obj
)
961 JSContext
*cx
= trc
->context
;
963 if (!JS_CLIST_IS_EMPTY(&cx
->runtime
->watchPointList
))
964 js_TraceWatchPoints(trc
, obj
);
966 obj
->getProxyHandler()->trace(trc
, obj
);
967 MarkValue(trc
, obj
->getProxyPrivate(), "private");
968 MarkValue(trc
, obj
->getProxyExtra(), "extra");
969 if (obj
->isFunctionProxy()) {
970 MarkValue(trc
, GetCall(obj
), "call");
971 MarkValue(trc
, GetConstruct(obj
), "construct");
976 proxy_Finalize(JSContext
*cx
, JSObject
*obj
)
978 JS_ASSERT(obj
->isProxy());
979 if (!obj
->getSlot(JSSLOT_PROXY_HANDLER
).isUndefined())
980 obj
->getProxyHandler()->finalize(cx
, obj
);
984 proxy_HasInstance(JSContext
*cx
, JSObject
*proxy
, const Value
*v
, JSBool
*bp
)
986 AutoPendingProxyOperation
pending(cx
, proxy
);
988 if (!JSProxy::hasInstance(cx
, proxy
, v
, &b
))
995 proxy_TypeOf(JSContext
*cx
, JSObject
*proxy
)
997 JS_ASSERT(proxy
->isProxy());
998 return JSProxy::typeOf(cx
, proxy
);
1001 JS_FRIEND_API(Class
) ObjectProxyClass
= {
1003 Class::NON_NATIVE
| JSCLASS_HAS_RESERVED_SLOTS(3),
1004 PropertyStub
, /* addProperty */
1005 PropertyStub
, /* delProperty */
1006 PropertyStub
, /* getProperty */
1007 StrictPropertyStub
, /* setProperty */
1011 NULL
, /* finalize */
1012 NULL
, /* reserved0 */
1013 NULL
, /* checkAccess */
1015 NULL
, /* construct */
1016 NULL
, /* xdrObject */
1017 proxy_HasInstance
, /* hasInstance */
1021 proxy_LookupProperty
,
1022 proxy_DefineProperty
,
1025 proxy_GetAttributes
,
1026 proxy_SetAttributes
,
1027 proxy_DeleteProperty
,
1028 NULL
, /* enumerate */
1032 NULL
, /* thisObject */
1033 proxy_Finalize
, /* clear */
1037 JS_FRIEND_API(Class
) OuterWindowProxyClass
= {
1039 Class::NON_NATIVE
| JSCLASS_HAS_RESERVED_SLOTS(3),
1040 PropertyStub
, /* addProperty */
1041 PropertyStub
, /* delProperty */
1042 PropertyStub
, /* getProperty */
1043 StrictPropertyStub
, /* setProperty */
1047 NULL
, /* finalize */
1048 NULL
, /* reserved0 */
1049 NULL
, /* checkAccess */
1051 NULL
, /* construct */
1052 NULL
, /* xdrObject */
1053 NULL
, /* hasInstance */
1056 NULL
, /* equality */
1057 NULL
, /* outerObject */
1062 proxy_LookupProperty
,
1063 proxy_DefineProperty
,
1066 proxy_GetAttributes
,
1067 proxy_SetAttributes
,
1068 proxy_DeleteProperty
,
1069 NULL
, /* enumerate */
1073 NULL
, /* thisObject */
1074 proxy_Finalize
, /* clear */
1079 proxy_Call(JSContext
*cx
, uintN argc
, Value
*vp
)
1081 JSObject
*proxy
= &JS_CALLEE(cx
, vp
).toObject();
1082 JS_ASSERT(proxy
->isProxy());
1083 return JSProxy::call(cx
, proxy
, argc
, vp
);
1087 proxy_Construct(JSContext
*cx
, uintN argc
, Value
*vp
)
1089 JSObject
*proxy
= &JS_CALLEE(cx
, vp
).toObject();
1090 JS_ASSERT(proxy
->isProxy());
1092 bool ok
= JSProxy::construct(cx
, proxy
, argc
, JS_ARGV(cx
, vp
), &rval
);
1097 JS_FRIEND_API(Class
) FunctionProxyClass
= {
1099 Class::NON_NATIVE
| JSCLASS_HAS_RESERVED_SLOTS(5),
1100 PropertyStub
, /* addProperty */
1101 PropertyStub
, /* delProperty */
1102 PropertyStub
, /* getProperty */
1103 StrictPropertyStub
, /* setProperty */
1107 NULL
, /* finalize */
1108 NULL
, /* reserved0 */
1109 NULL
, /* checkAccess */
1112 NULL
, /* xdrObject */
1113 js_FunctionClass
.hasInstance
,
1117 proxy_LookupProperty
,
1118 proxy_DefineProperty
,
1121 proxy_GetAttributes
,
1122 proxy_SetAttributes
,
1123 proxy_DeleteProperty
,
1124 NULL
, /* enumerate */
1128 NULL
, /* thisObject */
1133 JS_FRIEND_API(JSObject
*)
1134 NewProxyObject(JSContext
*cx
, JSProxyHandler
*handler
, const Value
&priv
, JSObject
*proto
,
1135 JSObject
*parent
, JSObject
*call
, JSObject
*construct
)
1137 bool fun
= call
|| construct
;
1140 clasp
= &FunctionProxyClass
;
1142 clasp
= handler
->isOuterWindow() ? &OuterWindowProxyClass
: &ObjectProxyClass
;
1144 JSObject
*obj
= NewNonFunction
<WithProto::Given
>(cx
, clasp
, proto
, parent
);
1145 if (!obj
|| !obj
->ensureInstanceReservedSlots(cx
, 0))
1147 obj
->setSlot(JSSLOT_PROXY_HANDLER
, PrivateValue(handler
));
1148 obj
->setSlot(JSSLOT_PROXY_PRIVATE
, priv
);
1150 obj
->setSlot(JSSLOT_PROXY_CALL
, call
? ObjectValue(*call
) : UndefinedValue());
1152 obj
->setSlot(JSSLOT_PROXY_CONSTRUCT
, ObjectValue(*construct
));
1159 NonNullObject(JSContext
*cx
, const Value
&v
)
1161 if (v
.isPrimitive()) {
1162 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_NOT_NONNULL_OBJECT
);
1165 return &v
.toObject();
1169 proxy_create(JSContext
*cx
, uintN argc
, Value
*vp
)
1172 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_MORE_ARGS_NEEDED
,
1173 "create", "0", "s");
1176 JSObject
*handler
= NonNullObject(cx
, vp
[2]);
1179 JSObject
*proto
, *parent
= NULL
;
1180 if (argc
> 1 && vp
[3].isObject()) {
1181 proto
= &vp
[3].toObject();
1182 parent
= proto
->getParent();
1184 JS_ASSERT(IsFunctionObject(vp
[0]));
1188 parent
= vp
[0].toObject().getParent();
1189 JSObject
*proxy
= NewProxyObject(cx
, &JSScriptedProxyHandler::singleton
, ObjectValue(*handler
),
1194 vp
->setObject(*proxy
);
1199 proxy_createFunction(JSContext
*cx
, uintN argc
, Value
*vp
)
1202 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_MORE_ARGS_NEEDED
,
1203 "createFunction", "1", "");
1206 JSObject
*handler
= NonNullObject(cx
, vp
[2]);
1209 JSObject
*proto
, *parent
;
1210 parent
= vp
[0].toObject().getParent();
1211 if (!js_GetClassPrototype(cx
, parent
, JSProto_Function
, &proto
))
1213 parent
= proto
->getParent();
1215 JSObject
*call
= js_ValueToCallableObject(cx
, &vp
[3], JSV2F_SEARCH_STACK
);
1218 JSObject
*construct
= NULL
;
1220 construct
= js_ValueToCallableObject(cx
, &vp
[4], JSV2F_SEARCH_STACK
);
1225 JSObject
*proxy
= NewProxyObject(cx
, &JSScriptedProxyHandler::singleton
,
1226 ObjectValue(*handler
),
1227 proto
, parent
, call
, construct
);
1231 vp
->setObject(*proxy
);
1238 proxy_isTrapping(JSContext
*cx
, uintN argc
, Value
*vp
)
1241 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_MORE_ARGS_NEEDED
,
1242 "isTrapping", "0", "s");
1245 JSObject
*obj
= NonNullObject(cx
, vp
[2]);
1248 vp
->setBoolean(obj
->isProxy());
1253 proxy_fix(JSContext
*cx
, uintN argc
, Value
*vp
)
1256 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_MORE_ARGS_NEEDED
,
1260 JSObject
*obj
= NonNullObject(cx
, vp
[2]);
1263 if (obj
->isProxy()) {
1265 if (!FixProxy(cx
, obj
, &flag
))
1267 vp
->setBoolean(flag
);
1269 vp
->setBoolean(true);
1276 static JSFunctionSpec static_methods
[] = {
1277 JS_FN("create", proxy_create
, 2, 0),
1278 JS_FN("createFunction", proxy_createFunction
, 3, 0),
1280 JS_FN("isTrapping", proxy_isTrapping
, 1, 0),
1281 JS_FN("fix", proxy_fix
, 1, 0),
1286 extern Class CallableObjectClass
;
1288 static const uint32 JSSLOT_CALLABLE_CALL
= 0;
1289 static const uint32 JSSLOT_CALLABLE_CONSTRUCT
= 1;
1292 callable_Call(JSContext
*cx
, uintN argc
, Value
*vp
)
1294 JSObject
*callable
= &JS_CALLEE(cx
, vp
).toObject();
1295 JS_ASSERT(callable
->getClass() == &CallableObjectClass
);
1296 const Value
&fval
= callable
->getSlot(JSSLOT_CALLABLE_CALL
);
1297 const Value
&thisval
= vp
[1];
1299 bool ok
= ExternalInvoke(cx
, thisval
, fval
, argc
, JS_ARGV(cx
, vp
), &rval
);
1305 callable_Construct(JSContext
*cx
, uintN argc
, Value
*vp
)
1307 JSObject
*thisobj
= js_CreateThis(cx
, &JS_CALLEE(cx
, vp
).toObject());
1311 JSObject
*callable
= &vp
[0].toObject();
1312 JS_ASSERT(callable
->getClass() == &CallableObjectClass
);
1313 Value fval
= callable
->getSlot(JSSLOT_CALLABLE_CONSTRUCT
);
1314 if (fval
.isUndefined()) {
1315 /* We don't have an explicit constructor so allocate a new object and use the call. */
1316 fval
= callable
->getSlot(JSSLOT_CALLABLE_CALL
);
1317 JS_ASSERT(fval
.isObject());
1319 /* callable is the constructor, so get callable.prototype is the proto of the new object. */
1321 if (!callable
->getProperty(cx
, ATOM_TO_JSID(ATOM(classPrototype
)), &protov
))
1325 if (protov
.isObject()) {
1326 proto
= &protov
.toObject();
1328 if (!js_GetClassPrototype(cx
, NULL
, JSProto_Object
, &proto
))
1332 JSObject
*newobj
= NewNativeClassInstance(cx
, &js_ObjectClass
, proto
, proto
->getParent());
1336 /* If the call returns an object, return that, otherwise the original newobj. */
1338 if (!ExternalInvoke(cx
, ObjectValue(*newobj
), callable
->getSlot(JSSLOT_CALLABLE_CALL
),
1339 argc
, vp
+ 2, &rval
)) {
1342 if (rval
.isPrimitive())
1343 vp
->setObject(*newobj
);
1350 bool ok
= ExternalInvoke(cx
, ObjectValue(*thisobj
), fval
, argc
, vp
+ 2, &rval
);
1355 Class CallableObjectClass
= {
1357 JSCLASS_HAS_RESERVED_SLOTS(2),
1358 PropertyStub
, /* addProperty */
1359 PropertyStub
, /* delProperty */
1360 PropertyStub
, /* getProperty */
1361 StrictPropertyStub
, /* setProperty */
1365 NULL
, /* finalize */
1366 NULL
, /* reserved0 */
1367 NULL
, /* checkAccess */
1372 JS_FRIEND_API(JSBool
)
1373 FixProxy(JSContext
*cx
, JSObject
*proxy
, JSBool
*bp
)
1375 AutoValueRooter
tvr(cx
);
1376 if (!JSProxy::fix(cx
, proxy
, tvr
.addr()))
1378 if (tvr
.value().isUndefined()) {
1383 if (OperationInProgress(cx
, proxy
)) {
1384 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_BAD_PROXY_FIX
);
1388 JSObject
*props
= NonNullObject(cx
, tvr
.value());
1392 JSObject
*proto
= proxy
->getProto();
1393 JSObject
*parent
= proxy
->getParent();
1394 Class
*clasp
= proxy
->isFunctionProxy() ? &CallableObjectClass
: &js_ObjectClass
;
1397 * Make a blank object from the recipe fix provided to us. This must have
1398 * number of fixed slots as the proxy so that we can swap their contents.
1400 gc::FinalizeKind kind
= gc::FinalizeKind(proxy
->arena()->header()->thingKind
);
1401 JSObject
*newborn
= NewNonFunction
<WithProto::Given
>(cx
, clasp
, proto
, parent
, kind
);
1404 AutoObjectRooter
tvr2(cx
, newborn
);
1406 if (clasp
== &CallableObjectClass
) {
1407 newborn
->setSlot(JSSLOT_CALLABLE_CALL
, GetCall(proxy
));
1408 newborn
->setSlot(JSSLOT_CALLABLE_CONSTRUCT
, GetConstruct(proxy
));
1412 AutoPendingProxyOperation
pending(cx
, proxy
);
1413 if (!js_PopulateObject(cx
, newborn
, props
))
1417 /* Trade contents between the newborn object and the proxy. */
1418 if (!proxy
->swap(cx
, newborn
))
1421 /* The GC will dispose of the proxy object. */
1429 Class js_ProxyClass
= {
1431 JSCLASS_HAS_CACHED_PROTO(JSProto_Proxy
),
1432 PropertyStub
, /* addProperty */
1433 PropertyStub
, /* delProperty */
1434 PropertyStub
, /* getProperty */
1435 StrictPropertyStub
, /* setProperty */
1441 JS_FRIEND_API(JSObject
*)
1442 js_InitProxyClass(JSContext
*cx
, JSObject
*obj
)
1444 JSObject
*module
= NewNonFunction
<WithProto::Class
>(cx
, &js_ProxyClass
, NULL
, obj
);
1447 if (!JS_DefineProperty(cx
, obj
, "Proxy", OBJECT_TO_JSVAL(module
),
1448 JS_PropertyStub
, JS_StrictPropertyStub
, 0)) {
1451 if (!JS_DefineFunctions(cx
, module
, static_methods
))