Introduction of ScriptOrFnNode as a Node to represent scripts and a base class for FunctionNode so it can be used to store variable tables, line information, regular expressions etc. instead of using special Node properties.

This commit is contained in:
igor%mir2.org 2003-02-17 08:51:00 +00:00
parent 918c00dbae
commit 5a9259c0aa
10 changed files with 196 additions and 140 deletions

View File

@ -2021,7 +2021,7 @@ public class Context {
if (debugger != null) {
if (sourceString == null) Context.codeBug();
tree.putProp(Node.DEBUGSOURCE_PROP, sourceString);
((ScriptOrFnNode)tree).originalSource = sourceString;
}
Object result = compiler.compile(this, scope, tree,

View File

@ -38,7 +38,7 @@ package org.mozilla.javascript;
import java.util.*;
public class FunctionNode extends Node {
public class FunctionNode extends ScriptOrFnNode {
public FunctionNode(String name) {
super(TokenStream.FUNCTION);
@ -49,10 +49,6 @@ public class FunctionNode extends Node {
return functionName;
}
public VariableTable getVariableTable() {
return itsVariableTable;
}
protected void markVariableTableReady() { }
public boolean requiresActivation() {
@ -99,10 +95,9 @@ public class FunctionNode extends Node {
}
public int getParameterCount() {
return itsVariableTable.getParameterCount();
return getVariableTable().getParameterCount();
}
protected VariableTable itsVariableTable;
protected boolean itsNeedsActivation;
protected boolean itsCheckThis;
protected int itsFunctionType;

View File

@ -56,15 +56,15 @@ public class IRFactory {
createScript(Object body, VariableTable vars, String sourceName,
int baseLineno, int endLineno, String source)
{
Node result = Node.newString(TokenStream.SCRIPT, sourceName);
ScriptOrFnNode result = new ScriptOrFnNode(TokenStream.SCRIPT);
result.variableTable = vars;
result.encodedSource = source;
result.sourceName = sourceName;
result.baseLineno = baseLineno;
result.endLineno = endLineno;
Node children = ((Node) body).getFirstChild();
if (children != null) { result.addChildrenToBack(children); }
result.putProp(Node.VARS_PROP, vars);
result.putProp(Node.SOURCENAME_PROP, sourceName);
result.putIntProp(Node.BASE_LINENO_PROP, baseLineno);
result.putIntProp(Node.END_LINENO_PROP, endLineno);
if (source != null)
result.putProp(Node.SOURCE_PROP, source);
return result;
}
@ -212,14 +212,13 @@ public class IRFactory {
name = "";
}
FunctionNode f = compiler.createFunctionNode(this, name);
f.itsVariableTable = vars;
f.variableTable = vars;
f.encodedSource = source;
f.sourceName = sourceName;
f.baseLineno = baseLineno;
f.endLineno = endLineno;
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);
if (source != null)
f.putProp(Node.SOURCE_PROP, source);
Node result = Node.newString(TokenStream.FUNCTION, name);
result.putProp(Node.FUNCTION_PROP, f);
return result;

View File

@ -87,21 +87,24 @@ public class Interpreter {
itsData.itsFunctionType = f.getFunctionType();
generateFunctionICode(cx, scope, f);
return createFunction(cx, scope, itsData, false);
}
generateScriptICode(cx, scope, tree);
} else {
generateScriptICode(cx, scope, (ScriptOrFnNode)tree);
return new InterpretedScript(cx, itsData);
}
}
private void generateScriptICode(Context cx, Scriptable scope, Node tree) {
itsSourceFile = (String) tree.getProp(Node.SOURCENAME_PROP);
private void
generateScriptICode(Context cx, Scriptable scope, ScriptOrFnNode tree)
{
itsSourceFile = tree.getSourceName();
itsData.itsSourceFile = itsSourceFile;
debugSource = (String) tree.getProp(Node.DEBUGSOURCE_PROP);
debugSource = tree.getOriginalSource();
generateNestedFunctions(cx, scope, tree);
generateRegExpLiterals(cx, scope, tree);
itsVariableTable = (VariableTable)tree.getProp(Node.VARS_PROP);
itsVariableTable = tree.getVariableTable();
generateICodeFromTree(tree);
if (Context.printICode) dumpICode(itsData);
@ -116,7 +119,7 @@ public class Interpreter {
// check if function has own source, which is the case
// with Function(...)
String savedSource = debugSource;
debugSource = (String)theFunction.getProp(Node.DEBUGSOURCE_PROP);
debugSource = theFunction.getOriginalSource();
if (debugSource == null) {
debugSource = savedSource;
}
@ -130,9 +133,8 @@ public class Interpreter {
generateICodeFromTree(theFunction.getLastChild());
itsData.itsName = theFunction.getFunctionName();
itsData.itsSourceFile = (String) theFunction.getProp(
Node.SOURCENAME_PROP);
itsData.itsSource = (String)theFunction.getProp(Node.SOURCE_PROP);
itsData.itsSourceFile = theFunction.getSourceName();
itsData.itsSource = theFunction.getEncodedSource();
if (Context.printICode) dumpICode(itsData);
if (cx.debugger != null) {
@ -167,25 +169,20 @@ public class Interpreter {
private void generateRegExpLiterals(Context cx,
Scriptable scope,
Node tree)
ScriptOrFnNode tree)
{
ObjArray regexps = (ObjArray)tree.getProp(Node.REGEXP_PROP);
if (regexps == null) return;
int N = tree.getRegexpCount();
if (N == 0) return;
RegExpProxy rep = cx.getRegExpProxy();
if (rep == null) {
throw cx.reportRuntimeError0("msg.no.regexp");
}
int N = regexps.size();
Object[] array = new Object[N];
for (int i = 0; i != N; i++) {
Node regexp = (Node) regexps.get(i);
Node left = regexp.getFirstChild();
Node right = regexp.getLastChild();
String source = left.getString();
String global = (left != right) ? right.getString() : null;
array[i] = rep.newRegExp(cx, scope, source, global, false);
regexp.putIntProp(Node.REGEXP_PROP, i);
String string = tree.getRegexpString(i);
String flags = tree.getRegexpFlags(i);
array[i] = rep.newRegExp(cx, scope, string, flags, false);
}
itsData.itsRegExpLiterals = array;
}
@ -996,8 +993,7 @@ public class Interpreter {
break;
case TokenStream.REGEXP : {
Node regexp = (Node) node.getProp(Node.REGEXP_PROP);
int index = regexp.getExistingIntProp(Node.REGEXP_PROP);
int index = node.getExistingIntProp(Node.REGEXP_PROP);
iCodeTop = addByte(TokenStream.REGEXP, iCodeTop);
iCodeTop = addIndex(index, iCodeTop);
itsStackDepth++;

View File

@ -277,19 +277,16 @@ public class Node implements Cloneable {
LOCAL_PROP = 7,
CODEOFFSET_PROP = 8,
FIXUPS_PROP = 9,
VARS_PROP = 10,
USES_PROP = 11,
REGEXP_PROP = 12,
CASES_PROP = 13,
DEFAULT_PROP = 14,
CASEARRAY_PROP = 15,
SOURCENAME_PROP = 16,
SOURCE_PROP = 17,
TYPE_PROP = 18,
SPECIAL_PROP_PROP = 19,
LABEL_PROP = 20,
FINALLY_PROP = 21,
LOCALCOUNT_PROP = 22,
USES_PROP = 10,
REGEXP_PROP = 11,
CASES_PROP = 12,
DEFAULT_PROP = 13,
CASEARRAY_PROP = 14,
TYPE_PROP = 15,
SPECIAL_PROP_PROP = 16,
LABEL_PROP = 17,
FINALLY_PROP = 18,
LOCALCOUNT_PROP = 19,
/*
the following properties are defined and manipulated by the
optimizer -
@ -304,16 +301,13 @@ public class Node implements Cloneable {
matches.
*/
TARGETBLOCK_PROP = 23,
VARIABLE_PROP = 24,
LASTUSE_PROP = 25,
ISNUMBER_PROP = 26,
DIRECTCALL_PROP = 27,
TARGETBLOCK_PROP = 20,
VARIABLE_PROP = 21,
LASTUSE_PROP = 22,
ISNUMBER_PROP = 23,
DIRECTCALL_PROP = 24,
BASE_LINENO_PROP = 28,
END_LINENO_PROP = 29,
SPECIALCALL_PROP = 30,
DEBUGSOURCE_PROP = 31;
SPECIALCALL_PROP = 25;
public static final int // this value of the ISNUMBER_PROP specifies
BOTH = 0, // which of the children are Number types
@ -334,14 +328,11 @@ public class Node implements Cloneable {
case LOCAL_PROP: return "local";
case CODEOFFSET_PROP: return "codeoffset";
case FIXUPS_PROP: return "fixups";
case VARS_PROP: return "vars";
case USES_PROP: return "uses";
case REGEXP_PROP: return "regexp";
case CASES_PROP: return "cases";
case DEFAULT_PROP: return "default";
case CASEARRAY_PROP: return "casearray";
case SOURCENAME_PROP: return "sourcename";
case SOURCE_PROP: return "source";
case TYPE_PROP: return "type";
case SPECIAL_PROP_PROP: return "special_prop";
case LABEL_PROP: return "label";
@ -354,10 +345,7 @@ public class Node implements Cloneable {
case ISNUMBER_PROP: return "isnumber";
case DIRECTCALL_PROP: return "directcall";
case BASE_LINENO_PROP: return "base_lineno";
case END_LINENO_PROP: return "end_lineno";
case SPECIALCALL_PROP: return "specialcall";
case DEBUGSOURCE_PROP: return "debugsource";
default: Context.codeBug();
}
@ -458,22 +446,29 @@ public class Node implements Cloneable {
if (this instanceof StringNode) {
sb.append(' ');
sb.append(getString());
} else {
switch (type) {
case TokenStream.TARGET:
sb.append(' ');
sb.append(hashCode());
break;
case TokenStream.NUMBER:
sb.append(' ');
sb.append(getDouble());
break;
case TokenStream.FUNCTION:
} else if (this instanceof ScriptOrFnNode) {
ScriptOrFnNode sof = (ScriptOrFnNode)this;
if (this instanceof FunctionNode) {
FunctionNode fn = (FunctionNode)this;
sb.append(' ');
sb.append(fn.getFunctionName());
break;
}
sb.append(" [source name: ");
sb.append(sof.getSourceName());
sb.append("] [encoded source length: ");
String encodedSource = sof.getEncodedSource();
sb.append(encodedSource != null ? encodedSource.length() : 0);
sb.append("] [base line: ");
sb.append(sof.getBaseLineno());
sb.append("] [end line: ");
sb.append(sof.getEndLineno());
sb.append(']');
} else if (type == TokenStream.TARGET) {
sb.append(' ');
sb.append(hashCode());
} else if (type == TokenStream.NUMBER) {
sb.append(' ');
sb.append(getDouble());
}
if (intDatum != -1) {
sb.append(' ');
@ -492,9 +487,6 @@ public class Node implements Cloneable {
case FIXUPS_PROP : // can't add this as it recurses
sb.append("fixups property");
break;
case SOURCE_PROP : // can't add this as it has unprintables
sb.append("source property");
break;
case TARGETBLOCK_PROP : // can't add this as it recurses
sb.append("target block property");
break;

View File

@ -396,15 +396,14 @@ public class NodeTransformer {
case TokenStream.REGEXP:
{
ObjArray regexps = (ObjArray) tree.getProp(Node.REGEXP_PROP);
if (regexps == null) {
regexps = new ObjArray();
tree.putProp(Node.REGEXP_PROP, regexps);
}
regexps.add(node);
Node left = node.getFirstChild();
Node right = node.getLastChild();
String string = left.getString();
String flags = (left != right) ? right.getString() : null;
int index = ((ScriptOrFnNode)tree).addRegexp(string, flags);
Node n = new Node(TokenStream.REGEXP);
iter.replaceCurrent(n);
n.putProp(Node.REGEXP_PROP, node);
n.putIntProp(Node.REGEXP_PROP, index);
break;
}
@ -613,18 +612,14 @@ public class NodeTransformer {
}
protected VariableTable getVariableTable(Node tree) {
if (inFunction) {
return ((FunctionNode)tree).getVariableTable();
} else {
return (VariableTable)(tree.getProp(Node.VARS_PROP));
}
return ((ScriptOrFnNode)tree).getVariableTable();
}
private void
reportError(String messageId, Object[] messageArgs, Node stmt, Node tree)
{
int lineno = stmt.getLineno();
String sourceName = (String)tree.getProp(Node.SOURCENAME_PROP);
String sourceName = ((ScriptOrFnNode)tree).getSourceName();
irFactory.ts.reportSyntaxError(true, messageId, messageArgs,
sourceName, lineno, null, 0);
}

View File

@ -0,0 +1,84 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape 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/NPL/
*
* 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 Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Igor Bukanov
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
package org.mozilla.javascript;
public class ScriptOrFnNode extends Node {
public ScriptOrFnNode(int nodeType) {
super(nodeType);
}
public final VariableTable getVariableTable() { return variableTable; }
public final String getEncodedSource() { return encodedSource; }
public final String getOriginalSource() { return originalSource; }
public final String getSourceName() { return sourceName; }
public final int getBaseLineno() { return baseLineno; }
public final int getEndLineno() { return baseLineno; }
public final int getRegexpCount() {
if (regexps == null) { return 0; }
return regexps.size() / 2;
}
public final String getRegexpString(int index) {
return (String)regexps.get(index * 2);
}
public final String getRegexpFlags(int index) {
return (String)regexps.get(index * 2 + 1);
}
public final int addRegexp(String string, String flags) {
if (regexps == null) { regexps = new ObjArray(); }
regexps.add(string);
regexps.add(flags);
return (regexps.size() - 2) / 2;
}
VariableTable variableTable;
String encodedSource;
String originalSource;
String sourceName;
int baseLineno = -1;
int endLineno = -1;
private ObjArray regexps;
}

View File

@ -397,8 +397,9 @@ public class Codegen extends Interpreter {
itsSourceFile = null;
// default is to generate debug info
if (!cx.isGeneratingDebugChanged() || cx.isGeneratingDebug())
itsSourceFile = (String) tree.getProp(Node.SOURCENAME_PROP);
if (!cx.isGeneratingDebugChanged() || cx.isGeneratingDebug()) {
itsSourceFile = ((ScriptOrFnNode)tree).getSourceName();
}
version = cx.getLanguageVersion();
optLevel = cx.getOptimizationLevel();
inFunction = tree.getType() == TokenStream.FUNCTION;
@ -496,7 +497,7 @@ public class Codegen extends Interpreter {
// better be a script
if (tree.getType() != TokenStream.SCRIPT)
badTree();
vars = (VariableTable) tree.getProp(Node.VARS_PROP);
vars = ((ScriptOrFnNode)tree).getVariableTable();
boolean isPrimary = nameHelper.getTargetExtends() == null &&
nameHelper.getTargetImplements() == null;
this.name = getScriptClassName(null, isPrimary);
@ -513,7 +514,7 @@ public class Codegen extends Interpreter {
"[Ljava/lang/Object;)Ljava/lang/Object;",
1, false, true);
generatePrologue(cx, tree, false, -1);
int linenum = tree.getIntProp(Node.END_LINENO_PROP, -1);
int linenum = ((ScriptOrFnNode)tree).getEndLineno();
if (linenum != -1)
classFile.addLineNumberEntry((short)linenum);
tree.addChildToBack(new Node(TokenStream.RETURN));
@ -1116,12 +1117,7 @@ public class Codegen extends Interpreter {
{
trivialInit = true;
boolean inCtor = false;
VariableTable vars;
if (tree instanceof OptFunctionNode)
vars = ((OptFunctionNode)tree).getVariableTable();
else
vars = (VariableTable) tree.getProp(Node.VARS_PROP);
VariableTable vars = ((ScriptOrFnNode)tree).getVariableTable();
if (methodName.equals("<init>")) {
inCtor = true;
setNonTrivialInit(methodName);
@ -1192,10 +1188,10 @@ public class Codegen extends Interpreter {
}
// precompile all regexp literals
ObjArray regexps = (ObjArray) tree.getProp(Node.REGEXP_PROP);
if (regexps != null) {
int regexpCount = ((ScriptOrFnNode)tree).getRegexpCount();
if (regexpCount != 0) {
setNonTrivialInit(methodName);
generateRegExpLiterals(regexps, inCtor);
generateRegExpLiterals((ScriptOrFnNode)tree, inCtor);
}
if (tree instanceof OptFunctionNode) {
@ -1229,7 +1225,7 @@ public class Codegen extends Interpreter {
// Change Parser if changing ordering.
if (cx.isGeneratingSource()) {
String source = (String) tree.getProp(Node.SOURCE_PROP);
String source = ((ScriptOrFnNode)tree).getEncodedSource();
if (source != null && source.length() < 65536) {
short flags = ClassFileWriter.ACC_PUBLIC
| ClassFileWriter.ACC_STATIC;
@ -1274,12 +1270,10 @@ public class Codegen extends Interpreter {
}
}
private void generateRegExpLiterals(ObjArray regexps, boolean inCtor) {
for (int i=0; i < regexps.size(); i++) {
Node regexp = (Node) regexps.get(i);
StringBuffer sb = new StringBuffer("_re");
sb.append(i);
String fieldName = sb.toString();
private void generateRegExpLiterals(ScriptOrFnNode tree, boolean inCtor) {
int regexpCount = tree.getRegexpCount();
for (int i=0; i < regexpCount; i++) {
String fieldName = getRegexpFieldName(i);
short flags = ClassFileWriter.ACC_PRIVATE;
if (inCtor)
flags |= ClassFileWriter.ACC_FINAL;
@ -1293,13 +1287,12 @@ public class Codegen extends Interpreter {
aload(contextLocal); // load 'context'
aload(variableObjectLocal); // load 'scope'
Node left = regexp.getFirstChild();
push(left.getString());
Node right = regexp.getLastChild();
if (left == right) {
push(tree.getRegexpString(i));
String regexpFlags = tree.getRegexpFlags(i);
if (regexpFlags == null) {
addByteCode(ByteCode.ACONST_NULL);
} else {
push(right.getString());
push(regexpFlags);
}
push(0);
@ -1309,14 +1302,16 @@ public class Codegen extends Interpreter {
"Lorg/mozilla/javascript/Scriptable;" +
"Ljava/lang/String;Ljava/lang/String;Z)",
"V");
regexp.putProp(Node.REGEXP_PROP, fieldName);
classFile.add(ByteCode.PUTFIELD,
classFile.fullyQualifiedForm(this.name),
fieldName, "Lorg/mozilla/javascript/regexp/NativeRegExp;");
}
}
private static String getRegexpFieldName(int i) {
return "_re" + i;
}
/**
* Generate the prologue for a function or script.
*
@ -3170,8 +3165,8 @@ public class Codegen extends Interpreter {
}
private void visitObject(Node node) {
Node regexp = (Node) node.getProp(Node.REGEXP_PROP);
String fieldName = (String)(regexp.getProp(Node.REGEXP_PROP));
int i = node.getExistingIntProp(Node.REGEXP_PROP);
String fieldName = getRegexpFieldName(i);
aload(funObjLocal);
classFile.add(ByteCode.GETFIELD,
classFile.fullyQualifiedForm(this.name),

View File

@ -48,17 +48,18 @@ class OptFunctionNode extends FunctionNode {
protected void markVariableTableReady() {
super.markVariableTableReady();
int N = itsVariableTable.size();
int parameterCount = itsVariableTable.getParameterCount();
VariableTable vars = getVariableTable();
int N = vars.size();
int parameterCount = getParameterCount();
optVars = new OptLocalVariable[N];
for (int i = 0; i != N; ++i) {
String name = itsVariableTable.getVariable(i);
String name = vars.getVariable(i);
optVars[i] = new OptLocalVariable(name, i < parameterCount);
}
}
String getDirectCallParameterSignature() {
int pCount = itsVariableTable.getParameterCount();
int pCount = getParameterCount();
switch (pCount) {
case 0: return ZERO_PARAM_SIG;
case 1: return ONE_PARAM_SIG;
@ -134,7 +135,7 @@ class OptFunctionNode extends FunctionNode {
}
OptLocalVariable getVar(String name) {
int index = itsVariableTable.getOrdinal(name);
int index = getVariableTable().getOrdinal(name);
if (index < 0) { return null; }
return optVars[index];
}

View File

@ -163,12 +163,11 @@ class OptTransformer extends NodeTransformer {
}
/*
if (oldFn != null) {
int line = fnNode.getIntProp(Node.BASE_LINENO_PROP, 0);
Object[] errArgs = { name };
Context.reportWarning(
Context.getMessage("msg.fn.redecl", errArgs),
(String) fnNode.getProp(Node.SOURCENAME_PROP),
line, null, 0);
fnNode.getSourceName(),
fnNode.getBaseLineno(), null, 0);
}
*/
theFnClassNameList.put(name, fnNode);