001: // Copyright (c) 1999, 2004 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.mapping.*;
007: import java.lang.reflect.*;
008:
009: /** Call a specified method in in a ModuleBody.
010: * We use an extra level of indirection, but we save by having
011: * to create fewer classes than in the one-class-per-procedure
012: * scheme, without having to use (slow) reflection.
013: */
014:
015: public class ModuleMethod extends MethodProc {
016: public ModuleBody module;
017: public final int selector;
018: protected int numArgs;
019:
020: public ModuleMethod(ModuleBody module, int selector, Object name,
021: int numArgs) {
022: this .module = module;
023: this .selector = selector;
024: this .numArgs = numArgs;
025: if (name != null)
026: setSymbol(name);
027: }
028:
029: public ModuleMethod(ModuleBody module, int selector, Object name,
030: int numArgs, Object argTypes) {
031: this .module = module;
032: this .selector = selector;
033: this .numArgs = numArgs;
034: if (name != null)
035: setSymbol(name);
036: this .argTypes = argTypes;
037: }
038:
039: /** Figure out parameter types.
040: * Uses reflection to get method parameter types.
041: * INCOMPLETE - does not handle procedures with optional or rest args. */
042: protected void resolveParameterTypes() {
043: Method method = null;
044: try {
045: Class moduleClass = module.getClass();
046: Method[] methods = moduleClass.getDeclaredMethods();
047: String mangledName = Compilation
048: .mangleNameIfNeeded(getName());
049: for (int i = methods.length; --i >= 0;) {
050: if (methods[i].getName().equals(mangledName)) {
051: if (method != null) {
052: method = null;
053: break;
054: }
055: method = methods[i];
056: }
057: }
058: if (method != null) {
059: Language lang = Language.getDefaultLanguage();
060: Class[] parameterClasses = method.getParameterTypes();
061: int numParamTypes = parameterClasses.length;
062: gnu.bytecode.Type[] atypes = new gnu.bytecode.Type[numParamTypes];
063: for (int i = numParamTypes; --i >= 0;) {
064: atypes[i] = lang.getTypeFor(parameterClasses[i]);
065: }
066: this .argTypes = atypes;
067: }
068: } catch (Throwable ex) {
069: }
070: if (argTypes == null)
071: super .resolveParameterTypes();
072: }
073:
074: public int numArgs() {
075: return numArgs;
076: }
077:
078: public int match0(CallContext ctx) {
079: ctx.count = 0;
080: ctx.where = 0;
081: return module.match0(this , ctx);
082: }
083:
084: public int match1(Object arg1, CallContext ctx) {
085: ctx.count = 1;
086: ctx.where = CallContext.ARG_IN_VALUE1;
087: return module.match1(this , arg1, ctx);
088: }
089:
090: public int match2(Object arg1, Object arg2, CallContext ctx) {
091: ctx.count = 2;
092: ctx.where = CallContext.ARG_IN_VALUE1
093: | (CallContext.ARG_IN_VALUE2 << 4);
094: return module.match2(this , arg1, arg2, ctx);
095: }
096:
097: public int match3(Object arg1, Object arg2, Object arg3,
098: CallContext ctx) {
099: ctx.count = 3;
100: ctx.where = CallContext.ARG_IN_VALUE1
101: | (CallContext.ARG_IN_VALUE2 << 4)
102: | (CallContext.ARG_IN_VALUE3 << 8);
103: return module.match3(this , arg1, arg2, arg3, ctx);
104: }
105:
106: public int match4(Object arg1, Object arg2, Object arg3,
107: Object arg4, CallContext ctx) {
108: ctx.count = 4;
109: ctx.where = (CallContext.ARG_IN_VALUE1
110: | (CallContext.ARG_IN_VALUE2 << 4)
111: | (CallContext.ARG_IN_VALUE3 << 8) | (CallContext.ARG_IN_VALUE4 << 12));
112: return module.match4(this , arg1, arg2, arg3, arg4, ctx);
113: }
114:
115: public int matchN(Object[] args, CallContext ctx) {
116: ctx.count = args.length;
117: ctx.where = 0;
118: return module.matchN(this , args, ctx);
119: }
120:
121: public void apply(CallContext ctx) throws Throwable {
122: // This method does not get called for methods compiled with
123: // --full-tailcalls, since their match methods set ctx.proc to the
124: // ModuleWithContext, rather than this ModuleMethod.
125: // We get here for methods compiled with the --no-full-tailcalls option.
126: // In that case the compiler-generated matchX methods set ctx.pc
127: // to 0...5 to indicate where the arguments were saved.
128: // It would be more consistent to set ctx.where and ctx.count, though
129: // a simple switch of ctx.pc is faster. But how robust is this?
130: Object result;
131: switch (ctx.pc) {
132: case 0:
133: result = apply0();
134: break;
135: case 1:
136: result = apply1(ctx.value1);
137: break;
138: case 2:
139: result = apply2(ctx.value1, ctx.value2);
140: break;
141: case 3:
142: result = apply3(ctx.value1, ctx.value2, ctx.value3);
143: break;
144: case 4:
145: result = apply4(ctx.value1, ctx.value2, ctx.value3,
146: ctx.value4);
147: break;
148: case 5:
149: result = applyN(ctx.values);
150: break;
151: default:
152: throw new Error("internal error - apply " + this );
153: }
154: ctx.writeValue(result);
155: }
156:
157: public Object apply0() throws Throwable {
158: return module.apply0(this );
159: }
160:
161: public Object apply1(Object arg1) throws Throwable {
162: return module.apply1(this , arg1);
163: }
164:
165: public Object apply2(Object arg1, Object arg2) throws Throwable {
166: return module.apply2(this , arg1, arg2);
167: }
168:
169: public Object apply3(Object arg1, Object arg2, Object arg3)
170: throws Throwable {
171: return module.apply3(this , arg1, arg2, arg3);
172: }
173:
174: public Object apply4(Object arg1, Object arg2, Object arg3,
175: Object arg4) throws Throwable {
176: return module.apply4(this , arg1, arg2, arg3, arg4);
177: }
178:
179: public Object applyN(Object[] args) throws Throwable {
180: return module.applyN(this , args);
181: }
182:
183: public static Object apply0Default(ModuleMethod method)
184: throws Throwable {
185: return method.module.applyN(method, Values.noArgs);
186: }
187:
188: public static Object apply1Default(ModuleMethod method, Object arg1)
189: throws Throwable {
190: Object[] args = new Object[1];
191: args[0] = arg1;
192: return method.module.applyN(method, args);
193: }
194:
195: public static Object apply2Default(ModuleMethod method,
196: Object arg1, Object arg2) throws Throwable {
197: Object[] args = new Object[2];
198: args[0] = arg1;
199: args[1] = arg2;
200: return method.module.applyN(method, args);
201: }
202:
203: public static Object apply3Default(ModuleMethod method,
204: Object arg1, Object arg2, Object arg3) throws Throwable {
205: Object[] args = new Object[3];
206: args[0] = arg1;
207: args[1] = arg2;
208: args[2] = arg3;
209: return method.module.applyN(method, args);
210: }
211:
212: public static Object apply4Default(ModuleMethod method,
213: Object arg1, Object arg2, Object arg3, Object arg4)
214: throws Throwable {
215: Object[] args = new Object[4];
216: args[0] = arg1;
217: args[1] = arg2;
218: args[2] = arg3;
219: args[3] = arg4;
220: return method.module.applyN(method, args);
221: }
222:
223: public static Object applyNDefault(ModuleMethod method,
224: Object[] args) throws Throwable {
225: int count = args.length;
226: int num = method.numArgs();
227: ModuleBody module = method.module;
228: if (count >= (num & 0xFFF) && (num < 0 || count <= (num >> 12))) {
229: switch (count) {
230: case 0:
231: return module.apply0(method);
232: case 1:
233: return module.apply1(method, args[0]);
234: case 2:
235: return module.apply2(method, args[0], args[1]);
236: case 3:
237: return module.apply3(method, args[0], args[1], args[2]);
238: case 4:
239: return module.apply4(method, args[0], args[1], args[2],
240: args[3]);
241: }
242: }
243: throw new WrongArguments(method, count);
244: }
245:
246: /** Helper methods for default ModuleBody actions. */
247:
248: public static void applyError() {
249: throw new Error("internal error - bad selector");
250: }
251: }
|