1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2025-12-20 11:18:00 +01:00

Replace some arrays with Objects after some memory profiling.

This commit is contained in:
Kris Maglione
2009-11-15 02:31:48 -05:00
parent cdaa26f968
commit a70f1c2926
2 changed files with 90 additions and 101 deletions

View File

@@ -20,7 +20,6 @@ const Hints = Module("hints", {
this._prevInput = ""; // record previous user input type, "text" || "number" this._prevInput = ""; // record previous user input type, "text" || "number"
this._extendedhintCount = null; // for the count argument of Mode#action (extended hint only) this._extendedhintCount = null; // for the count argument of Mode#action (extended hint only)
// hints[] = [elem, text, span, imgSpan, elem.style.backgroundColor, elem.style.color]
this._pageHints = []; this._pageHints = [];
this._validHints = []; // store the indices of the "hints" array with valid elements this._validHints = []; // store the indices of the "hints" array with valid elements
@@ -259,13 +258,12 @@ const Hints = Module("hints", {
let baseNodeAbsolute = util.xmlToDom(<span highlight="Hint"/>, doc); let baseNodeAbsolute = util.xmlToDom(<span highlight="Hint"/>, doc);
let elem, text, span, rect, showText;
let res = util.evaluateXPath(this._hintMode.tags(), doc, null, true); let res = util.evaluateXPath(this._hintMode.tags(), doc, null, true);
let fragment = util.xmlToDom(<div highlight="hints"/>, doc); let fragment = util.xmlToDom(<div highlight="hints"/>, doc);
let start = this._pageHints.length; let start = this._pageHints.length;
for (let elem in res) { for (let elem in res) {
showText = false; let hint = { elem: elem, showText: false };
// TODO: for iframes, this calculation is wrong // TODO: for iframes, this calculation is wrong
rect = elem.getBoundingClientRect(); rect = elem.getBoundingClientRect();
@@ -281,11 +279,11 @@ const Hints = Module("hints", {
continue; continue;
if (elem instanceof HTMLInputElement || elem instanceof HTMLSelectElement || elem instanceof HTMLTextAreaElement) if (elem instanceof HTMLInputElement || elem instanceof HTMLSelectElement || elem instanceof HTMLTextAreaElement)
[text, showText] = this._getInputHint(elem, doc); [hint.text, hint.showText] = this._getInputHint(elem, doc);
else else
text = elem.textContent.toLowerCase(); hint.text = elem.textContent.toLowerCase();
span = baseNodeAbsolute.cloneNode(true); hint.span = baseNodeAbsolute.cloneNode(true);
let leftPos = Math.max((rect.left + offsetX), offsetX); let leftPos = Math.max((rect.left + offsetX), offsetX);
let topPos = Math.max((rect.top + offsetY), offsetY); let topPos = Math.max((rect.top + offsetY), offsetY);
@@ -293,11 +291,11 @@ const Hints = Module("hints", {
if (elem instanceof HTMLAreaElement) if (elem instanceof HTMLAreaElement)
[leftPos, topPos] = this._getAreaOffset(elem, leftPos, topPos); [leftPos, topPos] = this._getAreaOffset(elem, leftPos, topPos);
span.style.left = leftPos + "px"; hint.span.style.left = leftPos + "px";
span.style.top = topPos + "px"; hint.span.style.top = topPos + "px";
fragment.appendChild(span); fragment.appendChild(hint.span);
this._pageHints.push([elem, text, span, null, elem.style.backgroundColor, elem.style.color, showText]); this._pageHints.push(hint);
} }
let body = doc.body || util.evaluateXPath(["body"], doc).snapshotItem(0); let body = doc.body || util.evaluateXPath(["body"], doc).snapshotItem(0);
@@ -348,8 +346,6 @@ const Hints = Module("hints", {
* Display the hints in pageHints that are still valid. * Display the hints in pageHints that are still valid.
*/ */
_showHints: function () { _showHints: function () {
let elem, text, rect, span, imgSpan, _a, _b, showText;
let hintnum = 1; let hintnum = 1;
let validHint = this._hintMatcher(this._hintString.toLowerCase()); let validHint = this._hintMatcher(this._hintString.toLowerCase());
let activeHint = this._hintNumber || 1; let activeHint = this._hintNumber || 1;
@@ -361,41 +357,39 @@ const Hints = Module("hints", {
inner: inner:
for (let i in (util.interruptibleRange(start, end + 1, 500))) { for (let i in (util.interruptibleRange(start, end + 1, 500))) {
let hint = this._pageHints[i]; let hint = this._pageHints[i];
[elem, text, span, imgSpan, _a, _b, showText] = hint;
let valid = validHint(text); let valid = validHint(hint.text);
span.style.display = (valid ? "" : "none"); hint.span.style.display = (valid ? "" : "none");
if (imgSpan) if (hint.imgSpan)
imgSpan.style.display = (valid ? "" : "none"); hint.imgSpan.style.display = (valid ? "" : "none");
if (!valid) { if (!valid) {
elem.removeAttributeNS(NS.uri, "highlight"); hint.elem.removeAttributeNS(NS.uri, "highlight");
continue inner; continue inner;
} }
if (text == "" && elem.firstChild && elem.firstChild instanceof HTMLImageElement) { if (hint.text == "" && hint.elem.firstChild && hint.elem.firstChild instanceof HTMLImageElement) {
if (!imgSpan) { if (!hint.imgSpan) {
rect = elem.firstChild.getBoundingClientRect(); rect = hint.elem.firstChild.getBoundingClientRect();
if (!rect) if (!rect)
continue; continue;
imgSpan = util.xmlToDom(<span highlight="Hint" liberator:class="HintImage" xmlns:liberator={NS}/>, doc); hint.imgSpan = util.xmlToDom(<span highlight="Hint" liberator:class="HintImage" xmlns:liberator={NS}/>, doc);
imgSpan.style.left = (rect.left + offsetX) + "px"; hint.imgSpan.style.left = (rect.left + offsetX) + "px";
imgSpan.style.top = (rect.top + offsetY) + "px"; hint.imgSpan.style.top = (rect.top + offsetY) + "px";
imgSpan.style.width = (rect.right - rect.left) + "px"; hint.imgSpan.style.width = (rect.right - rect.left) + "px";
imgSpan.style.height = (rect.bottom - rect.top) + "px"; hint.imgSpan.style.height = (rect.bottom - rect.top) + "px";
hint[Hints.IMG_SPAN] = imgSpan; hint.span.parentNode.appendChild(hint.imgSpan);
span.parentNode.appendChild(imgSpan);
} }
this._setClass(imgSpan, activeHint == hintnum); this._setClass(hint.imgSpan, activeHint == hintnum);
} }
span.setAttribute("number", showText ? hintnum + ": " + text.substr(0, 50) : hintnum); hint.span.setAttribute("number", hint.showText ? hintnum + ": " + hint.text.substr(0, 50) : hintnum);
if (imgSpan) if (hint.imgSpan)
imgSpan.setAttribute("number", hintnum); hint.imgSpan.setAttribute("number", hintnum);
else else
this._setClass(elem, activeHint == hintnum); this._setClass(hint.elem, activeHint == hintnum);
this._validHints.push(elem); this._validHints.push(hint.elem);
hintnum++; hintnum++;
} }
} }
@@ -431,8 +425,8 @@ const Hints = Module("hints", {
elem.parentNode.removeChild(elem); elem.parentNode.removeChild(elem);
for (let i in util.range(start, end + 1)) { for (let i in util.range(start, end + 1)) {
let hint = this._pageHints[i]; let hint = this._pageHints[i];
if (!timeout || hint[Hints.ELEM] != firstElem) if (!timeout || hint.elem != firstElem)
hint[Hints.ELEM].removeAttributeNS(NS.uri, "highlight"); hint.elem.removeAttributeNS(NS.uri, "highlight");
} }
// animate the disappearance of the first hint // animate the disappearance of the first hint
@@ -887,12 +881,6 @@ const Hints = Module("hints", {
//}}} //}}}
}, { }, {
ELEM: 0,
TEXT: 1,
SPAN: 2,
IMG_SPAN: 3,
indexOf: (function () { indexOf: (function () {
const table = [ const table = [
[0x00c0, 0x00c6, ["A"]], [0x00c0, 0x00c6, ["A"]],

View File

@@ -9,7 +9,7 @@ const JavaScript = Module("javascript", {
init: function () { init: function () {
this._stack = []; this._stack = [];
this._functions = []; this._functions = [];
this._top = []; // The element on the top of the stack. this._top = {}; // The element on the top of the stack.
this._last = ""; // The last opening char pushed onto the stack. this._last = ""; // The last opening char pushed onto the stack.
this._lastNonwhite = ""; // Last non-whitespace character we saw. this._lastNonwhite = ""; // Last non-whitespace character we saw.
this._lastChar = ""; // Last character we saw, used for \ escaping quotes. this._lastChar = ""; // Last character we saw, used for \ escaping quotes.
@@ -122,41 +122,51 @@ const JavaScript = Module("javascript", {
} }
}, },
// Get an element from the stack. If @n is negative, // Get an element from the stack. If @frame is negative,
// count from the top of the stack, otherwise, the bottom. // count from the top of the stack, otherwise, the bottom.
// If @m is provided, return the @mth value of element @o // If @nth is provided, return the @mth value of element @type
// of the stack entry at @n. // of the stack entry at @frame.
_get: function (n, m, o) { _get: function (frame, nth, type) {
let a = this._stack[n >= 0 ? n : this._stack.length + n]; let a = this._stack[frame >= 0 ? frame : this._stack.length + frame];
if (o != null) if (type != null)
a = a[o]; a = a[type];
if (m == null) if (nth == null)
return a; return a;
return a[a.length - m - 1]; return a[a.length - nth - 1];
}, },
// Push and pop the stack, maintaining references to 'top' and 'last'. // Push and pop the stack, maintaining references to 'top' and 'last'.
_push: function push(arg) { _push: function push(arg) {
this._top = [this._i, arg, [this._i], [], [], [], []]; this._top = {
this._last = this._top[JavaScript.CHAR]; offset: this._i,
char: arg,
statements: [this._i],
dots: [],
fullStatements: [],
comma: [],
functions: []
};
this._last = this._top.char;
this._stack.push(this._top); this._stack.push(this._top);
}, },
_pop: function pop(arg) { _pop: function pop(arg) {
if (this._top[JavaScript.CHAR] != arg) { if (this._top.char != arg) {
this.context.highlight(this._top[JavaScript.OFFSET], this._i - this._top[JavaScript.OFFSET], "SPELLCHECK"); this.context.highlight(this._top.offset, this._i - this._top.offset, "SPELLCHECK");
this.context.highlight(this._top[JavaScript.OFFSET], 1, "FIND"); this.context.highlight(this._top.offset, 1, "FIND");
throw new Error("Invalid JS"); throw new Error("Invalid JS");
} }
if (this._i == this.context.caret - 1) if (this._i == this.context.caret - 1)
this.context.highlight(this._top[JavaScript.OFFSET], 1, "FIND"); this.context.highlight(this._top.offset, 1, "FIND");
// The closing character of this stack frame will have pushed a new // The closing character of this stack frame will have pushed a new
// statement, leaving us with an empty statement. This doesn't matter, // statement, leaving us with an empty statement. This doesn't matter,
// now, as we simply throw away the frame when we pop it, but it may later. // now, as we simply throw away the frame when we pop it, but it may later.
if (this._top[JavaScript.STATEMENTS][this._top[JavaScript.STATEMENTS].length - 1] == this._i) if (this._top.statements[this._top.statements.length - 1] == this._i)
this._top[JavaScript.STATEMENTS].pop(); this._top.statements.pop();
this._top = this._get(-2); this._top = this._get(-2);
this._last = this._top[JavaScript.CHAR]; this._last = this._top.char;
let ret = this._stack.pop(); let ret = this._stack.pop();
return ret; return ret;
}, },
@@ -172,7 +182,7 @@ const JavaScript = Module("javascript", {
if (this._str && filter.substr(0, this._str.length) == this._str) { if (this._str && filter.substr(0, this._str.length) == this._str) {
this._i = this._str.length; this._i = this._str.length;
if (this.popStatement) if (this.popStatement)
this._top[JavaScript.STATEMENTS].pop(); this._top.statements.pop();
} }
else { else {
this._stack = []; this._stack = [];
@@ -200,21 +210,21 @@ const JavaScript = Module("javascript", {
// A word character following a non-word character, or simply a non-word // A word character following a non-word character, or simply a non-word
// character. Start a new statement. // character. Start a new statement.
if (/[a-zA-Z_$]/.test(this._c) && !/[\w$]/.test(this._lastChar) || !/[\w\s$]/.test(this._c)) if (/[a-zA-Z_$]/.test(this._c) && !/[\w$]/.test(this._lastChar) || !/[\w\s$]/.test(this._c))
this._top[JavaScript.STATEMENTS].push(this._i); this._top.statements.push(this._i);
// A "." or a "[" dereferences the last "statement" and effectively // A "." or a "[" dereferences the last "statement" and effectively
// joins it to this logical statement. // joins it to this logical statement.
if ((this._c == "." || this._c == "[") && /[\w$\])"']/.test(this._lastNonwhite) if ((this._c == "." || this._c == "[") && /[\w$\])"']/.test(this._lastNonwhite)
|| this._lastNonwhite == "." && /[a-zA-Z_$]/.test(this._c)) || this._lastNonwhite == "." && /[a-zA-Z_$]/.test(this._c))
this._top[JavaScript.STATEMENTS].pop(); this._top.statements.pop();
switch (this._c) { switch (this._c) {
case "(": case "(":
// Function call, or if/while/for/... // Function call, or if/while/for/...
if (/[\w$]/.test(this._lastNonwhite)) { if (/[\w$]/.test(this._lastNonwhite)) {
this._functions.push(this._i); this._functions.push(this._i);
this._top[JavaScript.FUNCTIONS].push(this._i); this._top.functions.push(this._i);
this._top[JavaScript.STATEMENTS].pop(); this._top.statements.pop();
} }
case '"': case '"':
case "'": case "'":
@@ -226,16 +236,16 @@ const JavaScript = Module("javascript", {
this._push(this._c); this._push(this._c);
break; break;
case ".": case ".":
this._top[JavaScript.DOTS].push(this._i); this._top.dots.push(this._i);
break; break;
case ")": this._pop("("); break; case ")": this._pop("("); break;
case "]": this._pop("["); break; case "]": this._pop("["); break;
case "}": this._pop("{"); // Fallthrough case "}": this._pop("{"); // Fallthrough
case ";": case ";":
this._top[JavaScript.FULL_STATEMENTS].push(this._i); this._top.fullStatements.push(this._i);
break; break;
case ",": case ",":
this._top[JavaScript.COMMA].push(this._i); this._top.comma.push(this._i);
break; break;
} }
@@ -247,7 +257,7 @@ const JavaScript = Module("javascript", {
this.popStatement = false; this.popStatement = false;
if (!/[\w$]/.test(this._lastChar) && this._lastNonwhite != ".") { if (!/[\w$]/.test(this._lastChar) && this._lastNonwhite != ".") {
this.popStatement = true; this.popStatement = true;
this._top[JavaScript.STATEMENTS].push(this._i); this._top.statements.push(this._i);
} }
this._lastIdx = this._i; this._lastIdx = this._i;
@@ -270,11 +280,11 @@ const JavaScript = Module("javascript", {
// of inputting a command (let foo=bar; frob(foo); foo=foo.bar; ...), // of inputting a command (let foo=bar; frob(foo); foo=foo.bar; ...),
// we'll still use the old value. But, it's worth it. // we'll still use the old value. But, it's worth it.
_getObj: function (frame, stop) { _getObj: function (frame, stop) {
let statement = this._get(frame, 0, JavaScript.STATEMENTS) || 0; // Current statement. let statement = this._get(frame, 0, "statements") || 0; // Current statement.
let prev = statement; let prev = statement;
let obj; let obj;
let cacheKey; let cacheKey;
for (let [, dot] in Iterator(this._get(frame)[JavaScript.DOTS].concat(stop))) { for (let [, dot] in Iterator(this._get(frame).dots.concat(stop))) {
if (dot < statement) if (dot < statement)
continue; continue;
if (dot > stop || dot <= prev) if (dot > stop || dot <= prev)
@@ -295,9 +305,9 @@ const JavaScript = Module("javascript", {
}, },
_getObjKey: function (frame) { _getObjKey: function (frame) {
let dot = this._get(frame, 0, JavaScript.DOTS) || -1; // Last dot in frame. let dot = this._get(frame, 0, "dots") || -1; // Last dot in frame.
let statement = this._get(frame, 0, JavaScript.STATEMENTS) || 0; // Current statement. let statement = this._get(frame, 0, "statements") || 0; // Current statement.
let end = (frame == -1 ? this._lastIdx : this._get(frame + 1)[JavaScript.OFFSET]); let end = (frame == -1 ? this._lastIdx : this._get(frame + 1).offset);
this._cacheKey = null; this._cacheKey = null;
let obj = [[this.cache.evalContext, "Local Variables"], let obj = [[this.cache.evalContext, "Local Variables"],
@@ -356,7 +366,7 @@ const JavaScript = Module("javascript", {
// TODO: Make this a generic completion helper function. // TODO: Make this a generic completion helper function.
let filter = key + (string || ""); let filter = key + (string || "");
for (let [, obj] in Iterator(objects)) { for (let [, obj] in Iterator(objects)) {
this.context.fork(obj[1], this._top[JavaScript.OFFSET], this, this._fill, this.context.fork(obj[1], this._top.offset, this, this._fill,
obj[0], obj[1], compl, obj[0], obj[1], compl,
true, filter, last, key.length); true, filter, last, key.length);
} }
@@ -366,21 +376,21 @@ const JavaScript = Module("javascript", {
for (let [, obj] in Iterator(objects)) { for (let [, obj] in Iterator(objects)) {
let name = obj[1] + " (prototypes)"; let name = obj[1] + " (prototypes)";
this.context.fork(name, this._top[JavaScript.OFFSET], this, this._fill, this.context.fork(name, this._top.offset, this, this._fill,
obj[0], name, function (a, b) compl(a, b, true), obj[0], name, function (a, b) compl(a, b, true),
true, filter, last, key.length); true, filter, last, key.length);
} }
for (let [, obj] in Iterator(objects)) { for (let [, obj] in Iterator(objects)) {
let name = obj[1] + " (substrings)"; let name = obj[1] + " (substrings)";
this.context.fork(name, this._top[JavaScript.OFFSET], this, this._fill, this.context.fork(name, this._top.offset, this, this._fill,
obj[0], name, compl, obj[0], name, compl,
false, filter, last, key.length); false, filter, last, key.length);
} }
for (let [, obj] in Iterator(objects)) { for (let [, obj] in Iterator(objects)) {
let name = obj[1] + " (prototype substrings)"; let name = obj[1] + " (prototype substrings)";
this.context.fork(name, this._top[JavaScript.OFFSET], this, this._fill, this.context.fork(name, this._top.offset, this, this._fill,
obj[0], name, function (a, b) compl(a, b, true), obj[0], name, function (a, b) compl(a, b, true),
false, filter, last, key.length); false, filter, last, key.length);
} }
@@ -390,7 +400,7 @@ const JavaScript = Module("javascript", {
if (this._last == "") if (this._last == "")
return ""; return "";
// After the opening [ upto the opening ", plus '' to take care of any operators before it // After the opening [ upto the opening ", plus '' to take care of any operators before it
let key = this._str.substring(this._get(-2, 0, JavaScript.STATEMENTS), this._get(-1, null, JavaScript.OFFSET)) + "''"; let key = this._str.substring(this._get(-2, 0, "statements"), this._get(-1, null, "offset")) + "''";
// Now eval the key, to process any referenced variables. // Now eval the key, to process any referenced variables.
return this.eval(key); return this.eval(key);
}, },
@@ -419,7 +429,7 @@ const JavaScript = Module("javascript", {
// Find any complete statements that we can eval before we eval our object. // Find any complete statements that we can eval before we eval our object.
// This allows for things like: let doc = window.content.document; let elem = doc.createElement...; elem.<Tab> // This allows for things like: let doc = window.content.document; let elem = doc.createElement...; elem.<Tab>
let prev = 0; let prev = 0;
for (let [, v] in Iterator(this._get(0)[JavaScript.FULL_STATEMENTS])) { for (let [, v] in Iterator(this._get(0).fullStatements)) {
let key = this._str.substring(prev, v + 1); let key = this._str.substring(prev, v + 1);
if (this._checkFunction(prev, v, key)) if (this._checkFunction(prev, v, key))
return null; return null;
@@ -438,11 +448,11 @@ const JavaScript = Module("javascript", {
// The top of the stack is the sting we're completing. // The top of the stack is the sting we're completing.
// Wrap it in its delimiters and eval it to process escape sequences. // Wrap it in its delimiters and eval it to process escape sequences.
let string = this._str.substring(this._get(-1)[JavaScript.OFFSET] + 1, this._lastIdx); let string = this._str.substring(this._get(-1).offset + 1, this._lastIdx);
string = eval(this._last + string + this._last); string = eval(this._last + string + this._last);
// Is this an object accessor? // Is this an object accessor?
if (this._get(-2)[JavaScript.CHAR] == "[") { // Are we inside of []? if (this._get(-2).char == "[") { // Are we inside of []?
// Stack: // Stack:
// [-1]: "... // [-1]: "...
// [-2]: [... // [-2]: [...
@@ -450,24 +460,24 @@ const JavaScript = Module("javascript", {
// Yes. If the [ starts at the beginning of a logical // Yes. If the [ starts at the beginning of a logical
// statement, we're in an array literal, and we're done. // statement, we're in an array literal, and we're done.
if (this._get(-3, 0, JavaScript.STATEMENTS) == this._get(-2)[JavaScript.OFFSET]) if (this._get(-3, 0, "statements") == this._get(-2).offset)
return null; return null;
// Beginning of the statement upto the opening [ // Beginning of the statement upto the opening [
let obj = this._getObj(-3, this._get(-2)[JavaScript.OFFSET]); let obj = this._getObj(-3, this._get(-2).offset);
return this._complete(obj, this._getKey(), null, string, this._last); return this._complete(obj, this._getKey(), null, string, this._last);
} }
// Is this a function call? // Is this a function call?
if (this._get(-2)[JavaScript.CHAR] == "(") { if (this._get(-2).char == "(") {
// Stack: // Stack:
// [-1]: "... // [-1]: "...
// [-2]: (... // [-2]: (...
// [-3]: base statement // [-3]: base statement
// Does the opening "(" mark a function call? // Does the opening "(" mark a function call?
if (this._get(-3, 0, JavaScript.FUNCTIONS) != this._get(-2)[JavaScript.OFFSET]) if (this._get(-3, 0, "functions") != this._get(-2).offset)
return null; // No. We're done. return null; // No. We're done.
let [offset, obj, func] = this._getObjKey(-3); let [offset, obj, func] = this._getObjKey(-3);
@@ -485,9 +495,9 @@ const JavaScript = Module("javascript", {
return null; return null;
// Split up the arguments // Split up the arguments
let prev = this._get(-2)[JavaScript.OFFSET]; let prev = this._get(-2).offset;
let args = []; let args = [];
for (let [, idx] in Iterator(this._get(-2)[JavaScript.COMMA])) { for (let [, idx] in Iterator(this._get(-2).comma)) {
let arg = this._str.substring(prev + 1, idx); let arg = this._str.substring(prev + 1, idx);
prev = idx; prev = idx;
util.memoize(args, this._i, function () self.eval(arg)); util.memoize(args, this._i, function () self.eval(arg));
@@ -533,27 +543,18 @@ const JavaScript = Module("javascript", {
return null; // Not a word. Forget it. Can this even happen? return null; // Not a word. Forget it. Can this even happen?
try { // FIXME try { // FIXME
var o = this._top[JavaScript.OFFSET]; var o = this._top.offset;
this._top[JavaScript.OFFSET] = offset; this._top.offset = offset;
return this._complete(obj, key); return this._complete(obj, key);
} }
finally { finally {
this._top[JavaScript.OFFSET] = o; this._top.offset = o;
} }
return null; return null;
} }
}, { }, {
EVAL_TMP: "__liberator_eval_tmp", EVAL_TMP: "__liberator_eval_tmp",
// Internal use only
OFFSET: 0,
CHAR: 1,
STATEMENTS: 2,
DOTS: 3,
FULL_STATEMENTS: 4,
COMMA: 5,
FUNCTIONS: 6,
/** /**
* A map of argument completion functions for named methods. The * A map of argument completion functions for named methods. The
* signature and specification of the completion function * signature and specification of the completion function