Remove use of Components.utils.methodjit

It appears that this flag can no longer be set in new-ish Nightlies.
This patch switches code that used nsITimers with the
Components.utils.methodjit hack to use setTimeout on the hidden DOM
window instead, so that we still get the JIT. (See
https://bugzilla.mozilla.org/show_bug.cgi?id=776798)

This might also mean that callbacks from doGet etc. no longer get JITed.
At some point, we should test this with the JIT profiler.
This commit is contained in:
Simon Kornblith 2013-06-05 18:12:52 -04:00
parent 5bfee27ab9
commit 53a4d987b6
3 changed files with 20 additions and 107 deletions

View file

@ -246,10 +246,8 @@ Zotero.HTTP = new function() {
// Don't cache GET requests
xmlhttp.channel.loadFlags |= Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE;
var useMethodjit = Components.utils.methodjit;
/** @ignore */
xmlhttp.onreadystatechange = function() {
Components.utils.methodjit = useMethodjit;
_stateChange(xmlhttp, onDone, responseCharset);
};
@ -334,10 +332,8 @@ Zotero.HTTP = new function() {
xmlhttp.setRequestHeader(header, headers[header]);
}
var useMethodjit = Components.utils.methodjit;
/** @ignore */
xmlhttp.onreadystatechange = function() {
Components.utils.methodjit = useMethodjit;
_stateChange(xmlhttp, onDone, responseCharset);
};
@ -398,10 +394,8 @@ Zotero.HTTP = new function() {
// Don't cache HEAD requests
xmlhttp.channel.loadFlags |= Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE;
var useMethodjit = Components.utils.methodjit;
/** @ignore */
xmlhttp.onreadystatechange = function() {
Components.utils.methodjit = useMethodjit;
_stateChange(xmlhttp, onDone);
};
@ -437,10 +431,8 @@ Zotero.HTTP = new function() {
xmlhttp.mozBackgroundRequest = true;
xmlhttp.open('OPTIONS', uri.spec, true);
var useMethodjit = Components.utils.methodjit;
/** @ignore */
xmlhttp.onreadystatechange = function() {
Components.utils.methodjit = useMethodjit;
_stateChange(xmlhttp, callback);
};
xmlhttp.send(null);
@ -479,10 +471,8 @@ Zotero.HTTP = new function() {
xmlhttp.channel.loadFlags |= Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE;
var useMethodjit = Components.utils.methodjit;
/** @ignore */
xmlhttp.onreadystatechange = function() {
Components.utils.methodjit = useMethodjit;
_stateChange(xmlhttp, function (xmlhttp) {
Zotero.debug("Proxy auth request completed with status "
+ xmlhttp.status + ": " + xmlhttp.responseText);
@ -558,10 +548,8 @@ Zotero.HTTP = new function() {
xmlhttp.setRequestHeader("Content-Type", 'text/xml; charset="utf-8"');
var useMethodjit = Components.utils.methodjit;
/** @ignore */
xmlhttp.onreadystatechange = function() {
Components.utils.methodjit = useMethodjit;
_stateChange(xmlhttp, callback);
};
@ -594,10 +582,8 @@ Zotero.HTTP = new function() {
// Prevent certificate/authentication dialogs from popping up
xmlhttp.mozBackgroundRequest = true;
xmlhttp.open('MKCOL', uri.spec, true);
var useMethodjit = Components.utils.methodjit;
/** @ignore */
xmlhttp.onreadystatechange = function() {
Components.utils.methodjit = useMethodjit;
_stateChange(xmlhttp, callback);
};
xmlhttp.send(null);
@ -639,10 +625,8 @@ Zotero.HTTP = new function() {
// with Content-Length: 0, which triggers a "no element found" error
// in Firefox, so we override to text
xmlhttp.overrideMimeType("text/plain");
var useMethodjit = Components.utils.methodjit;
/** @ignore */
xmlhttp.onreadystatechange = function() {
Components.utils.methodjit = useMethodjit;
_stateChange(xmlhttp, callback);
};
xmlhttp.send(body);
@ -678,10 +662,8 @@ Zotero.HTTP = new function() {
// Firefox 3 throws a "no element found" error even with a
// 204 ("No Content") response, so we override to text
xmlhttp.overrideMimeType("text/plain");
var useMethodjit = Components.utils.methodjit;
/** @ignore */
xmlhttp.onreadystatechange = function() {
Components.utils.methodjit = useMethodjit;
_stateChange(xmlhttp, callback);
};
xmlhttp.send(null);

View file

@ -186,28 +186,20 @@ Components.utils.import("resource://gre/modules/Services.jsm");
// whether we are waiting for another Zotero process to release its DB lock
var _waitingForDBLock = false;
/**
* Maintains nsITimers to be used when Zotero.wait() completes (to reduce performance penalty
* of initializing new objects)
*/
var _waitTimers = [];
/**
* Maintains nsITimerCallbacks to be used when Zotero.wait() completes
*/
var _waitTimerCallbacks = [];
/**
* Maintains running nsITimers in global scope, so that they don't disappear randomly
*/
var _runningTimers = [];
// Errors that were in the console at startup
var _startupErrors = [];
// Number of errors to maintain in the recent errors buffer
const ERROR_BUFFER_SIZE = 25;
// A rolling buffer of the last ERROR_BUFFER_SIZE errors
var _recentErrors = [];
// The hidden DOM window
var _hiddenDOMWindow;
/**
* Initialize the extension
@ -247,14 +239,12 @@ Components.utils.import("resource://gre/modules/Services.jsm");
}
// OS platform
var win = Components.classes["@mozilla.org/appshell/appShellService;1"]
.getService(Components.interfaces.nsIAppShellService)
.hiddenDOMWindow;
this.platform = win.navigator.platform;
_hiddenDOMWindow = Services.appShell.hiddenDOMWindow;
this.platform = _hiddenDOMWindow.navigator.platform;
this.isMac = (this.platform.substr(0, 3) == "Mac");
this.isWin = (this.platform.substr(0, 3) == "Win");
this.isLinux = (this.platform.substr(0, 5) == "Linux");
this.oscpu = win.navigator.oscpu;
this.oscpu = _hiddenDOMWindow.navigator.oscpu;
// Browser
Zotero.browser = "g";
@ -1521,10 +1511,9 @@ Components.utils.import("resource://gre/modules/Services.jsm");
_waiting--;
// requeue nsITimerCallbacks that came up during Zotero.wait() but couldn't execute
for(var i in _waitTimers) {
_waitTimers[i].initWithCallback(_waitTimerCallbacks[i], 0, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
for(var i=0; i<_waitTimerCallbacks.length; i++) {
Zotero.setTimeout(_waitTimerCallbacks[i], 0);
}
_waitTimers = [];
_waitTimerCallbacks = [];
//Zotero.debug("Waited " + cycles + " cycles");
@ -1540,13 +1529,8 @@ Components.utils.import("resource://gre/modules/Services.jsm");
this.pumpGenerator = function(generator, ms, errorHandler, doneHandler) {
_waiting++;
var timer = Components.classes["@mozilla.org/timer;1"].
createInstance(Components.interfaces.nsITimer),
yielded,
useJIT = Components.utils.methodjit;
var timerCallback = {"notify":function() {
Components.utils.methodjit = useJIT;
var yielded;
var interval = _hiddenDOMWindow.setInterval(function() {
var err = false;
_waiting--;
try {
@ -1560,14 +1544,12 @@ Components.utils.import("resource://gre/modules/Services.jsm");
err = e;
}
timer.cancel();
_runningTimers.splice(_runningTimers.indexOf(timer), 1);
_hiddenDOMWindow.clearInterval(interval);
// requeue nsITimerCallbacks that came up during generator pumping but couldn't execute
for(var i in _waitTimers) {
_waitTimers[i].initWithCallback(_waitTimerCallbacks[i], 0, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
for(var i=0; i<_waitTimerCallbacks.length; i++) {
Zotero.setTimeout(_waitTimerCallbacks[i], 0);
}
_waitTimers = [];
_waitTimerCallbacks = [];
if(err) {
@ -1579,10 +1561,7 @@ Components.utils.import("resource://gre/modules/Services.jsm");
} else if(doneHandler) {
doneHandler(yielded);
}
}}
timer.initWithCallback(timerCallback, ms ? ms : 0, Components.interfaces.nsITimer.TYPE_REPEATING_SLACK);
// add timer to global scope so that it doesn't get garbage collected before it completes
_runningTimers.push(timer);
}, 0);
};
/**
@ -1606,27 +1585,17 @@ Components.utils.import("resource://gre/modules/Services.jsm");
* is executing
*/
this.setTimeout = function(func, ms, runWhenWaiting) {
var timer = Components.classes["@mozilla.org/timer;1"].
createInstance(Components.interfaces.nsITimer),
useJIT = Components.utils.methodjit;
var timerCallback = {"notify":function() {
Components.utils.methodjit = useJIT;
var timerCallback = function() {
if(_waiting && !runWhenWaiting) {
// if our callback gets called during Zotero.wait(), queue it to be set again
// when Zotero.wait() completes
_waitTimers.push(timer);
_waitTimerCallbacks.push(timerCallback);
} else {
// execute callback function
func();
// remove timer from global scope, so it can be garbage collected
_runningTimers.splice(_runningTimers.indexOf(timer), 1);
}
}}
timer.initWithCallback(timerCallback, ms, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
// add timer to global scope so that it doesn't get garbage collected before it completes
_runningTimers.push(timer);
};
_hiddenDOMWindow.setTimeout(timerCallback, ms);
}
/**

View file

@ -58,49 +58,11 @@
// Mozilla JSM
} else if (~String(this).indexOf('BackstagePass')) {
EXPORTED_SYMBOLS = ["Q"];
Components.utils.import("resource://gre/modules/Services.jsm");
var hiddenDOMWindow = Services.appShell.hiddenDOMWindow;
// Q expects an implementation of setTimeout
setTimeout = new function() {
// We need to maintain references to running nsITimers. Otherwise, they can
// get garbage collected before they fire.
var _runningTimers = [];
return function setTimeout(func, ms) {
var useMethodjit = Components.utils.methodjit,
timer = Components.classes["@mozilla.org/timer;1"].
createInstance(Components.interfaces.nsITimer);
timer.initWithCallback({"notify":function() {
Components.utils.methodjit = useMethodjit;
// Remove timer from array so it can be garbage collected
_runningTimers.splice(_runningTimers.indexOf(timer), 1);
// Execute callback function
try {
func();
} catch(err) {
// Rethrow errors that occur so that they appear in the error
// console with the appropriate name and line numbers. While the
// the errors appear without this, the line numbers get eaten.
var scriptError = Components.classes["@mozilla.org/scripterror;1"]
.createInstance(Components.interfaces.nsIScriptError);
scriptError.init(
err.message || err.toString(),
err.fileName || err.filename || null,
null,
err.lineNumber || null,
null,
scriptError.errorFlag,
'component javascript'
);
Components.classes["@mozilla.org/consoleservice;1"]
.getService(Components.interfaces.nsIConsoleService)
.logMessage(scriptError);
}
}}, ms, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
_runningTimers.push(timer);
}
};
setTimeout = hiddenDOMWindow.setTimeout;
Q = definition();
// <script>