1 // Copyright (c) 2008, 2011 Per M.A. Bothner. 2 // This is free software; for terms and warranty disclaimer see ./COPYING. 3 4 package gnu.expr; 5 import gnu.bytecode.*; 6 import gnu.kawa.io.OutPort; 7 import gnu.mapping.*; 8 import java.util.*; 9 import java.lang.annotation.ElementType; 10 11 public class ClassExp extends LambdaExp 12 { 13 int state; 14 static final int PARTS_PREDECLARED = 1; 15 static final int TYPES_SET = 2; 16 static final int PARTS_DECLARED = 3; 17 18 private boolean simple; isSimple()19 public boolean isSimple() { return simple; } 20 isAbstract()21 public final boolean isAbstract() { return getFlag(IS_ABSTRACT); } 22 public static final int IS_ABSTRACT = LambdaExp.NEXT_AVAIL_FLAG; 23 public static final int INTERFACE_SPECIFIED = 2 * LambdaExp.NEXT_AVAIL_FLAG; 24 public static final int CLASS_SPECIFIED = 4 * LambdaExp.NEXT_AVAIL_FLAG; 25 public static final int HAS_SUBCLASS = 8 * LambdaExp.NEXT_AVAIL_FLAG; 26 /** True if the resulting class(es) are *not* member/inner classes. */ 27 public static final int IS_PACKAGE_MEMBER = 16 * LambdaExp.NEXT_AVAIL_FLAG; 28 29 /** True if there is at least one explicit "<init>" ("*init*"} method. */ 30 boolean explicitInit; 31 32 /** The class of instances of this class. 33 * Same as compiledType unless isMakingClassPair(), in which case super.type 34 * is an interface, and instanceType is a class implementing the interface. 35 * Using an interface plus a class gives us true multiple inheritance. */ 36 ClassType instanceType; 37 38 public String classNameSpecifier; 39 40 /** True if we should make a pair of an interface and a class. */ isMakingClassPair()41 public boolean isMakingClassPair() { 42 return compiledType != instanceType; 43 } 44 45 /** The ClassType generated for this class. 46 * Note difference from {@code getClassType}: 47 * The value of a {@code ClassExp} (viewed as an expression) is a 48 * class/type object, so {@code getType} returns the type of a type. 49 */ calculateType()50 protected Type calculateType() { 51 return simple ? Compilation.typeClass : Compilation.typeClassType; 52 } 53 54 /** The ClassType generated for this class. 55 */ getClassType()56 public ClassType getClassType() { return compiledType; } 57 setClassType(ClassType type)58 public void setClassType(ClassType type) { 59 this.compiledType = type; 60 this.instanceType = type; 61 } 62 63 /** List of base classes and implemented interfaces. */ 64 public Expression[] supers; 65 66 /** Index in supers array of class we extend, or -1. */ 67 public int superClassIndex = -1; 68 69 /** An artificial method named {@code "$finit$"} for evaluating 70 * non-static initializations. 71 * All constructors need to call this. */ 72 public LambdaExp initMethod; 73 74 /** An artificial method named {@code "$clinit$"} for evaluating 75 * static initializations. */ 76 public LambdaExp clinitMethod; 77 ClassExp(boolean simple, ClassType type)78 public ClassExp (boolean simple, ClassType type) { 79 this.simple = simple; 80 setClassType(type); 81 } 82 mustCompile()83 protected boolean mustCompile() { return true; } 84 compile(Compilation comp, Target target)85 public void compile(Compilation comp, Target target) { 86 if (target instanceof IgnoreTarget) 87 return; 88 compilePushClass(comp, target); 89 } 90 compilePushClass(Compilation comp, Target target)91 public void compilePushClass(Compilation comp, Target target) { 92 ClassType new_class = compiledType; 93 94 gnu.bytecode.CodeAttr code = comp.getCode(); 95 ClassType typeClass = Type.javalangClassType; 96 ClassType typeType; 97 int nargs; 98 boolean needsLink = getNeedsClosureEnv(); 99 comp.loadClassRef(new_class); 100 if (isSimple() && ! needsLink) { 101 typeType = typeClass; 102 } else { 103 if (isMakingClassPair() || needsLink) { 104 if (new_class == instanceType) 105 code.emitDup(instanceType); 106 else 107 comp.loadClassRef(instanceType); 108 typeType = ClassType.make("gnu.expr.PairClassType"); 109 nargs = needsLink ? 3 : 2; 110 } else { 111 typeType = Compilation.typeType; 112 nargs = 1; 113 } 114 Type[] argsClass = new Type[nargs]; 115 if (needsLink) { 116 getOwningLambda().loadHeapFrame(comp); 117 argsClass[--nargs] = Type.objectType; 118 } 119 while (--nargs >= 0) argsClass[nargs] = typeClass; 120 Method makeMethod 121 = typeType.addMethod("make", argsClass, 122 typeType, Access.STATIC|Access.PUBLIC); 123 code.emitInvokeStatic(makeMethod); 124 } 125 target.compileFromStack(comp, typeType); 126 } 127 getCompiledClassType(Compilation comp)128 protected ClassType getCompiledClassType(Compilation comp) { 129 return compiledType; 130 } 131 132 /** Create a Field in the instanceClass for each declared field. 133 * This allows name SlotGet.lookupMember (used in Translator.rewrite 134 * when looking for a binding for a symbol) to return a match. 135 * Note that if we later (in setTypes) create a pair-type, then the 136 * field will be replaced by a getter/setter pair. Later yet 137 * (in declareParts): We set the types of the Field or getter/setter pair. 138 * We should create tentative Methods for methods in the same manner, 139 * but that is is a project for another day. 140 */ createFields(Compilation comp)141 public void createFields(Compilation comp) { 142 if (state >= PARTS_PREDECLARED) 143 return; 144 state = PARTS_PREDECLARED; 145 Hashtable<String,Declaration> seenFields 146 = new Hashtable<String,Declaration>(); 147 for (Declaration decl = firstDecl(); 148 decl != null; decl = decl.nextDecl()) { 149 // If the declaration derives from a method, don't create field. 150 if (decl.getCanRead()) { 151 int flags = decl.getAccessFlags(Access.PUBLIC); 152 if (decl.getFlag(Declaration.STATIC_SPECIFIED)) 153 flags |= Access.STATIC; 154 String fname = Mangling.mangleField(decl.getName()); 155 decl.setField(instanceType.addField(fname, null, flags)); 156 Declaration old = seenFields.get(fname); 157 if (old != null) 158 duplicateDeclarationError(old, decl, comp); 159 seenFields.put(fname, decl); 160 } 161 } 162 } 163 setTypes(Compilation comp)164 public void setTypes(Compilation comp) { 165 if (state >= TYPES_SET) 166 return; 167 createFields(comp); 168 state = TYPES_SET; 169 int nsupers = supers == null ? 0 : supers.length; 170 ClassType[] superTypes = new ClassType[nsupers]; 171 ClassType superType = null; 172 int j = 0; 173 for (int i = 0; i < nsupers; i++) { 174 Type st = Language.getDefaultLanguage().getTypeFor(supers[i]); 175 ClassType t; 176 if (st instanceof ClassType) 177 t = (ClassType) st; 178 else if (st instanceof ParameterizedType) 179 t = ((ParameterizedType) st).getRawType(); 180 else { 181 comp.setLine(supers[i]); 182 comp.error('e', "invalid super type"); 183 continue; 184 } 185 int modifiers; 186 try { 187 modifiers = t.getModifiers(); 188 } catch (RuntimeException ex) { 189 modifiers = 0; 190 if (comp != null) 191 comp.error('e', "unknown super-type "+t.getName()); 192 } 193 if ((modifiers & Access.INTERFACE) == 0) { 194 if (j < i) 195 comp.error('e', "duplicate superclass for "+this); 196 superType = t; 197 superClassIndex = i; 198 } else 199 superTypes[j++] = t; 200 } 201 if (superType != null && (flags & INTERFACE_SPECIFIED) != 0) 202 comp.error('e', "cannot be interface since has superclass"); 203 if (! simple && superType == null && (flags & CLASS_SPECIFIED) == 0 204 // If the class is module-local and has no sub-classes, we can 205 // optimize away the need for a pair-class. 206 && (getFlag(HAS_SUBCLASS) 207 || (nameDecl != null && nameDecl.isPublic()))) { 208 PairClassType ptype = new PairClassType();//(PairClassType) type; 209 compiledType = ptype; 210 ptype.setInterface(true); 211 ptype.instanceType = instanceType; 212 ClassType[] interfaces = { compiledType }; 213 // Can do better. FIXME. 214 instanceType.setSuper(Type.pointer_type); 215 instanceType.setInterfaces(interfaces); 216 } 217 else if (getFlag(INTERFACE_SPECIFIED)) 218 instanceType.setInterface(true); 219 compiledType.setSuper(superType == null ? Type.pointer_type : superType); 220 221 ClassType[] interfaces; 222 if (j == nsupers) 223 interfaces = superTypes; 224 else { 225 interfaces = new ClassType[j]; 226 System.arraycopy(superTypes, 0, interfaces, 0, j); 227 } 228 compiledType.setInterfaces(interfaces); 229 230 if (compiledType.getName() == null) 231 compiledType.setName(getClassName(comp)); 232 233 // Don't add class twice - i.e. if ModuleExp.USE_DEFINED_CLASS is set. 234 if (compiledType != comp.mainClass) 235 comp.addClass(compiledType); 236 if (isMakingClassPair()) { 237 instanceType.setName(compiledType.getName()+"$class"); 238 comp.addClass(instanceType); 239 240 // Convert fields to getter/setter pairs. 241 // Note we don't know their types yet. 242 Field prev = null; 243 for (Declaration decl = firstDecl(); 244 decl != null; decl = decl.nextDecl()) { 245 Field fld = decl.getField(); 246 if (decl.getCanRead()) { 247 int fflags = decl.getField().getFlags() | Access.ABSTRACT; 248 String gname = slotToMethodName("get", decl.getName()); 249 decl.getterMethod = 250 compiledType.addMethod(gname, 251 fflags, Type.typeArray0, null); 252 decl.maybeSourceName(decl.getterMethod, null); 253 String sname = slotToMethodName("set", decl.getName()); 254 Type[] stypes = { null }; 255 decl.setterMethod = 256 compiledType.addMethod(sname, fflags, stypes, 257 Type.voidType); 258 instanceType.removeField(fld, prev); 259 decl.setField(null); 260 } 261 prev = fld; 262 } 263 } 264 } 265 getClassName(Compilation comp)266 public String getClassName(Compilation comp) { 267 String name; 268 if (classNameSpecifier != null) 269 name = classNameSpecifier; 270 else { 271 name = getName(); 272 if (name != null) { 273 int nlen = name.length(); 274 if (nlen > 2 275 && name.charAt(0) == '<' && name.charAt(nlen-1) == '>') 276 name = name.substring(1, nlen-1); 277 } 278 } 279 if (name == null) { 280 StringBuffer nbuf = new StringBuffer(100); 281 comp.getModule().classFor(comp); 282 nbuf.append(comp.mainClass.getName()); 283 nbuf.append('$'); 284 int len = nbuf.length(); 285 for (int i = 0; ; i++) { 286 nbuf.append(i); 287 name = nbuf.toString(); 288 if (comp.findNamedClass(name) == null) 289 break; 290 nbuf.setLength(len); 291 } 292 } 293 else if (! isSimple() || this instanceof ObjectExp) 294 name = comp.generateClassName(name); 295 else { 296 int start = 0; 297 StringBuilder nbuf = new StringBuilder(100); 298 // Mangle characters in name, if needed - but don't mangle '.'. 299 for (;;) { 300 int dot = name.indexOf('.', start); 301 if (dot < 0) 302 break; 303 nbuf.append(Mangling 304 .mangleClassName(name.substring(start, dot))); 305 start = dot + 1; 306 if (start < name.length()) 307 nbuf.append('.'); 308 } 309 // nbuf contains package prefix (mangled if needed, except for '.') 310 // start is the rest of name (after the package prefix) 311 if (start == 0) { // No '.' in name 312 setFlag(IS_PACKAGE_MEMBER); 313 String mainName = comp.mainClass == null ? null 314 : comp.mainClass.getName(); 315 int dot = mainName == null ? -1 : mainName.lastIndexOf('.'); 316 if (dot > 0) 317 nbuf.append(mainName.substring(0, dot + 1)); 318 else if (comp.classPrefix != null) 319 nbuf.append(comp.classPrefix); 320 } 321 else if (start == 1 && start < name.length()) { 322 // name has a single initial dot. Treat as member class. 323 nbuf.setLength(0); 324 nbuf.append(comp.mainClass.getName()); 325 nbuf.append('$'); 326 } 327 else 328 setFlag(IS_PACKAGE_MEMBER); 329 if (start < name.length()) 330 nbuf.append(Mangling 331 .mangleClassName(name.substring(start))); 332 name = nbuf.toString(); 333 } 334 return name; 335 } 336 declareParts(Compilation comp)337 public void declareParts(Compilation comp) { 338 if (state >= PARTS_DECLARED) 339 return; 340 setTypes(comp); 341 state = PARTS_DECLARED; 342 for (Declaration decl = firstDecl(); 343 decl != null; decl = decl.nextDecl()) { 344 if (decl.getCanRead()) { 345 if (isMakingClassPair()) { 346 Type ftype = decl.getType().getImplementationType(); 347 decl.getterMethod.setReturnType(ftype); 348 decl.setterMethod.getParameterTypes()[0] = ftype; 349 } else { 350 decl.setSimple(false); 351 decl.getField().setType(decl.getType()); 352 } 353 } 354 } 355 356 for (LambdaExp child = firstChild; child != null; 357 child = child.nextSibling) { 358 if (child.isAbstract()) 359 setFlag(IS_ABSTRACT); 360 if ("*init*".equals(child.getName())) { 361 explicitInit = true; 362 if (child.isAbstract()) 363 comp.error('e', "*init* method cannot be abstract", child); 364 if (compiledType instanceof PairClassType) 365 comp.error('e', 366 "'*init*' methods only supported for simple classes"); 367 } 368 // Setting child.outer isn't normally needed. The exception is 369 // if we're called from object.rewriteClassDef and there is some 370 // funny macro expansion going on, in which case outer 371 // might be a TemplateScope. 372 child.setOuter(this); 373 if ((child != initMethod && child != clinitMethod 374 && child.nameDecl != null // only if error 375 && ! child.nameDecl.getFlag(Declaration.STATIC_SPECIFIED)) 376 || ! isMakingClassPair()) 377 child.addMethodFor(compiledType, comp, null); 378 if (isMakingClassPair()) 379 child.addMethodFor(instanceType, comp, compiledType); 380 } 381 if (! explicitInit && ! instanceType.isInterface()) 382 Compilation.getConstructor(instanceType, this); 383 int instanceModifiers = instanceType.getModifiers(); 384 if (isAbstract()) { 385 instanceModifiers |= Access.ABSTRACT; 386 instanceType.setModifiers(instanceModifiers); 387 } 388 if (nameDecl != null) 389 instanceType.setModifiers((instanceModifiers & ~Access.PUBLIC) 390 | nameDecl.getAccessFlags(Access.PUBLIC)); 391 } 392 393 /** Return implementation method matching name and param types. 394 * Used when compiling a pair class and generating a concrete method 395 * implementing an interface method, to find static implementation method 396 * in this or super implementation class we need to call. 397 * @param interfaceType search the implementation classes corresponding 398 * to this interface type and its super-interfaces. 399 * @param mname method name to look for. 400 * @param paramTypes method types to look for. 401 * @param vec where to place found methods 402 * If a method is found, don't search super-interfaces, as the found method 403 * is more specific and overrides any that might in super-interfaces. 404 */ getImplMethods(ClassType interfaceType, String mname, Type[] paramTypes, ArrayList<Method> vec)405 static void getImplMethods(ClassType interfaceType, 406 String mname, Type[] paramTypes, 407 ArrayList<Method> vec) { 408 getImplMethods(interfaceType, mname, paramTypes, vec, null); 409 } 410 getImplMethods(ClassType interfaceType, String mname, Type[] paramTypes, ArrayList<Method> vec, Type[] itypes)411 private static void getImplMethods(ClassType interfaceType, 412 String mname, Type[] paramTypes, 413 ArrayList<Method> vec, Type[] itypes) { 414 ClassType implType; 415 if (interfaceType instanceof PairClassType) 416 implType = ((PairClassType) interfaceType).instanceType; 417 else if (! interfaceType.isInterface()) 418 return; 419 else { 420 try { 421 Class reflectClass = interfaceType.getReflectClass(); 422 if (reflectClass == null) 423 return; 424 String implTypeName = interfaceType.getName() + "$class"; 425 ClassLoader loader = reflectClass.getClassLoader(); 426 /* #ifdef JAVA2 */ 427 Class implClass = Class.forName(implTypeName, false, loader); 428 /* #else */ 429 // Class implClass = Class.forName(implTypeName); 430 /* #endif */ 431 implType = (ClassType) Type.make(implClass); 432 } catch (Exception ex) { 433 return; 434 } 435 } 436 if (itypes == null) { 437 itypes = new Type[paramTypes.length + 1]; 438 System.arraycopy (paramTypes, 0, itypes, 1, paramTypes.length); 439 } 440 itypes[0] = interfaceType; 441 Method implMethod = implType.getDeclaredMethod(mname, itypes); 442 if (implMethod != null) { 443 int count = vec.size(); 444 if (count == 0 || ! vec.get(count-1).equals(implMethod)) 445 vec.add(implMethod); 446 } else { 447 ClassType[] superInterfaces = interfaceType.getInterfaces(); 448 for (int i = 0; i < superInterfaces.length; i++) 449 getImplMethods(superInterfaces[i], mname, paramTypes, vec, 450 itypes); 451 } 452 } 453 454 /** Call comp.usedClass on the first arguments's supertypes. */ usedSuperClasses(ClassType clas, Compilation comp)455 private static void usedSuperClasses(ClassType clas, Compilation comp) { 456 comp.usedClass(clas.getSuperclass()); 457 ClassType[] interfaces = clas.getInterfaces(); 458 if (interfaces != null) { 459 for (int i = interfaces.length; --i >= 0; ) 460 comp.usedClass(interfaces[i]); 461 } 462 } 463 compileMembers(Compilation comp)464 public ClassType compileMembers (Compilation comp) { 465 ClassType saveClass = comp.curClass; 466 Method saveMethod = comp.method; 467 try { 468 ClassType new_class = getCompiledClassType(comp); 469 comp.curClass = new_class; 470 471 LambdaExp outer = outerLambda(); 472 Member enclosing = null; 473 if (outer instanceof ClassExp) 474 enclosing = outer.compiledType; 475 else if (outer != null && ! (outer instanceof ModuleExp)) 476 enclosing = saveMethod; 477 else if (outer instanceof ModuleExp && ! getFlag(IS_PACKAGE_MEMBER)) 478 enclosing = outer.compiledType; 479 if (enclosing != null) { 480 new_class.setEnclosingMember(enclosing); 481 if (enclosing instanceof ClassType) 482 ((ClassType) enclosing).addMemberClass(new_class); 483 } 484 if (instanceType != new_class) { 485 instanceType.setEnclosingMember(compiledType); 486 compiledType.addMemberClass(instanceType); 487 } 488 489 usedSuperClasses(compiledType, comp); 490 if (compiledType != instanceType) 491 usedSuperClasses(instanceType, comp); 492 493 String filename = getFileName(); 494 if (filename != null) 495 new_class.setSourceFile (filename); 496 497 LambdaExp saveLambda = comp.curLambda; 498 comp.curLambda = this; 499 500 allocFrame(comp); 501 CodeAttr code; 502 503 if (nameDecl != null) 504 nameDecl.compileAnnotations(compiledType, ElementType.TYPE); 505 for (Declaration decl = firstDecl(); decl != null; 506 decl = decl.nextDecl()) { 507 decl.compileAnnotations(decl.getField(), ElementType.FIELD); 508 } 509 510 for (LambdaExp child = firstChild; child != null; 511 child = child.nextSibling) { 512 if (child.isAbstract() || child.isNative()) 513 continue; 514 if (child == clinitMethod && compiledType == comp.mainClass) 515 continue; 516 Method save_method = comp.method; 517 LambdaExp save_lambda = comp.curLambda; 518 String saveFilename = comp.getFileName(); 519 int saveLine = comp.getLineNumber(); 520 int saveColumn = comp.getColumnNumber(); 521 comp.setLine(child); 522 comp.method = child.getMainMethod(); 523 //comp.curClass = comp.method.getDeclaringClass(); 524 Declaration childDecl = child.nameDecl; 525 if (childDecl != null) 526 childDecl.compileAnnotations(comp.method, ElementType.METHOD); 527 comp.curClass = instanceType; 528 comp.curLambda = child; 529 comp.method.initCode(); 530 child.allocChildClasses(comp); 531 child.allocParameters(comp); 532 if ("*init*".equals(child.getName())) { 533 code = comp.getCode(); 534 if (staticLinkField != null) { 535 code.emitPushThis(); 536 Variable var = code.getArg(1); 537 var.allocateLocal(code); 538 code.emitLoad(var); 539 code.emitPutField(staticLinkField); 540 } 541 542 // Extract "first" expression to see if it is special. 543 Expression bodyFirst = child.getBodyFirstExpression(); 544 // See if bodyFirst is a this(...) or super(...) call. 545 ClassType calledInit = checkForInitCall(bodyFirst); 546 ClassType superClass = instanceType.getSuperclass(); 547 if (calledInit == null && superClass != null) { 548 // Call default super constructor if there isn't 549 // an explicit call to a super constructor. 550 invokeDefaultSuperConstructor(superClass, comp, this); 551 compileCallInitMethods(comp); 552 } 553 else if (calledInit != instanceType) 554 ((ApplyExp) bodyFirst).setFlag(ApplyExp.IS_SUPER_INIT); 555 } 556 child.enterFunction(comp); 557 child.compileBody(comp); 558 559 // Check to see if child overrides a superclass method and has 560 // a covariant return type. If so, generate a bridge method 561 // matching the superclass method's return type. 562 563 Method thisMethod = comp.method; 564 Type[] ptypes = thisMethod.getParameterTypes(); 565 Type rtype = thisMethod.getReturnType(); 566 ClassType superClass = instanceType.getSuperclass(); 567 Method superMethod = superClass.getMethod(child.getName(), 568 ptypes); 569 if (superMethod != null && 570 superMethod.getReturnType().compare(rtype) == 1) { 571 generateBridgeMethod(comp, thisMethod, ptypes, 572 superMethod.getReturnType()); 573 } 574 575 comp.method = save_method; 576 comp.curClass = new_class; 577 comp.curLambda = save_lambda; 578 comp.setLine(saveFilename, saveLine, saveColumn); 579 } 580 if (! explicitInit && ! instanceType.isInterface()) 581 comp.generateConstructor(instanceType, this); 582 else if (initChain != null) 583 initChain.reportError("unimplemented: explicit constructor cannot initialize ", comp); 584 585 Method[] methods; 586 int nmethods; 587 if (isAbstract()) { 588 methods = null; 589 nmethods = 0; 590 } else { 591 methods = compiledType.getAbstractMethods(); 592 nmethods = methods.length; 593 } 594 for (int i = 0; i < nmethods; i++) { 595 Method meth = methods[i]; 596 String mname = meth.getName(); 597 Type[] ptypes = meth.getParameterTypes(); 598 Type rtype = meth.getReturnType(); 599 600 Method mimpl = instanceType.getMethod(mname, ptypes); 601 if (mimpl != null && ! mimpl.isAbstract()) 602 continue; 603 604 char ch; 605 ArrayList<Method> vec = new ArrayList<Method>(); 606 getImplMethods(compiledType, mname, ptypes, vec); 607 if (vec.size() == 0 608 && mname.length() > 3 609 && mname.charAt(2) == 't' 610 && mname.charAt(1) == 'e' 611 && ((ch = mname.charAt(0)) == 'g' || ch == 's')) { 612 // a "set" or "get" method is treated as a slot accessor. 613 Type ftype; 614 if (ch == 's' && rtype.isVoid() && ptypes.length == 1) 615 ftype = ptypes[0]; 616 else if (ch == 'g' && ptypes.length == 0) 617 ftype = rtype; 618 else 619 continue; 620 String fname = Character.toLowerCase(mname.charAt(3)) 621 + mname.substring(4); 622 Field fld = instanceType.getField(fname); 623 if (fld == null) 624 fld = instanceType.addField(fname, ftype, 625 Access.PUBLIC); 626 Method impl = instanceType.addMethod(mname, Access.PUBLIC, 627 ptypes, rtype); 628 code = impl.startCode(); 629 code.emitPushThis(); 630 if (ch == 'g') { 631 code.emitGetField(fld); 632 } else { 633 code.emitLoad(code.getArg(1)); 634 code.emitPutField(fld); 635 } 636 code.emitReturn(); 637 } else { 638 if (vec.size() != 1) { 639 Method impl = vec.size() != 0 ? null : 640 findMethodForBridge(mname, ptypes, rtype); 641 642 if (impl != null) { 643 generateBridgeMethod(comp, impl, ptypes, rtype); 644 } else { 645 // FIXME - need better error message! 646 String msg = vec.size() == 0 647 ? "missing implementation for " 648 : "ambiguous implementation for "; 649 comp.error('e', msg+meth); 650 } 651 } else { 652 Method impl 653 = instanceType.addMethod(mname, Access.PUBLIC, 654 ptypes, rtype); 655 code = impl.startCode(); 656 for (Variable var = code.getCurrentScope().firstVar(); 657 var != null; var = var.nextVar()) 658 code.emitLoad(var); 659 code.emitInvokeStatic(vec.get(0)); 660 code.emitReturn(); 661 } 662 } 663 } 664 665 generateApplyMethods(comp); 666 comp.curLambda = saveLambda; 667 668 return new_class; 669 } finally { 670 comp.curClass = saveClass; 671 comp.method = saveMethod; 672 } 673 } compileCallInitMethods(Compilation comp)674 void compileCallInitMethods(Compilation comp) { 675 comp.callInitMethods(getCompiledClassType(comp), 676 new ArrayList<ClassType>(10)); 677 } 678 679 /** 680 * Finds a like-named method suitable for bridging the given 681 * arg/return types (i.e. a method whose arg types and return types 682 * are subclasses of those given here. 683 */ findMethodForBridge(String mname, Type[] ptypes, Type rtype)684 protected Method findMethodForBridge(String mname, Type[] ptypes, 685 Type rtype) { 686 Method result = null; 687 for (Method method = compiledType.getDeclaredMethods(); 688 method != null; method = method.getNext()) { 689 if (mname.equals(method.getName()) && 690 method.getReturnType().isSubtype(rtype) && 691 Type.isMoreSpecific(method.getParameterTypes(), ptypes)) 692 result = method; 693 } 694 return result; 695 } 696 697 /** 698 * Given an existing method and a desired bridge method signature, 699 * generates an appropriate bridge method. 700 */ generateBridgeMethod(Compilation comp, Method src_method, Type[] bridge_arg_types, Type bridge_return_type)701 public final void generateBridgeMethod(Compilation comp, 702 Method src_method, 703 Type[] bridge_arg_types, 704 Type bridge_return_type) { 705 ClassType save_class = comp.curClass; 706 Method save_method = comp.method; 707 try { 708 comp.curClass = getCompiledClassType(comp); 709 comp.method = comp.curClass.addMethod 710 (src_method.getName(), 711 Access.PUBLIC|Access.BRIDGE|Access.SYNTHETIC, 712 bridge_arg_types, bridge_return_type); 713 Type[] src_arg_types = src_method.getParameterTypes(); 714 715 CodeAttr code = comp.method.startCode(); 716 code.emitLoad(code.getArg(0)); 717 for (int i = 0; i < src_arg_types.length; ++i) { 718 code.emitLoad(code.getArg(i+1)); 719 code.emitCheckcast(src_arg_types[i]); 720 } 721 code.emitInvokeVirtual(src_method); 722 code.emitReturn(); 723 } finally { 724 comp.method = save_method; 725 comp.curClass = save_class; 726 } 727 } 728 visit(ExpVisitor<R,D> visitor, D d)729 protected <R,D> R visit (ExpVisitor<R,D> visitor, D d) { 730 Compilation comp = visitor.getCompilation(); 731 if (comp == null) 732 return visitor.visitClassExp(this, d); 733 ClassType saveClass = comp.curClass; 734 try { 735 comp.curClass = compiledType; 736 return visitor.visitClassExp(this, d); 737 } finally { 738 comp.curClass = saveClass; 739 } 740 } 741 visitChildren(ExpVisitor<R,D> visitor, D d)742 protected <R,D> void visitChildren (ExpVisitor<R,D> visitor, D d) { 743 LambdaExp save = visitor.currentLambda; 744 visitor.currentLambda = this; 745 if (supers != null) 746 supers = visitor.visitExps(supers, supers.length, d); 747 try { 748 for (LambdaExp child = firstChild; 749 child != null && visitor.exitValue == null; 750 child = child.nextSibling) { 751 if (instanceType != null) { 752 Declaration firstParam = child.firstDecl(); 753 if (firstParam != null && firstParam.isThisParameter()) 754 firstParam.setType(compiledType); 755 } 756 visitor.visitLambdaExp(child, d); 757 } 758 } finally { 759 visitor.currentLambda = save; 760 } 761 } 762 loadSuperStaticLink(Expression superExp, ClassType superClass, Compilation comp)763 static void loadSuperStaticLink (Expression superExp, ClassType superClass, 764 Compilation comp) { 765 CodeAttr code = comp.getCode(); 766 // This can be optimized in most cases. FIXME. 767 superExp.compile(comp, Target.pushValue(Compilation.typeClassType)); 768 code.emitInvokeStatic(ClassType.make("gnu.expr.PairClassType").getDeclaredMethod("extractStaticLink", 1)); 769 code.emitCheckcast(superClass.getOuterLinkType()); 770 } 771 checkDefaultSuperConstructor(ClassType superClass, Compilation comp)772 void checkDefaultSuperConstructor(ClassType superClass, Compilation comp) { 773 if (superClass.getDeclaredMethod("<init>", 0) == null) 774 comp.error('e', ("super class "+superClass.getName() 775 +" does not have a default constructor")); 776 } 777 invokeDefaultSuperConstructor(ClassType superClass, Compilation comp, LambdaExp lexp)778 static void invokeDefaultSuperConstructor(ClassType superClass, 779 Compilation comp, 780 LambdaExp lexp) { 781 CodeAttr code = comp.getCode(); 782 Method superConstructor 783 = superClass.getDeclaredMethod("<init>", 0); 784 // InlineCalls catches the missing superConstructor case, using 785 // checkDefaultSuperConstructor. 786 assert superConstructor != null; 787 code.emitPushThis(); 788 if (superClass.hasOuterLink() && lexp instanceof ClassExp) { 789 ClassExp clExp = (ClassExp) lexp; 790 Expression superExp = clExp.supers[clExp.superClassIndex]; 791 loadSuperStaticLink(superExp, superClass, comp); 792 } 793 code.emitInvokeSpecial(superConstructor); 794 } 795 print(OutPort out)796 public void print(OutPort out) { 797 out.startLogicalBlock("("+getExpClassName()+"/", ")", 2); 798 Object name = getSymbol(); 799 if (name != null) { 800 out.print(name); 801 out.print('/'); 802 } 803 out.print(id); 804 out.print("/fl:"); out.print(Integer.toHexString(flags)); 805 if (supers.length > 0) { 806 out.writeSpaceFill(); 807 out.startLogicalBlock("supers:", "", 2); 808 for (int i = 0; i < supers.length; i++) { 809 supers[i].print(out); 810 out.writeSpaceFill(); 811 } 812 out.endLogicalBlock(""); 813 } 814 Special prevMode = null; 815 int key_args = keywords == null ? 0 : keywords.length; 816 //int opt_args = defaultArgs == null ? 0 : defaultArgs.length - key_args; 817 for (Declaration decl = firstDecl(); decl != null; 818 decl = decl.nextDecl()) { 819 out.writeSpaceFill(); 820 decl.printInfo(out); 821 } 822 for (LambdaExp child = firstChild; child != null; 823 child = child.nextSibling) { 824 out.writeBreakLinear(); 825 child.print(out); 826 } 827 if (body != null) { 828 out.writeBreakLinear(); 829 body.print (out); 830 } 831 out.endLogicalBlock(")"); 832 } 833 compileSetField(Compilation comp)834 public Field compileSetField (Compilation comp) { 835 Field field = allocFieldFor(comp); 836 if (! getNeedsClosureEnv() && field.getStaticFlag() 837 && ! comp.immediate && type != Type.javalangClassType) { 838 new Literal(compiledType, type, comp.litTable) 839 .assign(field, comp.litTable); 840 } else 841 new ClassInitializer(this, field, comp); 842 return field; 843 } 844 845 /** Mangle a "slot" name to a get- or set- method name. 846 * @param prefix either "get" or "set" or "add" 847 * @param sname a "slot" (property) name. This is mangled if needed. 848 */ slotToMethodName(String prefix, String sname)849 public static String slotToMethodName(String prefix, String sname) { 850 if (! Language.isValidJavaName(sname)) 851 sname = Mangling.mangleName(sname, false); 852 int slen = sname.length(); 853 StringBuffer sbuf = new StringBuffer(slen+3); 854 sbuf.append(prefix); 855 if (slen > 0) { 856 sbuf.append(Character.toTitleCase(sname.charAt(0))); 857 sbuf.append(sname.substring(1)); 858 } 859 return sbuf.toString(); 860 } 861 addMethod(LambdaExp lexp, Object mname)862 public Declaration addMethod (LambdaExp lexp, Object mname) { 863 Declaration mdecl = addDeclaration(mname, Compilation.typeProcedure); 864 lexp.setOuter(this); 865 lexp.setClassMethod(true); 866 mdecl.noteValue(lexp); 867 mdecl.setFlag(Declaration.FIELD_OR_METHOD); 868 mdecl.setProcedureDecl(true); 869 lexp.setSymbol(mname); 870 return mdecl; 871 } 872 } 873