Inline small functions used for code generation to produce intepreter or JVM bytecode for particular parser tree node: they just add to jar file size without readability benefits.

This commit is contained in:
igor%mir2.org 2004-09-07 09:08:31 +00:00
Родитель 96aed722f8
Коммит d29f6cb477
3 изменённых файлов: 632 добавлений и 709 удалений

Просмотреть файл

@ -535,9 +535,11 @@ public class Interpreter
Node child = node.getFirstChild(); Node child = node.getFirstChild();
switch (type) { switch (type) {
case Token.FUNCTION: { case Token.FUNCTION:
{
int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP); int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP);
int fnType = scriptOrFn.getFunctionNode(fnIndex).getFunctionType(); int fnType = scriptOrFn.getFunctionNode(fnIndex).
getFunctionType();
// Only function expressions or function expression // Only function expressions or function expression
// statements needs closure code creating new function // statements needs closure code creating new function
// object on stack as function statements are initialized // object on stack as function statements are initialized
@ -551,8 +553,8 @@ public class Interpreter
throw Kit.codeBug(); throw Kit.codeBug();
} }
} }
break;
} }
break;
case Token.SCRIPT: case Token.SCRIPT:
case Token.LABEL: case Token.LABEL:
@ -600,7 +602,32 @@ public class Interpreter
break; break;
case Token.SWITCH: case Token.SWITCH:
visitSwitch((Node.Jump)node); updateLineNumber(node);
// See comments in IRFactory.createSwitch() for description
// of SWITCH node
{
Node switchNode = (Node.Jump)node;
visitExpression(child, 0);
for (Node.Jump caseNode = (Node.Jump)child.getNext();
caseNode != null;
caseNode = (Node.Jump)caseNode.getNext())
{
if (caseNode.getType() != Token.CASE)
throw badTree(caseNode);
Node test = caseNode.getFirstChild();
addIcode(Icode_DUP);
stackChange(1);
visitExpression(test, 0);
addToken(Token.SHEQ);
stackChange(-1);
// If true, Icode_IFEQ_POP will jump and remove case
// value from stack
addGoto(caseNode.target, Icode_IFEQ_POP);
stackChange(-1);
}
addIcode(Icode_POP);
stackChange(-1);
}
break; break;
case Token.TARGET: case Token.TARGET:
@ -608,25 +635,28 @@ public class Interpreter
break; break;
case Token.IFEQ : case Token.IFEQ :
case Token.IFNE : { case Token.IFNE :
{
Node.Target target = ((Node.Jump)node).target; Node.Target target = ((Node.Jump)node).target;
visitExpression(child, 0); visitExpression(child, 0);
addGoto(target, type); addGoto(target, type);
stackChange(-1); stackChange(-1);
break;
} }
break;
case Token.GOTO: { case Token.GOTO:
{
Node.Target target = ((Node.Jump)node).target; Node.Target target = ((Node.Jump)node).target;
addGoto(target, type); addGoto(target, type);
break;
} }
break;
case Token.JSR: { case Token.JSR:
{
Node.Target target = ((Node.Jump)node).target; Node.Target target = ((Node.Jump)node).target;
addGoto(target, Icode_GOSUB); addGoto(target, Icode_GOSUB);
break;
} }
break;
case Token.FINALLY: case Token.FINALLY:
{ {
@ -652,7 +682,33 @@ public class Interpreter
break; break;
case Token.TRY: case Token.TRY:
visitTry((Node.Jump)node, child); {
Node.Jump tryNode = (Node.Jump)node;
int exceptionObjectLocal = getLocalBlockRef(tryNode);
int tryStart = itsICodeTop;
while (child != null) {
visitStatement(child);
child = child.getNext();
}
Node.Target catchTarget = tryNode.target;
if (catchTarget != null) {
int catchStartPC
= itsLabelTable[getTargetLabel(catchTarget)];
addExceptionHandler(
tryStart, catchStartPC, catchStartPC,
false, itsWithDepth, exceptionObjectLocal);
}
Node.Target finallyTarget = tryNode.getFinally();
if (finallyTarget != null) {
int finallyStartPC
= itsLabelTable[getTargetLabel(finallyTarget)];
addExceptionHandler(
tryStart, finallyStartPC, finallyStartPC,
true, itsWithDepth, exceptionObjectLocal);
}
}
break; break;
case Token.CATCH_SCOPE: case Token.CATCH_SCOPE:
@ -722,7 +778,8 @@ public class Interpreter
int savedStackDepth = itsStackDepth; int savedStackDepth = itsStackDepth;
switch (type) { switch (type) {
case Token.FUNCTION: { case Token.FUNCTION:
{
int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP); int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP);
FunctionNode fn = scriptOrFn.getFunctionNode(fnIndex); FunctionNode fn = scriptOrFn.getFunctionNode(fnIndex);
// See comments in visitStatement for Token.FUNCTION case // See comments in visitStatement for Token.FUNCTION case
@ -731,17 +788,19 @@ public class Interpreter
} }
addIndexOp(Icode_CLOSURE_EXPR, fnIndex); addIndexOp(Icode_CLOSURE_EXPR, fnIndex);
stackChange(1); stackChange(1);
break;
} }
break;
case Token.LOCAL_LOAD: { case Token.LOCAL_LOAD:
{
int localIndex = getLocalBlockRef(node); int localIndex = getLocalBlockRef(node);
addIndexOp(Token.LOCAL_LOAD, localIndex); addIndexOp(Token.LOCAL_LOAD, localIndex);
stackChange(1); stackChange(1);
break;
} }
break;
case Token.COMMA: { case Token.COMMA:
{
Node lastChild = node.getLastChild(); Node lastChild = node.getLastChild();
while (child != lastChild) { while (child != lastChild) {
visitExpression(child, 0); visitExpression(child, 0);
@ -751,8 +810,8 @@ public class Interpreter
} }
// Preserve tail context flag if any // Preserve tail context flag if any
visitExpression(child, contextFlags & ECF_TAIL); visitExpression(child, contextFlags & ECF_TAIL);
break;
} }
break;
case Token.USE_STACK: case Token.USE_STACK:
// Indicates that stack was modified externally, // Indicates that stack was modified externally,
@ -763,11 +822,50 @@ public class Interpreter
case Token.CALL: case Token.CALL:
case Token.NEW: case Token.NEW:
case Token.REF_CALL: case Token.REF_CALL:
visitCall(node, contextFlags); {
if (type == Token.NEW) {
visitExpression(child, 0);
} else {
generateCallFunAndThis(child);
}
int argCount = 0;
while ((child = child.getNext()) != null) {
visitExpression(child, 0);
++argCount;
}
int callType = node.getIntProp(Node.SPECIALCALL_PROP,
Node.NON_SPECIALCALL);
if (callType != Node.NON_SPECIALCALL) {
// embed line number and source filename
addIndexOp(Icode_CALLSPECIAL, argCount);
addUint8(callType);
addUint8(type == Token.NEW ? 1 : 0);
addUint16(itsLineNumber & 0xFFFF);
} else {
if (type == Token.CALL) {
if ((contextFlags & ECF_TAIL) != 0) {
type = Icode_TAIL_CALL;
}
}
addIndexOp(type, argCount);
}
// adjust stack
if (type == Token.NEW) {
// f, args -> results
stackChange(-argCount);
} else {
// f, thisObj, args -> results
stackChange(-1 - argCount);
}
if (argCount > itsData.itsMaxCalleeArgs) {
itsData.itsMaxCalleeArgs = argCount;
}
}
break; break;
case Token.AND: case Token.AND:
case Token.OR: { case Token.OR:
{
visitExpression(child, 0); visitExpression(child, 0);
addIcode(Icode_DUP); addIcode(Icode_DUP);
stackChange(1); stackChange(1);
@ -781,10 +879,11 @@ public class Interpreter
// Preserve tail context flag if any // Preserve tail context flag if any
visitExpression(child, contextFlags & ECF_TAIL); visitExpression(child, contextFlags & ECF_TAIL);
resolveForwardGoto(afterSecondJumpStart); resolveForwardGoto(afterSecondJumpStart);
break;
} }
break;
case Token.HOOK: { case Token.HOOK:
{
Node ifThen = child.getNext(); Node ifThen = child.getNext();
Node ifElse = ifThen.getNext(); Node ifElse = ifThen.getNext();
visitExpression(child, 0); visitExpression(child, 0);
@ -800,19 +899,26 @@ public class Interpreter
// Preserve tail context flag if any // Preserve tail context flag if any
visitExpression(ifElse, contextFlags & ECF_TAIL); visitExpression(ifElse, contextFlags & ECF_TAIL);
resolveForwardGoto(afterElseJumpStart); resolveForwardGoto(afterElseJumpStart);
break;
} }
break;
case Token.GETPROP: case Token.GETPROP:
visitGetProp(node, child); visitExpression(child, 0);
child = child.getNext();
addStringOp(Token.GETPROP, child.getString());
break; break;
case Token.GETELEM: case Token.GETELEM:
visitGetElem(node, child); visitExpression(child, 0);
child = child.getNext();
visitExpression(child, 0);
addToken(Token.GETELEM);
stackChange(-1);
break; break;
case Token.GET_REF: case Token.GET_REF:
visitGetRef(node, child); visitExpression(child, 0);
addToken(Token.GET_REF);
break; break;
case Token.DELPROP: case Token.DELPROP:
@ -861,7 +967,8 @@ public class Interpreter
break; break;
case Token.SETPROP: case Token.SETPROP:
case Token.SETPROP_OP: { case Token.SETPROP_OP:
{
visitExpression(child, 0); visitExpression(child, 0);
child = child.getNext(); child = child.getNext();
String property = child.getString(); String property = child.getString();
@ -876,8 +983,8 @@ public class Interpreter
visitExpression(child, 0); visitExpression(child, 0);
addStringOp(Token.SETPROP, property); addStringOp(Token.SETPROP, property);
stackChange(-1); stackChange(-1);
break;
} }
break;
case Token.SETELEM: case Token.SETELEM:
case Token.SETELEM_OP: case Token.SETELEM_OP:
@ -914,17 +1021,19 @@ public class Interpreter
stackChange(-1); stackChange(-1);
break; break;
case Token.SETNAME: { case Token.SETNAME:
{
String name = child.getString(); String name = child.getString();
visitExpression(child, 0); visitExpression(child, 0);
child = child.getNext(); child = child.getNext();
visitExpression(child, 0); visitExpression(child, 0);
addStringOp(Token.SETNAME, name); addStringOp(Token.SETNAME, name);
stackChange(-1); stackChange(-1);
break;
} }
break;
case Token.TYPEOFNAME: { case Token.TYPEOFNAME:
{
String name = node.getString(); String name = node.getString();
int index = -1; int index = -1;
// use typeofname if an activation frame exists // use typeofname if an activation frame exists
@ -939,8 +1048,8 @@ public class Interpreter
stackChange(1); stackChange(1);
addToken(Token.TYPEOF); addToken(Token.TYPEOF);
} }
break;
} }
break;
case Token.BINDNAME: case Token.BINDNAME:
case Token.NAME: case Token.NAME:
@ -955,10 +1064,36 @@ public class Interpreter
break; break;
case Token.NUMBER: case Token.NUMBER:
visitNumber(node); {
double num = node.getDouble();
int inum = (int)num;
if (inum == num) {
if (inum == 0) {
addIcode(Icode_ZERO);
// Check for negative zero
if (1.0 / num < 0.0) {
addToken(Token.NEG);
}
} else if (inum == 1) {
addIcode(Icode_ONE);
} else if ((short)inum == inum) {
addIcode(Icode_SHORTNUMBER);
// write short as uin16 bit pattern
addUint16(inum & 0xFFFF);
} else {
addIcode(Icode_INTNUMBER);
addInt(inum);
}
} else {
int index = getDoubleIndex(num);
addIndexOp(Token.NUMBER, index);
}
stackChange(1);
}
break; break;
case Token.GETVAR: { case Token.GETVAR:
{
String name = node.getString(); String name = node.getString();
if (itsData.itsNeedsActivation) { if (itsData.itsNeedsActivation) {
// SETVAR handled this by turning into a SETPROP, but // SETVAR handled this by turning into a SETPROP, but
@ -973,10 +1108,11 @@ public class Interpreter
addVarOp(Token.GETVAR, index); addVarOp(Token.GETVAR, index);
stackChange(1); stackChange(1);
} }
break;
} }
break;
case Token.SETVAR: { case Token.SETVAR:
{
if (itsData.itsNeedsActivation) { if (itsData.itsNeedsActivation) {
child.setType(Token.BINDNAME); child.setType(Token.BINDNAME);
node.setType(Token.SETNAME); node.setType(Token.SETNAME);
@ -988,8 +1124,8 @@ public class Interpreter
int index = scriptOrFn.getParamOrVarIndex(name); int index = scriptOrFn.getParamOrVarIndex(name);
addVarOp(Token.SETVAR, index); addVarOp(Token.SETVAR, index);
} }
break;
} }
break;
case Token.NULL: case Token.NULL:
case Token.THIS: case Token.THIS:
@ -1006,24 +1142,26 @@ public class Interpreter
stackChange(1); stackChange(1);
break; break;
case Token.REGEXP: { case Token.REGEXP:
{
int index = node.getExistingIntProp(Node.REGEXP_PROP); int index = node.getExistingIntProp(Node.REGEXP_PROP);
addIndexOp(Token.REGEXP, index); addIndexOp(Token.REGEXP, index);
stackChange(1); stackChange(1);
break;
} }
break;
case Token.ARRAYLIT: case Token.ARRAYLIT:
case Token.OBJECTLIT: case Token.OBJECTLIT:
visitLiteral(node, child); visitLiteral(node, child);
break; break;
case Token.SPECIAL_REF: { case Token.SPECIAL_REF:
visitExpression(child, 0); {
String special = (String)node.getProp(Node.SPECIAL_PROP_PROP); String special = (String)node.getProp(Node.SPECIAL_PROP_PROP);
visitExpression(child, 0);
addStringOp(Token.SPECIAL_REF, special); addStringOp(Token.SPECIAL_REF, special);
break;
} }
break;
case Token.XML_REF: case Token.XML_REF:
visitExpression(child, 0); visitExpression(child, 0);
@ -1031,7 +1169,16 @@ public class Interpreter
break; break;
case Token.DOTQUERY: case Token.DOTQUERY:
visitDotQery(node, child); {
int queryPC;
updateLineNumber(node);
visitExpression(child, 0);
addIcode(Icode_ENTERDQ);
stackChange(-1);
queryPC = itsICodeTop;
visitExpression(child.getNext(), 0);
addBackwardGoto(Icode_LEAVEDQ, queryPC);
}
break; break;
case Token.DEFAULTNAMESPACE : case Token.DEFAULTNAMESPACE :
@ -1043,16 +1190,16 @@ public class Interpreter
addToken(type); addToken(type);
break; break;
case Token.COLONCOLON : { case Token.COLONCOLON :
{
if (child.getType() != Token.STRING) if (child.getType() != Token.STRING)
throw badTree(child); throw badTree(child);
String namespace = child.getString(); String namespace = child.getString();
child = child.getNext(); child = child.getNext();
visitExpression(child, 0); visitExpression(child, 0);
addStringOp(Token.COLONCOLON, namespace); addStringOp(Token.COLONCOLON, namespace);
break;
} }
break;
default: default:
throw badTree(node); throw badTree(node);
@ -1062,103 +1209,6 @@ public class Interpreter
} }
} }
private void visitSwitch(Node.Jump switchNode)
{
// See comments in IRFactory.createSwitch() for description
// of SWITCH node
updateLineNumber(switchNode);
Node child = switchNode.getFirstChild();
visitExpression(child, 0);
for (Node.Jump caseNode = (Node.Jump)child.getNext();
caseNode != null;
caseNode = (Node.Jump)caseNode.getNext())
{
if (caseNode.getType() != Token.CASE)
throw badTree(caseNode);
Node test = caseNode.getFirstChild();
addIcode(Icode_DUP);
stackChange(1);
visitExpression(test, 0);
addToken(Token.SHEQ);
stackChange(-1);
// If true, Icode_IFEQ_POP will jump and remove case value
// from stack
addGoto(caseNode.target, Icode_IFEQ_POP);
stackChange(-1);
}
addIcode(Icode_POP);
stackChange(-1);
}
private void visitTry(Node.Jump tryNode, Node child)
{
int tryStart = itsICodeTop;
while (child != null) {
visitStatement(child);
child = child.getNext();
}
int exceptionObjectLocal = getLocalBlockRef(tryNode);
Node.Target catchTarget = tryNode.target;
if (catchTarget != null) {
int catchStartPC = itsLabelTable[getTargetLabel(catchTarget)];
addExceptionHandler(tryStart, catchStartPC, catchStartPC,
false, itsWithDepth, exceptionObjectLocal);
}
Node.Target finallyTarget = tryNode.getFinally();
if (finallyTarget != null) {
int finallyStartPC = itsLabelTable[getTargetLabel(finallyTarget)];
addExceptionHandler(tryStart, finallyStartPC, finallyStartPC,
true, itsWithDepth, exceptionObjectLocal);
}
}
private void visitCall(Node node, int contextFlags)
{
int type = node.getType();
Node child = node.getFirstChild();
if (type == Token.NEW) {
visitExpression(child, 0);
} else {
generateCallFunAndThis(child);
}
int argCount = 0;
while ((child = child.getNext()) != null) {
visitExpression(child, 0);
++argCount;
}
int callType = node.getIntProp(Node.SPECIALCALL_PROP,
Node.NON_SPECIALCALL);
if (callType != Node.NON_SPECIALCALL) {
// embed line number and source filename
addIndexOp(Icode_CALLSPECIAL, argCount);
addUint8(callType);
addUint8(type == Token.NEW ? 1 : 0);
addUint16(itsLineNumber & 0xFFFF);
} else {
if (type == Token.CALL) {
if ((contextFlags & ECF_TAIL) != 0) {
type = Icode_TAIL_CALL;
}
}
addIndexOp(type, argCount);
}
// adjust stack
if (type == Token.NEW) {
// f, args -> results
stackChange(-argCount);
} else {
// f, thisObj, args -> results
stackChange(-1 - argCount);
}
if (argCount > itsData.itsMaxCalleeArgs)
itsData.itsMaxCalleeArgs = argCount;
}
private void generateCallFunAndThis(Node left) private void generateCallFunAndThis(Node left)
{ {
// Generate code to place on stack function and thisObj // Generate code to place on stack function and thisObj
@ -1198,29 +1248,6 @@ public class Interpreter
} }
} }
private void visitGetProp(Node node, Node child)
{
visitExpression(child, 0);
child = child.getNext();
String property = child.getString();
addStringOp(Token.GETPROP, property);
}
private void visitGetElem(Node node, Node child)
{
visitExpression(child, 0);
child = child.getNext();
visitExpression(child, 0);
addToken(Token.GETELEM);
stackChange(-1);
}
private void visitGetRef(Node node, Node child)
{
visitExpression(child, 0);
addToken(Token.GET_REF);
}
private void visitIncDec(Node node, Node child) private void visitIncDec(Node node, Node child)
{ {
int incrDecrMask = node.getExistingIntProp(Node.INCRDECR_PROP); int incrDecrMask = node.getExistingIntProp(Node.INCRDECR_PROP);
@ -1279,34 +1306,6 @@ public class Interpreter
} }
} }
private void visitNumber(Node node)
{
double num = node.getDouble();
int inum = (int)num;
if (inum == num) {
if (inum == 0) {
addIcode(Icode_ZERO);
// Check for negative zero
if (1.0 / num < 0.0) {
addToken(Token.NEG);
}
} else if (inum == 1) {
addIcode(Icode_ONE);
} else if ((short)inum == inum) {
addIcode(Icode_SHORTNUMBER);
// write short as uin16 bit pattern
addUint16(inum & 0xFFFF);
} else {
addIcode(Icode_INTNUMBER);
addInt(inum);
}
} else {
int index = getDoubleIndex(num);
addIndexOp(Token.NUMBER, index);
}
stackChange(1);
}
private void visitLiteral(Node node, Node child) private void visitLiteral(Node node, Node child)
{ {
int type = node.getType(); int type = node.getType();
@ -1347,17 +1346,6 @@ public class Interpreter
} }
} }
private void visitDotQery(Node node, Node child)
{
updateLineNumber(node);
visitExpression(child, 0);
addIcode(Icode_ENTERDQ);
stackChange(-1);
int queryPC = itsICodeTop;
visitExpression(child.getNext(), 0);
addBackwardGoto(Icode_LEAVEDQ, queryPC);
}
private int getLocalBlockRef(Node node) private int getLocalBlockRef(Node node)
{ {
Node localBlock = (Node)node.getProp(Node.LOCAL_BLOCK_PROP); Node localBlock = (Node)node.getProp(Node.LOCAL_BLOCK_PROP);

Просмотреть файл

@ -1022,90 +1022,6 @@ public class ScriptRuntime {
return (char)i; return (char)i;
} }
/**
* Converts Java exceptions that JS can catch into an object the script
* will see as the catch argument.
*/
private static Object getCatchObject(Context cx, Scriptable scope,
Throwable t)
throws JavaScriptException
{
EvaluatorException evaluator = null;
if (t instanceof EvaluatorException) {
evaluator = (EvaluatorException)t;
while (t instanceof WrappedException) {
t = ((WrappedException)t).getWrappedException();
}
}
if (t instanceof JavaScriptException) {
return ((JavaScriptException)t).getValue();
} else if (t instanceof EcmaError) {
EcmaError ee = (EcmaError)t;
String errorName = ee.getName();
return makeErrorObject(cx, scope, errorName, ee.getErrorMessage(),
ee.sourceName(), ee.lineNumber());
} else if (evaluator == null) {
// Script can catch only instances of JavaScriptException,
// EcmaError and EvaluatorException
Kit.codeBug();
}
if (t != evaluator && t instanceof EvaluatorException) {
// ALERT: it should not happen as throwAsUncheckedException
// takes care about it when exception is propagated through Java
// reflection calls, but for now check for it
evaluator = (EvaluatorException)t;
}
String errorName;
String message;
if (t == evaluator) {
// Pure evaluator exception
if (evaluator instanceof WrappedException) Kit.codeBug();
message = evaluator.getMessage();
errorName = "InternalError";
} else {
errorName = "JavaException";
message = t.getClass().getName()+": "+t.getMessage();
}
Scriptable errorObject = makeErrorObject(cx, scope, errorName,
message,
evaluator.sourceName(),
evaluator.lineNumber());
if (t != evaluator) {
Object twrap = cx.getWrapFactory().wrap(cx, scope, t, null);
ScriptableObject.putProperty(errorObject, "javaException", twrap);
}
return errorObject;
}
private static Scriptable makeErrorObject(Context cx, Scriptable scope,
String errorName, String message,
String fileName, int lineNumber)
throws JavaScriptException
{
int argLength;
if (lineNumber > 0) {
argLength = 3;
} else {
argLength = 2;
}
Object args[] = new Object[argLength];
args[0] = message;
args[1] = (fileName != null) ? fileName : "";
if (lineNumber > 0) {
args[2] = new Integer(lineNumber);
}
Scriptable errorObject = cx.newObject(scope, errorName, args);
ScriptableObject.putProperty(errorObject, "name", errorName);
return errorObject;
}
// XXX: this is until setDefaultNamespace will learn how to store NS // XXX: this is until setDefaultNamespace will learn how to store NS
// properly and separates namespace form Scriptable.get etc. // properly and separates namespace form Scriptable.get etc.
private static final String DEFAULT_NS_TAG = "__default_namespace__"; private static final String DEFAULT_NS_TAG = "__default_namespace__";
@ -2982,26 +2898,95 @@ public class ScriptRuntime {
return null; return null;
} }
public static Scriptable newCatchScope(Throwable exception, public static Scriptable newCatchScope(Throwable t,
Scriptable lastCatchScope, Scriptable lastCatchScope,
String exceptionName, String exceptionName,
Context cx, Scriptable scope) Context cx, Scriptable scope)
{ {
Object obj; Object obj;
if (lastCatchScope == null) { boolean cacheObj;
obj = getCatchObject(cx, scope, exception);
getObj:
if (t instanceof JavaScriptException) {
cacheObj = false;
obj = ((JavaScriptException)t).getValue();
} else { } else {
cacheObj = true;
// Create wrapper object unless it was associated with
// the previous scope object
if (lastCatchScope != null) {
NativeObject last = (NativeObject)lastCatchScope; NativeObject last = (NativeObject)lastCatchScope;
obj = last.getAssociatedValue(exception); obj = last.getAssociatedValue(t);
if (obj == null) Kit.codeBug(); if (obj == null) Kit.codeBug();
break getObj;
} }
NativeObject catchScope = new NativeObject(); RhinoException re;
String errorName;
String errorMsg;
Throwable javaException = null;
if (t instanceof EcmaError) {
EcmaError ee = (EcmaError)t;
re = ee;
errorName = ee.getName();
errorMsg = ee.getErrorMessage();
} else if (t instanceof WrappedException) {
WrappedException we = (WrappedException)t;
re = we;
javaException = we.getWrappedException();
errorName = "JavaException";
errorMsg = javaException.getClass().getName()
+": "+javaException.getMessage();
} else if (t instanceof EvaluatorException) {
// Pure evaluator exception, nor WrappedException instance
EvaluatorException ee = (EvaluatorException)t;
re = ee;
errorName = "InternalError";
errorMsg = ee.getMessage();
} else {
// Script can catch only instances of JavaScriptException,
// EcmaError and EvaluatorException
throw Kit.codeBug();
}
String sourceUri = re.sourceName();
if (sourceUri == null) {
sourceUri = "";
}
int line = re.lineNumber();
Object args[];
if (line > 0) {
args = new Object[] { errorMsg, sourceUri, new Integer(line) };
} else {
args = new Object[] { errorMsg, sourceUri };
}
Scriptable errorObject = cx.newObject(scope, errorName, args);
ScriptableObject.putProperty(errorObject, "name", errorName);
if (javaException != null) {
Object wrap = cx.getWrapFactory().wrap(cx, scope, javaException,
null);
ScriptableObject.defineProperty(
errorObject, "javaException", wrap,
ScriptableObject.PERMANENT | ScriptableObject.READONLY);
}
obj = errorObject;
}
NativeObject catchScopeObject = new NativeObject();
// See ECMA 12.4 // See ECMA 12.4
catchScope.defineProperty( catchScopeObject.defineProperty(
exceptionName, obj, ScriptableObject.PERMANENT); exceptionName, obj, ScriptableObject.PERMANENT);
catchScope.associateValue(exception, obj); if (cacheObj) {
return catchScope; catchScopeObject.associateValue(t, obj);
}
return catchScopeObject;
} }
public static Scriptable enterWith(Object value, Scriptable scope) public static Scriptable enterWith(Object value, Scriptable scope)

