1 /*
   2  * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.tools.tree;
  27 
  28 import sun.tools.java.*;
  29 import sun.tools.asm.Assembler;
  30 import sun.tools.asm.Label;
  31 import sun.tools.asm.TryData;
  32 import sun.tools.asm.CatchData;
  33 import java.io.PrintStream;
  34 import java.util.Hashtable;
  35 
  36 /**
  37  * WARNING: The contents of this source file are not part of any
  38  * supported API.  Code that depends on them does so at its own risk:
  39  * they are subject to change or removal without notice.
  40  */
  41 public
  42 class SynchronizedStatement extends Statement {
  43     Expression expr;
  44     Statement body;
  45     boolean needReturnSlot;   // set by inner return statement
  46 
  47     /**
  48      * Constructor
  49      */
  50     public SynchronizedStatement(long where, Expression expr, Statement body) {
  51         super(SYNCHRONIZED, where);
  52         this.expr = expr;
  53         this.body = body;
  54     }
  55 
  56     /**
  57      * Check statement
  58      */
  59     Vset check(Environment env, Context ctx, Vset vset, Hashtable exp) {
  60         checkLabel(env, ctx);
  61         CheckContext newctx = new CheckContext(ctx, this);
  62         vset = reach(env, vset);
  63         vset = expr.checkValue(env, newctx, vset, exp);
  64         if (expr.type.equals(Type.tNull)) {
  65             env.error(expr.where, "synchronized.null");
  66         }
  67         expr = convert(env, newctx, Type.tClass(idJavaLangObject), expr);
  68         vset = body.check(env, newctx, vset, exp);
  69         return ctx.removeAdditionalVars(vset.join(newctx.vsBreak));
  70     }
  71 
  72     /**
  73      * Inline
  74      */
  75     public Statement inline(Environment env, Context ctx) {
  76         if (body != null) {
  77             body = body.inline(env, ctx);
  78         }
  79         expr = expr.inlineValue(env, ctx);
  80         return this;
  81     }
  82 
  83     /**
  84      * Create a copy of the statement for method inlining
  85      */
  86     public Statement copyInline(Context ctx, boolean valNeeded) {
  87         SynchronizedStatement s = (SynchronizedStatement)clone();
  88         s.expr = expr.copyInline(ctx);
  89         if (body != null) {
  90             s.body = body.copyInline(ctx, valNeeded);
  91         }
  92         return s;
  93     }
  94 
  95     /**
  96      * Compute cost of inlining this statement
  97      */
  98     public int costInline(int thresh, Environment env, Context ctx){
  99         int cost = 1;
 100         if (expr != null) {
 101             cost += expr.costInline(thresh, env,ctx);
 102             if (cost >= thresh) return cost;
 103         }
 104         if (body != null) {
 105             cost += body.costInline(thresh, env,ctx);
 106         }
 107         return cost;
 108     }
 109 
 110     /**
 111      * Code
 112      */
 113     public void code(Environment env, Context ctx, Assembler asm) {
 114         ClassDefinition clazz = ctx.field.getClassDefinition();
 115         expr.codeValue(env, ctx, asm);
 116         ctx = new Context(ctx);
 117 
 118         if (needReturnSlot) {
 119             Type returnType = ctx.field.getType().getReturnType();
 120             LocalMember localfield = new LocalMember(0, clazz, 0, returnType,
 121                                                    idFinallyReturnValue);
 122             ctx.declare(env, localfield);
 123             env.debugOutput("Assigning return slot to " + localfield.number);
 124         }
 125 
 126         LocalMember f1 = new LocalMember(where, clazz, 0, Type.tObject, null);
 127         LocalMember f2 = new LocalMember(where, clazz, 0, Type.tInt, null);
 128         Integer num1 = new Integer(ctx.declare(env, f1));
 129         Integer num2 = new Integer(ctx.declare(env, f2));
 130 
 131         Label endLabel = new Label();
 132 
 133         TryData td = new TryData();
 134         td.add(null);
 135 
 136         // lock the object
 137         asm.add(where, opc_astore, num1);
 138         asm.add(where, opc_aload, num1);
 139         asm.add(where, opc_monitorenter);
 140 
 141         // Main body
 142         CodeContext bodyctx = new CodeContext(ctx, this);
 143         asm.add(where, opc_try, td);
 144         if (body != null) {
 145             body.code(env, bodyctx, asm);
 146         } else {
 147             asm.add(where, opc_nop);
 148         }
 149         asm.add(bodyctx.breakLabel);
 150         asm.add(td.getEndLabel());
 151 
 152         // Cleanup afer body
 153         asm.add(where, opc_aload, num1);
 154         asm.add(where, opc_monitorexit);
 155         asm.add(where, opc_goto, endLabel);
 156 
 157         // Catch code
 158         CatchData cd = td.getCatch(0);
 159         asm.add(cd.getLabel());
 160         asm.add(where, opc_aload, num1);
 161         asm.add(where, opc_monitorexit);
 162         asm.add(where, opc_athrow);
 163 
 164         // Final body
 165         asm.add(bodyctx.contLabel);
 166         asm.add(where, opc_astore, num2);
 167         asm.add(where, opc_aload, num1);
 168         asm.add(where, opc_monitorexit);
 169         asm.add(where, opc_ret, num2);
 170 
 171         asm.add(endLabel);
 172     }
 173 
 174     /**
 175      * Print
 176      */
 177     public void print(PrintStream out, int indent) {
 178         super.print(out, indent);
 179         out.print("synchronized ");
 180         expr.print(out);
 181         out.print(" ");
 182         if (body != null) {
 183             body.print(out, indent);
 184         } else {
 185             out.print("{}");
 186         }
 187     }
 188 }