commit 1cee348f519761635a1d553d7218e2e29c8f5bfc
parent 53a4d987b60fafcb253de16a0cf5073a4406a719
Author: Simon Kornblith <simon@simonster.com>
Date: Thu, 6 Jun 2013 19:31:09 -0400
Revert "Remove use of Components.utils.methodjit"
This reverts commit 53a4d987b60fafcb253de16a0cf5073a4406a719.
Diffstat:
3 files changed, 107 insertions(+), 20 deletions(-)
diff --git a/chrome/content/zotero/xpcom/http.js b/chrome/content/zotero/xpcom/http.js
@@ -246,8 +246,10 @@ 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);
};
@@ -332,8 +334,10 @@ 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);
};
@@ -394,8 +398,10 @@ 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);
};
@@ -431,8 +437,10 @@ 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);
@@ -471,8 +479,10 @@ 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);
@@ -548,8 +558,10 @@ 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);
};
@@ -582,8 +594,10 @@ 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);
@@ -625,8 +639,10 @@ 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);
@@ -662,8 +678,10 @@ 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);
diff --git a/chrome/content/zotero/xpcom/zotero.js b/chrome/content/zotero/xpcom/zotero.js
@@ -187,19 +187,27 @@ Components.utils.import("resource://gre/modules/Services.jsm");
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
@@ -239,12 +247,14 @@ Components.utils.import("resource://gre/modules/Services.jsm");
}
// OS platform
- _hiddenDOMWindow = Services.appShell.hiddenDOMWindow;
- this.platform = _hiddenDOMWindow.navigator.platform;
+ var win = Components.classes["@mozilla.org/appshell/appShellService;1"]
+ .getService(Components.interfaces.nsIAppShellService)
+ .hiddenDOMWindow;
+ this.platform = win.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 = _hiddenDOMWindow.navigator.oscpu;
+ this.oscpu = win.navigator.oscpu;
// Browser
Zotero.browser = "g";
@@ -1511,9 +1521,10 @@ Components.utils.import("resource://gre/modules/Services.jsm");
_waiting--;
// requeue nsITimerCallbacks that came up during Zotero.wait() but couldn't execute
- for(var i=0; i<_waitTimerCallbacks.length; i++) {
- Zotero.setTimeout(_waitTimerCallbacks[i], 0);
+ for(var i in _waitTimers) {
+ _waitTimers[i].initWithCallback(_waitTimerCallbacks[i], 0, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
}
+ _waitTimers = [];
_waitTimerCallbacks = [];
//Zotero.debug("Waited " + cycles + " cycles");
@@ -1529,8 +1540,13 @@ Components.utils.import("resource://gre/modules/Services.jsm");
this.pumpGenerator = function(generator, ms, errorHandler, doneHandler) {
_waiting++;
- var yielded;
- var interval = _hiddenDOMWindow.setInterval(function() {
+ 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 err = false;
_waiting--;
try {
@@ -1544,12 +1560,14 @@ Components.utils.import("resource://gre/modules/Services.jsm");
err = e;
}
- _hiddenDOMWindow.clearInterval(interval);
+ timer.cancel();
+ _runningTimers.splice(_runningTimers.indexOf(timer), 1);
// requeue nsITimerCallbacks that came up during generator pumping but couldn't execute
- for(var i=0; i<_waitTimerCallbacks.length; i++) {
- Zotero.setTimeout(_waitTimerCallbacks[i], 0);
+ for(var i in _waitTimers) {
+ _waitTimers[i].initWithCallback(_waitTimerCallbacks[i], 0, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
}
+ _waitTimers = [];
_waitTimerCallbacks = [];
if(err) {
@@ -1561,7 +1579,10 @@ Components.utils.import("resource://gre/modules/Services.jsm");
} else if(doneHandler) {
doneHandler(yielded);
}
- }, 0);
+ }}
+ 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);
};
/**
@@ -1585,17 +1606,27 @@ Components.utils.import("resource://gre/modules/Services.jsm");
* is executing
*/
this.setTimeout = function(func, ms, runWhenWaiting) {
- var timerCallback = function() {
+ var timer = Components.classes["@mozilla.org/timer;1"].
+ createInstance(Components.interfaces.nsITimer),
+ useJIT = Components.utils.methodjit;
+ var timerCallback = {"notify":function() {
+ Components.utils.methodjit = useJIT;
+
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);
}
- };
- _hiddenDOMWindow.setTimeout(timerCallback, ms);
+ }}
+ 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);
}
/**
diff --git a/resource/q.js b/resource/q.js
@@ -58,11 +58,49 @@
// 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 = hiddenDOMWindow.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);
+ }
+ };
Q = definition();
// <script>