001: // Copyright (c) 1999, 2000 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.*;
008:
009: /** A primitive Procedure implemented by a plain Java method. */
010:
011: public class PrimProcedure extends MethodProc implements
012: gnu.expr.Inlineable {
013: Type retType;
014: /** The types of the method parameters.
015: * If known, the types have been coerced to Language-specific parameters.
016: * Does not include the implicit static link argument of some constructors.
017: */
018: Type[] argTypes;
019: Method method;
020: int op_code;
021: /** 'P' means use invokespecial;
022: * 'V' means expect a target (this) argument, even if method is static;
023: * '\0' means don't expect a target. */
024: char mode;
025:
026: /** If non-null, the LambdaExp that this PrimProcedure implements. */
027: LambdaExp source;
028:
029: java.lang.reflect.Member member;
030:
031: public final int opcode() {
032: return op_code;
033: }
034:
035: public Type getReturnType() {
036: return retType;
037: }
038:
039: public void setReturnType(Type retType) {
040: this .retType = retType;
041: }
042:
043: public boolean isSpecial() {
044: return mode == 'P';
045: }
046:
047: public Type getReturnType(Expression[] args) {
048: return retType;
049: }
050:
051: public Method getMethod() {
052: return method;
053: }
054:
055: /** Return true iff the last parameter is a "rest" argument. */
056: public boolean takesVarArgs() {
057: if (method != null) {
058: String name = method.getName();
059: return name.endsWith("$V") || name.endsWith("$V$X");
060: }
061: return false;
062: }
063:
064: public boolean takesContext() {
065: return method != null && takesContext(method);
066: }
067:
068: public static boolean takesContext(Method method) {
069: return method.getName().endsWith("$X");
070: }
071:
072: public final boolean isConstructor() {
073: // invokespecial == primitive-constructor
074: return opcode() == 183 && mode != 'P';
075: }
076:
077: /** Whether we are passed an argument for the 'target' / 'receiver' / 'this'.
078: * Normally this is false for static methods and true for non-static
079: * methods. However, we may need to be able to call a static method using
080: * {@code object.name(args...)} (Java syntax) or
081: * {@code (invoke object 'name args...)} (Scheme syntax).
082: * This includes when the {@code object} is implied.
083: * In this case we need to ignore the first argument's value.
084: */
085: public boolean takesTarget() {
086: return mode != '\0';
087: }
088:
089: /** The (minimum, number) of arguments.
090: * Doesn't not count implicit CallContext argument.
091: * Does count 'this' argument for non-static methods.
092: * Does count an implicit staticLink argument for constructor.
093: */
094: public int numArgs() {
095: int num = argTypes.length;
096: if (takesTarget())
097: num++;
098: if (takesContext())
099: num--;
100: return takesVarArgs() ? (num - 1) + (-1 << 12) : num
101: + (num << 12);
102: }
103:
104: public int match0(CallContext ctx) {
105: return matchN(ProcedureN.noArgs, ctx);
106: }
107:
108: public int match1(Object arg1, CallContext ctx) {
109: Object[] args = { arg1 };
110: return matchN(args, ctx);
111: }
112:
113: public int match2(Object arg1, Object arg2, CallContext ctx) {
114: Object[] args = { arg1, arg2 };
115: return matchN(args, ctx);
116: }
117:
118: public int match3(Object arg1, Object arg2, Object arg3,
119: CallContext ctx) {
120: Object[] args = { arg1, arg2, arg3 };
121: return matchN(args, ctx);
122: }
123:
124: public int match4(Object arg1, Object arg2, Object arg3,
125: Object arg4, CallContext ctx) {
126: Object[] args = { arg1, arg2, arg3, arg4 };
127: return matchN(args, ctx);
128: }
129:
130: public int matchN(Object[] args, CallContext ctx) {
131: int nargs = args.length;
132: boolean takesVarArgs = takesVarArgs();
133: int fixArgs = minArgs();
134: if (nargs < fixArgs)
135: return NO_MATCH_TOO_FEW_ARGS | fixArgs;
136: if (!takesVarArgs && nargs > fixArgs)
137: return NO_MATCH_TOO_MANY_ARGS | fixArgs;
138: int paramCount = argTypes.length;
139: Type elementType = null;
140: Object[] restArray = null;
141: int extraCount = (takesTarget() || isConstructor()) ? 1 : 0;
142: boolean takesContext = takesContext();
143: Object[] rargs = new Object[paramCount];
144: if (takesContext)
145: rargs[--paramCount] = ctx;
146: Object extraArg;
147: if (takesVarArgs) {
148: Type restType = argTypes[paramCount - 1];
149: if (restType == Compilation.scmListType) { // FIXME
150: rargs[paramCount - 1] = gnu.lists.LList.makeList(args,
151: fixArgs);
152: nargs = fixArgs;
153: elementType = Type.pointer_type;
154: } else {
155: ArrayType restArrayType = (ArrayType) restType;
156: elementType = restArrayType.getComponentType();
157: Class elementClass = elementType.getReflectClass();
158: restArray = (Object[]) java.lang.reflect.Array
159: .newInstance(elementClass, nargs - fixArgs);
160: rargs[paramCount - 1] = restArray;
161: }
162: }
163: if (isConstructor())
164: extraArg = args[0];
165: else if (extraCount != 0) {
166: try {
167: extraArg = method.getDeclaringClass().coerceFromObject(
168: args[0]);
169: } catch (ClassCastException ex) {
170: return NO_MATCH_BAD_TYPE | 1;
171: }
172: } else
173: extraArg = null;
174: for (int i = extraCount; i < args.length; i++) {
175: Object arg = args[i];
176: Type type = i < fixArgs ? argTypes[i - extraCount]
177: : elementType;
178: if (type != Type.pointer_type) {
179: try {
180: arg = type.coerceFromObject(arg);
181: } catch (ClassCastException ex) {
182: return NO_MATCH_BAD_TYPE | (i + 1);
183: }
184: }
185: if (i < fixArgs)
186: rargs[i - extraCount] = arg;
187: else if (restArray != null) // I.e. using array rather than LList.
188: restArray[i - fixArgs] = arg;
189: }
190: ctx.value1 = extraArg;
191: ctx.values = rargs;
192: ctx.proc = this ;
193: return 0;
194: }
195:
196: public void apply(CallContext ctx) throws Throwable {
197: int arg_count = argTypes.length;
198: boolean is_constructor = isConstructor();
199: boolean slink = is_constructor
200: && method.getDeclaringClass().hasOuterLink();
201:
202: try {
203: if (member == null) {
204: Class clas = method.getDeclaringClass()
205: .getReflectClass();
206: Class[] paramTypes = new Class[arg_count
207: + (slink ? 1 : 0)];
208: for (int i = arg_count; --i >= 0;)
209: paramTypes[i + (slink ? 1 : 0)] = argTypes[i]
210: .getReflectClass();
211: if (slink)
212: paramTypes[0] = method.getDeclaringClass()
213: .getOuterLinkType().getReflectClass();
214: if (is_constructor)
215: member = clas.getConstructor(paramTypes);
216: else if (method != Type.clone_method)
217: member = clas.getMethod(method.getName(),
218: paramTypes);
219: }
220: Object result;
221: if (is_constructor) {
222: Object[] args = ctx.values;
223: if (slink) {
224: int nargs = args.length + 1;
225: Object[] xargs = new Object[nargs];
226: System.arraycopy(args, 0, xargs, 1, nargs - 1);
227: xargs[0] = ((PairClassType) ctx.value1).staticLink;
228: args = xargs;
229: }
230:
231: result = (((java.lang.reflect.Constructor) member)
232: .newInstance(args));
233: } else if (method == Type.clone_method) {
234: // The special Type.clone_method is only used for array types.
235: Object arr = ctx.value1;
236: Class elClass = arr.getClass().getComponentType();
237: int n = java.lang.reflect.Array.getLength(arr);
238: result = java.lang.reflect.Array
239: .newInstance(elClass, n);
240: System.arraycopy(arr, 0, result, 0, n);
241: } else
242: result = retType
243: .coerceToObject(((java.lang.reflect.Method) member)
244: .invoke(ctx.value1, ctx.values));
245: if (!takesContext())
246: ctx.consumer.writeObject(result);
247: } catch (java.lang.reflect.InvocationTargetException ex) {
248: throw ex.getTargetException();
249: }
250: }
251:
252: public PrimProcedure(String className, String methodName,
253: int numArgs) {
254: this (ClassType.make(className).getDeclaredMethod(methodName,
255: numArgs));
256: }
257:
258: public PrimProcedure(java.lang.reflect.Method method,
259: Language language) {
260: this (((ClassType) language.getTypeFor(method
261: .getDeclaringClass())).getMethod(method), language);
262: }
263:
264: public PrimProcedure(Method method) {
265: init(method);
266: this .retType = method.getName().endsWith("$X") ? Type.pointer_type
267: : method.getReturnType();
268: }
269:
270: public PrimProcedure(Method method, Language language) {
271: this (method, '\0', language);
272: }
273:
274: public PrimProcedure(Method method, char mode, Language language) {
275: this .mode = mode;
276:
277: init(method);
278:
279: // This stuff deals with that a language may have its own mapping
280: // from Java types to language types, for coercions and other reasons.
281: Type[] pTypes = this .argTypes;
282: int nTypes = pTypes.length;
283: argTypes = null;
284: for (int i = nTypes; --i >= 0;) {
285: Type javaType = pTypes[i];
286: if (javaType instanceof ClassType
287: && !((ClassType) javaType).isExisting())
288: continue;
289: Type langType = language.getLangTypeFor(javaType);
290: if (javaType != langType) {
291: if (argTypes == null) {
292: argTypes = new Type[nTypes];
293: System.arraycopy(pTypes, 0, argTypes, 0, nTypes);
294: }
295: argTypes[i] = langType;
296: }
297: }
298: if (argTypes == null)
299: argTypes = pTypes;
300: if (isConstructor())
301: retType = method.getDeclaringClass();
302: else if (method.getName().endsWith("$X"))
303: retType = Type.pointer_type;
304: else {
305: retType = language.getLangTypeFor(method.getReturnType());
306:
307: // Kludge - tostring_type doesn't have methods.
308: // It shouldn't be used as the "type" of anything -
309: // it's just a type with a coercion. FIXME.
310: if (retType == Type.tostring_type)
311: retType = Type.string_type;
312: }
313: }
314:
315: private void init(Method method) {
316: this .method = method;
317: int flags = method.getModifiers();
318: if ((flags & Access.STATIC) != 0)
319: this .op_code = 184; // invokestatic
320: else {
321: ClassType mclass = method.getDeclaringClass();
322: if (mode == 'P')
323: this .op_code = 183; // invokespecial
324: else {
325: mode = 'V';
326: if ("<init>".equals(method.getName()))
327: this .op_code = 183; // invokespecial
328: else if ((mclass.getModifiers() & Access.INTERFACE) != 0)
329: this .op_code = 185; // invokeinterface
330: else
331: this .op_code = 182; // invokevirtual
332: }
333: }
334: Type[] mtypes = method.getParameterTypes();
335: if (isConstructor()
336: && method.getDeclaringClass().hasOuterLink()) {
337: int len = mtypes.length - 1;
338: Type[] types = new Type[len];
339: System.arraycopy(mtypes, 1, types, 0, len);
340: mtypes = types;
341: }
342: this .argTypes = mtypes;
343: }
344:
345: public PrimProcedure(Method method, LambdaExp source) {
346: this (method);
347: this .retType = source.getReturnType();
348: this .source = source;
349: }
350:
351: public PrimProcedure(int opcode, Type retType, Type[] argTypes) {
352: this .op_code = opcode;
353: this .retType = retType;
354: this .argTypes = argTypes;
355: }
356:
357: public static PrimProcedure makeBuiltinUnary(int opcode, Type type) {
358: // FIXME - should cache!
359: Type[] args = new Type[1];
360: args[0] = type;
361: return new PrimProcedure(opcode, type, args);
362: }
363:
364: public static PrimProcedure makeBuiltinBinary(int opcode, Type type) {
365: // FIXME - should cache!
366: Type[] args = new Type[2];
367: args[0] = type;
368: args[1] = type;
369: return new PrimProcedure(opcode, type, args);
370: }
371:
372: public PrimProcedure(int op_code, ClassType classtype, String name,
373: Type retType, Type[] argTypes) {
374: this .op_code = op_code;
375: method = classtype.addMethod(name,
376: op_code == 184 ? Access.STATIC : 0, argTypes, retType);
377: this .retType = retType;
378: this .argTypes = argTypes;
379: mode = op_code == 184 ? '\0' : 'V';
380: }
381:
382: /** True if there is no 'this' parameter. */
383: public final boolean getStaticFlag() {
384: return method == null || method.getStaticFlag()
385: || isConstructor();
386: }
387:
388: public final Type[] getParameterTypes() {
389: return argTypes;
390: }
391:
392: /** Compile arguments and push unto stack.
393: * @param args arguments to evaluate and push.
394: * @param thisType If we are calling a non-static function,
395: * then args[0] is the receiver and thisType is its expected class.
396: * If thisType==Type.void_type, ignore argTypes[0]. (It is used to to
397: * pass a link to a closure environment, which was pushed by our caller.)
398: * If thisType==null, no special handling of args[0] or argTypes[0].
399: */
400: private void compileArgs(Expression[] args, int startArg,
401: Type this Type, Compilation comp) {
402: boolean variable = takesVarArgs();
403: String name = getName();
404: Type arg_type = null;
405: gnu.bytecode.CodeAttr code = comp.getCode();
406: int skipArg = this Type == Type.void_type ? 1 : 0;
407: int arg_count = argTypes.length - skipArg;
408: if (takesContext())
409: arg_count--;
410: boolean is_static = this Type == null || skipArg != 0;
411: int fix_arg_count = variable ? arg_count - 1 : args.length
412: - startArg;
413: Declaration argDecl = source == null ? null : source
414: .firstDecl();
415: if (argDecl != null && argDecl.isThisParameter())
416: argDecl = argDecl.nextDecl();
417: for (int i = 0;; ++i) {
418: if (variable && i == fix_arg_count) {
419: arg_type = argTypes[arg_count - 1 + skipArg];
420: if (arg_type == Compilation.scmListType) {
421: gnu.kawa.functions.MakeList.compile(args, startArg
422: + i, comp);
423: break;
424: }
425: code
426: .emitPushInt(args.length - startArg
427: - fix_arg_count);
428: arg_type = ((ArrayType) arg_type).getComponentType();
429: code.emitNewArray(arg_type);
430: }
431: if (i + startArg >= args.length)
432: break;
433: if (i >= fix_arg_count) {
434: code.emitDup(1); // dup array.
435: code.emitPushInt(i - fix_arg_count);
436: } else
437: arg_type = argDecl != null && (is_static || i > 0) ? argDecl
438: .getType()
439: : is_static ? argTypes[i + skipArg]
440: : i == 0 ? this Type : argTypes[i - 1];
441: comp.usedClass(arg_type);
442: Target target = source == null ? CheckedTarget.getInstance(
443: arg_type, name, i + 1) : CheckedTarget.getInstance(
444: arg_type, source, i);
445: args[startArg + i].compileNotePosition(comp, target,
446: args[startArg + i]);
447: if (i >= fix_arg_count)
448: code.emitArrayStore(arg_type);
449: if (argDecl != null && (is_static || i > 0))
450: argDecl = argDecl.nextDecl();
451: }
452: }
453:
454: public void compile(ApplyExp exp, Compilation comp, Target target) {
455: gnu.bytecode.CodeAttr code = comp.getCode();
456: ClassType mclass = method == null ? null : method
457: .getDeclaringClass();
458: Expression[] args = exp.getArgs();
459: if (isConstructor()) {
460: code.emitNew(mclass);
461: code.emitDup(mclass);
462: }
463: String arg_error = WrongArguments.checkArgCount(this ,
464: args.length);
465: if (arg_error != null)
466: comp.error('e', arg_error);
467:
468: compile(getStaticFlag() ? null : mclass, exp, comp, target);
469: }
470:
471: void compile(Type this Type, ApplyExp exp, Compilation comp,
472: Target target) {
473: Expression[] args = exp.getArgs();
474: gnu.bytecode.CodeAttr code = comp.getCode();
475: Type stackType = retType;
476: int startArg = 0;
477: if (isConstructor()) {
478: ClassType mclass = method == null ? null : method
479: .getDeclaringClass();
480: if (mclass.hasOuterLink()) {
481: // This can be optimized in most cases. FIXME.
482: args[0].compile(comp, Target
483: .pushValue(Compilation.typeClassType));
484: code.emitInvokeStatic(ClassType.make(
485: "gnu.expr.PairClassType").getDeclaredMethod(
486: "extractStaticLink", 1));
487: code.emitCheckcast(mclass.getOuterLinkType());
488: this Type = Type.void_type;
489: } else
490: this Type = null;
491: startArg = 1;
492: } else if (takesTarget() && method.getStaticFlag())
493: startArg = 1;
494:
495: compileArgs(args, startArg, this Type, comp);
496:
497: if (method == null) {
498: code.emitPrimop(opcode(), args.length, retType);
499: target.compileFromStack(comp, stackType);
500: } else {
501: compileInvoke(comp, method, target, exp.isTailCall(),
502: op_code, stackType);
503: }
504: }
505:
506: /** Emit the actual invoke operation, after arguments have been pushed.
507: * Does whatever magic is needed to pass the result to target,
508: * including passing CallContext or special handling of ConsumerTarget.
509: */
510: public static void compileInvoke(Compilation comp, Method method,
511: Target target, boolean isTailCall, int op_code,
512: Type stackType) {
513: CodeAttr code = comp.getCode();
514: comp.usedClass(method.getDeclaringClass());
515: comp.usedClass(method.getReturnType());
516: if (!takesContext(method)) {
517: code.emitInvokeMethod(method, op_code);
518: } else if (target instanceof IgnoreTarget
519: || (target instanceof ConsumerTarget && ((ConsumerTarget) target)
520: .isContextTarget())) {
521: Field consumerFld = null;
522: Variable saveCallContext = null;
523: comp.loadCallContext();
524: if (target instanceof IgnoreTarget) {
525: ClassType typeCallContext = Compilation.typeCallContext;
526: consumerFld = typeCallContext
527: .getDeclaredField("consumer");
528:
529: // Consumer saveConsumer = ctx.consumer;
530: // ctx.consumer = VoidConsumer.instance:
531: code.pushScope();
532: saveCallContext = code.addLocal(typeCallContext);
533: code.emitDup();
534: code.emitGetField(consumerFld);
535: code.emitStore(saveCallContext);
536: code.emitDup();
537: code.emitGetStatic(ClassType.make(
538: "gnu.lists.VoidConsumer").getDeclaredField(
539: "instance"));
540: code.emitPutField(consumerFld);
541: }
542: code.emitInvokeMethod(method, op_code);
543: if (isTailCall) {
544: comp.loadCallContext();
545: code.emitInvoke(Compilation.typeCallContext
546: .getDeclaredMethod("runUntilDone", 0));
547: }
548: if (target instanceof IgnoreTarget) {
549: // ctx.consumer = saveConsumer
550: comp.loadCallContext();
551: code.emitLoad(saveCallContext);
552: code.emitPutField(consumerFld);
553: code.popScope();
554: }
555: return;
556: } else {
557: comp.loadCallContext();
558: stackType = Type.pointer_type;
559: code.pushScope();
560: Variable saveIndex = code.addLocal(Type.int_type);
561: comp.loadCallContext();
562: code.emitInvokeVirtual(Compilation.typeCallContext
563: .getDeclaredMethod("startFromContext", 0));
564: code.emitStore(saveIndex);
565: code.emitWithCleanupStart();
566: code.emitInvokeMethod(method, op_code);
567: code.emitWithCleanupCatch(null);
568: comp.loadCallContext();
569: code.emitLoad(saveIndex);
570: code.emitInvokeVirtual(Compilation.typeCallContext
571: .getDeclaredMethod("cleanupFromContext", 1));
572: code.emitWithCleanupDone();
573: comp.loadCallContext();
574: code.emitLoad(saveIndex);
575: code.emitInvokeVirtual(Compilation.typeCallContext
576: .getDeclaredMethod("getFromContext", 1));
577: code.popScope();
578: }
579: target.compileFromStack(comp, stackType);
580: }
581:
582: public Type getParameterType(int index) {
583: if (takesTarget()) {
584: if (index == 0)
585: return isConstructor() ? Type.pointer_type : method
586: .getDeclaringClass();
587: index--;
588: }
589: int lenTypes = argTypes.length;
590: if (index < lenTypes - 1)
591: return argTypes[index];
592: boolean varArgs = takesVarArgs();
593: if (index < lenTypes && !varArgs)
594: return argTypes[index];
595: // if (! varArgs) ERROR;
596: Type restType = argTypes[lenTypes - 1];
597: if (restType instanceof ArrayType)
598: return ((ArrayType) restType).getComponentType();
599: else
600: // Should be LList or some other Sequence class.
601: return Type.pointer_type;
602: }
603:
604: // This is null in JDK 1.1 and something else in JDK 1.2.
605: private static ClassLoader systemClassLoader = PrimProcedure.class
606: .getClassLoader();
607:
608: public static PrimProcedure getMethodFor(Procedure pproc,
609: Expression[] args) {
610: return getMethodFor(pproc, null, args, Language
611: .getDefaultLanguage());
612: }
613:
614: /** Search for a matching static method in a procedure's class.
615: * @return a PrimProcedure that is suitable, or null. */
616: public static PrimProcedure getMethodFor(Procedure pproc,
617: Declaration decl, Expression[] args, Language language) {
618: int nargs = args.length;
619: Type[] atypes = new Type[nargs];
620: for (int i = nargs; --i >= 0;)
621: atypes[i] = args[i].getType();
622: return getMethodFor(pproc, decl, atypes, language);
623: }
624:
625: public static PrimProcedure getMethodFor(Procedure pproc,
626: Declaration decl, Type[] atypes, Language language) {
627: if (pproc instanceof GenericProc) {
628: GenericProc gproc = (GenericProc) pproc;
629: MethodProc[] methods = gproc.methods;
630: pproc = null;
631: for (int i = gproc.count; --i >= 0;) {
632: int applic = methods[i].isApplicable(atypes);
633: if (applic < 0)
634: continue;
635: if (pproc != null)
636: return null; // Ambiguous.
637: pproc = methods[i];
638: }
639: if (pproc == null)
640: return null;
641: }
642: if (pproc instanceof PrimProcedure) {
643: PrimProcedure prproc = (PrimProcedure) pproc;
644: if (prproc.isApplicable(atypes) >= 0)
645: return prproc;
646: }
647: Class pclass = getProcedureClass(pproc);
648: if (pclass == null)
649: return null;
650: return getMethodFor((ClassType) Type.make(pclass), pproc
651: .getName(), decl, atypes, language);
652: }
653:
654: public static Class getProcedureClass(Object pproc) {
655: Class procClass;
656: if (pproc instanceof ModuleMethod)
657: procClass = ((ModuleMethod) pproc).module.getClass();
658: else
659: procClass = pproc.getClass();
660: try {
661: if (procClass.getClassLoader() == systemClassLoader)
662: return procClass;
663: } catch (SecurityException ex) {
664: }
665: return null;
666: }
667:
668: /** Get PrimProcedure for matching method in given class. */
669: public static PrimProcedure getMethodFor(Class procClass,
670: String name, Declaration decl, Expression[] args,
671: Language language) {
672: return getMethodFor((ClassType) Type.make(procClass), name,
673: decl, args, language);
674: }
675:
676: public static PrimProcedure getMethodFor(ClassType procClass,
677: String name, Declaration decl, Expression[] args,
678: Language language) {
679: int nargs = args.length;
680: Type[] atypes = new Type[nargs];
681: for (int i = nargs; --i >= 0;)
682: atypes[i] = args[i].getType();
683: return getMethodFor(procClass, name, decl, atypes, language);
684: }
685:
686: public static PrimProcedure getMethodFor(ClassType procClass,
687: String name, Declaration decl, Type[] atypes,
688: Language language) {
689: PrimProcedure best = null;
690: int bestCode = -1;
691: boolean bestIsApply = false;
692: try {
693: if (name == null)
694: return null;
695: String mangledName = Compilation.mangleName(name);
696: String mangledNameV = mangledName + "$V";
697: String mangledNameVX = mangledName + "$V$X";
698: String mangledNameX = mangledName + "$X";
699: boolean applyOk = true; // Also look for "apply" and "apply$V".
700: for (Method meth = procClass.getDeclaredMethods(); meth != null; meth = meth
701: .getNext()) {
702: int mods = meth.getModifiers();
703: if ((mods & (Access.STATIC | Access.PUBLIC)) != (Access.STATIC | Access.PUBLIC)) {
704: if (decl == null || decl.base == null)
705: continue;
706: }
707: String mname = meth.getName();
708: boolean isApply;
709: if (mname.equals(mangledName)
710: || mname.equals(mangledNameV)
711: || mname.equals(mangledNameX)
712: || mname.equals(mangledNameVX)) {
713: isApply = false;
714: } else if (applyOk
715: && (mname.equals("apply") || mname
716: .equals("apply$V"))) {
717: isApply = true;
718: } else
719: continue;
720: if (!isApply) {
721: // If we saw a real match, ignore "apply".
722: applyOk = false;
723: if (bestIsApply) {
724: best = null;
725: bestCode = -1;
726: bestIsApply = false;
727: }
728: }
729: PrimProcedure prproc = new PrimProcedure(meth, language);
730: prproc.setName(name);
731: int code = prproc.isApplicable(atypes);
732: if (code < 0 || code < bestCode)
733: continue;
734: if (code > bestCode) {
735: best = prproc;
736: } else if (best != null) {
737: best = (PrimProcedure) MethodProc.mostSpecific(
738: best, prproc);
739: if (best == null) { // Ambiguous.
740: if (bestCode > 0)
741: return null;
742: }
743: }
744: bestCode = code;
745: bestIsApply = isApply;
746: }
747: } catch (SecurityException ex) {
748: }
749: return best;
750: }
751:
752: public String getName() {
753: String name = super .getName();
754: if (name != null)
755: return name;
756: name = getVerboseName();
757: setName(name);
758: return name;
759: }
760:
761: public String getVerboseName() {
762: StringBuffer buf = new StringBuffer(100);
763: if (method == null) {
764: buf.append("<op ");
765: buf.append(op_code);
766: buf.append('>');
767: } else {
768: buf.append(method.getDeclaringClass().getName());
769: buf.append('.');
770: buf.append(method.getName());
771: }
772: buf.append('(');
773: for (int i = 0; i < argTypes.length; i++) {
774: if (i > 0)
775: buf.append(',');
776: buf.append(argTypes[i].getName());
777: }
778: buf.append(')');
779: return buf.toString();
780: }
781:
782: public String toString() {
783: StringBuffer buf = new StringBuffer(100);
784: buf.append(retType.getName());
785: buf.append(' ');
786: buf.append(getVerboseName());
787: return buf.toString();
788: }
789:
790: public void print(java.io.PrintWriter ps) {
791: ps.print("#<primitive procedure ");
792: ps.print(toString());
793: ps.print('>');
794: }
795: }
|