Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/derby/impl/services/bytecode/BCJava.java


1   /*
2   
3      Derby - Class org.apache.derby.impl.services.bytecode.BCJava
4   
5      Copyright 1997, 2004 The Apache Software Foundation or its licensors, as applicable.
6   
7      Licensed under the Apache License, Version 2.0 (the "License");
8      you may not use this file except in compliance with the License.
9      You may obtain a copy of the License at
10  
11        http://www.apache.org/licenses/LICENSE-2.0
12  
13     Unless required by applicable law or agreed to in writing, software
14     distributed under the License is distributed on an "AS IS" BASIS,
15     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16     See the License for the specific language governing permissions and
17     limitations under the License.
18  
19   */
20  
21  package org.apache.derby.impl.services.bytecode;
22  
23  import org.apache.derby.iapi.services.compiler.JavaFactory;
24  import org.apache.derby.iapi.services.compiler.ClassBuilder;
25  import org.apache.derby.iapi.services.compiler.MethodBuilder;
26  import org.apache.derby.iapi.services.loader.ClassFactory;
27  import org.apache.derby.iapi.services.classfile.ClassHolder;
28  
29  import org.apache.derby.iapi.services.cache.Cacheable;
30  import org.apache.derby.iapi.services.cache.CacheableFactory;
31  
32  import org.apache.derby.iapi.services.cache.CacheFactory;
33  import org.apache.derby.iapi.services.cache.CacheManager;
34  
35  import org.apache.derby.iapi.services.monitor.Monitor;
36  import org.apache.derby.iapi.services.monitor.ModuleControl;
37  
38  import org.apache.derby.iapi.error.StandardException;
39  
40  import org.apache.derby.iapi.services.sanity.SanityManager;
41  
42  import org.apache.derby.iapi.services.classfile.VMDescriptor;
43  
44  import java.util.Properties;
45  import java.util.Hashtable;
46  
47  /**
48    <p>
49    <b>Debugging problems with generated classes</b>
50    <p>
51    When the code has been generated incorrectly, all sorts of
52    odd things can go wrong.  This is one recommended approach to
53    finding the problem.
54    <p>
55    First, turn on ByteCodeGenInstr and DumpClassFile. Look
56    for missing files (right now they are consecutively numbered
57    by the activation class builder; later on they won't be, but
58    BytCodeGenInstr dumps messages about the classes it has).
59    Look at the log to make sure that all "GEN starting class/method"
60    messages are paired with a "GEN ending class/method" message.
61    If a file is missing or the pairing is missing, then something
62    went wrong when the system tried to generate the bytecodes.
63    Resort to your favorite debugging tool to step through
64    the faulty statement.
65    <p>
66    If you get class files but the system crashes on you (I had
67    an OS segmentation fault once) or you get funny messages like
68    JDBC Excpetion: ac5 where ac5 is just the name of a generated
69    class, then one of the following is likely:
70    <ul>
71    <li> you are calling INVOKEVIRTUAL when
72         you are supposed to call INVOKEINTERFACE
73    <li> you have an inexact match on a method argument or
74         return type.
75    <li> you are trying to get to a superclass's field using
76         a subclass.
77    </ul>
78    The best way to locate the problem here is to do this (replace
79    ac5.class with the name of your class file):
80    <ol>
81    <li> javap -c -v ac5 >ac5.gp<br>
82       if javap reports "Class not found", and the file ac5.class does
83       exist in the current directory, then the .class file is probably
84       corrupt.  Try running mocha on it to see if that works. The
85       problem will be in the code that generates the entries for
86       the class file -- most likely the ConstantPool is bad, an
87       attribute got created incorrectly, or
88       perhaps the instruction streams are goofed up.
89    <li> java mocha.Decompiler ac5.class<br>
90         if mocha cannot create good java source, then you really
91         need to go back and examine the calls creating the java 
92         constructs; a parameter might have been null when it should
93         have, a call to turn an expression into a statement may be
94         missing, or something else may be wrong.
95    <li> mv ac5.mocha ac5.java
96    <li> vi ac5.java ; you will have to fix any new SQLBoolean(1, ...)
97         calls to be new SQLBoolean(true, ...).  Also mocha 
98         occasionally messes up other stuff too.  Just iterate on it
99         until it builds or you figure out what is wrong with
100        the generated code.
101   <li> javac ac5.java
102   <li> javap -v -c ac5 >ac5.jp
103   <li> sed '1,$s/#[0-9]* </# </' ac5.gp > ac5.gn
104   <li> sed '1,$s/#[0-9]* </# </' ac5.jp > ac5.jn<br>
105        These seds are to get rid of constant pool entry numbers,
106        which will be wildly different on the two files.
107   <li> vdiff32 ac5.gn ac5.jn<br>
108        this tool shows you side-by-side diffs.  If you change
109        to the window that interleaves the diffs, you can see the 
110        length of the line.  Look for places where there are
111        invokevirtual vs. invokeinterface differences, differences
112        in the class name of a field, differences in the class name
113        of a method parameter or return type.  The generated code
114        *will* have some unavoidable differences from the
115        compiled code, such as:
116        <ul>
117        <li> it will have goto's at the end of try blocks
118       rather than return's.
119        <li> it will do a getstatic on a static final field
120       rather than inlining the static final field's value
121        <li> it will have more checkcast's in it, since it
122       doesn't see if the checkcast will always succeed
123       and thus remove it.
124        </ul>
125        Once you find a diff, you need to track down where
126        the call was generated and modify it appropriately:
127        change newMethodCall to newInterfaceMethodCall;
128        add newCastExpression to get a argument into the right
129        type for the parameter; ensure the return type given for
130        the method is its declared return type.
131   </ol>
132   @see org.apache.derby.iapi.services.compiler.JavaFactory
133 
134   @author ames
135  */
136 public class BCJava implements JavaFactory, CacheableFactory, ModuleControl {
137 
138   //////////////////////////////////////////////////////////////
139   //  
140   //  MEMBERS
141   //
142   //////////////////////////////////////////////////////////////
143 
144   /* Cache of Java class names versus VM type names */
145   private CacheManager  vmTypeIdCache;
146 
147   //
148   // class interface
149   //
150   public BCJava() {
151   }
152 
153   //
154   // ModuleControl interface
155   //
156   /**
157     Start this module. We need a read/write version of the class utilities
158 
159     @exception StandardException standard cloudscape policy
160    */
161   public void boot(boolean create, Properties properties) throws StandardException {
162 
163     CacheFactory cf =
164       (CacheFactory) Monitor.startSystemModule(org.apache.derby.iapi.reference.Module.CacheFactory);
165 
166     /*
167     ** The initial and maximum cache sizes are based on experiments
168     ** that I did with some of the language tests.  I found that
169     ** the size quickly grew to about 40, then continued to grow
170     ** slowly after that.
171     **
172     **      -  Jeff
173     */
174     vmTypeIdCache =
175       cf.newCacheManager(
176         this,
177         "VMTypeIdCache",
178         64,
179         256);
180   }
181 
182   /**
183     Stop this module.  In this case, nothing needs to be done.
184    */
185   public void stop() {
186   }
187 
188   //
189   // JavaFactory interface
190   //
191 
192   /**
193    * a class.  Once it is created, fields, methods,
194    * interfaces, static initialization code, 
195    * and constructors can be added to it.
196    * <verbatim>
197      Java: package #packageName;
198        #modifiers #className extends #superClass { }
199         // modifiers is the | of the JVM constants for
200         // the modifiers such as static, public, etc.
201      </verbatim>
202    *
203    * @see java.lang.reflect.Modifiers
204    * @param packageName the name of the package the class is in.
205    *  null if it is in the default package.
206    * @param modifiers the | of the Modifiers
207    *  constants representing the visibility and control of this
208    *  method.
209    * @param className the name of the class or interface
210    * @param superClass the name of the superclass or superinterface
211    *
212    * @return the class builder.
213    */
214   public ClassBuilder newClassBuilder(ClassFactory cf, String packageName,
215     int modifiers, String className, String superClass) {
216     
217     return new BCClass(cf, packageName, modifiers, className, superClass, this);
218   }
219 
220   /*
221   ** CacheableFactory interface
222   */
223   public Cacheable newCacheable(CacheManager cm) {
224     return new VMTypeIdCacheable();
225   }
226 
227   ///////////////////////////////////////////
228   //
229   // UTILITIES specific to this implementation
230   //
231   ////////////////////////////////////////////
232 
233   /**
234    * Get the VM Type ID that corresponds with the given java type name.
235    * This uses the cache of VM type ids.
236    *
237    * @param javaType  The java type name to translate to a java VM type id
238    *
239    * @return    The java VM type ID
240    */
241   Type type(String javaType) {
242 
243     Type retval;
244 
245     try {
246 
247       VMTypeIdCacheable vtic = (VMTypeIdCacheable) vmTypeIdCache.find(javaType);
248 
249       retval = (Type) vtic.descriptor();
250 
251       vmTypeIdCache.release(vtic);
252 
253       return retval;
254 
255     } catch (StandardException se) {
256       if (SanityManager.DEBUG) {
257         SanityManager.THROWASSERT("Unexpected exception " + se, se);
258       }
259 
260       /*
261       ** If we're running a sane server, let's act as if the
262       ** exception didn't happen, and just get the vmTypeId the
263       ** slow way, without caching.
264       */
265       retval = new Type(javaType, ClassHolder.convertToInternalDescriptor(javaType));
266     }
267 
268     return retval;
269   }
270 
271   String vmType(BCMethodDescriptor md) {
272     String retval;
273 
274     try {
275 
276       VMTypeIdCacheable vtic = (VMTypeIdCacheable) vmTypeIdCache.find(md);
277 
278       retval = vtic.descriptor().toString();
279 
280       vmTypeIdCache.release(vtic);
281 
282     } catch (StandardException se) {
283       if (SanityManager.DEBUG) {
284         SanityManager.THROWASSERT("Unexpected exception " + se, se);
285       }
286 
287       /*
288       ** If we're running a sane server, let's act as if the
289       ** exception didn't happen, and just get the vmTypeId the
290       ** slow way, without caching.
291       */
292       retval = md.buildMethodDescriptor();
293     }
294 
295     return retval;
296   }
297   /**
298    * Map vm types as strings to vm types as the VM
299    * handles, with int ids. Used in mapping opcodes
300    * based on type of operand/stack entry available.
301    */
302   static short vmTypeId(String vmTypeS) {
303     char vmTypeC = vmTypeS.charAt(0);
304     switch(vmTypeC) {
305       case VMDescriptor.C_CLASS : return BCExpr.vm_reference;
306       case VMDescriptor.C_BYTE : return BCExpr.vm_byte;
307       case VMDescriptor.C_CHAR : return BCExpr.vm_char;
308       case VMDescriptor.C_DOUBLE : return BCExpr.vm_double;
309       case VMDescriptor.C_FLOAT : return BCExpr.vm_float;
310       case VMDescriptor.C_INT : return BCExpr.vm_int;
311       case VMDescriptor.C_LONG : return BCExpr.vm_long;
312       case VMDescriptor.C_SHORT : return BCExpr.vm_short;
313       case VMDescriptor.C_BOOLEAN : return BCExpr.vm_int;
314       case VMDescriptor.C_ARRAY : return BCExpr.vm_reference;
315       case VMDescriptor.C_VOID : return BCExpr.vm_void;
316       default: 
317         if (SanityManager.DEBUG)
318         SanityManager.THROWASSERT("No type match for "+vmTypeS);
319     }
320     return BCExpr.vm_void;
321   }
322 }