001: // Copyright (c) 1999 Per M.A. Bothner.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.expr;
005:
006: import gnu.bytecode.*;
007: import gnu.mapping.Values;
008:
009: /** Same as StackTarget, but catch ClassCastException.
010: * Generate code so that if coercion fails, catch ClassCastException,
011: * and re-throw a WrongType. This gives better error messages. */
012:
013: public class CheckedTarget extends StackTarget {
014: LambdaExp proc;
015: String procname;
016: int argno;
017:
018: public CheckedTarget(Type type, LambdaExp proc, int argno) {
019: super (type);
020: this .proc = proc;
021: this .procname = proc.getName();
022: this .argno = argno;
023: }
024:
025: public CheckedTarget(Type type, String procname, int argno) {
026: super (type);
027: this .procname = procname;
028: this .argno = argno;
029: }
030:
031: public static Target getInstance(Type type, String procname,
032: int argno) {
033: return (type == Type.pointer_type ? Target.pushObject
034: : new CheckedTarget(type, procname, argno));
035: }
036:
037: public static Target getInstance(Type type, LambdaExp proc,
038: int argno) {
039: return (type == Type.pointer_type ? Target.pushObject
040: : new CheckedTarget(type, proc, argno));
041: }
042:
043: static ClassType typeClassCastException;
044: static ClassType typeWrongType;
045: static Method makeWrongTypeStringMethod;
046: static Method makeWrongTypeProcMethod;
047:
048: private static void initWrongType() {
049: if (typeClassCastException == null)
050: typeClassCastException = ClassType
051: .make("java.lang.ClassCastException");
052: if (typeWrongType == null) {
053: typeWrongType = ClassType.make("gnu.mapping.WrongType");
054: Type[] args = new Type[3];
055: args[0] = typeClassCastException;
056: args[1] = Compilation.javaStringType;
057: args[2] = Type.int_type;
058: makeWrongTypeStringMethod = typeWrongType.addMethod("make",
059: args, typeWrongType, Access.PUBLIC | Access.STATIC);
060: args = new Type[3];
061: args[0] = typeClassCastException;
062: args[1] = Compilation.typeProcedure;
063: args[2] = Type.int_type;
064: makeWrongTypeProcMethod = typeWrongType.addMethod("make",
065: args, typeWrongType, Access.PUBLIC | Access.STATIC);
066: }
067: }
068:
069: public void compileFromStack(Compilation comp, Type stackType) {
070: if (!compileFromStack0(comp, stackType))
071: emitCheckedCoerce(comp, proc, procname, argno, type);
072: }
073:
074: public static void emitCheckedCoerce(Compilation comp,
075: String procname, int argno, Type type) {
076: emitCheckedCoerce(comp, null, procname, argno, type);
077: }
078:
079: public static void emitCheckedCoerce(Compilation comp,
080: LambdaExp proc, int argno, Type type) {
081: emitCheckedCoerce(comp, proc, proc.getName(), argno, type);
082: }
083:
084: static void emitCheckedCoerce(Compilation comp, LambdaExp proc,
085: String procname, int argno, Type type) {
086: CodeAttr code = comp.getCode();
087: // If we're not in a try statement, it is more efficient to defer
088: // the handler to the end of the procedure (thus avoiding a goto,
089: // and potentially improving locality). If we're in a try statement,
090: // we can't safely do that
091: boolean isInTry = code.isInTry();
092: initWrongType();
093: int startPC = code.getPC();
094: type.emitCoerceFromObject(code);
095:
096: int endPC = code.getPC();
097: // If no cast was needed, no code has been generated.
098: // Thus endPC is equal to startPC and we can stop safely.
099: if (endPC == startPC)
100: return;
101:
102: // Can never raise an exception, so we don't need to catch it.
103: if (type == Type.tostring_type)
104: return;
105:
106: Label endLabel = null;
107: if (isInTry) {
108: endLabel = new Label(code);
109: code.emitGoto(endLabel);
110: endPC = code.getPC();
111: }
112: code.addHandler(startPC, endPC, isInTry ? endPC : -1,
113: typeClassCastException, code.getConstants());
114: if (!isInTry)
115: code.beginFragment(true);
116: // Push arguments:
117: // ClassCastException is already pushed
118: code.pushType(typeClassCastException);
119: boolean this IsProc = false;
120: if (proc != null && proc.isClassGenerated()
121: && !comp.method.getStaticFlag()) {
122: if (comp.method.getDeclaringClass() == proc
123: .getCompiledClassType(comp))
124: this IsProc = true;
125: }
126: int line = comp.position >> 12;
127: if (line > 0)
128: code.putLineNumber(comp.filename, line);
129: if (this IsProc)
130: code.emitPushThis();
131: else
132: code.emitPushString(procname == null ? "lambda" : procname);
133: code.emitPushInt(argno);
134: code.emitInvokeStatic(thisIsProc ? makeWrongTypeProcMethod
135: : makeWrongTypeStringMethod);
136: code.emitThrow();
137: if (isInTry)
138: endLabel.define(code);
139: else
140: code.endFragment();
141: }
142: }
|