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 | } |