author | Igor Bukanov <igor@mir2.org> |
Mon, 13 Feb 2012 14:10:04 +0100 | |
changeset 93548 | 46c5015550aff585c8b24e3e83e5472d97a994ae |
parent 93546 | 22af7bc45a186d51c4d940a49bfff7d32aba7ad6 |
child 93549 | 1383ac50bcff5ee23ec13e1948635ece0cba1748 |
push id | 160 |
push user | lsblakk@mozilla.com |
push date | Fri, 13 Jul 2012 18:18:57 +0000 |
treeherder | mozilla-release@228ba1a111fc [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
bugs | 730221 |
milestone | 14.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/caps/include/nsJSPrincipals.h +++ b/caps/include/nsJSPrincipals.h @@ -42,17 +42,16 @@ #include "nsIPrincipal.h" class nsCString; struct nsJSPrincipals : nsIPrincipal, JSPrincipals { static JSBool Subsume(JSPrincipals *jsprin, JSPrincipals *other); static void Destroy(JSPrincipals *jsprin); - static JSBool Transcode(JSXDRState *xdr, JSPrincipals **jsprinp); /* * Get a weak reference to nsIPrincipal associated with the given JS * principal. */ static nsJSPrincipals* get(JSPrincipals *principals) { nsJSPrincipals *self = static_cast<nsJSPrincipals *>(principals); MOZ_ASSERT_IF(self, self->debugToken == DEBUG_TOKEN);
--- a/caps/include/nsScriptSecurityManager.h +++ b/caps/include/nsScriptSecurityManager.h @@ -496,17 +496,17 @@ private: // Callers MUST pass in a non-null rv here. nsIPrincipal* GetFramePrincipal(JSContext* cx, JSStackFrame* fp, nsresult* rv); // Returns null if a principal cannot be found. Note that rv can be NS_OK // when this happens -- this means that there was no script. Callers MUST // pass in a non-null rv here. static nsIPrincipal* - GetScriptPrincipal(JSContext* cx, JSScript* script, nsresult* rv); + GetScriptPrincipal(JSScript* script, nsresult* rv); // Returns null if a principal cannot be found. Note that rv can be NS_OK // when this happens -- this means that there was no script associated // with the function object, and no global object associated with the scope // of obj (the last object on its parent chain). If the caller is walking // the JS stack, fp must point to the current frame in the stack iteration. // Callers MUST pass in a non-null rv here. static nsIPrincipal*
--- a/caps/src/nsJSPrincipals.cpp +++ b/caps/src/nsJSPrincipals.cpp @@ -81,80 +81,16 @@ nsJSPrincipals::Destroy(JSPrincipals *js nsjsprin->AddRef(); nsjsprin->refcount--; #else nsjsprin->refcount++; #endif nsjsprin->Release(); } -/* static */ JSBool -nsJSPrincipals::Transcode(JSXDRState *xdr, JSPrincipals **jsprinp) -{ - nsresult rv; - - if (xdr->mode == JSXDR_ENCODE) { - nsIObjectOutputStream *stream = - reinterpret_cast<nsIObjectOutputStream*>(xdr->userdata); - - // Flush xdr'ed data to the underlying object output stream. - uint32_t size; - char *data = (char*) ::JS_XDRMemGetData(xdr, &size); - - rv = stream->Write32(size); - if (NS_SUCCEEDED(rv)) { - rv = stream->WriteBytes(data, size); - if (NS_SUCCEEDED(rv)) { - ::JS_XDRMemResetData(xdr); - - rv = stream->WriteObject(nsJSPrincipals::get(*jsprinp), true); - } - } - } else { - NS_ASSERTION(JS_XDRMemDataLeft(xdr) == 0, "XDR out of sync?!"); - nsIObjectInputStream *stream = - reinterpret_cast<nsIObjectInputStream*>(xdr->userdata); - - nsCOMPtr<nsIPrincipal> prin; - rv = stream->ReadObject(true, getter_AddRefs(prin)); - if (NS_SUCCEEDED(rv)) { - PRUint32 size; - rv = stream->Read32(&size); - if (NS_SUCCEEDED(rv)) { - char *data = nsnull; - if (size != 0) - rv = stream->ReadBytes(size, &data); - if (NS_SUCCEEDED(rv)) { - char *olddata; - uint32_t oldsize; - - // Any decode-mode JSXDRState whose userdata points to an - // nsIObjectInputStream instance must use nsMemory to Alloc - // and Free its data buffer. Swap the new buffer we just - // read for the old, exhausted data. - olddata = (char*) ::JS_XDRMemGetData(xdr, &oldsize); - nsMemory::Free(olddata); - ::JS_XDRMemSetData(xdr, data, size); - - *jsprinp = nsJSPrincipals::get(prin); - JS_HoldPrincipals(*jsprinp); - } - } - } - } - - if (NS_FAILED(rv)) { - ::JS_ReportError(xdr->cx, "can't %scode principals (failure code %x)", - (xdr->mode == JSXDR_ENCODE) ? "en" : "de", - (unsigned int) rv); - return JS_FALSE; - } - return JS_TRUE; -} - #ifdef DEBUG // Defined here so one can do principals->dump() in the debugger JS_EXPORT_API(void) JSPrincipals::dump() { if (debugToken == nsJSPrincipals::DEBUG_TOKEN) { static_cast<nsJSPrincipals *>(this)->dumpImpl();
--- a/caps/src/nsScriptSecurityManager.cpp +++ b/caps/src/nsScriptSecurityManager.cpp @@ -2165,27 +2165,26 @@ nsScriptSecurityManager::GetPrincipalFro if (globalData) NS_IF_ADDREF(*result = globalData->GetPrincipal()); return NS_OK; } // static nsIPrincipal* -nsScriptSecurityManager::GetScriptPrincipal(JSContext *cx, - JSScript *script, +nsScriptSecurityManager::GetScriptPrincipal(JSScript *script, nsresult* rv) { NS_PRECONDITION(rv, "Null out param"); *rv = NS_OK; if (!script) { return nsnull; } - JSPrincipals *jsp = JS_GetScriptPrincipals(cx, script); + JSPrincipals *jsp = JS_GetScriptPrincipals(script); if (!jsp) { *rv = NS_ERROR_FAILURE; NS_ERROR("Script compiled without principals!"); return nsnull; } return nsJSPrincipals::get(jsp); } @@ -2248,31 +2247,31 @@ nsScriptSecurityManager::GetFunctionObje // reliable principals compiled into the function itself. nsIPrincipal *result = doGetObjectPrincipal(obj); if (!result) *rv = NS_ERROR_FAILURE; return result; } - return GetScriptPrincipal(cx, script, rv); + return GetScriptPrincipal(script, rv); } nsIPrincipal* nsScriptSecurityManager::GetFramePrincipal(JSContext *cx, JSStackFrame *fp, nsresult *rv) { NS_PRECONDITION(rv, "Null out param"); JSObject *obj = JS_GetFrameFunctionObject(cx, fp); if (!obj) { // Must be in a top-level script. Get principal from the script. JSScript *script = JS_GetFrameScript(cx, fp); - return GetScriptPrincipal(cx, script, rv); + return GetScriptPrincipal(script, rv); } nsIPrincipal* result = GetFunctionObjectPrincipal(cx, obj, fp, rv); #ifdef DEBUG if (NS_SUCCEEDED(*rv) && !result) { JSFunction *fun = JS_GetObjectFunction(obj); @@ -3376,17 +3375,16 @@ nsresult nsScriptSecurityManager::Init() NS_ENSURE_SUCCESS(rv, rv); rv = runtimeService->GetRuntime(&sRuntime); NS_ENSURE_SUCCESS(rv, rv); static const JSSecurityCallbacks securityCallbacks = { CheckObjectAccess, nsJSPrincipals::Subsume, - nsJSPrincipals::Transcode, ObjectPrincipalFinder, ContentSecurityPolicyPermitsJSAction }; MOZ_ASSERT(!JS_GetSecurityCallbacks(sRuntime)); JS_SetSecurityCallbacks(sRuntime, &securityCallbacks); JS_InitDestroyPrincipalsCallback(sRuntime, nsJSPrincipals::Destroy);
--- a/content/xbl/src/nsXBLSerialize.cpp +++ b/content/xbl/src/nsXBLSerialize.cpp @@ -33,82 +33,26 @@ * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsXBLSerialize.h" #include "nsDOMScriptObjectHolder.h" #include "nsContentUtils.h" -#include "jsxdrapi.h" nsresult XBL_SerializeFunction(nsIScriptContext* aContext, nsIObjectOutputStream* aStream, JSObject* aFunctionObject) { JSContext* cx = aContext->GetNativeContext(); - JSXDRState *xdr = ::JS_XDRNewMem(cx, JSXDR_ENCODE); - if (!xdr) - return NS_ERROR_OUT_OF_MEMORY; - xdr->userdata = static_cast<void*>(aStream); - - JSAutoRequest ar(cx); - nsresult rv; - if (!JS_XDRFunctionObject(xdr, &aFunctionObject)) { - rv = NS_ERROR_FAILURE; - } else { - uint32_t size; - const char* data = reinterpret_cast<const char*> - (JS_XDRMemGetData(xdr, &size)); - NS_ASSERTION(data, "no decoded JSXDRState data!"); - - rv = aStream->Write32(size); - if (NS_SUCCEEDED(rv)) - rv = aStream->WriteBytes(data, size); - } - - JS_XDRDestroy(xdr); - - return rv; + return nsContentUtils::XPConnect()->WriteFunction(aStream, cx, aFunctionObject); } -// static nsresult XBL_DeserializeFunction(nsIScriptContext* aContext, nsIObjectInputStream* aStream, - JSObject** aFunctionObject) + JSObject** aFunctionObjectp) { - *aFunctionObject = nsnull; - - PRUint32 size; - nsresult rv = aStream->Read32(&size); - if (NS_FAILED(rv)) - return rv; - - char* data; - rv = aStream->ReadBytes(size, &data); - if (NS_FAILED(rv)) - return rv; - JSContext* cx = aContext->GetNativeContext(); - JSXDRState *xdr = JS_XDRNewMem(cx, JSXDR_DECODE); - if (!xdr) { - rv = NS_ERROR_OUT_OF_MEMORY; - } else { - xdr->userdata = static_cast<void*>(aStream); - JSAutoRequest ar(cx); - JS_XDRMemSetData(xdr, data, size); - - if (!JS_XDRFunctionObject(xdr, aFunctionObject)) { - rv = NS_ERROR_FAILURE; - } - - uint32_t junk; - data = static_cast<char*>(JS_XDRMemGetData(xdr, &junk)); - JS_XDRMemSetData(xdr, NULL, 0); - JS_XDRDestroy(xdr); - } - - nsMemory::Free(data); - NS_ENSURE_SUCCESS(rv, rv); - return rv; + return nsContentUtils::XPConnect()->ReadFunction(aStream, cx, aFunctionObjectp); }
--- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -73,17 +73,16 @@ #include "nsXPCOMCIDInternal.h" #include "nsIXULRuntime.h" #include "nsDOMClassInfo.h" #include "xpcpublic.h" #include "jsdbgapi.h" // for JS_ClearWatchPointsForObject #include "jswrapper.h" -#include "jsxdrapi.h" #include "nsIArray.h" #include "nsIObjectInputStream.h" #include "nsIObjectOutputStream.h" #include "nsDOMScriptObjectHolder.h" #include "prmem.h" #include "WrapperFactory.h" #include "nsGlobalWindow.h" #include "nsScriptNameSpaceManager.h" @@ -1960,129 +1959,33 @@ nsJSContext::BindCompiledEventHandler(ns return rv; } // serialization nsresult nsJSContext::Serialize(nsIObjectOutputStream* aStream, JSScript* aScriptObject) { - if (!aScriptObject) - return NS_ERROR_FAILURE; - - nsresult rv; - - JSContext* cx = mContext; - JSXDRState *xdr = ::JS_XDRNewMem(cx, JSXDR_ENCODE); - if (! xdr) - return NS_ERROR_OUT_OF_MEMORY; - xdr->userdata = (void*) aStream; - - JSAutoRequest ar(cx); - if (! ::JS_XDRScript(xdr, &aScriptObject)) { - rv = NS_ERROR_FAILURE; // likely to be a principals serialization error - } else { - // Get the encoded JSXDRState data and write it. The JSXDRState owns - // this buffer memory and will free it beneath ::JS_XDRDestroy. - // - // If an XPCOM object needs to be written in the midst of the JS XDR - // encoding process, the C++ code called back from the JS engine (e.g., - // nsEncodeJSPrincipals in caps/src/nsJSPrincipals.cpp) will flush data - // from the JSXDRState to aStream, then write the object, then return - // to JS XDR code with xdr reset so new JS data is encoded at the front - // of the xdr's data buffer. - // - // However many XPCOM objects are interleaved with JS XDR data in the - // stream, when control returns here from ::JS_XDRScript, we'll have - // one last buffer of data to write to aStream. - - uint32_t size; - const char* data = reinterpret_cast<const char*> - (::JS_XDRMemGetData(xdr, &size)); - NS_ASSERTION(data, "no decoded JSXDRState data!"); - - rv = aStream->Write32(size); - if (NS_SUCCEEDED(rv)) - rv = aStream->WriteBytes(data, size); - } - - ::JS_XDRDestroy(xdr); - if (NS_FAILED(rv)) return rv; - - return rv; + if (!aScriptObject) + return NS_ERROR_FAILURE; + + return nsContentUtils::XPConnect()->WriteScript(aStream, mContext, aScriptObject); } nsresult nsJSContext::Deserialize(nsIObjectInputStream* aStream, nsScriptObjectHolder<JSScript>& aResult) { - NS_TIME_FUNCTION_MIN(1.0); - - PRUint32 size; - nsresult rv = aStream->Read32(&size); - if (NS_FAILED(rv)) return rv; - - char* data; - rv = aStream->ReadBytes(size, &data); - if (NS_FAILED(rv)) return rv; - - JSContext* cx = mContext; - - JSXDRState *xdr = ::JS_XDRNewMem(cx, JSXDR_DECODE); - JSScript *result = nsnull; - if (! xdr) { - rv = NS_ERROR_OUT_OF_MEMORY; - } else { - xdr->userdata = (void*) aStream; - JSAutoRequest ar(cx); - ::JS_XDRMemSetData(xdr, data, size); - - if (! ::JS_XDRScript(xdr, &result)) { - rv = NS_ERROR_FAILURE; // principals deserialization error? - } - - // Update data in case ::JS_XDRScript called back into C++ code to - // read an XPCOM object. - // - // In that case, the serialization process must have flushed a run - // of counted bytes containing JS data at the point where the XPCOM - // object starts, after which an encoding C++ callback from the JS - // XDR code must have written the XPCOM object directly into the - // nsIObjectOutputStream. - // - // The deserialization process will XDR-decode counted bytes up to - // but not including the XPCOM object, then call back into C++ to - // read the object, then read more counted bytes and hand them off - // to the JSXDRState, so more JS data can be decoded. - // - // This interleaving of JS XDR data and XPCOM object data may occur - // several times beneath the call to ::JS_XDRScript, above. At the - // end of the day, we need to free (via nsMemory) the data owned by - // the JSXDRState. So we steal it back, nulling xdr's buffer so it - // doesn't get passed to ::JS_free by ::JS_XDRDestroy. - - uint32_t junk; - data = (char*) ::JS_XDRMemGetData(xdr, &junk); - if (data) - ::JS_XDRMemSetData(xdr, NULL, 0); - ::JS_XDRDestroy(xdr); - } - - // If data is null now, it must have been freed while deserializing an - // XPCOM object (e.g., a principal) beneath ::JS_XDRScript. - if (data) - nsMemory::Free(data); - NS_ASSERTION(aResult.getScriptTypeID()==JAVASCRIPT, - "Expecting JS script object holder"); - - // Now that we've cleaned up, handle the case when rv is a failure - // code, which could happen for all sorts of reasons above. - NS_ENSURE_SUCCESS(rv, rv); - - return aResult.set(result); + NS_TIME_FUNCTION_MIN(1.0); + + JSScript *script; + nsresult rv = nsContentUtils::XPConnect()->ReadScript(aStream, mContext, &script); + if (NS_FAILED(rv)) return rv; + + return aResult.set(script); } nsIScriptGlobalObject * nsJSContext::GetGlobalObject() { JSObject *global = ::JS_GetGlobalObject(mContext); if (!global) {
--- a/js/src/jsapi-tests/testCloneScript.cpp +++ b/js/src/jsapi-tests/testCloneScript.cpp @@ -112,17 +112,17 @@ BEGIN_TEST(test_cloneScriptWithPrincipal JSFunction *fun; CHECK(fun = JS_CompileFunctionForPrincipals(cx, A, principalsA, "f", mozilla::ArrayLength(argnames), argnames, source, strlen(source), __FILE__, 1)); JSScript *script; CHECK(script = JS_GetFunctionScript(cx, fun)); - CHECK(JS_GetScriptPrincipals(cx, script) == principalsA); + CHECK(JS_GetScriptPrincipals(script) == principalsA); CHECK(obj = JS_GetFunctionObject(fun)); } // Clone into B { JSAutoEnterCompartment b; if (!b.enter(cx, B)) return false; @@ -131,25 +131,25 @@ BEGIN_TEST(test_cloneScriptWithPrincipal CHECK(cloned = JS_CloneFunctionObject(cx, obj, B)); JSFunction *fun; CHECK(fun = JS_ValueToFunction(cx, JS::ObjectValue(*cloned))); JSScript *script; CHECK(script = JS_GetFunctionScript(cx, fun)); - CHECK(JS_GetScriptPrincipals(cx, script) == principalsB); + CHECK(JS_GetScriptPrincipals(script) == principalsB); JS::Value v; JS::Value args[] = { JS::Int32Value(1) }; CHECK(JS_CallFunctionValue(cx, B, JS::ObjectValue(*cloned), 1, args, &v)); CHECK(v.isObject()); JSObject *funobj = &v.toObject(); CHECK(JS_ObjectIsFunction(cx, funobj)); CHECK(fun = JS_ValueToFunction(cx, v)); CHECK(script = JS_GetFunctionScript(cx, fun)); - CHECK(JS_GetScriptPrincipals(cx, script) == principalsB); + CHECK(JS_GetScriptPrincipals(script) == principalsB); } return true; } END_TEST(test_cloneScriptWithPrincipals)
--- a/js/src/jsapi-tests/testOriginPrincipals.cpp +++ b/js/src/jsapi-tests/testOriginPrincipals.cpp @@ -8,17 +8,16 @@ JSPrincipals * ObjectPrincipalsFinder(JSObject *) { return sCurrentGlobalPrincipals; } static const JSSecurityCallbacks seccb = { NULL, NULL, - NULL, ObjectPrincipalsFinder, NULL }; JSPrincipals *sOriginPrincipalsInErrorReporter = NULL; static void ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report) @@ -96,18 +95,18 @@ bool testInner(const char *asciiChars, JSPrincipals *principal, JSPrincipals *originPrincipal) { sCurrentGlobalPrincipals = principal; jsval rval; CHECK(eval(asciiChars, principal, originPrincipal, &rval)); JSScript *script = JS_GetFunctionScript(cx, JSVAL_TO_OBJECT(rval)->toFunction()); - CHECK(JS_GetScriptPrincipals(cx, script) == principal); - CHECK(JS_GetScriptOriginPrincipals(cx, script) == originPrincipal); + CHECK(JS_GetScriptPrincipals(script) == principal); + CHECK(JS_GetScriptOriginPrincipals(script) == originPrincipal); return true; } bool testError(const char *asciiChars) { jsval rval;
--- a/js/src/jsapi-tests/testXDR.cpp +++ b/js/src/jsapi-tests/testXDR.cpp @@ -49,109 +49,87 @@ FreezeThawImpl(JSContext *cx, T *thing, } JS_XDRDestroy(w); if (!memory) return NULL; // thaw JSXDRState *r = JS_XDRNewMem(cx, JSXDR_DECODE); JS_XDRMemSetData(r, memory, nbytes); + + JSScript *script = GetScript(cx, thing); + JS_XDRSetPrincipals(r, script->principals, script->originPrincipals); if (!xdrAction(r, &thing)) thing = NULL; JS_XDRDestroy(r); // this frees `memory return thing; } static JSScript * +GetScript(JSContext *cx, JSScript *script) +{ + return script; +} + +static JSScript * +GetScript(JSContext *cx, JSObject *funobj) +{ + return JS_GetFunctionScript(cx, JS_GetObjectFunction(funobj)); +} + +static JSScript * FreezeThaw(JSContext *cx, JSScript *script) { return FreezeThawImpl(cx, script, JS_XDRScript); } static JSObject * FreezeThaw(JSContext *cx, JSObject *funobj) { return FreezeThawImpl(cx, funobj, JS_XDRFunctionObject); } static JSPrincipals testPrincipals[] = { { 1 }, { 1 }, }; -static JSBool -TranscodePrincipals(JSXDRState *xdr, JSPrincipals **principalsp) -{ - uint32_t index; - if (xdr->mode == JSXDR_ENCODE) { - JSPrincipals *p = *principalsp; - for (index = 0; ; ++index) { - if (index == mozilla::ArrayLength(testPrincipals)) - return false; - if (p == &testPrincipals[index]) - break; - } - } - - if (!JS_XDRUint32(xdr, &index)) - return false; - - if (xdr->mode == JSXDR_DECODE) { - if (index >= mozilla::ArrayLength(testPrincipals)) - return false; - *principalsp = &testPrincipals[index]; - JS_HoldPrincipals(*principalsp); - } - - return true; -} - BEGIN_TEST(testXDR_principals) { - static const JSSecurityCallbacks seccb = { - NULL, - NULL, - TranscodePrincipals, - NULL, - NULL - }; - - JS_SetSecurityCallbacks(rt, &seccb); - JSScript *script; for (int i = TEST_FIRST; i != TEST_END; ++i) { script = createScriptViaXDR(NULL, NULL, i); CHECK(script); - CHECK(!JS_GetScriptPrincipals(cx, script)); - CHECK(!JS_GetScriptOriginPrincipals(cx, script)); + CHECK(!JS_GetScriptPrincipals(script)); + CHECK(!JS_GetScriptOriginPrincipals(script)); script = createScriptViaXDR(NULL, NULL, i); CHECK(script); - CHECK(!JS_GetScriptPrincipals(cx, script)); - CHECK(!JS_GetScriptOriginPrincipals(cx, script)); + CHECK(!JS_GetScriptPrincipals(script)); + CHECK(!JS_GetScriptOriginPrincipals(script)); script = createScriptViaXDR(&testPrincipals[0], NULL, i); CHECK(script); - CHECK(JS_GetScriptPrincipals(cx, script) == &testPrincipals[0]); - CHECK(JS_GetScriptOriginPrincipals(cx, script) == &testPrincipals[0]); + CHECK(JS_GetScriptPrincipals(script) == &testPrincipals[0]); + CHECK(JS_GetScriptOriginPrincipals(script) == &testPrincipals[0]); script = createScriptViaXDR(&testPrincipals[0], &testPrincipals[0], i); CHECK(script); - CHECK(JS_GetScriptPrincipals(cx, script) == &testPrincipals[0]); - CHECK(JS_GetScriptOriginPrincipals(cx, script) == &testPrincipals[0]); + CHECK(JS_GetScriptPrincipals(script) == &testPrincipals[0]); + CHECK(JS_GetScriptOriginPrincipals(script) == &testPrincipals[0]); script = createScriptViaXDR(&testPrincipals[0], &testPrincipals[1], i); CHECK(script); - CHECK(JS_GetScriptPrincipals(cx, script) == &testPrincipals[0]); - CHECK(JS_GetScriptOriginPrincipals(cx, script) == &testPrincipals[1]); + CHECK(JS_GetScriptPrincipals(script) == &testPrincipals[0]); + CHECK(JS_GetScriptOriginPrincipals(script) == &testPrincipals[1]); script = createScriptViaXDR(NULL, &testPrincipals[1], i); CHECK(script); - CHECK(!JS_GetScriptPrincipals(cx, script)); - CHECK(JS_GetScriptOriginPrincipals(cx, script) == &testPrincipals[1]); + CHECK(!JS_GetScriptPrincipals(script)); + CHECK(JS_GetScriptOriginPrincipals(script) == &testPrincipals[1]); } return true; } enum TestCase { TEST_FIRST, TEST_SCRIPT = TEST_FIRST, @@ -185,17 +163,17 @@ JSScript *createScriptViaXDR(JSPrincipal if (!ok || !v.isObject()) return NULL; JSObject *funobj = &v.toObject(); if (testCase == TEST_FUNCTION) { funobj = FreezeThaw(cx, funobj); if (!funobj) return NULL; } - return JS_GetFunctionScript(cx, JS_GetObjectFunction(funobj)); + return GetScript(cx, funobj); } END_TEST(testXDR_principals) BEGIN_TEST(testXDR_atline) { JS_ToggleOptions(cx, JSOPTION_ATLINE); CHECK(JS_GetOptions(cx) & JSOPTION_ATLINE);
--- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -1526,26 +1526,16 @@ typedef JSBool typedef void (* JSDestroyPrincipalsOp)(JSPrincipals *principals); typedef JSBool (* JSSubsumePrincipalsOp)(JSPrincipals *principals1, JSPrincipals *principals2); /* - * XDR-encode or -decode a principals instance, based on whether xdr->mode is - * JSXDR_ENCODE, in which case *principalsp should be encoded; or JSXDR_DECODE, - * in which case implementations must return a held (via JSPRINCIPALS_HOLD), - * non-null *principalsp out parameter. Return true on success, false on any - * error, which the implementation must have reported. - */ -typedef JSBool -(* JSPrincipalsTranscoder)(JSXDRState *xdr, JSPrincipals **principalsp); - -/* * Return a weak reference to the principals associated with obj, possibly via * the immutable parent chain leading from obj to a top-level container (e.g., * a window object in the DOM level 0). If there are no principals associated * with obj, return null. Therefore null does not mean an error was reported; * in no event should an error be reported or an exception be thrown by this * callback's implementation. */ typedef JSPrincipals * @@ -4122,17 +4112,16 @@ extern JS_PUBLIC_API(void) JS_HoldPrincipals(JSPrincipals *principals); extern JS_PUBLIC_API(void) JS_DropPrincipals(JSRuntime *rt, JSPrincipals *principals); struct JSSecurityCallbacks { JSCheckAccessOp checkObjectAccess; JSSubsumePrincipalsOp subsumePrincipals; - JSPrincipalsTranscoder principalsTranscoder; JSObjectPrincipalsFinder findObjectPrincipals; JSCSPEvalChecker contentSecurityPolicyAllows; }; extern JS_PUBLIC_API(void) JS_SetSecurityCallbacks(JSRuntime *rt, const JSSecurityCallbacks *callbacks); extern JS_PUBLIC_API(const JSSecurityCallbacks *)
--- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -477,23 +477,23 @@ JS_GetFunctionScript(JSContext *cx, JSFu JS_PUBLIC_API(JSNative) JS_GetFunctionNative(JSContext *cx, JSFunction *fun) { return fun->maybeNative(); } JS_PUBLIC_API(JSPrincipals *) -JS_GetScriptPrincipals(JSContext *cx, JSScript *script) +JS_GetScriptPrincipals(JSScript *script) { return script->principals; } JS_PUBLIC_API(JSPrincipals *) -JS_GetScriptOriginPrincipals(JSContext *cx, JSScript *script) +JS_GetScriptOriginPrincipals(JSScript *script) { return script->originPrincipals; } /************************************************************************/ /* * Stack Frame Iterator
--- a/js/src/jsdbgapi.h +++ b/js/src/jsdbgapi.h @@ -215,20 +215,20 @@ JS_ReleaseFunctionLocalNameArray(JSConte extern JS_PUBLIC_API(JSScript *) JS_GetFunctionScript(JSContext *cx, JSFunction *fun); extern JS_PUBLIC_API(JSNative) JS_GetFunctionNative(JSContext *cx, JSFunction *fun); extern JS_PUBLIC_API(JSPrincipals *) -JS_GetScriptPrincipals(JSContext *cx, JSScript *script); +JS_GetScriptPrincipals(JSScript *script); extern JS_PUBLIC_API(JSPrincipals *) -JS_GetScriptOriginPrincipals(JSContext *cx, JSScript *script); +JS_GetScriptOriginPrincipals(JSScript *script); /* * Stack Frame Iterator * * Used to iterate through the JS stack frames to extract * information from the frames. */
--- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -522,17 +522,17 @@ XDRScript(JSXDRState *xdr, JSScript **sc length = script->length; if (!JS_XDRUint32(xdr, &length)) return JS_FALSE; if (xdr->mode == JSXDR_ENCODE) { prologLength = script->mainOffset; JS_ASSERT(script->getVersion() != JSVERSION_UNKNOWN); version = (uint32_t)script->getVersion() | (script->nfixed << 16); - lineno = (uint32_t)script->lineno; + lineno = script->lineno; nslots = (uint32_t)script->nslots; nslots = (uint32_t)((script->staticLevel << 16) | script->nslots); natoms = script->natoms; notes = script->notes(); nsrcnotes = script->numNotes(); if (JSScript::isValidOffset(script->objectsOffset)) @@ -660,47 +660,44 @@ XDRScript(JSXDRState *xdr, JSScript **sc filename = const_cast<char *>(script->filename); if (!JS_XDRCString(xdr, &filename)) return false; if (xdr->mode == JSXDR_DECODE) { script->filename = SaveScriptFilename(xdr->cx, filename); Foreground::free_(filename); if (!script->filename) return false; - if (!xdr->sharedFilename) - xdr->sharedFilename = script->filename; } + if (!xdr->sharedFilename) + xdr->sharedFilename = script->filename; } else if (scriptBits & (1 << SharedFilename)) { JS_ASSERT(xdr->sharedFilename); if (xdr->mode == JSXDR_DECODE) script->filename = xdr->sharedFilename; } if (xdr->mode == JSXDR_DECODE) { + script->lineno = lineno; + script->nslots = uint16_t(nslots); + script->staticLevel = uint16_t(nslots >> 16); + + /* The origin principals must be normalized at this point. */ + JS_ASSERT_IF(xdr->principals, xdr->originPrincipals); JS_ASSERT(!script->principals); JS_ASSERT(!script->originPrincipals); - - /* The origin principals must be normalized at this point. */ - JS_ASSERT_IF(script->principals, script->originPrincipals); if (xdr->principals) { script->principals = xdr->principals; JS_HoldPrincipals(xdr->principals); } if (xdr->originPrincipals) { script->originPrincipals = xdr->originPrincipals; JS_HoldPrincipals(xdr->originPrincipals); } } - if (xdr->mode == JSXDR_DECODE) { - script->lineno = (unsigned)lineno; - script->nslots = uint16_t(nslots); - script->staticLevel = uint16_t(nslots >> 16); - } - for (i = 0; i != natoms; ++i) { if (!js_XDRAtom(xdr, &script->atoms[i])) return false; } /* * Here looping from 0-to-length to xdr objects is essential. It ensures * that block objects from the script->objects array will be written and @@ -1706,19 +1703,17 @@ CloneScript(JSContext *cx, JSScript *scr /* * Hand p off from w to r. Don't want them to share the data mem, lest * they both try to free it in JS_XDRDestroy. */ JS_XDRMemSetData(r, p, nbytes); JS_XDRMemSetData(w, NULL, 0); - r->principals = cx->compartment->principals; - r->originPrincipals = JSScript::normalizeOriginPrincipals(cx->compartment->principals, - script->originPrincipals); + JS_XDRSetPrincipals(r, cx->compartment->principals, script->originPrincipals); JSScript *newScript = NULL; if (!XDRScript(r, &newScript)) return NULL; return newScript; } } /* namespace js */
--- a/js/src/jsxdrapi.cpp +++ b/js/src/jsxdrapi.cpp @@ -231,17 +231,16 @@ static JSXDROps xdrmem_ops = { mem_raw, mem_seek, mem_tell, mem_finalize }; JS_PUBLIC_API(void) JS_XDRInitBase(JSXDRState *xdr, JSXDRMode mode, JSContext *cx) { xdr->mode = mode; xdr->cx = cx; - xdr->userdata = NULL; xdr->sharedFilename = NULL; xdr->principals = NULL; xdr->originPrincipals = NULL; } JS_PUBLIC_API(JSXDRState *) JS_XDRNewMem(JSContext *cx, JSXDRMode mode) { @@ -302,16 +301,24 @@ JS_XDRMemResetData(JSXDRState *xdr) JS_PUBLIC_API(void) JS_XDRDestroy(JSXDRState *xdr) { JSContext *cx = xdr->cx; xdr->ops->finalize(xdr); cx->free_(xdr); } +JS_PUBLIC_API(void) +JS_XDRSetPrincipals(JSXDRState *xdr, JSPrincipals *principals, JSPrincipals *originPrincipals) +{ + JS_ASSERT(xdr->mode == JSXDR_DECODE); + xdr->principals = principals; + xdr->originPrincipals = JSScript::normalizeOriginPrincipals(principals, originPrincipals); +} + JS_PUBLIC_API(JSBool) JS_XDRUint8(JSXDRState *xdr, uint8_t *b) { uint32_t l = *b; if (!JS_XDRUint32(xdr, &l)) return JS_FALSE; *b = (uint8_t) l; return JS_TRUE; @@ -527,105 +534,20 @@ js_XDRAtom(JSXDRState *xdr, JSAtom **ato cx->free_(chars); if (!atom) return JS_FALSE; *atomp = atom; return JS_TRUE; } -static bool -XDRPrincipals(JSXDRState *xdr) -{ - const uint8_t HAS_PRINCIPALS = 1; - const uint8_t HAS_ORIGIN = 2; - - uint8_t flags = 0; - if (xdr->mode == JSXDR_ENCODE) { - if (xdr->principals) - flags |= HAS_PRINCIPALS; - - /* - * For the common case when principals == originPrincipals we want to - * avoid serializing the same principal twice. As originPrincipals are - * normalized and principals imply originPrincipals we simply set - * HAS_ORIGIN only if originPrincipals is set and different from - * principals. During decoding we re-normalize originPrincipals. - */ - JS_ASSERT_IF(xdr->principals, xdr->originPrincipals); - if (xdr->originPrincipals && xdr->originPrincipals != xdr->principals) - flags |= HAS_ORIGIN; - } - - if (!JS_XDRUint8(xdr, &flags)) - return false; - - if (flags & (HAS_PRINCIPALS | HAS_ORIGIN)) { - const JSSecurityCallbacks *scb = JS_GetSecurityCallbacks(xdr->cx->runtime); - if (xdr->mode == JSXDR_DECODE) { - if (!scb || !scb->principalsTranscoder) { - JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, - JSMSG_CANT_DECODE_PRINCIPALS); - return false; - } - } else { - JS_ASSERT(scb); - JS_ASSERT(scb->principalsTranscoder); - } - - if (flags & HAS_PRINCIPALS) { - if (!scb->principalsTranscoder(xdr, &xdr->principals)) - return false; - } - - if (flags & HAS_ORIGIN) { - if (!scb->principalsTranscoder(xdr, &xdr->originPrincipals)) - return false; - } else if (xdr->mode == JSXDR_DECODE && xdr->principals) { - xdr->originPrincipals = xdr->principals; - JS_HoldPrincipals(xdr->principals); - } - } - - return true; -} - -namespace { - -struct AutoDropXDRPrincipals { - JSXDRState *const xdr; - - AutoDropXDRPrincipals(JSXDRState *xdr) - : xdr(xdr) { } - - ~AutoDropXDRPrincipals() { - if (xdr->mode == JSXDR_DECODE) { - if (xdr->principals) - JS_DropPrincipals(xdr->cx->runtime, xdr->principals); - if (xdr->originPrincipals) - JS_DropPrincipals(xdr->cx->runtime, xdr->originPrincipals); - } - xdr->principals = NULL; - xdr->originPrincipals = NULL; - } -}; - -} /* namespace anonymous */ - JS_PUBLIC_API(JSBool) JS_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) { - AutoDropXDRPrincipals drop(xdr); - if (xdr->mode == JSXDR_ENCODE) { - JSScript *script = (*objp)->toFunction()->script(); - xdr->principals = script->principals; - xdr->originPrincipals = script->originPrincipals; - } - - return XDRPrincipals(xdr) && XDRFunctionObject(xdr, objp); + return XDRFunctionObject(xdr, objp); } JS_PUBLIC_API(JSBool) JS_XDRScript(JSXDRState *xdr, JSScript **scriptp) { JSScript *script; uint32_t magic; uint32_t bytecodeVer; @@ -645,26 +567,18 @@ JS_XDRScript(JSXDRState *xdr, JSScript * if (magic != JSXDR_MAGIC_SCRIPT_CURRENT || bytecodeVer != JSXDR_BYTECODE_VERSION) { /* We do not provide binary compatibility with older scripts. */ JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL, JSMSG_BAD_SCRIPT_MAGIC); return false; } - { - AutoDropXDRPrincipals drop(xdr); - if (xdr->mode == JSXDR_ENCODE) { - xdr->principals = script->principals; - xdr->originPrincipals = script->originPrincipals; - } - - if (!XDRPrincipals(xdr) || !XDRScript(xdr, &script)) - return false; - } + if (!XDRScript(xdr, &script)) + return false; if (xdr->mode == JSXDR_DECODE) { JS_ASSERT(!script->compileAndGo); script->globalObject = GetCurrentGlobal(xdr->cx); js_CallNewScriptHook(xdr->cx, script, NULL); Debugger::onNewScript(xdr->cx, script, NULL); *scriptp = script; }
--- a/js/src/jsxdrapi.h +++ b/js/src/jsxdrapi.h @@ -104,17 +104,16 @@ typedef struct JSXDROps { uint32_t (*tell)(JSXDRState *); void (*finalize)(JSXDRState *); } JSXDROps; struct JSXDRState { JSXDRMode mode; JSXDROps *ops; JSContext *cx; - void *userdata; const char *sharedFilename; JSPrincipals *principals; JSPrincipals *originPrincipals; }; extern JS_PUBLIC_API(void) JS_XDRInitBase(JSXDRState *xdr, JSXDRMode mode, JSContext *cx); @@ -131,16 +130,26 @@ extern JS_PUBLIC_API(uint32_t) JS_XDRMemDataLeft(JSXDRState *xdr); extern JS_PUBLIC_API(void) JS_XDRMemResetData(JSXDRState *xdr); extern JS_PUBLIC_API(void) JS_XDRDestroy(JSXDRState *xdr); +/* + * Set principals that should be assigned to decoded scripts and functions. + * The principals is not held via JS_HoldPrincipals/JS_DropPrincipals unless + * they are stored in a decoded script. Thus the caller must either ensure + * that the principals outlive the XDR instance or are explicitly set to NULL + * before they release by the caller. + */ +extern JS_PUBLIC_API(void) +JS_XDRSetPrincipals(JSXDRState *xdr, JSPrincipals *principals, JSPrincipals *originPrincipals); + extern JS_PUBLIC_API(JSBool) JS_XDRUint8(JSXDRState *xdr, uint8_t *b); extern JS_PUBLIC_API(JSBool) JS_XDRUint16(JSXDRState *xdr, uint16_t *s); extern JS_PUBLIC_API(JSBool) JS_XDRUint32(JSXDRState *xdr, uint32_t *lp);
--- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -4854,17 +4854,16 @@ CheckObjectAccess(JSContext *cx, JSObjec { return true; } JSSecurityCallbacks securityCallbacks = { CheckObjectAccess, NULL, NULL, - NULL, NULL }; int main(int argc, char **argv, char **envp) { int stackDummy; JSRuntime *rt;
--- a/js/xpconnect/idl/nsIXPConnect.idl +++ b/js/xpconnect/idl/nsIXPConnect.idl @@ -45,16 +45,18 @@ #include "nsIClassInfo.idl" #include "xpccomponents.idl" #include "xpcjsid.idl" #include "xpcexception.idl" #include "nsIInterfaceInfo.idl" #include "nsIInterfaceInfoManager.idl" #include "nsIExceptionService.idl" #include "nsIVariant.idl" +#include "nsIObjectOutputStream.idl" +#include "nsIObjectInputStream.idl" %{ C++ #include "jspubtd.h" #include "xptinfo.h" #include "nsAXPCNativeCallContext.h" class nsWrapperCache; %} @@ -65,16 +67,17 @@ class nsWrapperCache; [ptr] native JSContextPtr(JSContext); [ptr] native JSClassPtr(JSClass); [ptr] native JSObjectPtr(JSObject); [ptr] native JSValPtr(jsval); [ptr] native JSValConstPtr(const jsval); native JSPropertyOp(JSPropertyOp); native JSEqualityOp(JSEqualityOp); +[ptr] native JSScriptPtr(JSScript); [ptr] native voidPtrPtr(void*); [ptr] native nsScriptObjectTracerPtr(nsScriptObjectTracer); [ref] native nsCCTraversalCallbackRef(nsCycleCollectionTraversalCallback); [ptr] native nsAXPCNativeCallContextPtr(nsAXPCNativeCallContext); [ptr] native nsWrapperCachePtr(nsWrapperCache); /***************************************************************************/ @@ -400,17 +403,17 @@ interface nsIXPCFunctionThisTranslator : enum nsGCType { nsGCNormal, nsGCShrinking, nsGCIncremental }; %} -[uuid(0213cb40-2dd5-4ac8-a9d3-157bd53c3824)] +[uuid(08ad2253-3ed6-40ed-beec-6472f2d8dc7f)] interface nsIXPConnect : nsISupports { %{ C++ NS_DEFINE_STATIC_CID_ACCESSOR(NS_XPCONNECT_CID) %} /** * Initializes classes on a global object that has already been created. @@ -796,9 +799,23 @@ interface nsIXPConnect : nsISupports * When we place the browser in JS debug mode, there can't be any * JS on the stack. This is because we currently activate debugMode * on all scripts in the JSRuntime when the debugger is activated. * This method will turn debug mode on or off when the context * stack reaches zero length. */ [noscript] void setDebugModeWhenPossible(in boolean mode, in boolean allowSyncDisable); + + [noscript] void writeScript(in nsIObjectOutputStream aStream, + in JSContextPtr aJSContext, + in JSScriptPtr aJSScript); + + [noscript] JSScriptPtr readScript(in nsIObjectInputStream aStream, + in JSContextPtr aJSContext); + + [noscript] void writeFunction(in nsIObjectOutputStream aStream, + in JSContextPtr aJSContext, + in JSObjectPtr aJSObject); + + [noscript] JSObjectPtr readFunction(in nsIObjectInputStream aStream, + in JSContextPtr aJSContext); };
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp +++ b/js/xpconnect/loader/mozJSComponentLoader.cpp @@ -746,17 +746,17 @@ mozJSComponentLoader::GlobalForLocation( bool writeToCache = false; StartupCache* cache = StartupCache::GetSingleton(); nsCAutoString cachePath(kJSCachePrefix); rv = PathifyURI(aURI, cachePath); NS_ENSURE_SUCCESS(rv, rv); if (cache) { - rv = ReadCachedScript(cache, cachePath, cx, &script); + rv = ReadCachedScript(cache, cachePath, cx, mSystemPrincipal, &script); if (NS_SUCCEEDED(rv)) { LOG(("Successfully loaded %s from startupcache\n", nativePath.get())); } else { // This is ok, it just means the script is not yet in the // cache. Could mean that the cache was corrupted and got removed, // but either way we're going to write this out. writeToCache = true; } @@ -929,17 +929,17 @@ mozJSComponentLoader::GlobalForLocation( #ifdef DEBUG_shaver_off fprintf(stderr, "mJCL: compiled JS component %s\n", nativePath.get()); #endif if (writeToCache) { // We successfully compiled the script, so cache it. - rv = WriteCachedScript(cache, cachePath, cx, script); + rv = WriteCachedScript(cache, cachePath, cx, mSystemPrincipal, script); // Don't treat failure to write as fatal, since we might be working // with a read-only cache. if (NS_SUCCEEDED(rv)) { LOG(("Successfully wrote to cache\n")); } else { LOG(("Failed to write to cache\n")); }
--- a/js/xpconnect/loader/mozJSLoaderUtils.cpp +++ b/js/xpconnect/loader/mozJSLoaderUtils.cpp @@ -34,158 +34,75 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsAutoPtr.h" #include "nsScriptLoader.h" #include "jsapi.h" +#include "jsdbgapi.h" #include "jsxdrapi.h" +#include "nsJSPrincipals.h" + #include "mozilla/scache/StartupCache.h" #include "mozilla/scache/StartupCacheUtils.h" using namespace mozilla::scache; -static nsresult -ReadScriptFromStream(JSContext *cx, nsIObjectInputStream *stream, - JSScript **script) +// We only serialize scripts with system principals. So we don't serialize the +// principals when writing a script. Instead, when reading it back, we set the +// principals to the system principals. +nsresult +ReadCachedScript(StartupCache* cache, nsACString &uri, JSContext *cx, + nsIPrincipal *systemPrincipal, JSScript **script) { - *script = nsnull; - - PRUint32 size; - nsresult rv = stream->Read32(&size); - NS_ENSURE_SUCCESS(rv, rv); - - char *data; - rv = stream->ReadBytes(size, &data); - NS_ENSURE_SUCCESS(rv, rv); - - JSXDRState *xdr = JS_XDRNewMem(cx, JSXDR_DECODE); - NS_ENSURE_TRUE(xdr, NS_ERROR_OUT_OF_MEMORY); - - xdr->userdata = stream; - JS_XDRMemSetData(xdr, data, size); - - if (!JS_XDRScript(xdr, script)) { - rv = NS_ERROR_FAILURE; - } - - // Update data in case ::JS_XDRScript called back into C++ code to - // read an XPCOM object. - // - // In that case, the serialization process must have flushed a run - // of counted bytes containing JS data at the point where the XPCOM - // object starts, after which an encoding C++ callback from the JS - // XDR code must have written the XPCOM object directly into the - // nsIObjectOutputStream. - // - // The deserialization process will XDR-decode counted bytes up to - // but not including the XPCOM object, then call back into C++ to - // read the object, then read more counted bytes and hand them off - // to the JSXDRState, so more JS data can be decoded. - // - // This interleaving of JS XDR data and XPCOM object data may occur - // several times beneath the call to ::JS_XDRScript, above. At the - // end of the day, we need to free (via nsMemory) the data owned by - // the JSXDRState. So we steal it back, nulling xdr's buffer so it - // doesn't get passed to ::JS_free by ::JS_XDRDestroy. - - uint32_t length; - data = static_cast<char*>(JS_XDRMemGetData(xdr, &length)); - JS_XDRMemSetData(xdr, nsnull, 0); - JS_XDRDestroy(xdr); - - // If data is null now, it must have been freed while deserializing an - // XPCOM object (e.g., a principal) beneath ::JS_XDRScript. - nsMemory::Free(data); - - return rv; -} - -static nsresult -WriteScriptToStream(JSContext *cx, JSScript *script, - nsIObjectOutputStream *stream) -{ - JSXDRState *xdr = JS_XDRNewMem(cx, JSXDR_ENCODE); - NS_ENSURE_TRUE(xdr, NS_ERROR_OUT_OF_MEMORY); - - xdr->userdata = stream; - nsresult rv = NS_OK; - - if (JS_XDRScript(xdr, &script)) { - // Get the encoded JSXDRState data and write it. The JSXDRState owns - // this buffer memory and will free it beneath ::JS_XDRDestroy. - // - // If an XPCOM object needs to be written in the midst of the JS XDR - // encoding process, the C++ code called back from the JS engine (e.g., - // nsEncodeJSPrincipals in caps/src/nsJSPrincipals.cpp) will flush data - // from the JSXDRState to aStream, then write the object, then return - // to JS XDR code with xdr reset so new JS data is encoded at the front - // of the xdr's data buffer. - // - // However many XPCOM objects are interleaved with JS XDR data in the - // stream, when control returns here from ::JS_XDRScript, we'll have - // one last buffer of data to write to aStream. - - uint32_t size; - const char* data = reinterpret_cast<const char*> - (JS_XDRMemGetData(xdr, &size)); - NS_ASSERTION(data, "no decoded JSXDRState data!"); - - rv = stream->Write32(size); - if (NS_SUCCEEDED(rv)) { - rv = stream->WriteBytes(data, size); - } - } else { - rv = NS_ERROR_FAILURE; // likely to be a principals serialization error - } - - JS_XDRDestroy(xdr); - return rv; -} - -nsresult -ReadCachedScript(StartupCache* cache, nsACString &uri, JSContext *cx, JSScript **script) -{ - nsresult rv; - nsAutoArrayPtr<char> buf; PRUint32 len; - rv = cache->GetBuffer(PromiseFlatCString(uri).get(), getter_Transfers(buf), - &len); + nsresult rv = cache->GetBuffer(PromiseFlatCString(uri).get(), + getter_Transfers(buf), &len); if (NS_FAILED(rv)) { return rv; // don't warn since NOT_AVAILABLE is an ok error } - nsCOMPtr<nsIObjectInputStream> ois; - rv = NewObjectInputStreamFromBuffer(buf, len, getter_AddRefs(ois)); - NS_ENSURE_SUCCESS(rv, rv); - buf.forget(); + JSXDRState *xdr = ::JS_XDRNewMem(cx, JSXDR_DECODE); + if (!xdr) { + return NS_ERROR_OUT_OF_MEMORY; + } + + ::JS_XDRMemSetData(xdr, buf, len); + ::JS_XDRSetPrincipals(xdr, nsJSPrincipals::get(systemPrincipal), nsnull); - return ReadScriptFromStream(cx, ois, script); + JSBool ok = ::JS_XDRScript(xdr, script); + + // Prevent XDR from automatically freeing the buffer. + ::JS_XDRMemSetData(xdr, NULL, 0); + ::JS_XDRDestroy(xdr); + + return ok ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } nsresult -WriteCachedScript(StartupCache* cache, nsACString &uri, JSContext *cx, JSScript *script) +WriteCachedScript(StartupCache* cache, nsACString &uri, JSContext *cx, + nsIPrincipal *systemPrincipal, JSScript *script) { - nsresult rv; + MOZ_ASSERT(JS_GetScriptPrincipals(script) == nsJSPrincipals::get(systemPrincipal)); + MOZ_ASSERT(JS_GetScriptOriginPrincipals(script) == nsJSPrincipals::get(systemPrincipal)); - nsCOMPtr<nsIObjectOutputStream> oos; - nsCOMPtr<nsIStorageStream> storageStream; - rv = NewObjectOutputWrappedStorageStream(getter_AddRefs(oos), - getter_AddRefs(storageStream), - true); - NS_ENSURE_SUCCESS(rv, rv); + JSXDRState *xdr = ::JS_XDRNewMem(cx, JSXDR_ENCODE); + if (!xdr) { + return NS_ERROR_OUT_OF_MEMORY; + } - rv = WriteScriptToStream(cx, script, oos); - oos->Close(); - NS_ENSURE_SUCCESS(rv, rv); + nsresult rv; + if (!::JS_XDRScript(xdr, &script)) { + rv = NS_ERROR_OUT_OF_MEMORY; + } else { + uint32_t size; + char* data = static_cast<char *>(::JS_XDRMemGetData(xdr, &size)); + MOZ_ASSERT(size); + rv = cache->PutBuffer(PromiseFlatCString(uri).get(), data, size); + } - nsAutoArrayPtr<char> buf; - PRUint32 len; - rv = NewBufferFromStorageStream(storageStream, getter_Transfers(buf), &len); - NS_ENSURE_SUCCESS(rv, rv); - - rv = cache->PutBuffer(PromiseFlatCString(uri).get(), buf, len); + ::JS_XDRDestroy(xdr); return rv; }
--- a/js/xpconnect/loader/mozJSLoaderUtils.h +++ b/js/xpconnect/loader/mozJSLoaderUtils.h @@ -47,14 +47,17 @@ class nsIURI; namespace mozilla { namespace scache { class StartupCache; } } nsresult ReadCachedScript(mozilla::scache::StartupCache* cache, nsACString &uri, - JSContext *cx, JSScript **script); + JSContext *cx, nsIPrincipal *systemPrincipal, + JSScript **script); nsresult WriteCachedScript(mozilla::scache::StartupCache* cache, nsACString &uri, - JSContext *cx, JSScript *script); + JSContext *cx, nsIPrincipal *systemPrincipal, + JSScript *script); + #endif /* mozJSLoaderUtils_h */
--- a/js/xpconnect/loader/mozJSSubScriptLoader.cpp +++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp @@ -324,17 +324,17 @@ mozJSSubScriptLoader::LoadSubScript(cons bool writeScript = false; JSVersion version = JS_GetVersion(cx); nsCAutoString cachePath; cachePath.AppendPrintf("jssubloader/%d", version); PathifyURI(uri, cachePath); script = nsnull; if (cache) - rv = ReadCachedScript(cache, cachePath, cx, &script); + rv = ReadCachedScript(cache, cachePath, cx, mSystemPrincipal, &script); if (!script) { rv = ReadScript(uri, cx, targetObj, charset, static_cast<const char*>(uriStr.get()), serv, principal, &script); writeScript = true; } if (NS_FAILED(rv) || !script) @@ -344,13 +344,13 @@ mozJSSubScriptLoader::LoadSubScript(cons if (ok) { JSAutoEnterCompartment rac; if (!rac.enter(cx, result_obj) || !JS_WrapValue(cx, retval)) return NS_ERROR_UNEXPECTED; } if (cache && ok && writeScript) { - WriteCachedScript(cache, cachePath, cx, script); + WriteCachedScript(cache, cachePath, cx, mSystemPrincipal, script); } return NS_OK; }
--- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -48,16 +48,17 @@ #include "xpcprivate.h" #include "XPCWrapper.h" #include "nsBaseHashtable.h" #include "nsHashKeys.h" #include "jsatom.h" #include "jsfriendapi.h" #include "jsgc.h" +#include "jsxdrapi.h" #include "dom_quickstubs.h" #include "nsNullPrincipal.h" #include "nsIURI.h" #include "nsJSEnvironment.h" #include "nsThreadUtils.h" #include "XrayWrapper.h" #include "WrapperFactory.h" @@ -503,17 +504,17 @@ struct NoteWeakMapsTracer : public js::W { JS_TracerInit(&mChildTracer, rt, TraceWeakMappingChild); } nsCycleCollectionTraversalCallback &mCb; NoteWeakMapChildrenTracer mChildTracer; }; static void -TraceWeakMapping(js::WeakMapTracer *trc, JSObject *m, +TraceWeakMapping(js::WeakMapTracer *trc, JSObject *m, void *k, JSGCTraceKind kkind, void *v, JSGCTraceKind vkind) { MOZ_ASSERT(trc->callback == TraceWeakMapping); NoteWeakMapsTracer *tracer = static_cast<NoteWeakMapsTracer *>(trc); if (vkind == JSTRACE_STRING) return; if (!xpc_IsGrayGCThing(v) && !tracer->mCb.WantAllTraces()) @@ -590,17 +591,17 @@ nsXPConnect::BeginCycleCollection(nsCycl JS_TracerInit(&trc, mCycleCollectionContext->GetJSContext(), NoteJSRoot); JS_TraceRuntime(&trc); } #else NS_ASSERTION(!explainLiveExpectedGarbage, "Didn't call nsXPConnect::Collect()?"); #endif GetRuntime()->AddXPConnectRoots(cb); - + NoteWeakMapsTracer trc(GetRuntime()->GetJSRuntime(), TraceWeakMapping, cb); js::TraceWeakMaps(&trc); return NS_OK; } bool nsXPConnect::NotifyLeaveMainThread() @@ -2789,16 +2790,183 @@ nsXPConnect::NotifyDidPaint() return UnexpectedFailure(NS_ERROR_FAILURE); JSContext *cx = ccx.GetJSContext(); js::NotifyDidPaint(cx); return NS_OK; } +const PRUint8 HAS_PRINCIPALS_FLAG = 1; +const PRUint8 HAS_ORIGIN_PRINCIPALS_FLAG = 2; + +static nsresult +WriteScriptOrFunction(nsIObjectOutputStream *stream, JSContext *cx, + JSScript *script, JSObject *functionObj) +{ + // Exactly one of script or functionObj must be given + MOZ_ASSERT(!script != !functionObj); + + if (!script) + script = JS_GetFunctionScript(cx, JS_GetObjectFunction(functionObj)); + + nsIPrincipal *principal = + nsJSPrincipals::get(JS_GetScriptPrincipals(script)); + nsIPrincipal *originPrincipal = + nsJSPrincipals::get(JS_GetScriptOriginPrincipals(script)); + + PRUint8 flags = 0; + if (principal) + flags |= HAS_PRINCIPALS_FLAG; + + // Optimize for the common case when originPrincipals == principals. As + // originPrincipals is set to principals when the former is null we can + // simply skip the originPrincipals when they are the same as principals. + if (originPrincipal && originPrincipal != principal) + flags |= HAS_ORIGIN_PRINCIPALS_FLAG; + + nsresult rv = stream->Write8(flags); + if (NS_FAILED(rv)) + return rv; + + if (flags & HAS_PRINCIPALS_FLAG) { + rv = stream->WriteObject(principal, true); + if (NS_FAILED(rv)) + return rv; + } + + if (flags & HAS_ORIGIN_PRINCIPALS_FLAG) { + rv = stream->WriteObject(originPrincipal, true); + if (NS_FAILED(rv)) + return rv; + } + + JSXDRState *xdr = JS_XDRNewMem(cx, JSXDR_ENCODE); + if (!xdr) + return NS_ERROR_OUT_OF_MEMORY; + + JSBool ok; + { + JSAutoRequest ar(cx); + if (functionObj) + ok = JS_XDRFunctionObject(xdr, &functionObj); + else + ok = JS_XDRScript(xdr, &script); + } + + if (!ok) { + rv = NS_ERROR_OUT_OF_MEMORY; + } else { + // Get the encoded JSXDRState data and write it. The JSXDRState owns + // this buffer memory and will free it beneath JS_XDRDestroy. + uint32_t size; + const char* data = reinterpret_cast<const char*>(::JS_XDRMemGetData(xdr, &size)); + NS_ASSERTION(data, "no decoded JSXDRState data!"); + + rv = stream->Write32(size); + if (NS_SUCCEEDED(rv)) + rv = stream->WriteBytes(data, size); + } + + JS_XDRDestroy(xdr); + + return rv; +} + +static nsresult +ReadScriptOrFunction(nsIObjectInputStream *stream, JSContext *cx, + JSScript **scriptp, JSObject **functionObjp) +{ + // Exactly one of script or functionObj must be given + MOZ_ASSERT(!scriptp != !functionObjp); + + PRUint8 flags; + nsresult rv = stream->Read8(&flags); + if (NS_FAILED(rv)) + return rv; + + nsJSPrincipals* principal = nsnull; + nsCOMPtr<nsIPrincipal> readPrincipal; + if (flags & HAS_PRINCIPALS_FLAG) { + rv = stream->ReadObject(true, getter_AddRefs(readPrincipal)); + if (NS_FAILED(rv)) + return rv; + principal = nsJSPrincipals::get(readPrincipal); + } + + nsJSPrincipals* originPrincipal = nsnull; + nsCOMPtr<nsIPrincipal> readOriginPrincipal; + if (flags & HAS_ORIGIN_PRINCIPALS_FLAG) { + rv = stream->ReadObject(true, getter_AddRefs(readOriginPrincipal)); + if (NS_FAILED(rv)) + return rv; + originPrincipal = nsJSPrincipals::get(readOriginPrincipal); + } + + PRUint32 size; + rv = stream->Read32(&size); + if (NS_FAILED(rv)) + return rv; + + char* data; + rv = stream->ReadBytes(size, &data); + if (NS_FAILED(rv)) + return rv; + + JSXDRState *xdr = JS_XDRNewMem(cx, JSXDR_DECODE); + if (!xdr) { + nsMemory::Free(data); + return NS_ERROR_OUT_OF_MEMORY; + } + + JS_XDRMemSetData(xdr, data, size); + JS_XDRSetPrincipals(xdr, principal, originPrincipal); + + JSBool ok; + { + JSAutoRequest ar(cx); + if (scriptp) + ok = JS_XDRScript(xdr, scriptp); + else + ok = JS_XDRFunctionObject(xdr, functionObjp); + } + + // We cannot rely on XDR automatically freeing the data memory as we must + // use nsMemory::Free to release it. + JS_XDRMemSetData(xdr, NULL, 0); + JS_XDRDestroy(xdr); + nsMemory::Free(data); + + return ok ? NS_OK : NS_ERROR_FAILURE; +} + +NS_IMETHODIMP +nsXPConnect::WriteScript(nsIObjectOutputStream *stream, JSContext *cx, JSScript *script) +{ + return WriteScriptOrFunction(stream, cx, script, nsnull); +} + +NS_IMETHODIMP +nsXPConnect::ReadScript(nsIObjectInputStream *stream, JSContext *cx, JSScript **scriptp) +{ + return ReadScriptOrFunction(stream, cx, scriptp, nsnull); +} + +NS_IMETHODIMP +nsXPConnect::WriteFunction(nsIObjectOutputStream *stream, JSContext *cx, JSObject *functionObj) +{ + return WriteScriptOrFunction(stream, cx, nsnull, functionObj); +} + +NS_IMETHODIMP +nsXPConnect::ReadFunction(nsIObjectInputStream *stream, JSContext *cx, JSObject **functionObjp) +{ + return ReadScriptOrFunction(stream, cx, nsnull, functionObjp); +} + /* These are here to be callable from a debugger */ JS_BEGIN_EXTERN_C JS_EXPORT_API(void) DumpJSStack() { nsresult rv; nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv)); if (NS_SUCCEEDED(rv) && xpc) xpc->DebugDumpJSStack(true, true, false);