001    /* Copyright (c) 2005-2008, Torbjorn Ekman
002     *                    2013, Jesper Öqvist <jesper.oqvist@cs.lth.se>
003     * All rights reserved.
004     *
005     * Redistribution and use in source and binary forms, with or without
006     * modification, are permitted provided that the following conditions are met:
007     *
008     * 1. Redistributions of source code must retain the above copyright notice,
009     * this list of conditions and the following disclaimer.
010     *
011     * 2. Redistributions in binary form must reproduce the above copyright notice,
012     * this list of conditions and the following disclaimer in the documentation
013     * and/or other materials provided with the distribution.
014     *
015     * 3. Neither the name of the copyright holder nor the names of its
016     * contributors may be used to endorse or promote products derived from this
017     * software without specific prior written permission.
018     *
019     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
020     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
021     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
022     * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
023     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
024     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
025     * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
026     * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
027     * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
028     * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
029     * POSSIBILITY OF SUCH DAMAGE.
030     */
031    
032    import java.util.*;
033    import java.io.*;
034    
035    aspect CreateBCode {
036    
037      inh TypeDecl CatchClause.hostType();
038    
039      public abstract void CatchClause.exceptionTableEntries(CodeGeneration gen, int begin_lbl, int end_lbl);
040    
041      public void BasicCatch.exceptionTableEntries(CodeGeneration gen, int begin_lbl, int end_lbl) {
042        gen.addException(
043          begin_lbl,
044          end_lbl,
045          label(),
046          gen.constantPool().addClass(getParameter().type().constantPoolName())
047        );
048      }
049    
050      syn lazy boolean TypeDecl.hasClinit() {
051        for (int i = 0; i < getNumBodyDecl(); i++) {
052          BodyDecl b = getBodyDecl(i);
053          if (b instanceof FieldDeclaration) {
054            FieldDeclaration f = (FieldDeclaration) b;
055            if (f.isStatic() && f.hasInit()) {
056              return true;
057            }
058          } else if (b instanceof StaticInitializer) {
059            return true;
060          }
061        }
062        return false;
063      }
064    
065      syn lazy CodeGeneration TypeDecl.bytecodes(ConstantPool constantPool) {
066        CodeGeneration gen = new CodeGeneration(constantPool);
067        generateBytecodes(gen);
068        if (!gen.numberFormatError()) {
069          return gen;
070        }
071        gen = new CodeGeneration(constantPool, true);
072        generateBytecodes(gen);
073        if (!gen.numberFormatError()) {
074          return gen;
075        }
076        throw new Error("Could not generate code for initializers in " + hostType().typeName());
077      }
078    
079      private void TypeDecl.generateBytecodes(CodeGeneration gen) {
080        for (int i = 0; i < getNumBodyDecl(); i++) {
081          BodyDecl b = getBodyDecl(i);
082          if (b instanceof FieldDeclaration && b.isBytecodeField()) {
083            FieldDeclaration f = (FieldDeclaration) b;
084            f.emitStaticInitializer(gen, this);
085          } else if (b instanceof StaticInitializer) {
086            b.createBCode(gen);
087          }
088        }
089        gen.emitReturn();
090      }
091    
092      syn lazy CodeGeneration MethodDecl.bytecodes(ConstantPool constantPool) {
093        CodeGeneration gen = new CodeGeneration(constantPool);
094        generateBytecodes(gen);
095        if (!gen.numberFormatError()) {
096          return gen;
097        }
098        gen = new CodeGeneration(constantPool, true);
099        generateBytecodes(gen);
100        if (!gen.numberFormatError()) {
101          return gen;
102        }
103        throw new Error("Could not generate code for " + signature() + " in " + hostType().typeName());
104      }
105    
106      private void MethodDecl.generateBytecodes(CodeGeneration gen) {
107        int label = gen.variableScopeLabel();
108        int paramLength = 0;
109        if (!isStatic()) {
110          paramLength += 1;
111          gen.addLocalVariableEntryAtCurrentPC("this", hostType().typeDescriptor(), 0, label);
112        }
113        for (ParameterDeclaration p: getParameterList()) {
114          paramLength += p.type().variableSize();
115          if (paramLength > 255) {
116            throw new Error("parameter list too large");
117          }
118          gen.addLocalVariableEntryAtCurrentPC(
119            p.name(), p.type().typeDescriptor(), p.localNum(), label
120          );
121        }
122        createBCode(gen);
123        if (type() instanceof VoidType) // TODO: canCompleteNormally check as well
124          gen.emitReturn();
125        gen.addVariableScopeLabel(label);
126      }
127    
128      syn lazy CodeGeneration ConstructorDecl.bytecodes(ConstantPool constantPool) {
129        CodeGeneration gen = new CodeGeneration(constantPool);
130        generateBytecodes(gen);
131        if (!gen.numberFormatError()) {
132          return gen;
133        }
134        gen = new CodeGeneration(constantPool, true);
135        generateBytecodes(gen);
136        if (!gen.numberFormatError()) {
137          return gen;
138        }
139        throw new Error("Could not generate code for " + signature() + " in " + hostType().typeName());
140      }
141    
142      private void ConstructorDecl.generateBytecodes(CodeGeneration gen) {
143        int label = gen.variableScopeLabel();
144        int paramLength = 1;
145        gen.addLocalVariableEntryAtCurrentPC("this", hostType().typeDescriptor(), 0, label);
146        for (ParameterDeclaration p: getParameterList()) {
147          paramLength += p.type().variableSize();
148          if (paramLength > 255) {
149            throw new Error("parameter list too large");
150          }
151          gen.addLocalVariableEntryAtCurrentPC(
152            p.name(), p.type().typeDescriptor(), p.localNum(), label
153          );
154        }
155        createBCode(gen);
156        gen.emitReturn();
157        gen.addVariableScopeLabel(label);
158      }
159    
160      public void MethodDecl.createBCode(CodeGeneration gen) {
161        try {
162          if (hasBlock()) {
163            gen.maxLocals = Math.max(gen.maxLocals, getBlock().localNum());
164            getBlock().createBCode(gen);
165          }
166        } catch (Error e) {
167          System.err.println(hostType().typeName() + ": " + this);
168          throw e;
169        }
170      }
171    
172      public void ConstructorDecl.createBCode(CodeGeneration gen) {
173        try {
174        boolean needsInit = true;
175    
176        if (hasConstructorInvocation()) {
177          getConstructorInvocation().createBCode(gen);
178          Stmt stmt = getConstructorInvocation();
179          if (stmt instanceof ExprStmt) {
180            ExprStmt exprStmt = (ExprStmt) stmt;
181            Expr expr = exprStmt.getExpr();
182            if (!expr.isSuperConstructorAccess()) {
183              needsInit = false;
184            }
185    
186          }
187        }
188    
189        if (needsEnclosing()) {
190          gen.emitLoadReference(0);
191          gen.emitLoadReference(1);
192          String classname = hostType().constantPoolName();
193          String desc = enclosing().typeDescriptor();
194          String name = "this$0";
195          int index = gen.constantPool().addFieldref(classname, name, desc);
196          gen.emit(Bytecode.PUTFIELD, -2).add2(index);
197        }
198    
199        int localIndex = offsetFirstEnclosingVariable();
200        for (Iterator iter = hostType().enclosingVariables().iterator(); iter.hasNext(); ) {
201            Variable v = (Variable) iter.next();
202            gen.emitLoadReference(0);
203            v.type().emitLoadLocal(gen, localIndex);
204            String classname = hostType().constantPoolName();
205            String desc = v.type().typeDescriptor();
206            String name = "val$" + v.name();
207            int index = gen.constantPool().addFieldref(classname, name, desc);
208            gen.emit(Bytecode.PUTFIELD, -1 - v.type().variableSize()).add2(index);
209            localIndex += v.type().variableSize();
210        }
211    
212        if (needsInit) {
213          TypeDecl typeDecl = hostType();
214          for (int i = 0; i < typeDecl.getNumBodyDecl(); i++) {
215            BodyDecl b = typeDecl.getBodyDecl(i);
216            if (b instanceof FieldDeclaration && b.isBytecodeField()) {
217              FieldDeclaration f = (FieldDeclaration) b;
218              f.emitInstanceInitializer(gen, hostType());
219            } else if (b instanceof InstanceInitializer) {
220              b.createBCode(gen);
221            }
222          }
223        }
224        gen.maxLocals = Math.max(gen.maxLocals, getBlock().localNum());
225        getBlock().createBCode(gen);
226        } catch (Error e) {
227          System.err.println(hostType().typeName() + ": " + this);
228          throw e;
229        }
230      }
231    
232      public void ASTNode.createBCode(CodeGeneration gen) {
233        for (int i=0; i<getNumChild(); i++) {
234          getChild(i).createBCode(gen);
235        }
236      }
237    
238      public void Literal.createBCode(CodeGeneration gen) {
239        emitPushConstant(gen);
240      }
241    
242      protected boolean Expr.needsPush() {
243        ASTNode n = getParent();
244        while (n instanceof ParExpr) {
245          n = n.getParent();
246        }
247        return !(n instanceof ExprStmt);
248      }
249    
250      syn boolean ExprStmt.needsPop() = getExpr().needsPop();
251      syn boolean Expr.needsPop() = true;
252      eq AbstractDot.needsPop() = lastAccess().needsPop();
253      eq ConstructorAccess.needsPop() = false;
254    
255      eq ParExpr.needsPop() = getExpr().needsPop();
256      //eq AssignExpr.needsPop() = false; // if dest is instance variable that needs accessor
257      eq AssignExpr.needsPop() = getDest().isVarAccessWithAccessor();
258      eq PreIncExpr.needsPop() = false;
259      eq PostIncExpr.needsPop() = getOperand().isVarAccessWithAccessor();
260      eq PreDecExpr.needsPop() = false;
261      eq PostDecExpr.needsPop() = getOperand().isVarAccessWithAccessor();
262    
263      syn boolean Expr.isVarAccessWithAccessor() = false;
264      eq ParExpr.isVarAccessWithAccessor() = getExpr().isVarAccessWithAccessor();
265      eq AbstractDot.isVarAccessWithAccessor() = lastAccess().isVarAccessWithAccessor();
266      eq VarAccess.isVarAccessWithAccessor() = decl() instanceof FieldDeclaration &&
267            decl().isInstanceVariable() && requiresAccessor();
268    
269      public void VarDeclStmt.createBCode(CodeGeneration gen) {
270        gen.addLineNumberEntryAtCurrentPC(this);// generate line number entry
271        for (VariableDeclaration decl: getSingleDeclList()) {
272          decl.createBCode(gen);
273        }
274      }
275    
276      public void VariableDeclaration.createBCode(CodeGeneration gen) {
277        if (hasInit()) {
278          gen.addLocalVariableEntryAtCurrentPC(name(), type().typeDescriptor(), localNum(), variableScopeEndLabel(gen));
279          emitInitializerBCode(gen);
280          type().emitStoreLocal(gen, localNum());
281        }
282      }
283    
284      /**
285       * Generate variable initialization bytecode.
286       */
287      protected void VariableDeclaration.emitInitializerBCode(CodeGeneration gen) {
288        getInit().createBCode(gen);
289        getInit().type().emitAssignConvTo(gen, type());
290      }
291    
292      /**
293       * Generate static initialization code for the field.
294       */
295      public void FieldDeclaration.emitStaticInitializer(CodeGeneration gen, TypeDecl hostType) {
296        if (isStatic() && hasInit()) {
297          emitInitializerBCode(gen);
298          emitStoreField(gen, hostType);
299        }
300      }
301    
302      /**
303       * Generate instance initialization code for the field.
304       */
305      public void FieldDeclaration.emitInstanceInitializer(CodeGeneration gen, TypeDecl hostType) {
306        if (!isStatic() && hasInit()) {
307          gen.emit(Bytecode.ALOAD_0);
308          emitInitializerBCode(gen);
309          emitStoreField(gen, hostType);
310        }
311      }
312    
313      /**
314       * Generate field initialization bytecode.
315       */
316      protected void FieldDeclaration.emitInitializerBCode(CodeGeneration gen) {
317        getInit().createBCode(gen);
318        getInit().type().emitAssignConvTo(gen, type());
319      }
320    
321      /**
322       * Create bytecode for a simple assign expression.
323       */
324      public void AssignSimpleExpr.createBCode(CodeGeneration gen) {
325        getDest().createAssignSimpleLoadDest(gen);
326        getSource().createBCode(gen);
327        getSource().type().emitAssignConvTo(gen, getDest().type()); // AssignConversion
328        if (needsPush()) {
329          getDest().createPushAssignmentResult(gen);
330        }
331        getDest().emitStore(gen);
332      }
333    
334      /**
335       * Create bytecode for a compund assign expression.
336       */
337      public void AssignExpr.createBCode(CodeGeneration gen) {
338        TypeDecl dest = getDest().type();
339        TypeDecl source = getSource().type();
340        TypeDecl type;
341        if (dest.isNumericType() && source.isNumericType()) {
342          type = dest.binaryNumericPromotion(source);
343        } else {
344          type = dest;
345        }
346        getDest().createAssignLoadDest(gen);
347        dest.emitCastTo(gen, type);
348        getSource().createBCode(gen);
349        source.emitCastTo(gen, type);
350        createAssignOp(gen, type);
351        type.emitCastTo(gen, dest);
352        if (needsPush()) {
353          getDest().createPushAssignmentResult(gen);
354        }
355        getDest().emitStore(gen);
356      }
357    
358      // string addition assign expression
359      public void AssignPlusExpr.createBCode(CodeGeneration gen) {
360        TypeDecl dest = getDest().type();
361        TypeDecl source = getSource().type();
362        if (dest.isString()) {
363          getDest().createAssignLoadDest(gen);
364    
365          // new StringBuffer()
366          TypeDecl stringBuffer = lookupType("java.lang", "StringBuffer");
367          String classname = stringBuffer.constantPoolName();
368          String desc;
369          int index;
370          TypeDecl argumentType;
371          stringBuffer.emitNew(gen); // new StringBuffer
372          gen.emitDup();             // dup
373          desc = "()V";
374          index = gen.constantPool().addMethodref(classname, "<init>", desc);
375          gen.emit(Bytecode.INVOKESPECIAL, -1).add2(index); // invokespecial StringBuffer()
376    
377          gen.emitSwap();
378    
379          // append
380          argumentType = dest.stringPromotion();
381          desc = "(" + argumentType.typeDescriptor() + ")" + stringBuffer.typeDescriptor();
382          index = gen.constantPool().addMethodref(classname, "append", desc);
383          gen.emit(Bytecode.INVOKEVIRTUAL, -argumentType.variableSize()).add2(index); // StringBuffer.append
384    
385          getSource().createBCode(gen);
386    
387          // typed append
388          argumentType = source.stringPromotion();
389          desc = "(" + argumentType.typeDescriptor() + ")" + stringBuffer.typeDescriptor();
390          index = gen.constantPool().addMethodref(classname, "append", desc);
391          gen.emit(Bytecode.INVOKEVIRTUAL, -argumentType.variableSize()).add2(index); // StringBuffer.append
392    
393          // toString
394          desc = "()" + type().typeDescriptor();
395          index = gen.constantPool().addMethodref(classname, "toString", desc);
396          gen.emit(Bytecode.INVOKEVIRTUAL, 0).add2(index); // StringBuffer.toString
397    
398          if (needsPush()) {
399            getDest().createPushAssignmentResult(gen);
400          }
401          getDest().emitStore(gen);
402        } else {
403          super.createBCode(gen);
404        }
405      }
406    
407      // shift assign expression
408      public void AssignExpr.emitShiftExpr(CodeGeneration gen) {
409        TypeDecl dest = getDest().type();
410        TypeDecl source = getSource().type();
411        TypeDecl type = dest.unaryNumericPromotion();
412        getDest().createAssignLoadDest(gen);
413        dest.emitCastTo(gen, type);
414        getSource().createBCode(gen);
415        source.emitCastTo(gen, typeInt());
416        createAssignOp(gen, type);
417        type.emitCastTo(gen, dest);
418        if (needsPush()) {
419          getDest().createPushAssignmentResult(gen);
420        }
421        getDest().emitStore(gen);
422      }
423      public void AssignLShiftExpr.createBCode(CodeGeneration gen) { emitShiftExpr(gen); }
424      public void AssignRShiftExpr.createBCode(CodeGeneration gen) { emitShiftExpr(gen); }
425      public void AssignURShiftExpr.createBCode(CodeGeneration gen) { emitShiftExpr(gen); }
426    
427      // load left hand side of destination in a simple assign expression
428      public void Expr.createAssignSimpleLoadDest(CodeGeneration gen) {
429      }
430      public void AbstractDot.createAssignSimpleLoadDest(CodeGeneration gen) {
431        lastAccess().createAssignSimpleLoadDest(gen);
432      }
433      public void VarAccess.createAssignSimpleLoadDest(CodeGeneration gen) {
434        createLoadQualifier(gen);
435      }
436      public void ArrayAccess.createAssignSimpleLoadDest(CodeGeneration gen) {
437        prevExpr().createBCode(gen);
438        getExpr().createBCode(gen);
439      }
440    
441      /**
442       * duplicate top value on stack and store below destination element
443       */
444      public void Expr.createPushAssignmentResult(CodeGeneration gen) {
445      }
446      public void AbstractDot.createPushAssignmentResult(CodeGeneration gen) {
447        lastAccess().createPushAssignmentResult(gen);
448      }
449      public void VarAccess.createPushAssignmentResult(CodeGeneration gen) {
450        if (hostType().needsAccessorFor(decl())) {
451          return;
452        }
453        if (decl().isInstanceVariable()) {
454          type().emitDup_x1(gen);
455        } else {
456          type().emitDup(gen);
457        }
458      }
459      public void ArrayAccess.createPushAssignmentResult(CodeGeneration gen) {
460        type().emitDup_x2(gen);
461      }
462    
463      // load left hand side of destination in a compound assign expression
464      public void Expr.createAssignLoadDest(CodeGeneration gen) {
465      }
466      public void AbstractDot.createAssignLoadDest(CodeGeneration gen) {
467        lastAccess().createAssignLoadDest(gen);
468      }
469      public void VarAccess.createAssignLoadDest(CodeGeneration gen) {
470        createLoadQualifier(gen);
471        Variable v = decl();
472        if (v.isInstanceVariable()) {
473          gen.emitDup();
474        }
475        if (v instanceof VariableDeclaration) {
476          VariableDeclaration decl = (VariableDeclaration) v;
477          decl.type().emitLoadLocal(gen, decl.localNum());
478        } else if (v instanceof ParameterDeclaration) {
479          ParameterDeclaration decl = (ParameterDeclaration) v;
480          decl.type().emitLoadLocal(gen, decl.localNum());
481        } else if (v instanceof FieldDeclaration) {
482          FieldDeclaration f = (FieldDeclaration) v;
483          if (requiresAccessor()) {
484            f.createAccessor(fieldQualifierType()).emitInvokeMethod(gen, fieldQualifierType());
485          } else {
486            f.emitLoadField(gen, fieldQualifierType());
487          }
488        }
489      }
490      public void ArrayAccess.createAssignLoadDest(CodeGeneration gen) {
491        prevExpr().createBCode(gen);
492        gen.emitDup();
493        getExpr().createBCode(gen);
494        typeInt().emitDup_x1(gen);
495        gen.emit(type().arrayLoad());
496      }
497    
498      // select the typed operation for a compound assign expression
499      public void AssignExpr.createAssignOp(CodeGeneration gen, TypeDecl type) {
500        throw new Error("Operation createAssignOp is not implemented for " + getClass().getName());
501      }
502      public void AssignMulExpr.createAssignOp(CodeGeneration gen, TypeDecl type)     { type.mul(gen); }
503      public void AssignDivExpr.createAssignOp(CodeGeneration gen, TypeDecl type)     { type.div(gen); }
504      public void AssignModExpr.createAssignOp(CodeGeneration gen, TypeDecl type)     { type.rem(gen); }
505      public void AssignPlusExpr.createAssignOp(CodeGeneration gen, TypeDecl type)    { type.add(gen); }
506      public void AssignMinusExpr.createAssignOp(CodeGeneration gen, TypeDecl type)   { type.sub(gen); }
507      public void AssignLShiftExpr.createAssignOp(CodeGeneration gen, TypeDecl type)  { type.shl(gen); }
508      public void AssignRShiftExpr.createAssignOp(CodeGeneration gen, TypeDecl type)  { type.shr(gen); }
509      public void AssignURShiftExpr.createAssignOp(CodeGeneration gen, TypeDecl type) { type.ushr(gen); }
510      public void AssignAndExpr.createAssignOp(CodeGeneration gen, TypeDecl type)     { type.bitand(gen); }
511      public void AssignXorExpr.createAssignOp(CodeGeneration gen, TypeDecl type)     { type.bitxor(gen); }
512      public void AssignOrExpr.createAssignOp(CodeGeneration gen, TypeDecl type)      { type.bitor(gen); }
513    
514      public void AbstractDot.createBCode(CodeGeneration gen) {
515        lastAccess().createBCode(gen);
516      }
517    
518      public void VarAccess.createBCode(CodeGeneration gen) {
519        Variable v = decl();
520        if (v instanceof VariableDeclaration) {
521          VariableDeclaration decl = (VariableDeclaration) v;
522          if (decl.hostType() == hostType()) {
523            decl.type().emitLoadLocal(gen, decl.localNum());
524          } else {
525            emitLoadLocalInNestedClass(gen, decl);
526          }
527        } else if (v instanceof ParameterDeclaration) {
528          ParameterDeclaration decl = (ParameterDeclaration) v;
529          if (decl.hostType() == hostType()) {
530            decl.type().emitLoadLocal(gen, decl.localNum());
531          } else {
532            emitLoadLocalInNestedClass(gen, decl);
533          }
534        } else if (v instanceof FieldDeclaration) {
535          FieldDeclaration f = (FieldDeclaration) v;
536          createLoadQualifier(gen);
537          if (f.isConstant() && (f.type().isPrimitive() || f.type().isString())) {
538            if (!f.isStatic()) {
539              fieldQualifierType().emitPop(gen);
540            }
541            f.constant().createBCode(gen);
542          } else if (requiresAccessor()) {
543            f.createAccessor(fieldQualifierType()).emitInvokeMethod(gen, fieldQualifierType());
544          } else {
545            f.emitLoadField(gen, fieldQualifierType());
546          }
547        }
548      }
549    
550      syn boolean TypeDecl.needsAccessorFor(Variable v) {
551        if (!(v instanceof FieldDeclaration)) {
552          return false;
553        }
554        FieldDeclaration f = (FieldDeclaration) v;
555        if (f.isConstant() && (f.type().isPrimitive() || f.type().isString())) {
556          return false;
557        }
558        return f.isPrivate() && !hasField(v.name());
559      }
560    
561      inh boolean Access.inExplicitConstructorInvocation();
562      public void Access.emitLoadLocalInNestedClass(CodeGeneration gen, Variable v) {
563        if (inExplicitConstructorInvocation() && enclosingBodyDecl() instanceof ConstructorDecl) {
564          ConstructorDecl c = (ConstructorDecl) enclosingBodyDecl();
565          v.type().emitLoadLocal(gen, c.localIndexOfEnclosingVariable(v));
566        } else {
567          String classname = hostType().constantPoolName();
568          String      desc = v.type().typeDescriptor();
569          String      name = "val$" + v.name();
570          int index = gen.constantPool().addFieldref(classname, name, desc);
571          gen.emit(Bytecode.ALOAD_0);
572          gen.emit(Bytecode.GETFIELD, v.type().variableSize() - 1).add2(index);
573        }
574      }
575    
576      protected void VarAccess.createLoadQualifier(CodeGeneration gen) {
577        Variable v = decl();
578        if (v instanceof FieldDeclaration) {
579          FieldDeclaration f = (FieldDeclaration) v;
580          if (hasPrevExpr()) {
581            // load explicit qualifier
582            prevExpr().createBCode(gen);
583            // pop qualifier stack element for class variables
584            // this qualifier must be computed to ensure side effects
585            if (!prevExpr().isTypeAccess() && f.isClassVariable()) {
586              prevExpr().type().emitPop(gen);
587            }
588          } else if (f.isInstanceVariable()) {
589            emitThis(gen, fieldQualifierType());
590          }
591        }
592      }
593    
594      public void MethodAccess.createBCode(CodeGeneration gen) {
595        createLoadQualifier(gen);
596    
597        if (program().options().hasOption("-debug")) {
598          if (decl().type().isUnknown()) {
599            System.err.println("Could not bind " + this);
600            for (int i = 0; i < getNumArg(); ++i) {
601              System.err.println("Argument " + getArg(i)
602                  + " is of type " + getArg(i).type().typeName());
603              if (getArg(i).varDecl() != null) {
604                System.err.println(getArg(i).varDecl() + " in "
605                    + getArg(i).varDecl().hostType().typeName());
606              }
607            }
608            if (isQualified()) {
609              System.err.println("Qualifier " + qualifier()
610                  + " is of type " + qualifier().type().typeName());
611            }
612            throw new Error("Could not bind " + this);
613          }
614          if (decl().getNumParameter() != getNumArg()) {
615            System.err.println(this
616                + " does not have the same number of arguments as " + decl());
617          }
618        }
619    
620        for (int i = 0; i < getNumArg(); ++i) {
621          getArg(i).createBCode(gen);
622          getArg(i).type().emitCastTo(gen, decl().getParameter(i).type()); // MethodInvocationConversion
623        }
624    
625        if (!decl().isStatic() && isQualified() && prevExpr().isSuperAccess()) {
626          if (!hostType().instanceOf(prevExpr().type())) {
627            decl().createSuperAccessor(superAccessorTarget()).emitInvokeMethod(gen, superAccessorTarget());
628          } else {
629            decl().emitInvokeSpecialMethod(gen, methodQualifierType());
630          }
631        } else {
632          decl().emitInvokeMethod(gen, methodQualifierType());
633        }
634      }
635    
636      protected void MethodAccess.createLoadQualifier(CodeGeneration gen) {
637        MethodDecl m = decl();
638        if (hasPrevExpr()) {
639          // load explicit qualifier
640          prevExpr().createBCode(gen);
641          // pop qualifier stack element for class variables
642          // this qualifier must be computed to ensure side effects
643          if (m.isStatic() && !prevExpr().isTypeAccess()) {
644            prevExpr().type().emitPop(gen);
645          }
646        } else if (!m.isStatic()) {
647          // load implicit this qualifier
648          emitThis(gen, methodQualifierType());
649        }
650      }
651    
652      public void ArrayAccess.createBCode(CodeGeneration gen) {
653        prevExpr().createBCode(gen);
654        getExpr().createBCode(gen);
655        gen.emit(type().arrayLoad());
656      }
657    
658      public void ThisAccess.createBCode(CodeGeneration gen) {
659        emitThis(gen, decl());
660      }
661      public void SuperAccess.createBCode(CodeGeneration gen) {
662        emitThis(gen, decl());
663      }
664    
665      // load this where hostType is the target this instance
666      // supporting inner classes and in explicit contructor invocations
667      public void Access.emitThis(CodeGeneration gen, TypeDecl targetDecl) {
668        if (targetDecl == hostType()) {
669          gen.emit(Bytecode.ALOAD_0);
670        } else {
671          TypeDecl enclosing = hostType();
672          if (inExplicitConstructorInvocation()) {
673            gen.emit(Bytecode.ALOAD_1);
674            enclosing = enclosing.enclosing();
675          } else {
676            gen.emit(Bytecode.ALOAD_0);
677          }
678          while (enclosing != targetDecl) {
679            String classname = enclosing.constantPoolName();
680            enclosing = enclosing.enclosingType();
681            String desc = enclosing.typeDescriptor();
682            int index = gen.constantPool().addFieldref(classname, "this$0", desc);
683            gen.emit(Bytecode.GETFIELD, 0).add2(index);
684          }
685        }
686      }
687    
688    
689      public void ConstructorAccess.createBCode(CodeGeneration gen) {
690        ConstructorDecl c = decl();
691        int index = 0;
692        // this
693        gen.emitLoadReference(index++);
694        // this$0
695        if (c.needsEnclosing()) {
696          gen.emitLoadReference(index++);
697        }
698        if (c.needsSuperEnclosing()) {
699          gen.emitLoadReference(index++);
700        }
701    
702        // args
703        for (int i = 0; i < getNumArg(); ++i) {
704          getArg(i).createBCode(gen);
705          getArg(i).type().emitCastTo(gen, decl().getParameter(i).type()); // MethodInvocationConversion
706        }
707        if (decl().isPrivate() && decl().hostType() != hostType()) {
708          gen.emit(Bytecode.ACONST_NULL);
709          decl().createAccessor().emitInvokeConstructor(gen);
710        } else {
711          decl().emitInvokeConstructor(gen);
712        }
713      }
714    
715      public void SuperConstructorAccess.createBCode(CodeGeneration gen) {
716        ConstructorDecl c = decl();
717    
718        // this
719        gen.emit(Bytecode.ALOAD_0);
720    
721        if (c.needsEnclosing()) {
722          if (hasPrevExpr() && !prevExpr().isTypeAccess()) {
723            prevExpr().createBCode(gen);
724            gen.emitDup();
725            int index = gen.constantPool().addMethodref("java/lang/Object", "getClass", "()Ljava/lang/Class;");
726            gen.emit(Bytecode.INVOKEVIRTUAL, 0).add2(index);
727            gen.emitPop();
728          } else {
729            if (hostType().needsSuperEnclosing()) {
730              if (hostType().needsEnclosing()) {
731                gen.emit(Bytecode.ALOAD_2);
732              } else {
733                gen.emit(Bytecode.ALOAD_1);
734              }
735            } else {
736              emitThis(gen, superConstructorQualifier(c.hostType().enclosingType()));
737            }
738          }
739        }
740    
741        // args
742        for (int i = 0; i < getNumArg(); ++i) {
743          getArg(i).createBCode(gen);
744          getArg(i).type().emitCastTo(gen, decl().getParameter(i).type()); // MethodInvocationConversion
745        }
746        if (decl().isPrivate() && decl().hostType() != hostType()) {
747          gen.emit(Bytecode.ACONST_NULL);
748          decl().createAccessor().emitInvokeConstructor(gen);
749        } else {
750          decl().emitInvokeConstructor(gen);
751        }
752      }
753    
754      // 15.9.2
755      private void ClassInstanceExpr.emitLocalEnclosing(CodeGeneration gen, TypeDecl localClass) {
756        if (!localClass.inStaticContext()) {
757          emitThis(gen, localClass.enclosingType());
758        }
759      }
760      private void ClassInstanceExpr.emitInnerMemberEnclosing(CodeGeneration gen, TypeDecl innerClass) {
761        if (hasPrevExpr()) {
762          prevExpr().createBCode(gen);
763          gen.emitDup();
764          int index = gen.constantPool().addMethodref("java/lang/Object", "getClass", "()Ljava/lang/Class;");
765          gen.emit(Bytecode.INVOKEVIRTUAL, 0).add2(index);
766          gen.emitPop();
767        } else {
768          TypeDecl enclosing = hostType();
769          while (enclosing != null && !enclosing.hasType(innerClass.name())) {
770            enclosing = enclosing.enclosingType();
771          }
772          if (enclosing == null) {
773            throw new Error(errorPrefix() + "Could not find enclosing for " + this);
774          } else {
775            emitThis(gen, enclosing);
776          }
777        }
778      }
779      public void ClassInstanceExpr.createBCode(CodeGeneration gen) {
780        type().emitNew(gen);
781        type().emitDup(gen);
782    
783        // 15.9.2 first part
784        if (type().isAnonymous()) {
785          if (type().isAnonymousInNonStaticContext()) {
786            if (type().inExplicitConstructorInvocation()) {
787              gen.emit(Bytecode.ALOAD_1);
788            } else {
789              gen.emit(Bytecode.ALOAD_0);
790            }
791          }
792          // 15.9.2 second part
793          ClassDecl C = (ClassDecl) type();
794          TypeDecl S = C.superclass();
795          if (S.isLocalClass()) {
796            if (!type().inStaticContext()) {
797              emitLocalEnclosing(gen, S);
798            }
799          } else if (S.isInnerType()) {
800            emitInnerMemberEnclosing(gen, S);
801          }
802        } else if (type().isLocalClass()) {
803          if (!type().inStaticContext()) {
804            emitLocalEnclosing(gen, type());
805          }
806        } else if (type().isInnerType()) {
807          emitInnerMemberEnclosing(gen, type());
808        }
809        /*
810        // 15.9.2 first part
811        if (type().isAnonymous()) {
812          if (type().isAnonymousInNonStaticContext()) {
813            if (type().inExplicitConstructorInvocation()) {
814              gen.emit(Bytecode.ALOAD_1);
815            } else {
816              gen.emit(Bytecode.ALOAD_0);
817            }
818          }
819          if (type().needsSuperEnclosing()) {
820            // 15.9.2 second part
821            ClassDecl C = (ClassDecl) type();
822            TypeDecl S = C.superclass();
823            if (S.isLocalClass()) {
824              emitLocalEnclosing(gen, S);
825            } else if (S.isInnerType()) {
826              emitInnerMemberEnclosing(gen, S);
827            }
828          }
829        } else if (type().isLocalClass()) {
830          emitLocalEnclosing(gen, type());
831        } else if (type().isInnerType()) {
832          emitInnerMemberEnclosing(gen, type());
833        }
834        */
835    
836        for (int i = 0; i < getNumArg(); ++i) {
837          getArg(i).createBCode(gen);
838          getArg(i).type().emitCastTo(gen, decl().getParameter(i).type()); // MethodInvocationConversion
839        }
840    
841        if (decl().isPrivate() && type() != hostType()) {
842          gen.emit(Bytecode.ACONST_NULL);
843          decl().createAccessor().emitInvokeConstructor(gen);
844        } else {
845          decl().emitInvokeConstructor(gen);
846        }
847      }
848    
849      public void ArrayCreationExpr.createBCode(CodeGeneration gen) {
850        if (hasArrayInit()){
851          getArrayInit().createBCode(gen);
852        } else {
853          getTypeAccess().createBCode(gen); // push array sizes
854          if (type().componentType().isPrimitive()) {
855            gen.emit(Bytecode.NEWARRAY).add(type().componentType().arrayPrimitiveTypeDescriptor());
856          } else {
857            if (numArrays() == 1) {
858              String n = type().componentType().arrayTypeDescriptor();
859              int index = gen.constantPool().addClass(n);
860              gen.emit(Bytecode.ANEWARRAY).add2(index);
861            } else {
862              String n = type().arrayTypeDescriptor();
863              int index = gen.constantPool().addClass(n);
864              gen.emit(Bytecode.MULTIANEWARRAY, 1 - numArrays()).add2(index).add(numArrays());
865            }
866          }
867        }
868      }
869    
870      public void ArrayInit.createBCode(CodeGeneration gen) {
871        IntegerLiteral.push(gen, getNumInit());
872        if (type().componentType().isPrimitive()) {
873          gen.emit(Bytecode.NEWARRAY).add(type().componentType().arrayPrimitiveTypeDescriptor());
874        } else {
875          String n = type().componentType().arrayTypeDescriptor();
876          int index = gen.constantPool().addClass(n);
877          gen.emit(Bytecode.ANEWARRAY).add2(index);
878        }
879        for (int i = 0; i < getNumInit(); i++) {
880          gen.emitDup();
881          IntegerLiteral.push(gen, i);
882          getInit(i).createBCode(gen);
883          if (getInit(i) instanceof ArrayInit) {
884            gen.emit(Bytecode.AASTORE);
885          } else {
886            getInit(i).type().emitAssignConvTo(gen, expectedType()); // AssignConversion
887            gen.emit(expectedType().arrayStore());
888          }
889        }
890      }
891    
892      public void ArrayTypeAccess.createBCode(CodeGeneration gen) {
893        getAccess().createBCode(gen);
894      }
895      public void ArrayTypeWithSizeAccess.createBCode(CodeGeneration gen) {
896        getAccess().createBCode(gen);
897        getExpr().createBCode(gen);
898      }
899    
900      syn String TypeDecl.arrayTypeDescriptor() { throw new Error("Operation not supported"); }
901      eq ArrayDecl.arrayTypeDescriptor() = typeDescriptor();
902      eq ClassDecl.arrayTypeDescriptor() = constantPoolName();
903      eq InterfaceDecl.arrayTypeDescriptor() = constantPoolName();
904    
905      syn int TypeDecl.arrayPrimitiveTypeDescriptor() { error(); return -1; }
906      eq BooleanType.arrayPrimitiveTypeDescriptor() = 4; // T_BOOLEAN
907      eq CharType.arrayPrimitiveTypeDescriptor()    = 5; // T_CHAR
908      eq FloatType.arrayPrimitiveTypeDescriptor()   = 6; // T_FLOAT
909      eq DoubleType.arrayPrimitiveTypeDescriptor()  = 7; // T_DOUBLE
910      eq ByteType.arrayPrimitiveTypeDescriptor()    = 8; // T_BYTE
911      eq ShortType.arrayPrimitiveTypeDescriptor()   = 9; // T_SHORT
912      eq IntType.arrayPrimitiveTypeDescriptor()     = 10; // T_INT
913      eq LongType.arrayPrimitiveTypeDescriptor()    = 11; // T_LONG
914    
915      public void Unary.createBCode(CodeGeneration gen) {
916        super.createBCode(gen);
917        emitOperation(gen);
918      }
919    
920      public void CastExpr.createBCode(CodeGeneration gen) {
921        getExpr().createBCode(gen);
922        getExpr().type().emitCastTo(gen, type());
923      }
924    
925      // TODO: consider using IINC or WIDE,IINC
926    
927      public void Unary.emitPostfix(CodeGeneration gen, int constant) {
928        Expr operand = getOperand();
929        while (operand instanceof ParExpr) {
930          operand = ((ParExpr) operand).getExpr();
931        }
932        Access access = ((Access) operand).lastAccess();
933        access.createAssignLoadDest(gen);
934        if (needsPush()) {
935          access.createPushAssignmentResult(gen);
936        }
937        TypeDecl type = access.type().binaryNumericPromotion(typeInt());
938        type.emitPushConstant(gen, constant);
939        type.add(gen);
940        type.emitCastTo(gen, access.type());
941        access.emitStore(gen);
942      }
943      public void PostIncExpr.createBCode(CodeGeneration gen) { emitPostfix(gen, 1); }
944      public void PostDecExpr.createBCode(CodeGeneration gen) { emitPostfix(gen, -1); }
945    
946      public void Unary.emitPrefix(CodeGeneration gen, int constant) {
947        Expr operand = getOperand();
948        while (operand instanceof ParExpr) {
949          operand = ((ParExpr) operand).getExpr();
950        }
951        Access access = ((Access) operand).lastAccess();
952        access.createAssignLoadDest(gen);
953        TypeDecl type = access.type().binaryNumericPromotion(typeInt());
954        type.emitPushConstant(gen, constant);
955        type.add(gen);
956        type.emitCastTo(gen, access.type());
957        if (needsPush()) {
958          access.createPushAssignmentResult(gen);
959        }
960        access.emitStore(gen);
961      }
962      public void PreIncExpr.createBCode(CodeGeneration gen) { emitPrefix(gen, 1); }
963      public void PreDecExpr.createBCode(CodeGeneration gen) { emitPrefix(gen, -1); }
964    
965      public void Binary.createBCode(CodeGeneration gen) {
966        getLeftOperand().createBCode(gen);
967        getLeftOperand().type().emitCastTo(gen, type()); // Binary numeric promotion
968        getRightOperand().createBCode(gen);
969        getRightOperand().type().emitCastTo(gen, type()); // Binary numeric promotion
970        emitOperation(gen);
971      }
972    
973      public void Binary.emitShiftExpr(CodeGeneration gen) {
974        getLeftOperand().createBCode(gen);
975        getLeftOperand().type().emitCastTo(gen, type()); // Binary numeric promotion
976        getRightOperand().createBCode(gen);
977        getRightOperand().type().emitCastTo(gen, typeInt());
978        emitOperation(gen);
979      }
980      public void LShiftExpr.createBCode(CodeGeneration gen) { emitShiftExpr(gen); }
981      public void RShiftExpr.createBCode(CodeGeneration gen) { emitShiftExpr(gen); }
982      public void URShiftExpr.createBCode(CodeGeneration gen) { emitShiftExpr(gen); }
983    
984      public void AddExpr.createBCode(CodeGeneration gen) {
985        if (!type().isString()) {
986          super.createBCode(gen);
987        } else if (isConstant()) {
988          StringLiteral.push(gen, constant().stringValue());
989        } else {
990          TypeDecl stringBuffer = lookupType("java.lang", "StringBuffer");
991          String classname = stringBuffer.constantPoolName();
992          String desc;
993          int index;
994          TypeDecl argumentType;
995          if (firstStringAddPart()) {
996            stringBuffer.emitNew(gen); // new StringBuffer
997            gen.emitDup();             // dup
998            desc = "()V";
999            index = gen.constantPool().addMethodref(classname, "<init>", desc);
1000            gen.emit(Bytecode.INVOKESPECIAL, -1).add2(index); // invokespecial StringBuffer()
1001            getLeftOperand().createBCode(gen); // left
1002            argumentType = getLeftOperand().type().stringPromotion();
1003            desc = "(" + argumentType.typeDescriptor() + ")" + stringBuffer.typeDescriptor();
1004            index = gen.constantPool().addMethodref(classname, "append", desc);
1005            gen.emit(Bytecode.INVOKEVIRTUAL, -argumentType.variableSize()).add2(index); // StringBuffer.append
1006          } else {
1007            getLeftOperand().createBCode(gen);
1008          }
1009          getRightOperand().createBCode(gen); // right
1010          argumentType = getRightOperand().type().stringPromotion();
1011          desc = "(" + argumentType.typeDescriptor() + ")" + stringBuffer.typeDescriptor();
1012          index = gen.constantPool().addMethodref(classname, "append", desc);
1013          gen.emit(Bytecode.INVOKEVIRTUAL, -argumentType.variableSize()).add2(index); // StringBuffer.append
1014          if (lastStringAddPart()) {
1015            desc = "()" + type().typeDescriptor();
1016            index = gen.constantPool().addMethodref(classname, "toString", desc);
1017            gen.emit(Bytecode.INVOKEVIRTUAL, 0).add2(index); // StringBuffer.toString
1018          }
1019        }
1020      }
1021    
1022      syn boolean Expr.canBeTrue() = !isFalse();
1023      eq CastExpr.canBeTrue() = getExpr().canBeTrue();
1024      eq ParExpr.canBeTrue() = getExpr().canBeTrue();
1025      eq AbstractDot.canBeTrue() = lastAccess().canBeTrue();
1026      eq OrLogicalExpr.canBeTrue() = getLeftOperand().canBeTrue() || getRightOperand().canBeTrue();
1027      eq AndLogicalExpr.canBeTrue() = getLeftOperand().canBeTrue() && getRightOperand().canBeTrue();
1028      eq ConditionalExpr.canBeTrue() =
1029          type().isBoolean()
1030          && (getCondition().canBeTrue() && getTrueExpr().canBeTrue()
1031              || getCondition().canBeFalse() && getFalseExpr().canBeTrue());
1032      eq LogNotExpr.canBeTrue() = getOperand().canBeFalse();
1033    
1034      syn boolean Expr.canBeFalse() = !isTrue();
1035      eq CastExpr.canBeFalse() = getExpr().canBeFalse();
1036      eq ParExpr.canBeFalse() = getExpr().canBeFalse();
1037      eq AbstractDot.canBeFalse() = lastAccess().canBeFalse();
1038      eq OrLogicalExpr.canBeFalse() = getLeftOperand().canBeFalse() && getRightOperand().canBeFalse();
1039      eq AndLogicalExpr.canBeFalse() = getLeftOperand().canBeFalse() || getRightOperand().canBeFalse();
1040      eq ConditionalExpr.canBeFalse() =
1041          type().isBoolean()
1042          && (getCondition().canBeTrue() && getTrueExpr().canBeFalse()
1043              || getCondition().canBeFalse() && getFalseExpr().canBeFalse());
1044      eq LogNotExpr.canBeFalse() = getOperand().canBeTrue();
1045    
1046      public void RelationalExpr.createBCode(CodeGeneration gen) { emitBooleanCondition(gen); }
1047      public void LogNotExpr.createBCode(CodeGeneration gen) { emitBooleanCondition(gen); }
1048      public void LogicalExpr.createBCode(CodeGeneration gen) { emitBooleanCondition(gen); }
1049    
1050      protected void Expr.emitBooleanCondition(CodeGeneration gen) {
1051        int end_label = -1;
1052        int false_label = -1;
1053        if (!isConstant()) {
1054          false_label = gen.constantPool().newLabel();
1055          branchFalse(gen, false_label);
1056        }
1057        if (canBeTrue()) {
1058          BooleanLiteral.push(gen, true);
1059          if (canBeFalse()) {
1060            end_label = gen.constantPool().newLabel();
1061            gen.emitGoto(end_label);
1062            gen.changeStackDepth(-1); // discard value from stack depth computation
1063          }
1064        }
1065        if (false_label != -1) {
1066          gen.addLabel(false_label);
1067        }
1068        if (canBeFalse()) {
1069          BooleanLiteral.push(gen, false);
1070        }
1071        if (end_label != -1) {
1072          gen.addLabel(end_label);
1073        }
1074      }
1075    
1076      public void ConditionalExpr.createBCode(CodeGeneration gen) {
1077        int end_label = -1;
1078        int false_label = -1;
1079        if (!getCondition().isConstant()) {
1080          false_label = gen.constantPool().newLabel();
1081          getCondition().branchFalse(gen, false_label);
1082        }
1083        if (getCondition().canBeTrue()) {
1084          getTrueExpr().createBCode(gen);
1085          getTrueExpr().type().emitCastTo(gen, type());
1086          if (getCondition().canBeFalse()) {
1087            end_label = gen.constantPool().newLabel();
1088            gen.emitGoto(end_label);
1089            gen.changeStackDepth(-type().variableSize());
1090          }
1091        }
1092        if (false_label != -1) {
1093          gen.addLabel(false_label);
1094        }
1095        if (getCondition().canBeFalse()) {
1096          getFalseExpr().createBCode(gen);
1097          getFalseExpr().type().emitCastTo(gen, type());
1098        }
1099        if (end_label != -1) {
1100          gen.addLabel(end_label);
1101        }
1102      }
1103    
1104      /**
1105       * Generate a conditional branch statement. The branch should be taken if the
1106       * expression evaluates to true. May in some cases not result in an actual
1107       * branch statement if the branch would never be taken.
1108       * @param gen code generator
1109       * @param target target label to jump to if the condition was true
1110       */
1111      public void Expr.branchTrue(CodeGeneration gen, int target) {
1112        // branch when true
1113        if (isConstant()) {
1114          if (isTrue()) {
1115            gen.emitGoto(target);
1116            //gen.GOTO(target);
1117          } // else { fallthrough }
1118        } else {
1119          createBCode(gen);
1120          gen.emitCompare(Bytecode.IFNE, target);
1121          //gen.IFNE(target);// branch if value != 0
1122        }
1123      }
1124    
1125      public void ParExpr.branchTrue(CodeGeneration gen, int target) {
1126        // branch when true
1127        getExpr().branchTrue(gen, target);
1128      }
1129    
1130      public void AbstractDot.branchTrue(CodeGeneration gen, int target) {
1131        // branch when true
1132        lastAccess().branchTrue(gen, target);
1133      }
1134    
1135      public void LogNotExpr.branchTrue(CodeGeneration gen, int target)  {
1136        // branch when true
1137        getOperand().branchFalse(gen, target);
1138      }
1139    
1140      public void AndLogicalExpr.branchTrue(CodeGeneration gen, int target) {
1141        // branch when true
1142        Expr left = getLeftOperand();
1143        Expr right = getRightOperand();
1144        int skip_lbl = -1;
1145        if (!left.isConstant()) {
1146          skip_lbl = gen.constantPool().newLabel();
1147          left.branchFalse(gen, skip_lbl);
1148        }
1149        if (left.canBeTrue()) {
1150          right.branchTrue(gen, target);
1151        }
1152        if (skip_lbl != -1) {
1153          gen.addLabel(skip_lbl);
1154        }
1155      }
1156    
1157      public void OrLogicalExpr.branchTrue(CodeGeneration gen, int target) {
1158        // branch when true
1159        Expr left = getLeftOperand();
1160        Expr right = getRightOperand();
1161        if (!left.isFalse()) {
1162          left.branchTrue(gen, target);
1163        }
1164        if (left.canBeFalse()) {
1165          right.branchTrue(gen, target);
1166        }
1167      }
1168    
1169      public void ConditionalExpr.branchTrue(CodeGeneration gen, int target) {
1170        // branch when true
1171        int else_label = -1;
1172        int end_label = -1;
1173        if (!getCondition().isConstant()) {
1174          else_label = gen.constantPool().newLabel();
1175          getCondition().branchFalse(gen, else_label);
1176        }
1177        if (getCondition().canBeTrue()) {
1178          getTrueExpr().branchTrue(gen, target);
1179          if (getCondition().canBeFalse() && getTrueExpr().canBeFalse()) {
1180            end_label = gen.constantPool().newLabel();
1181            gen.emitGoto(end_label);
1182            //gen.GOTO(end_label);
1183          }
1184        }
1185        if (else_label != -1) {
1186          gen.addLabel(else_label);
1187        }
1188        if (getCondition().canBeFalse()) {
1189          getFalseExpr().branchTrue(gen, target);
1190        }
1191        if (end_label != -1) {
1192          gen.addLabel(end_label);
1193        }
1194      }
1195    
1196      public void RelationalExpr.branchTrue(CodeGeneration gen, int target) {
1197        // branch when true
1198        if (isConstant()) {
1199          if (isTrue()) {
1200            gen.emitGoto(target);
1201            //gen.GOTO(target);
1202          }
1203        } else {
1204          TypeDecl type = getLeftOperand().type();
1205          if (type.isNumericType()) {
1206            type = binaryNumericPromotedType();
1207            getLeftOperand().createBCode(gen);
1208            getLeftOperand().type().emitCastTo(gen, type); // Binary numeric promotion
1209            getRightOperand().createBCode(gen);
1210            getRightOperand().type().emitCastTo(gen, type); // Binary numeric promotion
1211          } else {
1212            getLeftOperand().createBCode(gen);
1213            getRightOperand().createBCode(gen);
1214          }
1215          compareBranch(gen, target, type);
1216        }
1217      }
1218    
1219      /**
1220       * Generate a conditional branch statement. The branch should be taken if the
1221       * expression evaluates to false. May in some cases not result in an actual
1222       * branch statement if the branch would never be taken.
1223       * @param gen code generator
1224       * @param target target label to jump to if the condition was false
1225       */
1226      public void Expr.branchFalse(CodeGeneration gen, int target) {
1227        // branch when false
1228        if (isConstant()) {
1229          if (isFalse()) {
1230            gen.emitGoto(target);
1231            //gen.GOTO(target);
1232          } // else { fallthrough }
1233        } else {
1234          createBCode(gen);
1235          gen.emitCompare(Bytecode.IFEQ, target);
1236          //gen.IFEQ(target);// branch if value == 0
1237        }
1238      }
1239    
1240      public void ParExpr.branchFalse(CodeGeneration gen, int target) {
1241        // branch when false
1242        getExpr().branchFalse(gen, target);
1243      }
1244    
1245      public void AbstractDot.branchFalse(CodeGeneration gen, int target) {
1246        // branch when false
1247        lastAccess().branchFalse(gen, target);
1248      }
1249    
1250      public void LogNotExpr.branchFalse(CodeGeneration gen, int target)  {
1251        // branch when false
1252        getOperand().branchTrue(gen, target);
1253      }
1254    
1255      public void AndLogicalExpr.branchFalse(CodeGeneration gen, int target) {
1256        // branch when false
1257        Expr left = getLeftOperand();
1258        Expr right = getRightOperand();
1259        if (!left.isTrue()) {
1260          left.branchFalse(gen, target);
1261        }
1262        if (left.canBeTrue()) {
1263          right.branchFalse(gen, target);
1264        }
1265      }
1266    
1267      public void OrLogicalExpr.branchFalse(CodeGeneration gen, int target) {
1268        // branch when false
1269        Expr left = getLeftOperand();
1270        Expr right = getRightOperand();
1271        int skip_lbl = -1;
1272        if (!left.isConstant()) {
1273          skip_lbl = gen.constantPool().newLabel();
1274          left.branchTrue(gen, skip_lbl);
1275        }
1276        if (left.canBeFalse()) {
1277          right.branchFalse(gen, target);
1278        }
1279        if (skip_lbl != -1) {
1280          gen.addLabel(skip_lbl);
1281        }
1282      }
1283    
1284      public void ConditionalExpr.branchFalse(CodeGeneration gen, int target) {
1285        // branch when false
1286        int else_label = -1;
1287        int end_label = -1;
1288        if (!getCondition().isConstant()) {
1289          else_label = gen.constantPool().newLabel();
1290          getCondition().branchFalse(gen, else_label);
1291        }
1292        if (getCondition().canBeTrue()) {
1293          getTrueExpr().branchFalse(gen, target);
1294          if (getCondition().canBeFalse() && getTrueExpr().canBeTrue()) {
1295            end_label = gen.constantPool().newLabel();
1296            gen.emitGoto(end_label);
1297            //gen.GOTO(end_label);
1298          }
1299        }
1300        if (else_label != -1) {
1301          gen.addLabel(else_label);
1302        }
1303        if (getCondition().canBeFalse()) {
1304          getFalseExpr().branchFalse(gen, target);
1305        }
1306        if (end_label != -1) {
1307          gen.addLabel(end_label);
1308        }
1309      }
1310    
1311      public void RelationalExpr.branchFalse(CodeGeneration gen, int target) {
1312        // branch when false
1313        if (isConstant()) {
1314          if (isFalse()) {
1315            gen.emitGoto(target);
1316            //gen.GOTO(target);
1317          }
1318        } else {
1319          TypeDecl type = getLeftOperand().type();
1320          if (type.isNumericType()) {
1321            type = binaryNumericPromotedType();
1322            getLeftOperand().createBCode(gen);
1323            getLeftOperand().type().emitCastTo(gen, type); // Binary numeric promotion
1324            getRightOperand().createBCode(gen);
1325            getRightOperand().type().emitCastTo(gen, type); // Binary numeric promotion
1326          } else {
1327            getLeftOperand().createBCode(gen);
1328            getRightOperand().createBCode(gen);
1329          }
1330          compareNotBranch(gen, target, type);
1331        }
1332      }
1333    
1334      public void RelationalExpr.compareBranch(CodeGeneration gen, int label, TypeDecl typeDecl) {
1335        throw new Error("compareBranch not implemented for " + getClass().getName());
1336      }
1337      public void LTExpr.compareBranch(CodeGeneration gen, int label, TypeDecl typeDecl) { typeDecl.branchLT(gen, label); }
1338      public void LEExpr.compareBranch(CodeGeneration gen, int label, TypeDecl typeDecl) { typeDecl.branchLE(gen, label); }
1339      public void GEExpr.compareBranch(CodeGeneration gen, int label, TypeDecl typeDecl) { typeDecl.branchGE(gen, label); }
1340      public void GTExpr.compareBranch(CodeGeneration gen, int label, TypeDecl typeDecl) { typeDecl.branchGT(gen, label); }
1341      public void EQExpr.compareBranch(CodeGeneration gen, int label, TypeDecl typeDecl) { typeDecl.branchEQ(gen, label); }
1342      public void NEExpr.compareBranch(CodeGeneration gen, int label, TypeDecl typeDecl) { typeDecl.branchNE(gen, label); }
1343    
1344      public void RelationalExpr.compareNotBranch(CodeGeneration gen, int label, TypeDecl typeDecl) {
1345        throw new Error("compareNotBranch not implemented for " + getClass().getName());
1346      }
1347      public void LTExpr.compareNotBranch(CodeGeneration gen, int label, TypeDecl typeDecl) { typeDecl.branchGEInv(gen, label); }
1348      public void LEExpr.compareNotBranch(CodeGeneration gen, int label, TypeDecl typeDecl) { typeDecl.branchGTInv(gen, label); }
1349      public void GEExpr.compareNotBranch(CodeGeneration gen, int label, TypeDecl typeDecl) { typeDecl.branchLTInv(gen, label); }
1350      public void GTExpr.compareNotBranch(CodeGeneration gen, int label, TypeDecl typeDecl) { typeDecl.branchLEInv(gen, label); }
1351      public void EQExpr.compareNotBranch(CodeGeneration gen, int label, TypeDecl typeDecl) { typeDecl.branchNE(gen, label); }
1352      public void NEExpr.compareNotBranch(CodeGeneration gen, int label, TypeDecl typeDecl) { typeDecl.branchEQ(gen, label); }
1353    
1354      public void InstanceOfExpr.createBCode(CodeGeneration gen) {
1355        getExpr().createBCode(gen);
1356        gen.emitInstanceof(getTypeAccess().type());
1357      }
1358    
1359      public void Stmt.createBCode(CodeGeneration gen) {
1360        gen.addLineNumberEntryAtCurrentPC(this);
1361      }
1362    
1363      public void Block.createBCode(CodeGeneration gen) {
1364        //super.createBCode(gen);
1365        for (int i = 0; i < getNumStmt(); i++) {
1366          try {
1367            getStmt(i).createBCode(gen);
1368          } catch (Exception e) {
1369            e.printStackTrace();
1370            throw new Error("Error generating code for " + errorPrefix() + " " + getStmt(i));
1371          }
1372        }
1373        gen.addVariableScopeLabel(variableScopeEndLabel(gen));
1374      }
1375    
1376      public void EmptyStmt.createBCode(CodeGeneration gen) {
1377        super.createBCode(gen);
1378      }
1379    
1380      syn lazy int LabeledStmt.label() = hostType().constantPool().newLabel();
1381      syn lazy int LabeledStmt.end_label() = hostType().constantPool().newLabel();
1382      public void LabeledStmt.createBCode(CodeGeneration gen) {
1383        super.createBCode(gen);
1384        gen.addLabel(label());
1385        getStmt().createBCode(gen);
1386        gen.addLabel(end_label());
1387      }
1388    
1389      public void ExprStmt.createBCode(CodeGeneration gen) {
1390        super.createBCode(gen);
1391        getExpr().createBCode(gen);
1392        if (needsPop()) {
1393          getExpr().type().emitPop(gen);
1394        }
1395      }
1396    
1397      syn lazy DefaultCase SwitchStmt.defaultCase() {
1398        for (int i= 0; i < getBlock().getNumStmt(); i++) {
1399          if (getBlock().getStmt(i) instanceof DefaultCase) {
1400            return (DefaultCase) getBlock().getStmt(i);
1401          }
1402        }
1403        return null;
1404      }
1405    
1406      syn lazy int SwitchStmt.end_label() = hostType().constantPool().newLabel();
1407    
1408      public void SwitchStmt.createBCode(CodeGeneration gen) {
1409        super.createBCode(gen);
1410        int switch_label = gen.constantPool().newLabel();
1411    
1412        getExpr().createBCode(gen);
1413    
1414        TreeMap<Integer, ConstCase> map = new TreeMap<Integer, ConstCase>();
1415        for (int i = 0; i < getBlock().getNumStmt(); i++) {
1416          if (getBlock().getStmt(i) instanceof ConstCase) {
1417            ConstCase ca = (ConstCase) getBlock().getStmt(i);
1418            map.put(ca.getValue().constant().intValue(), ca);
1419          }
1420        }
1421    
1422        int low = map.isEmpty() ? 0 : map.firstKey();
1423        int high = map.isEmpty() ? 0 : map.lastKey();
1424    
1425        int tableSwitchSize = 4 * (3 + (high - low + 1));
1426        int lookupSwitchSize = 4 * (2 + 2 * map.size());
1427        int pad;
1428        int switchSize;
1429        int switchPos;
1430        boolean tableSwitch = tableSwitchSize < lookupSwitchSize;
1431    
1432        gen.addLabel(switch_label);
1433    
1434        // Select the switch type which produces the smallest switch instr.
1435        if (tableSwitch) {
1436          // TABLESWITCH
1437          gen.emit(Bytecode.TABLESWITCH);
1438          switchSize = tableSwitchSize;
1439        } else {
1440          // LOOKUPSWITCH
1441          gen.emit(Bytecode.LOOKUPSWITCH);
1442          switchSize = lookupSwitchSize;
1443        }
1444    
1445        pad = emitPad(gen);
1446        switchPos = gen.pos();
1447    
1448        // leave room for the address table
1449        gen.skip(switchSize);
1450    
1451        getBlock().createBCode(gen);
1452    
1453        // write jump address table
1454        int endpos = gen.pos();
1455        gen.setPos(switchPos);
1456        if (tableSwitch) {
1457          int defaultOffset = defaultOffset(gen, switch_label);
1458          int numCase = high - low + 1;
1459          if (defaultOffset == 0) {
1460            defaultOffset = 1 + pad + switchSize;
1461          }
1462          gen.add4(defaultOffset);
1463          gen.add4(low);
1464          gen.add4(high);
1465          for (int i = low; i <= high; i++) {
1466            ConstCase ca = map.get(i);
1467            if (ca != null) {
1468              int offset = gen.addressOf(ca.label())
1469                - gen.addressOf(switch_label);
1470              gen.add4(offset);
1471            } else {
1472              gen.add4(defaultOffset);
1473            }
1474          }
1475        } else {
1476          int defaultOffset = defaultOffset(gen, switch_label);
1477          if (defaultOffset == 0) {
1478            defaultOffset = 1 + pad + switchSize;
1479          }
1480          gen.add4(defaultOffset);
1481          gen.add4(map.size());
1482          for (ConstCase ca : map.values()) {
1483            gen.add4(ca.getValue().constant().intValue());
1484            int offset = gen.addressOf(ca.label())
1485              - gen.addressOf(switch_label);
1486            gen.add4(offset);
1487          }
1488        }
1489        gen.setPos(endpos);
1490    
1491        gen.addLabel(end_label());
1492      }
1493    
1494      syn int SwitchStmt.numCase() {
1495        int result = 0;
1496        for (int i = 0; i < getBlock().getNumStmt(); i++) {
1497          if (getBlock().getStmt(i) instanceof Case) {
1498            result++;
1499          }
1500        }
1501        return result;
1502      }
1503    
1504      private int SwitchStmt.emitPad(CodeGeneration gen) {
1505        int pad = (4 - (gen.pos() % 4)) % 4;
1506        for (int i = 0; i < pad; i++) {
1507          gen.emit(Bytecode.NOP);
1508        }
1509        if (gen.pos() % 4 != 0) {
1510          throw new Error("Switch not at 4-byte boundary:" + gen.pos());
1511        }
1512        return pad;
1513      }
1514    
1515      /**
1516       * Calculate offset to the default label.
1517       * @return bytecode offset to default label (or zero if there is no
1518       * default label)
1519       */
1520      private int SwitchStmt.defaultOffset(CodeGeneration gen, int switch_label) {
1521        DefaultCase defaultCase = defaultCase();
1522        if (defaultCase != null) {
1523          int offset = gen.addressOf(defaultCase.label())
1524            - gen.addressOf(switch_label);
1525          return offset;
1526        }
1527        return 0;
1528      }
1529    
1530      syn lazy int Case.label() = hostType().constantPool().newLabel();
1531    
1532      public void Case.createBCode(CodeGeneration gen) {
1533        gen.addLabel(label());
1534      }
1535    
1536      syn lazy int IfStmt.else_branch_label() = hostType().constantPool().newLabel();
1537      syn lazy int IfStmt.then_branch_label() = hostType().constantPool().newLabel();
1538      syn lazy int IfStmt.end_label() = hostType().constantPool().newLabel();
1539      public void IfStmt.createBCode(CodeGeneration gen) {
1540        super.createBCode(gen);
1541        int elseBranch = else_branch_label();
1542        int thenBranch = then_branch_label();
1543        int endBranch = end_label();
1544        if (!getCondition().isConstant()) {
1545          getCondition().branchFalse(gen, elseBranch);
1546        }
1547        gen.addLabel(thenBranch);
1548        if (getCondition().canBeTrue()) {
1549          getThen().createBCode(gen);
1550          if (getThen().canCompleteNormally() && hasElse() && getCondition().canBeFalse()) {
1551            gen.emitGoto(endBranch);
1552          }
1553        }
1554        gen.addLabel(elseBranch);
1555        if (hasElse() && getCondition().canBeFalse()) {
1556          getElse().createBCode(gen);
1557        }
1558        gen.addLabel(endBranch);
1559      }
1560    
1561      syn lazy int WhileStmt.cond_label() = hostType().constantPool().newLabel();
1562      syn lazy int WhileStmt.end_label() = hostType().constantPool().newLabel();
1563      syn lazy int WhileStmt.stmt_label() = hostType().constantPool().newLabel();
1564    
1565      public void WhileStmt.createBCode(CodeGeneration gen) {
1566        super.createBCode(gen);
1567        gen.addLabel(cond_label());
1568        if (!getCondition().isConstant()) {
1569          getCondition().branchFalse(gen, end_label());
1570        }
1571        gen.addLabel(stmt_label());
1572        if (getCondition().canBeTrue()) {
1573          getStmt().createBCode(gen);
1574          if (getStmt().canCompleteNormally()) {
1575            gen.emitGoto(cond_label());
1576          }
1577        }
1578        gen.addLabel(end_label());
1579      }
1580    
1581      syn lazy int DoStmt.begin_label() = hostType().constantPool().newLabel();
1582      syn lazy int DoStmt.cond_label() = hostType().constantPool().newLabel();
1583      syn lazy int DoStmt.end_label() = hostType().constantPool().newLabel();
1584    
1585      public void DoStmt.createBCode(CodeGeneration gen) {
1586        super.createBCode(gen);
1587        gen.addLabel(begin_label());
1588        getStmt().createBCode(gen);
1589        gen.addLabel(cond_label());
1590        getCondition().branchTrue(gen, begin_label());
1591        gen.addLabel(end_label());
1592      }
1593    
1594      syn lazy int ForStmt.cond_label() = hostType().constantPool().newLabel();
1595      syn lazy int ForStmt.begin_label() = hostType().constantPool().newLabel();
1596      syn lazy int ForStmt.update_label() = hostType().constantPool().newLabel();
1597      syn lazy int ForStmt.end_label() = hostType().constantPool().newLabel();
1598    
1599      public void ForStmt.createBCode(CodeGeneration gen) {
1600        super.createBCode(gen);
1601        for (int i=0; i<getNumInitStmt(); i++) {
1602          getInitStmt(i).createBCode(gen);
1603        }
1604        gen.addLabel(cond_label());
1605        if (!getCondition().isConstant()) {
1606          getCondition().branchFalse(gen, end_label());
1607        }
1608        if (getCondition().canBeTrue()) {
1609          gen.addLabel(begin_label());
1610          getStmt().createBCode(gen);
1611          gen.addLabel(update_label());
1612          for (int i=0; i<getNumUpdateStmt(); i++) {
1613            getUpdateStmt(i).createBCode(gen);
1614          }
1615          gen.emitGoto(cond_label());
1616        }
1617        gen.addLabel(end_label());
1618        gen.addVariableScopeLabel(variableScopeEndLabel(gen));
1619      }
1620    
1621      syn int Stmt.break_label() {
1622        throw new UnsupportedOperationException("Can not break at this statement of type " + getClass().getName());
1623      }
1624      eq ForStmt.break_label() = end_label();
1625      eq WhileStmt.break_label() = end_label();
1626      eq DoStmt.break_label() = end_label();
1627      eq LabeledStmt.break_label() = end_label();
1628      eq SwitchStmt.break_label() = end_label();
1629      eq TryStmt.break_label() =  label_end();
1630      syn lazy int SynchronizedStmt.start_label() = hostType().constantPool().newLabel();
1631    
1632      public void BreakStmt.createBCode(CodeGeneration gen) {
1633        super.createBCode(gen);
1634        if (hasFinally()) {
1635          int nextRange = gen.constantPool().newLabel();
1636          getFinally().createBCode(gen);
1637          gen.emitGoto(targetStmt().break_label());
1638          gen.addLabel(nextRange);
1639          gen.monitorRangesStart(this, nextRange);
1640        } else {
1641          gen.emitGoto(targetStmt().break_label());
1642        }
1643      }
1644    
1645      syn int Stmt.continue_label() {
1646        throw new UnsupportedOperationException("Can not continue at this statement");
1647      }
1648      eq ForStmt.continue_label() = update_label();
1649      eq WhileStmt.continue_label() = cond_label();
1650      eq DoStmt.continue_label() = cond_label();
1651      eq LabeledStmt.continue_label() = getStmt().continue_label();
1652    
1653      // TODO: test continue in try-statement!!!
1654      eq TryStmt.continue_label() = label_end();
1655    
1656      public void ContinueStmt.createBCode(CodeGeneration gen) {
1657        super.createBCode(gen);
1658        if (hasFinally()) {
1659          int nextRange = gen.constantPool().newLabel();
1660          getFinally().createBCode(gen);
1661          gen.emitGoto(targetStmt().continue_label());
1662          gen.addLabel(nextRange);
1663          gen.monitorRangesStart(this, nextRange);
1664        } else {
1665          gen.emitGoto(targetStmt().continue_label());
1666        }
1667      }
1668    
1669      public void ReturnStmt.createBCode(CodeGeneration gen) {
1670        super.createBCode(gen);
1671        if (hasResult()) {
1672          TypeDecl type = null;
1673          BodyDecl b = enclosingBodyDecl();
1674          if (b instanceof MethodDecl) {
1675            type = ((MethodDecl) b).type();
1676          } else {
1677            throw new Error("Can not create code that returns value within non method");
1678          }
1679          getResult().createBCode(gen);
1680          getResult().type().emitCastTo(gen, type);
1681          if (hasFinally()) {
1682            int nextRange = gen.constantPool().newLabel();
1683            type.emitStoreLocal(gen, resultSaveLocalNum());
1684            getFinally().createBCode(gen);
1685            type.emitLoadLocal(gen, resultSaveLocalNum());
1686            type.emitReturn(gen);
1687            gen.addLabel(nextRange);
1688            gen.monitorRangesStart(this, nextRange);
1689          } else {
1690            type.emitReturn(gen);
1691          }
1692        } else {
1693          if (hasFinally()) {
1694            int nextRange = gen.constantPool().newLabel();
1695            getFinally().createBCode(gen);
1696            gen.emitReturn();
1697            gen.addLabel(nextRange);
1698            gen.monitorRangesStart(this, nextRange);
1699          } else {
1700            gen.emitReturn();
1701          }
1702        }
1703      }
1704    
1705      public void ThrowStmt.createBCode(CodeGeneration gen) {
1706        super.createBCode(gen);
1707        getExpr().createBCode(gen);
1708        gen.emitThrow();
1709      }
1710    
1711      syn lazy int TryStmt.fallthrough_label() =
1712          hasNonEmptyFinally() ? hostType().constantPool().newLabel() : label_end();
1713    
1714      public void TryStmt.createBCode(CodeGeneration gen) {
1715        int block_top_lbl = gen.constantPool().newLabel();
1716        int block_end_lbl = gen.constantPool().newLabel();
1717        int fallthrough_lbl = fallthrough_label();
1718        int handler_lbl = gen.constantPool().newLabel();
1719        boolean needsHandler = false;
1720    
1721        super.createBCode(gen);
1722        gen.addLabel(block_top_lbl);
1723        getBlock().createBCode(gen);
1724        gen.addLabel(block_end_lbl);
1725    
1726        if (getBlock().canCompleteNormally()) {
1727          gen.emitGoto(fallthrough_lbl);
1728        }
1729    
1730        for (int i = 0; i < getNumCatchClause(); i++) {
1731          CatchClause cc = getCatchClause(i);
1732          cc.createBCode(gen);
1733          cc.exceptionTableEntries(gen, block_top_lbl, block_end_lbl);
1734          if (cc.getBlock().canCompleteNormally()) {
1735            gen.emitGoto(fallthrough_lbl);
1736          }
1737          if (hasNonEmptyFinally()) {
1738            int cc_end_lbl = gen.constantPool().newLabel();
1739            gen.addLabel(cc_end_lbl);
1740            needsHandler = true;
1741            gen.addException(cc.label(), cc_end_lbl, handler_lbl,
1742                CodeGeneration.ExceptionEntry.CATCH_ALL);
1743          }
1744        }
1745    
1746        if (hasNonEmptyFinally()) {
1747    
1748          emitExceptionHandler(gen, block_top_lbl, block_end_lbl, handler_lbl,
1749              needsHandler);
1750    
1751          // fallthrough finally
1752          gen.addLabel(fallthrough_lbl);
1753          getFinally().createBCode(gen);
1754        }
1755    
1756        gen.addLabel(label_end());
1757      }
1758    
1759      /**
1760       * Outer finally host with a finally block that can complete normally
1761       */
1762      syn FinallyHost TryStmt.outerFinallyHost() {
1763        // find outer finally
1764        FinallyHost outer = this;
1765        Iterator<FinallyHost> iter = finallyIterator();
1766        while (iter.hasNext()) {
1767          outer = iter.next();
1768        }
1769        return outer;
1770      }
1771    
1772      /**
1773       * Generate catch-all (finally)
1774       */
1775      public void TryStmt.emitExceptionHandler(CodeGeneration gen, int start_lbl, int end_lbl, int handler_lbl, boolean needsHandler) {
1776        int top_pc = gen.addressOf(start_lbl);
1777        int end_pc = gen.addressOf(end_lbl);
1778        if (needsHandler || top_pc != end_pc) {
1779          // catch-all exception handler (finally)
1780          gen.addLabel(handler_lbl);
1781          gen.changeStackDepth(1);
1782          int num = getBlock().localNum();
1783          gen.emitStoreReference(num);
1784          getExceptionHandler().createBCode(gen);
1785          gen.emitLoadReference(num);
1786          gen.emit(Bytecode.ATHROW);
1787    
1788          gen.addException(start_lbl, end_lbl, handler_lbl,
1789              CodeGeneration.ExceptionEntry.CATCH_ALL);
1790        }
1791      }
1792    
1793      public void SynchronizedStmt.emitMonitorEnter(CodeGeneration gen) {
1794        gen.emitDup();
1795        int num = localNum();
1796        gen.emitStoreReference(num);
1797        gen.emit(Bytecode.MONITORENTER);
1798      }
1799    
1800      syn lazy int CatchClause.label() = hostType().constantPool().newLabel();
1801      public void BasicCatch.createBCode(CodeGeneration gen) {
1802        gen.addLabel(label());
1803        // add 1 to stack depth
1804        gen.changeStackDepth(1);
1805        getParameter().type().emitStoreLocal(gen, getParameter().localNum());
1806        getBlock().createBCode(gen);
1807      }
1808    
1809      protected int SynchronizedStmt.monitorId = -1;
1810    
1811      public void SynchronizedStmt.createBCode(CodeGeneration gen) {
1812        int lbl_start = gen.constantPool().newLabel();
1813        super.createBCode(gen);
1814        getExpr().createBCode(gen);
1815    
1816        monitorId = gen.monitorEnter(this);
1817        gen.addLabel(lbl_start);
1818        gen.monitorRangeStart(monitorId, lbl_start);
1819    
1820        getBlock().createBCode(gen);
1821    
1822        if (getBlock().canCompleteNormally()) {
1823          getMonitorExit().createBCode(gen);
1824          gen.emitGoto(label_end());
1825        }
1826    
1827        gen.monitorExit();
1828    
1829        gen.addLabel(label_end());
1830      }
1831    
1832      /**
1833       * Checks if the branch statement leaves the monitor.
1834       * @return <code>true</code> if the branch leaves the monitor
1835       */
1836      inh boolean Stmt.leavesMonitor(Stmt branch, SynchronizedStmt monitor);
1837    
1838      eq BodyDecl.getChild().leavesMonitor(Stmt branch, SynchronizedStmt monitor) {
1839        throw new Error("Enclosing monitor not found!");
1840      }
1841    
1842      eq SynchronizedStmt.getChild().leavesMonitor(Stmt branch, SynchronizedStmt monitor) {
1843        if (monitor == this) {
1844          return true;
1845        } else {
1846          return leavesMonitor(branch, monitor);
1847        }
1848      }
1849    
1850      eq BranchTargetStmt.getChild().leavesMonitor(Stmt branch, SynchronizedStmt monitor) {
1851        if (potentialTargetOf(branch)) {
1852          return false;
1853        } else {
1854          return leavesMonitor(branch, monitor);
1855        }
1856      }
1857    
1858      /**
1859       * Assert statement bytecode is generated through the transformed
1860       * version of the assert statement!
1861       *
1862       * @see java4/backend/Transformations.jrag
1863       */
1864      public void AssertStmt.createBCode(CodeGeneration gen) {
1865        throw new UnsupportedOperationException("Assert not yet implemented");
1866      }
1867    
1868      public void LocalClassDeclStmt.createBCode(CodeGeneration gen) {
1869      }
1870    
1871      public void ClassAccess.createBCode(CodeGeneration gen) {
1872        if (prevExpr().type().isPrimitiveType() || prevExpr().type().isVoid()) {
1873          TypeDecl typeDecl = lookupType("java.lang", prevExpr().type().primitiveClassName());
1874          SimpleSet c = typeDecl.memberFields("TYPE");
1875          FieldDeclaration f = (FieldDeclaration) c.iterator().next();
1876          f.emitLoadField(gen, typeDecl);
1877        } else {
1878          FieldDeclaration f = hostType().topLevelType().createStaticClassField(prevExpr().type().referenceClassFieldName());
1879          // add method to perform lookup as a side-effect
1880          MethodDecl m = hostType().topLevelType().createStaticClassMethod();
1881    
1882          int next_label = gen.constantPool().newLabel();
1883          int end_label = gen.constantPool().newLabel();
1884          f.emitLoadField(gen, hostType());
1885          gen.emitBranchNonNull(next_label);
1886    
1887          // emit string literal
1888    
1889          StringLiteral.push(gen, prevExpr().type().jvmName());
1890          m.emitInvokeMethod(gen, hostType());
1891          gen.emitDup();
1892          f.emitStoreField(gen, hostType());
1893          gen.emitGoto(end_label);
1894          gen.addLabel(next_label);
1895          gen.changeStackDepth(-1);
1896          f.emitLoadField(gen, hostType());
1897          gen.addLabel(end_label);
1898        }
1899      }
1900    
1901      /**
1902       * Generate bytecode for the monitor exit call.
1903       */
1904      public void MonitorExit.createBCode(CodeGeneration gen) {
1905        gen.monitorRangeEnd(monitor.monitorId,
1906            hostType().constantPool().newLabel());
1907      }
1908    
1909      /**
1910       * Generate exception handler for monitor closing.
1911       * @param gen
1912       */
1913      public void MonitorExit.emitMonitorExitHandler(CodeGeneration gen) {
1914        int handler_lbl = handler_label();
1915        int end_lbl = handler_end_label();
1916    
1917        gen.changeStackDepth(1);
1918        int num = localNum() + 1;
1919    
1920        // handler start
1921        gen.addLabel(handler_lbl);
1922    
1923        gen.emitStoreReference(num);
1924    
1925        gen.emitLoadReference(monitor.localNum());
1926        gen.emit(Bytecode.MONITOREXIT);
1927    
1928        // handler end
1929        gen.addLabel(end_lbl);
1930    
1931        gen.emitLoadReference(num);
1932        gen.emit(Bytecode.ATHROW);
1933    
1934        // add exception handler for the monitor closing
1935        // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4414101
1936        gen.addException(handler_lbl, end_lbl, handler_lbl,
1937            CodeGeneration.ExceptionEntry.CATCH_ALL);
1938    
1939      }
1940    }