KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > fractal > julia > asm > LifeCycleCodeGenerator


1 /***
2  * Julia: France Telecom's implementation of the Fractal API
3  * Copyright (C) 2001-2002 France Telecom R&D
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * Contact: Eric.Bruneton@rd.francetelecom.com
20  *
21  * Author: Eric Bruneton
22  */

23
24 package org.objectweb.fractal.julia.asm;
25
26 import org.objectweb.fractal.julia.InitializationContext;
27
28 import org.objectweb.asm.CodeVisitor;
29 import org.objectweb.asm.Label;
30 import org.objectweb.asm.Type;
31
32 import java.lang.reflect.Method JavaDoc;
33
34 /**
35  * A {@link CodeGenerator} to generate pre and post code
36  * to enforce the component's lifecycle. More precisely the code adapters
37  * returned by the {@link #generateInterceptionCode generateInterceptionCode}
38  * method (see {@link CodeGenerator}) transform the original methods into
39  * methods of the following form:
40  * <pre>
41  * &lt;method signature&gt; {
42  * synchronized (lc) {
43  * if (lc.fcState != 2)
44  * lc.incrementFcInvocationCounter();
45  * else
46  * lc.fcInvocationCounter++;
47  * }
48  * try {
49  * // original method code
50  * } finally {
51  * synchronized (lc) {
52  * if (lc.fcState != 2)
53  * lc.decrementFcInvocationCounter();
54  * else
55  * lc.fcInvocationCounter--;
56  * }
57  * }
58  * }
59  * </pre>
60  * The {@link #generateInitCode generateInitCode} method generates code blocks
61  * of the following form:
62  * <pre>
63  * lc = (...)ic.getInterface("lifecycle-controller");
64  * </pre>
65  * where <tt>lc</tt> is a field added to the class that is being generated (in
66  * fact, if the controller and interceptor classes are merged (see {@link
67  * InterceptorClassGenerator}), the <tt>lc</tt> field
68  * is not generated and replaced by <tt>this</tt> in the above code).
69  * <p>
70  * <b>Note:</b> as you can see the code generated by this code generator is
71  * specific to the {@link
72  * org.objectweb.fractal.julia.control.lifecycle.BasicLifeCycleControllerMixin}
73  * class (in fact the generated pre and post code blocks are a partially inlined
74  * version of the incrementFcInvocationCounter and decrementFcInvocationCounter
75  * methods of this class): it can not work if the lifecycle controller of the
76  * component, either merged or not with other controllers, does not include
77  * this mixin, or an equivalent (i.e. with a fcInvocationCounter field, and with
78  * the corresponding increment and decrement methods).
79  */

