1 4 package gnu.expr; 5 import gnu.bytecode.*; 6 import gnu.mapping.*; 7 8 9 10 public class PrimProcedure extends MethodProc implements gnu.expr.Inlineable 11 { 12 Type retType; 13 17 Type[] argTypes; 18 Method method; 19 int op_code; 20 23 char mode; 24 25 26 LambdaExp source; 27 28 java.lang.reflect.Member member; 29 30 public final int opcode() { return op_code; } 31 32 public Type getReturnType () { return retType; } 33 public void setReturnType (Type retType) { this.retType = retType; } 34 35 public boolean isSpecial() { return mode == 'P'; } 36 37 public Type getReturnType (Expression[] args) { return retType; } 38 39 40 public boolean takesVarArgs() 41 { 42 if (method != null) 43 { 44 String name = method.getName(); 45 return name.endsWith("$V") || name.endsWith("$V$X"); 46 } 47 return false; 48 } 49 50 public boolean takesContext() 51 { 52 return method != null && takesContext(method); 53 } 54 55 public static boolean takesContext(Method method) 56 { 57 return method.getName().endsWith("$X"); 58 } 59 60 public final boolean isConstructor() 61 { 62 return opcode() == 183 && mode != 'P'; 64 } 65 66 74 public boolean takesTarget () 75 { 76 return mode != '\0'; 77 } 78 79 84 public int numArgs() 85 { 86 int num = argTypes.length; 87 if (takesTarget()) 88 num++; 89 if (takesContext()) 90 num--; 91 return takesVarArgs() ? (num - 1) + (-1 << 12) : num + (num << 12); 92 } 93 94 public int match0 (CallContext ctx) 95 { 96 return matchN(ProcedureN.noArgs, ctx); 97 } 98 99 public int match1 (Object arg1, CallContext ctx) 100 { 101 Object [] args = { arg1 }; 102 return matchN(args, ctx); 103 } 104 105 public int match2 (Object arg1, Object arg2, CallContext ctx) 106 { 107 Object [] args = { arg1, arg2 }; 108 return matchN(args, ctx); 109 } 110 111 public int match3 (Object arg1, Object arg2, Object arg3, CallContext ctx) 112 { 113 Object [] args = { arg1, arg2, arg3 }; 114 return matchN(args, ctx); 115 } 116 117 public int match4 (Object arg1, Object arg2, Object arg3, Object arg4, 118 CallContext ctx) 119 { 120 Object [] args = { arg1, arg2, arg3, arg4 }; 121 return matchN(args, ctx); 122 } 123 124 public int matchN (Object [] args, CallContext ctx) 125 { 126 int nargs = args.length; 127 boolean takesVarArgs = takesVarArgs(); 128 int fixArgs = minArgs(); 129 if (nargs < fixArgs) 130 return NO_MATCH_TOO_FEW_ARGS|fixArgs; 131 if (! takesVarArgs && nargs > fixArgs) 132 return NO_MATCH_TOO_MANY_ARGS|fixArgs; 133 int paramCount = argTypes.length; 134 Type elementType = null; 135 Object [] restArray = null; 136 int extraCount = (takesTarget() || isConstructor()) ? 1 : 0; 137 boolean takesContext = takesContext(); 138 Object [] rargs = new Object [paramCount]; 139 if (takesContext) 140 rargs[--paramCount] = ctx; 141 Object extraArg; 142 if (takesVarArgs) 143 { 144 Type restType = argTypes[paramCount-1]; 145 if (restType == Compilation.scmListType) 146 { rargs[paramCount-1] = gnu.lists.LList.makeList(args, fixArgs); 148 nargs = fixArgs; 149 elementType = Type.pointer_type; 150 } 151 else 152 { 153 ArrayType restArrayType = (ArrayType) restType; 154 elementType = restArrayType.getComponentType(); 155 Class elementClass = elementType.getReflectClass(); 156 restArray = (Object []) 157 java.lang.reflect.Array.newInstance(elementClass, nargs-fixArgs); 158 rargs[paramCount-1] = restArray; 159 } 160 } 161 if (isConstructor()) 162 extraArg = args[0]; 163 else if (extraCount != 0) 164 { 165 try 166 { 167 extraArg = method.getDeclaringClass().coerceFromObject(args[0]); 168 } 169 catch (ClassCastException ex) 170 { 171 return NO_MATCH_BAD_TYPE|1; 172 } 173 } 174 else 175 extraArg = null; 176 for (int i = extraCount; i < args.length; i++) 177 { 178 Object arg = args[i]; 179 Type type = i < fixArgs ? argTypes[i-extraCount] : elementType; 180 if (type != Type.pointer_type) 181 { 182 try 183 { 184 arg = type.coerceFromObject(arg); 185 } 186 catch (ClassCastException ex) 187 { 188 return NO_MATCH_BAD_TYPE|(i+1); 189 } 190 } 191 if (i < fixArgs) 192 rargs[i-extraCount] = arg; 193 else if (restArray != null) restArray[i - fixArgs] = arg; 195 } 196 ctx.value1 = extraArg; 197 ctx.values = rargs; 198 ctx.proc = this; 199 return 0; 200 } 201 202 public void apply (CallContext ctx) throws Throwable 203 { 204 int arg_count = argTypes.length; 205 boolean is_constructor = isConstructor(); 206 boolean slink = is_constructor && method.getDeclaringClass().hasOuterLink(); 207 208 try 209 { 210 if (member == null) 211 { 212 Class clas = method.getDeclaringClass().getReflectClass(); 213 Class [] paramTypes = new Class [arg_count+(slink?1:0)]; 214 for (int i = arg_count; --i >= 0; ) 215 paramTypes[i+(slink?1:0)] = argTypes[i].getReflectClass(); 216 if (slink) 217 paramTypes[0] = method.getDeclaringClass().getOuterLinkType().getReflectClass(); 218 if (is_constructor) 219 member = clas.getConstructor(paramTypes); 220 else 221 member = clas.getMethod(method.getName(), paramTypes); 222 } 223 Object result; 224 if (is_constructor) 225 { 226 Object [] args = ctx.values; 227 if (slink) 228 { 229 int nargs = args.length + 1; 230 Object [] xargs = new Object [nargs]; 231 System.arraycopy(args, 0, xargs, 1, nargs-1); 232 xargs[0] = ((PairClassType) ctx.value1).staticLink; 233 args = xargs; 234 } 235 236 result = (((java.lang.reflect.Constructor ) member) 237 .newInstance(args)); 238 } 239 else 240 result = retType.coerceToObject(((java.lang.reflect.Method ) member) 241 .invoke(ctx.value1, ctx.values)); 242 if (! takesContext()) 243 ctx.consumer.writeObject(result); 244 } 245 catch (java.lang.reflect.InvocationTargetException ex) 246 { 247 throw ex.getTargetException(); 248 } 249 } 250 251 public PrimProcedure (String className, String methodName, int numArgs) 252 { 253 this(ClassType.make(className).getDeclaredMethod(methodName, numArgs)); 254 } 255 256 public PrimProcedure(java.lang.reflect.Method method, Language language) 257 { 258 this(((ClassType) language.getTypeFor(method.getDeclaringClass())) 259 .getMethod(method), language); 260 } 261 262 public PrimProcedure(Method method) 263 { 264 init(method); 265 this.retType = method.getName().endsWith("$X") ? Type.pointer_type 266 : method.getReturnType(); 267 } 268 269 public PrimProcedure(Method method, Language language) 270 { 271 this(method, '\0', language); 272 } 273 274 public PrimProcedure(Method method, char mode, Language language) 275 { 276 this.mode = mode; 277 278 init(method); 279 280 Type[] pTypes = this.argTypes; 283 int nTypes = pTypes.length; 284 argTypes = null; 285 for (int i = nTypes; --i >= 0; ) 286 { 287 Type javaType = pTypes[i]; 288 if (javaType instanceof ClassType 289 && ! ((ClassType) javaType).isExisting()) 290 continue; 291 Type langType = language.getLangTypeFor(javaType); 292 if (javaType != langType) 293 { 294 if (argTypes == null) 295 { 296 argTypes = new Type[nTypes]; 297 System.arraycopy(pTypes, 0, argTypes, 0, nTypes); 298 } 299 argTypes[i] = langType; 300 } 301 } 302 if (argTypes == null) 303 argTypes = pTypes; 304 if (isConstructor()) 305 retType = method.getDeclaringClass(); 306 else if (method.getName().endsWith("$X")) 307 retType = Type.pointer_type; 308 else 309 { 310 retType = language.getLangTypeFor(method.getReturnType()); 311 312 if (retType == Type.tostring_type) 316 retType = Type.string_type; 317 } 318 } 319 320 private void init(Method method) 321 { 322 this.method = method; 323 int flags = method.getModifiers(); 324 if ((flags & Access.STATIC) != 0) 325 this.op_code = 184; else 327 { 328 ClassType mclass = method.getDeclaringClass(); 329 if (mode == 'P') 330 this.op_code = 183; else 332 { 333 mode = 'V'; 334 if ("<init>".equals(method.getName())) 335 this.op_code = 183; else if ((mclass.getModifiers() & Access.INTERFACE) != 0) 337 this.op_code = 185; else 339 this.op_code = 182; } 341 } 342 Type[] mtypes = method.getParameterTypes(); 343 if (isConstructor() && method.getDeclaringClass().hasOuterLink()) 344 { 345 int len = mtypes.length-1; 346 Type[] types = new Type[len]; 347 System.arraycopy(mtypes, 1, types, 0, len); 348 mtypes = types; 349 } 350 this.argTypes = mtypes; 351 } 352 353 public PrimProcedure(Method method, LambdaExp source) 354 { 355 this(method); 356 this.retType = source.getReturnType(); 357 this.source = source; 358 } 359 360 public PrimProcedure(int opcode, Type retType, Type[] argTypes) 361 { 362 this.op_code = opcode; 363 this.retType = retType; 364 this.argTypes= argTypes; 365 } 366 367 public static PrimProcedure makeBuiltinUnary(int opcode, Type type) 368 { 369 Type[] args = new Type[1]; 371 args[0] = type; 372 return new PrimProcedure(opcode, type, args); 373 } 374 375 public static PrimProcedure makeBuiltinBinary(int opcode, Type type) 376 { 377 Type[] args = new Type[2]; 379 args[0] = type; 380 args[1] = type; 381 return new PrimProcedure(opcode, type, args); 382 } 383 384 public PrimProcedure(int op_code, ClassType classtype, String name, 385 Type retType, Type[] argTypes) 386 { 387 this.op_code = op_code; 388 method = classtype.addMethod (name, op_code == 184 ? Access.STATIC : 0, 389 argTypes, retType); 390 this.retType = retType; 391 this.argTypes= argTypes; 392 mode = op_code == 184 ? '\0' : 'V'; 393 } 394 395 396 public final boolean getStaticFlag() 397 { 398 return method == null 399 || method.getStaticFlag() 400 || isConstructor(); 401 } 402 403 public final Type[] getParameterTypes() { return argTypes; } 404 405 413 private void compileArgs(Expression[] args, int startArg, Type thisType, Compilation comp) 414 { 415 boolean variable = takesVarArgs(); 416 String name = getName(); 417 Type arg_type = null; 418 gnu.bytecode.CodeAttr code = comp.getCode(); 419 int skipArg = thisType == Type.void_type ? 1 : 0; 420 int arg_count = argTypes.length - skipArg; 421 if (takesContext()) 422 arg_count--; 423 boolean is_static = thisType == null || skipArg != 0; 424 int fix_arg_count = variable ? arg_count - 1 : args.length - startArg; 425 Declaration argDecl = source == null ? null : source.firstDecl(); 426 if (argDecl != null && argDecl.isThisParameter()) 427 argDecl = argDecl.nextDecl(); 428 for (int i = 0; ; ++i) 429 { 430 if (variable && i == fix_arg_count) 431 { 432 arg_type = argTypes[arg_count-1+skipArg]; 433 if (arg_type == Compilation.scmListType) 434 { 435 gnu.kawa.functions.MakeList.compile(args, startArg+i, comp); 436 break; 437 } 438 code.emitPushInt(args.length - startArg - fix_arg_count); 439 arg_type = ((ArrayType) arg_type).getComponentType(); 440 code.emitNewArray(arg_type); 441 } 442 if (i + startArg >= args.length) 443 break; 444 if (i >= fix_arg_count) 445 { 446 code.emitDup(1); code.emitPushInt(i - fix_arg_count); 448 } 449 else 450 arg_type = argDecl != null && (is_static || i > 0) ? argDecl.getType() 451 : is_static ? argTypes[i + skipArg] 452 : i==0 ? thisType 453 : argTypes[i-1]; 454 comp.usedClass(arg_type); 455 Target target = 456 source == null ? CheckedTarget.getInstance(arg_type, name, i+1) 457 : CheckedTarget.getInstance(arg_type, source, i); 458 args[startArg+i].compileNotePosition(comp, target, args[startArg+i]); 459 if (i >= fix_arg_count) 460 code.emitArrayStore(arg_type); 461 if (argDecl != null && (is_static || i > 0)) 462 argDecl = argDecl.nextDecl(); 463 } 464 } 465 466 public void compile (ApplyExp exp, Compilation comp, Target target) 467 { 468 gnu.bytecode.CodeAttr code = comp.getCode(); 469 ClassType mclass = method == null ? null : method.getDeclaringClass(); 470 Expression[] args = exp.getArgs(); 471 if (isConstructor()) 472 { 473 code.emitNew(mclass); 474 code.emitDup(mclass); 475 } 476 String arg_error = WrongArguments.checkArgCount(this, args.length); 477 if (arg_error != null) 478 comp.error('e', arg_error); 479 480 compile(getStaticFlag() ? null : mclass, exp, comp, target); 481 } 482 483 void compile (Type thisType, ApplyExp exp, Compilation comp, Target target) 484 { 485 Expression[] args = exp.getArgs(); 486 gnu.bytecode.CodeAttr code = comp.getCode(); 487 Type stackType = retType; 488 int startArg = 0; 489 if (isConstructor()) 490 { 491 ClassType mclass = method == null ? null : method.getDeclaringClass(); 492 if (mclass.hasOuterLink()) 493 { 494 args[0].compile(comp, Target.pushValue(Compilation.typeClassType)); 496 code.emitInvokeStatic(ClassType.make("gnu.expr.PairClassType").getDeclaredMethod("extractStaticLink", 1)); 497 code.emitCheckcast(mclass.getOuterLinkType()); 498 thisType = Type.void_type; 499 } 500 else 501 thisType = null; 502 startArg = 1; 503 } 504 else if (takesTarget() && method.getStaticFlag()) 505 startArg = 1; 506 507 compileArgs(args, startArg, thisType, comp); 508 509 if (method == null) 510 { 511 code.emitPrimop (opcode(), args.length, retType); 512 target.compileFromStack(comp, stackType); 513 } 514 else 515 { 516 compileInvoke(comp, method, target, 517 exp.isTailCall(), op_code, stackType); 518 } 519 } 520 521 525 public static void 526 compileInvoke (Compilation comp, Method method, Target target, 527 boolean isTailCall, int op_code, Type stackType) 528 { 529 CodeAttr code = comp.getCode(); 530 comp.usedClass(method.getDeclaringClass()); 531 comp.usedClass(method.getReturnType()); 532 if (! takesContext(method)) 533 { 534 code.emitInvokeMethod(method, op_code); 535 } 536 else if (target instanceof IgnoreTarget 537 || (target instanceof ConsumerTarget 538 && ((ConsumerTarget) target).isContextTarget())) 539 { 540 Field consumerFld = null; 541 Variable saveCallContext = null; 542 comp.loadCallContext(); 543 if (target instanceof IgnoreTarget) 544 { 545 ClassType typeCallContext = Compilation.typeCallContext; 546 consumerFld = typeCallContext.getDeclaredField("consumer"); 547 548 code.pushScope(); 551 saveCallContext = code.addLocal(typeCallContext); 552 code.emitDup(); 553 code.emitGetField(consumerFld); 554 code.emitStore(saveCallContext); 555 code.emitDup(); 556 code.emitGetStatic(ClassType.make("gnu.lists.VoidConsumer") 557 .getDeclaredField("instance")); 558 code.emitPutField(consumerFld); 559 } 560 code.emitInvokeMethod(method, op_code); 561 if (isTailCall) 562 { 563 comp.loadCallContext(); 564 code.emitInvoke(Compilation.typeCallContext 565 .getDeclaredMethod("runUntilDone", 0)); 566 } 567 if (target instanceof IgnoreTarget) 568 { 569 comp.loadCallContext(); 571 code.emitLoad(saveCallContext); 572 code.emitPutField(consumerFld); 573 code.popScope(); 574 } 575 return; 576 } 577 else 578 { 579 comp.loadCallContext(); 580 stackType = Type.pointer_type; 581 code.pushScope(); 582 Variable saveIndex = code.addLocal(Type.int_type); 583 comp.loadCallContext(); 584 code.emitInvokeVirtual(Compilation.typeCallContext. 585 getDeclaredMethod("startFromContext", 0)); 586 code.emitStore(saveIndex); 587 code.emitWithCleanupStart(); 588 code.emitInvokeMethod(method, op_code); 589 code.emitWithCleanupCatch(null); 590 comp.loadCallContext(); 591 code.emitLoad(saveIndex); 592 code.emitInvokeVirtual(Compilation.typeCallContext. 593 getDeclaredMethod("cleanupFromContext", 1)); 594 code.emitWithCleanupDone(); 595 comp.loadCallContext(); 596 code.emitLoad(saveIndex); 597 code.emitInvokeVirtual(Compilation.typeCallContext. 598 getDeclaredMethod("getFromContext", 1)); 599 code.popScope(); 600 } 601 target.compileFromStack(comp, stackType); 602 } 603 604 public Type getParameterType(int index) 605 { 606 if (takesTarget()) 607 { 608 if (index == 0) 609 return isConstructor() ? Type.pointer_type 610 : method.getDeclaringClass(); 611 index--; 612 } 613 int lenTypes = argTypes.length; 614 if (index < lenTypes - 1) 615 return argTypes[index]; 616 boolean varArgs = takesVarArgs(); 617 if (index < lenTypes && ! varArgs) 618 return argTypes[index]; 619 Type restType = argTypes[lenTypes - 1]; 621 if (restType instanceof ArrayType) 622 return ((ArrayType) restType).getComponentType(); 623 else return Type.pointer_type; 625 } 626 627 private static ClassLoader systemClassLoader 629 = PrimProcedure.class.getClassLoader(); 630 631 public static PrimProcedure getMethodFor (Procedure pproc, Expression[] args) 632 { 633 return getMethodFor(pproc, null, args, Language.getDefaultLanguage()); 634 } 635 636 638 public static PrimProcedure getMethodFor (Procedure pproc, Declaration decl, 639 Expression[] args, 640 Language language) 641 { 642 int nargs = args.length; 643 Type[] atypes = new Type[nargs]; 644 for (int i = nargs; --i >= 0;) atypes[i] = args[i].getType(); 645 return getMethodFor(pproc, decl, atypes, language); 646 } 647 648 public static PrimProcedure getMethodFor (Procedure pproc, Declaration decl, 649 Type[] atypes, Language language) 650 { 651 if (pproc instanceof GenericProc) 652 { 653 GenericProc gproc = (GenericProc) pproc; 654 MethodProc[] methods = gproc.methods; 655 pproc = null; 656 for (int i = gproc.count; --i >= 0; ) 657 { 658 int applic = methods[i].isApplicable(atypes); 659 if (applic < 0) 660 continue; 661 if (pproc != null) 662 return null; pproc = methods[i]; 664 } 665 if (pproc == null) 666 return null; 667 } 668 if (pproc instanceof PrimProcedure) 669 { 670 PrimProcedure prproc = (PrimProcedure) pproc; 671 if (prproc.isApplicable(atypes) >= 0) 672 return prproc; 673 } 674 Class pclass = getProcedureClass(pproc); 675 if (pclass == null) 676 return null; 677 return getMethodFor((ClassType) Type.make(pclass), pproc.getName(), 678 decl, atypes, language); 679 } 680 681 public static Class getProcedureClass (Object pproc) 682 { 683 Class procClass; 684 if (pproc instanceof ModuleMethod) 685 procClass = ((ModuleMethod) pproc).module.getClass(); 686 else 687 procClass = pproc.getClass(); 688 try 689 { 690 if (procClass.getClassLoader() == systemClassLoader) 691 return procClass; 692 } 693 catch (SecurityException ex) 694 { 695 } 696 return null; 697 } 698 699 700 public static PrimProcedure 701 getMethodFor (Class procClass, String name, Declaration decl, 702 Expression[] args, Language language) 703 { 704 return getMethodFor((ClassType) Type.make(procClass), 705 name, decl, args, language); 706 } 707 708 public static PrimProcedure 709 getMethodFor (ClassType procClass, String name, Declaration decl, 710 Expression[] args, Language language) 711 { 712 int nargs = args.length; 713 Type[] atypes = new Type[nargs]; 714 for (int i = nargs; --i >= 0;) atypes[i] = args[i].getType(); 715 return getMethodFor(procClass, name, decl, atypes, language); 716 } 717 718 public static PrimProcedure 719 getMethodFor (ClassType procClass, String name, Declaration decl, 720 Type[] atypes, Language language) 721 { 722 PrimProcedure best = null; 723 int bestCode = -1; 724 boolean bestIsApply = false; 725 try 726 { 727 if (name == null) 728 return null; 729 String mangledName = Compilation.mangleName(name); 730 String mangledNameV = mangledName + "$V"; 731 String mangledNameVX = mangledName + "$V$X"; 732 String mangledNameX = mangledName + "$X"; 733 boolean applyOk = true; for (Method meth = procClass.getDeclaredMethods(); 735 meth != null; meth = meth.getNext()) 736 { 737 int mods = meth.getModifiers(); 738 if ((mods & (Access.STATIC|Access.PUBLIC)) 739 != (Access.STATIC|Access.PUBLIC)) 740 { 741 if (decl == null || decl.base == null) 742 continue; 743 } 744 String mname = meth.getName(); 745 boolean isApply; 746 if (mname.equals(mangledName) 747 || mname.equals(mangledNameV) 748 || mname.equals(mangledNameX) 749 || mname.equals(mangledNameVX)) 750 { 751 isApply = false; 752 } 753 else if (applyOk 754 && (mname.equals("apply") || mname.equals("apply$V"))) 755 { 756 isApply = true; 757 } 758 else 759 continue; 760 if (! isApply) 761 { 762 applyOk = false; 764 if (bestIsApply) 765 { 766 best = null; 767 bestCode = -1; 768 bestIsApply = false; 769 } 770 } 771 PrimProcedure prproc = new PrimProcedure(meth, language); 772 prproc.setName(name); 773 int code = prproc.isApplicable(atypes); 774 if (code < 0 || code < bestCode) 775 continue; 776 if (code > bestCode) 777 { 778 best = prproc; 779 } 780 else if (best != null) 781 { 782 best = (PrimProcedure) MethodProc.mostSpecific(best, prproc); 783 if (best == null) 784 { if (bestCode > 0) 786 return null; 787 } 788 } 789 bestCode = code; 790 bestIsApply = isApply; 791 } 792 } 793 catch (SecurityException ex) 794 { 795 } 796 return best; 797 } 798 799 public String getName() 800 { 801 String name = super.getName(); 802 if (name != null) 803 return name; 804 name = getVerboseName(); 805 setName(name); 806 return name; 807 } 808 809 public String getVerboseName() 810 { 811 StringBuffer buf = new StringBuffer (100); 812 if (method == null) 813 { 814 buf.append("<op "); 815 buf.append(op_code); 816 buf.append('>'); 817 } 818 else 819 { 820 buf.append(method.getDeclaringClass().getName()); 821 buf.append('.'); 822 buf.append(method.getName()); 823 } 824 buf.append('('); 825 for (int i = 0; i < argTypes.length; i++) 826 { 827 if (i > 0) 828 buf.append(','); 829 buf.append(argTypes[i].getName()); 830 } 831 buf.append(')'); 832 return buf.toString(); 833 } 834 835 836 public String toString() 837 { 838 StringBuffer buf = new StringBuffer (100); 839 buf.append(retType.getName()); 840 buf.append(' '); 841 buf.append(getVerboseName()); 842 return buf.toString(); 843 } 844 845 public void print(java.io.PrintWriter ps) 846 { 847 ps.print("#<primitive procedure "); 848 ps.print(toString()); 849 ps.print ('>'); 850 } 851 } 852 | Popular Tags |