Skip to content

Commit

Permalink
Bug 1718481 - Use stencil in nsXULPrototypeCache. r=tcampbell,kmag
Browse files Browse the repository at this point in the history
  • Loading branch information
arai-a committed Sep 21, 2021
1 parent 6d6d53e commit f263a1a
Show file tree
Hide file tree
Showing 18 changed files with 224 additions and 326 deletions.
6 changes: 0 additions & 6 deletions dom/base/Document.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16224,12 +16224,6 @@ 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
Expand Down
2 changes: 0 additions & 2 deletions dom/base/Document.h
Original file line number Diff line number Diff line change
Expand Up @@ -5281,8 +5281,6 @@ class Document : public nsINode,
nsRefPtrHashtable<nsRefPtrHashKey<Element>, nsXULPrototypeElement>
mL10nProtoElements;

void TraceProtos(JSTracer* aTrc);

float GetSavedResolutionBeforeMVM() { return mSavedResolutionBeforeMVM; }
void SetSavedResolutionBeforeMVM(float aResolution) {
mSavedResolutionBeforeMVM = aResolution;
Expand Down
22 changes: 1 addition & 21 deletions dom/base/nsCCUncollectableMarker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -429,20 +429,7 @@ nsresult nsCCUncollectableMarker::Observe(nsISupports* aSubject,
return NS_OK;
}

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

void mozilla::dom::TraceBlackJS(JSTracer* aTrc) {
if (!nsCCUncollectableMarker::sGeneration) {
return;
}
Expand Down Expand Up @@ -504,13 +491,6 @@ void mozilla::dom::TraceBlackJS(JSTracer* aTrc, bool aIsShutdownGC) {
}
}
}

