root/trunk/ProjectFortress/src/com/sun/fortress/compiler/phases/OverloadSet.java @ 3915

Revision 3915, 36.2 KB (checked in by jrhil47, 5 months ago)

[index] Changed all Functional indices to store a thunk to get the return types, since during type checking the return types might need to be lazily evaluated. Also changed Functional indices to yield an Option for return types.
[type checker] Started implementing extraction of bindings from nodes for type environments.

Line 
1/*******************************************************************************
2    Copyright 2009 Sun Microsystems, Inc.,
3    4150 Network Circle, Santa Clara, California 95054, U.S.A.
4    All rights reserved.
5
6    U.S. Government Rights - Commercial software.
7    Government users are subject to the Sun Microsystems, Inc. standard
8    license agreement and applicable provisions of the FAR and its supplements.
9
10    Use is subject to license terms.
11
12    This distribution may include materials developed by third parties.
13
14    Sun, Sun Microsystems, the Sun logo and Java are trademarks or registered
15    trademarks of Sun Microsystems, Inc. in the U.S. and other countries.
16 ******************************************************************************/
17
18package com.sun.fortress.compiler.phases;
19
20import static com.sun.fortress.exceptions.InterpreterBug.bug;
21import static com.sun.fortress.exceptions.ProgramError.error;
22
23import java.util.ArrayList;
24import java.util.Collections;
25import java.util.Comparator;
26import java.util.HashSet;
27import java.util.List;
28import java.util.Map;
29import java.util.Set;
30
31import org.objectweb.asm.ClassVisitor;
32import org.objectweb.asm.Label;
33import org.objectweb.asm.MethodVisitor;
34import org.objectweb.asm.Opcodes;
35
36import com.sun.fortress.compiler.NamingCzar;
37import com.sun.fortress.compiler.codegen.CodeGen;
38import com.sun.fortress.compiler.index.ApiIndex;
39import com.sun.fortress.compiler.index.Function;
40import com.sun.fortress.compiler.index.Functional;
41import com.sun.fortress.compiler.typechecker.TypeAnalyzer;
42import com.sun.fortress.exceptions.InterpreterBug;
43import com.sun.fortress.nodes.APIName;
44import com.sun.fortress.nodes.AnyType;
45import com.sun.fortress.nodes.ArrowType;
46import com.sun.fortress.nodes.BaseType;
47import com.sun.fortress.nodes.IdOrOpOrAnonymousName;
48import com.sun.fortress.nodes.IntersectionType;
49import com.sun.fortress.nodes.Param;
50import com.sun.fortress.nodes.TupleType;
51import com.sun.fortress.nodes.Type;
52import com.sun.fortress.nodes_util.NodeFactory;
53import com.sun.fortress.useful.BASet;
54import com.sun.fortress.useful.BATree;
55import com.sun.fortress.useful.DefaultComparator;
56import com.sun.fortress.useful.F;
57import com.sun.fortress.useful.GMultiMap;
58import com.sun.fortress.useful.Hasher;
59import com.sun.fortress.useful.MagicNumbers;
60import com.sun.fortress.useful.MultiMap;
61import com.sun.fortress.useful.TopSort;
62import com.sun.fortress.useful.TopSortItemImpl;
63import com.sun.fortress.useful.Useful;
64
65import edu.rice.cs.plt.tuple.Option;
66
67abstract public class OverloadSet implements Comparable<OverloadSet> {
68
69    static class POType extends TopSortItemImpl<Type> {
70        public POType(Type x) {
71            super(x);
72        }
73    }
74
75    public static class TaggedFunctionName implements Comparable<TaggedFunctionName> {
76        final private APIName tagA;
77        final private Function tagF;
78        public TaggedFunctionName(APIName a, Function f) {
79            this.tagF = f;
80            this.tagA = a;
81        }
82        public List<Param> tagParameters() {
83            return tagF.parameters();
84        }
85        public List<Param> callParameters() {
86            return tagF.parameters();
87        }
88        public Type getReturnType() {
89            return tagF.getReturnType().unwrap();
90        }
91        public int hashCode() {
92            return tagF.hashCode() + MagicNumbers.a * tagA.hashCode();
93        }
94        public boolean equals(Object o) {
95            if (o instanceof TaggedFunctionName) {
96                TaggedFunctionName tfn = (TaggedFunctionName) o;
97                return tagF.equals(tfn.tagF) && tagA.equals(tfn.tagA);
98            }
99            return false;
100        }
101        public List<BaseType> thrownTypes() {
102            return tagF.thrownTypes();
103        }
104        public String toString() {
105            return tagA.toString() + ".." + tagF.toString();
106        }
107       
108        @Override
109        public int compareTo(TaggedFunctionName o) {
110            int i = tagF.toUndecoratedName().toString().compareTo(o.tagF.toUndecoratedName().toString());
111            if (i != 0) return i;
112            i = tagA.toString().compareTo(o.tagA.toString());
113            List<Param> p = tagParameters();
114            List<Param> q = o.tagParameters();
115            if (p.size() < q.size()) return -1;
116            if (p.size() > q.size()) return 1;
117            for (int j = 0; j < p.size(); j++) {
118                Param pp = p.get(i);
119                Param qq = q.get(i);
120                Type tp = pp.getIdType().unwrap();
121                Type tq = qq.getIdType().unwrap();
122                Class cp = tp.getClass();
123                Class cq = tq.getClass();
124                if (cp.equals(cq)) {
125                    i = tp.toString().compareTo(tq.toString());
126                } else {
127                    i = cp.getName().compareTo(cq.getName());
128                }
129                if (i != 0)
130                    return i;
131               
132            }
133            return 0;
134        }
135    }
136
137    /**
138     * The set of functions that are less-specific-than-or-equal to the
139     * parameters seen so far, so the parameter seen so far would be legal
140     * for any of them.  The goal is to thin this set as more parameters
141     * are found, and ultimately to choose the most specific one that
142     * remains.
143     */
144    final Set<TaggedFunctionName> lessSpecificThanSoFar;
145    final IdOrOpOrAnonymousName name;
146   
147    /**
148     * This overloaded function may have a member whose signature matches
149     * the overloaded function's signature.  If so, the principalMember is not
150     * null.
151     *
152     */
153    TaggedFunctionName principalMember;
154   
155    /**
156     * If there are subsets of the overload set that have principal
157     * members, those can be referenced by name (the signature of the principal
158     * member).  Overloaded functions need to be compiled for those subsets.
159     * Note that if the entire set has a principal member, then it also appears
160     * in this subset, because that indicates that the principal member
161     * (a single function that may be dispatched to) needs a local-mangled name.
162     * Thus, when iterating over the values in this set to generate code,
163     * it is necessary to guard against generating code for the outermost
164     * overloaded set.
165     *
166     * Uses a comparator that takes parameter lists into account.
167     */
168    private BATree<String, OverloadSet> overloadSubsets = new BATree<String, OverloadSet>(DefaultComparator.<String>normal());
169   
170    /**
171     * Used to answer subtype questions.
172     */
173    final TypeAnalyzer ta;
174    /**
175     * All the indices that have been tested already.
176     * Dispatch begins at the "most profitable" index, which
177     * is defined to be the one with the greatest variation.
178     * (Alternative plan might be to order them by the one
179     * with the smallest subsets, thus guaranteeing log depth).
180     */
181    final BASet<Integer> testedIndices;
182
183    /**
184     * Assuming we have a parent (are not the root of a tree of OverloadSets),
185     * what is that parent.
186     */
187    final OverloadSet parent;
188    /**
189     * Assuming we have a parent that dispatched on a parameter, how did we
190     * get here?
191     */
192    final Type selectedParameterType;
193
194    final int paramCount;
195
196    /**
197     * Which parameter is used to split this set into subsets?
198     */
199    int dispatchParameterIndex;
200    OverloadSet[] children;
201    boolean splitDone;
202
203    protected OverloadSet(IdOrOpOrAnonymousName name, TypeAnalyzer ta,
204                Set<TaggedFunctionName> lessSpecificThanSoFar,
205                BASet<Integer> testedIndices, OverloadSet parent, Type selectedParameterType, int paramCount) {
206        this.name = name;
207        this.ta = ta;
208        this.lessSpecificThanSoFar = lessSpecificThanSoFar;
209        this.testedIndices = testedIndices;
210        this.parent = parent;
211        this.selectedParameterType = selectedParameterType;
212        this.paramCount = paramCount;
213    }
214
215    protected OverloadSet(IdOrOpOrAnonymousName name, TypeAnalyzer ta,
216            Set<TaggedFunctionName> lessSpecificThanSoFar,
217            int paramCount) {
218        this(name, ta, lessSpecificThanSoFar, new BASet<Integer>(DefaultComparator.<Integer>normal()),
219            null, null, paramCount);
220    }
221   
222    protected OverloadSet(final APIName apiname, IdOrOpOrAnonymousName name, TypeAnalyzer ta, Set<Function> defs, int n) {
223
224        this(name, ta, Useful.applyToAll(defs, new F<Function, TaggedFunctionName>(){
225
226            @Override
227            public TaggedFunctionName apply(Function f) {
228                return new TaggedFunctionName(apiname, f);
229            }} ), n);
230
231        // Ensure that they are all the same size.
232        for (TaggedFunctionName f : lessSpecificThanSoFar) {
233            if (CodeGenerationPhase.debugOverloading)
234                System.err.println("Overload: " + f);
235            List<Param> parameters = f.tagParameters();
236            int this_size = parameters.size();
237            if (this_size != paramCount)
238                InterpreterBug.bug("Need to handle variable arg dispatch elsewhere " + name);
239
240        }
241    }
242
243    abstract protected  void invokeParticularMethod(MethodVisitor mv, TaggedFunctionName f,
244            String sig);
245
246    /**
247     * Creates a dispatch-child overload set; one in which the dispatch choices have been reduced.
248     *
249     * @param childLSTSF
250     * @param childTestedIndices
251     * @param t
252     * @return
253     */
254    abstract protected OverloadSet makeChild(Set<TaggedFunctionName> childLSTSF, BASet<Integer> childTestedIndices, Type t);
255
256    /**
257     * Creates a subset overload set; one that can be named independently as an overloaded function.
258     *
259     * @param childLSTSF
260     * @param principalMember
261     * @return
262     */
263    abstract protected OverloadSet makeSubset(Set<TaggedFunctionName> childLSTSF, TaggedFunctionName principalMember);
264   
265    public void split(boolean computeSubsets) {
266        /* First determine if there are any overload subsets.
267           This matters because it may affect naming of the leaf (single) functions.
268        */
269        if (computeSubsets) {
270            for (TaggedFunctionName f : lessSpecificThanSoFar) {
271                int i = 1; // for self
272                for (TaggedFunctionName g : lessSpecificThanSoFar) {
273                    if (!(f == g)) {
274                        if (fSuperTypeOfG(f, g)) {
275                            i++;
276                        }
277                    }
278                }
279                if (i > 1) {
280                    if (i == lessSpecificThanSoFar.size()) {
281                        principalMember = f;
282                    } else {
283                        // TODO work in progress
284                        HashSet<TaggedFunctionName> subLSTSF = new HashSet<TaggedFunctionName>();
285                        subLSTSF.add(f);
286                        for (TaggedFunctionName g : lessSpecificThanSoFar) {
287                            if (!(f == g)) {
288                                if (fSuperTypeOfG(f, g)) {
289                                    subLSTSF.add(g);
290                                }
291                            }
292                        }
293                        OverloadSet subset = makeSubset(subLSTSF, f);
294                        subset.overloadSubsets = overloadSubsets;
295                       
296                        overloadSubsets.put(jvmSignatureFor(f), subset);
297                    }
298                }
299            }
300
301            for (OverloadSet subset : overloadSubsets.values()) {
302                subset.splitInternal();
303            }
304        }
305
306        if (principalMember != null)
307            overloadSubsets.put(jvmSignatureFor(principalMember), this);
308       
309        /* Split set into dispatch tree. */
310        splitInternal();
311       
312    }
313   
314   
315
316    public void splitInternal() {
317        if (splitDone)
318            return;
319
320        if (lessSpecificThanSoFar.size() == 1) {
321                splitDone = true;
322                return;
323            // If there are no other alternatives, then we are done.
324        }
325
326        {
327            // Accumulate sets of parameter types.
328            int nargs = paramCount;;
329
330            MultiMap<Type, TaggedFunctionName>[] typeSets = new MultiMap[nargs];
331            for (int i = 0; i < nargs; i++) {
332                typeSets[i] = new MultiMap<Type, TaggedFunctionName>();
333            }
334
335            for (TaggedFunctionName f : lessSpecificThanSoFar) {
336                List<Param> parameters = f.tagParameters();
337                int i = 0;
338                for (Param p : parameters) {
339                    if (testedIndices.contains(i)) {
340                        i++;
341                        continue;
342                    }
343                    Option<Type> ot = p.getIdType();
344                    Option<Type> ovt = p.getVarargsType();
345                    if (ovt.isSome()) {
346                        InterpreterBug.bug("Not ready to handle compilation of overloaded varargs yet, function is " + f);
347                    }
348                    if (ot.isNone()) {
349                        InterpreterBug.bug("Missing type for parameter " + i + " of " + f);
350                    }
351                    Type t = ot.unwrap();
352                    typeSets[i++].putItem(t, f);
353                }
354            }
355
356            // Choose parameter index with greatest variation.
357            // Choose parameter index with the smallest largest subset.
358            int besti = -1; int best = 0;
359            boolean greatest_variation = false;
360            for (int i = 0; i < nargs; i++) {
361                if (testedIndices.contains(i))
362                    continue;
363                if (greatest_variation) {
364                    if (typeSets[i].size() > best) {
365                        best = typeSets[i].size();
366                        besti = i;
367                    }
368                } else {
369                    MultiMap<Type, TaggedFunctionName> mm = typeSets[i];
370                    int largest = 0;
371                    for (Set<TaggedFunctionName> sf : mm.values()) {
372                        if (sf.size() > largest)
373                            largest = sf.size();
374                    }
375                    if (besti == -1 || largest < best) {
376                        besti = i;
377                        best = largest;
378                    }
379                }
380            }
381
382            // dispatch on maxi'th parameter.
383            dispatchParameterIndex = besti;
384            Set<Type> dispatchTypes = typeSets[dispatchParameterIndex].keySet();
385
386
387            children = new OverloadSet[best];
388            BASet<Integer> childTestedIndices = testedIndices.putNew(besti);
389
390            int i = 0;
391            TopSortItemImpl<Type>[] potypes =
392                new OverloadSet.POType[dispatchTypes.size()];
393            /* Convert set of dispatch types into something that can be
394               (topologically) sorted. */
395            for (Type t : dispatchTypes) {
396                potypes[i] = new POType(t);
397                i++;
398            }
399
400            /*
401             * Figure out ordering relationship for top sort.  O(N^2) work,
402             * hope N is not too large.
403             */
404            for (i = 0; i < potypes.length; i++) {
405                for (int j = i+1; j < potypes.length; j++) {
406                    Type ti = potypes[i].x;
407                    Type tj = potypes[j].x;
408                    if (ta.subtype(ti, tj).isTrue()) {
409                        potypes[i].edgeTo(potypes[j]);
410                    } else if (ta.subtype(tj, ti).isTrue()) {
411                        potypes[j].edgeTo(potypes[i]);
412                    }
413                }
414            }
415
416            List<TopSortItemImpl<Type>> specificFirst = TopSort.depthFirst(potypes);
417            children = new OverloadSet[specificFirst.size()];
418            Set<TaggedFunctionName> alreadySelected = new HashSet<TaggedFunctionName>();
419
420            // fill in children.
421            for (i = 0; i < specificFirst.size(); i++) {
422                Type t = specificFirst.get(i).x;
423                Set<TaggedFunctionName> childLSTSF = new HashSet<TaggedFunctionName>();
424
425                    for (TaggedFunctionName f : lessSpecificThanSoFar) {
426//                        if (alreadySelected.contains(f))
427//                            continue;
428                        List<Param> parameters = f.tagParameters();
429                        Param p = parameters.get(dispatchParameterIndex);
430                        Type pt = p.getIdType().unwrap();
431                        if (ta.subtype(t, pt).isTrue()) {
432                            childLSTSF.add(f);
433                            alreadySelected.add(f);
434
435                        }
436                    }
437
438               childLSTSF = thin(childLSTSF, childTestedIndices);
439
440               // ought to not be necessary
441               if (paramCount == childTestedIndices.size()) {
442                        // Choose most specific member of lessSpecificThanSoFar
443                   childLSTSF = mostSpecificMemberOf(childLSTSF);
444
445                }
446
447                OverloadSet ch = makeChild(childLSTSF, childTestedIndices, t);
448                ch.overloadSubsets = overloadSubsets;
449                children[i] = ch;
450
451            }
452            for (OverloadSet child: children) {
453                child.splitInternal();
454            }
455        }
456        splitDone = true;
457    }
458
459    private Set<TaggedFunctionName> thin(Set<TaggedFunctionName> childLSTSF, final Set<Integer> childTestedIndices) {
460        /*
461         * Hashes together functions that are equal in their unexamined parameter lists.
462         */
463        Hasher<TaggedFunctionName> hasher = new Hasher<TaggedFunctionName>() {
464
465            @Override
466            public boolean equiv(TaggedFunctionName x, TaggedFunctionName y) {
467                List<Param> px = x.tagParameters();
468                List<Param> py = y.tagParameters();
469                for (int i = 0; i < px.size(); i++) {
470                    if (childTestedIndices.contains(i))
471                        continue;
472                    Type tx = px.get(i).getIdType().unwrap();
473                    Type ty = px.get(i).getIdType().unwrap();
474                    if (! tx.equals(ty))
475                        return false;
476                }
477                return true;
478            }
479
480            @Override
481            public long hash(TaggedFunctionName x) {
482                int h = MagicNumbers.T;
483
484                List<Param> px = x.tagParameters();
485                for (int i = 0; i < px.size(); i++) {
486                    if (childTestedIndices.contains(i))
487                        continue;
488                    Type tx = px.get(i).getIdType().unwrap();
489                    h = h * MagicNumbers.t + tx.hashCode();
490                }
491                return h;
492            }
493
494        };
495
496        /*
497         * Creates map from (some) functions to the
498         * equivalence sets to which they are members.
499         */
500        GMultiMap<TaggedFunctionName, TaggedFunctionName> eqSetMap = new GMultiMap<TaggedFunctionName, TaggedFunctionName>(hasher);
501        for (TaggedFunctionName f : childLSTSF)
502            eqSetMap.putItem(f, f);
503
504        Set<TaggedFunctionName> tmp = new HashSet<TaggedFunctionName>();
505
506        /*
507         * Take the most specific member of each equivalence set, and union
508         * those together.
509         */
510        for (Set<TaggedFunctionName> sf : eqSetMap.values())
511            tmp.addAll(mostSpecificMemberOf(sf));
512
513        return tmp;
514    }
515
516    /**
517     *
518     */
519    private Set<TaggedFunctionName> mostSpecificMemberOf(Set<TaggedFunctionName> set) {
520        TaggedFunctionName msf = null;
521        for (TaggedFunctionName candidate : set) {
522            if (msf == null)
523                msf = candidate;
524            else {
525                boolean cand_better = fSuperTypeOfG(msf, candidate);
526                if (cand_better)
527                    msf = candidate;
528
529            }
530        }
531        if (msf == null)
532            return Collections.<TaggedFunctionName>emptySet();
533        else
534            return Collections.singleton(msf);
535    }
536
537    /**
538     * @param f
539     * @param g
540     * @return
541     */
542    private boolean fSuperTypeOfG(TaggedFunctionName f, TaggedFunctionName g) {
543        List<Param> msf_parameters = f.tagParameters();
544        List<Param> cand_parameters = g.tagParameters();
545        if (msf_parameters.size() != cand_parameters.size()) {
546            InterpreterBug.bug("Diff length parameter lists, should not be possible");
547        }
548        boolean cand_better = true;
549        for (int i = 0; i < msf_parameters.size(); i++) {
550            // Not handling varargs yet!
551            Type msf_t = msf_parameters.get(i).getIdType().unwrap();
552            Type cand_t = cand_parameters.get(i).getIdType().unwrap();
553            // if any type of the candidate is not a subtype(or eq)
554            // of the corresponding type of the msf, then the candidate
555            // is NOT better.
556            if (! ta.subtype(cand_t, msf_t).isTrue()) {
557                cand_better = false;
558                break;
559            }
560        }
561        return cand_better;
562    }
563
564    @Override
565    public int compareTo(OverloadSet o) {
566        // TODO Auto-generated method stub
567        return name.stringName().compareTo(o.name.stringName());
568    }
569
570    public IdOrOpOrAnonymousName getName() {
571        return name;
572    }
573
574    public int getParamCount() {
575        return paramCount;
576    }
577
578    /**
579     * returns the code generation signature for the overloaded function.
580     * (separation of concerns problem here -- taking joins of types,
581     * and returning a target-platform (i.e., Java) signature).
582     *
583     * @return
584     */
585    public String getSignature() {
586        String s = overloadedDomainSig();
587
588        Type r = null;
589
590        for (TaggedFunctionName f : lessSpecificThanSoFar) {
591            r = join(r, f.getReturnType(), ta);
592        }
593        s += NamingCzar.boxedImplDesc(r, null);
594
595        return s;
596    }
597
598    /**
599     * @param r
600     * @param r0
601     * @return
602     */
603    private static Type join(Type r, Type r0, TypeAnalyzer ta) {
604        // Eventually we want to use the join from TypeAnalyzer, once we
605        // figure out how to deal with union types.
606        if(r == null) {
607            r = r0;
608        } else if (r.equals(r0)) {
609            // ok
610        } else if (ta.subtype(r, r0).isTrue()) {
611            r = r0;
612        } else if (ta.subtype(r0, r).isTrue()) {
613            // ok
614        } else if (!(r instanceof AnyType)) {
615            // Locate the any at the place we realized it was necessary.
616            r = NodeFactory.makeAnyType(r0.getInfo().getSpan());
617        }
618        return r;
619    }
620
621    /**
622     * Given an intersection of arrow types (what we get for at least some
623     * overloaded functions) and an indication of how many parameters actually
624     * appeared, create the signature for the overloaded function that will be
625     * called.
626     *
627     * There's some fiddliness with varargs that has to be sorted out.
628     *
629     * @param t
630     * @param paramCount
631     * @return
632     */
633    public static String getSignature(IntersectionType t, int paramCount, TypeAnalyzer ta) {
634
635        String s = overloadedDomainSig(t, paramCount, ta);
636
637        Type r = getRangeSignature(t, paramCount, ta);
638
639        s += NamingCzar.boxedImplDesc(r, null);
640
641        return s;
642    }
643   
644    /**
645     * Checks the parameter count against the intersection type to see if
646     * this is a real overloading, or one that can trivially be disambiguated
647     * by counting parameters.
648     *
649     * @param t
650     * @param paramCount
651     * @return
652     */
653    public static boolean actuallyOverloaded(IntersectionType t, int paramCount) {
654        return matchingCount(t, paramCount) > 1;
655    }
656    public static int matchingCount(IntersectionType t, int paramCount) {
657        int sum = 0;
658        List<Type> types = t.getElements();
659
660        Type r = null;
661
662        for (Type type : types) {
663            Type r0;
664
665            if (type instanceof ArrowType) {
666                ArrowType at = (ArrowType) type;
667                r0 = at.getDomain();
668                if (r0 instanceof TupleType) {
669                    TupleType tt = (TupleType) r0;
670                    if (paramCount != tt.getElements().size())
671                        continue;
672                } else if (paramCount != 1) {
673                    continue;
674                }
675               
676                sum++;
677               
678            } else if (type instanceof IntersectionType) {
679                sum += matchingCount((IntersectionType) type, paramCount);
680            } else {
681                InterpreterBug.bug("Non arrowtype " + type + " in (function) intersection type");
682            }
683        }
684        return sum;
685    }
686
687
688    private static Type getRangeSignature(IntersectionType t, int paramCount, TypeAnalyzer ta) {
689        List<Type> types = t.getElements();
690
691        Type r = null;
692
693        for (Type type : types) {
694            Type r0;
695
696            if (type instanceof ArrowType) {
697                ArrowType at = (ArrowType) type;
698               
699                // Ensure that the domain count matches the paramCount
700                r0 = at.getDomain();
701                if (r0 instanceof TupleType) {
702                    TupleType tt = (TupleType) r0;
703                    if (paramCount != tt.getElements().size())
704                        continue;
705                } else if (paramCount != 1) {
706                    continue;
707                }
708               
709                r0 = at.getRange();
710            } else if (type instanceof IntersectionType) {
711                r0 = getRangeSignature((IntersectionType) type, paramCount, ta);
712            } else {
713                InterpreterBug.bug("Non arrowtype " + type + " in (function) intersection type");
714                return null; // not reached
715            }
716
717            r = join(r, r0, ta);
718
719            if (r instanceof AnyType)
720                break;
721        }
722        return r;
723    }
724
725    private  static Type getParamType(IntersectionType t, int i, int paramCount, TypeAnalyzer ta) {
726        List<Type> types = t.getElements();
727
728        Type r = null;
729
730        for (Type type : types) {
731            Type r0;
732
733            r0 = getParamType(type, i, paramCount, ta);
734
735            if (r0 != null)
736                r = join(r, r0, ta);
737
738            if (r instanceof AnyType)
739                break;
740        }
741        return r;
742    }
743
744    /**
745     * @param type
746     * @param i
747     * @param paramCount
748     * @param ta
749     * @return
750     */
751    public static Type getParamType(Type type, int i, int paramCount,
752            TypeAnalyzer ta) {
753        Type r0;
754        if (type instanceof ArrowType) {
755            ArrowType at = (ArrowType) type;
756            r0 = at.getDomain();
757           
758            // Ensure that the domain count matches the paramCount
759            if (r0 instanceof TupleType) {
760                TupleType tt = (TupleType) r0;
761                if (paramCount != tt.getElements().size())
762                    r0 = null;
763                else
764                    r0 = tt.getElements().get(i);
765            } else if (paramCount != 1) {
766                r0 = null;
767            }
768        } else if (type instanceof IntersectionType) {
769            r0 = getParamType((IntersectionType) type, i, paramCount, ta);
770        } else {
771            r0 = InterpreterBug.bug("Non arrowtype " + type + " in (function) intersection type");
772            // not reached
773        }
774        return r0;
775    }
776
777    public static boolean functionInstanceofType(Functional f, com.sun.fortress.nodes.Type ty, TypeAnalyzer ta) {
778        List<Param> params = f.parameters();
779        int l = params.size();
780        int i = 0;
781        // TODO this check is imperfect in a land of intersection types.
782        // ought to iteratively ask the question, not reify the parameter type.
783        for (Param p : params) {
784            com.sun.fortress.nodes.Type ti = getParamType(ty, i, l, ta);
785            com.sun.fortress.nodes.Type tp = p.getIdType().unwrap();
786            if (ti == null)
787                return false;
788            if (! ta.subtype(tp, ti).isTrue())
789                return false;
790        }
791        return true;
792    }
793   
794    /**
795     * @param paramCount
796     * @return
797     */
798    private static String overloadedDomainSig(IntersectionType t, int paramCount, TypeAnalyzer ta) {
799        String s = "(";
800
801        for (int i = 0; i < paramCount; i++) {
802            s += NamingCzar.boxedImplDesc(getParamType(t,i,paramCount, ta), null);
803        }
804        s += ")";
805        return s;
806    }
807
808    private String overloadedDomainSig() {
809        String s = "(";
810
811        for (int i = 0; i < paramCount; i++) {
812            s += NamingCzar.boxedImplDesc(overloadedParamType(i), null);
813        }
814        s += ")";
815        return s;
816    }
817
818    private Type overloadedParamType(int param) {
819        Type r = null;
820        for (TaggedFunctionName f : lessSpecificThanSoFar) {
821            List<Param> params = f.tagParameters();
822            Param p = params.get(param);
823            r = join(r, p.getIdType().unwrap(), ta);
824        }
825        return r;
826    }
827
828    public String[] getExceptions() {
829        HashSet<Type> exceptions = new HashSet<Type>();
830        for (TaggedFunctionName f : lessSpecificThanSoFar) {
831            List<BaseType> f_exceptions =  f.thrownTypes();
832            exceptions.addAll(f_exceptions);
833        }
834        String[] string_exceptions = new String[exceptions.size()];
835        int i = 0;
836        for (Type e : exceptions) {
837            string_exceptions[i++] = NamingCzar.boxedImplDesc(e, null);
838        }
839        return string_exceptions;
840    }
841
842    public void generateCall(MethodVisitor mv, int firstArgIndex, Label failLabel) {
843        if (!splitDone) {
844             InterpreterBug.bug("Must split overload set before generating call(s)");
845             return;
846        }
847
848        if (lessSpecificThanSoFar.size() == 1) {
849            // Emit casts and call of f.
850            TaggedFunctionName f =  lessSpecificThanSoFar.iterator().next();
851
852            String sig = jvmSignatureFor(f);
853           
854            int i = firstArgIndex;
855            List<Param> params = f.callParameters();
856
857            for (Param p : params ) {
858                mv.visitVarInsn(Opcodes.ALOAD, i);
859               
860                Type ty = p.getIdType().unwrap();
861                mv.visitTypeInsn(Opcodes.CHECKCAST, NamingCzar.boxedImplType(ty));
862                i++;
863            }
864            if (CodeGenerationPhase.debugOverloading)
865                System.err.println("Emitting call " + f.tagF + sig);
866
867
868            invokeParticularMethod(mv, f, sig);
869            mv.visitInsn(Opcodes.ARETURN);
870
871        } else {
872            // Perform instanceof checks on specified parameter to dispatch to children.
873            Label lookahead = new Label();
874            for (int i = 0; i < children.length; i++) {
875                OverloadSet os = children[i];
876                mv.visitVarInsn(Opcodes.ALOAD, dispatchParameterIndex + firstArgIndex);
877                mv.visitTypeInsn(Opcodes.INSTANCEOF, NamingCzar.boxedImplType(os.selectedParameterType));
878                mv.visitJumpInsn(Opcodes.IFEQ, lookahead);
879                os.generateCall(mv, firstArgIndex, failLabel);
880                mv.visitLabel(lookahead);
881                if (i+1 < children.length)
882                    lookahead = new Label();
883                else lookahead = null;
884            }
885            mv.visitJumpInsn(Opcodes.GOTO, failLabel);
886        }
887    }
888
889    /**
890     * @param f
891     * @return
892     */
893    static String jvmSignatureFor(TaggedFunctionName f) {
894        return NamingCzar.jvmSignatureFor(f.tagF, f.tagA);
895    }
896
897
898    public String toString() {
899        if (lessSpecificThanSoFar.size() == 1) {
900            return lessSpecificThanSoFar.iterator().next().toString();
901        }
902        if (splitDone) {
903            return toStringR("");
904        } else {
905            return lessSpecificThanSoFar.toString();
906        }
907    }
908
909    private String toStringR(String indent) {
910        if (lessSpecificThanSoFar.size() == 1) {
911            return indent + lessSpecificThanSoFar.iterator().next().toString();
912        } else {
913            String s =  indent + "#" + dispatchParameterIndex + "\n";
914            for (int i = 0; i < children.length; i++) {
915                OverloadSet os = children[i];
916                s += indent + os.selectedParameterType + "->" + os.toStringR(indent + "   ") + "\n";
917            }
918            return s;
919        }
920    }
921
922    /**
923     * Overloaded functions get a slightly mangled name.
924     *
925     * @param name
926     * @return
927     */
928    public static String oMangle(String name) {
929        return /* "O$" + */ name; // no mangling after all.
930    }
931 
932    public void generateAnOverloadDefinition(String name, ClassVisitor cv) {
933        generateAnOverloadDefinitionInner(name, cv);
934       
935        for (Map.Entry<String, OverloadSet> o_entry : getOverloadSubsets().entrySet()) {
936            String ss = o_entry.getKey();
937            OverloadSet sos = o_entry.getValue();
938            if (sos != this) {
939                sos.generateAnOverloadDefinitionInner(name, cv);
940            }
941        }
942    }
943   
944    public void generateAnOverloadDefinitionInner(String name, ClassVisitor cv) {
945
946        // "(" anOverloadedArg^N ")" returnType
947        // Not sure what to do with return type.
948        String signature = getSignature();
949        String[] exceptions = getExceptions();
950        if (CodeGenerationPhase.debugOverloading)
951            System.err.println("Emitting overload " + name + signature);
952
953        MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC
954                + Opcodes.ACC_STATIC, // access,
955                oMangle(name), // name,
956                signature, // sp.getFortressifiedSignature(),
957                null, // signature, // depends on generics, I think
958                exceptions); // exceptions);
959
960        mv.visitCode();
961        Label fail = new Label();
962
963        generateCall(mv, 0, fail); // Guts of overloaded method
964
965        // Emit failure case
966        mv.visitLabel(fail);
967        // Boilerplate for throwing an error.
968        mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
969        mv.visitTypeInsn(Opcodes.NEW, "java/lang/Error");
970        mv.visitInsn(Opcodes.DUP);
971        mv.visitLdcInsn("Should not happen");
972        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Error", "<init>",
973                "(Ljava/lang/String;)V");
974        mv.visitInsn(Opcodes.ATHROW);
975
976        mv.visitMaxs(getParamCount(), getParamCount()); // autocomputed
977        mv.visitEnd();
978
979    }
980
981   
982
983    public BATree<String, OverloadSet> getOverloadSubsets() {
984        return overloadSubsets;
985    }
986
987    static public class Local extends AmongApis {
988        public Local(final APIName apiname, IdOrOpOrAnonymousName name, TypeAnalyzer ta, Set<Function> defs, int n) {
989            super(name, ta, Useful.applyToAll(defs, new F<Function, TaggedFunctionName>(){
990
991                @Override
992                public TaggedFunctionName apply(Function f) {
993                    return new TaggedFunctionName(apiname, f);
994                }} ), n);
995        }
996     
997    }
998   
999    static public class AmongApis extends OverloadSet {
1000        /**
1001         * Emit the invocation for a particular type of overloaded functions.
1002         *
1003         * @param mv
1004         * @param f
1005         * @param sig
1006         */
1007        protected void invokeParticularMethod(MethodVisitor mv, TaggedFunctionName f,
1008                String sig) {
1009           
1010           
1011            String ownerName = NamingCzar.only.apiAndMethodToMethodOwner(f.tagA, f.tagF);
1012            String mname = NamingCzar.only.apiAndMethodToMethod(f.tagA, f.tagF);
1013           
1014            if (getOverloadSubsets().containsKey(sig))
1015                mname = NamingCzar.only.mangleAwayFromOverload(mname);
1016           
1017            mv.visitMethodInsn(Opcodes.INVOKESTATIC, ownerName, mname, sig);
1018        }
1019
1020        /* Boilerplate follows, because this is a subtype. */
1021
1022        protected AmongApis(IdOrOpOrAnonymousName name, TypeAnalyzer ta,
1023                Set<TaggedFunctionName> lessSpecificThanSoFar,
1024                BASet<Integer> testedIndices, OverloadSet parent, Type selectedParameterType, int paramCount) {
1025            super(name, ta, lessSpecificThanSoFar, testedIndices, parent, selectedParameterType, paramCount);
1026        }
1027
1028        public AmongApis(IdOrOpOrAnonymousName name, TypeAnalyzer ta, Set<TaggedFunctionName> defs, int n) {
1029            super(name, ta, defs, n);
1030        }
1031       
1032        protected OverloadSet makeChild(Set<TaggedFunctionName> childLSTSF, BASet<Integer> childTestedIndices, Type t) {
1033            return new AmongApis(name, ta, childLSTSF,
1034                    childTestedIndices, this, t, paramCount);
1035        }
1036
1037        protected OverloadSet makeSubset(Set<TaggedFunctionName> childLSTSF, TaggedFunctionName principalMember) {
1038            OverloadSet subset =  new AmongApis(name, ta, childLSTSF, paramCount);
1039            subset.principalMember = principalMember;
1040            return subset;
1041        }
1042
1043    }
1044
1045}
Note: See TracBrowser for help on using the browser.