mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
Remove code duplication when reporting syntax errors in NodeTransformer, ToekStream, IRFactory and Parser and add a method to create FunctionNode to Interpreter/Codegen to remove the need to have OptIRFactory.
This commit is contained in:
parent
9ad003b9a0
commit
19e12f45e4
@ -845,9 +845,10 @@ public class Context {
|
||||
setErrorReporter(new DefaultErrorReporter());
|
||||
|
||||
boolean errorseen = false;
|
||||
Interpreter compiler = new Interpreter();
|
||||
IRFactory irf = compiler.createIRFactory(this, ts);
|
||||
Parser p = createParser(irf);
|
||||
try {
|
||||
IRFactory irf = new IRFactory(ts, null);
|
||||
Parser p = createParser(irf);
|
||||
p.parse(ts);
|
||||
} catch (IOException ioe) {
|
||||
errorseen = true;
|
||||
@ -1999,13 +2000,13 @@ public class Context {
|
||||
Interpreter compiler = createCompiler();
|
||||
|
||||
errorCount = 0;
|
||||
IRFactory irf = compiler.createIRFactory(this, ts, scope);
|
||||
IRFactory irf = compiler.createIRFactory(this, ts);
|
||||
Parser p = createParser(irf);
|
||||
Node tree = (Node) p.parse(ts);
|
||||
if (tree == null)
|
||||
return null;
|
||||
|
||||
tree = compiler.transform(tree, ts, scope);
|
||||
tree = compiler.transform(this, irf, tree);
|
||||
|
||||
if (printTrees) { System.out.println(tree.toStringTree()); }
|
||||
|
||||
@ -2024,7 +2025,7 @@ public class Context {
|
||||
}
|
||||
|
||||
Object result = compiler.compile(this, scope, tree,
|
||||
securityDomain, securityController);
|
||||
securityController, securityDomain);
|
||||
|
||||
return errorCount == 0 ? result : null;
|
||||
}
|
||||
|
@ -40,8 +40,8 @@ import java.util.*;
|
||||
|
||||
public class FunctionNode extends Node {
|
||||
|
||||
public FunctionNode(String name, Node statements) {
|
||||
super(TokenStream.FUNCTION, statements);
|
||||
public FunctionNode(String name) {
|
||||
super(TokenStream.FUNCTION);
|
||||
functionName = name;
|
||||
}
|
||||
|
||||
|
@ -44,9 +44,9 @@ package org.mozilla.javascript;
|
||||
*/
|
||||
public class IRFactory {
|
||||
|
||||
public IRFactory(TokenStream ts, Scriptable scope) {
|
||||
public IRFactory(Interpreter compiler, TokenStream ts) {
|
||||
this.compiler = compiler;
|
||||
this.ts = ts;
|
||||
this.scope = scope;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -72,7 +72,7 @@ public class IRFactory {
|
||||
* Leaf
|
||||
*/
|
||||
public Object createLeaf(int nodeType) {
|
||||
return new Node(nodeType);
|
||||
return new Node(nodeType);
|
||||
}
|
||||
|
||||
public Object createLeaf(int nodeType, int nodeOp) {
|
||||
@ -202,23 +202,19 @@ public class IRFactory {
|
||||
return new Node(TokenStream.BLOCK, lineno);
|
||||
}
|
||||
|
||||
public Object createFunctionNode(String name, Object statements)
|
||||
{
|
||||
return new FunctionNode(name, (Node) statements);
|
||||
}
|
||||
|
||||
public Object createFunction(String name, VariableTable vars,
|
||||
Object statements,
|
||||
String sourceName, int baseLineno,
|
||||
int endLineno, Object source,
|
||||
int endLineno, String source,
|
||||
int functionType)
|
||||
{
|
||||
if (name == null) {
|
||||
name = "";
|
||||
}
|
||||
FunctionNode f = (FunctionNode) createFunctionNode(name, statements);
|
||||
FunctionNode f = compiler.createFunctionNode(this, name);
|
||||
f.itsVariableTable = vars;
|
||||
f.setFunctionType(functionType);
|
||||
f.addChildToBack((Node)statements);
|
||||
f.putProp(Node.SOURCENAME_PROP, sourceName);
|
||||
f.putIntProp(Node.BASE_LINENO_PROP, baseLineno);
|
||||
f.putIntProp(Node.END_LINENO_PROP, endLineno);
|
||||
@ -341,13 +337,13 @@ public class IRFactory {
|
||||
*/
|
||||
Node lastChild = lhsNode.getLastChild();
|
||||
if (lhsNode.getFirstChild() != lastChild) {
|
||||
reportError("msg.mult.index");
|
||||
ts.reportCurrentLineError("msg.mult.index", null);
|
||||
}
|
||||
lvalue = Node.newString(TokenStream.NAME, lastChild.getString());
|
||||
break;
|
||||
|
||||
default:
|
||||
reportError("msg.bad.for.in.lhs");
|
||||
ts.reportCurrentLineError("msg.bad.for.in.lhs", null);
|
||||
return objNode;
|
||||
}
|
||||
|
||||
@ -845,7 +841,7 @@ public class IRFactory {
|
||||
default:
|
||||
// TODO: This should be a ReferenceError--but that's a runtime
|
||||
// exception. Should we compile an exception into the code?
|
||||
reportError("msg.bad.lhs.assign");
|
||||
ts.reportCurrentLineError("msg.bad.lhs.assign", null);
|
||||
return left;
|
||||
}
|
||||
}
|
||||
@ -1014,28 +1010,12 @@ public class IRFactory {
|
||||
return result;
|
||||
}
|
||||
|
||||
private void reportError(String msgResource) {
|
||||
private Interpreter compiler;
|
||||
|
||||
if (scope != null)
|
||||
throw NativeGlobal.constructError(
|
||||
Context.getContext(), "SyntaxError",
|
||||
ScriptRuntime.getMessage0(msgResource),
|
||||
scope, ts.getSourceName(), ts.getLineno(),
|
||||
ts.getOffset(), ts.getLine());
|
||||
else {
|
||||
String message = Context.getMessage0(msgResource);
|
||||
Context.reportError(message, ts.getSourceName(), ts.getLineno(),
|
||||
ts.getLine(), ts.getOffset());
|
||||
}
|
||||
}
|
||||
|
||||
// Only needed to get file/line information. Could create an interface
|
||||
// Only needed to call reportSyntaxError. Could create an interface
|
||||
// that TokenStream implements if we want to make the connection less
|
||||
// direct.
|
||||
private TokenStream ts;
|
||||
|
||||
// Only needed to pass to the Erorr exception constructors
|
||||
private Scriptable scope;
|
||||
TokenStream ts;
|
||||
|
||||
private static final int LOOP_DO_WHILE = 0;
|
||||
private static final int LOOP_WHILE = 1;
|
||||
|
@ -60,19 +60,25 @@ public class Interpreter {
|
||||
// Last icode
|
||||
END_ICODE = TokenStream.LAST_TOKEN + 6;
|
||||
|
||||
public IRFactory createIRFactory(Context cx, TokenStream ts,
|
||||
Scriptable scope)
|
||||
public IRFactory createIRFactory(Context cx, TokenStream ts)
|
||||
{
|
||||
return new IRFactory(ts, scope);
|
||||
return new IRFactory(this, ts);
|
||||
}
|
||||
|
||||
public Node transform(Node tree, TokenStream ts, Scriptable scope) {
|
||||
return (new NodeTransformer()).transform(tree, null, ts, scope);
|
||||
public FunctionNode createFunctionNode(IRFactory irFactory, String name)
|
||||
{
|
||||
return new FunctionNode(name);
|
||||
}
|
||||
|
||||
public Object compile(Context cx, Scriptable scope, Node tree,
|
||||
Object securityDomain,
|
||||
SecurityController securityController)
|
||||
public Node transform(Context cx, IRFactory irFactory, Node tree)
|
||||
{
|
||||
tree = (new NodeTransformer(irFactory)).transform(tree, null);
|
||||
return tree;
|
||||
}
|
||||
|
||||
public Object
|
||||
compile(Context cx, Scriptable scope, Node tree,
|
||||
SecurityController securityController, Object securityDomain)
|
||||
{
|
||||
version = cx.getLanguageVersion();
|
||||
itsData = new InterpreterData(securityDomain);
|
||||
|
@ -46,35 +46,28 @@ package org.mozilla.javascript;
|
||||
|
||||
public class NodeTransformer {
|
||||
|
||||
public NodeTransformer(IRFactory irFactory) {
|
||||
this.irFactory = irFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return new instance of this class. So that derived classes
|
||||
* can override methods of the transformer.
|
||||
*/
|
||||
public NodeTransformer newInstance() {
|
||||
return new NodeTransformer();
|
||||
return new NodeTransformer(irFactory);
|
||||
}
|
||||
|
||||
public IRFactory createIRFactory(TokenStream ts, Scriptable scope) {
|
||||
return new IRFactory(ts, scope);
|
||||
}
|
||||
|
||||
public Node transform(Node tree, Node enclosing, TokenStream ts,
|
||||
Scriptable scope)
|
||||
public Node transform(Node tree, Node enclosing)
|
||||
{
|
||||
loops = new ObjArray();
|
||||
loopEnds = new ObjArray();
|
||||
inFunction = tree.getType() == TokenStream.FUNCTION;
|
||||
VariableTable vars;
|
||||
if (!inFunction) {
|
||||
vars = (VariableTable)tree.getProp(Node.VARS_PROP);
|
||||
checkVariables(tree, vars);
|
||||
} else {
|
||||
FunctionNode fnNode = (FunctionNode)tree;
|
||||
vars = fnNode.getVariableTable();
|
||||
checkVariables(tree, vars);
|
||||
fnNode.markVariableTableReady();
|
||||
VariableTable vars = getVariableTable(tree);
|
||||
checkVariables(tree, vars);
|
||||
if (inFunction) {
|
||||
((FunctionNode)tree).markVariableTableReady();
|
||||
}
|
||||
irFactory = createIRFactory(ts, scope);
|
||||
|
||||
// to save against upchecks if no finally blocks are used.
|
||||
boolean hasFinally = false;
|
||||
@ -112,8 +105,7 @@ public class NodeTransformer {
|
||||
fnNode.setCheckThis(true);
|
||||
}
|
||||
NodeTransformer inner = newInstance();
|
||||
fnNode = (FunctionNode)
|
||||
inner.transform(fnNode, tree, ts, scope);
|
||||
fnNode = (FunctionNode)inner.transform(fnNode, tree);
|
||||
node.putProp(Node.FUNCTION_PROP, fnNode);
|
||||
ObjArray fns = (ObjArray) tree.getProp(Node.FUNCTION_PROP);
|
||||
if (fns == null) {
|
||||
@ -136,10 +128,9 @@ public class NodeTransformer {
|
||||
if (n.getType() == TokenStream.LABEL) {
|
||||
String otherId = (String)n.getProp(Node.LABEL_PROP);
|
||||
if (id.equals(otherId)) {
|
||||
String message = Context.getMessage1(
|
||||
"msg.dup.label", id);
|
||||
reportMessage(Context.getContext(), message, node,
|
||||
tree, true, scope);
|
||||
Object[] messageArgs = { id };
|
||||
reportError("msg.dup.label", messageArgs,
|
||||
node, tree);
|
||||
break typeswitch;
|
||||
}
|
||||
}
|
||||
@ -336,25 +327,22 @@ public class NodeTransformer {
|
||||
? null
|
||||
: (Node) loop.getProp(propType);
|
||||
if (loop == null || target == null) {
|
||||
String message;
|
||||
String messageId;
|
||||
Object[] messageArgs = null;
|
||||
if (!labelled) {
|
||||
// didn't find an appropriate target
|
||||
if (type == TokenStream.CONTINUE) {
|
||||
message = Context.getMessage
|
||||
("msg.continue.outside", null);
|
||||
messageId = "msg.continue.outside";
|
||||
} else {
|
||||
message = Context.getMessage
|
||||
("msg.bad.break", null);
|
||||
messageId = "msg.bad.break";
|
||||
}
|
||||
} else if (loop != null) {
|
||||
message = Context.getMessage0("msg.continue.nonloop");
|
||||
messageId = "msg.continue.nonloop";
|
||||
} else {
|
||||
Object[] errArgs = { id };
|
||||
message = Context.getMessage
|
||||
("msg.undef.label", errArgs);
|
||||
messageArgs = new Object[] { id };
|
||||
messageId = "msg.undef.label";
|
||||
}
|
||||
reportMessage(Context.getContext(), message, node,
|
||||
tree, true, scope);
|
||||
reportError(messageId, messageArgs, node, tree);
|
||||
node.setType(TokenStream.NOP);
|
||||
break;
|
||||
}
|
||||
@ -457,8 +445,7 @@ public class NodeTransformer {
|
||||
Context cx = Context.getCurrentContext();
|
||||
if ((cx != null && cx.isActivationNeeded(name)) ||
|
||||
(name.equals("length") &&
|
||||
Context.getContext().getLanguageVersion() ==
|
||||
Context.VERSION_1_2))
|
||||
cx.getLanguageVersion() == Context.VERSION_1_2))
|
||||
{
|
||||
// Use of "arguments" or "length" in 1.2 requires
|
||||
// an activation object.
|
||||
@ -657,24 +644,13 @@ public class NodeTransformer {
|
||||
}
|
||||
}
|
||||
|
||||
protected void reportMessage(Context cx, String msg, Node stmt,
|
||||
Node tree, boolean isError,
|
||||
Scriptable scope)
|
||||
private void
|
||||
reportError(String messageId, Object[] messageArgs, Node stmt, Node tree)
|
||||
{
|
||||
int lineno = stmt.getLineno();
|
||||
Object prop = tree == null
|
||||
? null
|
||||
: tree.getProp(Node.SOURCENAME_PROP);
|
||||
if (isError) {
|
||||
if (scope != null)
|
||||
throw NativeGlobal.constructError(
|
||||
cx, "SyntaxError", msg, scope,
|
||||
(String) prop, lineno, 0, null);
|
||||
else
|
||||
cx.reportError(msg, (String) prop, lineno, null, 0);
|
||||
}
|
||||
else
|
||||
cx.reportWarning(msg, (String) prop, lineno, null, 0);
|
||||
String sourceName = (String)tree.getProp(Node.SOURCENAME_PROP);
|
||||
irFactory.ts.reportSyntaxError(true, messageId, messageArgs,
|
||||
sourceName, lineno, null, 0);
|
||||
}
|
||||
|
||||
protected ObjArray loops;
|
||||
|
@ -65,7 +65,7 @@ class Parser {
|
||||
}
|
||||
|
||||
private void mustMatchToken(TokenStream ts, int toMatch, String messageId)
|
||||
throws IOException, JavaScriptException
|
||||
throws IOException, ParserException
|
||||
{
|
||||
int tt;
|
||||
if ((tt = ts.getToken()) != toMatch) {
|
||||
@ -75,17 +75,14 @@ class Parser {
|
||||
}
|
||||
|
||||
private void reportError(TokenStream ts, String messageId)
|
||||
throws JavaScriptException
|
||||
throws ParserException
|
||||
{
|
||||
this.ok = false;
|
||||
ts.reportSyntaxError(messageId, null);
|
||||
ts.reportCurrentLineError(messageId, null);
|
||||
|
||||
/* Throw an exception to unwind the recursive descent parse.
|
||||
* We use JavaScriptException here even though it is really
|
||||
* a different use of the exception than it is usually used
|
||||
* for.
|
||||
*/
|
||||
throw new JavaScriptException(messageId);
|
||||
// Throw a ParserException exception to unwind the recursive descent
|
||||
// parse.
|
||||
throw new ParserException();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -129,7 +126,7 @@ class Parser {
|
||||
if (tt == ts.FUNCTION) {
|
||||
try {
|
||||
n = function(ts, FunctionNode.FUNCTION_STATEMENT);
|
||||
} catch (JavaScriptException e) {
|
||||
} catch (ParserException e) {
|
||||
this.ok = false;
|
||||
break;
|
||||
}
|
||||
@ -179,7 +176,7 @@ class Parser {
|
||||
}
|
||||
nf.addChildToBack(pn, n);
|
||||
}
|
||||
} catch (JavaScriptException e) {
|
||||
} catch (ParserException e) {
|
||||
this.ok = false;
|
||||
} finally {
|
||||
// also in finally block:
|
||||
@ -192,7 +189,7 @@ class Parser {
|
||||
}
|
||||
|
||||
private Object function(TokenStream ts, int functionType)
|
||||
throws IOException, JavaScriptException
|
||||
throws IOException, ParserException
|
||||
{
|
||||
int baseLineno = ts.getLineno(); // line number where source starts
|
||||
|
||||
@ -266,7 +263,7 @@ class Parser {
|
||||
String s = ts.getString();
|
||||
if (new_vars.hasVariable(s)) {
|
||||
Object[] msgArgs = { s };
|
||||
ts.reportSyntaxWarning("msg.dup.parms", msgArgs);
|
||||
ts.reportCurrentLineWarning("msg.dup.parms", msgArgs);
|
||||
}
|
||||
new_vars.addParameter(s);
|
||||
sourceAddString(ts.NAME, s);
|
||||
@ -345,7 +342,7 @@ class Parser {
|
||||
}
|
||||
|
||||
private Object condition(TokenStream ts)
|
||||
throws IOException, JavaScriptException
|
||||
throws IOException, ParserException
|
||||
{
|
||||
Object pn;
|
||||
mustMatchToken(ts, ts.LP, "msg.no.paren.cond");
|
||||
@ -360,7 +357,7 @@ class Parser {
|
||||
}
|
||||
|
||||
private void checkWellTerminated(TokenStream ts)
|
||||
throws IOException, JavaScriptException
|
||||
throws IOException, ParserException
|
||||
{
|
||||
int tt = ts.peekTokenSameLine();
|
||||
switch (tt) {
|
||||
@ -385,7 +382,7 @@ class Parser {
|
||||
}
|
||||
|
||||
private void checkWellTerminatedFunction(TokenStream ts)
|
||||
throws IOException, JavaScriptException
|
||||
throws IOException, ParserException
|
||||
{
|
||||
if (languageVersion < Context.VERSION_1_2) {
|
||||
// See comments in checkWellTerminated
|
||||
@ -396,7 +393,7 @@ class Parser {
|
||||
|
||||
// match a NAME; return null if no match.
|
||||
private String matchLabel(TokenStream ts)
|
||||
throws IOException, JavaScriptException
|
||||
throws IOException, ParserException
|
||||
{
|
||||
int lineno = ts.getLineno();
|
||||
|
||||
@ -419,7 +416,7 @@ class Parser {
|
||||
{
|
||||
try {
|
||||
return statementHelper(ts);
|
||||
} catch (JavaScriptException e) {
|
||||
} catch (ParserException e) {
|
||||
// skip to end of statement
|
||||
int lineno = ts.getLineno();
|
||||
int t;
|
||||
@ -437,7 +434,7 @@ class Parser {
|
||||
*/
|
||||
|
||||
private Object statementHelper(TokenStream ts)
|
||||
throws IOException, JavaScriptException
|
||||
throws IOException, ParserException
|
||||
{
|
||||
Object pn = null;
|
||||
|
||||
@ -868,7 +865,7 @@ class Parser {
|
||||
}
|
||||
|
||||
private Object variables(TokenStream ts, boolean inForInit)
|
||||
throws IOException, JavaScriptException
|
||||
throws IOException, ParserException
|
||||
{
|
||||
Object pn = nf.createVariables(ts.getLineno());
|
||||
boolean first = true;
|
||||
@ -909,7 +906,7 @@ class Parser {
|
||||
}
|
||||
|
||||
private Object expr(TokenStream ts, boolean inForInit)
|
||||
throws IOException, JavaScriptException
|
||||
throws IOException, ParserException
|
||||
{
|
||||
Object pn = assignExpr(ts, inForInit);
|
||||
while (ts.matchToken(ts.COMMA)) {
|
||||
@ -920,7 +917,7 @@ class Parser {
|
||||
}
|
||||
|
||||
private Object assignExpr(TokenStream ts, boolean inForInit)
|
||||
throws IOException, JavaScriptException
|
||||
throws IOException, ParserException
|
||||
{
|
||||
Object pn = condExpr(ts, inForInit);
|
||||
|
||||
@ -936,7 +933,7 @@ class Parser {
|
||||
}
|
||||
|
||||
private Object condExpr(TokenStream ts, boolean inForInit)
|
||||
throws IOException, JavaScriptException
|
||||
throws IOException, ParserException
|
||||
{
|
||||
Object ifTrue;
|
||||
Object ifFalse;
|
||||
@ -956,7 +953,7 @@ class Parser {
|
||||
}
|
||||
|
||||
private Object orExpr(TokenStream ts, boolean inForInit)
|
||||
throws IOException, JavaScriptException
|
||||
throws IOException, ParserException
|
||||
{
|
||||
Object pn = andExpr(ts, inForInit);
|
||||
if (ts.matchToken(ts.OR)) {
|
||||
@ -968,7 +965,7 @@ class Parser {
|
||||
}
|
||||
|
||||
private Object andExpr(TokenStream ts, boolean inForInit)
|
||||
throws IOException, JavaScriptException
|
||||
throws IOException, ParserException
|
||||
{
|
||||
Object pn = bitOrExpr(ts, inForInit);
|
||||
if (ts.matchToken(ts.AND)) {
|
||||
@ -980,7 +977,7 @@ class Parser {
|
||||
}
|
||||
|
||||
private Object bitOrExpr(TokenStream ts, boolean inForInit)
|
||||
throws IOException, JavaScriptException
|
||||
throws IOException, ParserException
|
||||
{
|
||||
Object pn = bitXorExpr(ts, inForInit);
|
||||
while (ts.matchToken(ts.BITOR)) {
|
||||
@ -991,7 +988,7 @@ class Parser {
|
||||
}
|
||||
|
||||
private Object bitXorExpr(TokenStream ts, boolean inForInit)
|
||||
throws IOException, JavaScriptException
|
||||
throws IOException, ParserException
|
||||
{
|
||||
Object pn = bitAndExpr(ts, inForInit);
|
||||
while (ts.matchToken(ts.BITXOR)) {
|
||||
@ -1002,7 +999,7 @@ class Parser {
|
||||
}
|
||||
|
||||
private Object bitAndExpr(TokenStream ts, boolean inForInit)
|
||||
throws IOException, JavaScriptException
|
||||
throws IOException, ParserException
|
||||
{
|
||||
Object pn = eqExpr(ts, inForInit);
|
||||
while (ts.matchToken(ts.BITAND)) {
|
||||
@ -1013,7 +1010,7 @@ class Parser {
|
||||
}
|
||||
|
||||
private Object eqExpr(TokenStream ts, boolean inForInit)
|
||||
throws IOException, JavaScriptException
|
||||
throws IOException, ParserException
|
||||
{
|
||||
Object pn = relExpr(ts, inForInit);
|
||||
while (ts.matchToken(ts.EQOP)) {
|
||||
@ -1026,7 +1023,7 @@ class Parser {
|
||||
}
|
||||
|
||||
private Object relExpr(TokenStream ts, boolean inForInit)
|
||||
throws IOException, JavaScriptException
|
||||
throws IOException, ParserException
|
||||
{
|
||||
Object pn = shiftExpr(ts);
|
||||
while (ts.matchToken(ts.RELOP)) {
|
||||
@ -1043,7 +1040,7 @@ class Parser {
|
||||
}
|
||||
|
||||
private Object shiftExpr(TokenStream ts)
|
||||
throws IOException, JavaScriptException
|
||||
throws IOException, ParserException
|
||||
{
|
||||
Object pn = addExpr(ts);
|
||||
while (ts.matchToken(ts.SHOP)) {
|
||||
@ -1055,7 +1052,7 @@ class Parser {
|
||||
}
|
||||
|
||||
private Object addExpr(TokenStream ts)
|
||||
throws IOException, JavaScriptException
|
||||
throws IOException, ParserException
|
||||
{
|
||||
int tt;
|
||||
Object pn = mulExpr(ts);
|
||||
@ -1071,7 +1068,7 @@ class Parser {
|
||||
}
|
||||
|
||||
private Object mulExpr(TokenStream ts)
|
||||
throws IOException, JavaScriptException
|
||||
throws IOException, ParserException
|
||||
{
|
||||
int tt;
|
||||
|
||||
@ -1090,7 +1087,7 @@ class Parser {
|
||||
}
|
||||
|
||||
private Object unaryExpr(TokenStream ts)
|
||||
throws IOException, JavaScriptException
|
||||
throws IOException, ParserException
|
||||
{
|
||||
int tt;
|
||||
|
||||
@ -1153,7 +1150,7 @@ class Parser {
|
||||
}
|
||||
|
||||
private Object argumentList(TokenStream ts, Object listNode)
|
||||
throws IOException, JavaScriptException
|
||||
throws IOException, ParserException
|
||||
{
|
||||
boolean matched;
|
||||
ts.flags |= ts.TSF_REGEXP;
|
||||
@ -1175,7 +1172,7 @@ class Parser {
|
||||
}
|
||||
|
||||
private Object memberExpr(TokenStream ts, boolean allowCallSyntax)
|
||||
throws IOException, JavaScriptException
|
||||
throws IOException, ParserException
|
||||
{
|
||||
int tt;
|
||||
|
||||
@ -1222,7 +1219,7 @@ class Parser {
|
||||
|
||||
private Object memberExprTail(TokenStream ts, boolean allowCallSyntax,
|
||||
Object pn)
|
||||
throws IOException, JavaScriptException
|
||||
throws IOException, ParserException
|
||||
{
|
||||
int tt;
|
||||
while ((tt = ts.getToken()) > ts.EOF) {
|
||||
@ -1261,7 +1258,7 @@ class Parser {
|
||||
}
|
||||
|
||||
private Object primaryExpr(TokenStream ts)
|
||||
throws IOException, JavaScriptException
|
||||
throws IOException, ParserException
|
||||
{
|
||||
int tt;
|
||||
|
||||
@ -2298,3 +2295,6 @@ class Parser {
|
||||
|
||||
}
|
||||
|
||||
// Exception to unwind
|
||||
class ParserException extends Exception { }
|
||||
|
||||
|
@ -46,8 +46,10 @@ import java.io.StringWriter;
|
||||
|
||||
public class Block {
|
||||
|
||||
public Block(int startNodeIndex, int endNodeIndex, Node[] statementNodes)
|
||||
public Block(IRFactory irFactory, int startNodeIndex, int endNodeIndex,
|
||||
Node[] statementNodes)
|
||||
{
|
||||
itsIRFactory = irFactory;
|
||||
itsStartNodeIndex = startNodeIndex;
|
||||
itsEndNodeIndex = endNodeIndex;
|
||||
itsStatementNodes = statementNodes;
|
||||
@ -61,7 +63,8 @@ public class Block {
|
||||
public Block[] getPredecessorList() { return itsPredecessors; }
|
||||
public Block[] getSuccessorList() { return itsSuccessors; }
|
||||
|
||||
public static Block[] buildBlocks(Node[] statementNodes)
|
||||
public static Block[]
|
||||
buildBlocks(IRFactory irFactory, Node[] statementNodes)
|
||||
{
|
||||
// a mapping from each target node to the block it begins
|
||||
Hashtable theTargetBlocks = new Hashtable();
|
||||
@ -75,8 +78,9 @@ public class Block {
|
||||
case TokenStream.TARGET :
|
||||
{
|
||||
if (i != beginNodeIndex) {
|
||||
FatBlock fb = new FatBlock(beginNodeIndex,
|
||||
i - 1, statementNodes);
|
||||
FatBlock fb = new FatBlock(irFactory,
|
||||
beginNodeIndex, i - 1,
|
||||
statementNodes);
|
||||
if (statementNodes[beginNodeIndex].getType()
|
||||
== TokenStream.TARGET)
|
||||
theTargetBlocks.put(statementNodes[beginNodeIndex], fb);
|
||||
@ -90,8 +94,9 @@ public class Block {
|
||||
case TokenStream.IFEQ :
|
||||
case TokenStream.GOTO :
|
||||
{
|
||||
FatBlock fb = new FatBlock(beginNodeIndex,
|
||||
i, statementNodes);
|
||||
FatBlock fb = new FatBlock(irFactory,
|
||||
beginNodeIndex, i,
|
||||
statementNodes);
|
||||
if (statementNodes[beginNodeIndex].getType()
|
||||
== TokenStream.TARGET)
|
||||
theTargetBlocks.put(statementNodes[beginNodeIndex], fb);
|
||||
@ -104,9 +109,10 @@ public class Block {
|
||||
}
|
||||
|
||||
if ((beginNodeIndex != statementNodes.length)) {
|
||||
FatBlock fb = new FatBlock(beginNodeIndex,
|
||||
statementNodes.length - 1,
|
||||
statementNodes);
|
||||
FatBlock fb = new FatBlock(irFactory,
|
||||
beginNodeIndex,
|
||||
statementNodes.length - 1,
|
||||
statementNodes);
|
||||
if (statementNodes[beginNodeIndex].getType() == TokenStream.TARGET)
|
||||
theTargetBlocks.put(statementNodes[beginNodeIndex], fb);
|
||||
theBlocks.add(fb);
|
||||
@ -607,11 +613,8 @@ public class Block {
|
||||
}
|
||||
}
|
||||
|
||||
private IRFactory itsIRFactory;
|
||||
|
||||
Hashtable localCSE(Hashtable theCSETable, OptFunctionNode theFunction)
|
||||
{
|
||||
itsIRFactory = new IRFactory(null, null);
|
||||
if (theCSETable == null) theCSETable = new Hashtable(5);
|
||||
for (int i = itsStartNodeIndex; i <= itsEndNodeIndex; i++) {
|
||||
Node n = itsStatementNodes[i];
|
||||
@ -666,6 +669,8 @@ public class Block {
|
||||
public void setSuccessorList(Block[] b) { itsSuccessors = b; }
|
||||
public void setPredecessorList(Block[] b) { itsPredecessors = b; }
|
||||
|
||||
private IRFactory itsIRFactory;
|
||||
|
||||
// all the Blocks that come immediately after this
|
||||
private Block[] itsSuccessors;
|
||||
// all the Blocks that come immediately before this
|
||||
|
@ -53,38 +53,46 @@ import java.lang.reflect.Constructor;
|
||||
|
||||
public class Codegen extends Interpreter {
|
||||
|
||||
public Codegen() {
|
||||
}
|
||||
public Codegen() { }
|
||||
|
||||
private Codegen(Codegen parent) {
|
||||
private Codegen(Codegen parent)
|
||||
{
|
||||
this.nameHelper = parent.nameHelper;
|
||||
this.classNames = parent.classNames;
|
||||
}
|
||||
|
||||
public IRFactory createIRFactory(Context cx, TokenStream ts,
|
||||
Scriptable scope)
|
||||
public IRFactory createIRFactory(Context cx, TokenStream ts)
|
||||
{
|
||||
if (nameHelper == null) {
|
||||
nameHelper = (OptClassNameHelper)ClassNameHelper.get(cx);
|
||||
classNames = new ObjToIntMap();
|
||||
}
|
||||
return new OptIRFactory(ts, scope, this);
|
||||
return new IRFactory(this, ts);
|
||||
}
|
||||
|
||||
public Node transform(Node tree, TokenStream ts, Scriptable scope) {
|
||||
OptTransformer opt = new OptTransformer(new Hashtable(11));
|
||||
return opt.transform(tree, null, ts, scope);
|
||||
public FunctionNode createFunctionNode(IRFactory irFactory, String name)
|
||||
{
|
||||
String className = getScriptClassName(name, false);
|
||||
return new OptFunctionNode(name, className);
|
||||
}
|
||||
|
||||
public Object compile(Context cx, Scriptable scope, Node tree,
|
||||
Object securityDomain,
|
||||
SecurityController securityController)
|
||||
public Node transform(Context cx, IRFactory irFactory, Node tree)
|
||||
{
|
||||
int optimizationLevel = cx.getOptimizationLevel();
|
||||
OptTransformer opt = new OptTransformer(irFactory, new Hashtable(11));
|
||||
tree = opt.transform(tree, null);
|
||||
if (optimizationLevel > 0) {
|
||||
(new Optimizer(irFactory)).optimize(tree, optimizationLevel);
|
||||
}
|
||||
return tree;
|
||||
}
|
||||
|
||||
public Object
|
||||
compile(Context cx, Scriptable scope, Node tree,
|
||||
SecurityController securityController, Object securityDomain)
|
||||
{
|
||||
ObjArray classFiles = new ObjArray();
|
||||
ObjArray names = new ObjArray();
|
||||
if (cx.getOptimizationLevel() > 0) {
|
||||
(new Optimizer()).optimize(tree, cx.getOptimizationLevel());
|
||||
}
|
||||
generateCode(tree, names, classFiles);
|
||||
String generatedName = name;
|
||||
|
||||
|
@ -40,9 +40,11 @@ import org.mozilla.javascript.*;
|
||||
|
||||
public class FatBlock {
|
||||
|
||||
public FatBlock(int startNodeIndex, int endNodeIndex, Node[] statementNodes)
|
||||
public FatBlock(IRFactory irFactory, int startNodeIndex, int endNodeIndex,
|
||||
Node[] statementNodes)
|
||||
{
|
||||
itsShadowOfFormerSelf = new Block(startNodeIndex, endNodeIndex, statementNodes);
|
||||
itsShadowOfFormerSelf = new Block(irFactory, startNodeIndex,
|
||||
endNodeIndex, statementNodes);
|
||||
}
|
||||
|
||||
public Node getEndNode()
|
||||
|
@ -41,9 +41,8 @@ import java.util.*;
|
||||
|
||||
class OptFunctionNode extends FunctionNode {
|
||||
|
||||
OptFunctionNode(String name, Node statements, String className)
|
||||
{
|
||||
super(name, statements);
|
||||
OptFunctionNode(String name, String className) {
|
||||
super(name);
|
||||
itsClassName = className;
|
||||
}
|
||||
|
||||
|
@ -49,27 +49,24 @@ import java.util.Hashtable;
|
||||
class OptTransformer extends NodeTransformer {
|
||||
private Hashtable theFnClassNameList;
|
||||
|
||||
OptTransformer(Hashtable theFnClassNameList) {
|
||||
OptTransformer(IRFactory irFactory, Hashtable theFnClassNameList) {
|
||||
super(irFactory);
|
||||
this.theFnClassNameList = theFnClassNameList;
|
||||
}
|
||||
|
||||
public NodeTransformer newInstance() {
|
||||
return new OptTransformer((Hashtable) theFnClassNameList.clone());
|
||||
Hashtable listCopy = (Hashtable) theFnClassNameList.clone();
|
||||
return new OptTransformer(irFactory, listCopy);
|
||||
}
|
||||
|
||||
public IRFactory createIRFactory(TokenStream ts, Scriptable scope) {
|
||||
return new IRFactory(ts, scope);
|
||||
}
|
||||
|
||||
public Node transform(Node tree, Node enclosing, TokenStream ts,
|
||||
Scriptable scope) {
|
||||
public Node transform(Node tree, Node enclosing) {
|
||||
|
||||
// Collect all of the contained functions into a hashtable
|
||||
// so that the call optimizer can access the class name & parameter
|
||||
// count for any call it encounters
|
||||
collectContainedFunctions(tree.getFirstChild());
|
||||
|
||||
return super.transform(tree, enclosing, ts, scope);
|
||||
return super.transform(tree, enclosing);
|
||||
}
|
||||
|
||||
private int detectDirectCall(Node node, Node tree)
|
||||
|
@ -49,6 +49,10 @@ import java.util.Hashtable;
|
||||
|
||||
class Optimizer {
|
||||
|
||||
Optimizer(IRFactory irFactory) {
|
||||
this.irFactory = irFactory;
|
||||
}
|
||||
|
||||
void optimize(Node tree, int optLevel)
|
||||
{
|
||||
itsOptLevel = optLevel;
|
||||
@ -74,7 +78,7 @@ class Optimizer {
|
||||
inDirectCallFunction = theFunction.isTargetOfDirectCall();
|
||||
|
||||
Node[] theStatementNodes = buildStatementList(theFunction);
|
||||
Block[] theBlocks = Block.buildBlocks(theStatementNodes);
|
||||
Block[] theBlocks = Block.buildBlocks(irFactory, theStatementNodes);
|
||||
PrintWriter pw = null;
|
||||
try {
|
||||
if (DEBUG_OPTIMIZER) {
|
||||
@ -1040,6 +1044,7 @@ class Optimizer {
|
||||
private static final int ALWAYS_TRUE_BOOLEAN = 1;
|
||||
private static final int ALWAYS_FALSE_BOOLEAN = -1;
|
||||
|
||||
private IRFactory irFactory;
|
||||
private int itsOptLevel;
|
||||
private boolean inDirectCallFunction;
|
||||
private boolean parameterUsedInNumberContext;
|
||||
|
Loading…
Reference in New Issue
Block a user