Просмотреть файл

@ -1192,7 +1192,7 @@ class BodyCodegen
localsMax = firstFreeLocal; localsMax = firstFreeLocal;
if (fnCurrent == null) { if (fnCurrent == null) {
// See comments in visitRegexp // See comments in case Token.REGEXP
if (scriptOrFn.getRegexpCount() != 0) { if (scriptOrFn.getRegexpCount() != 0) {
scriptRegexpLocal = getNewWordLocal(); scriptRegexpLocal = getNewWordLocal();
codegen.pushRegExpArray(cfw, scriptOrFn, contextLocal, codegen.pushRegExpArray(cfw, scriptOrFn, contextLocal,
@ -1470,11 +1470,50 @@ class BodyCodegen
break; break;
case Token.CATCH_SCOPE: case Token.CATCH_SCOPE:
visitCatchScope(node, child); {
int local = getLocalBlockRegister(node);
int scopeIndex
= node.getExistingIntProp(Node.CATCH_SCOPE_PROP);
String name = child.getString(); // name of exception
child = child.getNext();
generateExpression(child, node); // load expression object
if (scopeIndex == 0) {
cfw.add(ByteCode.ACONST_NULL);
} else {
// Load previous catch scope object
cfw.addALoad(local);
}
cfw.addPush(name);
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);
addScriptRuntimeInvoke(
"newCatchScope",
"(Ljava/lang/Throwable;"
+"Lorg/mozilla/javascript/Scriptable;"
+"Ljava/lang/String;"
+"Lorg/mozilla/javascript/Context;"
+"Lorg/mozilla/javascript/Scriptable;"
+")Lorg/mozilla/javascript/Scriptable;");
cfw.addAStore(local);
}
break; break;
case Token.THROW: case Token.THROW:
visitThrow(node, child); generateExpression(child, node);
cfw.add(ByteCode.NEW,
"org/mozilla/javascript/JavaScriptException");
cfw.add(ByteCode.DUP_X1);
cfw.add(ByteCode.SWAP);
cfw.addPush(scriptOrFn.getSourceName());
cfw.addPush(itsLineNumber);
cfw.addInvoke(
ByteCode.INVOKESPECIAL,
"org/mozilla/javascript/JavaScriptException",
"<init>",
"(Ljava/lang/Object;Ljava/lang/String;I)V");
cfw.add(ByteCode.ATHROW);
break; break;
case Token.RETHROW: case Token.RETHROW:
@ -1504,11 +1543,23 @@ class BodyCodegen
break; break;
case Token.ENTERWITH: case Token.ENTERWITH:
visitEnterWith(node, child); generateExpression(child, node);
cfw.addALoad(variableObjectLocal);
addScriptRuntimeInvoke(
"enterWith",
"(Ljava/lang/Object;"
+"Lorg/mozilla/javascript/Scriptable;"
+")Lorg/mozilla/javascript/Scriptable;");
cfw.addAStore(variableObjectLocal);
break; break;
case Token.LEAVEWITH: case Token.LEAVEWITH:
visitLeaveWith(node, child); cfw.addALoad(variableObjectLocal);
addScriptRuntimeInvoke(
"leaveWith",
"(Lorg/mozilla/javascript/Scriptable;"
+")Lorg/mozilla/javascript/Scriptable;");
cfw.addAStore(variableObjectLocal);
break; break;
case Token.ENUM_INIT_KEYS: case Token.ENUM_INIT_KEYS:
@ -1547,7 +1598,10 @@ class BodyCodegen
break; break;
case Token.TARGET: case Token.TARGET:
visitTarget((Node.Target)node); {
int label = getTargetLabel((Node.Target)node);
cfw.markLabel(label);
}
break; break;
case Token.JSR: case Token.JSR:
@ -1558,7 +1612,17 @@ class BodyCodegen
break; break;
case Token.FINALLY: case Token.FINALLY:
visitFinally(node, child); {
//Save return address in a new local where
int finallyRegister = getNewWordLocal();
cfw.addAStore(finallyRegister);
while (child != null) {
generateStatement(child, node);
child = child.getNext();
}
cfw.add(ByteCode.RET, finallyRegister);
releaseWordLocal((short)finallyRegister);
}
break; break;
default: default:
@ -1589,27 +1653,68 @@ class BodyCodegen
break; break;
case Token.NAME: case Token.NAME:
visitName(node); {
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);
cfw.addPush(node.getString());
addScriptRuntimeInvoke(
"name",
"(Lorg/mozilla/javascript/Context;"
+"Lorg/mozilla/javascript/Scriptable;"
+"Ljava/lang/String;"
+")Ljava/lang/Object;");
}
break; break;
case Token.CALL: case Token.CALL:
case Token.NEW: { case Token.NEW:
{
int specialType = node.getIntProp(Node.SPECIALCALL_PROP, int specialType = node.getIntProp(Node.SPECIALCALL_PROP,
Node.NON_SPECIALCALL); Node.NON_SPECIALCALL);
if (specialType == Node.NON_SPECIALCALL) { if (specialType == Node.NON_SPECIALCALL) {
visitCall(node, type, child); OptFunctionNode target;
target = (OptFunctionNode)node.getProp(
Node.DIRECTCALL_PROP);
if (target != null) {
visitOptimizedCall(node, target, type, child);
} else if (type == Token.CALL) {
visitStandardCall(node, child);
} else {
visitStandardNew(node, child);
}
} else { } else {
visitSpecialCall(node, type, specialType, child); visitSpecialCall(node, type, specialType, child);
} }
break;
} }
break;
case Token.REF_CALL: case Token.REF_CALL:
visitRefCall(node, type, child); generateFunctionAndThisObj(child, node);
// stack: ... functionObj thisObj
child = child.getNext();
generateCallArgArray(node, child, false);
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);
addScriptRuntimeInvoke(
"referenceCall",
"(Lorg/mozilla/javascript/Function;"
+"Lorg/mozilla/javascript/Scriptable;"
+"[Ljava/lang/Object;"
+"Lorg/mozilla/javascript/Context;"
+"Lorg/mozilla/javascript/Scriptable;"
+")Ljava/lang/Object;");
break; break;
case Token.NUMBER: case Token.NUMBER:
visitNumber(node); {
double num = node.getDouble();
if (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1) {
cfw.addPush(num);
} else {
codegen.pushNumberAsObject(cfw, num);
}
}
break; break;
case Token.STRING: case Token.STRING:
@ -1639,7 +1744,24 @@ class BodyCodegen
break; break;
case Token.REGEXP: case Token.REGEXP:
visitRegexp(node); {
int i = node.getExistingIntProp(Node.REGEXP_PROP);
// Scripts can not use REGEXP_ARRAY_FIELD_NAME since
// it it will make script.exec non-reentrant so they
// store regexp array in a local variable while
// functions always access precomputed
// REGEXP_ARRAY_FIELD_NAME not to consume locals
if (fnCurrent == null) {
cfw.addALoad(scriptRegexpLocal);
} else {
cfw.addALoad(funObjLocal);
cfw.add(ByteCode.GETFIELD, codegen.mainClassName,
Codegen.REGEXP_ARRAY_FIELD_NAME,
Codegen.REGEXP_ARRAY_FIELD_TYPE);
}
cfw.addPush(i);
cfw.add(ByteCode.AALOAD);
}
break; break;
case Token.COMMA: { case Token.COMMA: {
@ -1875,11 +1997,35 @@ class BodyCodegen
break; break;
case Token.GETELEM: case Token.GETELEM:
visitGetElem(node, child); generateExpression(child, node); // object
generateExpression(child.getNext(), node); // id
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);
if (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1) {
addOptRuntimeInvoke(
"getObjectIndex",
"(Ljava/lang/Object;D"
+"Lorg/mozilla/javascript/Context;"
+"Lorg/mozilla/javascript/Scriptable;"
+")Ljava/lang/Object;");
}
else {
addScriptRuntimeInvoke(
"getObjectElem",
"(Ljava/lang/Object;"
+"Ljava/lang/Object;"
+"Lorg/mozilla/javascript/Context;"
+"Lorg/mozilla/javascript/Scriptable;"
+")Ljava/lang/Object;");
}
break; break;
case Token.GET_REF: case Token.GET_REF:
visitGetRef(node, child); generateExpression(child, node); // reference
addScriptRuntimeInvoke(
"getReference",
"(Ljava/lang/Object;"
+")Ljava/lang/Object;");
break; break;
case Token.GETVAR: case Token.GETVAR:
@ -1906,7 +2052,23 @@ class BodyCodegen
case Token.SET_REF: case Token.SET_REF:
case Token.SET_REF_OP: case Token.SET_REF_OP:
visitSetRef(type, node, child); {
generateExpression(child, node);
child = child.getNext();
if (type == Token.SET_REF_OP) {
cfw.add(ByteCode.DUP);
addScriptRuntimeInvoke(
"getReference",
"(Ljava/lang/Object;"
+")Ljava/lang/Object;");
}
generateExpression(child, node);
addScriptRuntimeInvoke(
"setReference",
"(Ljava/lang/Object;"
+"Ljava/lang/Object;"
+")Ljava/lang/Object;");
}
break; break;
case Token.DEL_REF: case Token.DEL_REF:
@ -1931,7 +2093,22 @@ class BodyCodegen
break; break;
case Token.BINDNAME: case Token.BINDNAME:
visitBind(node, child); {
while (child != null) {
generateExpression(child, node);
child = child.getNext();
}
// Generate code for "ScriptRuntime.bind(varObj, "s")"
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);
cfw.addPush(node.getString());
addScriptRuntimeInvoke(
"bind",
"(Lorg/mozilla/javascript/Context;"
+"Lorg/mozilla/javascript/Scriptable;"
+"Ljava/lang/String;"
+")Lorg/mozilla/javascript/Scriptable;");
}
break; break;
case Token.LOCAL_LOAD: case Token.LOCAL_LOAD:
@ -1939,11 +2116,33 @@ class BodyCodegen
break; break;
case Token.SPECIAL_REF: case Token.SPECIAL_REF:
visitSpecialRef(node, child); {
String special
= (String)node.getProp(Node.SPECIAL_PROP_PROP);
generateExpression(child, node);
cfw.addPush(special);
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);
addScriptRuntimeInvoke("specialReference",
"(Ljava/lang/Object;"
+"Ljava/lang/String;"
+"Lorg/mozilla/javascript/Context;"
+"Lorg/mozilla/javascript/Scriptable;"
+")Ljava/lang/Object;");
}
break; break;
case Token.XML_REF: case Token.XML_REF:
visitXMLRef(node, child); {
generateExpression(child, node);
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);
addScriptRuntimeInvoke("xmlReference",
"(Ljava/lang/Object;"
+"Lorg/mozilla/javascript/Context;"
+"Lorg/mozilla/javascript/Scriptable;"
+")Ljava/lang/Object;");
}
break; break;
case Token.DOTQUERY: case Token.DOTQUERY:
@ -2142,12 +2341,6 @@ class BodyCodegen
return target.labelId; return target.labelId;
} }
private void visitTarget(Node.Target target)
{
int label = getTargetLabel(target);
cfw.markLabel(label);
}
private void visitGOTO(Node.Jump node, int type, Node child) private void visitGOTO(Node.Jump node, int type, Node child)
{ {
Node.Target target = node.target; Node.Target target = node.target;
@ -2168,39 +2361,6 @@ class BodyCodegen
} }
} }
private void visitFinally(Node node, Node child)
{
//Save return address in a new local where
int finallyRegister = getNewWordLocal();
cfw.addAStore(finallyRegister);
while (child != null) {
generateStatement(child, node);
child = child.getNext();
}
cfw.add(ByteCode.RET, finallyRegister);
releaseWordLocal((short)finallyRegister);
}
private void visitEnterWith(Node node, Node child)
{
generateExpression(child, node);
cfw.addALoad(variableObjectLocal);
addScriptRuntimeInvoke("enterWith",
"(Ljava/lang/Object;"
+"Lorg/mozilla/javascript/Scriptable;"
+")Lorg/mozilla/javascript/Scriptable;");
cfw.addAStore(variableObjectLocal);
}
private void visitLeaveWith(Node node, Node child)
{
cfw.addALoad(variableObjectLocal);
addScriptRuntimeInvoke("leaveWith",
"(Lorg/mozilla/javascript/Scriptable;"
+")Lorg/mozilla/javascript/Scriptable;");
cfw.addAStore(variableObjectLocal);
}
private void visitArrayLiteral(Node node, Node child) private void visitArrayLiteral(Node node, Node child)
{ {
int count = 0; int count = 0;
@ -2274,20 +2434,6 @@ class BodyCodegen
+")Lorg/mozilla/javascript/Scriptable;"); +")Lorg/mozilla/javascript/Scriptable;");
} }
private void visitCall(Node node, int type, Node child)
{
OptFunctionNode
target = (OptFunctionNode)node.getProp(Node.DIRECTCALL_PROP);
if (target != null) {
visitOptimizedCall(node, target, type, child);
} else if (type == Token.CALL) {
visitStandardCall(node, child);
} else {
visitStandardNew(node, child);
}
}
private void visitSpecialCall(Node node, int type, int specialType, private void visitSpecialCall(Node node, int type, int specialType,
Node child) Node child)
{ {
@ -2341,23 +2487,6 @@ class BodyCodegen
addOptRuntimeInvoke(methodName, callSignature); addOptRuntimeInvoke(methodName, callSignature);
} }
private void visitRefCall(Node node, int type, Node child)
{
generateFunctionAndThisObj(child, node);
// stack: ... functionObj thisObj
child = child.getNext();
generateCallArgArray(node, child, false);
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);
addScriptRuntimeInvoke("referenceCall",
"(Lorg/mozilla/javascript/Function;"
+"Lorg/mozilla/javascript/Scriptable;"
+"[Ljava/lang/Object;"
+"Lorg/mozilla/javascript/Context;"
+"Lorg/mozilla/javascript/Scriptable;"
+")Ljava/lang/Object;");
}
private void visitStandardCall(Node node, Node child) private void visitStandardCall(Node node, Node child)
{ {
if (node.getType() != Token.CALL) throw Codegen.badTree(); if (node.getType() != Token.CALL) throw Codegen.badTree();
@ -2867,23 +2996,6 @@ Else pass the JS object in the aReg and 0.0 in the dReg.
cfw.add(ByteCode.GOTO, catchLabel); cfw.add(ByteCode.GOTO, catchLabel);
} }
private void visitThrow(Node node, Node child)
{
generateExpression(child, node);
cfw.add(ByteCode.NEW,
"org/mozilla/javascript/JavaScriptException");
cfw.add(ByteCode.DUP_X1);
cfw.add(ByteCode.SWAP);
cfw.addPush(scriptOrFn.getSourceName());
cfw.addPush(itsLineNumber);
cfw.addInvoke(ByteCode.INVOKESPECIAL,
"org/mozilla/javascript/JavaScriptException",
"<init>",
"(Ljava/lang/Object;Ljava/lang/String;I)V");
cfw.add(ByteCode.ATHROW);
}
private void visitSwitch(Node.Jump switchNode, Node child) private void visitSwitch(Node.Jump switchNode, Node child)
{ {
// See comments in IRFactory.createSwitch() for description // See comments in IRFactory.createSwitch() for description
@ -3397,77 +3509,6 @@ Else pass the JS object in the aReg and 0.0 in the dReg.
if (stackInitial != cfw.getStackTop()) throw Codegen.badTree(); if (stackInitial != cfw.getStackTop()) throw Codegen.badTree();
} }
private void visitNumber(Node node)
{
double num = node.getDouble();
if (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1) {
cfw.addPush(num);
} else {
codegen.pushNumberAsObject(cfw, num);
}
}
private void visitRegexp(Node node)
{
int i = node.getExistingIntProp(Node.REGEXP_PROP);
// Scripts can not use REGEXP_ARRAY_FIELD_NAME since
// it it will make script.exec non-reentrant so they
// store regexp array in a local variable while
// functions always access precomputed REGEXP_ARRAY_FIELD_NAME
// not to consume locals
if (fnCurrent == null) {
cfw.addALoad(scriptRegexpLocal);
} else {
cfw.addALoad(funObjLocal);
cfw.add(ByteCode.GETFIELD, codegen.mainClassName,
Codegen.REGEXP_ARRAY_FIELD_NAME,
Codegen.REGEXP_ARRAY_FIELD_TYPE);
}
cfw.addPush(i);
cfw.add(ByteCode.AALOAD);
}
private void visitCatchScope(Node node, Node child)
{
int local = getLocalBlockRegister(node);
int scopeIndex = node.getExistingIntProp(Node.CATCH_SCOPE_PROP);
String name = child.getString(); // name of exception variable
child = child.getNext();
generateExpression(child, node); // load expression object
if (scopeIndex == 0) {
cfw.add(ByteCode.ACONST_NULL);
} else {
// Load previous catch scope object
cfw.addALoad(local);
}
cfw.addPush(name);
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);
addScriptRuntimeInvoke("newCatchScope",
"(Ljava/lang/Throwable;"
+"Lorg/mozilla/javascript/Scriptable;"
+"Ljava/lang/String;"
+"Lorg/mozilla/javascript/Context;"
+"Lorg/mozilla/javascript/Scriptable;"
+")Lorg/mozilla/javascript/Scriptable;");
cfw.addAStore(local);
}
private void visitName(Node node)
{
cfw.addALoad(contextLocal); // push cx
cfw.addALoad(variableObjectLocal); // get variable object
cfw.addPush(node.getString()); // push name
addScriptRuntimeInvoke(
"name",
"(Lorg/mozilla/javascript/Context;"
+"Lorg/mozilla/javascript/Scriptable;"
+"Ljava/lang/String;"
+")Ljava/lang/Object;");
}
private void visitSetName(Node node, Node child) private void visitSetName(Node node, Node child)
{ {
String name = node.getFirstChild().getString(); String name = node.getFirstChild().getString();
@ -3609,38 +3650,6 @@ Else pass the JS object in the aReg and 0.0 in the dReg.
} }
} }
private void visitGetElem(Node node, Node child)
{
generateExpression(child, node); // object
generateExpression(child.getNext(), node); // id
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);
if (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1) {
addOptRuntimeInvoke(
"getObjectIndex",
"(Ljava/lang/Object;D"
+"Lorg/mozilla/javascript/Context;"
+"Lorg/mozilla/javascript/Scriptable;"
+")Ljava/lang/Object;");
}
else {
addScriptRuntimeInvoke(
"getObjectElem",
"(Ljava/lang/Object;"
+"Ljava/lang/Object;"
+"Lorg/mozilla/javascript/Context;"
+"Lorg/mozilla/javascript/Scriptable;"
+")Ljava/lang/Object;");
}
}
private void visitGetRef(Node node, Node child)
{
generateExpression(child, node); // reference
addScriptRuntimeInvoke(
"getReference", "(Ljava/lang/Object;)Ljava/lang/Object;");
}
private void visitSetProp(int type, Node node, Node child) private void visitSetProp(int type, Node node, Node child)
{ {
Node objectChild = child; Node objectChild = child;
@ -3754,65 +3763,6 @@ Else pass the JS object in the aReg and 0.0 in the dReg.
} }
} }
private void visitSetRef(int type, Node node, Node child)
{
generateExpression(child, node);
child = child.getNext();
if (type == Token.SET_REF_OP) {
cfw.add(ByteCode.DUP);
addScriptRuntimeInvoke(
"getReference", "(Ljava/lang/Object;)Ljava/lang/Object;");
}
generateExpression(child, node);
addScriptRuntimeInvoke(
"setReference",
"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
}
private void visitBind(Node node, Node child)
{
while (child != null) {
generateExpression(child, node);
child = child.getNext();
}
// Generate code for "ScriptRuntime.bind(varObj, "s")"
cfw.addALoad(contextLocal); // push cx
cfw.addALoad(variableObjectLocal); // push variable object
cfw.addPush(node.getString()); // push name
addScriptRuntimeInvoke("bind",
"(Lorg/mozilla/javascript/Context;"
+"Lorg/mozilla/javascript/Scriptable;"
+"Ljava/lang/String;"
+")Lorg/mozilla/javascript/Scriptable;");
}
private void visitSpecialRef(Node node, Node child)
{
String special = (String)node.getProp(Node.SPECIAL_PROP_PROP);
generateExpression(child, node);
cfw.addPush(special);
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);
addScriptRuntimeInvoke("specialReference",
"(Ljava/lang/Object;"
+"Ljava/lang/String;"
+"Lorg/mozilla/javascript/Context;"
+"Lorg/mozilla/javascript/Scriptable;"
+")Ljava/lang/Object;");
}
private void visitXMLRef(Node node, Node child)
{
generateExpression(child, node);
cfw.addALoad(contextLocal);
cfw.addALoad(variableObjectLocal);
addScriptRuntimeInvoke("xmlReference",
"(Ljava/lang/Object;"
+"Lorg/mozilla/javascript/Context;"
+"Lorg/mozilla/javascript/Scriptable;"
+")Ljava/lang/Object;");
}
private void visitDotQuery(Node node, Node child) private void visitDotQuery(Node node, Node child)
{ {
updateLineNumber(node); updateLineNumber(node);