001: /*
002:
003: Derby - Class org.apache.derby.impl.services.bytecode.BCJava
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.services.bytecode;
023:
024: import org.apache.derby.iapi.services.compiler.JavaFactory;
025: import org.apache.derby.iapi.services.compiler.ClassBuilder;
026: import org.apache.derby.iapi.services.compiler.MethodBuilder;
027: import org.apache.derby.iapi.services.loader.ClassFactory;
028: import org.apache.derby.iapi.services.classfile.ClassHolder;
029:
030: import org.apache.derby.iapi.services.cache.Cacheable;
031: import org.apache.derby.iapi.services.cache.CacheableFactory;
032:
033: import org.apache.derby.iapi.services.cache.CacheFactory;
034: import org.apache.derby.iapi.services.cache.CacheManager;
035:
036: import org.apache.derby.iapi.services.monitor.Monitor;
037: import org.apache.derby.iapi.services.monitor.ModuleControl;
038:
039: import org.apache.derby.iapi.error.StandardException;
040:
041: import org.apache.derby.iapi.services.sanity.SanityManager;
042:
043: import org.apache.derby.iapi.services.classfile.VMDescriptor;
044:
045: import java.util.Properties;
046: import java.util.Hashtable;
047:
048: /**
049: <p>
050: <b>Debugging problems with generated classes</b>
051: <p>
052: When the code has been generated incorrectly, all sorts of
053: odd things can go wrong. This is one recommended approach to
054: finding the problem.
055: <p>
056: First, turn on ByteCodeGenInstr and DumpClassFile. Look
057: for missing files (right now they are consecutively numbered
058: by the activation class builder; later on they won't be, but
059: BytCodeGenInstr dumps messages about the classes it has).
060: Look at the log to make sure that all "GEN starting class/method"
061: messages are paired with a "GEN ending class/method" message.
062: If a file is missing or the pairing is missing, then something
063: went wrong when the system tried to generate the bytecodes.
064: Resort to your favorite debugging tool to step through
065: the faulty statement.
066: <p>
067: If you get class files but the system crashes on you (I had
068: an OS segmentation fault once) or you get funny messages like
069: JDBC Excpetion: ac5 where ac5 is just the name of a generated
070: class, then one of the following is likely:
071: <ul>
072: <li> you are calling INVOKEVIRTUAL when
073: you are supposed to call INVOKEINTERFACE
074: <li> you have an inexact match on a method argument or
075: return type.
076: <li> you are trying to get to a superclass's field using
077: a subclass.
078: </ul>
079: The best way to locate the problem here is to do this (replace
080: ac5.class with the name of your class file):
081: <ol>
082: <li> javap -c -v ac5 >ac5.gp<br>
083: if javap reports "Class not found", and the file ac5.class does
084: exist in the current directory, then the .class file is probably
085: corrupt. Try running mocha on it to see if that works. The
086: problem will be in the code that generates the entries for
087: the class file -- most likely the ConstantPool is bad, an
088: attribute got created incorrectly, or
089: perhaps the instruction streams are goofed up.
090: <li> java mocha.Decompiler ac5.class<br>
091: if mocha cannot create good java source, then you really
092: need to go back and examine the calls creating the java
093: constructs; a parameter might have been null when it should
094: have, a call to turn an expression into a statement may be
095: missing, or something else may be wrong.
096: <li> mv ac5.mocha ac5.java
097: <li> vi ac5.java ; you will have to fix any new SQLBoolean(1, ...)
098: calls to be new SQLBoolean(true, ...). Also mocha
099: occasionally messes up other stuff too. Just iterate on it
100: until it builds or you figure out what is wrong with
101: the generated code.
102: <li> javac ac5.java
103: <li> javap -v -c ac5 >ac5.jp
104: <li> sed '1,$s/#[0-9]* </# </' ac5.gp > ac5.gn
105: <li> sed '1,$s/#[0-9]* </# </' ac5.jp > ac5.jn<br>
106: These seds are to get rid of constant pool entry numbers,
107: which will be wildly different on the two files.
108: <li> vdiff32 ac5.gn ac5.jn<br>
109: this tool shows you side-by-side diffs. If you change
110: to the window that interleaves the diffs, you can see the
111: length of the line. Look for places where there are
112: invokevirtual vs. invokeinterface differences, differences
113: in the class name of a field, differences in the class name
114: of a method parameter or return type. The generated code
115: *will* have some unavoidable differences from the
116: compiled code, such as:
117: <ul>
118: <li> it will have goto's at the end of try blocks
119: rather than return's.
120: <li> it will do a getstatic on a static final field
121: rather than inlining the static final field's value
122: <li> it will have more checkcast's in it, since it
123: doesn't see if the checkcast will always succeed
124: and thus remove it.
125: </ul>
126: Once you find a diff, you need to track down where
127: the call was generated and modify it appropriately:
128: change newMethodCall to newInterfaceMethodCall;
129: add newCastExpression to get a argument into the right
130: type for the parameter; ensure the return type given for
131: the method is its declared return type.
132: </ol>
133: @see org.apache.derby.iapi.services.compiler.JavaFactory
134:
135: @author ames
136: */
137: public class BCJava implements JavaFactory, CacheableFactory,
138: ModuleControl {
139:
140: //////////////////////////////////////////////////////////////
141: //
142: // MEMBERS
143: //
144: //////////////////////////////////////////////////////////////
145:
146: /* Cache of Java class names versus VM type names */
147: private CacheManager vmTypeIdCache;
148:
149: //
150: // class interface
151: //
152: public BCJava() {
153: }
154:
155: //
156: // ModuleControl interface
157: //
158: /**
159: Start this module. We need a read/write version of the class utilities
160:
161: @exception StandardException standard cloudscape policy
162: */
163: public void boot(boolean create, Properties properties)
164: throws StandardException {
165:
166: CacheFactory cf = (CacheFactory) Monitor
167: .startSystemModule(org.apache.derby.iapi.reference.Module.CacheFactory);
168:
169: /*
170: ** The initial and maximum cache sizes are based on experiments
171: ** that I did with some of the language tests. I found that
172: ** the size quickly grew to about 40, then continued to grow
173: ** slowly after that.
174: **
175: ** - Jeff
176: */
177: vmTypeIdCache = cf.newCacheManager(this , "VMTypeIdCache", 64,
178: 256);
179: }
180:
181: /**
182: Stop this module. In this case, nothing needs to be done.
183: */
184: public void stop() {
185: }
186:
187: //
188: // JavaFactory interface
189: //
190:
191: /**
192: * a class. Once it is created, fields, methods,
193: * interfaces, static initialization code,
194: * and constructors can be added to it.
195: * <verbatim>
196: Java: package #packageName;
197: #modifiers #className extends #superClass { }
198: // modifiers is the | of the JVM constants for
199: // the modifiers such as static, public, etc.
200: </verbatim>
201: *
202: * See java.lang.reflect.Modifiers
203: * @param packageName the name of the package the class is in.
204: * null if it is in the default package.
205: * @param modifiers the | of the Modifiers
206: * constants representing the visibility and control of this
207: * method.
208: * @param className the name of the class or interface
209: * @param superClass the name of the superclass or superinterface
210: *
211: * @return the class builder.
212: */
213: public ClassBuilder newClassBuilder(ClassFactory cf,
214: String packageName, int modifiers, String className,
215: String super Class) {
216:
217: return new BCClass(cf, packageName, modifiers, className,
218: super Class, this );
219: }
220:
221: /*
222: ** CacheableFactory interface
223: */
224: public Cacheable newCacheable(CacheManager cm) {
225: return new VMTypeIdCacheable();
226: }
227:
228: ///////////////////////////////////////////
229: //
230: // UTILITIES specific to this implementation
231: //
232: ////////////////////////////////////////////
233:
234: /**
235: * Get the VM Type ID that corresponds with the given java type name.
236: * This uses the cache of VM type ids.
237: *
238: * @param javaType The java type name to translate to a java VM type id
239: *
240: * @return The java VM type ID
241: */
242: Type type(String javaType) {
243:
244: Type retval;
245:
246: try {
247:
248: VMTypeIdCacheable vtic = (VMTypeIdCacheable) vmTypeIdCache
249: .find(javaType);
250:
251: retval = (Type) vtic.descriptor();
252:
253: vmTypeIdCache.release(vtic);
254:
255: return retval;
256:
257: } catch (StandardException se) {
258: if (SanityManager.DEBUG) {
259: SanityManager.THROWASSERT("Unexpected exception " + se,
260: se);
261: }
262:
263: /*
264: ** If we're running a sane server, let's act as if the
265: ** exception didn't happen, and just get the vmTypeId the
266: ** slow way, without caching.
267: */
268: retval = new Type(javaType, ClassHolder
269: .convertToInternalDescriptor(javaType));
270: }
271:
272: return retval;
273: }
274:
275: String vmType(BCMethodDescriptor md) {
276: String retval;
277:
278: try {
279:
280: VMTypeIdCacheable vtic = (VMTypeIdCacheable) vmTypeIdCache
281: .find(md);
282:
283: retval = vtic.descriptor().toString();
284:
285: vmTypeIdCache.release(vtic);
286:
287: } catch (StandardException se) {
288: if (SanityManager.DEBUG) {
289: SanityManager.THROWASSERT("Unexpected exception " + se,
290: se);
291: }
292:
293: /*
294: ** If we're running a sane server, let's act as if the
295: ** exception didn't happen, and just get the vmTypeId the
296: ** slow way, without caching.
297: */
298: retval = md.buildMethodDescriptor();
299: }
300:
301: return retval;
302: }
303:
304: /**
305: * Map vm types as strings to vm types as the VM
306: * handles, with int ids. Used in mapping opcodes
307: * based on type of operand/stack entry available.
308: */
309: static short vmTypeId(String vmTypeS) {
310: char vmTypeC = vmTypeS.charAt(0);
311: switch (vmTypeC) {
312: case VMDescriptor.C_CLASS:
313: return BCExpr.vm_reference;
314: case VMDescriptor.C_BYTE:
315: return BCExpr.vm_byte;
316: case VMDescriptor.C_CHAR:
317: return BCExpr.vm_char;
318: case VMDescriptor.C_DOUBLE:
319: return BCExpr.vm_double;
320: case VMDescriptor.C_FLOAT:
321: return BCExpr.vm_float;
322: case VMDescriptor.C_INT:
323: return BCExpr.vm_int;
324: case VMDescriptor.C_LONG:
325: return BCExpr.vm_long;
326: case VMDescriptor.C_SHORT:
327: return BCExpr.vm_short;
328: case VMDescriptor.C_BOOLEAN:
329: return BCExpr.vm_int;
330: case VMDescriptor.C_ARRAY:
331: return BCExpr.vm_reference;
332: case VMDescriptor.C_VOID:
333: return BCExpr.vm_void;
334: default:
335: if (SanityManager.DEBUG)
336: SanityManager.THROWASSERT("No type match for "
337: + vmTypeS);
338: }
339: return BCExpr.vm_void;
340: }
341: }
|