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,24 +535,26 @@ public class Interpreter
Node child = node.getFirstChild();
switch (type) {
case Token.FUNCTION: {
int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP);
int fnType = scriptOrFn.getFunctionNode(fnIndex).getFunctionType();
// Only function expressions or function expression
// statements needs closure code creating new function
// object on stack as function statements are initialized
// at script/function start
// In addition function expression can not present here
// at statement level, they must only present as expressions.
if (fnType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) {
addIndexOp(Icode_CLOSURE_STMT, fnIndex);
} else {
if (fnType != FunctionNode.FUNCTION_STATEMENT) {
throw Kit.codeBug();
case Token.FUNCTION:
{
int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP);
int fnType = scriptOrFn.getFunctionNode(fnIndex).
getFunctionType();
// Only function expressions or function expression
// statements needs closure code creating new function
// object on stack as function statements are initialized
// at script/function start
// In addition function expression can not present here
// at statement level, they must only present as expressions.
if (fnType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) {
addIndexOp(Icode_CLOSURE_STMT, fnIndex);
} else {
if (fnType != FunctionNode.FUNCTION_STATEMENT) {
throw Kit.codeBug();
}
}
}
break;
}
case Token.SCRIPT:
case Token.LABEL:
@ -600,7 +602,32 @@ public class Interpreter
break;
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;
case Token.TARGET:
@ -608,25 +635,28 @@ public class Interpreter
break;
case Token.IFEQ :
case Token.IFNE : {
Node.Target target = ((Node.Jump)node).target;
visitExpression(child, 0);
addGoto(target, type);
stackChange(-1);
case Token.IFNE :
{
Node.Target target = ((Node.Jump)node).target;
visitExpression(child, 0);
addGoto(target, type);
stackChange(-1);
}
break;
}
case Token.GOTO: {
Node.Target target = ((Node.Jump)node).target;
addGoto(target, type);
case Token.GOTO:
{
Node.Target target = ((Node.Jump)node).target;
addGoto(target, type);
}
break;
}
case Token.JSR: {
Node.Target target = ((Node.Jump)node).target;
addGoto(target, Icode_GOSUB);
case Token.JSR:
{
Node.Target target = ((Node.Jump)node).target;
addGoto(target, Icode_GOSUB);
}
break;
}
case Token.FINALLY:
{
@ -652,7 +682,33 @@ public class Interpreter
break;
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;
case Token.CATCH_SCOPE:
@ -722,37 +778,40 @@ public class Interpreter
int savedStackDepth = itsStackDepth;
switch (type) {
case Token.FUNCTION: {
int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP);
FunctionNode fn = scriptOrFn.getFunctionNode(fnIndex);
// See comments in visitStatement for Token.FUNCTION case
if (fn.getFunctionType() != FunctionNode.FUNCTION_EXPRESSION) {
throw Kit.codeBug();
case Token.FUNCTION:
{
int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP);
FunctionNode fn = scriptOrFn.getFunctionNode(fnIndex);
// See comments in visitStatement for Token.FUNCTION case
if (fn.getFunctionType() != FunctionNode.FUNCTION_EXPRESSION) {
throw Kit.codeBug();
}
addIndexOp(Icode_CLOSURE_EXPR, fnIndex);
stackChange(1);
}
addIndexOp(Icode_CLOSURE_EXPR, fnIndex);
stackChange(1);
break;
}
case Token.LOCAL_LOAD: {
int localIndex = getLocalBlockRef(node);
addIndexOp(Token.LOCAL_LOAD, localIndex);
stackChange(1);
break;
}
case Token.COMMA: {
Node lastChild = node.getLastChild();
while (child != lastChild) {
visitExpression(child, 0);
addIcode(Icode_POP);
stackChange(-1);
child = child.getNext();
case Token.LOCAL_LOAD:
{
int localIndex = getLocalBlockRef(node);
addIndexOp(Token.LOCAL_LOAD, localIndex);
stackChange(1);
}
break;
case Token.COMMA:
{
Node lastChild = node.getLastChild();
while (child != lastChild) {
visitExpression(child, 0);
addIcode(Icode_POP);
stackChange(-1);
child = child.getNext();
}
// Preserve tail context flag if any
visitExpression(child, contextFlags & ECF_TAIL);
}
// Preserve tail context flag if any
visitExpression(child, contextFlags & ECF_TAIL);
break;
}
case Token.USE_STACK:
// Indicates that stack was modified externally,
@ -763,56 +822,103 @@ public class Interpreter
case Token.CALL:
case Token.NEW:
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;
case Token.AND:
case Token.OR: {
visitExpression(child, 0);
addIcode(Icode_DUP);
stackChange(1);
int afterSecondJumpStart = itsICodeTop;
int jump = (type == Token.AND) ? Token.IFNE : Token.IFEQ;
addForwardGoto(jump);
stackChange(-1);
addIcode(Icode_POP);
stackChange(-1);
child = child.getNext();
// Preserve tail context flag if any
visitExpression(child, contextFlags & ECF_TAIL);
resolveForwardGoto(afterSecondJumpStart);
case Token.OR:
{
visitExpression(child, 0);
addIcode(Icode_DUP);
stackChange(1);
int afterSecondJumpStart = itsICodeTop;
int jump = (type == Token.AND) ? Token.IFNE : Token.IFEQ;
addForwardGoto(jump);
stackChange(-1);
addIcode(Icode_POP);
stackChange(-1);
child = child.getNext();
// Preserve tail context flag if any
visitExpression(child, contextFlags & ECF_TAIL);
resolveForwardGoto(afterSecondJumpStart);
}
break;
}
case Token.HOOK: {
Node ifThen = child.getNext();
Node ifElse = ifThen.getNext();
visitExpression(child, 0);
int elseJumpStart = itsICodeTop;
addForwardGoto(Token.IFNE);
stackChange(-1);
// Preserve tail context flag if any
visitExpression(ifThen, contextFlags & ECF_TAIL);
int afterElseJumpStart = itsICodeTop;
addForwardGoto(Token.GOTO);
resolveForwardGoto(elseJumpStart);
itsStackDepth = savedStackDepth;
// Preserve tail context flag if any
visitExpression(ifElse, contextFlags & ECF_TAIL);
resolveForwardGoto(afterElseJumpStart);
case Token.HOOK:
{
Node ifThen = child.getNext();
Node ifElse = ifThen.getNext();
visitExpression(child, 0);
int elseJumpStart = itsICodeTop;
addForwardGoto(Token.IFNE);
stackChange(-1);
// Preserve tail context flag if any
visitExpression(ifThen, contextFlags & ECF_TAIL);
int afterElseJumpStart = itsICodeTop;
addForwardGoto(Token.GOTO);
resolveForwardGoto(elseJumpStart);
itsStackDepth = savedStackDepth;
// Preserve tail context flag if any
visitExpression(ifElse, contextFlags & ECF_TAIL);
resolveForwardGoto(afterElseJumpStart);
}
break;
}
case Token.GETPROP:
visitGetProp(node, child);
visitExpression(child, 0);
child = child.getNext();
addStringOp(Token.GETPROP, child.getString());
break;
case Token.GETELEM:
visitGetElem(node, child);
visitExpression(child, 0);
child = child.getNext();
visitExpression(child, 0);
addToken(Token.GETELEM);
stackChange(-1);
break;
case Token.GET_REF:
visitGetRef(node, child);
visitExpression(child, 0);
addToken(Token.GET_REF);
break;
case Token.DELPROP:
@ -860,24 +966,25 @@ public class Interpreter
}
break;
case Token.SETPROP:
case Token.SETPROP_OP: {
visitExpression(child, 0);
child = child.getNext();
String property = child.getString();
child = child.getNext();
if (type == Token.SETPROP_OP) {
addIcode(Icode_DUP);
stackChange(1);
addStringOp(Token.GETPROP, property);
// Compensate for the following USE_STACK
case Token.SETPROP:
case Token.SETPROP_OP:
{
visitExpression(child, 0);
child = child.getNext();
String property = child.getString();
child = child.getNext();
if (type == Token.SETPROP_OP) {
addIcode(Icode_DUP);
stackChange(1);
addStringOp(Token.GETPROP, property);
// Compensate for the following USE_STACK
stackChange(-1);
}
visitExpression(child, 0);
addStringOp(Token.SETPROP, property);
stackChange(-1);
}
visitExpression(child, 0);
addStringOp(Token.SETPROP, property);
stackChange(-1);
break;
}
case Token.SETELEM:
case Token.SETELEM_OP:
@ -914,33 +1021,35 @@ public class Interpreter
stackChange(-1);
break;
case Token.SETNAME: {
String name = child.getString();
visitExpression(child, 0);
child = child.getNext();
visitExpression(child, 0);
addStringOp(Token.SETNAME, name);
stackChange(-1);
break;
}
case Token.TYPEOFNAME: {
String name = node.getString();
int index = -1;
// use typeofname if an activation frame exists
// since the vars all exist there instead of in jregs
if (itsInFunctionFlag && !itsData.itsNeedsActivation)
index = scriptOrFn.getParamOrVarIndex(name);
if (index == -1) {
addStringOp(Icode_TYPEOFNAME, name);
stackChange(1);
} else {
addVarOp(Token.GETVAR, index);
stackChange(1);
addToken(Token.TYPEOF);
case Token.SETNAME:
{
String name = child.getString();
visitExpression(child, 0);
child = child.getNext();
visitExpression(child, 0);
addStringOp(Token.SETNAME, name);
stackChange(-1);
}
break;
case Token.TYPEOFNAME:
{
String name = node.getString();
int index = -1;
// use typeofname if an activation frame exists
// since the vars all exist there instead of in jregs
if (itsInFunctionFlag && !itsData.itsNeedsActivation)
index = scriptOrFn.getParamOrVarIndex(name);
if (index == -1) {
addStringOp(Icode_TYPEOFNAME, name);
stackChange(1);
} else {
addVarOp(Token.GETVAR, index);
stackChange(1);
addToken(Token.TYPEOF);
}
}
break;
}
case Token.BINDNAME:
case Token.NAME:
@ -955,41 +1064,68 @@ public class Interpreter
break;
case Token.NUMBER:
visitNumber(node);
break;
case Token.GETVAR: {
String name = node.getString();
if (itsData.itsNeedsActivation) {
// SETVAR handled this by turning into a SETPROP, but
// we can't do that to a GETVAR without manufacturing
// bogus children. Instead we use a special op to
// push the current scope.
addIcode(Icode_SCOPE);
stackChange(1);
addStringOp(Token.GETPROP, name);
} else {
int index = scriptOrFn.getParamOrVarIndex(name);
addVarOp(Token.GETVAR, index);
{
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;
}
case Token.SETVAR: {
if (itsData.itsNeedsActivation) {
child.setType(Token.BINDNAME);
node.setType(Token.SETNAME);
visitExpression(node, 0);
} else {
String name = child.getString();
child = child.getNext();
visitExpression(child, 0);
int index = scriptOrFn.getParamOrVarIndex(name);
addVarOp(Token.SETVAR, index);
case Token.GETVAR:
{
String name = node.getString();
if (itsData.itsNeedsActivation) {
// SETVAR handled this by turning into a SETPROP, but
// we can't do that to a GETVAR without manufacturing
// bogus children. Instead we use a special op to
// push the current scope.
addIcode(Icode_SCOPE);
stackChange(1);
addStringOp(Token.GETPROP, name);
} else {
int index = scriptOrFn.getParamOrVarIndex(name);
addVarOp(Token.GETVAR, index);
stackChange(1);
}
}
break;
case Token.SETVAR:
{
if (itsData.itsNeedsActivation) {
child.setType(Token.BINDNAME);
node.setType(Token.SETNAME);
visitExpression(node, 0);
} else {
String name = child.getString();
child = child.getNext();
visitExpression(child, 0);
int index = scriptOrFn.getParamOrVarIndex(name);
addVarOp(Token.SETVAR, index);
}
}
break;
}
case Token.NULL:
case Token.THIS:
@ -1006,24 +1142,26 @@ public class Interpreter
stackChange(1);
break;
case Token.REGEXP: {
int index = node.getExistingIntProp(Node.REGEXP_PROP);
addIndexOp(Token.REGEXP, index);
stackChange(1);
case Token.REGEXP:
{
int index = node.getExistingIntProp(Node.REGEXP_PROP);
addIndexOp(Token.REGEXP, index);
stackChange(1);
}
break;
}
case Token.ARRAYLIT:
case Token.OBJECTLIT:
visitLiteral(node, child);
break;
case Token.SPECIAL_REF: {
visitExpression(child, 0);
String special = (String)node.getProp(Node.SPECIAL_PROP_PROP);
addStringOp(Token.SPECIAL_REF, special);
case Token.SPECIAL_REF:
{
String special = (String)node.getProp(Node.SPECIAL_PROP_PROP);
visitExpression(child, 0);
addStringOp(Token.SPECIAL_REF, special);
}
break;
}
case Token.XML_REF:
visitExpression(child, 0);
@ -1031,7 +1169,16 @@ public class Interpreter
break;
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;
case Token.DEFAULTNAMESPACE :
@ -1043,16 +1190,16 @@ public class Interpreter
addToken(type);
break;
case Token.COLONCOLON : {
if (child.getType() != Token.STRING)
throw badTree(child);
String namespace = child.getString();
child = child.getNext();
visitExpression(child, 0);
addStringOp(Token.COLONCOLON, namespace);
case Token.COLONCOLON :
{
if (child.getType() != Token.STRING)
throw badTree(child);
String namespace = child.getString();
child = child.getNext();
visitExpression(child, 0);
addStringOp(Token.COLONCOLON, namespace);
}
break;
}
default:
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)
{
// 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)
{
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)
{
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)
{
Node localBlock = (Node)node.getProp(Node.LOCAL_BLOCK_PROP);

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

@ -1022,90 +1022,6 @@ public class ScriptRuntime {
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
// properly and separates namespace form Scriptable.get etc.
private static final String DEFAULT_NS_TAG = "__default_namespace__";
@ -2982,26 +2898,95 @@ public class ScriptRuntime {
return null;
}
public static Scriptable newCatchScope(Throwable exception,
public static Scriptable newCatchScope(Throwable t,
Scriptable lastCatchScope,
String exceptionName,
Context cx, Scriptable scope)
{
Object obj;
if (lastCatchScope == null) {
obj = getCatchObject(cx, scope, exception);
boolean cacheObj;
getObj:
if (t instanceof JavaScriptException) {
cacheObj = false;
obj = ((JavaScriptException)t).getValue();
} else {
NativeObject last = (NativeObject)lastCatchScope;
obj = last.getAssociatedValue(exception);
if (obj == null) Kit.codeBug();
cacheObj = true;
// Create wrapper object unless it was associated with
// the previous scope object
if (lastCatchScope != null) {
NativeObject last = (NativeObject)lastCatchScope;
obj = last.getAssociatedValue(t);
if (obj == null) Kit.codeBug();
break getObj;
}
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 catchScope = new NativeObject();
NativeObject catchScopeObject = new NativeObject();
// See ECMA 12.4
catchScope.defineProperty(
catchScopeObject.defineProperty(
exceptionName, obj, ScriptableObject.PERMANENT);
catchScope.associateValue(exception, obj);
return catchScope;
if (cacheObj) {
catchScopeObject.associateValue(t, obj);
}
return catchScopeObject;
}
public static Scriptable enterWith(Object value, Scriptable scope)

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

@ -1192,7 +1192,7 @@ class BodyCodegen
localsMax = firstFreeLocal;
if (fnCurrent == null) {
// See comments in visitRegexp
// See comments in case Token.REGEXP
if (scriptOrFn.getRegexpCount() != 0) {
scriptRegexpLocal = getNewWordLocal();
codegen.pushRegExpArray(cfw, scriptOrFn, contextLocal,
@ -1470,11 +1470,50 @@ class BodyCodegen
break;
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;
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;
case Token.RETHROW:
@ -1504,11 +1543,23 @@ class BodyCodegen
break;
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;
case Token.LEAVEWITH:
visitLeaveWith(node, child);
cfw.addALoad(variableObjectLocal);
addScriptRuntimeInvoke(
"leaveWith",
"(Lorg/mozilla/javascript/Scriptable;"
+")Lorg/mozilla/javascript/Scriptable;");
cfw.addAStore(variableObjectLocal);
break;
case Token.ENUM_INIT_KEYS:
@ -1547,7 +1598,10 @@ class BodyCodegen
break;
case Token.TARGET:
visitTarget((Node.Target)node);
{
int label = getTargetLabel((Node.Target)node);
cfw.markLabel(label);
}
break;
case Token.JSR:
@ -1558,7 +1612,17 @@ class BodyCodegen
break;
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;
default:
@ -1589,27 +1653,68 @@ class BodyCodegen
break;
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;
case Token.CALL:
case Token.NEW: {
int specialType = node.getIntProp(Node.SPECIALCALL_PROP,
Node.NON_SPECIALCALL);
if (specialType == Node.NON_SPECIALCALL) {
visitCall(node, type, child);
} else {
visitSpecialCall(node, type, specialType, child);
case Token.NEW:
{
int specialType = node.getIntProp(Node.SPECIALCALL_PROP,
Node.NON_SPECIALCALL);
if (specialType == Node.NON_SPECIALCALL) {
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 {
visitSpecialCall(node, type, specialType, child);
}
}
break;
}
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;
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;
case Token.STRING:
@ -1639,7 +1744,24 @@ class BodyCodegen
break;
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;
case Token.COMMA: {
@ -1875,11 +1997,35 @@ class BodyCodegen
break;
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;
case Token.GET_REF:
visitGetRef(node, child);
generateExpression(child, node); // reference
addScriptRuntimeInvoke(
"getReference",
"(Ljava/lang/Object;"
+")Ljava/lang/Object;");
break;
case Token.GETVAR:
@ -1906,7 +2052,23 @@ class BodyCodegen
case Token.SET_REF:
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;
case Token.DEL_REF:
@ -1931,7 +2093,22 @@ class BodyCodegen
break;
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;
case Token.LOCAL_LOAD:
@ -1939,11 +2116,33 @@ class BodyCodegen
break;
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;
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;
case Token.DOTQUERY:
@ -2142,12 +2341,6 @@ class BodyCodegen
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)
{
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)
{
int count = 0;
@ -2274,20 +2434,6 @@ class BodyCodegen
+")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,
Node child)
{
@ -2341,23 +2487,6 @@ class BodyCodegen
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)
{
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);
}
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)
{
// 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();
}
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)
{
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)
{
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)
{
updateLineNumber(node);