Bug 588735 - Mirror glass caption buttons for rtl windows. r=roc, a=blocking-betaN.
[mozilla-central.git] / js / src / jswrapper.cpp
blobbffa7c4068516f91e5f6a34d57e4f2885b7d20dd
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
15 * License.
17 * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
18 * May 28, 2008.
20 * The Initial Developer of the Original Code is
21 * Mozilla Foundation
22 * Portions created by the Initial Developer are Copyright (C) 2010
23 * the Initial Developer. All Rights Reserved.
25 * Contributor(s):
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 ***** */
42 #include "jsapi.h"
43 #include "jscntxt.h"
44 #include "jsiter.h"
45 #include "jsnum.h"
46 #include "jsregexp.h"
47 #include "jswrapper.h"
49 #include "jsobjinlines.h"
51 using namespace js;
53 static int sWrapperFamily = 0;
55 bool
56 JSObject::isWrapper() const
58 return isProxy() && getProxyHandler()->family() == &sWrapperFamily;
61 JSObject *
62 JSObject::unwrap(uintN *flagsp)
64 JSObject *wrapped = this;
65 uintN flags = 0;
66 if (wrapped->isWrapper()) {
67 flags |= static_cast<JSWrapper *>(wrapped->getProxyHandler())->flags();
68 wrapped = wrapped->getProxyPrivate().toObjectOrNull();
70 if (flagsp)
71 *flagsp = flags;
72 return wrapped;
75 JSWrapper::JSWrapper(uintN flags) : JSProxyHandler(&sWrapperFamily), mFlags(flags)
79 JSWrapper::~JSWrapper()
83 #define CHECKED(op, set) \
84 JS_BEGIN_MACRO \
85 if (!enter(cx, wrapper, id, set)) \
86 return false; \
87 bool ok = (op); \
88 leave(cx, wrapper); \
89 return ok; \
90 JS_END_MACRO
92 #define SET(action) CHECKED(action, true)
93 #define GET(action) CHECKED(action, false)
95 bool
96 JSWrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
97 PropertyDescriptor *desc)
99 GET(JS_GetPropertyDescriptorById(cx, wrappedObject(wrapper), id, JSRESOLVE_QUALIFIED,
100 Jsvalify(desc)));
103 static bool
104 GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSPropertyDescriptor *desc)
106 if (!JS_GetPropertyDescriptorById(cx, obj, id, flags, desc))
107 return false;
108 if (desc->obj != obj)
109 desc->obj = NULL;
110 return true;
113 bool
114 JSWrapper::getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
115 PropertyDescriptor *desc)
117 GET(GetOwnPropertyDescriptor(cx, wrappedObject(wrapper), id, JSRESOLVE_QUALIFIED,
118 Jsvalify(desc)));
121 bool
122 JSWrapper::defineProperty(JSContext *cx, JSObject *wrapper, jsid id,
123 PropertyDescriptor *desc)
125 SET(JS_DefinePropertyById(cx, wrappedObject(wrapper), id, Jsvalify(desc->value),
126 Jsvalify(desc->getter), Jsvalify(desc->setter), desc->attrs));
129 bool
130 JSWrapper::getOwnPropertyNames(JSContext *cx, JSObject *wrapper, AutoIdVector &props)
132 jsid id = JSID_VOID;
133 GET(GetPropertyNames(cx, wrappedObject(wrapper), JSITER_OWNONLY | JSITER_HIDDEN, props));
136 static bool
137 ValueToBoolean(Value *vp, bool *bp)
139 *bp = js_ValueToBoolean(*vp);
140 return true;
143 bool
144 JSWrapper::delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
146 Value v;
147 SET(JS_DeletePropertyById2(cx, wrappedObject(wrapper), id, Jsvalify(&v)) &&
148 ValueToBoolean(&v, bp));
151 bool
152 JSWrapper::enumerate(JSContext *cx, JSObject *wrapper, AutoIdVector &props)
154 static jsid id = JSID_VOID;
155 GET(GetPropertyNames(cx, wrappedObject(wrapper), 0, props));
158 bool
159 JSWrapper::fix(JSContext *cx, JSObject *wrapper, Value *vp)
161 vp->setUndefined();
162 return true;
165 static bool
166 Cond(JSBool b, bool *bp)
168 *bp = !!b;
169 return true;
172 bool
173 JSWrapper::has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
175 JSBool found;
176 GET(JS_HasPropertyById(cx, wrappedObject(wrapper), id, &found) &&
177 Cond(found, bp));
180 bool
181 JSWrapper::hasOwn(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
183 PropertyDescriptor desc;
184 JSObject *wobj = wrappedObject(wrapper);
185 GET(JS_GetPropertyDescriptorById(cx, wobj, id, JSRESOLVE_QUALIFIED, Jsvalify(&desc)) &&
186 Cond(desc.obj == wobj, bp));
189 bool
190 JSWrapper::get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, Value *vp)
192 GET(JS_GetPropertyById(cx, wrappedObject(wrapper), id, Jsvalify(vp)));
195 bool
196 JSWrapper::set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, Value *vp)
198 SET(JS_SetPropertyById(cx, wrappedObject(wrapper), id, Jsvalify(vp)));
201 bool
202 JSWrapper::enumerateOwn(JSContext *cx, JSObject *wrapper, AutoIdVector &props)
204 const jsid id = JSID_VOID;
205 GET(GetPropertyNames(cx, wrappedObject(wrapper), JSITER_OWNONLY, props));
208 bool
209 JSWrapper::iterate(JSContext *cx, JSObject *wrapper, uintN flags, Value *vp)
211 const jsid id = JSID_VOID;
212 GET(GetIterator(cx, wrappedObject(wrapper), flags, vp));
215 bool
216 JSWrapper::call(JSContext *cx, JSObject *wrapper, uintN argc, Value *vp)
218 const jsid id = JSID_VOID;
219 GET(JSProxyHandler::call(cx, wrapper, argc, vp));
222 bool
223 JSWrapper::construct(JSContext *cx, JSObject *wrapper, uintN argc, Value *argv, Value *rval)
225 const jsid id = JSID_VOID;
226 GET(JSProxyHandler::construct(cx, wrapper, argc, argv, rval));
229 JSString *
230 JSWrapper::obj_toString(JSContext *cx, JSObject *wrapper)
232 JSString *str;
233 if (!enter(cx, wrapper, JSID_VOID, false))
234 return NULL;
235 str = JSProxyHandler::obj_toString(cx, wrapper);
236 leave(cx, wrapper);
237 return str;
240 JSString *
241 JSWrapper::fun_toString(JSContext *cx, JSObject *wrapper, uintN indent)
243 JSString *str;
244 if (!enter(cx, wrapper, JSID_VOID, false))
245 return NULL;
246 str = JSProxyHandler::fun_toString(cx, wrapper, indent);
247 leave(cx, wrapper);
248 return str;
251 void
252 JSWrapper::trace(JSTracer *trc, JSObject *wrapper)
254 JS_CALL_OBJECT_TRACER(trc, wrappedObject(wrapper), "wrappedObject");
257 bool
258 JSWrapper::enter(JSContext *cx, JSObject *wrapper, jsid id, bool set)
260 return true;
263 void
264 JSWrapper::leave(JSContext *cx, JSObject *wrapper)
268 JSWrapper JSWrapper::singleton(0);
270 JSObject *
271 JSWrapper::New(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent,
272 JSWrapper *handler)
274 return NewProxyObject(cx, handler, ObjectValue(*obj), proto, parent,
275 obj->isCallable() ? obj : NULL, NULL);
278 /* Compartments. */
280 namespace js {
282 extern JSObject *
283 TransparentObjectWrapper(JSContext *cx, JSObject *obj, JSObject *wrappedProto, uintN flags)
285 JS_ASSERT(!obj->isWrapper());
286 return JSWrapper::New(cx, obj, wrappedProto, NULL, &JSCrossCompartmentWrapper::singleton);
291 JSCompartment::JSCompartment(JSRuntime *rt)
292 : rt(rt), principals(NULL), data(NULL), marked(false)
296 JSCompartment::~JSCompartment()
300 bool
301 JSCompartment::init()
303 return crossCompartmentWrappers.init();
306 bool
307 JSCompartment::wrap(JSContext *cx, Value *vp)
309 JS_ASSERT(cx->compartment == this);
311 uintN flags = 0;
313 JS_CHECK_RECURSION(cx, return false);
315 /* Only GC things have to be wrapped or copied. */
316 if (!vp->isMarkable())
317 return true;
319 /* Static strings do not have to be wrapped. */
320 if (vp->isString() && JSString::isStatic(vp->toString()))
321 return true;
323 /* Unwrap incoming objects. */
324 if (vp->isObject()) {
325 JSObject *obj = vp->toObject().unwrap(&flags);
326 vp->setObject(*obj);
327 /* If the wrapped object is already in this compartment, we are done. */
328 if (obj->getCompartment(cx) == this)
329 return true;
332 /* If we already have a wrapper for this value, use it. */
333 if (WrapperMap::Ptr p = crossCompartmentWrappers.lookup(*vp)) {
334 *vp = p->value;
335 return true;
338 if (vp->isString()) {
339 Value orig = *vp;
340 JSString *str = vp->toString();
341 JSString *wrapped = js_NewStringCopyN(cx, str->chars(), str->length());
342 if (!wrapped)
343 return false;
344 vp->setString(wrapped);
345 return crossCompartmentWrappers.put(orig, *vp);
348 JSObject *obj = &vp->toObject();
351 * Recurse to wrap the prototype. Long prototype chains will run out of
352 * stack, causing an error in CHECK_RECURSE.
354 * Wrapping the proto before creating the new wrapper and adding it to the
355 * cache helps avoid leaving a bad entry in the cache on OOM. But note that
356 * if we wrapped both proto and parent, we would get infinite recursion
357 * here (since Object.prototype->parent->proto leads to Object.prototype
358 * itself).
360 JSObject *proto = obj->getProto();
361 if (!wrap(cx, &proto))
362 return false;
365 * We hand in the original wrapped object into the wrap hook to allow
366 * the wrap hook to reason over what wrappers are currently applied
367 * to the object.
369 JSObject *wrapper = cx->runtime->wrapObjectCallback(cx, obj, proto, flags);
370 if (!wrapper)
371 return false;
372 wrapper->setProto(proto);
373 vp->setObject(*wrapper);
374 if (!crossCompartmentWrappers.put(wrapper->getProxyPrivate(), *vp))
375 return false;
378 * Wrappers should really be parented to the wrapped parent of the wrapped
379 * object, but in that case a wrapped global object would have a NULL
380 * parent without being a proper global object (JSCLASS_IS_GLOBAL). Instead,
381 * we parent all wrappers to the global object in their home compartment.
382 * This loses us some transparency, and is generally very cheesy.
384 JSObject *global =
385 cx->hasfp() ? cx->fp()->getScopeChain()->getGlobal() : cx->globalObject;
386 wrapper->setParent(global);
387 return true;
390 bool
391 JSCompartment::wrap(JSContext *cx, JSString **strp)
393 AutoValueRooter tvr(cx, StringValue(*strp));
394 if (!wrap(cx, tvr.addr()))
395 return false;
396 *strp = tvr.value().toString();
397 return true;
400 bool
401 JSCompartment::wrap(JSContext *cx, JSObject **objp)
403 if (!*objp)
404 return true;
405 AutoValueRooter tvr(cx, ObjectValue(**objp));
406 if (!wrap(cx, tvr.addr()))
407 return false;
408 *objp = &tvr.value().toObject();
409 return true;
412 bool
413 JSCompartment::wrapId(JSContext *cx, jsid *idp) {
414 if (JSID_IS_INT(*idp))
415 return true;
416 AutoValueRooter tvr(cx, IdToValue(*idp));
417 if (!wrap(cx, tvr.addr()))
418 return false;
419 return ValueToId(cx, tvr.value(), idp);
422 bool
423 JSCompartment::wrap(JSContext *cx, PropertyOp *propp)
425 Value v = CastAsObjectJsval(*propp);
426 if (!wrap(cx, &v))
427 return false;
428 *propp = CastAsPropertyOp(v.toObjectOrNull());
429 return true;
432 bool
433 JSCompartment::wrap(JSContext *cx, PropertyDescriptor *desc) {
434 return wrap(cx, &desc->obj) &&
435 (!(desc->attrs & JSPROP_GETTER) || wrap(cx, &desc->getter)) &&
436 (!(desc->attrs & JSPROP_SETTER) || wrap(cx, &desc->setter)) &&
437 wrap(cx, &desc->value);
440 bool
441 JSCompartment::wrap(JSContext *cx, AutoIdVector &props) {
442 jsid *vector = props.begin();
443 jsint length = props.length();
444 for (size_t n = 0; n < size_t(length); ++n) {
445 if (!wrapId(cx, &vector[n]))
446 return false;
448 return true;
451 bool
452 JSCompartment::wrapException(JSContext *cx) {
453 JS_ASSERT(cx->compartment == this);
455 if (cx->throwing) {
456 AutoValueRooter tvr(cx, cx->exception);
457 cx->throwing = false;
458 cx->exception.setNull();
459 if (wrap(cx, tvr.addr())) {
460 cx->throwing = true;
461 cx->exception = tvr.value();
463 return false;
465 return true;
468 void
469 JSCompartment::sweep(JSContext *cx)
471 /* Remove dead wrappers from the table. */
472 for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
473 if (js_IsAboutToBeFinalized(e.front().value.asGCThing()))
474 e.removeFront();
478 AutoCompartment::AutoCompartment(JSContext *cx, JSObject *target)
479 : context(cx),
480 origin(cx->compartment),
481 target(target),
482 destination(target->getCompartment(cx)),
483 statics(cx),
484 input(cx),
485 entered(false)
489 AutoCompartment::~AutoCompartment()
491 if (entered)
492 leave();
495 bool
496 AutoCompartment::enter()
498 JS_ASSERT(!entered);
499 if (origin != destination) {
500 LeaveTrace(context);
501 context->compartment = destination;
502 JSObject *scopeChain = target->getGlobal();
503 frame.construct();
504 if (!context->stack().pushDummyFrame(context, frame.ref(), regs, scopeChain)) {
505 frame.destroy();
506 context->compartment = origin;
507 return false;
509 js_SaveAndClearRegExpStatics(context, &statics, &input);
511 entered = true;
512 return true;
515 void
516 AutoCompartment::leave()
518 JS_ASSERT(entered);
519 if (origin != destination) {
520 js_RestoreRegExpStatics(context, &statics);
521 frame.destroy();
522 context->compartment = origin;
523 origin->wrapException(context);
525 entered = false;
528 /* Cross compartment wrappers. */
530 JSCrossCompartmentWrapper::JSCrossCompartmentWrapper(uintN flags) : JSWrapper(flags)
534 JSCrossCompartmentWrapper::~JSCrossCompartmentWrapper()
538 bool
539 JSCrossCompartmentWrapper::isCrossCompartmentWrapper(JSObject *obj)
541 return obj->isProxy() && obj->getProxyHandler() == &JSCrossCompartmentWrapper::singleton;
544 #define PIERCE(cx, wrapper, mode, pre, op, post) \
545 JS_BEGIN_MACRO \
546 AutoCompartment call(cx, wrappedObject(wrapper)); \
547 if (!call.enter()) \
548 return false; \
549 bool ok = (pre) && (op); \
550 call.leave(); \
551 return ok && (post); \
552 JS_END_MACRO
554 #define NOTHING (true)
556 bool
557 JSCrossCompartmentWrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, PropertyDescriptor *desc)
559 PIERCE(cx, wrapper, GET,
560 call.destination->wrapId(cx, &id),
561 JSWrapper::getPropertyDescriptor(cx, wrapper, id, desc),
562 call.origin->wrap(cx, desc));
565 bool
566 JSCrossCompartmentWrapper::getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, PropertyDescriptor *desc)
568 PIERCE(cx, wrapper, GET,
569 call.destination->wrapId(cx, &id),
570 JSWrapper::getOwnPropertyDescriptor(cx, wrapper, id, desc),
571 call.origin->wrap(cx, desc));
574 bool
575 JSCrossCompartmentWrapper::defineProperty(JSContext *cx, JSObject *wrapper, jsid id, PropertyDescriptor *desc)
577 AutoPropertyDescriptorRooter desc2(cx, desc);
578 PIERCE(cx, wrapper, SET,
579 call.destination->wrapId(cx, &id) && call.destination->wrap(cx, &desc2),
580 JSWrapper::defineProperty(cx, wrapper, id, &desc2),
581 NOTHING);
584 bool
585 JSCrossCompartmentWrapper::getOwnPropertyNames(JSContext *cx, JSObject *wrapper, AutoIdVector &props)
587 PIERCE(cx, wrapper, GET,
588 NOTHING,
589 JSWrapper::getOwnPropertyNames(cx, wrapper, props),
590 call.origin->wrap(cx, props));
593 bool
594 JSCrossCompartmentWrapper::delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
596 PIERCE(cx, wrapper, SET,
597 call.destination->wrapId(cx, &id),
598 JSWrapper::delete_(cx, wrapper, id, bp),
599 NOTHING);
602 bool
603 JSCrossCompartmentWrapper::enumerate(JSContext *cx, JSObject *wrapper, AutoIdVector &props)
605 PIERCE(cx, wrapper, GET,
606 NOTHING,
607 JSWrapper::enumerate(cx, wrapper, props),
608 call.origin->wrap(cx, props));
611 bool
612 JSCrossCompartmentWrapper::has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
614 PIERCE(cx, wrapper, GET,
615 call.destination->wrapId(cx, &id),
616 JSWrapper::has(cx, wrapper, id, bp),
617 NOTHING);
620 bool
621 JSCrossCompartmentWrapper::hasOwn(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
623 PIERCE(cx, wrapper, GET,
624 call.destination->wrapId(cx, &id),
625 JSWrapper::hasOwn(cx, wrapper, id, bp),
626 NOTHING);
629 bool
630 JSCrossCompartmentWrapper::get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, Value *vp)
632 PIERCE(cx, wrapper, GET,
633 call.destination->wrap(cx, &receiver) && call.destination->wrapId(cx, &id),
634 JSWrapper::get(cx, wrapper, receiver, id, vp),
635 call.origin->wrap(cx, vp));
638 bool
639 JSCrossCompartmentWrapper::set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, Value *vp)
641 AutoValueRooter tvr(cx, *vp);
642 PIERCE(cx, wrapper, SET,
643 call.destination->wrap(cx, &receiver) && call.destination->wrapId(cx, &id) && call.destination->wrap(cx, tvr.addr()),
644 JSWrapper::set(cx, wrapper, receiver, id, tvr.addr()),
645 NOTHING);
648 bool
649 JSCrossCompartmentWrapper::enumerateOwn(JSContext *cx, JSObject *wrapper, AutoIdVector &props)
651 PIERCE(cx, wrapper, GET,
652 NOTHING,
653 JSWrapper::enumerateOwn(cx, wrapper, props),
654 call.origin->wrap(cx, props));
658 * We can reify non-escaping iterator objects instead of having to wrap them. This
659 * allows fast iteration over objects across a compartment boundary.
661 static bool
662 CanReify(Value *vp)
664 JSObject *obj;
665 return vp->isObject() &&
666 (obj = &vp->toObject())->getClass() == &js_IteratorClass &&
667 (obj->getNativeIterator()->flags & JSITER_ENUMERATE);
670 static bool
671 Reify(JSContext *cx, JSCompartment *origin, Value *vp)
673 JSObject *iterObj = &vp->toObject();
674 NativeIterator *ni = iterObj->getNativeIterator();
676 /* Wrap the iteratee. */
677 JSObject *obj = ni->obj;
678 if (!origin->wrap(cx, &obj))
679 return false;
682 * Wrap the elements in the iterator's snapshot.
683 * N.B. the order of closing/creating iterators is important due to the
684 * implicit cx->enumerators state.
687 if (ni->isKeyIter()) {
688 size_t length = ni->numKeys();
689 AutoIdVector keys(cx);
690 if (length > 0) {
691 if (!keys.resize(length))
692 return false;
693 for (size_t i = 0; i < length; ++i) {
694 keys[i] = ni->beginKey()[i];
695 if (!origin->wrapId(cx, &keys[i]))
696 return false;
700 return js_CloseIterator(cx, iterObj) &&
701 VectorToKeyIterator(cx, obj, ni->flags, keys, vp);
704 size_t length = ni->numValues();
705 AutoValueVector vals(cx);
706 if (length > 0) {
707 if (!vals.resize(length))
708 return false;
709 for (size_t i = 0; i < length; ++i) {
710 vals[i] = ni->beginValue()[i];
711 if (!origin->wrap(cx, &vals[i]))
712 return false;
717 return js_CloseIterator(cx, iterObj) &&
718 VectorToValueIterator(cx, obj, ni->flags, vals, vp);
721 bool
722 JSCrossCompartmentWrapper::iterate(JSContext *cx, JSObject *wrapper, uintN flags, Value *vp)
724 PIERCE(cx, wrapper, GET,
725 NOTHING,
726 JSWrapper::iterate(cx, wrapper, flags, vp),
727 CanReify(vp) ? Reify(cx, call.origin, vp) : call.origin->wrap(cx, vp));
730 bool
731 JSCrossCompartmentWrapper::call(JSContext *cx, JSObject *wrapper, uintN argc, Value *vp)
733 AutoCompartment call(cx, wrappedObject(wrapper));
734 if (!call.enter())
735 return false;
737 vp[0] = ObjectValue(*call.target);
738 if (!call.destination->wrap(cx, &vp[1]))
739 return false;
740 Value *argv = JS_ARGV(cx, vp);
741 for (size_t n = 0; n < argc; ++n) {
742 if (!call.destination->wrap(cx, &argv[n]))
743 return false;
745 if (!JSWrapper::call(cx, wrapper, argc, vp))
746 return false;
748 call.leave();
749 return call.origin->wrap(cx, vp);
752 bool
753 JSCrossCompartmentWrapper::construct(JSContext *cx, JSObject *wrapper, uintN argc, Value *argv,
754 Value *rval)
756 AutoCompartment call(cx, wrappedObject(wrapper));
757 if (!call.enter())
758 return false;
760 for (size_t n = 0; n < argc; ++n) {
761 if (!call.destination->wrap(cx, &argv[n]))
762 return false;
764 if (!JSWrapper::construct(cx, wrapper, argc, argv, rval))
765 return false;
767 call.leave();
768 return call.origin->wrap(cx, rval) &&
769 call.origin->wrapException(cx);
772 JSString *
773 JSCrossCompartmentWrapper::obj_toString(JSContext *cx, JSObject *wrapper)
775 AutoCompartment call(cx, wrappedObject(wrapper));
776 if (!call.enter())
777 return NULL;
779 JSString *str = JSWrapper::obj_toString(cx, wrapper);
780 if (!str)
781 return NULL;
783 call.leave();
784 if (!call.origin->wrap(cx, &str))
785 return NULL;
786 return str;
789 JSString *
790 JSCrossCompartmentWrapper::fun_toString(JSContext *cx, JSObject *wrapper, uintN indent)
792 AutoCompartment call(cx, wrappedObject(wrapper));
793 if (!call.enter())
794 return NULL;
796 JSString *str = JSWrapper::fun_toString(cx, wrapper, indent);
797 if (!str)
798 return NULL;
800 call.leave();
801 if (!call.origin->wrap(cx, &str))
802 return NULL;
803 return str;
806 JSCrossCompartmentWrapper JSCrossCompartmentWrapper::singleton(0);