Skip to content

Commit

Permalink
dedup script source before evaluating it in the sandbox
Browse files Browse the repository at this point in the history
strings sent via e10s message manager are duplicated and the sandbox
holds onto them as source code, this causes unnecessary memory overhead.
  • Loading branch information
the8472 committed Aug 18, 2015
1 parent f7219b4 commit 219218d
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 7 deletions.
1 change: 1 addition & 0 deletions content/framescript.js
Expand Up @@ -79,6 +79,7 @@ function createScriptFromObject(aObject) {
for (var key in aObject) {
script[key] = aObject[key];
}
script.dedup();
return script;
};

Expand Down
19 changes: 18 additions & 1 deletion modules/ipcscript.js
Expand Up @@ -3,6 +3,8 @@ var EXPORTED_SYMBOLS = ['IPCScript'];
Components.utils.import("chrome://greasemonkey-modules/content/extractMeta.js");
Components.utils.import("chrome://greasemonkey-modules/content/util.js");

var instances = new Map();

function IPCScript(aScript, addonVersion) {
this.addonVersion = addonVersion;
this.description = aScript.description;
Expand Down Expand Up @@ -48,6 +50,21 @@ function IPCScript_getMetaStr() {
return this._metaStr;
});

IPCScript.prototype.dedup = function() {
// scripts sent via e10s message manager contain new string instances every time a new one is created -> dedup them to reduce memory footprint

// alternative approaches:
// a) beam down IPC script instances only once via the parent process manager every time they change.
// b) creating resource URIs and loading user scripts straight from URIs might also be more elegant
// see: https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Using#Programmatically_adding_aliases
var old = instances.get(this.uuid);

if(old == this.textContent)
this.textContent = old
else
instances.set(this.uuid, this.textContent)
};

IPCScript.prototype.info = function() {
var resources = {};
for (var i = 0, r = null; r = this.resources[i]; i++) {
Expand Down Expand Up @@ -80,4 +97,4 @@ IPCScript.prototype.info = function() {
'version': this.version
}
};
};
};
34 changes: 28 additions & 6 deletions modules/sandbox.js
Expand Up @@ -34,9 +34,8 @@ function createSandbox(aScript, aContentWin, aUrl, aFrameScope) {
'wantXrays': false,
});
// GM_info is always provided.
// TODO: lazy getter? XPCOMUtils.defineLazyGetter
Components.utils.evalInSandbox(
'const GM_info = ' + uneval(aScript.info()), contentSandbox);
injectGMInfo(aScript, contentSandbox);

// Alias unsafeWindow for compatibility.
Components.utils.evalInSandbox(
'const unsafeWindow = window;', contentSandbox);
Expand Down Expand Up @@ -122,14 +121,37 @@ function createSandbox(aScript, aContentWin, aUrl, aFrameScope) {
'contentStartRequest');
}

// TODO: lazy getter?
Components.utils.evalInSandbox(
'const GM_info = ' + uneval(aScript.info()), sandbox);
injectGMInfo(aScript, sandbox)

return sandbox;
}


function injectGMInfo(aScript, sandbox) {
// info contains scriptSource, which can be quite large and would get cloned into every tab
// to avoid the memory overhead we only clone the lightweight properties into the sandbox
// and define a getter for the scriptSource instead
var rawInfo = aScript.info();
var infoProxy = {}
for(var key in Object.keys(rawInfo)) {
if(key == "scriptSource")
continue;
infoProxy[key] = rawInfo[key]
}

// TODO: also delay top level clone via lazy getter? XPCOMUtils.defineLazyGetter
sandbox.GM_info = Cu.cloneInto(infoProxy, sandbox);

var waivedSandbox = Components.utils.waiveXrays(sandbox)

waivedSandbox.Object.defineProperty(sandbox.GM_info,
"scriptSource",
{ get: Cu.exportFunction(function() {return rawInfo.scriptSource}, sandbox)
});
}



function runScriptInSandbox(script, sandbox) {
// Eval the code, with anonymous wrappers when/if appropriate.
function evalWithWrapper(code, fileName) {
Expand Down

0 comments on commit 219218d

Please sign in to comment.