From 0aeafafb0932588e5970f7dfccecbaf70c269a3e Mon Sep 17 00:00:00 2001 From: Justin Lebar Date: Tue, 4 Oct 2011 15:25:18 -0400 Subject: [PATCH] Bug 691192 - JSAutoEnterCompartment::enter shouldn't malloc(). r=luke --- js/src/jsapi.cpp | 26 +++++++++++++++++++++----- js/src/jsapi.h | 40 +++++++++++++++++++++++++++------------- 2 files changed, 48 insertions(+), 18 deletions(-) diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 0c117cfe3525..d005723de3bb 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -1323,13 +1323,20 @@ JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call) bool JSAutoEnterCompartment::enter(JSContext *cx, JSObject *target) { - JS_ASSERT(!call); - if (cx->compartment == target->compartment()) { - call = reinterpret_cast(1); + JS_ASSERT(state == STATE_UNENTERED); + if (cx->compartment == target->getCompartment()) { + state = STATE_SAME_COMPARTMENT; return true; } - call = JS_EnterCrossCompartmentCall(cx, target); - return call != NULL; + + JS_STATIC_ASSERT(sizeof(bytes) == sizeof(AutoCompartment)); + CHECK_REQUEST(cx); + AutoCompartment *call = new (bytes) AutoCompartment(cx, target); + if (call->enter()) { + state = STATE_OTHER_COMPARTMENT; + return true; + } + return false; } void @@ -1338,6 +1345,15 @@ JSAutoEnterCompartment::enterAndIgnoreErrors(JSContext *cx, JSObject *target) (void) enter(cx, target); } +JSAutoEnterCompartment::~JSAutoEnterCompartment() +{ + if (state == STATE_OTHER_COMPARTMENT) { + AutoCompartment* ac = reinterpret_cast(bytes); + CHECK_REQUEST(ac->context); + ac->~AutoCompartment(); + } +} + namespace JS { bool diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 63530844d52c..28ca2a3b4fd8 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -2214,27 +2214,41 @@ JS_END_EXTERN_C class JS_PUBLIC_API(JSAutoEnterCompartment) { - JSCrossCompartmentCall *call; + /* + * This is a poor man's Maybe, because we don't have + * access to the AutoCompartment definition here. We statically assert in + * jsapi.cpp that we have the right size here. + */ +#ifndef _MSC_VER + void* bytes[13]; +#else + void* bytes[sizeof(void*) == 4 ? 16 : 13]; +#endif + + /* + * This object may be in one of three states. If enter() or + * enterAndIgnoreErrors() hasn't been called, it's in STATE_UNENTERED. + * Otherwise, if we were asked to enter into the current compartment, our + * state is STATE_SAME_COMPARTMENT. If we actually created an + * AutoCompartment and entered another compartment, our state is + * STATE_OTHER_COMPARTMENT. + */ + enum State { + STATE_UNENTERED, + STATE_SAME_COMPARTMENT, + STATE_OTHER_COMPARTMENT + } state; public: - JSAutoEnterCompartment() : call(NULL) {} + JSAutoEnterCompartment() : state(STATE_UNENTERED) {} bool enter(JSContext *cx, JSObject *target); void enterAndIgnoreErrors(JSContext *cx, JSObject *target); - bool entered() const { return call != NULL; } + bool entered() const { return state != STATE_UNENTERED; } - ~JSAutoEnterCompartment() { - if (call && call != reinterpret_cast(1)) - JS_LeaveCrossCompartmentCall(call); - } - - void swap(JSAutoEnterCompartment &other) { - JSCrossCompartmentCall *tmp = call; - call = other.call; - other.call = tmp; - } + ~JSAutoEnterCompartment(); }; JS_BEGIN_EXTERN_C