mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Backed out 3 changesets (bug 1718194, bug 1718623, bug 1718481) for causing leaks. CLOSED TREE
Backed out changeset 1cd8bdf1fc92 (bug 1718481) Backed out changeset aa56fe2c069d (bug 1718194) Backed out changeset f7cb7313d1c7 (bug 1718623)
This commit is contained in:
parent
3a98545701
commit
8957144a0f
@ -16215,6 +16215,12 @@ bool Document::IsExtensionPage() const {
|
||||
BasePrincipal::Cast(NodePrincipal())->AddonPolicy();
|
||||
}
|
||||
|
||||
void Document::TraceProtos(JSTracer* aTrc) {
|
||||
if (mPrototypeDocument) {
|
||||
mPrototypeDocument->TraceProtos(aTrc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the classification of the Flash plugins in the document based on
|
||||
* the classification lists. For more information, see
|
||||
|
@ -5279,6 +5279,8 @@ class Document : public nsINode,
|
||||
nsRefPtrHashtable<nsRefPtrHashKey<Element>, nsXULPrototypeElement>
|
||||
mL10nProtoElements;
|
||||
|
||||
void TraceProtos(JSTracer* aTrc);
|
||||
|
||||
float GetSavedResolutionBeforeMVM() { return mSavedResolutionBeforeMVM; }
|
||||
void SetSavedResolutionBeforeMVM(float aResolution) {
|
||||
mSavedResolutionBeforeMVM = aResolution;
|
||||
|
@ -429,7 +429,20 @@ nsresult nsCCUncollectableMarker::Observe(nsISupports* aSubject,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void mozilla::dom::TraceBlackJS(JSTracer* aTrc) {
|
||||
void mozilla::dom::TraceBlackJS(JSTracer* aTrc, bool aIsShutdownGC) {
|
||||
#ifdef MOZ_XUL
|
||||
// Mark the scripts held in the XULPrototypeCache. This is required to keep
|
||||
// the JS script in the cache live across GC.
|
||||
nsXULPrototypeCache* cache = nsXULPrototypeCache::MaybeGetInstance();
|
||||
if (cache) {
|
||||
if (aIsShutdownGC) {
|
||||
cache->FlushScripts();
|
||||
} else {
|
||||
cache->MarkInGC(aTrc);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!nsCCUncollectableMarker::sGeneration) {
|
||||
return;
|
||||
}
|
||||
@ -491,6 +504,13 @@ void mozilla::dom::TraceBlackJS(JSTracer* aTrc) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
Document* doc = window->GetExtantDoc();
|
||||
if (doc) {
|
||||
doc->TraceProtos(aTrc);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ class nsCCUncollectableMarker final : public nsIObserver {
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
void TraceBlackJS(JSTracer* aTrc);
|
||||
void TraceBlackJS(JSTracer* aTrc, bool aIsShutdownGC);
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -15,20 +15,15 @@
|
||||
#include "ContentChild.h"
|
||||
#include "ErrorList.h"
|
||||
#include "mozilla/ProfilerLabels.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "base/process_util.h"
|
||||
#include "chrome/common/ipc_channel.h"
|
||||
#include "js/CallAndConstruct.h" // JS::IsCallable, JS_CallFunctionValue
|
||||
#include "js/CompilationAndEvaluation.h"
|
||||
#include "js/CompileOptions.h"
|
||||
#include "js/experimental/JSStencil.h"
|
||||
#include "js/GCVector.h"
|
||||
#include "js/JSON.h"
|
||||
#include "js/PropertyAndElement.h" // JS_GetProperty
|
||||
#include "js/RootingAPI.h"
|
||||
#include "js/SourceText.h"
|
||||
#include "js/StructuredClone.h"
|
||||
#include "js/TypeDecls.h"
|
||||
#include "js/Wrapper.h"
|
||||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
@ -1173,11 +1168,6 @@ void nsMessageManagerScriptExecutor::Shutdown() {
|
||||
}
|
||||
}
|
||||
|
||||
static void FillCompileOptionsForCachedStencil(JS::CompileOptions& aOptions) {
|
||||
ScriptPreloader::FillCompileOptionsForCachedStencil(aOptions);
|
||||
aOptions.setNonSyntacticScope(true);
|
||||
}
|
||||
|
||||
void nsMessageManagerScriptExecutor::LoadScriptInternal(
|
||||
JS::Handle<JSObject*> aMessageManager, const nsAString& aURL,
|
||||
bool aRunInUniqueScope) {
|
||||
@ -1188,59 +1178,48 @@ void nsMessageManagerScriptExecutor::LoadScriptInternal(
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<JS::Stencil> stencil;
|
||||
JS::RootingContext* rcx = RootingCx();
|
||||
JS::Rooted<JSScript*> script(rcx);
|
||||
|
||||
nsMessageManagerScriptHolder* holder = sCachedScripts->Get(aURL);
|
||||
if (holder) {
|
||||
stencil = holder->mStencil;
|
||||
script = holder->mScript;
|
||||
} else {
|
||||
stencil =
|
||||
TryCacheLoadAndCompileScript(aURL, aRunInUniqueScope, aMessageManager);
|
||||
TryCacheLoadAndCompileScript(aURL, aRunInUniqueScope, aMessageManager,
|
||||
&script);
|
||||
}
|
||||
|
||||
AutoEntryScript aes(aMessageManager, "message manager script load");
|
||||
JSContext* cx = aes.cx();
|
||||
if (stencil) {
|
||||
JS::CompileOptions options(cx);
|
||||
FillCompileOptionsForCachedStencil(options);
|
||||
|
||||
if (JS::StencilCanLazilyParse(stencil)) {
|
||||
// See TryCacheLoadAndCompileScript.
|
||||
options.setSourceIsLazy(false);
|
||||
}
|
||||
|
||||
JS::Rooted<JSScript*> script(
|
||||
cx, JS::InstantiateGlobalStencil(cx, options, stencil));
|
||||
|
||||
if (script) {
|
||||
if (aRunInUniqueScope) {
|
||||
JS::Rooted<JSObject*> scope(cx);
|
||||
bool ok = js::ExecuteInFrameScriptEnvironment(cx, aMessageManager,
|
||||
script, &scope);
|
||||
if (ok) {
|
||||
// Force the scope to stay alive.
|
||||
mAnonymousGlobalScopes.AppendElement(scope);
|
||||
}
|
||||
} else {
|
||||
JS::RootedValue rval(cx);
|
||||
JS::RootedVector<JSObject*> envChain(cx);
|
||||
if (!envChain.append(aMessageManager)) {
|
||||
return;
|
||||
}
|
||||
Unused << JS_ExecuteScript(cx, envChain, script, &rval);
|
||||
if (script) {
|
||||
if (aRunInUniqueScope) {
|
||||
JS::Rooted<JSObject*> scope(cx);
|
||||
bool ok = js::ExecuteInFrameScriptEnvironment(cx, aMessageManager, script,
|
||||
&scope);
|
||||
if (ok) {
|
||||
// Force the scope to stay alive.
|
||||
mAnonymousGlobalScopes.AppendElement(scope);
|
||||
}
|
||||
} else {
|
||||
JS::RootedValue rval(cx);
|
||||
JS::RootedVector<JSObject*> envChain(cx);
|
||||
if (!envChain.append(aMessageManager)) {
|
||||
return;
|
||||
}
|
||||
JS::CloneAndExecuteScript(cx, envChain, script, &rval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<JS::Stencil>
|
||||
nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript(
|
||||
void nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript(
|
||||
const nsAString& aURL, bool aRunInUniqueScope,
|
||||
JS::Handle<JSObject*> aMessageManager) {
|
||||
JS::Handle<JSObject*> aMessageManager,
|
||||
JS::MutableHandle<JSScript*> aScriptp) {
|
||||
nsCString url = NS_ConvertUTF16toUTF8(aURL);
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(uri), url);
|
||||
if (NS_FAILED(rv)) {
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
bool hasFlags;
|
||||
@ -1248,7 +1227,7 @@ nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript(
|
||||
&hasFlags);
|
||||
if (NS_FAILED(rv) || !hasFlags) {
|
||||
NS_WARNING("Will not load a frame script!");
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
// If this script won't be cached, or there is only one of this type of
|
||||
@ -1271,13 +1250,14 @@ nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript(
|
||||
// compartment alive.
|
||||
AutoJSAPI jsapi;
|
||||
if (!jsapi.Init(isRunOnce ? aMessageManager : xpc::CompilationScope())) {
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
JS::CompileOptions options(cx);
|
||||
FillCompileOptionsForCachedStencil(options);
|
||||
ScriptPreloader::FillCompileOptionsForCachedStencil(options);
|
||||
options.setFileAndLine(url.get(), 1);
|
||||
options.setNonSyntacticScope(true);
|
||||
|
||||
RefPtr<JS::Stencil> stencil;
|
||||
if (useScriptPreloader) {
|
||||
@ -1293,12 +1273,12 @@ nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript(
|
||||
nsIContentPolicy::TYPE_INTERNAL_FRAME_MESSAGEMANAGER_SCRIPT);
|
||||
|
||||
if (!channel) {
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> input;
|
||||
rv = channel->Open(getter_AddRefs(input));
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
nsString dataString;
|
||||
char16_t* dataStringBuf = nullptr;
|
||||
size_t dataStringLength = 0;
|
||||
@ -1306,7 +1286,7 @@ nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript(
|
||||
nsCString buffer;
|
||||
uint64_t written;
|
||||
if (NS_FAILED(NS_ReadInputStreamToString(input, buffer, -1, &written))) {
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t size = (uint32_t)std::min(written, (uint64_t)UINT32_MAX);
|
||||
@ -1316,7 +1296,7 @@ nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript(
|
||||
}
|
||||
|
||||
if (!dataStringBuf || dataStringLength == 0) {
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
// If we are not encoding to the ScriptPreloader cache, we can now relax the
|
||||
@ -1329,17 +1309,25 @@ nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript(
|
||||
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
if (!srcBuf.init(cx, std::move(srcChars), dataStringLength)) {
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
stencil = JS::CompileGlobalScriptToStencil(cx, options, srcBuf);
|
||||
if (!stencil) {
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(stencil);
|
||||
|
||||
JS::Rooted<JSScript*> script(
|
||||
cx, JS::InstantiateGlobalStencil(cx, options, stencil));
|
||||
if (!script) {
|
||||
return;
|
||||
}
|
||||
|
||||
aScriptp.set(script);
|
||||
|
||||
if (useScriptPreloader) {
|
||||
ScriptPreloader::GetChildSingleton().NoteStencil(url, url, stencil,
|
||||
isRunOnce);
|
||||
@ -1348,12 +1336,10 @@ nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript(
|
||||
// preloader cache, not the session cache.
|
||||
if (!isRunOnce) {
|
||||
// Root the object also for caching.
|
||||
auto* holder = new nsMessageManagerScriptHolder(stencil);
|
||||
auto* holder = new nsMessageManagerScriptHolder(cx, script);
|
||||
sCachedScripts->InsertOrUpdate(aURL, holder);
|
||||
}
|
||||
}
|
||||
|
||||
return stencil.forget();
|
||||
}
|
||||
|
||||
void nsMessageManagerScriptExecutor::Trace(const TraceCallbacks& aCallbacks,
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include <string.h>
|
||||
#include <utility>
|
||||
#include "ErrorList.h"
|
||||
#include "js/experimental/JSStencil.h"
|
||||
#include "js/RootingAPI.h"
|
||||
#include "js/TypeDecls.h"
|
||||
#include "js/Value.h"
|
||||
#include "mozilla/AlreadyAddRefed.h"
|
||||
@ -308,14 +308,14 @@ class nsSameProcessAsyncMessageBase {
|
||||
class nsScriptCacheCleaner;
|
||||
|
||||
struct nsMessageManagerScriptHolder {
|
||||
explicit nsMessageManagerScriptHolder(JS::Stencil* aStencil)
|
||||
: mStencil(aStencil) {
|
||||
nsMessageManagerScriptHolder(JSContext* aCx, JSScript* aScript)
|
||||
: mScript(aCx, aScript) {
|
||||
MOZ_COUNT_CTOR(nsMessageManagerScriptHolder);
|
||||
}
|
||||
|
||||
MOZ_COUNTED_DTOR(nsMessageManagerScriptHolder)
|
||||
|
||||
RefPtr<JS::Stencil> mStencil;
|
||||
JS::PersistentRooted<JSScript*> mScript;
|
||||
};
|
||||
|
||||
class nsMessageManagerScriptExecutor {
|
||||
@ -335,9 +335,10 @@ class nsMessageManagerScriptExecutor {
|
||||
void DidCreateScriptLoader();
|
||||
void LoadScriptInternal(JS::Handle<JSObject*> aMessageManager,
|
||||
const nsAString& aURL, bool aRunInUniqueScope);
|
||||
already_AddRefed<JS::Stencil> TryCacheLoadAndCompileScript(
|
||||
const nsAString& aURL, bool aRunInUniqueScope,
|
||||
JS::Handle<JSObject*> aMessageManager);
|
||||
void TryCacheLoadAndCompileScript(const nsAString& aURL,
|
||||
bool aRunInUniqueScope,
|
||||
JS::Handle<JSObject*> aMessageManager,
|
||||
JS::MutableHandle<JSScript*> aScriptp);
|
||||
bool Init();
|
||||
void Trace(const TraceCallbacks& aCallbacks, void* aClosure);
|
||||
void Unlink();
|
||||
|
@ -12,8 +12,6 @@
|
||||
#include "nsISupports.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "jspubtd.h"
|
||||
#include "js/experimental/JSStencil.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
class nsIScriptGlobalObject;
|
||||
|
||||
@ -79,12 +77,11 @@ class nsIOffThreadScriptReceiver : public nsISupports {
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IOFFTHREADSCRIPTRECEIVER_IID)
|
||||
|
||||
/**
|
||||
* Notify this object that a previous Compile call specifying this as
|
||||
* Notify this object that a previous CompileScript call specifying this as
|
||||
* aOffThreadReceiver has completed. The script being passed in must be
|
||||
* rooted before any call which could trigger GC.
|
||||
*/
|
||||
NS_IMETHOD OnScriptCompileComplete(JS::Stencil* aStencil,
|
||||
nsresult aStatus) = 0;
|
||||
NS_IMETHOD OnScriptCompileComplete(JSScript* aScript, nsresult aStatus) = 0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIOffThreadScriptReceiver,
|
||||
|
@ -50,13 +50,11 @@
|
||||
#include "mozilla/LoadInfo.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/ProfilerLabels.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
#include "nsXULPrototypeCache.h"
|
||||
#include "nsXULElement.h"
|
||||
#include "mozilla/CycleCollectedJSContext.h"
|
||||
#include "js/CompilationAndEvaluation.h"
|
||||
#include "js/experimental/JSStencil.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
@ -568,7 +566,7 @@ nsresult PrototypeDocumentContentSink::ResumeWalkInternal() {
|
||||
// If the script cannot be loaded, just keep going!
|
||||
|
||||
if (NS_SUCCEEDED(rv) && blocked) return NS_OK;
|
||||
} else if (scriptproto->HasStencil()) {
|
||||
} else if (scriptproto->HasScriptObject()) {
|
||||
// An inline script
|
||||
rv = ExecuteScript(scriptproto);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
@ -727,7 +725,7 @@ nsresult PrototypeDocumentContentSink::LoadScript(
|
||||
|
||||
bool isChromeDoc = IsChromeURI(mDocumentURI);
|
||||
|
||||
if (isChromeDoc && aScriptProto->HasStencil()) {
|
||||
if (isChromeDoc && aScriptProto->HasScriptObject()) {
|
||||
rv = ExecuteScript(aScriptProto);
|
||||
|
||||
// Ignore return value from execution, and don't block
|
||||
@ -741,15 +739,15 @@ nsresult PrototypeDocumentContentSink::LoadScript(
|
||||
bool useXULCache = nsXULPrototypeCache::GetInstance()->IsEnabled();
|
||||
|
||||
if (isChromeDoc && useXULCache) {
|
||||
RefPtr<JS::Stencil> newStencil =
|
||||
nsXULPrototypeCache::GetInstance()->GetStencil(aScriptProto->mSrcURI);
|
||||
if (newStencil) {
|
||||
JSScript* newScriptObject =
|
||||
nsXULPrototypeCache::GetInstance()->GetScript(aScriptProto->mSrcURI);
|
||||
if (newScriptObject) {
|
||||
// The script language for a proto must remain constant - we
|
||||
// can't just change it for this unexpected language.
|
||||
aScriptProto->Set(newStencil);
|
||||
aScriptProto->Set(newScriptObject);
|
||||
}
|
||||
|
||||
if (aScriptProto->HasStencil()) {
|
||||
if (aScriptProto->HasScriptObject()) {
|
||||
rv = ExecuteScript(aScriptProto);
|
||||
|
||||
// Ignore return value from execution, and don't block
|
||||
@ -758,8 +756,8 @@ nsresult PrototypeDocumentContentSink::LoadScript(
|
||||
}
|
||||
}
|
||||
|
||||
// Release stencil from FastLoad since we decided against using them
|
||||
aScriptProto->Set(nullptr);
|
||||
// Release script objects from FastLoad since we decided against using them
|
||||
aScriptProto->UnlinkJSObjects();
|
||||
|
||||
// Set the current script prototype so that OnStreamComplete can report
|
||||
// the right file if there are errors in the script.
|
||||
@ -843,7 +841,7 @@ PrototypeDocumentContentSink::OnStreamComplete(nsIStreamLoader* aLoader,
|
||||
// be writing a new FastLoad file. If we were reading this script
|
||||
// from the FastLoad file, XULContentSinkImpl::OpenScript (over in
|
||||
// nsXULContentSink.cpp) would have already deserialized a non-null
|
||||
// script->mStencil, causing control flow at the top of LoadScript
|
||||
// script->mScriptObject, causing control flow at the top of LoadScript
|
||||
// not to reach here.
|
||||
nsCOMPtr<nsIURI> uri = mCurrentScriptProto->mSrcURI;
|
||||
|
||||
@ -869,7 +867,7 @@ PrototypeDocumentContentSink::OnStreamComplete(nsIStreamLoader* aLoader,
|
||||
rv = mCurrentScriptProto->Compile(units, unitsLength,
|
||||
JS::SourceOwnership::TakeOwnership, uri,
|
||||
1, mDocument, this);
|
||||
if (NS_SUCCEEDED(rv) && !mCurrentScriptProto->HasStencil()) {
|
||||
if (NS_SUCCEEDED(rv) && !mCurrentScriptProto->HasScriptObject()) {
|
||||
mOffThreadCompiling = true;
|
||||
mDocument->BlockOnload();
|
||||
return NS_OK;
|
||||
@ -877,11 +875,11 @@ PrototypeDocumentContentSink::OnStreamComplete(nsIStreamLoader* aLoader,
|
||||
}
|
||||
}
|
||||
|
||||
return OnScriptCompileComplete(mCurrentScriptProto->GetStencil(), rv);
|
||||
return OnScriptCompileComplete(mCurrentScriptProto->GetScriptObject(), rv);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PrototypeDocumentContentSink::OnScriptCompileComplete(JS::Stencil* aStencil,
|
||||
PrototypeDocumentContentSink::OnScriptCompileComplete(JSScript* aScript,
|
||||
nsresult aStatus) {
|
||||
// The mCurrentScriptProto may have been cleared out by another
|
||||
// PrototypeDocumentContentSink.
|
||||
@ -891,9 +889,8 @@ PrototypeDocumentContentSink::OnScriptCompileComplete(JS::Stencil* aStencil,
|
||||
|
||||
// When compiling off thread the script will not have been attached to the
|
||||
// script proto yet.
|
||||
if (aStencil && !mCurrentScriptProto->HasStencil()) {
|
||||
mCurrentScriptProto->Set(aStencil);
|
||||
}
|
||||
if (aScript && !mCurrentScriptProto->HasScriptObject())
|
||||
mCurrentScriptProto->Set(aScript);
|
||||
|
||||
// Allow load events to be fired once off thread compilation finishes.
|
||||
if (mOffThreadCompiling) {
|
||||
@ -946,9 +943,11 @@ PrototypeDocumentContentSink::OnScriptCompileComplete(JS::Stencil* aStencil,
|
||||
// the true crime story.)
|
||||
bool useXULCache = nsXULPrototypeCache::GetInstance()->IsEnabled();
|
||||
|
||||
if (useXULCache && IsChromeURI(mDocumentURI) && scriptProto->HasStencil()) {
|
||||
nsXULPrototypeCache::GetInstance()->PutStencil(scriptProto->mSrcURI,
|
||||
scriptProto->GetStencil());
|
||||
if (useXULCache && IsChromeURI(mDocumentURI) &&
|
||||
scriptProto->HasScriptObject()) {
|
||||
JS::Rooted<JSScript*> script(RootingCx(), scriptProto->GetScriptObject());
|
||||
nsXULPrototypeCache::GetInstance()->PutScript(scriptProto->mSrcURI,
|
||||
script);
|
||||
}
|
||||
// ignore any evaluation errors
|
||||
}
|
||||
@ -971,7 +970,7 @@ PrototypeDocumentContentSink::OnScriptCompileComplete(JS::Stencil* aStencil,
|
||||
*docp = doc->mNextSrcLoadWaiter;
|
||||
doc->mNextSrcLoadWaiter = nullptr;
|
||||
|
||||
if (aStatus == NS_BINDING_ABORTED && !scriptProto->HasStencil()) {
|
||||
if (aStatus == NS_BINDING_ABORTED && !scriptProto->HasScriptObject()) {
|
||||
// If the previous doc load was aborted, we want to try loading
|
||||
// again for the next doc. Otherwise, one abort would lead to all
|
||||
// subsequent waiting docs to abort as well.
|
||||
@ -982,7 +981,7 @@ PrototypeDocumentContentSink::OnScriptCompileComplete(JS::Stencil* aStencil,
|
||||
}
|
||||
|
||||
// Execute only if we loaded and compiled successfully, then resume
|
||||
if (NS_SUCCEEDED(aStatus) && scriptProto->HasStencil()) {
|
||||
if (NS_SUCCEEDED(aStatus) && scriptProto->HasScriptObject()) {
|
||||
doc->ExecuteScript(scriptProto);
|
||||
}
|
||||
doc->ResumeWalk();
|
||||
@ -1011,22 +1010,22 @@ nsresult PrototypeDocumentContentSink::ExecuteScript(
|
||||
// Execute the precompiled script with the given version
|
||||
nsAutoMicroTask mt;
|
||||
|
||||
// We're about to run script via JS_ExecuteScript, so we need an
|
||||
// We're about to run script via JS::CloneAndExecuteScript, so we need an
|
||||
// AutoEntryScript. This is Gecko specific and not in any spec.
|
||||
AutoEntryScript aes(scriptGlobalObject, "precompiled XUL <script> element");
|
||||
JSContext* cx = aes.cx();
|
||||
|
||||
JS::Rooted<JSScript*> scriptObject(cx);
|
||||
rv = aScript->InstantiateScript(cx, &scriptObject);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
JS::Rooted<JSScript*> scriptObject(cx, aScript->GetScriptObject());
|
||||
NS_ENSURE_TRUE(scriptObject, NS_ERROR_UNEXPECTED);
|
||||
|
||||
JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
|
||||
NS_ENSURE_TRUE(xpc::Scriptability::Get(global).Allowed(), NS_OK);
|
||||
|
||||
// On failure, ~AutoScriptEntry will handle exceptions, so
|
||||
// The script is in the compilation scope. Clone it into the target scope
|
||||
// and execute it. On failure, ~AutoScriptEntry will handle exceptions, so
|
||||
// there is no need to manually check the return value.
|
||||
JS::RootedValue rval(cx);
|
||||
Unused << JS_ExecuteScript(cx, scriptObject, &rval);
|
||||
JS::CloneAndExecuteScript(cx, scriptObject, &rval);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -21,8 +21,6 @@
|
||||
#include "nsIScriptContext.h"
|
||||
#include "nsICSSLoaderObserver.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "js/experimental/JSStencil.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
class nsIURI;
|
||||
class nsIChannel;
|
||||
@ -88,7 +86,7 @@ class PrototypeDocumentContentSink final : public nsIStreamLoaderObserver,
|
||||
nsresult aStatus) override;
|
||||
|
||||
// nsIOffThreadScriptReceiver
|
||||
NS_IMETHOD OnScriptCompileComplete(JS::Stencil* aStencil,
|
||||
NS_IMETHOD OnScriptCompileComplete(JSScript* aScript,
|
||||
nsresult aStatus) override;
|
||||
|
||||
nsresult OnPrototypeLoadDone(nsXULPrototypeDocument* aPrototype);
|
||||
|
@ -427,7 +427,7 @@ XULContentSinkImpl::HandleEndElement(const char16_t* aName) {
|
||||
static_cast<nsXULPrototypeScript*>(node.get());
|
||||
|
||||
// If given a src= attribute, we must ignore script tag content.
|
||||
if (!script->mSrcURI && !script->HasStencil()) {
|
||||
if (!script->mSrcURI && !script->HasScriptObject()) {
|
||||
nsCOMPtr<Document> doc = do_QueryReferent(mDocument);
|
||||
|
||||
script->mOutOfLine = false;
|
||||
|
@ -19,13 +19,10 @@
|
||||
#include "XULTreeElement.h"
|
||||
#include "js/CompilationAndEvaluation.h"
|
||||
#include "js/CompileOptions.h"
|
||||
#include "js/experimental/JSStencil.h"
|
||||
#include "js/OffThreadScriptCompilation.h"
|
||||
#include "js/SourceText.h"
|
||||
#include "js/Transcoding.h"
|
||||
#include "js/Utility.h"
|
||||
#include "jsapi.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/ArrayIterator.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/DeclarationBlock.h"
|
||||
@ -40,7 +37,6 @@
|
||||
#include "mozilla/MouseEvents.h"
|
||||
#include "mozilla/OwningNonNull.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/StaticAnalysisFunctions.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/URLExtraData.h"
|
||||
@ -1211,6 +1207,8 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULPrototypeNode)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXULPrototypeNode)
|
||||
if (tmp->mType == nsXULPrototypeNode::eType_Element) {
|
||||
static_cast<nsXULPrototypeElement*>(tmp)->Unlink();
|
||||
} else if (tmp->mType == nsXULPrototypeNode::eType_Script) {
|
||||
static_cast<nsXULPrototypeScript*>(tmp)->UnlinkJSObjects();
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXULPrototypeNode)
|
||||
@ -1233,6 +1231,10 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXULPrototypeNode)
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsXULPrototypeNode)
|
||||
if (tmp->mType == nsXULPrototypeNode::eType_Script) {
|
||||
nsXULPrototypeScript* script = static_cast<nsXULPrototypeScript*>(tmp);
|
||||
script->Trace(aCallbacks, aClosure);
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsXULPrototypeNode, AddRef)
|
||||
@ -1341,7 +1343,7 @@ nsresult nsXULPrototypeElement::Serialize(
|
||||
rv = tmp;
|
||||
}
|
||||
|
||||
if (script->HasStencil()) {
|
||||
if (script->HasScriptObject()) {
|
||||
// This may return NS_OK without muxing script->mSrcURI's
|
||||
// data into the cache file, in the case where that
|
||||
// muxed document is already there (written by a prior
|
||||
@ -1563,6 +1565,17 @@ void nsXULPrototypeElement::Unlink() {
|
||||
mChildren.Clear();
|
||||
}
|
||||
|
||||
void nsXULPrototypeElement::TraceAllScripts(JSTracer* aTrc) {
|
||||
for (uint32_t i = 0; i < mChildren.Length(); ++i) {
|
||||
nsXULPrototypeNode* child = mChildren[i];
|
||||
if (child->mType == nsXULPrototypeNode::eType_Element) {
|
||||
static_cast<nsXULPrototypeElement*>(child)->TraceAllScripts(aTrc);
|
||||
} else if (child->mType == nsXULPrototypeNode::eType_Script) {
|
||||
static_cast<nsXULPrototypeScript*>(child)->TraceScriptObject(aTrc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
// nsXULPrototypeScript
|
||||
@ -1574,103 +1587,9 @@ nsXULPrototypeScript::nsXULPrototypeScript(uint32_t aLineNo)
|
||||
mSrcLoading(false),
|
||||
mOutOfLine(true),
|
||||
mSrcLoadWaiters(nullptr),
|
||||
mStencil(nullptr) {}
|
||||
mScriptObject(nullptr) {}
|
||||
|
||||
static nsresult WriteStencil(nsIObjectOutputStream* aStream, JSContext* aCx,
|
||||
const JS::ReadOnlyCompileOptions& aOptions,
|
||||
JS::Stencil* aStencil) {
|
||||
uint8_t flags = 0; // We don't have flags anymore.
|
||||
nsresult rv = aStream->Write8(flags);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
JS::TranscodeBuffer buffer;
|
||||
JS::TranscodeResult code;
|
||||
code = JS::EncodeStencil(aCx, aOptions, aStencil, buffer);
|
||||
|
||||
if (code != JS::TranscodeResult::Ok) {
|
||||
if (code == JS::TranscodeResult::Throw) {
|
||||
JS_ClearPendingException(aCx);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(IsTranscodeFailureResult(code));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
size_t size = buffer.length();
|
||||
if (size > UINT32_MAX) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
rv = aStream->Write32(size);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// Ideally we could just pass "buffer" here. See bug 1566574.
|
||||
rv = aStream->WriteBytes(Span(buffer.begin(), size));
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static nsresult ReadStencil(nsIObjectInputStream* aStream, JSContext* aCx,
|
||||
const JS::ReadOnlyCompileOptions& aOptions,
|
||||
JS::Stencil** aStencilOut) {
|
||||
uint8_t flags;
|
||||
nsresult rv = aStream->Read8(&flags);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// We don't serialize mutedError-ness of scripts, which is fine as long as
|
||||
// we only serialize system and XUL-y things. We can detect this by checking
|
||||
// where the caller wants us to deserialize.
|
||||
//
|
||||
// CompilationScope() could theoretically GC, so get that out of the way
|
||||
// before comparing to the cx global.
|
||||
JSObject* loaderGlobal = xpc::CompilationScope();
|
||||
MOZ_RELEASE_ASSERT(nsContentUtils::IsSystemCaller(aCx) ||
|
||||
JS::CurrentGlobalOrNull(aCx) == loaderGlobal);
|
||||
|
||||
uint32_t size;
|
||||
rv = aStream->Read32(&size);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
char* data;
|
||||
rv = aStream->ReadBytes(size, &data);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
JS::TranscodeRange range(reinterpret_cast<uint8_t*>(data), size);
|
||||
|
||||
{
|
||||
JS::TranscodeResult code;
|
||||
RefPtr<JS::Stencil> stencil;
|
||||
code = JS::DecodeStencil(aCx, aOptions, range, getter_AddRefs(stencil));
|
||||
if (code == JS::TranscodeResult::Ok) {
|
||||
stencil.forget(aStencilOut);
|
||||
} else {
|
||||
if (code == JS::TranscodeResult::Throw) {
|
||||
JS_ClearPendingException(aCx);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(IsTranscodeFailureResult(code));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void nsXULPrototypeScript::FillCompileOptions(JS::CompileOptions& options) {
|
||||
// If the script was inline, tell the JS parser to save source for
|
||||
// Function.prototype.toSource(). If it's out of line, we retrieve the
|
||||
// source from the files on demand.
|
||||
options.setSourceIsLazy(mOutOfLine);
|
||||
}
|
||||
nsXULPrototypeScript::~nsXULPrototypeScript() { UnlinkJSObjects(); }
|
||||
|
||||
nsresult nsXULPrototypeScript::Serialize(
|
||||
nsIObjectOutputStream* aStream, nsXULPrototypeDocument* aProtoDoc,
|
||||
@ -1682,9 +1601,9 @@ nsresult nsXULPrototypeScript::Serialize(
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!mSrcLoading || mSrcLoadWaiters != nullptr || !mStencil,
|
||||
NS_ASSERTION(!mSrcLoading || mSrcLoadWaiters != nullptr || !mScriptObject,
|
||||
"script source still loading when serializing?!");
|
||||
if (!mStencil) return NS_ERROR_FAILURE;
|
||||
if (!mScriptObject) return NS_ERROR_FAILURE;
|
||||
|
||||
// Write basic prototype data
|
||||
nsresult rv;
|
||||
@ -1694,12 +1613,9 @@ nsresult nsXULPrototypeScript::Serialize(
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::Rooted<JSScript*> script(cx, mScriptObject);
|
||||
MOZ_ASSERT(xpc::CompilationScope() == JS::CurrentGlobalOrNull(cx));
|
||||
|
||||
JS::CompileOptions options(cx);
|
||||
FillCompileOptions(options);
|
||||
|
||||
return WriteStencil(aStream, cx, options, mStencil);
|
||||
return nsContentUtils::XPConnect()->WriteScript(aStream, cx, script);
|
||||
}
|
||||
|
||||
nsresult nsXULPrototypeScript::SerializeOutOfLine(
|
||||
@ -1740,12 +1656,19 @@ nsresult nsXULPrototypeScript::SerializeOutOfLine(
|
||||
return rv;
|
||||
}
|
||||
|
||||
void nsXULPrototypeScript::FillCompileOptions(JS::CompileOptions& options) {
|
||||
// If the script was inline, tell the JS parser to save source for
|
||||
// Function.prototype.toSource(). If it's out of line, we retrieve the
|
||||
// source from the files on demand.
|
||||
options.setSourceIsLazy(mOutOfLine);
|
||||
}
|
||||
|
||||
nsresult nsXULPrototypeScript::Deserialize(
|
||||
nsIObjectInputStream* aStream, nsXULPrototypeDocument* aProtoDoc,
|
||||
nsIURI* aDocumentURI,
|
||||
const nsTArray<RefPtr<mozilla::dom::NodeInfo>>* aNodeInfos) {
|
||||
nsresult rv;
|
||||
NS_ASSERTION(!mSrcLoading || mSrcLoadWaiters != nullptr || !mStencil,
|
||||
NS_ASSERTION(!mSrcLoading || mSrcLoadWaiters != nullptr || !mScriptObject,
|
||||
"prototype script not well-initialized when deserializing?!");
|
||||
|
||||
// Read basic prototype data
|
||||
@ -1764,10 +1687,11 @@ nsresult nsXULPrototypeScript::Deserialize(
|
||||
JS::CompileOptions options(cx);
|
||||
FillCompileOptions(options);
|
||||
|
||||
RefPtr<JS::Stencil> newStencil;
|
||||
rv = ReadStencil(aStream, cx, options, getter_AddRefs(newStencil));
|
||||
JS::Rooted<JSScript*> newScriptObject(cx);
|
||||
rv = nsContentUtils::XPConnect()->ReadScript(aStream, cx, options,
|
||||
newScriptObject.address());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
Set(newStencil);
|
||||
Set(newScriptObject);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1794,14 +1718,12 @@ nsresult nsXULPrototypeScript::DeserializeOutOfLine(
|
||||
useXULCache = cache->IsEnabled();
|
||||
|
||||
if (useXULCache) {
|
||||
RefPtr<JS::Stencil> newStencil = cache->GetStencil(mSrcURI);
|
||||
if (newStencil) {
|
||||
Set(newStencil);
|
||||
}
|
||||
JSScript* newScriptObject = cache->GetScript(mSrcURI);
|
||||
if (newScriptObject) Set(newScriptObject);
|
||||
}
|
||||
}
|
||||
|
||||
if (!mStencil) {
|
||||
if (!mScriptObject) {
|
||||
if (mSrcURI) {
|
||||
rv = cache->GetInputStream(mSrcURI, getter_AddRefs(objectInput));
|
||||
}
|
||||
@ -1809,7 +1731,7 @@ nsresult nsXULPrototypeScript::DeserializeOutOfLine(
|
||||
// to do anything else in that case, I think.
|
||||
|
||||
// We do reflect errors into rv, but our caller may want to
|
||||
// ignore our return value, because mStencil will be null
|
||||
// ignore our return value, because mScriptObject will be null
|
||||
// after any error, and that suffices to cause the script to
|
||||
// be reloaded (from the src= URI, if any) and recompiled.
|
||||
// We're better off slow-loading than bailing out due to a
|
||||
@ -1819,7 +1741,8 @@ nsresult nsXULPrototypeScript::DeserializeOutOfLine(
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (useXULCache && mSrcURI && mSrcURI->SchemeIs("chrome")) {
|
||||
cache->PutStencil(mSrcURI, GetStencil());
|
||||
JS::Rooted<JSScript*> script(RootingCx(), GetScriptObject());
|
||||
cache->PutScript(mSrcURI, script);
|
||||
}
|
||||
cache->FinishInputStream(mSrcURI);
|
||||
} else {
|
||||
@ -1880,7 +1803,7 @@ NS_IMETHODIMP
|
||||
NotifyOffThreadScriptCompletedRunnable::Run() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
RefPtr<JS::Stencil> stencil;
|
||||
JS::Rooted<JSScript*> script(RootingCx());
|
||||
{
|
||||
AutoJSAPI jsapi;
|
||||
if (!jsapi.Init(xpc::CompilationScope())) {
|
||||
@ -1889,7 +1812,7 @@ NotifyOffThreadScriptCompletedRunnable::Run() {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
JSContext* cx = jsapi.cx();
|
||||
stencil = JS::FinishOffThreadCompileToStencil(cx, mToken);
|
||||
script = JS::FinishOffThreadScript(cx, mToken);
|
||||
}
|
||||
|
||||
if (!sReceivers) {
|
||||
@ -1903,8 +1826,8 @@ NotifyOffThreadScriptCompletedRunnable::Run() {
|
||||
std::move((*sReceivers)[index]);
|
||||
sReceivers->RemoveElementAt(index);
|
||||
|
||||
return receiver->OnScriptCompileComplete(stencil,
|
||||
stencil ? NS_OK : NS_ERROR_FAILURE);
|
||||
return receiver->OnScriptCompileComplete(script,
|
||||
script ? NS_OK : NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
static void OffThreadScriptReceiverCallback(JS::OffThreadToken* aToken,
|
||||
@ -1955,43 +1878,38 @@ nsresult nsXULPrototypeScript::Compile(
|
||||
JS::Rooted<JSObject*> scope(cx, JS::CurrentGlobalOrNull(cx));
|
||||
|
||||
if (aOffThreadReceiver && JS::CanCompileOffThread(cx, options, aTextLength)) {
|
||||
if (!JS::CompileToStencilOffThread(
|
||||
cx, options, srcBuf, OffThreadScriptReceiverCallback,
|
||||
static_cast<void*>(aOffThreadReceiver))) {
|
||||
JS_ClearPendingException(cx);
|
||||
if (!JS::CompileOffThread(cx, options, srcBuf,
|
||||
OffThreadScriptReceiverCallback,
|
||||
static_cast<void*>(aOffThreadReceiver))) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
NotifyOffThreadScriptCompletedRunnable::NoteReceiver(aOffThreadReceiver);
|
||||
} else {
|
||||
RefPtr<JS::Stencil> stencil =
|
||||
JS::CompileGlobalScriptToStencil(cx, options, srcBuf);
|
||||
if (!stencil) {
|
||||
JS::Rooted<JSScript*> script(cx, JS::Compile(cx, options, srcBuf));
|
||||
if (!script) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
Set(stencil);
|
||||
Set(script);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsXULPrototypeScript::InstantiateScript(
|
||||
JSContext* aCx, JS::MutableHandleScript aScript) {
|
||||
MOZ_ASSERT(mStencil);
|
||||
|
||||
JS::CompileOptions options(aCx);
|
||||
FillCompileOptions(options);
|
||||
// We don't need setIntroductionType and setFileAndLine here, unlike
|
||||
// nsXULPrototypeScript::Compile.
|
||||
// mStencil already contains the information.
|
||||
aScript.set(JS::InstantiateGlobalStencil(aCx, options, mStencil));
|
||||
if (!aScript) {
|
||||
JS_ClearPendingException(aCx);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
void nsXULPrototypeScript::UnlinkJSObjects() {
|
||||
if (mScriptObject) {
|
||||
mozilla::DropJSObjects(this);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsXULPrototypeScript::Set(JS::Stencil* aStencil) { mStencil = aStencil; }
|
||||
void nsXULPrototypeScript::Set(JSScript* aObject) {
|
||||
MOZ_ASSERT(!mScriptObject, "Leaking script object.");
|
||||
if (!aObject) {
|
||||
mScriptObject = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
mScriptObject = aObject;
|
||||
mozilla::HoldJSObjects(this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
|
@ -15,11 +15,9 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "ErrorList.h"
|
||||
#include "js/experimental/JSStencil.h"
|
||||
#include "js/RootingAPI.h"
|
||||
#include "js/SourceText.h"
|
||||
#include "js/TracingAPI.h"
|
||||
#include "js/TypeDecls.h"
|
||||
#include "mozilla/AlreadyAddRefed.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
@ -50,6 +48,7 @@
|
||||
#include "nscore.h"
|
||||
|
||||
class JSObject;
|
||||
class JSScript;
|
||||
class nsAttrValueOrString;
|
||||
class nsIControllers;
|
||||
class nsIObjectInputStream;
|
||||
@ -196,6 +195,9 @@ class nsXULPrototypeElement : public nsXULPrototypeNode {
|
||||
|
||||
void Unlink();
|
||||
|
||||
// Trace all scripts held by this element and its children.
|
||||
void TraceAllScripts(JSTracer* aTrc);
|
||||
|
||||
nsPrototypeArray mChildren;
|
||||
|
||||
RefPtr<mozilla::dom::NodeInfo> mNodeInfo;
|
||||
@ -212,7 +214,7 @@ class nsXULPrototypeScript : public nsXULPrototypeNode {
|
||||
explicit nsXULPrototypeScript(uint32_t aLineNo);
|
||||
|
||||
private:
|
||||
virtual ~nsXULPrototypeScript() = default;
|
||||
virtual ~nsXULPrototypeScript();
|
||||
|
||||
void FillCompileOptions(JS::CompileOptions& options);
|
||||
|
||||
@ -234,15 +236,26 @@ class nsXULPrototypeScript : public nsXULPrototypeNode {
|
||||
uint32_t aLineNo, mozilla::dom::Document* aDocument,
|
||||
nsIOffThreadScriptReceiver* aOffThreadReceiver = nullptr);
|
||||
|
||||
void UnlinkStencil() { mStencil = nullptr; }
|
||||
void UnlinkJSObjects();
|
||||
|
||||
void Set(JS::Stencil* aStencil);
|
||||
void Set(JSScript* aObject);
|
||||
|
||||
bool HasStencil() { return mStencil; }
|
||||
bool HasScriptObject() {
|
||||
// Conversion to bool doesn't trigger mScriptObject's read barrier.
|
||||
return mScriptObject;
|
||||
}
|
||||
|
||||
JS::Stencil* GetStencil() { return mStencil.get(); }
|
||||
JSScript* GetScriptObject() { return mScriptObject; }
|
||||
|
||||
nsresult InstantiateScript(JSContext* aCx, JS::MutableHandleScript aScript);
|
||||
void TraceScriptObject(JSTracer* aTrc) {
|
||||
JS::TraceEdge(aTrc, &mScriptObject, "active window XUL prototype script");
|
||||
}
|
||||
|
||||
void Trace(const TraceCallbacks& aCallbacks, void* aClosure) {
|
||||
if (mScriptObject) {
|
||||
aCallbacks.Trace(&mScriptObject, "mScriptObject", aClosure);
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> mSrcURI;
|
||||
uint32_t mLineNo;
|
||||
@ -251,7 +264,7 @@ class nsXULPrototypeScript : public nsXULPrototypeNode {
|
||||
mozilla::dom::PrototypeDocumentContentSink*
|
||||
mSrcLoadWaiters; // [OWNER] but not COMPtr
|
||||
private:
|
||||
RefPtr<JS::Stencil> mStencil;
|
||||
JS::Heap<JSScript*> mScriptObject;
|
||||
};
|
||||
|
||||
class nsXULPrototypeText : public nsXULPrototypeNode {
|
||||
|
@ -20,7 +20,6 @@
|
||||
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
|
||||
#include "js/experimental/JSStencil.h"
|
||||
#include "js/TracingAPI.h"
|
||||
|
||||
#include "mozilla/StyleSheetInlines.h"
|
||||
@ -28,7 +27,6 @@
|
||||
#include "mozilla/scache/StartupCache.h"
|
||||
#include "mozilla/scache/StartupCacheUtils.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/intl/LocaleService.h"
|
||||
|
||||
using namespace mozilla;
|
||||
@ -75,6 +73,8 @@ nsXULPrototypeCache* nsXULPrototypeCache::sInstance = nullptr;
|
||||
|
||||
nsXULPrototypeCache::nsXULPrototypeCache() = default;
|
||||
|
||||
nsXULPrototypeCache::~nsXULPrototypeCache() { FlushScripts(); }
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsXULPrototypeCache, nsIObserver)
|
||||
|
||||
/* static */
|
||||
@ -165,18 +165,19 @@ nsresult nsXULPrototypeCache::PutPrototype(nsXULPrototypeDocument* aDocument) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
JS::Stencil* nsXULPrototypeCache::GetStencil(nsIURI* aURI) {
|
||||
if (auto* entry = mStencilTable.GetEntry(aURI)) {
|
||||
return entry->mStencil;
|
||||
JSScript* nsXULPrototypeCache::GetScript(nsIURI* aURI) {
|
||||
if (auto* entry = mScriptTable.GetEntry(aURI)) {
|
||||
return entry->mScript.get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsresult nsXULPrototypeCache::PutStencil(nsIURI* aURI, JS::Stencil* aStencil) {
|
||||
MOZ_ASSERT(aStencil, "Need a non-NULL stencil");
|
||||
nsresult nsXULPrototypeCache::PutScript(nsIURI* aURI,
|
||||
JS::Handle<JSScript*> aScriptObject) {
|
||||
MOZ_ASSERT(aScriptObject, "Need a non-NULL script");
|
||||
|
||||
#ifdef DEBUG_BUG_392650
|
||||
if (mStencilTable.Get(aURI)) {
|
||||
if (mScriptTable.Get(aURI)) {
|
||||
nsAutoCString scriptName;
|
||||
aURI->GetSpec(scriptName);
|
||||
nsAutoCString message("Loaded script ");
|
||||
@ -186,14 +187,16 @@ nsresult nsXULPrototypeCache::PutStencil(nsIURI* aURI, JS::Stencil* aStencil) {
|
||||
}
|
||||
#endif
|
||||
|
||||
mStencilTable.PutEntry(aURI)->mStencil = aStencil;
|
||||
mScriptTable.PutEntry(aURI)->mScript.set(aScriptObject);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsXULPrototypeCache::FlushScripts() { mScriptTable.Clear(); }
|
||||
|
||||
void nsXULPrototypeCache::Flush() {
|
||||
mPrototypeTable.Clear();
|
||||
mStencilTable.Clear();
|
||||
mScriptTable.Clear();
|
||||
}
|
||||
|
||||
bool nsXULPrototypeCache::IsEnabled() { return !gDisableXULCache; }
|
||||
@ -458,6 +461,12 @@ void nsXULPrototypeCache::MarkInCCGeneration(uint32_t aGeneration) {
|
||||
}
|
||||
}
|
||||
|
||||
void nsXULPrototypeCache::MarkInGC(JSTracer* aTrc) {
|
||||
for (auto& entry : mScriptTable) {
|
||||
JS::TraceEdge(aTrc, &entry.mScript, "nsXULPrototypeCache script");
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_DEFINE_MALLOC_SIZE_OF(CacheMallocSizeOf)
|
||||
|
||||
static void ReportSize(const nsCString& aPath, size_t aAmount,
|
||||
@ -487,8 +496,8 @@ void nsXULPrototypeCache::CollectMemoryReports(
|
||||
other += sInstance->mPrototypeTable.ShallowSizeOfExcludingThis(mallocSizeOf);
|
||||
// TODO Report content in mPrototypeTable?
|
||||
|
||||
other += sInstance->mStencilTable.ShallowSizeOfExcludingThis(mallocSizeOf);
|
||||
// TODO Report content inside mStencilTable?
|
||||
other += sInstance->mScriptTable.ShallowSizeOfExcludingThis(mallocSizeOf);
|
||||
// TODO Report content inside mScriptTable?
|
||||
|
||||
other +=
|
||||
sInstance->mStartupCacheURITable.ShallowSizeOfExcludingThis(mallocSizeOf);
|
||||
|
@ -16,8 +16,6 @@
|
||||
#include "nsIStorageStream.h"
|
||||
|
||||
#include "mozilla/scache/StartupCache.h"
|
||||
#include "js/experimental/JSStencil.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
class nsIHandleReportCallback;
|
||||
namespace mozilla {
|
||||
@ -58,8 +56,8 @@ class nsXULPrototypeCache : public nsIObserver {
|
||||
nsXULPrototypeDocument* GetPrototype(nsIURI* aURI);
|
||||
nsresult PutPrototype(nsXULPrototypeDocument* aDocument);
|
||||
|
||||
JS::Stencil* GetStencil(nsIURI* aURI);
|
||||
nsresult PutStencil(nsIURI* aURI, JS::Stencil* aStencil);
|
||||
JSScript* GetScript(nsIURI* aURI);
|
||||
nsresult PutScript(nsIURI* aURI, JS::Handle<JSScript*> aScriptObject);
|
||||
|
||||
/**
|
||||
* Write the XUL prototype document to a cache file. The proto must be
|
||||
@ -83,6 +81,8 @@ class nsXULPrototypeCache : public nsIObserver {
|
||||
static void ReleaseGlobals() { NS_IF_RELEASE(sInstance); }
|
||||
|
||||
void MarkInCCGeneration(uint32_t aGeneration);
|
||||
void MarkInGC(JSTracer* aTrc);
|
||||
void FlushScripts();
|
||||
|
||||
static void CollectMemoryReports(nsIHandleReportCallback* aHandleReport,
|
||||
nsISupports* aData);
|
||||
@ -92,22 +92,26 @@ class nsXULPrototypeCache : public nsIObserver {
|
||||
void** aResult);
|
||||
|
||||
nsXULPrototypeCache();
|
||||
virtual ~nsXULPrototypeCache() = default;
|
||||
virtual ~nsXULPrototypeCache();
|
||||
|
||||
static nsXULPrototypeCache* sInstance;
|
||||
|
||||
nsRefPtrHashtable<nsURIHashKey, nsXULPrototypeDocument>
|
||||
mPrototypeTable; // owns the prototypes
|
||||
|
||||
class StencilHashKey : public nsURIHashKey {
|
||||
class ScriptHashKey : public nsURIHashKey {
|
||||
public:
|
||||
explicit StencilHashKey(const nsIURI* aKey) : nsURIHashKey(aKey) {}
|
||||
StencilHashKey(StencilHashKey&&) = default;
|
||||
explicit ScriptHashKey(const nsIURI* aKey) : nsURIHashKey(aKey) {}
|
||||
ScriptHashKey(ScriptHashKey&&) = default;
|
||||
|
||||
RefPtr<JS::Stencil> mStencil;
|
||||
// Mark ALLOW_MEMMOVE as false, as hash tables containing JS:Heap<T>
|
||||
// values must be copied rather than memmoved.
|
||||
enum { ALLOW_MEMMOVE = false };
|
||||
|
||||
JS::Heap<JSScript*> mScript;
|
||||
};
|
||||
|
||||
nsTHashtable<StencilHashKey> mStencilTable;
|
||||
nsTHashtable<ScriptHashKey> mScriptTable;
|
||||
|
||||
// URIs already written to the startup cache, to prevent double-caching.
|
||||
nsTHashtable<nsURIHashKey> mStartupCacheURITable;
|
||||
|
@ -42,7 +42,11 @@ uint32_t nsXULPrototypeDocument::gRefCnt;
|
||||
//
|
||||
|
||||
nsXULPrototypeDocument::nsXULPrototypeDocument()
|
||||
: mRoot(nullptr), mLoaded(false), mCCGeneration(0), mWasL10nCached(false) {
|
||||
: mRoot(nullptr),
|
||||
mLoaded(false),
|
||||
mCCGeneration(0),
|
||||
mGCNumber(0),
|
||||
mWasL10nCached(false) {
|
||||
++gRefCnt;
|
||||
}
|
||||
|
||||
@ -423,6 +427,21 @@ nsresult nsXULPrototypeDocument::NotifyLoadDone() {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsXULPrototypeDocument::TraceProtos(JSTracer* aTrc) {
|
||||
// Only trace the protos once per GC if we are marking.
|
||||
if (aTrc->isMarkingTracer()) {
|
||||
uint32_t currentGCNumber = aTrc->gcNumberForMarking();
|
||||
if (mGCNumber == currentGCNumber) {
|
||||
return;
|
||||
}
|
||||
mGCNumber = currentGCNumber;
|
||||
}
|
||||
|
||||
if (mRoot) {
|
||||
mRoot->TraceAllScripts(aTrc);
|
||||
}
|
||||
}
|
||||
|
||||
void nsXULPrototypeDocument::SetIsL10nCached(bool aIsCached) {
|
||||
mWasL10nCached = aIsCached;
|
||||
}
|
||||
|
@ -94,6 +94,8 @@ class nsXULPrototypeDocument final : public nsISerializable {
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(nsXULPrototypeDocument)
|
||||
|
||||
void TraceProtos(JSTracer* aTrc);
|
||||
|
||||
bool WasL10nCached() { return mWasL10nCached; };
|
||||
|
||||
void SetIsL10nCached(bool aIsCached);
|
||||
@ -112,6 +114,7 @@ class nsXULPrototypeDocument final : public nsISerializable {
|
||||
RefPtr<nsNodeInfoManager> mNodeInfoManager;
|
||||
|
||||
uint32_t mCCGeneration;
|
||||
uint32_t mGCNumber;
|
||||
|
||||
nsXULPrototypeDocument();
|
||||
virtual ~nsXULPrototypeDocument();
|
||||
|
@ -87,9 +87,6 @@ extern JS_PUBLIC_API JSScript* InstantiateGlobalStencil(
|
||||
// decoding.
|
||||
extern JS_PUBLIC_API bool StencilIsBorrowed(Stencil* stencil);
|
||||
|
||||
// Return true if the stencil is lazily parsed.
|
||||
extern JS_PUBLIC_API bool StencilCanLazilyParse(Stencil* stencil);
|
||||
|
||||
// Instantiate a module Stencil and return the associated object. Inside the
|
||||
// engine this is a js::ModuleObject.
|
||||
extern JS_PUBLIC_API JSObject* InstantiateModuleStencil(
|
||||
|
@ -4044,10 +4044,6 @@ JS_PUBLIC_API bool JS::StencilIsBorrowed(Stencil* stencil) {
|
||||
return stencil->hasExternalDependency;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API bool JS::StencilCanLazilyParse(Stencil* stencil) {
|
||||
return stencil->canLazilyParse;
|
||||
}
|
||||
|
||||
JSObject* JS::InstantiateModuleStencil(
|
||||
JSContext* cx, const JS::ReadOnlyCompileOptions& optionsInput,
|
||||
JS::Stencil* stencil) {
|
||||
|
@ -4455,9 +4455,8 @@ static JSScript* CopyScriptImpl(JSContext* cx, HandleScript src,
|
||||
SourceExtent extent = src->extent();
|
||||
|
||||
ImmutableScriptFlags flags = src->immutableFlags();
|
||||
// The source/target of clone should agree with syntactic scope.
|
||||
MOZ_ASSERT(flags.hasFlag(JSScript::ImmutableFlags::HasNonSyntacticScope) ==
|
||||
scopes[0]->hasOnChain(ScopeKind::NonSyntactic));
|
||||
flags.setFlag(JSScript::ImmutableFlags::HasNonSyntacticScope,
|
||||
scopes[0]->hasOnChain(ScopeKind::NonSyntactic));
|
||||
|
||||
// FunctionFlags and ImmutableScriptFlags should agree on self-hosting status.
|
||||
MOZ_ASSERT_IF(functionOrGlobal->is<JSFunction>(),
|
||||
|
@ -1787,6 +1787,13 @@
|
||||
* The result is always `undefined` except when the name refers to a
|
||||
* binding in a non-syntactic `with` environment.
|
||||
*
|
||||
* Note: The frontend has to emit `JSOp::GImplicitThis` (and not
|
||||
* `JSOp::Undefined`) for global unqualified function calls, even when
|
||||
* `CompileOptions::nonSyntacticScope == false`, because later
|
||||
* `js::CloneGlobalScript` can be called with `ScopeKind::NonSyntactic` to
|
||||
* clone the script into a non-syntactic environment, with the bytecode
|
||||
* reused, unchanged.
|
||||
*
|
||||
* Category: Functions
|
||||
* Type: Calls
|
||||
* Operands: uint32_t nameIndex
|
||||
|
@ -25,6 +25,7 @@ class nsWrapperCache;
|
||||
|
||||
[ptr] native JSContextPtr(JSContext);
|
||||
[ptr] native JSObjectPtr(JSObject);
|
||||
[ptr] native JSScriptPtr(JSScript);
|
||||
[ptr] native nsWrapperCachePtr(nsWrapperCache);
|
||||
native JSHandleId(JS::Handle<jsid>);
|
||||
[ref] native const_JSReadOnlyCompileOptionsRef(const JS::ReadOnlyCompileOptions);
|
||||
@ -258,4 +259,14 @@ interface nsIXPConnect : nsISupports
|
||||
[noscript] jsval evalInSandboxObject(in AString source, in string filename,
|
||||
in JSContextPtr cx,
|
||||
in JSObjectPtr sandbox);
|
||||
|
||||
[noscript] void writeScript(in nsIObjectOutputStream aStream,
|
||||
in JSContextPtr aJSContext,
|
||||
in JSScriptPtr aJSScript);
|
||||
|
||||
[noscript] JSScriptPtr readScript(in nsIObjectInputStream aStream,
|
||||
in JSContextPtr aJSContext,
|
||||
in const_JSReadOnlyCompileOptionsRef aOptions);
|
||||
|
||||
[infallible] readonly attribute boolean isShuttingDown;
|
||||
};
|
||||
|
@ -695,7 +695,7 @@ void XPCJSRuntime::TraceNativeBlackRoots(JSTracer* trc) {
|
||||
}
|
||||
}
|
||||
|
||||
dom::TraceBlackJS(trc);
|
||||
dom::TraceBlackJS(trc, nsIXPConnect::XPConnect()->GetIsShuttingDown());
|
||||
}
|
||||
|
||||
void XPCJSRuntime::TraceAdditionalNativeGrayRoots(JSTracer* trc) {
|
||||
|
@ -70,7 +70,7 @@ const char XPC_SCRIPT_ERROR_CONTRACTID[] = "@mozilla.org/scripterror;1";
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
nsXPConnect::nsXPConnect() {
|
||||
nsXPConnect::nsXPConnect() : mShuttingDown(false) {
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
JS::SetProfilingThreadCallbacks(profiler_register_thread,
|
||||
profiler_unregister_thread);
|
||||
@ -111,6 +111,7 @@ nsXPConnect::~nsXPConnect() {
|
||||
// get by with only the second GC. :-(
|
||||
mRuntime->GarbageCollect(JS::GCReason::XPCONNECT_SHUTDOWN);
|
||||
|
||||
mShuttingDown = true;
|
||||
XPCWrappedNativeScope::SystemIsBeingShutDown();
|
||||
mRuntime->SystemIsBeingShutDown();
|
||||
|
||||
@ -918,6 +919,110 @@ void SetLocationForGlobal(JSObject* global, nsIURI* locationURI) {
|
||||
|
||||
} // namespace xpc
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPConnect::WriteScript(nsIObjectOutputStream* stream, JSContext* cx,
|
||||
JSScript* scriptArg) {
|
||||
RootedScript script(cx, scriptArg);
|
||||
|
||||
uint8_t flags = 0; // We don't have flags anymore.
|
||||
nsresult rv = stream->Write8(flags);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
TranscodeBuffer buffer;
|
||||
TranscodeResult code;
|
||||
code = EncodeScript(cx, buffer, script);
|
||||
|
||||
if (code != TranscodeResult::Ok) {
|
||||
if (code == TranscodeResult::Throw) {
|
||||
JS_ClearPendingException(cx);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(IsTranscodeFailureResult(code));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
size_t size = buffer.length();
|
||||
if (size > UINT32_MAX) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
rv = stream->Write32(size);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// Ideally we could just pass "buffer" here. See bug 1566574.
|
||||
rv = stream->WriteBytes(Span(buffer.begin(), size));
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPConnect::ReadScript(nsIObjectInputStream* stream, JSContext* cx,
|
||||
const JS::ReadOnlyCompileOptions& options,
|
||||
JSScript** scriptp) {
|
||||
uint8_t flags;
|
||||
nsresult rv = stream->Read8(&flags);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// We don't serialize mutedError-ness of scripts, which is fine as long as
|
||||
// we only serialize system and XUL-y things. We can detect this by checking
|
||||
// where the caller wants us to deserialize.
|
||||
//
|
||||
// CompilationScope() could theoretically GC, so get that out of the way
|
||||
// before comparing to the cx global.
|
||||
JSObject* loaderGlobal = xpc::CompilationScope();
|
||||
MOZ_RELEASE_ASSERT(nsContentUtils::IsSystemCaller(cx) ||
|
||||
CurrentGlobalOrNull(cx) == loaderGlobal);
|
||||
|
||||
uint32_t size;
|
||||
rv = stream->Read32(&size);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
char* data;
|
||||
rv = stream->ReadBytes(size, &data);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
TranscodeBuffer buffer;
|
||||
buffer.replaceRawBuffer(reinterpret_cast<uint8_t*>(data), size);
|
||||
|
||||
{
|
||||
TranscodeResult code;
|
||||
Rooted<JSScript*> script(cx);
|
||||
code = DecodeScript(cx, options, buffer, &script);
|
||||
if (code == TranscodeResult::Ok) {
|
||||
*scriptp = script.get();
|
||||
} else {
|
||||
if (code == TranscodeResult::Throw) {
|
||||
JS_ClearPendingException(cx);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(IsTranscodeFailureResult(code));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXPConnect::GetIsShuttingDown(bool* aIsShuttingDown) {
|
||||
if (!aIsShuttingDown) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
*aIsShuttingDown = mShuttingDown;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsIXPConnect* nsIXPConnect::XPConnect() {
|
||||
// Do a release-mode assert that we're not doing anything significant in
|
||||
|
@ -249,6 +249,7 @@ class nsXPConnect final : public nsIXPConnect {
|
||||
|
||||
XPCJSContext* mContext = nullptr;
|
||||
XPCJSRuntime* mRuntime = nullptr;
|
||||
bool mShuttingDown;
|
||||
|
||||
friend class nsIXPConnect;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user