зеркало из https://github.com/mozilla/pjs.git
Merge tracemonkey.
This commit is contained in:
Коммит
b925418444
|
@ -68,6 +68,7 @@ function my_load(filename) {
|
|||
}
|
||||
|
||||
my_load('jsdefs.js');
|
||||
my_load('jslex.js');
|
||||
my_load('jsparse.js');
|
||||
my_load('jsexec.js');
|
||||
|
||||
|
|
|
@ -42,8 +42,6 @@
|
|||
* separately to take advantage of the simple switch-case constant propagation
|
||||
* done by SpiderMonkey.
|
||||
*/
|
||||
const GLOBAL = this;
|
||||
|
||||
var tokens = [
|
||||
// End of source.
|
||||
"END",
|
||||
|
@ -95,9 +93,9 @@ var tokens = [
|
|||
];
|
||||
|
||||
// Operator and punctuator mapping from token to tree node type name.
|
||||
// NB: superstring tokens (e.g., ++) must come before their substring token
|
||||
// counterparts (+ in the example), so that the opRegExp regular expression
|
||||
// synthesized from this list makes the longest possible match.
|
||||
// NB: because the lexer doesn't backtrack, all token prefixes must themselves
|
||||
// be valid tokens (e.g. !== is acceptable because its prefixes are the valid
|
||||
// tokens != and !).
|
||||
var opTypeNames = {
|
||||
'\n': "NEWLINE",
|
||||
';': "SEMICOLON",
|
||||
|
@ -144,18 +142,21 @@ var opTypeNames = {
|
|||
var keywords = {__proto__: null};
|
||||
|
||||
// Define const END, etc., based on the token names. Also map name to index.
|
||||
var tokenIds = {};
|
||||
var consts = "const ";
|
||||
for (var i = 0, j = tokens.length; i < j; i++) {
|
||||
if (i > 0)
|
||||
consts += ", ";
|
||||
var t = tokens[i];
|
||||
var name;
|
||||
if (/^[a-z]/.test(t)) {
|
||||
consts += t.toUpperCase();
|
||||
name = t.toUpperCase();
|
||||
keywords[t] = i;
|
||||
} else {
|
||||
consts += (/^\W/.test(t) ? opTypeNames[t] : t);
|
||||
name = (/^\W/.test(t) ? opTypeNames[t] : t);
|
||||
}
|
||||
consts += " = " + i;
|
||||
consts += name + " = " + i;
|
||||
tokenIds[name] = i;
|
||||
tokens[t] = i;
|
||||
}
|
||||
eval(consts + ";");
|
||||
|
|
|
@ -110,9 +110,9 @@ var global = {
|
|||
var s = {object: global, parent: null};
|
||||
return new FunctionObject(f, s);
|
||||
},
|
||||
Array: function Array(dummy) {
|
||||
Array: function (dummy) {
|
||||
// Array when called as a function acts as a constructor.
|
||||
return GLOBAL.Array.apply(this, arguments);
|
||||
return Array.apply(this, arguments);
|
||||
},
|
||||
String: function String(s) {
|
||||
// Called as function or constructor: convert argument to string type.
|
||||
|
|
|
@ -0,0 +1,430 @@
|
|||
/* vim: set sw=4 ts=8 et tw=78: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is the Narcissus JavaScript engine.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Brendan Eich <brendan@mozilla.org>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2004
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
* Narcissus - JS implemented in JS.
|
||||
*
|
||||
* Lexical scanner.
|
||||
*/
|
||||
|
||||
// Build up a trie of operator tokens.
|
||||
var opTokens = {};
|
||||
for (var op in opTypeNames) {
|
||||
if (op === '\n' || op === '.')
|
||||
continue;
|
||||
|
||||
var node = opTokens;
|
||||
for (var i = 0; i < op.length; i++) {
|
||||
var ch = op[i];
|
||||
if (!(ch in node))
|
||||
node[ch] = {};
|
||||
node = node[ch];
|
||||
node.op = op;
|
||||
}
|
||||
}
|
||||
|
||||
function Tokenizer(s, f, l) {
|
||||
this.cursor = 0;
|
||||
this.source = String(s);
|
||||
this.tokens = [];
|
||||
this.tokenIndex = 0;
|
||||
this.lookahead = 0;
|
||||
this.scanNewlines = false;
|
||||
this.scanOperand = true;
|
||||
this.filename = f || "";
|
||||
this.lineno = l || 1;
|
||||
}
|
||||
|
||||
Tokenizer.prototype = {
|
||||
get done() {
|
||||
return this.peek() == END;
|
||||
},
|
||||
|
||||
get token() {
|
||||
return this.tokens[this.tokenIndex];
|
||||
},
|
||||
|
||||
match: function (tt) {
|
||||
return this.get() == tt || this.unget();
|
||||
},
|
||||
|
||||
mustMatch: function (tt) {
|
||||
if (!this.match(tt))
|
||||
throw this.newSyntaxError("Missing " + tokens[tt].toLowerCase());
|
||||
return this.token;
|
||||
},
|
||||
|
||||
peek: function () {
|
||||
var tt, next;
|
||||
if (this.lookahead) {
|
||||
next = this.tokens[(this.tokenIndex + this.lookahead) & 3];
|
||||
tt = (this.scanNewlines && next.lineno != this.lineno)
|
||||
? NEWLINE
|
||||
: next.type;
|
||||
} else {
|
||||
tt = this.get();
|
||||
this.unget();
|
||||
}
|
||||
return tt;
|
||||
},
|
||||
|
||||
peekOnSameLine: function () {
|
||||
this.scanNewlines = true;
|
||||
var tt = this.peek();
|
||||
this.scanNewlines = false;
|
||||
return tt;
|
||||
},
|
||||
|
||||
// Eats comments and whitespace.
|
||||
skip: function () {
|
||||
var input = this.source;
|
||||
for (;;) {
|
||||
var ch = input[this.cursor++];
|
||||
var next = input[this.cursor];
|
||||
if (ch === '\n' && !this.scanNewlines) {
|
||||
this.lineno++;
|
||||
} else if (ch === '/' && next === '*') {
|
||||
this.cursor++;
|
||||
for (;;) {
|
||||
ch = input[this.cursor++];
|
||||
if (ch === undefined)
|
||||
throw this.newSyntaxError("Unterminated comment");
|
||||
|
||||
if (ch === '*') {
|
||||
next = input[this.cursor];
|
||||
if (next === '/') {
|
||||
this.cursor++;
|
||||
break;
|
||||
}
|
||||
} else if (ch === '\n') {
|
||||
this.lineno++;
|
||||
}
|
||||
}
|
||||
} else if (ch === '/' && next === '/') {
|
||||
this.cursor++;
|
||||
for (;;) {
|
||||
ch = input[this.cursor++];
|
||||
if (ch === undefined)
|
||||
return;
|
||||
|
||||
if (ch === '\n') {
|
||||
this.lineno++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (ch !== ' ' && ch !== '\t') {
|
||||
this.cursor--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Lexes the exponential part of a number, if present. Returns true iff an
|
||||
// exponential part was found.
|
||||
lexExponent: function() {
|
||||
var input = this.source;
|
||||
var next = input[this.cursor];
|
||||
if (next === 'e' || next === 'E') {
|
||||
this.cursor++;
|
||||
ch = input[this.cursor++];
|
||||
if (ch === '+' || ch === '-')
|
||||
ch = input[this.cursor++];
|
||||
|
||||
if (ch < '0' || ch > '9')
|
||||
throw this.newSyntaxError("Missing exponent");
|
||||
|
||||
do {
|
||||
ch = input[this.cursor++];
|
||||
} while (ch >= '0' && ch <= '9');
|
||||
this.cursor--;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
lexZeroNumber: function (ch) {
|
||||
var token = this.token, input = this.source;
|
||||
token.type = NUMBER;
|
||||
|
||||
ch = input[this.cursor++];
|
||||
if (ch === '.') {
|
||||
do {
|
||||
ch = input[this.cursor++];
|
||||
} while (ch >= '0' && ch <= '9');
|
||||
this.cursor--;
|
||||
|
||||
this.lexExponent();
|
||||
token.value = parseFloat(token.start, this.cursor);
|
||||
} else if (ch === 'x' || ch === 'X') {
|
||||
do {
|
||||
ch = input[this.cursor++];
|
||||
} while ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') ||
|
||||
(ch >= 'A' && ch <= 'F'));
|
||||
this.cursor--;
|
||||
|
||||
token.value = parseInt(input.substring(token.start, this.cursor));
|
||||
} else if (ch >= '0' && ch <= '7') {
|
||||
do {
|
||||
ch = input[this.cursor++];
|
||||
} while (ch >= '0' && ch <= '7');
|
||||
this.cursor--;
|
||||
|
||||
token.value = parseInt(input.substring(token.start, this.cursor));
|
||||
} else {
|
||||
this.cursor--;
|
||||
this.lexExponent(); // 0E1, &c.
|
||||
token.value = 0;
|
||||
}
|
||||
},
|
||||
|
||||
lexNumber: function (ch) {
|
||||
var token = this.token, input = this.source;
|
||||
token.type = NUMBER;
|
||||
|
||||
var floating = false;
|
||||
do {
|
||||
ch = input[this.cursor++];
|
||||
if (ch === '.' && !floating) {
|
||||
floating = true;
|
||||
ch = input[this.cursor++];
|
||||
}
|
||||
} while (ch >= '0' && ch <= '9');
|
||||
|
||||
this.cursor--;
|
||||
|
||||
var exponent = this.lexExponent();
|
||||
floating = floating || exponent;
|
||||
|
||||
var str = input.substring(token.start, this.cursor);
|
||||
token.value = floating ? parseFloat(str) : parseInt(str);
|
||||
},
|
||||
|
||||
lexDot: function (ch) {
|
||||
var token = this.token, input = this.source;
|
||||
var next = input[this.cursor];
|
||||
if (next >= '0' && next <= '9') {
|
||||
do {
|
||||
ch = input[this.cursor++];
|
||||
} while (ch >= '0' && ch <= '9');
|
||||
this.cursor--;
|
||||
|
||||
this.lexExponent();
|
||||
|
||||
token.type = NUMBER;
|
||||
token.value = parseFloat(token.start, this.cursor);
|
||||
} else {
|
||||
token.type = DOT;
|
||||
token.assignOp = null;
|
||||
token.value = '.';
|
||||
}
|
||||
},
|
||||
|
||||
lexString: function (ch) {
|
||||
var token = this.token, input = this.source;
|
||||
token.type = STRING;
|
||||
|
||||
var hasEscapes = false;
|
||||
var delim = ch;
|
||||
ch = input[this.cursor++];
|
||||
while (ch !== delim) {
|
||||
if (ch === '\\') {
|
||||
hasEscapes = true;
|
||||
this.cursor++;
|
||||
}
|
||||
ch = input[this.cursor++];
|
||||
}
|
||||
|
||||
token.value = (hasEscapes)
|
||||
? eval(input.substring(token.start, this.cursor))
|
||||
: input.substring(token.start + 1, this.cursor - 1);
|
||||
},
|
||||
|
||||
lexRegExp: function (ch) {
|
||||
var token = this.token, input = this.source;
|
||||
token.type = REGEXP;
|
||||
|
||||
do {
|
||||
ch = input[this.cursor++];
|
||||
if (ch === '\\') {
|
||||
this.cursor++;
|
||||
} else if (ch === '[') {
|
||||
do {
|
||||
if (ch === undefined)
|
||||
throw this.newSyntaxError("Unterminated character class");
|
||||
|
||||
if (ch === '\\')
|
||||
this.cursor++;
|
||||
|
||||
ch = input[this.cursor++];
|
||||
} while (ch !== ']');
|
||||
} else if (ch === undefined) {
|
||||
throw this.newSyntaxError("Unterminated regex");
|
||||
}
|
||||
} while (ch !== '/');
|
||||
|
||||
do {
|
||||
ch = input[this.cursor++];
|
||||
} while (ch >= 'a' && ch <= 'z');
|
||||
|
||||
this.cursor--;
|
||||
|
||||
token.value = eval(input.substring(token.start, this.cursor));
|
||||
},
|
||||
|
||||
lexOp: function (ch) {
|
||||
var token = this.token, input = this.source;
|
||||
|
||||
// A bit ugly, but it seems wasteful to write a trie lookup routine for
|
||||
// only 3 characters...
|
||||
var node = opTokens[ch];
|
||||
var next = input[this.cursor];
|
||||
if (next in node) {
|
||||
node = node[next];
|
||||
this.cursor++;
|
||||
next = input[this.cursor];
|
||||
if (next in node) {
|
||||
node = node[next];
|
||||
this.cursor++;
|
||||
next = input[this.cursor];
|
||||
}
|
||||
}
|
||||
|
||||
var op = node.op;
|
||||
if (assignOps[op] && input[this.cursor] === '=') {
|
||||
this.cursor++;
|
||||
token.type = ASSIGN;
|
||||
token.assignOp = tokenIds[opTypeNames[op]];
|
||||
op += '=';
|
||||
} else {
|
||||
token.type = tokenIds[opTypeNames[op]];
|
||||
if (this.scanOperand) {
|
||||
switch (token.type) {
|
||||
case PLUS: token.type = UNARY_PLUS; break;
|
||||
case MINUS: token.type = UNARY_MINUS; break;
|
||||
}
|
||||
}
|
||||
|
||||
token.assignOp = null;
|
||||
}
|
||||
|
||||
token.value = op;
|
||||
},
|
||||
|
||||
// FIXME: Unicode escape sequences
|
||||
// FIXME: Unicode identifiers
|
||||
lexIdent: function (ch) {
|
||||
var token = this.token, input = this.source;
|
||||
|
||||
do {
|
||||
ch = input[this.cursor++];
|
||||
} while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
|
||||
(ch >= '0' && ch <= '9') || ch === '$' || ch === '_');
|
||||
|
||||
this.cursor--; // Put the non-word character back.
|
||||
|
||||
var id = input.substring(token.start, this.cursor);
|
||||
token.type = keywords[id] || IDENTIFIER;
|
||||
token.value = id;
|
||||
},
|
||||
|
||||
get: function () {
|
||||
var token;
|
||||
while (this.lookahead) {
|
||||
--this.lookahead;
|
||||
this.tokenIndex = (this.tokenIndex + 1) & 3;
|
||||
token = this.tokens[this.tokenIndex];
|
||||
if (token.type != NEWLINE || this.scanNewlines)
|
||||
return token.type;
|
||||
}
|
||||
|
||||
this.skip();
|
||||
|
||||
this.tokenIndex = (this.tokenIndex + 1) & 3;
|
||||
token = this.tokens[this.tokenIndex];
|
||||
if (!token)
|
||||
this.tokens[this.tokenIndex] = token = {};
|
||||
|
||||
var input = this.source;
|
||||
if (this.cursor === input.length)
|
||||
return token.type = END;
|
||||
|
||||
token.start = this.cursor;
|
||||
token.lineno = this.lineno;
|
||||
|
||||
var ch = input[this.cursor++];
|
||||
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
|
||||
ch === '$' || ch === '_') {
|
||||
this.lexIdent(ch);
|
||||
} else if (this.scanOperand && ch === '/') {
|
||||
this.lexRegExp(ch);
|
||||
} else if (ch in opTokens) {
|
||||
this.lexOp(ch);
|
||||
} else if (ch === '.') {
|
||||
this.lexDot(ch);
|
||||
} else if (ch >= '1' && ch <= '9') {
|
||||
this.lexNumber(ch);
|
||||
} else if (ch === '0') {
|
||||
this.lexZeroNumber(ch);
|
||||
} else if (ch === '"' || ch === "'") {
|
||||
this.lexString(ch);
|
||||
} else if (this.scanNewlines && ch === '\n') {
|
||||
token.type = NEWLINE;
|
||||
token.value = '\n';
|
||||
this.lineno++;
|
||||
} else {
|
||||
throw this.newSyntaxError("Illegal token");
|
||||
}
|
||||
|
||||
token.end = this.cursor;
|
||||
return token.type;
|
||||
},
|
||||
|
||||
unget: function () {
|
||||
if (++this.lookahead == 4) throw "PANIC: too much lookahead!";
|
||||
this.tokenIndex = (this.tokenIndex - 1) & 3;
|
||||
},
|
||||
|
||||
newSyntaxError: function (m) {
|
||||
var e = new SyntaxError(m, this.filename, this.lineno);
|
||||
e.source = this.source;
|
||||
e.cursor = this.cursor;
|
||||
return e;
|
||||
}
|
||||
};
|
||||
|
|
@ -38,179 +38,9 @@
|
|||
/*
|
||||
* Narcissus - JS implemented in JS.
|
||||
*
|
||||
* Lexical scanner and parser.
|
||||
* Parser.
|
||||
*/
|
||||
|
||||
// Build a regexp that recognizes operators and punctuators (except newline).
|
||||
var opRegExpSrc = "^";
|
||||
for (i in opTypeNames) {
|
||||
if (i == '\n')
|
||||
continue;
|
||||
if (opRegExpSrc != "^")
|
||||
opRegExpSrc += "|^";
|
||||
opRegExpSrc += i.replace(/[?|^&(){}\[\]+\-*\/\.]/g, "\\$&");
|
||||
}
|
||||
var opRegExp = new RegExp(opRegExpSrc);
|
||||
|
||||
// A regexp to match floating point literals (but not integer literals).
|
||||
var fpRegExp = /^\d+\.\d*(?:[eE][-+]?\d+)?|^\d+(?:\.\d*)?[eE][-+]?\d+|^\.\d+(?:[eE][-+]?\d+)?/;
|
||||
|
||||
// A regexp to match regexp literals.
|
||||
var reRegExp = /^\/((?:\\.|\[(?:\\.|[^\]])*\]|[^\/])+)\/([gimy]*)/;
|
||||
|
||||
function Tokenizer(s, f, l) {
|
||||
this.cursor = 0;
|
||||
this.source = String(s);
|
||||
this.tokens = [];
|
||||
this.tokenIndex = 0;
|
||||
this.lookahead = 0;
|
||||
this.scanNewlines = false;
|
||||
this.scanOperand = true;
|
||||
this.filename = f || "";
|
||||
this.lineno = l || 1;
|
||||
}
|
||||
|
||||
Tokenizer.prototype = {
|
||||
get input() {
|
||||
return this.source.substring(this.cursor);
|
||||
},
|
||||
|
||||
get done() {
|
||||
return this.peek() == END;
|
||||
},
|
||||
|
||||
get token() {
|
||||
return this.tokens[this.tokenIndex];
|
||||
},
|
||||
|
||||
match: function (tt) {
|
||||
return this.get() == tt || this.unget();
|
||||
},
|
||||
|
||||
mustMatch: function (tt) {
|
||||
if (!this.match(tt))
|
||||
throw this.newSyntaxError("Missing " + tokens[tt].toLowerCase());
|
||||
return this.token;
|
||||
},
|
||||
|
||||
peek: function () {
|
||||
var tt, next;
|
||||
if (this.lookahead) {
|
||||
next = this.tokens[(this.tokenIndex + this.lookahead) & 3];
|
||||
if (this.scanNewlines && next.lineno != this.lineno)
|
||||
tt = NEWLINE;
|
||||
else
|
||||
tt = next.type;
|
||||
} else {
|
||||
tt = this.get();
|
||||
this.unget();
|
||||
}
|
||||
return tt;
|
||||
},
|
||||
|
||||
peekOnSameLine: function () {
|
||||
this.scanNewlines = true;
|
||||
var tt = this.peek();
|
||||
this.scanNewlines = false;
|
||||
return tt;
|
||||
},
|
||||
|
||||
get: function () {
|
||||
var token;
|
||||
while (this.lookahead) {
|
||||
--this.lookahead;
|
||||
this.tokenIndex = (this.tokenIndex + 1) & 3;
|
||||
token = this.tokens[this.tokenIndex];
|
||||
if (token.type != NEWLINE || this.scanNewlines)
|
||||
return token.type;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
var input = this.input;
|
||||
var match = (this.scanNewlines ? /^[ \t]+/ : /^\s+/)(input);
|
||||
if (match) {
|
||||
var spaces = match[0];
|
||||
this.cursor += spaces.length;
|
||||
var newlines = spaces.match(/\n/g);
|
||||
if (newlines)
|
||||
this.lineno += newlines.length;
|
||||
input = this.input;
|
||||
}
|
||||
|
||||
if (!(match = /^\/(?:\*(?:.|\n)*?\*\/|\/.*)/(input)))
|
||||
break;
|
||||
var comment = match[0];
|
||||
this.cursor += comment.length;
|
||||
newlines = comment.match(/\n/g);
|
||||
if (newlines)
|
||||
this.lineno += newlines.length
|
||||
}
|
||||
|
||||
this.tokenIndex = (this.tokenIndex + 1) & 3;
|
||||
token = this.tokens[this.tokenIndex];
|
||||
if (!token)
|
||||
this.tokens[this.tokenIndex] = token = {};
|
||||
|
||||
if (!input)
|
||||
return token.type = END;
|
||||
|
||||
if ((match = fpRegExp(input))) {
|
||||
token.type = NUMBER;
|
||||
token.value = parseFloat(match[0]);
|
||||
} else if ((match = /^0[xX][\da-fA-F]+|^0[0-7]*|^\d+/(input))) {
|
||||
token.type = NUMBER;
|
||||
token.value = parseInt(match[0]);
|
||||
} else if ((match = /^[$_\w]+/(input))) { // FIXME no ES3 unicode
|
||||
var id = match[0];
|
||||
token.type = keywords[id] || IDENTIFIER;
|
||||
token.value = id;
|
||||
} else if ((match = /^"(?:\\.|[^"])*"|^'(?:\\.|[^'])*'/(input))) { //"){
|
||||
token.type = STRING;
|
||||
token.value = eval(match[0]);
|
||||
} else if (this.scanOperand && (match = reRegExp(input))) {
|
||||
token.type = REGEXP;
|
||||
token.value = new RegExp(match[1], match[2]);
|
||||
} else if ((match = opRegExp(input))) {
|
||||
var op = match[0];
|
||||
if (assignOps[op] && input[op.length] == '=') {
|
||||
token.type = ASSIGN;
|
||||
token.assignOp = GLOBAL[opTypeNames[op]];
|
||||
match[0] += '=';
|
||||
} else {
|
||||
token.type = GLOBAL[opTypeNames[op]];
|
||||
if (this.scanOperand &&
|
||||
(token.type == PLUS || token.type == MINUS)) {
|
||||
token.type += UNARY_PLUS - PLUS;
|
||||
}
|
||||
token.assignOp = null;
|
||||
}
|
||||
token.value = op;
|
||||
} else if (this.scanNewlines && (match = /^\n/(input))) {
|
||||
token.type = NEWLINE;
|
||||
} else {
|
||||
throw this.newSyntaxError("Illegal token");
|
||||
}
|
||||
|
||||
token.start = this.cursor;
|
||||
this.cursor += match[0].length;
|
||||
token.end = this.cursor;
|
||||
token.lineno = this.lineno;
|
||||
return token.type;
|
||||
},
|
||||
|
||||
unget: function () {
|
||||
if (++this.lookahead == 4) throw "PANIC: too much lookahead!";
|
||||
this.tokenIndex = (this.tokenIndex - 1) & 3;
|
||||
},
|
||||
|
||||
newSyntaxError: function (m) {
|
||||
var e = new SyntaxError(m, this.filename, this.lineno);
|
||||
e.source = this.source;
|
||||
e.cursor = this.cursor;
|
||||
return e;
|
||||
}
|
||||
};
|
||||
|
||||
function CompilerContext(inFunction) {
|
||||
this.inFunction = inFunction;
|
||||
this.stmtStack = [];
|
||||
|
@ -690,7 +520,7 @@ var opPrecedence = {
|
|||
|
||||
// Map operator type code to precedence.
|
||||
for (i in opPrecedence)
|
||||
opPrecedence[GLOBAL[i]] = opPrecedence[i];
|
||||
opPrecedence[tokenIds[i]] = opPrecedence[i];
|
||||
|
||||
var opArity = {
|
||||
COMMA: -2,
|
||||
|
@ -715,7 +545,7 @@ var opArity = {
|
|||
|
||||
// Map operator type code to arity.
|
||||
for (i in opArity)
|
||||
opArity[GLOBAL[i]] = opArity[i];
|
||||
opArity[tokenIds[i]] = opArity[i];
|
||||
|
||||
function Expression(t, x, stop) {
|
||||
var n, id, tt, operators = [], operands = [];
|
||||
|
|
|
@ -2248,6 +2248,11 @@ class AutoValueRooter : private AutoGCRooter
|
|||
JS_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
}
|
||||
|
||||
void set(jsval v) {
|
||||
JS_ASSERT(tag == JSVAL);
|
||||
val = v;
|
||||
}
|
||||
|
||||
void setObject(JSObject *obj) {
|
||||
JS_ASSERT(tag == JSVAL);
|
||||
val = OBJECT_TO_JSVAL(obj);
|
||||
|
|
|
@ -159,7 +159,7 @@ class HashTable : AllocPolicy
|
|||
return cur == end;
|
||||
}
|
||||
|
||||
const T &front() const {
|
||||
T &front() const {
|
||||
JS_ASSERT(!empty());
|
||||
return cur->t;
|
||||
}
|
||||
|
|
|
@ -248,8 +248,6 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap)
|
|||
jsid id;
|
||||
JSObject *obj2;
|
||||
JSProperty *prop;
|
||||
uintN attrs;
|
||||
jsval val;
|
||||
|
||||
JS_CHECK_RECURSION(cx, return NULL);
|
||||
|
||||
|
@ -279,32 +277,37 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap)
|
|||
break;
|
||||
if (!prop)
|
||||
continue;
|
||||
ok = obj2->getAttributes(cx, id, prop, &attrs);
|
||||
if (ok) {
|
||||
if (obj2->isNative() &&
|
||||
(attrs & (JSPROP_GETTER | JSPROP_SETTER))) {
|
||||
bool hasGetter, hasSetter;
|
||||
AutoValueRooter v(cx, JSVAL_VOID);
|
||||
AutoValueRooter setter(cx, JSVAL_VOID);
|
||||
if (obj->isNative()) {
|
||||
JSScopeProperty *sprop = (JSScopeProperty *) prop;
|
||||
val = JSVAL_VOID;
|
||||
if (attrs & JSPROP_GETTER)
|
||||
val = sprop->getterValue();
|
||||
if (attrs & JSPROP_SETTER) {
|
||||
if (val != JSVAL_VOID) {
|
||||
/* Mark the getter, then set val to setter. */
|
||||
ok = (MarkSharpObjects(cx, JSVAL_TO_OBJECT(val),
|
||||
NULL)
|
||||
!= NULL);
|
||||
}
|
||||
val = sprop->setterValue();
|
||||
}
|
||||
hasGetter = sprop->hasGetterValue();
|
||||
hasSetter = sprop->hasSetterValue();
|
||||
if (hasGetter)
|
||||
v.set(sprop->getterValue());
|
||||
if (hasSetter)
|
||||
setter.set(sprop->setterValue());
|
||||
JS_UNLOCK_OBJ(cx, obj2);
|
||||
} else {
|
||||
ok = obj->getProperty(cx, id, &val);
|
||||
obj->dropProperty(cx, prop);
|
||||
hasGetter = hasSetter = false;
|
||||
}
|
||||
}
|
||||
obj2->dropProperty(cx, prop);
|
||||
if (hasSetter) {
|
||||
/* Mark the getter, then set val to setter. */
|
||||
if (hasGetter && !JSVAL_IS_PRIMITIVE(v.value())) {
|
||||
ok = !!MarkSharpObjects(cx, JSVAL_TO_OBJECT(v.value()), NULL);
|
||||
if (!ok)
|
||||
break;
|
||||
if (!JSVAL_IS_PRIMITIVE(val) &&
|
||||
!MarkSharpObjects(cx, JSVAL_TO_OBJECT(val), NULL)) {
|
||||
}
|
||||
v.set(setter.value());
|
||||
} else if (!hasGetter) {
|
||||
ok = obj->getProperty(cx, id, v.addr());
|
||||
if (!ok)
|
||||
break;
|
||||
}
|
||||
if (!JSVAL_IS_PRIMITIVE(v.value()) &&
|
||||
!MarkSharpObjects(cx, JSVAL_TO_OBJECT(v.value()), NULL)) {
|
||||
ok = JS_FALSE;
|
||||
break;
|
||||
}
|
||||
|
@ -873,7 +876,7 @@ obj_toString(JSContext *cx, uintN argc, jsval *vp)
|
|||
if (!obj)
|
||||
return JS_FALSE;
|
||||
if (obj->isProxy()) {
|
||||
if (!JS_GetProxyObjectClass(cx, obj, &clazz))
|
||||
if (!GetProxyObjectClass(cx, obj, &clazz))
|
||||
return false;
|
||||
} else {
|
||||
obj = js_GetWrappedObject(cx, obj);
|
||||
|
@ -1118,14 +1121,6 @@ obj_eval(JSContext *cx, uintN argc, jsval *vp)
|
|||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the caller is a lightweight function and doesn't have a variables
|
||||
* object, then we need to provide one for the compiler to stick any
|
||||
* declared (var) variables into.
|
||||
*/
|
||||
if (caller->fun && !caller->callobj && !js_GetCallObject(cx, caller))
|
||||
return JS_FALSE;
|
||||
|
||||
/* Accept an optional trailing argument that overrides the scope object. */
|
||||
JSObject *scopeobj = NULL;
|
||||
if (argc >= 2) {
|
||||
|
@ -1196,6 +1191,7 @@ obj_eval(JSContext *cx, uintN argc, jsval *vp)
|
|||
* NB: This means that native callers (who reach this point through
|
||||
* the C API) must use the two parameter form.
|
||||
*/
|
||||
JS_ASSERT_IF(caller->argv, caller->callobj);
|
||||
scopeobj = callerScopeChain;
|
||||
}
|
||||
#endif
|
||||
|
@ -3199,6 +3195,14 @@ js_DefineBlockVariable(JSContext *cx, JSObject *obj, jsid id, intN index)
|
|||
JSScopeProperty::HAS_SHORTID, index, NULL);
|
||||
}
|
||||
|
||||
static size_t
|
||||
GetObjectSize(JSObject *obj)
|
||||
{
|
||||
return (obj->isFunction() && !obj->getPrivate())
|
||||
? sizeof(JSFunction)
|
||||
: sizeof(JSObject);
|
||||
}
|
||||
|
||||
/*
|
||||
* Use this method with extreme caution. It trades the guts of two objects and updates
|
||||
* scope ownership. This operation is not thread-safe, just as fast array to slow array
|
||||
|
@ -3212,11 +3216,17 @@ JSObject::swap(JSObject *other)
|
|||
bool thisOwns = this->isNative() && scope()->object == this;
|
||||
bool otherOwns = other->isNative() && other->scope()->object == other;
|
||||
|
||||
size_t size = GetObjectSize(this);
|
||||
JS_ASSERT(size == GetObjectSize(other));
|
||||
|
||||
/* Trade the guts of the objects. */
|
||||
JSObject tmp;
|
||||
memcpy(&tmp, this, sizeof(JSObject));
|
||||
memcpy(this, other, sizeof(JSObject));
|
||||
memcpy(other, &tmp, sizeof(JSObject));
|
||||
union {
|
||||
JSFunction fun;
|
||||
JSObject obj;
|
||||
} tmp;
|
||||
memcpy(&tmp, this, size);
|
||||
memcpy(this, other, size);
|
||||
memcpy(other, &tmp, size);
|
||||
|
||||
/* Fixup scope ownerships. */
|
||||
if (otherOwns)
|
||||
|
|
|
@ -52,6 +52,8 @@
|
|||
|
||||
using namespace js;
|
||||
|
||||
namespace js {
|
||||
|
||||
JSProxyHandler::~JSProxyHandler()
|
||||
{
|
||||
}
|
||||
|
@ -173,6 +175,11 @@ JSProxyHandler::finalize(JSContext *cx, JSObject *proxy)
|
|||
{
|
||||
}
|
||||
|
||||
void
|
||||
JSProxyHandler::trace(JSTracer *trc, JSObject *proxy)
|
||||
{
|
||||
}
|
||||
|
||||
JSNoopProxyHandler::JSNoopProxyHandler(JSObject *obj) : mWrappedObject(obj)
|
||||
{
|
||||
}
|
||||
|
@ -276,6 +283,13 @@ JSNoopProxyHandler::finalize(JSContext *cx, JSObject *proxy)
|
|||
delete this;
|
||||
}
|
||||
|
||||
void
|
||||
JSNoopProxyHandler::trace(JSTracer *trc, JSObject *proxy)
|
||||
{
|
||||
if (mWrappedObject)
|
||||
JS_CALL_OBJECT_TRACER(trc, mWrappedObject, "wrappedObject");
|
||||
}
|
||||
|
||||
void *
|
||||
JSNoopProxyHandler::family()
|
||||
{
|
||||
|
@ -591,8 +605,8 @@ JSProxy::enumerateOwn(JSContext *cx, JSObject *proxy, JSIdArray **idap)
|
|||
return TryHandlerTrap(cx, proxy, ((JSProxyHandler *) JSVAL_TO_PRIVATE(handler))->enumerateOwn(cx, proxy, idap));
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_GetProxyObjectClass(JSContext *cx, JSObject *proxy, const char **namep)
|
||||
JS_FRIEND_API(JSBool)
|
||||
GetProxyObjectClass(JSContext *cx, JSObject *proxy, const char **namep)
|
||||
{
|
||||
if (!proxy->isProxy()) {
|
||||
char *bytes = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK,
|
||||
|
@ -712,7 +726,11 @@ proxy_TraceObject(JSTracer *trc, JSObject *obj)
|
|||
|
||||
obj->traceProtoAndParent(trc);
|
||||
|
||||
JS_CALL_VALUE_TRACER(trc, obj->fslots[JSSLOT_PROXY_HANDLER], "handler");
|
||||
jsval handler = obj->fslots[JSSLOT_PROXY_HANDLER];
|
||||
if (!JSVAL_IS_PRIMITIVE(handler))
|
||||
JS_CALL_OBJECT_TRACER(trc, JSVAL_TO_OBJECT(handler), "handler");
|
||||
else
|
||||
((JSProxyHandler *) JSVAL_TO_PRIVATE(handler))->trace(trc, obj);
|
||||
if (obj->isFunctionProxy()) {
|
||||
JS_CALL_VALUE_TRACER(trc, obj->fslots[JSSLOT_PROXY_CALL], "call");
|
||||
JS_CALL_VALUE_TRACER(trc, obj->fslots[JSSLOT_PROXY_CONSTRUCT], "construct");
|
||||
|
@ -756,7 +774,7 @@ obj_proxy_getObjectOps(JSContext *cx, JSClass *clasp)
|
|||
return &js_ObjectProxyObjectOps;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSClass) js_ObjectProxyClass = {
|
||||
JS_FRIEND_API(JSClass) ObjectProxyClass = {
|
||||
"ObjectProxy",
|
||||
JSCLASS_HAS_RESERVED_SLOTS(3) |
|
||||
JSCLASS_NEW_ENUMERATE,
|
||||
|
@ -835,7 +853,7 @@ fun_proxy_getObjectOps(JSContext *cx, JSClass *clasp)
|
|||
return &js_FunctionProxyObjectOps;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSClass) js_FunctionProxyClass = {
|
||||
JS_FRIEND_API(JSClass) FunctionProxyClass = {
|
||||
"FunctionProxy",
|
||||
JSCLASS_HAS_RESERVED_SLOTS(3) |
|
||||
JSCLASS_NEW_ENUMERATE,
|
||||
|
@ -845,10 +863,10 @@ JS_FRIEND_API(JSClass) js_FunctionProxyClass = {
|
|||
NULL, NULL, NULL, NULL
|
||||
};
|
||||
|
||||
JS_PUBLIC_API(JSObject *)
|
||||
JS_NewObjectProxy(JSContext *cx, jsval handler, JSObject *proto, JSObject *parent, JSString *className)
|
||||
JS_FRIEND_API(JSObject *)
|
||||
NewObjectProxy(JSContext *cx, jsval handler, JSObject *proto, JSObject *parent, JSString *className)
|
||||
{
|
||||
JSObject *obj = NewObject(cx, &js_ObjectProxyClass, proto, parent);
|
||||
JSObject *obj = NewObjectWithGivenProto(cx, &ObjectProxyClass, proto, parent);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
obj->fslots[JSSLOT_PROXY_HANDLER] = handler;
|
||||
|
@ -857,11 +875,11 @@ JS_NewObjectProxy(JSContext *cx, jsval handler, JSObject *proto, JSObject *paren
|
|||
return obj;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSObject *)
|
||||
JS_NewFunctionProxy(JSContext *cx, jsval handler, JSObject *proto, JSObject *parent,
|
||||
JS_FRIEND_API(JSObject *)
|
||||
NewFunctionProxy(JSContext *cx, jsval handler, JSObject *proto, JSObject *parent,
|
||||
JSObject *call, JSObject *construct)
|
||||
{
|
||||
JSObject *obj = NewObject(cx, &js_FunctionProxyClass, proto, parent);
|
||||
JSObject *obj = NewObjectWithGivenProto(cx, &FunctionProxyClass, proto, parent);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
obj->fslots[JSSLOT_PROXY_HANDLER] = handler;
|
||||
|
@ -901,7 +919,7 @@ proxy_create(JSContext *cx, uintN argc, jsval *vp)
|
|||
parent = JSVAL_TO_OBJECT(vp[0])->getParent();
|
||||
}
|
||||
JSString *className = (argc > 2 && JSVAL_IS_STRING(vp[4])) ? JSVAL_TO_STRING(vp[4]) : NULL;
|
||||
JSObject *proxy = JS_NewObjectProxy(cx, OBJECT_TO_JSVAL(handler), proto, parent, className);
|
||||
JSObject *proxy = NewObjectProxy(cx, OBJECT_TO_JSVAL(handler), proto, parent, className);
|
||||
if (!proxy)
|
||||
return false;
|
||||
|
||||
|
@ -936,7 +954,7 @@ proxy_createFunction(JSContext *cx, uintN argc, jsval *vp)
|
|||
return false;
|
||||
}
|
||||
|
||||
JSObject *proxy = JS_NewFunctionProxy(cx, OBJECT_TO_JSVAL(handler), proto, parent, call, construct);
|
||||
JSObject *proxy = NewFunctionProxy(cx, OBJECT_TO_JSVAL(handler), proto, parent, call, construct);
|
||||
if (!proxy)
|
||||
return false;
|
||||
|
||||
|
@ -974,7 +992,7 @@ proxy_fix(JSContext *cx, uintN argc, jsval *vp)
|
|||
return false;
|
||||
if (obj->isProxy()) {
|
||||
JSBool flag;
|
||||
if (!JS_FixProxy(cx, obj, &flag))
|
||||
if (!FixProxy(cx, obj, &flag))
|
||||
return false;
|
||||
*vp = BOOLEAN_TO_JSVAL(flag);
|
||||
} else {
|
||||
|
@ -995,22 +1013,7 @@ static JSFunctionSpec static_methods[] = {
|
|||
JS_FS_END
|
||||
};
|
||||
|
||||
JS_FRIEND_API(JSObject *)
|
||||
js_InitProxyClass(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
JSObject *module = NewObject(cx, &js_ObjectClass, NULL, obj);
|
||||
if (!module)
|
||||
return NULL;
|
||||
if (!JS_DefineProperty(cx, obj, "Proxy", OBJECT_TO_JSVAL(module),
|
||||
JS_PropertyStub, JS_PropertyStub, 0)) {
|
||||
return NULL;
|
||||
}
|
||||
if (!JS_DefineFunctions(cx, module, static_methods))
|
||||
return NULL;
|
||||
return obj;
|
||||
}
|
||||
|
||||
extern JSClass js_CallableObjectClass;
|
||||
extern JSClass CallableObjectClass;
|
||||
|
||||
static const uint32 JSSLOT_CALLABLE_CALL = JSSLOT_PRIVATE;
|
||||
static const uint32 JSSLOT_CALLABLE_CONSTRUCT = JSSLOT_PRIVATE + 1;
|
||||
|
@ -1019,7 +1022,7 @@ static JSBool
|
|||
callable_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
JSObject *callable = JSVAL_TO_OBJECT(argv[-2]);
|
||||
JS_ASSERT(callable->getClass() == &js_CallableObjectClass);
|
||||
JS_ASSERT(callable->getClass() == &CallableObjectClass);
|
||||
jsval fval = callable->fslots[JSSLOT_CALLABLE_CALL];
|
||||
return js_InternalCall(cx, obj, fval, argc, argv, rval);
|
||||
}
|
||||
|
@ -1028,7 +1031,7 @@ static JSBool
|
|||
callable_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
JSObject *callable = JSVAL_TO_OBJECT(argv[-2]);
|
||||
JS_ASSERT(callable->getClass() == &js_CallableObjectClass);
|
||||
JS_ASSERT(callable->getClass() == &CallableObjectClass);
|
||||
jsval fval = callable->fslots[JSSLOT_CALLABLE_CONSTRUCT];
|
||||
if (fval == JSVAL_VOID) {
|
||||
/* We don't have an explicit constructor so allocate a new object and use the call. */
|
||||
|
@ -1054,7 +1057,7 @@ callable_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval
|
|||
return js_InternalCall(cx, obj, fval, argc, argv, rval);
|
||||
}
|
||||
|
||||
JSClass js_CallableObjectClass = {
|
||||
JSClass CallableObjectClass = {
|
||||
"CallableObject",
|
||||
JSCLASS_HAS_RESERVED_SLOTS(2) |
|
||||
JSCLASS_NEW_ENUMERATE,
|
||||
|
@ -1064,8 +1067,8 @@ JSClass js_CallableObjectClass = {
|
|||
NULL, NULL, NULL, NULL
|
||||
};
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp)
|
||||
JS_FRIEND_API(JSBool)
|
||||
FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp)
|
||||
{
|
||||
AutoValueRooter tvr(cx);
|
||||
if (!JSProxy::fix(cx, proxy, tvr.addr()))
|
||||
|
@ -1081,7 +1084,7 @@ JS_FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp)
|
|||
|
||||
JSObject *proto = proxy->getProto();
|
||||
JSObject *parent = proxy->getParent();
|
||||
JSClass *clasp = proxy->isFunctionProxy() ? &js_CallableObjectClass : &js_ObjectClass;
|
||||
JSClass *clasp = proxy->isFunctionProxy() ? &CallableObjectClass : &js_ObjectClass;
|
||||
|
||||
/* Make a blank object from the recipe fix provided to us. */
|
||||
JSObject *newborn = NewObjectWithGivenProto(cx, clasp, proto, parent);
|
||||
|
@ -1089,7 +1092,7 @@ JS_FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp)
|
|||
return NULL;
|
||||
AutoValueRooter tvr2(cx, newborn);
|
||||
|
||||
if (clasp == &js_CallableObjectClass) {
|
||||
if (clasp == &CallableObjectClass) {
|
||||
newborn->fslots[JSSLOT_CALLABLE_CALL] = proxy->fslots[JSSLOT_PROXY_CALL];
|
||||
newborn->fslots[JSSLOT_CALLABLE_CONSTRUCT] = proxy->fslots[JSSLOT_PROXY_CONSTRUCT];
|
||||
}
|
||||
|
@ -1106,13 +1109,19 @@ JS_FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp)
|
|||
return true;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_Becomes(JSContext *cx, JSObject *obj, JSObject *obj2)
|
||||
{
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_ASSERT_IF(obj->isNative(), obj->scope()->title.ownercx == cx);
|
||||
JS_ASSERT_IF(obj2->isNative(), obj2->scope()->title.ownercx == cx);
|
||||
#endif
|
||||
obj->swap(obj2);
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSObject *)
|
||||
js_InitProxyClass(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
JSObject *module = NewObject(cx, &js_ObjectClass, NULL, obj);
|
||||
if (!module)
|
||||
return NULL;
|
||||
if (!JS_DefineProperty(cx, obj, "Proxy", OBJECT_TO_JSVAL(module),
|
||||
JS_PropertyStub, JS_PropertyStub, 0)) {
|
||||
return NULL;
|
||||
}
|
||||
if (!JS_DefineFunctions(cx, module, static_methods))
|
||||
return NULL;
|
||||
return obj;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,8 @@
|
|||
#include "jsapi.h"
|
||||
#include "jsobj.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
/* Base class for all C++ proxy handlers. */
|
||||
class JSProxyHandler {
|
||||
public:
|
||||
|
@ -68,6 +70,7 @@ class JSProxyHandler {
|
|||
|
||||
/* Spidermonkey extensions. */
|
||||
virtual void finalize(JSContext *cx, JSObject *proxy);
|
||||
virtual void trace(JSTracer *trc, JSObject *proxy);
|
||||
virtual void *family() = 0;
|
||||
};
|
||||
|
||||
|
@ -99,6 +102,7 @@ class JSNoopProxyHandler {
|
|||
|
||||
/* Spidermonkey extensions. */
|
||||
virtual JS_FRIEND_API(void) finalize(JSContext *cx, JSObject *proxy);
|
||||
virtual JS_FRIEND_API(void) trace(JSTracer *trc, JSObject *proxy);
|
||||
virtual JS_FRIEND_API(void) *family();
|
||||
|
||||
static JSNoopProxyHandler singleton;
|
||||
|
@ -143,20 +147,22 @@ const uint32 JSSLOT_PROXY_PRIVATE = JSSLOT_PRIVATE + 2;
|
|||
const uint32 JSSLOT_PROXY_CALL = JSSLOT_PRIVATE + 1;
|
||||
const uint32 JSSLOT_PROXY_CONSTRUCT = JSSLOT_PRIVATE + 2;
|
||||
|
||||
extern JS_FRIEND_API(JSClass) js_ObjectProxyClass;
|
||||
extern JS_FRIEND_API(JSClass) js_FunctionProxyClass;
|
||||
extern JSClass js_CallableObjectClass;
|
||||
extern JS_FRIEND_API(JSClass) ObjectProxyClass;
|
||||
extern JS_FRIEND_API(JSClass) FunctionProxyClass;
|
||||
extern JSClass CallableObjectClass;
|
||||
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSObject::isObjectProxy() const
|
||||
{
|
||||
return getClass() == &js_ObjectProxyClass;
|
||||
return getClass() == &js::ObjectProxyClass;
|
||||
}
|
||||
|
||||
inline bool
|
||||
JSObject::isFunctionProxy() const
|
||||
{
|
||||
return getClass() == &js_FunctionProxyClass;
|
||||
return getClass() == &js::FunctionProxyClass;
|
||||
}
|
||||
|
||||
inline bool
|
||||
|
@ -169,7 +175,7 @@ inline jsval
|
|||
JSObject::getProxyHandler() const
|
||||
{
|
||||
JS_ASSERT(isProxy());
|
||||
jsval handler = fslots[JSSLOT_PROXY_HANDLER];
|
||||
jsval handler = fslots[js::JSSLOT_PROXY_HANDLER];
|
||||
JS_ASSERT(JSVAL_IS_OBJECT(handler) || JSVAL_IS_INT(handler));
|
||||
return handler;
|
||||
}
|
||||
|
@ -178,30 +184,29 @@ inline jsval
|
|||
JSObject::getProxyPrivate() const
|
||||
{
|
||||
JS_ASSERT(isObjectProxy());
|
||||
return fslots[JSSLOT_PROXY_PRIVATE];
|
||||
return fslots[js::JSSLOT_PROXY_PRIVATE];
|
||||
}
|
||||
|
||||
inline void
|
||||
JSObject::setProxyPrivate(jsval priv)
|
||||
{
|
||||
JS_ASSERT(isObjectProxy());
|
||||
fslots[JSSLOT_PROXY_PRIVATE] = priv;
|
||||
fslots[js::JSSLOT_PROXY_PRIVATE] = priv;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSObject *)
|
||||
JS_NewObjectProxy(JSContext *cx, jsval handler, JSObject *proto, JSObject *parent, JSString *className);
|
||||
namespace js {
|
||||
|
||||
JS_PUBLIC_API(JSObject *)
|
||||
JS_NewFunctionProxy(JSContext *cx, jsval handler, JSObject *proto, JSObject *parent, JSObject *call, JSObject *construct);
|
||||
JS_FRIEND_API(JSObject *)
|
||||
NewObjectProxy(JSContext *cx, jsval handler, JSObject *proto, JSObject *parent, JSString *className);
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_GetProxyObjectClass(JSContext *cx, JSObject *proxy, const char **namep);
|
||||
JS_FRIEND_API(JSObject *)
|
||||
NewFunctionProxy(JSContext *cx, jsval handler, JSObject *proto, JSObject *parent, JSObject *call, JSObject *construct);
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp);
|
||||
JS_FRIEND_API(JSBool)
|
||||
GetProxyObjectClass(JSContext *cx, JSObject *proxy, const char **namep);
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_Becomes(JSContext *cx, JSObject *obj, JSObject *obj2);
|
||||
JS_FRIEND_API(JSBool)
|
||||
FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp);
|
||||
|
||||
template <class T>
|
||||
JSObject *
|
||||
|
@ -211,17 +216,19 @@ JSNoopProxyHandler::wrap(JSContext *cx, JSObject *obj, JSObject *proto, JSObject
|
|||
JSNoopProxyHandler *handler = new T(obj);
|
||||
if (!handler)
|
||||
return NULL;
|
||||
JSObject *wrapper = JS_NewFunctionProxy(cx, PRIVATE_TO_JSVAL(handler), proto, parent, obj, NULL);
|
||||
JSObject *wrapper = NewFunctionProxy(cx, PRIVATE_TO_JSVAL(handler), proto, parent, obj, NULL);
|
||||
if (!wrapper)
|
||||
delete handler;
|
||||
return wrapper;
|
||||
}
|
||||
JSObject *wrapper = JS_NewObjectProxy(cx, PRIVATE_TO_JSVAL(&T::singleton), proto, parent, className);
|
||||
JSObject *wrapper = NewObjectProxy(cx, PRIVATE_TO_JSVAL(&T::singleton), proto, parent, className);
|
||||
if (wrapper)
|
||||
wrapper->setProxyPrivate(OBJECT_TO_JSVAL(obj));
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
|
|
|
@ -13946,6 +13946,8 @@ TraceRecorder::record_JSOP_BINDNAME()
|
|||
JSAtom *atom = atoms[GET_INDEX(cx->regs->pc)];
|
||||
jsid id = ATOM_TO_JSID(atom);
|
||||
JSObject *obj2 = js_FindIdentifierBase(cx, fp->scopeChain, id);
|
||||
if (!obj2)
|
||||
RETURN_ERROR_A("error in js_FindIdentifierBase");
|
||||
if (obj2 != globalObj && obj2->getClass() != &js_CallClass)
|
||||
RETURN_STOP_A("BINDNAME on non-global, non-call object");
|
||||
|
||||
|
@ -14012,7 +14014,7 @@ TraceRecorder::record_JSOP_IN()
|
|||
if (!localtm.recorder) {
|
||||
if (prop)
|
||||
obj2->dropProperty(localcx, prop);
|
||||
return ARECORD_STOP;
|
||||
return ARECORD_ABORTED;
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
|
|
Загрузка…
Ссылка в новой задаче