80
81 public class LifeCycleCodeGenerator extends AbstractCodeGenerator {
82
83   /**
84    * The interceptor class generator to which this code generator belongs.
85    */

86
87   private InterceptorClassGenerator icg;
88
89   /**
90    * The 'lc' field descriptor.
91    */

92
93   private String JavaDoc lcFieldDesc;
94
95   /**
96    * The 'fcState' and 'fcInvocationCounter' fields owner.
97    */

98
99   private String JavaDoc scFieldsOwner;
100
101   // -------------------------------------------------------------------------
102
// Overriden methods
103
// -------------------------------------------------------------------------
104

105   public int init (final InterceptorClassGenerator icg) {
106     this.icg = icg;
107     return IN;
108   }
109
110   public void generateInitCode (final CodeVisitor cv)
111     throws ClassGenerationException
112   {
113     // computes the internal name of the controller class
114
// that contains the 'fcInvocationCounter' field
115
String JavaDoc owner = null;
116     for (int i = 0; i < icg.controllerClasses.length; ++i) {
117       Class JavaDoc c = icg.controllerClasses[i];
118       try {
119         c.getField("fcInvocationCounter");
120         owner = c.getName();
121         break;
122       } catch (Exception JavaDoc ignored) {
123       }
124     }
125     if (owner == null) {
126       throw new ClassGenerationException(
127         null,
128         icg.args.toString(),
129         "Cannot find a controller providing a 'fcInvocationCounter' field");
130     }
131     owner = owner.replace('.', '/');
132
133     lcFieldDesc = "L" + owner + ";";
134     scFieldsOwner = owner;
135
136     icg.cw.visitField(ACC_PRIVATE, "lc", lcFieldDesc, null, null);
137
138     cv.visitVarInsn(ALOAD, 0);
139     cv.visitVarInsn(ALOAD, 1);
140     cv.visitLdcInsn("lifecycle-controller");
141     cv.visitMethodInsn(
142       INVOKEVIRTUAL,
143       Type.getInternalName(InitializationContext.class),
144       "getInterface",
145       "(Ljava/lang/String;)Ljava/lang/Object;");
146     cv.visitTypeInsn(CHECKCAST, owner);
147     cv.visitFieldInsn(PUTFIELD, icg.name, "lc", lcFieldDesc);
148   }
149
150   protected int getInterceptionType (final Method JavaDoc m) {
151     return InterceptorCodeAdapter.FINALLY;
152   }
153
154   protected int getInterceptionCodeFormals (final Method JavaDoc m) {
155     // one local variable used to store the lock for the synchronized blocks
156
return 1;
157   }
158
159   public void generateCloneCode (final CodeVisitor cv) {
160     cv.visitVarInsn(ALOAD, 1);
161     cv.visitVarInsn(ALOAD, 0);
162     cv.visitFieldInsn(GETFIELD, icg.name, "lc", lcFieldDesc);
163     cv.visitFieldInsn(PUTFIELD, icg.name, "lc", lcFieldDesc);
164   }
165
166   // -------------------------------------------------------------------------
167
// Implementation of inherited abstract methods
168
// -------------------------------------------------------------------------
169

170   protected void generateInterceptionCodeBlock (
171     final Method JavaDoc m,
172     final boolean pre,
173     final CodeVisitor cv,
174     final int formals)
175   {
176     if (scFieldsOwner == null) {
177       // if stateField is null this means generateInitCode was not called,
178
// i.e., the controller and interceptor classes are merged. We
179
// must therefore initialize stateField and counterField here, by using
180
// the fields of the generated class (in fact of its super class).
181
scFieldsOwner = icg.name;
182     }
183
184     Label beginHandler = new Label();
185     Label endHandler = new Label();
186     Label ifLabel = new Label();
187     Label endIfLabel = new Label();
188     Label endLabel = new Label();
189
190     // generates the bytecode corresponding to 'synchronized (lc) {'
191
cv.visitVarInsn(ALOAD, 0);
192     // if controller and interceptor classes are merged, the generateInitCode
193
// method is not called, and the lcFieldDesc is therefore null.
194
if (lcFieldDesc != null) {
195       cv.visitFieldInsn(GETFIELD, icg.name, "lc", lcFieldDesc);
196     }
197     cv.visitInsn(DUP);
198     cv.visitVarInsn(ASTORE, formals);
199     cv.visitInsn(MONITORENTER);
200     cv.visitLabel(beginHandler);
201
202     // generates the bytecode corresponding to 'if (lc.fcState != 2) {'
203
cv.visitVarInsn(ALOAD, 0);
204     if (lcFieldDesc != null) {
205       cv.visitFieldInsn(GETFIELD, icg.name, "lc", lcFieldDesc);
206     }
207     cv.visitFieldInsn(GETFIELD, scFieldsOwner, "fcState", "I");
208     cv.visitInsn(ICONST_2);
209     cv.visitJumpInsn(IF_ICMPEQ, ifLabel);
210
211     // generates the bytecode corresponding to 'lc.incrementInvocationCounter()'
212
cv.visitVarInsn(ALOAD, 0);
213     if (lcFieldDesc != null) {
214       cv.visitFieldInsn(GETFIELD, icg.name, "lc", lcFieldDesc);
215     }
216     cv.visitMethodInsn(
217       INVOKEVIRTUAL,
218       scFieldsOwner,
219       pre ? "incrementFcInvocationCounter" : "decrementFcInvocationCounter",
220       "()V");
221
222     // generates the bytecode corresponding to '} else {'
223
cv.visitJumpInsn(GOTO, endIfLabel);
224     cv.visitLabel(ifLabel);
225
226     // generates the bytecode corresponding to '++lc.fcInvocationCounter'
227
cv.visitVarInsn(ALOAD, 0);
228     if (lcFieldDesc != null) {
229       cv.visitFieldInsn(GETFIELD, icg.name, "lc", lcFieldDesc);
230     }
231     cv.visitInsn(DUP);
232     cv.visitFieldInsn(GETFIELD, scFieldsOwner, "fcInvocationCounter", "I");
233     cv.visitInsn(ICONST_1);
234     cv.visitInsn(pre ? IADD : ISUB);
235     cv.visitFieldInsn(PUTFIELD, scFieldsOwner, "fcInvocationCounter", "I");
236
237     // generates the bytecode corresponding to the end of the synchronized block
238
cv.visitLabel(endIfLabel);
239     cv.visitVarInsn(ALOAD, formals);
240     cv.visitInsn(MONITOREXIT);
241     cv.visitJumpInsn(GOTO, endLabel);
242     cv.visitLabel(endHandler);
243     cv.visitVarInsn(ALOAD, formals);
244     cv.visitInsn(MONITOREXIT);
245     cv.visitInsn(ATHROW);
246     cv.visitLabel(endLabel);
247
248     cv.visitTryCatchBlock(beginHandler, endHandler, endHandler, null);
249   }
250 }
251
Popular Tags