root/trunk/ProjectFortress/src/com/sun/fortress/compiler/codegen/CodeGen.java @ 3852

Revision 3852, 42.1 KB (checked in by chf, 5 months ago)

alphabetize codegen, ParallelismAnallyzer? isn't working yet.

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******************************************************************************/
17package com.sun.fortress.compiler.codegen;
18
19import java.io.FileOutputStream;
20import java.io.PrintWriter;
21import java.math.BigInteger;
22import java.util.*;
23
24import org.objectweb.asm.*;
25import org.objectweb.asm.util.*;
26
27import edu.rice.cs.plt.collect.PredicateSet;
28import edu.rice.cs.plt.collect.Relation;
29import edu.rice.cs.plt.tuple.Option;
30
31import com.sun.fortress.compiler.AnalyzeResult;
32import com.sun.fortress.compiler.ByteCodeWriter;
33import com.sun.fortress.compiler.NamingCzar;
34import com.sun.fortress.compiler.WellKnownNames;
35import com.sun.fortress.compiler.index.ApiIndex;
36import com.sun.fortress.compiler.index.ComponentIndex;
37import com.sun.fortress.compiler.index.Function;
38import com.sun.fortress.compiler.index.FunctionalMethod;
39import com.sun.fortress.compiler.phases.OverloadSet;
40import com.sun.fortress.compiler.typechecker.TypeAnalyzer;
41import com.sun.fortress.exceptions.CompilerError;
42import com.sun.fortress.nodes.*;
43import com.sun.fortress.nodes.Type;
44import com.sun.fortress.nodes_util.*;
45import com.sun.fortress.repository.ForeignJava;
46import com.sun.fortress.repository.ProjectProperties;
47import com.sun.fortress.useful.BASet;
48import com.sun.fortress.useful.BATree;
49import com.sun.fortress.useful.Debug;
50import com.sun.fortress.useful.DefaultComparator;
51import com.sun.fortress.useful.MultiMap;
52import com.sun.fortress.useful.StringHashComparer;
53
54// Note we have a name clash with org.objectweb.asm.Type
55// and com.sun.fortress.nodes.Type.  If anyone has a better
56// solution than writing out their entire types, please
57// shout out.
58public class CodeGen extends NodeAbstractVisitor_void {
59    ClassWriter cw;
60    MethodVisitor mv;
61    final String packageAndClassName;
62    private final HashMap<String, String> aliasTable;
63    private final TypeAnalyzer ta;
64    private final Map<IdOrOpOrAnonymousName, MultiMap<Integer, Function>> topLevelOverloads;
65    private HashSet<String> overloadedNamesAndSigs;
66
67    // lexEnv does not include the top level or object right now, just
68    // args and local vars.  Object fields should have been translated
69    // to dotted notation at this point, right?  Right?
70    BATree<String, VarCodeGen> lexEnv = null;
71    Symbols symbols;
72    boolean inATrait = false;
73    boolean inAnObject = false;
74    boolean inABlock = false;
75    int localsDepth = 0;
76    Component component;
77    private final ComponentIndex ci;
78
79    public CodeGen(Component c, Symbols s, TypeAnalyzer ta, ComponentIndex ci) {
80        component = c;
81        packageAndClassName = NamingCzar.javaPackageClassForApi(c.getName().getText(), "/").toString();
82        aliasTable = new HashMap<String, String>();
83        symbols = s;
84        this.ta = ta;
85        this.ci = ci;
86        this.topLevelOverloads =
87            sizePartitionedOverloads(ci.functions());
88        this.overloadedNamesAndSigs = new HashSet<String>();
89        debug( "Compile: Compiling ", packageAndClassName );
90    }
91
92    // Create a fresh codegen object for a nested scope.  Technically,
93    // we ought to be able to get by with a single lexEnv, because
94    // variables ought to be unique by location etc.  But in practice
95    // I'm not assuming we have a unique handle for any variable,
96    // so we get a fresh CodeGen for each scope to avoid collisions.
97    private CodeGen(CodeGen c) {
98        this.cw = c.cw;
99        this.mv = c.mv;
100         this.packageAndClassName = c.packageAndClassName;
101        this.aliasTable = c.aliasTable;
102        this.symbols = c.symbols;
103        this.inATrait = c.inATrait;
104        this.inAnObject = c.inAnObject;
105        this.inABlock = c.inABlock;
106        this.localsDepth = c.localsDepth;
107        this.ta = c.ta;
108        this.ci = c.ci;
109        this.topLevelOverloads = c.topLevelOverloads;
110        this.overloadedNamesAndSigs = c.overloadedNamesAndSigs;
111        if (c.lexEnv == null) {
112            this.lexEnv = new BATree<String,VarCodeGen>(StringHashComparer.V);
113        } else {
114            this.lexEnv = new BATree<String,VarCodeGen>(c.lexEnv);
115        }
116    }
117
118    private void generateMainMethod() {
119
120        // We generate two methods.  First a springboard method that creates an
121        // instance of the class we are generating, and then the real main method
122        // which takes the instance and uses it to pass to the primordial task.
123
124        mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "main",
125                            NamingCzar.stringArrayToVoid, null, null);
126        mv.visitCode();
127        mv.visitVarInsn(Opcodes.ALOAD, 0);
128        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/sun/fortress/nativeHelpers/systemHelper",
129                           "registerArgs", NamingCzar.stringArrayToVoid);
130
131        mv.visitTypeInsn(Opcodes.NEW, packageAndClassName);
132        mv.visitInsn(Opcodes.DUP);
133        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, packageAndClassName, "<init>", "()V");
134
135        mv.visitMethodInsn(Opcodes.INVOKESTATIC, packageAndClassName, "main",
136                           "(Lcom/sun/fortress/runtimeSystem/FortressComponent;)V");
137
138        mv.visitInsn(Opcodes.RETURN);
139        mv.visitMaxs(NamingCzar.ignore,NamingCzar.ignore);
140        mv.visitEnd();
141
142        mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "main",
143                            "(Lcom/sun/fortress/runtimeSystem/FortressComponent;)V",
144                            null, null);
145        mv.visitVarInsn(Opcodes.ALOAD, 0);
146        mv.visitMethodInsn(Opcodes.INVOKESTATIC, NamingCzar.primordialTask, "startFortress",
147                           "(Lcom/sun/fortress/runtimeSystem/FortressComponent;)Lcom/sun/fortress/runtimeSystem/PrimordialTask;");
148
149        mv.visitInsn(Opcodes.RETURN);
150        mv.visitMaxs(NamingCzar.ignore,NamingCzar.ignore);
151        mv.visitEnd();
152    }
153
154    private void generateInitMethod() {
155        mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", NamingCzar.voidToVoid, null, null);
156        mv.visitCode();
157        mv.visitVarInsn(Opcodes.ALOAD, 0);
158        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, NamingCzar.internalObject, "<init>", NamingCzar.voidToVoid);
159        mv.visitInsn(Opcodes.RETURN);
160        mv.visitMaxs(NamingCzar.ignore, NamingCzar.ignore);
161        mv.visitEnd();
162    }
163
164
165    private void cgWithNestedScope(ASTNode n) {
166        CodeGen cg = new CodeGen(this);
167        n.accept(cg);
168        this.localsDepth = cg.localsDepth;
169    }
170
171    private void addLocalVar( VarCodeGen v ) {
172        lexEnv.put(v.name.getText(), v);
173        localsDepth += v.sizeOnStack;
174    }
175
176    private VarCodeGen addParam(Param p) {
177        VarCodeGen v =
178            new VarCodeGen.ParamVar(p.getName(), p.getIdType().unwrap(),
179                                    localsDepth);
180        addLocalVar(v);
181        return v;
182    }
183
184    private VarCodeGen getLocalVar( IdOrOp nm ) {
185        VarCodeGen r = lexEnv.get(nm.getText());
186        if (r==null) return sayWhat(nm, "Can't find lexEnv mapping for local var");
187        return r;
188    }
189
190    public void dumpClass( String file ) {
191        PrintWriter pw = new PrintWriter(System.out);
192        cw.visitEnd();
193
194        if (ProjectProperties.getBoolean("fortress.bytecode.verify", false))
195            CheckClassAdapter.verify(new ClassReader(cw.toByteArray()), true, pw);
196
197        ByteCodeWriter.writeClass(NamingCzar.cache, file, cw.toByteArray());
198        debug( "Writing class ", file);
199    }
200
201    private void popAll(int onStack) {
202        if (onStack > 0) {
203            for (; onStack > 1; onStack -= 2) {
204                mv.visitInsn(Opcodes.POP2);
205            }
206            if (onStack==1) {
207                mv.visitInsn(Opcodes.POP);
208            }
209        }
210    }
211
212    private void dumpDecls(List<Decl> decls) {
213        debug("dumpDecls", decls);
214        for (Decl d : decls) {
215            if (!(d instanceof FnDecl)) {
216                sayWhat(d);
217                return;
218            }
219            d.accept(this);
220        }
221    }
222
223
224    private void addLineNumberInfo(ASTNode x) {
225        addLineNumberInfo(mv, x);
226    }
227
228    private void addLineNumberInfo(MethodVisitor m, ASTNode x) {
229        org.objectweb.asm.Label bogus_label = new org.objectweb.asm.Label();
230        m.visitLabel(bogus_label);
231        Span span = NodeUtil.getSpan(x);
232        SourceLoc begin = span.getBegin();
233        SourceLoc end = span.getEnd();
234        String fileName = span.getFileName();
235        m.visitLineNumber(begin.getLine(), bogus_label);
236    }
237
238    public static String jvmSignatureFor(Function f) {
239        String sig;
240        List<Param> params = f.parameters();
241        sig = "(";
242        for (Param p : params ) {               
243            Type ty = p.getIdType().unwrap();
244            String toType = NamingCzar.only.boxedImplDesc(ty);
245            sig += toType;
246        }
247        sig += ")";
248        sig += NamingCzar.only.boxedImplDesc(f.getReturnType());
249        return sig;
250    }
251   
252
253    /**
254     * @param x
255     * @param arrow
256     * @param pkgAndClassName
257     * @param methodName
258     */
259    private void callStaticSingleOrOverloaded(FnRef x,
260            com.sun.fortress.nodes.Type arrow, String pkgAndClassName,
261            String methodName) {
262        {
263            debug("class = " + pkgAndClassName + " method = " + methodName );
264
265            if ( arrow instanceof ArrowType ) {
266                addLineNumberInfo(x);
267                mv.visitMethodInsn(Opcodes.INVOKESTATIC, pkgAndClassName,
268                                   methodName, Naming.emitDesc(arrow));
269            } else if (arrow instanceof IntersectionType) {
270                addLineNumberInfo(x);
271                IntersectionType it = (IntersectionType) arrow;
272                mv.visitMethodInsn(Opcodes.INVOKESTATIC, pkgAndClassName,
273                                   OverloadSet.actuallyOverloaded(it, paramCount) ?
274                                   OverloadSet.oMangle(methodName) :methodName,
275                                   OverloadSet.getSignature(it, paramCount, ta));
276            } else {
277                    sayWhat( x, "Neither arrow nor intersection type: " + arrow );
278            }
279        }
280
281    }
282
283    // paramCount communicates this information from call to function reference,
284    // as it's needed to determine type descriptors for methods.
285    private int paramCount = -1;
286
287    /**
288     * @param y
289     */
290    private void pushInteger(int y) {
291        switch (y) {
292        case 0:
293            mv.visitInsn(Opcodes.ICONST_0);
294            break;
295        case 1:
296            mv.visitInsn(Opcodes.ICONST_1);
297            break;
298        case 2:
299            mv.visitInsn(Opcodes.ICONST_2);
300            break;
301        case 3:
302            mv.visitInsn(Opcodes.ICONST_3);
303            break;
304        case 4:
305            mv.visitInsn(Opcodes.ICONST_4);
306            break;
307        case 5:
308            mv.visitInsn(Opcodes.ICONST_5);
309            break;
310        default:
311            mv.visitLdcInsn(y);
312            break;
313        }
314
315    }
316    private <T> T sayWhat(ASTNode x) {
317        throw new CompilerError(NodeUtil.getSpan(x), "Can't compile " + x);
318    }
319
320    private <T> T sayWhat(ASTNode x, String message) {
321        throw new CompilerError(NodeUtil.getSpan(x), message + " node = " + x);
322    }
323
324    private void debug(Object... message){
325        Debug.debug(Debug.Type.CODEGEN,1,message);
326    }
327
328    public void defaultCase(ASTNode x) {
329        System.out.println("defaultCase: " + x + " of class " + x.getClass());
330        sayWhat(x);
331    }
332
333    public void forBlock(Block x) {
334        boolean oldInABlock = inABlock;
335        inABlock = true;
336        int onStack = 0;
337        debug("forBlock ", x);
338        for ( Expr e : x.getExprs() ) {
339            popAll(onStack);
340            e.accept(this);
341            onStack = 1;
342            // TODO: can we have multiple values on stack in future?
343            // Whither primitive types?
344            // May require some tracking of abstract stack state.
345            // For now we always have 1 pointer on stack and this doesn't
346            // matter.
347        }
348        inABlock=oldInABlock;
349    }
350    public void forChainExpr(ChainExpr x) {
351        debug( "forChainExpr" + x);
352        Expr first = x.getFirst();
353        List<Link> links = x.getLinks();
354        debug( "forChainExpr" + x + " about to call accept on " +
355               first + " of class " + first.getClass());
356        first.accept(this);
357        Iterator<Link> i = links.iterator();
358        if (links.size() != 1)
359            throw new CompilerError(NodeUtil.getSpan(x), x + "links.size != 1");
360        Link link = i.next();
361        link.getExpr().accept(this);
362        debug( "forChainExpr" + x + " about to call accept on " +
363               link.getOp() + " of class " + link.getOp().getClass());
364        link.getOp().accept(this);
365
366        debug( "We've got a link " + link + " an op " + link.getOp() +
367               " and an expr " + link.getExpr() + " What do we do now");
368    }
369
370    public void forComponent(Component x) {
371        debug("forComponent ",x.getName(),NodeUtil.getSpan(x));
372        cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES );
373        cw.visitSource(packageAndClassName, null);
374        boolean exportsExecutable = false;
375        boolean exportsDefaultLibrary = false;
376
377        for ( APIName export : x.getExports() ) {
378            if ( WellKnownNames.exportsMain(export.getText()) )
379                exportsExecutable = true;
380            if ( WellKnownNames.exportsDefaultLibrary(export.getText()) )
381                exportsDefaultLibrary = true;
382        }
383
384        cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER,
385                 packageAndClassName, null, NamingCzar.fortressComponent,
386                 null);
387
388        // Always generate the init method
389        generateInitMethod();
390
391        // If this component exports an executable API,
392        // generate a main method.
393        if ( exportsExecutable ) {
394            generateMainMethod();
395        }
396        for ( Import i : x.getImports() ) {
397            i.accept(this);
398        }
399
400        // determineOverloadedNames(x.getDecls() );
401       
402        // Must do this first, to get local decls right.
403        generateTopLevelOverloads();
404       
405        for ( Decl d : x.getDecls() ) {
406            d.accept(this);
407        }
408       
409       
410
411        dumpClass( packageAndClassName );
412    }
413
414    public void forDecl(Decl x) {
415        sayWhat(x, "forDecl");
416    }
417
418
419    public void forDo(Do x) {
420        debug("forDo ", x);
421        int onStack = 0;
422        for ( Block b : x.getFronts() ) {
423            popAll(onStack);
424            b.accept(this);
425            onStack = 1;
426        }
427    }
428
429    public void forFnDecl(FnDecl x) {
430        debug("forFnDecl ", x );
431        FnHeader header = x.getHeader();
432        boolean canCompile =
433            header.getStaticParams().isEmpty() && // no static parameter
434            header.getWhereClause().isNone() &&   // no where clause
435            header.getThrowsClause().isNone() &&  // no throws clause
436            header.getContract().isNone() &&      // no contract
437            header.getMods().isEmpty() &&         // no modifiers
438            !inABlock;                            // no local functions
439
440        if ( !canCompile ) sayWhat(x);
441
442        Option<Expr> body = x.getBody();
443        IdOrOpOrAnonymousName name = header.getName();
444        List<Param> params = header.getParams();
445        boolean functionalMethod = false;
446        boolean emitUnambiguous = false;
447
448        for (Param p : params) {
449            debug("iterating params looking for self : param = ", p);
450            if (p.getName().getText() == "self")
451                functionalMethod = true;
452        }
453
454        Option<com.sun.fortress.nodes.Type> returnType = header.getReturnType();
455
456        // For now every Fortress entity is made public, with
457        // namespace management happening in Fortress-land.  Right?
458        int modifiers = Opcodes.ACC_PUBLIC;
459
460        if ( body.isNone() )
461            sayWhat(x, "Abstract function declarations are not supported.");
462        if ( returnType.isNone() )
463            sayWhat(x, "Return type is not inferred.");
464        if ( !( name instanceof IdOrOp ))
465            sayWhat(x, "Unhandled function name.");
466
467        String nameString = ((IdOrOp)name).getText();
468        if ( name instanceof Id ) {
469            Id id = (Id) name;
470            debug("forId ", id,
471                  " class = ", Naming.getJavaClassForSymbol(id));
472        } else if ( name instanceof Op ) {
473            Op op = (Op) name;
474            Fixity fixity = op.getFixity();
475            boolean isEnclosing = op.isEnclosing();
476            Option<APIName> maybe_apiName = op.getApiName();
477            debug("forOp ", op, " fixity = ", fixity,
478                  " isEnclosing = ", isEnclosing,
479                  " class = ", Naming.getJavaClassForSymbol(op));
480        } else {
481            sayWhat(x);
482        }
483
484        CodeGen cg = new CodeGen(this);
485        cg.localsDepth = 0;
486
487        if (!functionalMethod && (inAnObject || inATrait)) {
488            // TODO: Add proper type information here based on the
489            // enclosing trait/object decl.  For now we can get away
490            // with just stashing a null as we're not using it to
491            // determine stack sizing or anything similarly crucial.
492            cg.addLocalVar(new VarCodeGen.SelfVar(NodeUtil.getSpan(name), null));
493        } else if (!nameString.equals("run")) {
494            // Top-level function or functional method
495           
496            // I'm a little puzzled about how else "run" might be called,
497            // if it is not static.  (DRC)
498            modifiers += Opcodes.ACC_STATIC;
499        }
500
501        String mname = NamingCzar.mangleIdentifier(nameString);
502        String sig = Naming.emitFnDeclDesc(NodeUtil.getParamType(x),
503                returnType.unwrap());
504       
505        if (overloadedNamesAndSigs.contains(mname+sig)) {
506            mname = NamingCzar.only.mangleAwayFromOverload(mname);
507        }
508       
509        cg.mv = cw.visitMethod(modifiers,
510                               mname,
511                               sig,
512                               null, null);
513
514        // Now inside method body.  Generate code for the method body.
515        for (Param p : params) {
516            VarCodeGen v = cg.addParam(p);
517            // v.pushValue(cg.mv);
518        }
519        body.unwrap().accept(cg);
520
521        // Method body is complete except for returning final result if any.
522        // TODO: Fancy footwork here later on if we need to return a non-pointer;
523        // for now every fortress functional returns a single pointer result.
524        cg.mv.visitInsn(Opcodes.ARETURN);
525        cg.mv.visitMaxs(NamingCzar.ignore,NamingCzar.ignore);
526        cg.mv.visitEnd();
527        // Method body complete, cg now invalid.
528       
529        // Check to see if a wrapper is needed.
530        if (topLevelOverloads.containsKey(name)) {
531           
532        }
533       
534        Option<IdOrOp> iun = x.getImplementsUnambiguousName();
535       
536        if (iun.isSome()) {
537           
538        }
539    }
540
541
542    // Setting up the alias table which we will refer to at runtime.
543    public void forFnRef(FnRef x) {
544        debug("forFnRef ", x);
545        String name = x.getOriginalName().getText();
546        Option<com.sun.fortress.nodes.Type> type = x.getInfo().getExprType();
547        if ( type.isNone() ) {
548            sayWhat( x, "The type of this expression is not inferred." );
549        }
550        /* Arrow, or perhaps an intersection if it is an overloaded function. */
551        com.sun.fortress.nodes.Type arrow = type.unwrap();
552
553        List<IdOrOp> names = x.getNames();
554
555        /* Note that after pre-processing in the overload rewriter, there is
556         * only one name here; this is not an overload check.
557         */
558        if ( names.size() == 1) {
559            IdOrOp fnName = names.get(0);
560            Option<APIName> apiName = fnName.getApiName();
561            if (apiName.isSome() && ForeignJava.only.definesApi(apiName.unwrap())) {
562
563                if ( aliasTable.containsKey(name) ) {
564                    String n = aliasTable.get(name);
565                    // Cheating by assuming class is everything before the dot.
566                    int lastDot = n.lastIndexOf(".");
567                    String calleePackageAndClass = n.substring(0, lastDot).replace(".", "/");
568                    String _method = n.substring(lastDot+1);
569
570
571                   callStaticSingleOrOverloaded(x, arrow, calleePackageAndClass, _method);
572                } else {
573                 sayWhat(x, "Should be a foreign function in Alias table");
574                }
575
576            } else {
577                // NOT Foreign
578
579                // deal with in component, or in imported api.
580                String calleePackageAndClass = apiName.isSome() ?
581                        NamingCzar.fortressPackage + "/" + apiName.unwrap().getText()
582                        : packageAndClassName;
583                String _method = fnName.getText();
584
585                callStaticSingleOrOverloaded(x, arrow, calleePackageAndClass, _method);
586
587
588            }
589        } else {
590//             sayWhat(x, "Expected to see only one name here");
591//         }
592//     }
593        }
594    }
595
596    public void forIf(If x) {
597        Debug.debug( Debug.Type.CODEGEN, 1,"forIf " + x);
598        List<IfClause> clauses = x.getClauses();
599        Option<Block> elseClause = x.getElseClause();
600        if (clauses.size() > 1) throw new CompilerError(NodeUtil.getSpan(x), "Don't know how to compile multiple if clauses yet");
601
602        org.objectweb.asm.Label action = new org.objectweb.asm.Label();
603        org.objectweb.asm.Label done = new org.objectweb.asm.Label();
604        IfClause ifclause = clauses.get(0);
605        GeneratorClause cond = ifclause.getTestClause();
606
607        if (!cond.getBind().isEmpty())
608            sayWhat(x, "Undesugared generalized if expression.");
609
610        Expr testExpr = cond.getInit();
611        debug( "about to accept " + testExpr + " of class " + testExpr.getClass());
612        testExpr.accept(this);
613        addLineNumberInfo(x);
614        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, NamingCzar.internalFortressBoolean, "getValue",
615                           NamingCzar.makeMethodDesc("", NamingCzar.descBoolean));
616
617        mv.visitJumpInsn(Opcodes.IFNE, action);
618        Option<Block> maybe_else = x.getElseClause();
619        if (maybe_else.isSome()) {
620            maybe_else.unwrap().accept(this);
621        }
622        mv.visitJumpInsn(Opcodes.GOTO, done);
623        mv.visitLabel(action);
624        ifclause.getBody().accept(this);
625        mv.visitLabel(done);
626    }
627
628    public void forImportNames(ImportNames x) {
629        debug("forImportNames", x);
630        Option<String> foreign = x.getForeignLanguage();
631        if ( !foreign.isSome() ) return;
632        if ( !foreign.unwrap().equals("java") ) {
633            sayWhat(x, "Unrecognized foreign import type (only recognize java): "+
634                       foreign.unwrap());
635            return;
636        }
637        String apiName = x.getApiName().getText();
638        for ( AliasedSimpleName n : x.getAliasedNames() ) {
639            Option<IdOrOpOrAnonymousName> aliasId = n.getAlias();
640            if (!(aliasId.isSome())) continue;
641            debug("forImportNames ", x,
642                  " aliasing ", NodeUtil.nameString(aliasId.unwrap()),
643                  " to ", NodeUtil.nameString(n.getName()));
644            aliasTable.put(NodeUtil.nameString(aliasId.unwrap()),
645                           apiName + "." + NodeUtil.nameString(n.getName()));
646        }
647    }
648
649    public void forIntLiteralExpr(IntLiteralExpr x) {
650        debug("forIntLiteral ", x);
651        BigInteger bi = x.getIntVal();
652        // This might not work.
653        int l = bi.bitLength();
654        if (l < 32) {
655            int y = bi.intValue();
656            addLineNumberInfo(x);
657            pushInteger(y);
658            addLineNumberInfo(x);
659
660            mv.visitMethodInsn(Opcodes.INVOKESTATIC,
661                    NamingCzar.internalFortressZZ32, NamingCzar.make,
662                    NamingCzar.makeMethodDesc(NamingCzar.descInt,
663                                              NamingCzar.descFortressZZ32));
664        } else if (l < 64) {
665            long yy = bi.longValue();
666            addLineNumberInfo(x);
667            mv.visitLdcInsn(yy);
668            addLineNumberInfo(x);
669            mv.visitMethodInsn(Opcodes.INVOKESTATIC,
670                    NamingCzar.internalFortressZZ64, NamingCzar.make,
671                    NamingCzar.makeMethodDesc(NamingCzar.descLong,
672                                              NamingCzar.descFortressZZ64));
673        }
674    }
675
676    public void forObjectDecl(ObjectDecl x) {
677        debug("forObjectDecl", x);
678        TraitTypeHeader header = x.getHeader();
679        List<TraitTypeWhere> extendsC = header.getExtendsClause();
680        boolean canCompile =
681            x.getParams().isNone() &&             // no parameters
682            header.getStaticParams().isEmpty() && // no static parameter
683            header.getWhereClause().isNone() &&   // no where clause
684            header.getThrowsClause().isNone() &&  // no throws clause
685            header.getContract().isNone() &&      // no contract
686            //            header.getDecls().isEmpty() &&        // no members
687            header.getMods().isEmpty()         && // no modifiers
688            ( extendsC.size() <= 1 ); // 0 or 1 super trait
689        if ( !canCompile ) sayWhat(x);
690        inAnObject = true;
691        String [] superInterfaces = NamingCzar.extendsClauseToInterfaces(extendsC);
692
693        if (!header.getDecls().isEmpty()) {
694            debug("header.getDecls:", header.getDecls());
695
696            cw.visitField(Opcodes.ACC_STATIC + Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL,
697                          "default_args",
698                          "LCompilerSystem$args;",
699                          null,
700                          null);
701
702            mv = cw.visitMethod(Opcodes.ACC_STATIC,
703                                "<clinit>",
704                                "()V",
705                                null,
706                                null);
707
708            mv.visitTypeInsn(Opcodes.NEW, "CompilerSystem$args");
709            mv.visitInsn(Opcodes.DUP);
710            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "CompilerSystem$args", "<init>", NamingCzar.voidToVoid);
711            mv.visitFieldInsn(Opcodes.PUTSTATIC, "CompilerSystem", "default_args", "LCompilerSystem$args;");
712            mv.visitInsn(Opcodes.RETURN);
713            mv.visitMaxs(NamingCzar.ignore, NamingCzar.ignore);
714            mv.visitEnd();
715        }
716
717        String classFile = Naming.makeClassName(packageAndClassName, x);
718        ClassWriter prev = cw;
719        cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
720        cw.visitSource(classFile, null);
721        // Until we resolve the directory hierarchy problem.
722        //            cw.visit( Opcodes.V1_5, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER+ Opcodes.ACC_FINAL,
723        //                      classFile, null, NamingCzar.internalObject, new String[] { parent });
724        cw.visit( Opcodes.V1_5, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER+ Opcodes.ACC_FINAL,
725                  classFile, null, NamingCzar.internalObject, superInterfaces);
726
727        generateInitMethod();
728
729        for (Decl d : header.getDecls()) {
730            d.accept(this);
731            // If we have a singleton object we can create a default_xxx accessor for it.
732            if (d instanceof ObjectDecl) {
733            }
734        }
735        dumpClass( classFile );
736        cw = prev;
737        inAnObject = false;
738    }
739
740    public void forOpExpr(OpExpr x) {
741        debug("forOpExpr ", x, " op = ", x.getOp(),
742                     " of class ", x.getOp().getClass(),  " args = ", x.getArgs());
743        FunctionalRef op = x.getOp();
744
745        List<Expr> args = x.getArgs();
746        for (Expr arg : args) {
747            arg.accept(this);
748        }
749        op.accept(this);
750    }
751
752    public void forOpRef(OpRef x) {
753        debug("forOpRef " + x );
754        ExprInfo info = x.getInfo();
755        Option<com.sun.fortress.nodes.Type> exprType = info.getExprType();
756        List<StaticArg> staticArgs = x.getStaticArgs();
757        int lexicalDepth = x.getLexicalDepth();
758        IdOrOp originalName = x.getOriginalName();
759        List<IdOrOp> names = x.getNames();
760        Option<List<FunctionalRef>> overloadings = x.getOverloadings();
761        Option<com.sun.fortress.nodes.Type> overloadingType = x.getOverloadingType();
762        debug("forOpRef ", x,
763                     " info = ", info, "staticArgs = ", staticArgs, " exprType = ", exprType,
764                     " lexicalDepth = ", lexicalDepth, " originalName = ", originalName,
765                     " overloadings = ", overloadings,
766                     " overloadingType = ", overloadingType, " names = ", names);
767
768        boolean canCompile =
769            x.getStaticArgs().isEmpty() &&
770            x.getOverloadings().isNone() &&
771            names.size() == 1;
772
773        if (canCompile) {
774            String name = NamingCzar.mangleIdentifier(originalName.getText());
775            IdOrOp newName = names.get(0);
776            Option<APIName> api = newName.getApiName();
777
778            addLineNumberInfo(x);
779
780            if (api.isSome()) {
781                APIName apiName = api.unwrap();
782                debug("forOpRef name = ", name,
783                             " api = ", apiName);
784                if (exprType.isSome())
785                    mv.visitMethodInsn(Opcodes.INVOKESTATIC, Naming.getJavaClassForSymbol(newName),
786                                       NamingCzar.mangleIdentifier(newName.getText()),
787                                       Naming.emitDesc(exprType.unwrap()));
788                else
789                    mv.visitMethodInsn(Opcodes.INVOKESTATIC,
790                                       NamingCzar.fortressPackage + "/" + api.unwrap().getText(),
791                                       NamingCzar.mangleIdentifier(newName.getText()),
792                                       symbols.getTypeSignatureForIdOrOp(newName, component));
793
794            } else {
795                if (exprType.isSome())
796                    mv.visitMethodInsn(Opcodes.INVOKESTATIC, packageAndClassName, NamingCzar.mangleIdentifier(name),
797                                       Naming.emitDesc(exprType.unwrap()));
798                else
799                    mv.visitMethodInsn(Opcodes.INVOKESTATIC, packageAndClassName,
800                                       NamingCzar.mangleIdentifier(name), symbols.getTypeSignatureForIdOrOp(newName, component));
801            }
802        } else
803            debug("forOpRef can't compile staticArgs ",
804                        x.getStaticArgs().isEmpty(), " overloadings ",
805                        x.getOverloadings().isNone());
806
807    }
808
809    public void forStringLiteralExpr(StringLiteralExpr x) {
810        // This is cheating, but the best we can do for now.
811        // We make a FString and push it on the stack.
812        debug("forStringLiteral ", x);
813        addLineNumberInfo(x);
814        mv.visitLdcInsn(x.getText());
815        addLineNumberInfo(x);
816        mv.visitMethodInsn(Opcodes.INVOKESTATIC, NamingCzar.internalFortressString, NamingCzar.make,
817                           NamingCzar.makeMethodDesc(NamingCzar.descString, NamingCzar.descFortressString));
818    }
819
820    public void forSubscriptExpr(SubscriptExpr x) {
821        debug("forSubscriptExpr ", x);
822        Expr obj = x.getObj();
823        List<Expr> subs = x.getSubs();
824        Option<Op> maybe_op = x.getOp();
825        List<StaticArg> staticArgs = x.getStaticArgs();
826        boolean canCompile = staticArgs.isEmpty() && maybe_op.isSome() && (obj instanceof VarRef);
827        if (!canCompile) { sayWhat(x); return; }
828        Op op = maybe_op.unwrap();
829        VarRef var = (VarRef) obj;
830        Id id = var.getVarId();
831
832        debug("ForSubscriptExpr  ", x, "obj = ", obj,
833              " subs = ", subs, " op = ", op, " static args = ", staticArgs,
834              " varRef = ", id.getText());
835
836        addLineNumberInfo(x);
837        mv.visitFieldInsn(Opcodes.GETSTATIC, Naming.getJavaClassForSymbol(id) , "default_" + id.getText(),
838                          "L" + Naming.getJavaClassForSymbol(id) + "$" + id.getText() + ";");
839
840
841
842        for (Expr e : subs) {
843            debug("calling accept on ", e);
844            e.accept(this);
845        }
846        addLineNumberInfo(x);
847        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
848                           Naming.getJavaClassForSymbol(id) + "$" + id.getText(),
849                           NamingCzar.mangleIdentifier(op.getText()),
850                           "(Lcom/sun/fortress/compiler/runtimeValues/FZZ32;)Lcom/sun/fortress/compiler/runtimeValues/FString;");
851    }
852
853    public void forTraitDecl(TraitDecl x) {
854        debug("forTraitDecl", x);
855        TraitTypeHeader header = x.getHeader();
856        List<TraitTypeWhere> extendsC = header.getExtendsClause();
857        boolean canCompile =
858            // NOTE: Presence of excludes or comprises clauses should not
859            // affect code generation once type checking is complete.
860            // x.getExcludesClause().isEmpty() &&    // no excludes clause
861            header.getStaticParams().isEmpty() && // no static parameter
862            header.getWhereClause().isNone() &&   // no where clause
863            header.getThrowsClause().isNone() &&  // no throws clause
864            header.getContract().isNone() &&      // no contract
865            header.getMods().isEmpty() && // no modifiers
866            extendsC.size() <= 1;
867        debug("forTraitDecl", x,
868                    " decls = ", header.getDecls(), " extends = ", extendsC);
869        if ( !canCompile ) sayWhat(x);
870        inATrait = true;
871        String [] superInterfaces = NamingCzar.extendsClauseToInterfaces(extendsC);
872
873        // First let's do the interface class
874        String classFile = Naming.makeClassName(packageAndClassName, x);
875        if (classFile.equals("fortress/AnyType$Any")) {
876            superInterfaces = new String[0];
877        }
878        ClassWriter prev = cw;
879        cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
880        cw.visitSource(classFile, null);
881        cw.visit( Opcodes.V1_5,
882                  Opcodes.ACC_PUBLIC + Opcodes.ACC_ABSTRACT + Opcodes.ACC_INTERFACE,
883                  classFile, null, NamingCzar.internalObject, superInterfaces);
884        dumpSigs(header.getDecls());
885        dumpClass( classFile );
886        // Now lets do the springboard inner class that implements this interface.
887        String springBoardClass = classFile + NamingCzar.springBoard;
888        cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
889        cw.visitSource(springBoardClass, null);
890        cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC, springBoardClass,
891                 null, NamingCzar.internalObject, new String[0] );
892        debug("Start writing springboard class ",
893              springBoardClass);
894        generateInitMethod();
895        debug("Finished init method ", springBoardClass);
896        dumpDecls(header.getDecls());
897        debug("Finished dumpDecls ", springBoardClass);
898        dumpClass(springBoardClass);
899        // Now lets dump out the functional methods at top level.
900        cw = prev;
901        cw.visitSource(classFile, null);
902        dumpDecls(header.getDecls());
903        debug("Finished dumpDecls for parent");
904        inATrait = false;
905    }
906
907    public void forVarRef(VarRef v) {
908        debug("forVarRef ", v, " which had better be local (for the moment)");
909        if (v.getStaticArgs().size() > 0) {
910            sayWhat(v,"varRef with static args!  That requires non-local VarRefs");
911        }
912        VarCodeGen vcg = getLocalVar(v.getVarId());
913        vcg.pushValue(mv);
914    }
915
916    public void forVoidLiteralExpr(VoidLiteralExpr x) {
917        debug("forVoidLiteral ", x);
918        addLineNumberInfo(x);
919        mv.visitMethodInsn(Opcodes.INVOKESTATIC, NamingCzar.internalFortressVoid, NamingCzar.make,
920                           NamingCzar.makeMethodDesc("", NamingCzar.descFortressVoid));
921
922    }
923
924    public void for_RewriteFnApp(_RewriteFnApp x) {
925        debug("for_RewriteFnApp ", x,
926                     " args = ", x.getArgument(), " function = ", x.getFunction());
927        // This is a little weird.  If a function takes no arguments the parser gives me a void literal expr
928        // however I don't want to be putting a void literal on the stack because it gets in the way.
929        int savedParamCount = paramCount;
930        try {
931            Expr arg = x.getArgument();
932            if (arg instanceof VoidLiteralExpr) {
933                paramCount = 0;
934            } else if (arg instanceof TupleExpr) {
935                TupleExpr targ = (TupleExpr) arg;
936                List<Expr> exprs = targ.getExprs();
937                for (Expr expr : exprs) {
938                    expr.accept(this);
939                }
940                paramCount = exprs.size();
941            } else {
942                paramCount = 1; // for now; need to dissect tuple and do more.
943                arg.accept(this);
944            }
945            x.getFunction().accept(this);
946        } finally {
947            paramCount = savedParamCount;
948        }
949    }
950
951    public void for_RewriteFnOverloadDecl(_RewriteFnOverloadDecl x) {
952        /* Note for refactoring -- this code does it the "right" way.
953         * And also, this code NEEDS refactoring.
954         */
955        List<IdOrOp> fns = x.getFns();
956        IdOrOp name = x.getName();
957        Option<com.sun.fortress.nodes.Type> ot = x.getType();
958        Relation<IdOrOpOrAnonymousName, Function> fnrl = ci.functions();
959
960        MultiMap<Integer, OverloadSet.TaggedFunctionName> byCount =
961            new MultiMap<Integer,OverloadSet.TaggedFunctionName>();
962
963        for (IdOrOp fn : fns) {
964
965            Option<APIName> fnapi = fn.getApiName();
966            PredicateSet<Function> set_of_f;
967            APIName apiname;
968
969            if (fnapi.isNone()) {
970                apiname = ci.ast().getName();
971                set_of_f = fnrl.matchFirst(fn);
972            } else {
973                apiname = fnapi.unwrap();
974                ApiIndex ai = symbols.apis.get(apiname);
975                IdOrOp fnnoapi = NodeFactory.makeLocalIdOrOp(fn);
976                set_of_f = ai.functions().matchFirst(fnnoapi);
977            }
978
979            for (Function f : set_of_f) {
980                OverloadSet.TaggedFunctionName tagged_f = new OverloadSet.TaggedFunctionName(apiname, f);
981                byCount.putItem(f.parameters().size(), tagged_f);
982            }
983
984            for (Map.Entry<Integer, Set<OverloadSet.TaggedFunctionName>> entry : byCount
985                    .entrySet()) {
986                int i = entry.getKey();
987                Set<OverloadSet.TaggedFunctionName> fs = entry.getValue();
988                if (fs.size() > 1) {
989                    OverloadSet os = new OverloadSet.AmongApis(name,
990                            ta, fs, i);
991
992                    os.split(false);
993                    os.generateAnOverloadDefinition(name.stringName(), cw);
994
995                }
996            }
997        }
998    }
999
1000   
1001    /**
1002     * Creates overloaded functions for any overloads present at the top level
1003     * of this component.  Top level overloads are those that might be exported;
1004     * Reference overloads are rewritten into _RewriteFnOverloadDecl nodes
1005     * and generated in the normal visits.
1006     */
1007    private void generateTopLevelOverloads() {
1008               
1009        for (Map.Entry<IdOrOpOrAnonymousName, MultiMap<Integer, Function>> entry1 : topLevelOverloads.entrySet()) {
1010            IdOrOpOrAnonymousName  name = entry1.getKey();
1011            MultiMap<Integer, Function> partitionedByArgCount = entry1.getValue();
1012           
1013            for (Map.Entry<Integer, Set<Function>> entry : partitionedByArgCount
1014                    .entrySet()) {
1015               int i = entry.getKey();
1016               Set<Function> fs = entry.getValue();
1017
1018               OverloadSet os =
1019                   new OverloadSet.Local(ci.ast().getName(), name,
1020                                         ta, fs, i);
1021
1022               os.split(true);
1023               
1024               String s = name.stringName();
1025               
1026               os.generateAnOverloadDefinition(s, cw);
1027               
1028               for (Map.Entry<String, OverloadSet> o_entry : os.getOverloadSubsets().entrySet()) {
1029                   String ss = o_entry.getKey();
1030                   ss = s + ss;
1031                   overloadedNamesAndSigs.add(ss);
1032               }
1033           }
1034        }
1035    }
1036
1037    Map<IdOrOpOrAnonymousName, MultiMap<Integer, Function>>
1038       sizePartitionedOverloads(Relation<IdOrOpOrAnonymousName, Function> fns) {
1039       
1040        Map<IdOrOpOrAnonymousName, MultiMap<Integer, Function>> result =
1041            new HashMap<IdOrOpOrAnonymousName, MultiMap<Integer, Function>>();
1042       
1043        for (IdOrOpOrAnonymousName name : fns.firstSet()) {
1044            Set<Function> defs = fns.matchFirst(name);
1045            if (defs.size() <= 1) continue;
1046
1047            MultiMap<Integer, Function> partitionedByArgCount =
1048                new MultiMap<Integer, Function>();
1049
1050            for (Function d : defs) {
1051                partitionedByArgCount.putItem(d.parameters().size(), d);
1052            }
1053           
1054            for (Function d : defs) {
1055                Set<Function> sf = partitionedByArgCount.get(d.parameters().size());
1056                if (sf != null && sf.size() <= 1)
1057                    partitionedByArgCount.remove(d.parameters().size());
1058            }
1059            if (partitionedByArgCount.size() > 0)
1060                result.put(name, partitionedByArgCount);
1061        }
1062       
1063        return result;
1064    }
1065
1066
1067
1068    private void dumpSigs(List<Decl> decls) {
1069        debug("dumpSigs", decls);
1070        for (Decl d : decls) {
1071            debug("dumpSigs decl =", d);
1072            if (!(d instanceof FnDecl)) {
1073                sayWhat(d);
1074                return;
1075            }
1076
1077            FnDecl f = (FnDecl) d;
1078            FnHeader h = f.getHeader();
1079            IdOrOpOrAnonymousName xname = h.getName();
1080            IdOrOp name = (IdOrOp) xname;
1081            String desc = Naming.generateTypeDescriptor(f);
1082            debug("about to call visitMethod with", name.getText(),
1083                  " and desc ", desc);
1084            mv = cw.visitMethod(Opcodes.ACC_ABSTRACT + Opcodes.ACC_PUBLIC,
1085                                NamingCzar.mangleIdentifier(name.getText()), desc, null, null);
1086            mv.visitMaxs(NamingCzar.ignore, NamingCzar.ignore);
1087            mv.visitEnd();
1088        }
1089    }
1090}
Note: See TracBrowser for help on using the browser.