[Nice-commit] Nice/src/bossa/syntax reset.nice,NONE,1.1 overloadedsymbol.nice,1.18,1.19 niceMethod.n
Brought to you by:
bonniot
|
From: Daniel B. <bo...@us...> - 2005-08-19 16:04:39
|
Update of /cvsroot/nice/Nice/src/bossa/syntax In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27857/src/bossa/syntax Modified Files: overloadedsymbol.nice niceMethod.nice methodDeclaration.nice arguments.nice alternative.nice Added Files: reset.nice Log Message: Dramatically speedup the "remove non-minimal methods" from the overloading resolution phase. Use overriding information for nice methods instead of recomputing the specialization relationship each time. For others (inlined, retyped methods), cache the results. This phase goes down from about 30% of overloading resolution to something negligible. For large enough packages, this translates to about 15% global compilation speedup. Index: arguments.nice =================================================================== RCS file: /cvsroot/nice/Nice/src/bossa/syntax/arguments.nice,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** arguments.nice 16 Jan 2005 21:51:15 -0000 1.3 --- arguments.nice 19 Aug 2005 16:04:28 -0000 1.4 *************** *** 102,105 **** --- 102,119 ---- int[?] getUsedArguments(VarSymbol s) = usedArguments.get(s); + boolean usedReordering(VarSymbol s) + { + let map = this.getUsedArguments(s); + + if (map == null) + return false; + + for (int i = 0; i < map.length; i++) + if (map[i] != i+1) + return true; + + return false; + } + /** return true if there are arity non-tagged arguments. Index: overloadedsymbol.nice =================================================================== RCS file: /cvsroot/nice/Nice/src/bossa/syntax/overloadedsymbol.nice,v retrieving revision 1.18 retrieving revision 1.19 diff -C2 -d -r1.18 -r1.19 *** overloadedsymbol.nice 4 Apr 2005 15:56:31 -0000 1.18 --- overloadedsymbol.nice 19 Aug 2005 16:04:28 -0000 1.19 *************** *** 107,110 **** --- 107,113 ---- // SECOND PASS: check argument types + // This pass takes about half the time of the whole overloading resolution + // (which dominates typechecking, which dominates global compile time + // for large packages) removed.clear(); *************** *** 159,169 **** let res = symbols[0]; // store the formal argument types for later use together with the type callExp.setComputedType(notNull(arguments.types.get(res)), nice.tools.typing.Types.parameters(res.getClonedType())); res.releaseClonedType(); // store the expression (including default arguments) callExp.arguments.computedExpressions = arguments.getExpressions(res); ! //callExp.arguments = null; // free memory return this.uniqueExpression(); } --- 162,174 ---- let res = symbols[0]; // store the formal argument types for later use together with the type + // this takes about the other half of overloading resolution time callExp.setComputedType(notNull(arguments.types.get(res)), nice.tools.typing.Types.parameters(res.getClonedType())); + res.releaseClonedType(); // store the expression (including default arguments) callExp.arguments.computedExpressions = arguments.getExpressions(res); ! //callExp.arguments.arguments = cast(null); // free memory return this.uniqueExpression(); } *************** *** 535,542 **** return; ! int len = symbols.size(); List<VarSymbol> syms = new ArrayList(symbols); boolean[] remove = new boolean[len]; for(int s1 = 0; s1<len; s1++) { --- 540,550 ---- return; ! let len = symbols.size(); ! var remaining = len; ! List<VarSymbol> syms = new ArrayList(symbols); boolean[] remove = new boolean[len]; + trim: for(int s1 = 0; s1<len; s1++) { *************** *** 559,574 **** arguments.getUsedArguments(syms[s2])); ! try { ! mlsub.typing.Typing.leq(d2, d1); ! try { ! mlsub.typing.Typing.leq(d1, d2); ! } ! catch (mlsub.typing.TypingEx e) { remove[s1] = true; ! break; } - } - catch(mlsub.typing.TypingEx e){ - } } } --- 567,579 ---- arguments.getUsedArguments(syms[s2])); ! if (isLeq(syms[s2], syms[s1], s2, s1, d2, d1, arguments) && ! ! isLeq(syms[s1], syms[s2], s1, s2, d1, d2, arguments)) ! { remove[s1] = true; ! if (--remaining == 1) ! break trim; ! else ! break; } } } *************** *** 585,588 **** --- 590,679 ---- } + boolean isLeq(VarSymbol sym1, VarSymbol sym2, + int s1, int s2, mlsub.typing.Domain d1, mlsub.typing.Domain d2, + Arguments arguments) + { + let res = leqFromOverride(sym1, sym2, arguments); + if (res != 0) + { + let result = res == 1; + storeLeq(result, sym1, sym2); + return result; + } + + boolean result = computeIsLeq(s1, s2, d1, d2); + // Cache method specificity results. + // This is especially important as many frequently used methods + // (inline, retyped) are not covered by the leqFromOverride optimization. + storeLeq(result, sym1, sym2, arguments); + return result; + } + + boolean computeIsLeq(int s1, int s2, + mlsub.typing.Domain d1, mlsub.typing.Domain d2) + { + try { + mlsub.typing.Typing.leq(d1, d2); + return true; + } + catch (mlsub.typing.TypingEx e) { + return false; + } + } + + private int leqFromOverride(VarSymbol s1, VarSymbol s2, Arguments arguments) + { + let reordering = + arguments.usedReordering(s1) || + arguments.usedReordering(s2); + if (reordering) + return 0; + + // Lookup the cache. + // This is especially important as many frequently used methods + // (inline, retyped) do not have override information. + let m = methodLeqs[s1]; + if (m != null) + { + let res = m[s2]; + if (res != null) + return res ? 1 : -1; + } + + let d1 = s1.getMethodDeclaration(); + let d2 = s2.getMethodDeclaration(); + if (d1 == null || d2 == null) + return 0; + + if (! (d1 instanceof NiceMethod && d2 instanceof NiceMethod)) + return 0; + + if (d1.specializes(d2)) + return 1; + else + return -1; + } + + let Map<VarSymbol, Map<VarSymbol, boolean>> methodLeqs = new HashMap(); + + private void storeLeq(boolean result, + VarSymbol s1, VarSymbol s2, Arguments arguments) + { + let reordering = + arguments.usedReordering(s1) || + arguments.usedReordering(s2); + + if (! reordering) + storeLeq(result, s1, s2); + } + + private void storeLeq(boolean result, VarSymbol s1, VarSymbol s2) + { + var m = methodLeqs[s1]; + if (m == null) + methodLeqs[s1] = m = new HashMap(); + m[s2] = result; + } + private mlsub.typing.Domain domain(mlsub.typing.Polytype t, int[?] usedArguments) { Index: methodDeclaration.nice =================================================================== RCS file: /cvsroot/nice/Nice/src/bossa/syntax/methodDeclaration.nice,v retrieving revision 1.9 retrieving revision 1.10 diff -C2 -d -r1.9 -r1.10 *** methodDeclaration.nice 1 Apr 2005 00:09:23 -0000 1.9 --- methodDeclaration.nice 19 Aug 2005 16:04:28 -0000 1.10 *************** *** 251,254 **** --- 251,259 ---- } + public boolean specializes(MethodDeclaration d) + { + return false; + } + public ?Iterator<MethodDeclaration> listSpecializedMethods() { Index: niceMethod.nice =================================================================== RCS file: /cvsroot/nice/Nice/src/bossa/syntax/niceMethod.nice,v retrieving revision 1.28 retrieving revision 1.29 diff -C2 -d -r1.28 -r1.29 *** niceMethod.nice 7 Apr 2005 22:28:12 -0000 1.28 --- niceMethod.nice 19 Aug 2005 16:04:28 -0000 1.29 *************** *** 26,29 **** --- 26,30 ---- private ?List<VarSymbol> homonyms = null; private ?List<MethodDeclaration> specializedMethods = null; + private ?List<MethodDeclaration> specializedMethodsCompileTime = null; { *************** *** 58,77 **** this.findSpecializedMethods(); ! if (isOverride && specializedMethods == null) ! User.error(this, "This method does not override any other method"); ! ! if (! this.inInterfaceFile() && ! isOverride && specializedMethods != null) { ! let parent = notNull(specializedMethods)[0]; ! boolean sameResult = ! this.getReturnType().toString().equals(parent.getReturnType().toString()); ! if (sameResult) ! User.warning(this, "This method overrides " + parent + "\nYou should make this explicit, either by omitting the return type" + ! "\nor by using the 'override' keyword"); ! else ! User.warning(this, "This method overrides " + parent + "\nYou should make this explicit by using the 'override' keyword"); } --- 59,82 ---- this.findSpecializedMethods(); ! // Perform checks if we are compiling from source ! if (! this.inInterfaceFile()) { ! if (isOverride && specializedMethods == null) ! User.error(this, "This method does not override any other method"); ! if (! isOverride && specializedMethods != null) ! { ! let parent = notNull(specializedMethods)[0]; ! boolean sameResult = ! this.getReturnType().toString().equals(parent.getReturnType().toString()); ! ! if (sameResult) ! User.warning(this, "This method overrides " + parent + "\nYou should make this explicit, either by omitting the return type" + ! "\nor by using the 'override' keyword"); ! else ! User.warning(this, "This method overrides " + parent + "\nYou should make this explicit by using the 'override' keyword"); + } } *************** *** 86,89 **** --- 91,100 ---- specializesMethods() = specializedMethods != null; + specializes(MethodDeclaration d) + { + return specializedMethods != null && notNull(specializedMethods).contains(d) || + specializedMethodsCompileTime != null && notNull(specializedMethodsCompileTime).contains(d); + } + private void findSpecializedMethods() { *************** *** 107,112 **** let itsDomain = nice.tools.typing.Types.domain(s.getType()); ! if (this.specializes(s, ourDomain, itsDomain)) { // In a compiled package, we don't need checking. if (! module.compiled()) --- 118,131 ---- let itsDomain = nice.tools.typing.Types.domain(s.getType()); ! if (mlsub.typing.Typing.smaller(ourDomain, itsDomain)) { + // Check if we cannot discover this specialization at runtime + if (! mlsub.typing.Typing.smaller(ourDomain, itsDomain, true) || + nice.tools.typing.Types.typeParameterDispatch(this.getType(), s.getType())) + { + this.addSpecializedMethod(d, compileTimeOnly: true); + continue; + } + // In a compiled package, we don't need checking. if (! module.compiled()) *************** *** 119,124 **** else if (this.isSpecializedBy(d, s, ourDomain, itsDomain)) { ! if (! nice.tools.typing.Types.covariantSpecialization(s.getType(), this.getType())) ! this.reportReturnTypeError(shouldBeLessPrecise: true, than: d); // d is a specialized version of this. --- 138,145 ---- else if (this.isSpecializedBy(d, s, ourDomain, itsDomain)) { ! // In a compiled package, we don't need checking. ! if (! module.compiled()) ! if (! nice.tools.typing.Types.covariantSpecialization(s.getType(), this.getType())) ! this.reportReturnTypeError(shouldBeLessPrecise: true, than: d); // d is a specialized version of this. *************** *** 134,144 **** } - private boolean specializes - (VarSymbol s, - mlsub.typing.Domain ourDomain, mlsub.typing.Domain itsDomain) - = - mlsub.typing.Typing.smaller(ourDomain, itsDomain, true) - && ! nice.tools.typing.Types.typeParameterDispatch(this.getType(), s.getType()); - private boolean isSpecializedBy (MethodDeclaration d, VarSymbol s, --- 155,158 ---- *************** *** 200,205 **** } ! private void addSpecializedMethod(MethodDeclaration method) { if (specializedMethods == null) specializedMethods = new ArrayList(5); --- 214,229 ---- } ! private void addSpecializedMethod(MethodDeclaration method, boolean compileTimeOnly = false) { + if (compileTimeOnly) + { + if (specializedMethodsCompileTime == null) + specializedMethodsCompileTime = new ArrayList(5); + + notNull(specializedMethodsCompileTime).add(method); + + return; + } + if (specializedMethods == null) specializedMethods = new ArrayList(5); *************** *** 220,224 **** { s.print(keyword(0, visibility)); ! if (specializedMethods != null) s.print("override "); s.print(this.toString() + ";\n"); --- 244,253 ---- { s.print(keyword(0, visibility)); ! // In the compiled package's interface, we write 'override' even when ! // there are only compile time specializations (which would be invalid ! // in user source code). This is needed so that we know the method has ! // some type of override that we recompute at package load time, without ! // having to do it for all methods. ! if (specializedMethods != null || specializedMethodsCompileTime != null) s.print("override "); s.print(this.toString() + ";\n"); --- NEW FILE: reset.nice --- /**************************************************************************/ /* N I C E */ /* A high-level object-oriented research language */ /* (c) Daniel Bonniot 2005 */ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /**************************************************************************/ package bossa.syntax; public void reset() { methodLeqs.clear(); } Index: alternative.nice =================================================================== RCS file: /cvsroot/nice/Nice/src/bossa/syntax/alternative.nice,v retrieving revision 1.13 retrieving revision 1.14 diff -C2 -d -r1.13 -r1.14 *** alternative.nice 1 Apr 2005 00:09:23 -0000 1.13 --- alternative.nice 19 Aug 2005 16:04:28 -0000 1.14 *************** *** 179,182 **** --- 179,184 ---- public void resetAlternatives() { + // Temporary, reset should be called directly + reset(); alternativesMap = new HashMap(); } |