From aeb02db39dc0ef8c07b57336f4610fd3fd178247 Mon Sep 17 00:00:00 2001 From: Markus Schorn Date: Tue, 24 Mar 2009 15:52:39 +0000 Subject: [PATCH] Performance optimization: defer attempt to use user-defined conversions during overload resolution, bug 268383. --- .../parser/cpp/semantics/CPPSemantics.java | 31 +++++++++- .../dom/parser/cpp/semantics/Conversions.java | 49 ++++++++++------ .../core/dom/parser/cpp/semantics/Cost.java | 27 ++++++--- .../parser/cpp/semantics/FunctionCost.java | 56 ++++++++++++++++++- 4 files changed, 132 insertions(+), 31 deletions(-) diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java index 1c28845bac5..f1e81c60086 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java @@ -175,6 +175,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalUnknownScope; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType; import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.UDCMode; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.Rank; import org.eclipse.cdt.internal.core.index.IIndexScope; @@ -2116,7 +2117,9 @@ public class CPPSemantics { boolean ambiguous = false; // ambiguity, 2 functions are equally good FunctionCost bestFnCost = null; // the cost of the best function + // Loop over all functions + List potentialCosts= null; for (IFunction fn : fns) { if (fn == null) continue; @@ -2131,6 +2134,13 @@ public class CPPSemantics { return CPPUnknownFunction.createForSample(firstViable, data.astName); } + if (fnCost.hasDeferredUDC()) { + if (potentialCosts == null) { + potentialCosts= new ArrayList(); + } + potentialCosts.add(fnCost); + continue; + } int cmp= fnCost.compareTo(data, bestFnCost); if (cmp < 0) { bestFnCost= fnCost; @@ -2139,6 +2149,20 @@ public class CPPSemantics { ambiguous= true; } } + + if (potentialCosts != null) { + for (FunctionCost fnCost : potentialCosts) { + if (!fnCost.mustBeWorse(bestFnCost) && fnCost.performUDC()) { + int cmp= fnCost.compareTo(data, bestFnCost); + if (cmp < 0) { + bestFnCost= fnCost; + ambiguous= false; + } else if (cmp == 0) { + ambiguous= true; + } + } + } + } if (bestFnCost == null) return null; @@ -2186,14 +2210,15 @@ public class CPPSemantics { } else { if (CPPTemplates.isDependentType(implicitType)) return CONTAINS_DEPENDENT_TYPES; - cost = Conversions.checkImplicitConversionSequence(null, thisType, implicitType, false, true); + cost = Conversions.checkImplicitConversionSequence(null, thisType, implicitType, UDCMode.noUDC, true); } if (cost.getRank() == Rank.NO_MATCH) return null; result.setCost(k++, cost); } - + + final UDCMode udc = allowUDC ? UDCMode.deferUDC : UDCMode.noUDC; for (int j = 0; j < sourceLen; j++) { final IType argType= argTypes[j]; if (argType == null) @@ -2217,7 +2242,7 @@ public class CPPSemantics { } else { if (CPPTemplates.isDependentType(paramType)) return CONTAINS_DEPENDENT_TYPES; - cost = Conversions.checkImplicitConversionSequence(arg, argType, paramType, allowUDC, false); + cost = Conversions.checkImplicitConversionSequence(arg, argType, paramType, udc, false); } if (cost.getRank() == Rank.NO_MATCH) return null; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java index c5677e88a6e..d0b051b503b 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Conversions.java @@ -51,21 +51,24 @@ import org.eclipse.core.runtime.CoreException; * Routines for calculating the cost of conversions. */ public class Conversions { + enum UDCMode {allowUDC, noUDC, deferUDC} /** * Computes the cost of an implicit conversion sequence * [over.best.ics] 13.3.3.1 * @param sourceExp the expression behind the source type * @param source the source (argument) type * @param target the target (parameter) type - * @param allowUDC whether a user-defined conversion is allowed during the sequence * @param isImpliedObject * * @return the cost of converting from source to target * @throws DOMException */ public static Cost checkImplicitConversionSequence(IASTExpression sourceExp, IType source, - IType target, boolean allowUDC, boolean isImpliedObject) throws DOMException { - allowUDC &= !isImpliedObject; + IType target, UDCMode udc, boolean isImpliedObject) throws DOMException { + if (isImpliedObject) { + udc= UDCMode.noUDC; + } + target= getNestedType(target, TDEF); source= getNestedType(source, TDEF); @@ -92,7 +95,7 @@ public class Conversions { } } - if (T2 instanceof ICPPClassType && allowUDC) { + if (T2 instanceof ICPPClassType && udc != UDCMode.noUDC) { // Or has a class type (i.e., T2 is a class type) and can be implicitly converted to // an lvalue of type "cv3 T3," where "cv1 T1" is reference-compatible with "cv3 T3" 92) // (this conversion is selected by enumerating the applicable conversion functions @@ -107,7 +110,7 @@ public class Conversions { IType cvT2= getNestedType(newSource, TDEF | REF); Cost cost2= isReferenceCompatible(cv1T1, cvT2, false); if (cost2 != null) { - int cmp= cost2.compare(operatorCost); + int cmp= cost2.compareTo(operatorCost); if (cmp <= 0) { ambiguousConversionOperator= cmp == 0; operatorCost= cost2; @@ -150,7 +153,7 @@ public class Conversions { // We must do a non-reference initialization if (!illformed) { - return nonReferenceConversion(source, cv1T1, allowUDC, isImpliedObject); + return nonReferenceConversion(source, cv1T1, udc, isImpliedObject); } } } @@ -158,17 +161,17 @@ public class Conversions { } // Non-reference binding - return nonReferenceConversion(source, target, allowUDC, isImpliedObject); + return nonReferenceConversion(source, target, udc, isImpliedObject); } - private static Cost nonReferenceConversion(IType source, IType target, boolean allowUDC, - boolean isImpliedObject) throws DOMException { + private static Cost nonReferenceConversion(IType source, IType target, UDCMode udc, boolean isImpliedObject) throws DOMException { Cost cost= checkStandardConversionSequence(source, target, isImpliedObject); - if (allowUDC && cost.getRank() == Rank.NO_MATCH) { - Cost temp = checkUserDefinedConversionSequence(source, target); - if (temp != null) { - cost = temp; - } + if (cost.getRank() != Rank.NO_MATCH || udc == UDCMode.noUDC) + return cost; + + Cost temp = checkUserDefinedConversionSequence(source, target, udc == UDCMode.deferUDC); + if (temp != null) { + cost = temp; } return cost; } @@ -318,13 +321,23 @@ public class Conversions { * @return * @throws DOMException */ - private static final Cost checkUserDefinedConversionSequence(IType source, IType target) throws DOMException { + static final Cost checkUserDefinedConversionSequence(IType source, IType target, boolean deferUDC) throws DOMException { Cost constructorCost= null; Cost operatorCost= null; IType s= getNestedType(source, TDEF | CVQ | REF); IType t= getNestedType(target, TDEF | CVQ | REF); + if (!(s instanceof ICPPClassType || t instanceof ICPPClassType)) { + return null; + } + + if (deferUDC) { + Cost c= new Cost(s, t, Rank.USER_DEFINED_CONVERSION); + c.setDeferredUDC(true); + return c; + } + //constructors if (t instanceof ICPPClassType) { ICPPConstructor[] ctors= ((ICPPClassType) t).getConstructors(); @@ -359,7 +372,7 @@ public class Conversions { for (final ICPPMethod op : ops) { Cost cost= checkStandardConversionSequence(op.getType().getReturnType(), target, false); if (cost.getRank() != Rank.NO_MATCH) { - int cmp= cost.compare(operatorCost); + int cmp= cost.compareTo(operatorCost); if (cmp <= 0) { cost.setUserDefinedConversion(op); operatorCost= cost; @@ -373,13 +386,13 @@ public class Conversions { if (constructorCost != null) { if (operatorCost != null && !ambiguousConversionOperator) { // If both are valid, then the conversion is ambiguous - constructorCost.setAmbiguousUserdefinedConversion(true); + constructorCost.setAmbiguousUDC(true); } return constructorCost; } if (operatorCost != null) { - operatorCost.setAmbiguousUserdefinedConversion(ambiguousConversionOperator); + operatorCost.setAmbiguousUDC(ambiguousConversionOperator); return operatorCost; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Cost.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Cost.java index cb049e0dd7f..a39e3a7f76f 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Cost.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/Cost.java @@ -13,7 +13,6 @@ *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics; -import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; @@ -34,7 +33,8 @@ final class Cost { private Rank fRank; private Rank fSecondStandardConversionRank; - private boolean fAmbiguousUserdefinedConversion; + private boolean fAmbiguousUDC; + private boolean fDeferredUDC; private int fQualificationAdjustments; private int fInheritanceDistance; private ICPPFunction fUserDefinedConversion; @@ -53,12 +53,20 @@ final class Cost { fRank= rank; } - public boolean isAmbiguousUserdefinedConversion() { - return fAmbiguousUserdefinedConversion; + public boolean isAmbiguousUDC() { + return fAmbiguousUDC; } - public void setAmbiguousUserdefinedConversion(boolean val) { - fAmbiguousUserdefinedConversion= val; + public void setAmbiguousUDC(boolean val) { + fAmbiguousUDC= val; + } + + public boolean isDeferredUDC() { + return fDeferredUDC; + } + + public void setDeferredUDC(boolean val) { + fDeferredUDC= val; } public int getInheritanceDistance() { @@ -93,10 +101,13 @@ final class Cost { * 0 if this cost is equal to the other cost, * an integer > 0 if this cost is larger than the other cost. */ - public int compare(Cost other) throws DOMException { + public int compareTo(Cost other) { if (other == null) return -1; + // cannot compare costs with deferred user defined conversions + assert !fDeferredUDC && !other.fDeferredUDC; + int cmp= fRank.compareTo(other.fRank); if (cmp != 0) return cmp; @@ -104,7 +115,7 @@ final class Cost { // rank is equal if (fRank == Rank.USER_DEFINED_CONVERSION) { // 13.3.3.1.10 - if (isAmbiguousUserdefinedConversion() || other.isAmbiguousUserdefinedConversion()) + if (isAmbiguousUDC() || other.isAmbiguousUDC()) return 0; if (!fUserDefinedConversion.equals(other.fUserDefinedConversion)) diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/FunctionCost.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/FunctionCost.java index 97a22c69dd8..85ef69e1c57 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/FunctionCost.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/FunctionCost.java @@ -47,12 +47,34 @@ class FunctionCost { public boolean hasAmbiguousUserDefinedConversion() { for (Cost cost : fCosts) { - if (cost.isAmbiguousUserdefinedConversion()) + if (cost.isAmbiguousUDC()) return true; } return false; } + public boolean hasDeferredUDC() { + for (Cost cost : fCosts) { + if (cost.isDeferredUDC()) + return true; + } + return false; + } + + public boolean performUDC() throws DOMException { + for (int i = 0; i < fCosts.length; i++) { + Cost cost = fCosts[i]; + if (cost.isDeferredUDC()) { + Cost udcCost= Conversions.checkUserDefinedConversionSequence(cost.source, cost.target, false); + if (udcCost == null) { + return false; + } + fCosts[i]= udcCost; + } + } + return true; + } + /** * Compares this function call cost to another one. */ @@ -75,7 +97,7 @@ class FunctionCost { break; } - int cmp = cost.compare(other.getCost(idxOther)); + int cmp = cost.compareTo(other.getCost(idxOther)); haveWorse |= (cmp > 0); haveBetter |= (cmp < 0); } @@ -112,6 +134,36 @@ class FunctionCost { return 1; } + + public boolean mustBeWorse(FunctionCost other) { + if (other == null) + return false; + + boolean haveWorse= false; + int idx= getLength()-1; + int idxOther= other.getLength()-1; + for (; idx>=0 && idxOther>=0; idx--,idxOther--) { + Cost cost= getCost(idx); + if (cost.getRank() == Rank.NO_MATCH) + return true; + + Cost otherCost= other.getCost(idxOther); + + int cmp; + if (cost.isDeferredUDC()) { + cmp= cost.getRank().compareTo(otherCost.getRank()); + } else { + cmp= cost.compareTo(otherCost); + } + + if (cmp < 0) + return false; + if (cmp > 0) + haveWorse= true; + } + + return haveWorse; + } private static ICPPFunctionTemplate asTemplate(IFunction function) { if (function instanceof ICPPSpecialization) {