--- 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);