#ifdef MOZ_XUL
Document* doc = window->GetExtantDoc();
if (doc) {
doc->TraceProtos(aTrc);
}
#endif
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion dom/base/nsCCUncollectableMarker.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class nsCCUncollectableMarker final : public nsIObserver {

namespace mozilla {
namespace dom {
void TraceBlackJS(JSTracer* aTrc, bool aIsShutdownGC);
void TraceBlackJS(JSTracer* aTrc);
} // namespace dom
} // namespace mozilla

Expand Down
7 changes: 5 additions & 2 deletions dom/base/nsIScriptContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include "nsISupports.h"
#include "nsCOMPtr.h"
#include "jspubtd.h"
#include "js/experimental/JSStencil.h"
#include "mozilla/RefPtr.h"

class nsIScriptGlobalObject;

Expand Down Expand Up @@ -77,11 +79,12 @@ class nsIOffThreadScriptReceiver : public nsISupports {
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IOFFTHREADSCRIPTRECEIVER_IID)

/**
* Notify this object that a previous CompileScript call specifying this as
* Notify this object that a previous Compile 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(JSScript* aScript, nsresult aStatus) = 0;
NS_IMETHOD OnScriptCompileComplete(JS::Stencil* aStencil,
nsresult aStatus) = 0;
};

NS_DEFINE_STATIC_IID_ACCESSOR(nsIOffThreadScriptReceiver,
Expand Down
57 changes: 29 additions & 28 deletions dom/prototype/PrototypeDocumentContentSink.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,13 @@
#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;
Expand Down Expand Up @@ -566,7 +568,7 @@ nsresult PrototypeDocumentContentSink::ResumeWalkInternal() {
// If the script cannot be loaded, just keep going!

if (NS_SUCCEEDED(rv) && blocked) return NS_OK;
} else if (scriptproto->HasScriptObject()) {
} else if (scriptproto->HasStencil()) {
// An inline script
rv = ExecuteScript(scriptproto);
if (NS_FAILED(rv)) return rv;
Expand Down Expand Up @@ -725,7 +727,7 @@ nsresult PrototypeDocumentContentSink::LoadScript(

bool isChromeDoc = IsChromeURI(mDocumentURI);

if (isChromeDoc && aScriptProto->HasScriptObject()) {
if (isChromeDoc && aScriptProto->HasStencil()) {
rv = ExecuteScript(aScriptProto);

// Ignore return value from execution, and don't block
Expand All @@ -739,15 +741,15 @@ nsresult PrototypeDocumentContentSink::LoadScript(
bool useXULCache = nsXULPrototypeCache::GetInstance()->IsEnabled();

if (isChromeDoc && useXULCache) {
JSScript* newScriptObject =
nsXULPrototypeCache::GetInstance()->GetScript(aScriptProto->mSrcURI);
if (newScriptObject) {
RefPtr<JS::Stencil> newStencil =
nsXULPrototypeCache::GetInstance()->GetStencil(aScriptProto->mSrcURI);
if (newStencil) {
// The script language for a proto must remain constant - we
// can't just change it for this unexpected language.
aScriptProto->Set(newScriptObject);
aScriptProto->Set(newStencil);
}

if (aScriptProto->HasScriptObject()) {
if (aScriptProto->HasStencil()) {
rv = ExecuteScript(aScriptProto);

// Ignore return value from execution, and don't block
Expand All @@ -756,8 +758,8 @@ nsresult PrototypeDocumentContentSink::LoadScript(
}
}

// Release script objects from FastLoad since we decided against using them
aScriptProto->UnlinkJSObjects();
// Release stencil from FastLoad since we decided against using them
aScriptProto->Set(nullptr);

// Set the current script prototype so that OnStreamComplete can report
// the right file if there are errors in the script.
Expand Down Expand Up @@ -841,7 +843,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->mScriptObject, causing control flow at the top of LoadScript
// script->mStencil, causing control flow at the top of LoadScript
// not to reach here.
nsCOMPtr<nsIURI> uri = mCurrentScriptProto->mSrcURI;

Expand All @@ -867,19 +869,19 @@ PrototypeDocumentContentSink::OnStreamComplete(nsIStreamLoader* aLoader,
rv = mCurrentScriptProto->Compile(units, unitsLength,
JS::SourceOwnership::TakeOwnership, uri,
1, mDocument, this);
if (NS_SUCCEEDED(rv) && !mCurrentScriptProto->HasScriptObject()) {
if (NS_SUCCEEDED(rv) && !mCurrentScriptProto->HasStencil()) {
mOffThreadCompiling = true;
mDocument->BlockOnload();
return NS_OK;
}
}
}

return OnScriptCompileComplete(mCurrentScriptProto->GetScriptObject(), rv);
return OnScriptCompileComplete(mCurrentScriptProto->GetStencil(), rv);
}

NS_IMETHODIMP
PrototypeDocumentContentSink::OnScriptCompileComplete(JSScript* aScript,
PrototypeDocumentContentSink::OnScriptCompileComplete(JS::Stencil* aStencil,
nsresult aStatus) {
// The mCurrentScriptProto may have been cleared out by another
// PrototypeDocumentContentSink.
Expand All @@ -889,8 +891,9 @@ PrototypeDocumentContentSink::OnScriptCompileComplete(JSScript* aScript,

// When compiling off thread the script will not have been attached to the
// script proto yet.
if (aScript && !mCurrentScriptProto->HasScriptObject())
mCurrentScriptProto->Set(aScript);
if (aStencil && !mCurrentScriptProto->HasStencil()) {
mCurrentScriptProto->Set(aStencil);
}

// Allow load events to be fired once off thread compilation finishes.
if (mOffThreadCompiling) {
Expand Down Expand Up @@ -943,11 +946,9 @@ PrototypeDocumentContentSink::OnScriptCompileComplete(JSScript* aScript,
// the true crime story.)
bool useXULCache = nsXULPrototypeCache::GetInstance()->IsEnabled();

if (useXULCache && IsChromeURI(mDocumentURI) &&
scriptProto->HasScriptObject()) {
JS::Rooted<JSScript*> script(RootingCx(), scriptProto->GetScriptObject());
nsXULPrototypeCache::GetInstance()->PutScript(scriptProto->mSrcURI,
script);
if (useXULCache && IsChromeURI(mDocumentURI) && scriptProto->HasStencil()) {
nsXULPrototypeCache::GetInstance()->PutStencil(scriptProto->mSrcURI,
scriptProto->GetStencil());
}
// ignore any evaluation errors
}
Expand All @@ -970,7 +971,7 @@ PrototypeDocumentContentSink::OnScriptCompileComplete(JSScript* aScript,
*docp = doc->mNextSrcLoadWaiter;
doc->mNextSrcLoadWaiter = nullptr;

if (aStatus == NS_BINDING_ABORTED && !scriptProto->HasScriptObject()) {
if (aStatus == NS_BINDING_ABORTED && !scriptProto->HasStencil()) {
// 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.
Expand All @@ -981,7 +982,7 @@ PrototypeDocumentContentSink::OnScriptCompileComplete(JSScript* aScript,
}

// Execute only if we loaded and compiled successfully, then resume
if (NS_SUCCEEDED(aStatus) && scriptProto->HasScriptObject()) {
if (NS_SUCCEEDED(aStatus) && scriptProto->HasStencil()) {
doc->ExecuteScript(scriptProto);
}
doc->ResumeWalk();
Expand Down Expand Up @@ -1010,22 +1011,22 @@ nsresult PrototypeDocumentContentSink::ExecuteScript(
// Execute the precompiled script with the given version
nsAutoMicroTask mt;

// We're about to run script via JS::CloneAndExecuteScript, so we need an
// We're about to run script via JS_ExecuteScript, 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, aScript->GetScriptObject());
NS_ENSURE_TRUE(scriptObject, NS_ERROR_UNEXPECTED);
JS::Rooted<JSScript*> scriptObject(cx);
rv = aScript->InstantiateScript(cx, &scriptObject);
NS_ENSURE_SUCCESS(rv, rv);

JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
NS_ENSURE_TRUE(xpc::Scriptability::Get(global).Allowed(), NS_OK);

// The script is in the compilation scope. Clone it into the target scope
// and execute it. On failure, ~AutoScriptEntry will handle exceptions, so
// On failure, ~AutoScriptEntry will handle exceptions, so
// there is no need to manually check the return value.
JS::RootedValue rval(cx);
JS::CloneAndExecuteScript(cx, scriptObject, &rval);
Unused << JS_ExecuteScript(cx, scriptObject, &rval);

return NS_OK;
}
Expand Down
4 changes: 3 additions & 1 deletion dom/prototype/PrototypeDocumentContentSink.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include "nsIScriptContext.h"
#include "nsICSSLoaderObserver.h"
#include "mozilla/Logging.h"
#include "js/experimental/JSStencil.h"
#include "mozilla/RefPtr.h"

class nsIURI;
class nsIChannel;
Expand Down Expand Up @@ -86,7 +88,7 @@ class PrototypeDocumentContentSink final : public nsIStreamLoaderObserver,
nsresult aStatus) override;

// nsIOffThreadScriptReceiver
NS_IMETHOD OnScriptCompileComplete(JSScript* aScript,
NS_IMETHOD OnScriptCompileComplete(JS::Stencil* aStencil,
nsresult aStatus) override;

nsresult OnPrototypeLoadDone(nsXULPrototypeDocument* aPrototype);
Expand Down
2 changes: 1 addition & 1 deletion dom/xul/nsXULContentSink.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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->HasScriptObject()) {
if (!script->mSrcURI && !script->HasStencil()) {
nsCOMPtr<Document> doc = do_QueryReferent(mDocument);

script->mOutOfLine = false;
Expand Down
Loading

0 comments on commit f263a1a

Please sign in to comment.