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

Revision 3850, 42.1 KB (checked in by dr2chase, 5 months ago)

Partial work on using unambiguousnames -- pre-codegen reorg

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