1 |
/* RMIC.java -- |
/* ASMRMIC.java -- |
2 |
Copyright (c) 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004 |
Copyright (c) 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004, 2005 |
3 |
Free Software Foundation, Inc. |
Free Software Foundation, Inc. |
4 |
|
|
5 |
This file is part of GNU Classpath. |
This file is part of GNU Classpath. |
22 |
package gnu.classpath.tools.rmi.rmic; |
package gnu.classpath.tools.rmi.rmic; |
23 |
|
|
24 |
import gnu.java.rmi.server.RMIHashes; |
import gnu.java.rmi.server.RMIHashes; |
25 |
|
import java.io.ByteArrayOutputStream; |
26 |
|
import java.io.DataOutputStream; |
27 |
import java.io.File; |
import java.io.File; |
28 |
|
import java.io.FileOutputStream; |
29 |
import java.io.FileWriter; |
import java.io.FileWriter; |
30 |
import java.io.IOException; |
import java.io.IOException; |
31 |
|
import java.io.ObjectInput; |
32 |
|
import java.io.ObjectOutput; |
33 |
import java.io.PrintWriter; |
import java.io.PrintWriter; |
34 |
import java.lang.reflect.Method; |
import java.lang.reflect.Method; |
35 |
|
import java.net.URL; |
36 |
|
import java.net.URLClassLoader; |
37 |
|
import java.rmi.MarshalException; |
38 |
|
import java.rmi.Remote; |
39 |
import java.rmi.RemoteException; |
import java.rmi.RemoteException; |
40 |
|
import java.rmi.UnexpectedException; |
41 |
|
import java.rmi.UnmarshalException; |
42 |
|
import java.rmi.server.Operation; |
43 |
|
import java.rmi.server.RemoteCall; |
44 |
|
import java.rmi.server.RemoteObject; |
45 |
|
import java.rmi.server.RemoteRef; |
46 |
|
import java.rmi.server.RemoteStub; |
47 |
|
import java.rmi.server.Skeleton; |
48 |
|
import java.rmi.server.SkeletonMismatchException; |
49 |
|
import java.security.MessageDigest; |
50 |
|
import java.util.ArrayList; |
51 |
import java.util.Arrays; |
import java.util.Arrays; |
52 |
import java.util.HashSet; |
import java.util.HashSet; |
53 |
import java.util.Iterator; |
import java.util.Iterator; |
54 |
|
import java.util.List; |
55 |
import java.util.Set; |
import java.util.Set; |
56 |
|
import java.util.StringTokenizer; |
57 |
|
import org.objectweb.asm.ClassVisitor; |
58 |
|
import org.objectweb.asm.ClassWriter; |
59 |
|
import org.objectweb.asm.CodeVisitor; |
60 |
|
import org.objectweb.asm.Constants; |
61 |
|
import org.objectweb.asm.Label; |
62 |
|
import org.objectweb.asm.Type; |
63 |
|
|
64 |
public class RMIC |
public class RMIC |
65 |
{ |
{ |
72 |
private boolean compile = true; |
private boolean compile = true; |
73 |
private boolean verbose; |
private boolean verbose; |
74 |
private String destination; |
private String destination; |
75 |
private PrintWriter out; |
private String classpath; |
76 |
private TabbedWriter ctrl; |
private ClassLoader loader; |
77 |
|
private int errorCount = 0; |
78 |
|
|
79 |
private Class clazz; |
private Class clazz; |
80 |
private String classname; |
private String classname; |
81 |
|
private String classInternalName; |
82 |
private String fullclassname; |
private String fullclassname; |
83 |
private MethodRef[] remotemethods; |
private MethodRef[] remotemethods; |
84 |
private String stubname; |
private String stubname; |
85 |
private String skelname; |
private String skelname; |
86 |
private int errorCount = 0; |
private List mRemoteInterfaces; |
87 |
private Class mRemoteInterface; |
|
88 |
|
private static class C |
89 |
|
implements Constants |
90 |
|
{ |
91 |
|
} |
92 |
|
|
93 |
public RMIC(String[] a) |
public RMIC(String[] a) |
94 |
{ |
{ |
130 |
return (true); |
return (true); |
131 |
} |
} |
132 |
|
|
133 |
private boolean processClass(String classname) throws Exception |
private boolean processClass(String cls) throws Exception |
134 |
{ |
{ |
135 |
|
// reset class specific vars |
136 |
|
clazz = null; |
137 |
|
classname = null; |
138 |
|
classInternalName = null; |
139 |
|
fullclassname = null; |
140 |
|
remotemethods = null; |
141 |
|
stubname = null; |
142 |
|
skelname = null; |
143 |
|
mRemoteInterfaces = new ArrayList(); |
144 |
|
|
145 |
errorCount = 0; |
errorCount = 0; |
146 |
analyzeClass(classname); |
|
147 |
|
analyzeClass(cls); |
148 |
if (errorCount > 0) |
if (errorCount > 0) |
149 |
System.exit(1); |
System.exit(1); |
150 |
generateStub(); |
generateStub(); |
151 |
if (need11Stubs) |
if (need11Stubs) |
152 |
generateSkel(); |
generateSkel(); |
|
if (compile) |
|
|
{ |
|
|
compile(stubname.replace('.', File.separatorChar) + ".java"); |
|
|
if (need11Stubs) |
|
|
compile(skelname.replace('.', File.separatorChar) + ".java"); |
|
|
} |
|
|
if (! keep) |
|
|
{ |
|
|
(new File(stubname.replace('.', File.separatorChar) + ".java")).delete(); |
|
|
if (need11Stubs) |
|
|
(new File(skelname.replace('.', File.separatorChar) + ".java")) |
|
|
.delete(); |
|
|
} |
|
153 |
return (true); |
return (true); |
154 |
} |
} |
155 |
|
|
164 |
classname = cname; |
classname = cname; |
165 |
fullclassname = cname; |
fullclassname = cname; |
166 |
|
|
|
HashSet rmeths = new HashSet(); |
|
167 |
findClass(); |
findClass(); |
168 |
|
findRemoteMethods(); |
|
// get the remote interface |
|
|
mRemoteInterface = getRemoteInterface(clazz); |
|
|
if (mRemoteInterface == null) |
|
|
return; |
|
|
if (verbose) |
|
|
System.out.println("[implements " + mRemoteInterface.getName() + "]"); |
|
|
|
|
|
// check if the methods of the remote interface declare RemoteExceptions |
|
|
Method[] meths = mRemoteInterface.getDeclaredMethods(); |
|
|
for (int i = 0; i < meths.length; i++) |
|
|
{ |
|
|
Class[] exceptions = meths[i].getExceptionTypes(); |
|
|
int index = 0; |
|
|
for (; index < exceptions.length; index++) |
|
|
{ |
|
|
if (exceptions[index].equals(RemoteException.class)) |
|
|
break; |
|
|
} |
|
|
if (index < exceptions.length) |
|
|
rmeths.add(meths[i]); |
|
|
else |
|
|
logError("Method " + meths[i] |
|
|
+ " does not throw a java.rmi.RemoteException"); |
|
|
} |
|
|
|
|
|
// Convert into a MethodRef array and sort them |
|
|
remotemethods = new MethodRef[rmeths.size()]; |
|
|
int c = 0; |
|
|
for (Iterator i = rmeths.iterator(); i.hasNext();) |
|
|
remotemethods[c++] = new MethodRef((Method) i.next()); |
|
|
Arrays.sort(remotemethods); |
|
169 |
} |
} |
170 |
|
|
171 |
public Exception getException() |
public Exception getException() |
173 |
return (exception); |
return (exception); |
174 |
} |
} |
175 |
|
|
176 |
private void findClass() throws ClassNotFoundException |
private void findClass() |
177 |
{ |
{ |
178 |
clazz = |
try |
179 |
Class.forName(fullclassname, true, ClassLoader.getSystemClassLoader()); |
{ |
180 |
|
ClassLoader cl = (loader == null |
181 |
|
? ClassLoader.getSystemClassLoader() |
182 |
|
: loader); |
183 |
|
clazz = Class.forName(fullclassname, false, cl); |
184 |
|
} |
185 |
|
catch (ClassNotFoundException cnfe) |
186 |
|
{ |
187 |
|
System.err.println(fullclassname + " not found in " + classpath); |
188 |
|
throw new RuntimeException(cnfe); |
189 |
|
} |
190 |
|
|
191 |
|
if (! Remote.class.isAssignableFrom(clazz)) |
192 |
|
{ |
193 |
|
logError("Class " + clazz.getName() + " is not a remote object. " |
194 |
|
+ "It does not implement an interface that is a " |
195 |
|
+ "java.rmi.Remote-interface."); |
196 |
|
throw new RuntimeException |
197 |
|
("Class " + clazz.getName() + " is not a remote object. " |
198 |
|
+ "It does not implement an interface that is a " |
199 |
|
+ "java.rmi.Remote-interface."); |
200 |
|
} |
201 |
} |
} |
202 |
|
|
203 |
private void generateStub() throws IOException |
private static Type[] typeArray(Class[] cls) |
204 |
{ |
{ |
205 |
stubname = fullclassname + "_Stub"; |
Type[] t = new Type[cls.length]; |
206 |
String stubclassname = classname + "_Stub"; |
for (int i = 0; i < cls.length; i++) |
|
ctrl = |
|
|
new TabbedWriter(new FileWriter((destination == null ? "" |
|
|
: destination |
|
|
+ File.separator) |
|
|
+ stubname.replace('.', |
|
|
File.separatorChar) |
|
|
+ ".java")); |
|
|
out = new PrintWriter(ctrl); |
|
|
|
|
|
if (verbose) |
|
|
System.out.println("[Generating class " + stubname + ".java]"); |
|
|
|
|
|
out.println("// Stub class generated by rmic - DO NOT EDIT!"); |
|
|
out.println(); |
|
|
if (fullclassname != classname) |
|
207 |
{ |
{ |
208 |
String pname = |
t[i] = Type.getType(cls[i]); |
|
fullclassname.substring(0, fullclassname.lastIndexOf('.')); |
|
|
out.println("package " + pname + ";"); |
|
|
out.println(); |
|
209 |
} |
} |
210 |
|
|
211 |
out.print("public final class " + stubclassname); |
return t; |
212 |
ctrl.indent(); |
} |
|
out.println("extends java.rmi.server.RemoteStub"); |
|
213 |
|
|
214 |
// Output interfaces we implement |
private static String[] internalNameArray(Type[] t) |
215 |
out.print("implements "); |
{ |
216 |
/* Scan implemented interfaces, and only print remote interfaces. */ |
String[] s = new String[t.length]; |
217 |
Class[] ifaces = clazz.getInterfaces(); |
for (int i = 0; i < t.length; i++) |
|
Set remoteIfaces = new HashSet(); |
|
|
for (int i = 0; i < ifaces.length; i++) |
|
218 |
{ |
{ |
219 |
Class iface = ifaces[i]; |
s[i] = t[i].getInternalName(); |
|
if (java.rmi.Remote.class.isAssignableFrom(iface)) |
|
|
remoteIfaces.add(iface); |
|
220 |
} |
} |
|
Iterator iter = remoteIfaces.iterator(); |
|
|
while (iter.hasNext()) |
|
|
{ |
|
|
/* Print remote interface. */ |
|
|
Class iface = (Class) iter.next(); |
|
|
out.print(iface.getName()); |
|
221 |
|
|
222 |
/* Print ", " if more remote interfaces follow. */ |
return s; |
223 |
if (iter.hasNext()) |
} |
|
out.print(", "); |
|
|
} |
|
|
ctrl.unindent(); |
|
|
out.print("{"); |
|
|
ctrl.indent(); |
|
224 |
|
|
225 |
// UID |
private static String[] internalNameArray(Class[] c) |
226 |
if (need12Stubs) |
{ |
227 |
|
return internalNameArray(typeArray(c)); |
228 |
|
} |
229 |
|
|
230 |
|
private static final String forName = "class$"; |
231 |
|
|
232 |
|
private static Object param(Method m, int argIndex) |
233 |
|
{ |
234 |
|
List l = new ArrayList(); |
235 |
|
l.add(m); |
236 |
|
l.add(new Integer(argIndex)); |
237 |
|
return l; |
238 |
|
} |
239 |
|
|
240 |
|
private static void generateClassForNamer(ClassVisitor cls) |
241 |
|
{ |
242 |
|
CodeVisitor cv = |
243 |
|
cls.visitMethod |
244 |
|
(C.ACC_PRIVATE + C.ACC_STATIC + C.ACC_SYNTHETIC, forName, |
245 |
|
Type.getMethodDescriptor |
246 |
|
(Type.getType(Class.class), new Type[] { Type.getType(String.class) }), |
247 |
|
null, null); |
248 |
|
|
249 |
|
Label start = new Label(); |
250 |
|
cv.visitLabel(start); |
251 |
|
cv.visitVarInsn(C.ALOAD, 0); |
252 |
|
cv.visitMethodInsn |
253 |
|
(C.INVOKESTATIC, |
254 |
|
Type.getInternalName(Class.class), |
255 |
|
"forName", |
256 |
|
Type.getMethodDescriptor |
257 |
|
(Type.getType(Class.class), new Type[] { Type.getType(String.class) })); |
258 |
|
cv.visitInsn(C.ARETURN); |
259 |
|
|
260 |
|
Label handler = new Label(); |
261 |
|
cv.visitLabel(handler); |
262 |
|
cv.visitVarInsn(C.ASTORE, 1); |
263 |
|
cv.visitTypeInsn(C.NEW, typeArg(NoClassDefFoundError.class)); |
264 |
|
cv.visitInsn(C.DUP); |
265 |
|
cv.visitVarInsn(C.ALOAD, 1); |
266 |
|
cv.visitMethodInsn |
267 |
|
(C.INVOKEVIRTUAL, |
268 |
|
Type.getInternalName(ClassNotFoundException.class), |
269 |
|
"getMessage", |
270 |
|
Type.getMethodDescriptor(Type.getType(String.class), new Type[] {})); |
271 |
|
cv.visitMethodInsn |
272 |
|
(C.INVOKESPECIAL, |
273 |
|
Type.getInternalName(NoClassDefFoundError.class), |
274 |
|
"<init>", |
275 |
|
Type.getMethodDescriptor |
276 |
|
(Type.VOID_TYPE, new Type[] { Type.getType(String.class) })); |
277 |
|
cv.visitInsn(C.ATHROW); |
278 |
|
cv.visitTryCatchBlock |
279 |
|
(start, handler, handler, |
280 |
|
Type.getInternalName(ClassNotFoundException.class)); |
281 |
|
cv.visitMaxs(-1, -1); |
282 |
|
} |
283 |
|
|
284 |
|
private void generateClassConstant(CodeVisitor cv, Class cls) { |
285 |
|
if (cls.isPrimitive()) |
286 |
{ |
{ |
287 |
out.println("private static final long serialVersionUID = 2L;"); |
Class boxCls; |
288 |
out.println(); |
if (cls.equals(Boolean.TYPE)) |
289 |
|
boxCls = Boolean.class; |
290 |
|
else if (cls.equals(Character.TYPE)) |
291 |
|
boxCls = Character.class; |
292 |
|
else if (cls.equals(Byte.TYPE)) |
293 |
|
boxCls = Byte.class; |
294 |
|
else if (cls.equals(Short.TYPE)) |
295 |
|
boxCls = Short.class; |
296 |
|
else if (cls.equals(Integer.TYPE)) |
297 |
|
boxCls = Integer.class; |
298 |
|
else if (cls.equals(Long.TYPE)) |
299 |
|
boxCls = Long.class; |
300 |
|
else if (cls.equals(Float.TYPE)) |
301 |
|
boxCls = Float.class; |
302 |
|
else if (cls.equals(Double.TYPE)) |
303 |
|
boxCls = Double.class; |
304 |
|
else if (cls.equals(Void.TYPE)) |
305 |
|
boxCls = Void.class; |
306 |
|
else |
307 |
|
throw new IllegalArgumentException("unknown primitive type " + cls); |
308 |
|
|
309 |
|
cv.visitFieldInsn |
310 |
|
(C.GETSTATIC, Type.getInternalName(boxCls), "TYPE", |
311 |
|
Type.getDescriptor(Class.class)); |
312 |
|
return; |
313 |
|
} |
314 |
|
cv.visitLdcInsn(cls.getName()); |
315 |
|
cv.visitMethodInsn |
316 |
|
(C.INVOKESTATIC, classInternalName, forName, |
317 |
|
Type.getMethodDescriptor |
318 |
|
(Type.getType(Class.class), |
319 |
|
new Type[] { Type.getType(String.class) })); |
320 |
|
} |
321 |
|
|
322 |
|
private void generateClassArray(CodeVisitor code, Class[] classes) |
323 |
|
{ |
324 |
|
code.visitLdcInsn(new Integer(classes.length)); |
325 |
|
code.visitTypeInsn(C.ANEWARRAY, typeArg(Class.class)); |
326 |
|
for (int i = 0; i < classes.length; i++) |
327 |
|
{ |
328 |
|
code.visitInsn(C.DUP); |
329 |
|
code.visitLdcInsn(new Integer(i)); |
330 |
|
generateClassConstant(code, classes[i]); |
331 |
|
code.visitInsn(C.AASTORE); |
332 |
} |
} |
333 |
|
} |
334 |
|
|
335 |
// InterfaceHash - don't know how to calculate this - XXX |
private void fillOperationArray(CodeVisitor clinit) |
336 |
if (need11Stubs) |
{ |
337 |
|
// Operations array |
338 |
|
clinit.visitLdcInsn(new Integer(remotemethods.length)); |
339 |
|
clinit.visitTypeInsn(C.ANEWARRAY, typeArg(Operation.class)); |
340 |
|
clinit.visitFieldInsn |
341 |
|
(C.PUTSTATIC, classInternalName, "operations", |
342 |
|
Type.getDescriptor(Operation[].class)); |
343 |
|
|
344 |
|
for (int i = 0; i < remotemethods.length; i++) |
345 |
{ |
{ |
346 |
out.println("private static final long interfaceHash = " |
Method m = remotemethods[i].meth; |
|
+ RMIHashes.getInterfaceHash(clazz) + "L;"); |
|
|
out.println(); |
|
|
if (need12Stubs) |
|
|
{ |
|
|
out.println("private static boolean useNewInvoke;"); |
|
|
out.println(); |
|
|
} |
|
347 |
|
|
348 |
// Operation table |
StringBuffer desc = new StringBuffer(); |
349 |
out.print("private static final java.rmi.server.Operation[] operations = {"); |
desc.append(getPrettyName(m.getReturnType()) + " "); |
350 |
|
desc.append(m.getName() + "("); |
351 |
|
|
352 |
|
// signature |
353 |
|
Class[] sig = m.getParameterTypes(); |
354 |
|
for (int j = 0; j < sig.length; j++) |
355 |
|
{ |
356 |
|
desc.append(getPrettyName(sig[j])); |
357 |
|
if (j + 1 < sig.length) |
358 |
|
desc.append(", "); |
359 |
|
} |
360 |
|
|
361 |
|
// push operations array |
362 |
|
clinit.visitFieldInsn |
363 |
|
(C.GETSTATIC, classInternalName, "operations", |
364 |
|
Type.getDescriptor(Operation[].class)); |
365 |
|
|
366 |
|
// push array index |
367 |
|
clinit.visitLdcInsn(new Integer(i)); |
368 |
|
|
369 |
|
// instantiate operation and leave a copy on the stack |
370 |
|
clinit.visitTypeInsn(C.NEW, typeArg(Operation.class)); |
371 |
|
clinit.visitInsn(C.DUP); |
372 |
|
clinit.visitLdcInsn(desc.toString()); |
373 |
|
clinit.visitMethodInsn |
374 |
|
(C.INVOKESPECIAL, |
375 |
|
Type.getInternalName(Operation.class), |
376 |
|
"<init>", |
377 |
|
Type.getMethodDescriptor |
378 |
|
(Type.VOID_TYPE, new Type[] { Type.getType(String.class) })); |
379 |
|
|
380 |
ctrl.indent(); |
// store in operations array |
381 |
for (int i = 0; i < remotemethods.length; i++) |
clinit.visitInsn(C.AASTORE); |
|
{ |
|
|
Method m = remotemethods[i].meth; |
|
|
out.print("new java.rmi.server.Operation(\""); |
|
|
out.print(getPrettyName(m.getReturnType()) + " "); |
|
|
out.print(m.getName() + "("); |
|
|
// Output signature |
|
|
Class[] sig = m.getParameterTypes(); |
|
|
for (int j = 0; j < sig.length; j++) |
|
|
{ |
|
|
out.print(getPrettyName(sig[j])); |
|
|
if (j + 1 < sig.length) |
|
|
out.print(", "); |
|
|
} |
|
|
out.print(")\")"); |
|
|
if (i + 1 < remotemethods.length) |
|
|
out.println(","); |
|
|
} |
|
|
ctrl.unindent(); |
|
|
out.println("};"); |
|
|
out.println(); |
|
382 |
} |
} |
383 |
|
} |
384 |
|
|
385 |
// Set of method references. |
private void generateStaticMethodObjs(CodeVisitor clinit) |
386 |
if (need12Stubs) |
{ |
387 |
|
for (int i = 0; i < remotemethods.length; i++) |
388 |
{ |
{ |
389 |
for (int i = 0; i < remotemethods.length; i++) |
Method m = remotemethods[i].meth; |
|
{ |
|
|
Method m = remotemethods[i].meth; |
|
|
out.println("private static java.lang.reflect.Method $method_" |
|
|
+ m.getName() + "_" + i + ";"); |
|
|
} |
|
|
|
|
|
// Initialize the methods references. |
|
|
out.println(); |
|
|
out.print("static {"); |
|
|
ctrl.indent(); |
|
390 |
|
|
391 |
out.print("try {"); |
/* |
392 |
ctrl.indent(); |
* $method_<i>m.getName()</i>_<i>i</i> = |
393 |
|
* <i>m.getDeclaringClass()</i>.class.getMethod |
394 |
|
* (m.getName(), m.getParameterType()) |
395 |
|
*/ |
396 |
|
String methodVar = "$method_" + m.getName() + "_" + i; |
397 |
|
generateClassConstant(clinit, m.getDeclaringClass()); |
398 |
|
clinit.visitLdcInsn(m.getName()); |
399 |
|
generateClassArray(clinit, m.getParameterTypes()); |
400 |
|
clinit.visitMethodInsn |
401 |
|
(C.INVOKEVIRTUAL, |
402 |
|
Type.getInternalName(Class.class), |
403 |
|
"getMethod", |
404 |
|
Type.getMethodDescriptor |
405 |
|
(Type.getType(Method.class), |
406 |
|
new Type[] { Type.getType(String.class), |
407 |
|
Type.getType(Class[].class) })); |
408 |
|
|
409 |
|
clinit.visitFieldInsn |
410 |
|
(C.PUTSTATIC, classInternalName, methodVar, |
411 |
|
Type.getDescriptor(Method.class)); |
412 |
|
} |
413 |
|
} |
414 |
|
|
415 |
if (need11Stubs) |
private void generateStub() throws IOException |
416 |
{ |
{ |
417 |
out.println("java.rmi.server.RemoteRef.class.getMethod(\"invoke\", new java.lang.Class[] { java.rmi.Remote.class, java.lang.reflect.Method.class, java.lang.Object[].class, long.class });"); |
stubname = fullclassname + "_Stub"; |
418 |
out.println("useNewInvoke = true;"); |
String stubclassname = classname + "_Stub"; |
419 |
} |
File file = new File((destination == null ? "." : destination) |
420 |
|
+ File.separator |
421 |
|
+ stubname.replace('.', File.separatorChar) |
422 |
|
+ ".class"); |
423 |
|
|
424 |
for (int i = 0; i < remotemethods.length; i++) |
if (verbose) |
425 |
{ |
System.out.println("[Generating class " + stubname + "]"); |
|
Method m = remotemethods[i].meth; |
|
|
out.print("$method_" + m.getName() + "_" + i + " = "); |
|
|
out.print(mRemoteInterface.getName() + ".class.getMethod(\"" |
|
|
+ m.getName() + "\""); |
|
|
out.print(", new java.lang.Class[] {"); |
|
|
// Output signature |
|
|
Class[] sig = m.getParameterTypes(); |
|
|
for (int j = 0; j < sig.length; j++) |
|
|
{ |
|
|
out.print(getPrettyName(sig[j]) + ".class"); |
|
|
if (j + 1 < sig.length) |
|
|
out.print(", "); |
|
|
} |
|
|
out.println("});"); |
|
|
} |
|
|
ctrl.unindent(); |
|
|
out.println("}"); |
|
|
out.print("catch (java.lang.NoSuchMethodException e) {"); |
|
|
ctrl.indent(); |
|
|
if (need11Stubs) |
|
|
out.print("useNewInvoke = false;"); |
|
|
else |
|
|
out.print("throw new java.lang.NoSuchMethodError(\"stub class initialization failed\");"); |
|
426 |
|
|
427 |
ctrl.unindent(); |
final ClassWriter stub = new ClassWriter(true); |
428 |
out.print("}"); |
classInternalName = stubname.replace('.', '/'); |
429 |
|
final String superInternalName = |
430 |
|
Type.getType(RemoteStub.class).getInternalName(); |
431 |
|
|
432 |
|
String[] remoteInternalNames = |
433 |
|
internalNameArray((Class[]) mRemoteInterfaces.toArray(new Class[] {})); |
434 |
|
stub.visit |
435 |
|
(C.V1_2, C.ACC_PUBLIC + C.ACC_FINAL, classInternalName, |
436 |
|
superInternalName, remoteInternalNames, null); |
437 |
|
|
438 |
ctrl.unindent(); |
if (need12Stubs) |
439 |
out.println("}"); |
{ |
440 |
out.println(); |
stub.visitField |
441 |
|
(C.ACC_PRIVATE + C.ACC_STATIC + C.ACC_FINAL, "serialVersionUID", |
442 |
|
Type.LONG_TYPE.getDescriptor(), new Long(2L), null); |
443 |
} |
} |
444 |
|
|
|
// Constructors |
|
445 |
if (need11Stubs) |
if (need11Stubs) |
446 |
{ |
{ |
447 |
out.print("public " + stubclassname + "() {"); |
stub.visitField |
448 |
ctrl.indent(); |
(C.ACC_PRIVATE + C.ACC_STATIC + C.ACC_FINAL, |
449 |
out.print("super();"); |
"interfaceHash", Type.LONG_TYPE.getDescriptor(), |
450 |
ctrl.unindent(); |
new Long(RMIHashes.getInterfaceHash(clazz)), null); |
451 |
out.println("}"); |
|
452 |
|
if (need12Stubs) |
453 |
|
{ |
454 |
|
stub.visitField |
455 |
|
(C.ACC_PRIVATE + C.ACC_STATIC, "useNewInvoke", |
456 |
|
Type.BOOLEAN_TYPE.getDescriptor(), null, null); |
457 |
|
} |
458 |
|
|
459 |
|
stub.visitField |
460 |
|
(C.ACC_PRIVATE + C.ACC_STATIC + C.ACC_FINAL, |
461 |
|
"operations", Type.getDescriptor(Operation[].class), null, null); |
462 |
} |
} |
463 |
|
|
464 |
|
// Set of method references. |
465 |
if (need12Stubs) |
if (need12Stubs) |
466 |
{ |
{ |
467 |
out.print("public " + stubclassname |
for (int i = 0; i < remotemethods.length; i++) |
468 |
+ "(java.rmi.server.RemoteRef ref) {"); |
{ |
469 |
ctrl.indent(); |
Method m = remotemethods[i].meth; |
470 |
out.print("super(ref);"); |
String slotName = "$method_" + m.getName() + "_" + i; |
471 |
ctrl.unindent(); |
stub.visitField |
472 |
out.println("}"); |
(C.ACC_PRIVATE + C.ACC_STATIC, slotName, |
473 |
|
Type.getDescriptor(Method.class), null, null); |
474 |
|
} |
475 |
} |
} |
476 |
|
|
477 |
// Method implementations |
CodeVisitor clinit = stub.visitMethod |
478 |
for (int i = 0; i < remotemethods.length; i++) |
(C.ACC_STATIC, "<clinit>", |
479 |
{ |
Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}), null, null); |
|
Method m = remotemethods[i].meth; |
|
|
Class[] sig = m.getParameterTypes(); |
|
|
Class returntype = m.getReturnType(); |
|
|
Class[] except = sortExceptions(m.getExceptionTypes()); |
|
|
|
|
|
out.println(); |
|
|
out.print("public " + getPrettyName(returntype) + " " + m.getName() |
|
|
+ "("); |
|
|
for (int j = 0; j < sig.length; j++) |
|
|
{ |
|
|
out.print(getPrettyName(sig[j])); |
|
|
out.print(" $param_" + j); |
|
|
if (j + 1 < sig.length) |
|
|
out.print(", "); |
|
|
} |
|
|
out.print(") "); |
|
|
out.print("throws "); |
|
|
for (int j = 0; j < except.length; j++) |
|
|
{ |
|
|
out.print(getPrettyName(except[j])); |
|
|
if (j + 1 < except.length) |
|
|
out.print(", "); |
|
|
} |
|
|
out.print(" {"); |
|
|
ctrl.indent(); |
|
|
|
|
|
out.print("try {"); |
|
|
ctrl.indent(); |
|
|
|
|
|
if (need12Stubs) |
|
|
{ |
|
|
if (need11Stubs) |
|
|
{ |
|
|
out.print("if (useNewInvoke) {"); |
|
|
ctrl.indent(); |
|
|
} |
|
|
if (returntype != Void.TYPE) |
|
|
out.print("java.lang.Object $result = "); |
|
|
out.print("ref.invoke(this, $method_" + m.getName() + "_" + i |
|
|
+ ", "); |
|
|
if (sig.length == 0) |
|
|
out.print("null, "); |
|
|
else |
|
|
{ |
|
|
out.print("new java.lang.Object[] {"); |
|
|
for (int j = 0; j < sig.length; j++) |
|
|
{ |
|
|
if (sig[j] == Boolean.TYPE) |
|
|
out.print("new java.lang.Boolean($param_" + j + ")"); |
|
|
else if (sig[j] == Byte.TYPE) |
|
|
out.print("new java.lang.Byte($param_" + j + ")"); |
|
|
else if (sig[j] == Character.TYPE) |
|
|
out.print("new java.lang.Character($param_" + j + ")"); |
|
|
else if (sig[j] == Short.TYPE) |
|
|
out.print("new java.lang.Short($param_" + j + ")"); |
|
|
else if (sig[j] == Integer.TYPE) |
|
|
out.print("new java.lang.Integer($param_" + j + ")"); |
|
|
else if (sig[j] == Long.TYPE) |
|
|
out.print("new java.lang.Long($param_" + j + ")"); |
|
|
else if (sig[j] == Float.TYPE) |
|
|
out.print("new java.lang.Float($param_" + j + ")"); |
|
|
else if (sig[j] == Double.TYPE) |
|
|
out.print("new java.lang.Double($param_" + j + ")"); |
|
|
else |
|
|
out.print("$param_" + j); |
|
|
if (j + 1 < sig.length) |
|
|
out.print(", "); |
|
|
} |
|
|
out.print("}, "); |
|
|
} |
|
|
out.print(Long.toString(remotemethods[i].hash) + "L"); |
|
|
out.print(");"); |
|
|
|
|
|
if (returntype != Void.TYPE) |
|
|
{ |
|
|
out.println(); |
|
|
out.print("return ("); |
|
|
if (returntype == Boolean.TYPE) |
|
|
out.print("((java.lang.Boolean)$result).booleanValue()"); |
|
|
else if (returntype == Byte.TYPE) |
|
|
out.print("((java.lang.Byte)$result).byteValue()"); |
|
|
else if (returntype == Character.TYPE) |
|
|
out.print("((java.lang.Character)$result).charValue()"); |
|
|
else if (returntype == Short.TYPE) |
|
|
out.print("((java.lang.Short)$result).shortValue()"); |
|
|
else if (returntype == Integer.TYPE) |
|
|
out.print("((java.lang.Integer)$result).intValue()"); |
|
|
else if (returntype == Long.TYPE) |
|
|
out.print("((java.lang.Long)$result).longValue()"); |
|
|
else if (returntype == Float.TYPE) |
|
|
out.print("((java.lang.Float)$result).floatValue()"); |
|
|
else if (returntype == Double.TYPE) |
|
|
out.print("((java.lang.Double)$result).doubleValue()"); |
|
|
else |
|
|
out.print("(" + getPrettyName(returntype) + ")$result"); |
|
|
out.print(");"); |
|
|
} |
|
480 |
|
|
481 |
if (need11Stubs) |
if (need11Stubs) |
482 |
{ |
{ |
483 |
ctrl.unindent(); |
fillOperationArray(clinit); |
484 |
out.println("}"); |
if (! need12Stubs) |
485 |
out.print("else {"); |
clinit.visitInsn(C.RETURN); |
486 |
ctrl.indent(); |
} |
|
} |
|
|
} |
|
487 |
|
|
488 |
if (need11Stubs) |
if (need12Stubs) |
489 |
{ |
{ |
490 |
out.println("java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject)this, operations, " |
// begin of try |
491 |
+ i + ", interfaceHash);"); |
Label begin = new Label(); |
|
out.print("try {"); |
|
|
ctrl.indent(); |
|
|
out.print("java.io.ObjectOutput out = call.getOutputStream();"); |
|
|
for (int j = 0; j < sig.length; j++) |
|
|
{ |
|
|
out.println(); |
|
|
if (sig[j] == Boolean.TYPE) |
|
|
out.print("out.writeBoolean("); |
|
|
else if (sig[j] == Byte.TYPE) |
|
|
out.print("out.writeByte("); |
|
|
else if (sig[j] == Character.TYPE) |
|
|
out.print("out.writeChar("); |
|
|
else if (sig[j] == Short.TYPE) |
|
|
out.print("out.writeShort("); |
|
|
else if (sig[j] == Integer.TYPE) |
|
|
out.print("out.writeInt("); |
|
|
else if (sig[j] == Long.TYPE) |
|
|
out.print("out.writeLong("); |
|
|
else if (sig[j] == Float.TYPE) |
|
|
out.print("out.writeFloat("); |
|
|
else if (sig[j] == Double.TYPE) |
|
|
out.print("out.writeDouble("); |
|
|
else |
|
|
out.print("out.writeObject("); |
|
|
out.print("$param_" + j + ");"); |
|
|
} |
|
|
ctrl.unindent(); |
|
|
out.println("}"); |
|
|
out.print("catch (java.io.IOException e) {"); |
|
|
ctrl.indent(); |
|
|
out.print("throw new java.rmi.MarshalException(\"error marshalling arguments\", e);"); |
|
|
ctrl.unindent(); |
|
|
out.println("}"); |
|
|
out.println("ref.invoke(call);"); |
|
|
if (returntype != Void.TYPE) |
|
|
out.println(getPrettyName(returntype) + " $result;"); |
|
|
out.print("try {"); |
|
|
ctrl.indent(); |
|
|
out.print("java.io.ObjectInput in = call.getInputStream();"); |
|
|
boolean needcastcheck = false; |
|
|
if (returntype != Void.TYPE) |
|
|
{ |
|
|
out.println(); |
|
|
out.print("$result = "); |
|
|
if (returntype == Boolean.TYPE) |
|
|
out.print("in.readBoolean();"); |
|
|
else if (returntype == Byte.TYPE) |
|
|
out.print("in.readByte();"); |
|
|
else if (returntype == Character.TYPE) |
|
|
out.print("in.readChar();"); |
|
|
else if (returntype == Short.TYPE) |
|
|
out.print("in.readShort();"); |
|
|
else if (returntype == Integer.TYPE) |
|
|
out.print("in.readInt();"); |
|
|
else if (returntype == Long.TYPE) |
|
|
out.print("in.readLong();"); |
|
|
else if (returntype == Float.TYPE) |
|
|
out.print("in.readFloat();"); |
|
|
else if (returntype == Double.TYPE) |
|
|
out.print("in.readDouble();"); |
|
|
else |
|
|
{ |
|
|
if (returntype != Object.class) |
|
|
out.print("(" + getPrettyName(returntype) + ")"); |
|
|
else |
|
|
needcastcheck = true; |
|
|
out.print("in.readObject();"); |
|
|
} |
|
|
out.println(); |
|
|
out.print("return ($result);"); |
|
|
} |
|
|
ctrl.unindent(); |
|
|
out.println("}"); |
|
|
out.print("catch (java.io.IOException e) {"); |
|
|
ctrl.indent(); |
|
|
out.print("throw new java.rmi.UnmarshalException(\"error unmarshalling return\", e);"); |
|
|
ctrl.unindent(); |
|
|
out.println("}"); |
|
|
if (needcastcheck) |
|
|
{ |
|
|
out.print("catch (java.lang.ClassNotFoundException e) {"); |
|
|
ctrl.indent(); |
|
|
out.print("throw new java.rmi.UnmarshalException(\"error unmarshalling return\", e);"); |
|
|
ctrl.unindent(); |
|
|
out.println("}"); |
|
|
} |
|
|
out.print("finally {"); |
|
|
ctrl.indent(); |
|
|
out.print("ref.done(call);"); |
|
|
ctrl.unindent(); |
|
|
out.print("}"); |
|
492 |
|
|
493 |
if (need12Stubs && need11Stubs) |
// beginning of catch |
494 |
{ |
Label handler = new Label(); |
495 |
ctrl.unindent(); |
clinit.visitLabel(begin); |
496 |
out.print("}"); |
|
497 |
} |
// Initialize the methods references. |
498 |
} |
if (need11Stubs) |
499 |
|
{ |
500 |
|
/* |
501 |
|
* RemoteRef.class.getMethod("invoke", new Class[] { |
502 |
|
* Remote.class, Method.class, Object[].class, long.class }) |
503 |
|
*/ |
504 |
|
generateClassConstant(clinit, RemoteRef.class); |
505 |
|
clinit.visitLdcInsn("invoke"); |
506 |
|
generateClassArray |
507 |
|
(clinit, new Class[] { Remote.class, Method.class, |
508 |
|
Object[].class, long.class }); |
509 |
|
clinit.visitMethodInsn |
510 |
|
(C.INVOKEVIRTUAL, |
511 |
|
Type.getInternalName(Class.class), |
512 |
|
"getMethod", |
513 |
|
Type.getMethodDescriptor |
514 |
|
(Type.getType(Method.class), |
515 |
|
new Type[] { Type.getType(String.class), |
516 |
|
Type.getType(Class[].class) })); |
517 |
|
|
518 |
|
// useNewInvoke = true |
519 |
|
clinit.visitInsn(C.ICONST_1); |
520 |
|
clinit.visitFieldInsn |
521 |
|
(C.PUTSTATIC, classInternalName, "useNewInvoke", |
522 |
|
Type.BOOLEAN_TYPE.getDescriptor()); |
523 |
|
} |
524 |
|
|
525 |
|
generateStaticMethodObjs(clinit); |
526 |
|
|
527 |
|
// jump past handler |
528 |
|
clinit.visitInsn(C.RETURN); |
529 |
|
clinit.visitLabel(handler); |
530 |
|
if (need11Stubs) |
531 |
|
{ |
532 |
|
// useNewInvoke = false |
533 |
|
clinit.visitInsn(C.ICONST_0); |
534 |
|
clinit.visitFieldInsn |
535 |
|
(C.PUTSTATIC, classInternalName, "useNewInvoke", |
536 |
|
Type.BOOLEAN_TYPE.getDescriptor()); |
537 |
|
clinit.visitInsn(C.RETURN); |
538 |
|
} |
539 |
|
else |
540 |
|
{ |
541 |
|
// throw NoSuchMethodError |
542 |
|
clinit.visitTypeInsn(C.NEW, typeArg(NoSuchMethodError.class)); |
543 |
|
clinit.visitInsn(C.DUP); |
544 |
|
clinit.visitLdcInsn("stub class initialization failed"); |
545 |
|
clinit.visitMethodInsn |
546 |
|
(C.INVOKESPECIAL, |
547 |
|
Type.getInternalName(NoSuchMethodError.class), |
548 |
|
"<init>", |
549 |
|
Type.getMethodDescriptor |
550 |
|
(Type.VOID_TYPE, |
551 |
|
new Type[] { Type.getType(String.class) })); |
552 |
|
clinit.visitInsn(C.ATHROW); |
553 |
|
} |
554 |
|
|
555 |
|
clinit.visitTryCatchBlock |
556 |
|
(begin, handler, handler, |
557 |
|
Type.getInternalName(NoSuchMethodException.class)); |
558 |
|
|
559 |
ctrl.unindent(); |
} |
|
out.print("}"); |
|
560 |
|
|
561 |
boolean needgeneral = true; |
clinit.visitMaxs(-1, -1); |
|
for (int j = 0; j < except.length; j++) |
|
|
{ |
|
|
out.println(); |
|
|
out.print("catch (" + getPrettyName(except[j]) + " e) {"); |
|
|
ctrl.indent(); |
|
|
out.print("throw e;"); |
|
|
ctrl.unindent(); |
|
|
out.print("}"); |
|
|
if (except[j] == Exception.class) |
|
|
needgeneral = false; |
|
|
} |
|
|
if (needgeneral) |
|
|
{ |
|
|
out.println(); |
|
|
out.print("catch (java.lang.Exception e) {"); |
|
|
ctrl.indent(); |
|
|
out.print("throw new java.rmi.UnexpectedException(\"undeclared checked exception\", e);"); |
|
|
ctrl.unindent(); |
|
|
out.print("}"); |
|
|
} |
|
562 |
|
|
563 |
ctrl.unindent(); |
generateClassForNamer(stub); |
|
out.print("}"); |
|
|
out.println(); |
|
|
} |
|
564 |
|
|
565 |
ctrl.unindent(); |
// Constructors |
566 |
out.println("}"); |
if (need11Stubs) |
567 |
|
{ |
568 |
|
// no arg public constructor |
569 |
|
CodeVisitor code = stub.visitMethod |
570 |
|
(C.ACC_PUBLIC, "<init>", |
571 |
|
Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}), |
572 |
|
null, null); |
573 |
|
code.visitVarInsn(C.ALOAD, 0); |
574 |
|
code.visitMethodInsn |
575 |
|
(C.INVOKESPECIAL, superInternalName, "<init>", |
576 |
|
Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {})); |
577 |
|
code.visitInsn(C.RETURN); |
578 |
|
|
579 |
|
code.visitMaxs(-1, -1); |
580 |
|
} |
581 |
|
|
582 |
|
// public RemoteRef constructor |
583 |
|
CodeVisitor constructor = stub.visitMethod |
584 |
|
(C.ACC_PUBLIC, "<init>", |
585 |
|
Type.getMethodDescriptor |
586 |
|
(Type.VOID_TYPE, new Type[] {Type.getType(RemoteRef.class)}), |
587 |
|
null, null); |
588 |
|
constructor.visitVarInsn(C.ALOAD, 0); |
589 |
|
constructor.visitVarInsn(C.ALOAD, 1); |
590 |
|
constructor.visitMethodInsn |
591 |
|
(C.INVOKESPECIAL, superInternalName, "<init>", |
592 |
|
Type.getMethodDescriptor |
593 |
|
(Type.VOID_TYPE, new Type[] {Type.getType(RemoteRef.class)})); |
594 |
|
constructor.visitInsn(C.RETURN); |
595 |
|
constructor.visitMaxs(-1, -1); |
596 |
|
|
597 |
out.close(); |
// Method implementations |
598 |
|
for (int i = 0; i < remotemethods.length; i++) |
599 |
|
{ |
600 |
|
Method m = remotemethods[i].meth; |
601 |
|
Class[] sig = m.getParameterTypes(); |
602 |
|
Class returntype = m.getReturnType(); |
603 |
|
Class[] except = sortExceptions |
604 |
|
((Class[]) remotemethods[i].exceptions.toArray(new Class[0])); |
605 |
|
|
606 |
|
CodeVisitor code = stub.visitMethod |
607 |
|
(C.ACC_PUBLIC, |
608 |
|
m.getName(), |
609 |
|
Type.getMethodDescriptor(Type.getType(returntype), typeArray(sig)), |
610 |
|
internalNameArray(typeArray(except)), |
611 |
|
null); |
612 |
|
|
613 |
|
final Variables var = new Variables(); |
614 |
|
|
615 |
|
// this and parameters are the declared vars |
616 |
|
var.declare("this"); |
617 |
|
for (int j = 0; j < sig.length; j++) |
618 |
|
var.declare(param(m, j), size(sig[j])); |
619 |
|
|
620 |
|
Label methodTryBegin = new Label(); |
621 |
|
code.visitLabel(methodTryBegin); |
622 |
|
|
623 |
|
if (need12Stubs) |
624 |
|
{ |
625 |
|
Label oldInvoke = new Label(); |
626 |
|
if (need11Stubs) |
627 |
|
{ |
628 |
|
// if not useNewInvoke jump to old invoke |
629 |
|
code.visitFieldInsn |
630 |
|
(C.GETSTATIC, classInternalName, "useNewInvoke", |
631 |
|
Type.getDescriptor(boolean.class)); |
632 |
|
code.visitJumpInsn(C.IFEQ, oldInvoke); |
633 |
|
} |
634 |
|
|
635 |
|
// this.ref |
636 |
|
code.visitVarInsn(C.ALOAD, var.get("this")); |
637 |
|
code.visitFieldInsn |
638 |
|
(C.GETFIELD, Type.getInternalName(RemoteObject.class), |
639 |
|
"ref", Type.getDescriptor(RemoteRef.class)); |
640 |
|
|
641 |
|
// "this" is first arg to invoke |
642 |
|
code.visitVarInsn(C.ALOAD, var.get("this")); |
643 |
|
|
644 |
|
// method object is second arg to invoke |
645 |
|
String methName = "$method_" + m.getName() + "_" + i; |
646 |
|
code.visitFieldInsn |
647 |
|
(C.GETSTATIC, classInternalName, methName, |
648 |
|
Type.getDescriptor(Method.class)); |
649 |
|
|
650 |
|
// args to remote method are third arg to invoke |
651 |
|
if (sig.length == 0) |
652 |
|
code.visitInsn(C.ACONST_NULL); |
653 |
|
else |
654 |
|
{ |
655 |
|
// create arg Object[] (with boxed primitives) and push it |
656 |
|
code.visitLdcInsn(new Integer(sig.length)); |
657 |
|
code.visitTypeInsn(C.ANEWARRAY, typeArg(Object.class)); |
658 |
|
|
659 |
|
var.allocate("argArray"); |
660 |
|
code.visitVarInsn(C.ASTORE, var.get("argArray")); |
661 |
|
|
662 |
|
for (int j = 0; j < sig.length; j++) |
663 |
|
{ |
664 |
|
int size = size(sig[j]); |
665 |
|
int insn = loadOpcode(sig[j]); |
666 |
|
Class box = sig[j].isPrimitive() ? box(sig[j]) : null; |
667 |
|
|
668 |
|
code.visitVarInsn(C.ALOAD, var.get("argArray")); |
669 |
|
code.visitLdcInsn(new Integer(j)); |
670 |
|
|
671 |
|
// put argument on stack |
672 |
|
if (box != null) |
673 |
|
{ |
674 |
|
code.visitTypeInsn(C.NEW, typeArg(box)); |
675 |
|
code.visitInsn(C.DUP); |
676 |
|
code.visitVarInsn(insn, var.get(param(m, j))); |
677 |
|
code.visitMethodInsn |
678 |
|
(C.INVOKESPECIAL, |
679 |
|
Type.getInternalName(box), |
680 |
|
"<init>", |
681 |
|
Type.getMethodDescriptor |
682 |
|
(Type.VOID_TYPE, |
683 |
|
new Type[] { Type.getType(sig[j]) })); |
684 |
|
} |
685 |
|
else |
686 |
|
code.visitVarInsn(insn, var.get(param(m, j))); |
687 |
|
|
688 |
|
code.visitInsn(C.AASTORE); |
689 |
|
} |
690 |
|
|
691 |
|
code.visitVarInsn(C.ALOAD, var.deallocate("argArray")); |
692 |
|
} |
693 |
|
|
694 |
|
// push remote operation opcode |
695 |
|
code.visitLdcInsn(new Long(remotemethods[i].hash)); |
696 |
|
code.visitMethodInsn |
697 |
|
(C.INVOKEINTERFACE, |
698 |
|
Type.getInternalName(RemoteRef.class), |
699 |
|
"invoke", |
700 |
|
Type.getMethodDescriptor |
701 |
|
(Type.getType(Object.class), |
702 |
|
new Type[] { Type.getType(Remote.class), |
703 |
|
Type.getType(Method.class), |
704 |
|
Type.getType(Object[].class), |
705 |
|
Type.LONG_TYPE })); |
706 |
|
|
707 |
|
if (! returntype.equals(Void.TYPE)) |
708 |
|
{ |
709 |
|
int retcode = returnOpcode(returntype); |
710 |
|
Class boxCls = |
711 |
|
returntype.isPrimitive() ? box(returntype) : null; |
712 |
|
code.visitTypeInsn |
713 |
|
(C.CHECKCAST, typeArg(boxCls == null ? returntype : boxCls)); |
714 |
|
if (returntype.isPrimitive()) |
715 |
|
{ |
716 |
|
// unbox |
717 |
|
code.visitMethodInsn |
718 |
|
(C.INVOKEVIRTUAL, |
719 |
|
Type.getType(boxCls).getInternalName(), |
720 |
|
unboxMethod(returntype), |
721 |
|
Type.getMethodDescriptor |
722 |
|
(Type.getType(returntype), new Type[] {})); |
723 |
|
} |
724 |
|
|
725 |
|
code.visitInsn(retcode); |
726 |
|
} |
727 |
|
else |
728 |
|
code.visitInsn(C.RETURN); |
729 |
|
|
730 |
|
|
731 |
|
if (need11Stubs) |
732 |
|
code.visitLabel(oldInvoke); |
733 |
|
} |
734 |
|
|
735 |
|
if (need11Stubs) |
736 |
|
{ |
737 |
|
|
738 |
|
// this.ref.newCall(this, operations, index, interfaceHash) |
739 |
|
code.visitVarInsn(C.ALOAD, var.get("this")); |
740 |
|
code.visitFieldInsn |
741 |
|
(C.GETFIELD, |
742 |
|
Type.getInternalName(RemoteObject.class), |
743 |
|
"ref", |
744 |
|
Type.getDescriptor(RemoteRef.class)); |
745 |
|
|
746 |
|
// "this" is first arg to newCall |
747 |
|
code.visitVarInsn(C.ALOAD, var.get("this")); |
748 |
|
|
749 |
|
// operations is second arg to newCall |
750 |
|
code.visitFieldInsn |
751 |
|
(C.GETSTATIC, classInternalName, "operations", |
752 |
|
Type.getDescriptor(Operation[].class)); |
753 |
|
|
754 |
|
// method index is third arg |
755 |
|
code.visitLdcInsn(new Integer(i)); |
756 |
|
|
757 |
|
// interface hash is fourth arg |
758 |
|
code.visitFieldInsn |
759 |
|
(C.GETSTATIC, classInternalName, "interfaceHash", |
760 |
|
Type.LONG_TYPE.getDescriptor()); |
761 |
|
|
762 |
|
code.visitMethodInsn |
763 |
|
(C.INVOKEINTERFACE, |
764 |
|
Type.getInternalName(RemoteRef.class), |
765 |
|
"newCall", |
766 |
|
Type.getMethodDescriptor |
767 |
|
(Type.getType(RemoteCall.class), |
768 |
|
new Type[] { Type.getType(RemoteObject.class), |
769 |
|
Type.getType(Operation[].class), |
770 |
|
Type.INT_TYPE, |
771 |
|
Type.LONG_TYPE })); |
772 |
|
|
773 |
|
// store call object on stack and leave copy on stack |
774 |
|
var.allocate("call"); |
775 |
|
code.visitInsn(C.DUP); |
776 |
|
code.visitVarInsn(C.ASTORE, var.get("call")); |
777 |
|
|
778 |
|
Label beginArgumentTryBlock = new Label(); |
779 |
|
code.visitLabel(beginArgumentTryBlock); |
780 |
|
|
781 |
|
// ObjectOutput out = call.getOutputStream(); |
782 |
|
code.visitMethodInsn |
783 |
|
(C.INVOKEINTERFACE, |
784 |
|
Type.getInternalName(RemoteCall.class), |
785 |
|
"getOutputStream", |
786 |
|
Type.getMethodDescriptor |
787 |
|
(Type.getType(ObjectOutput.class), new Type[] {})); |
788 |
|
|
789 |
|
for (int j = 0; j < sig.length; j++) |
790 |
|
{ |
791 |
|
// dup the ObjectOutput |
792 |
|
code.visitInsn(C.DUP); |
793 |
|
|
794 |
|
// get j'th arg to remote method |
795 |
|
code.visitVarInsn(loadOpcode(sig[j]), var.get(param(m, j))); |
796 |
|
|
797 |
|
Class argCls = |
798 |
|
sig[j].isPrimitive() ? sig[j] : Object.class; |
799 |
|
|
800 |
|
// out.writeFoo |
801 |
|
code.visitMethodInsn |
802 |
|
(C.INVOKEINTERFACE, |
803 |
|
Type.getInternalName(ObjectOutput.class), |
804 |
|
writeMethod(sig[j]), |
805 |
|
Type.getMethodDescriptor |
806 |
|
(Type.VOID_TYPE, |
807 |
|
new Type[] { Type.getType(argCls) })); |
808 |
|
} |
809 |
|
|
810 |
|
// pop ObjectOutput |
811 |
|
code.visitInsn(C.POP); |
812 |
|
|
813 |
|
Label iohandler = new Label(); |
814 |
|
Label endArgumentTryBlock = new Label(); |
815 |
|
code.visitJumpInsn(C.GOTO, endArgumentTryBlock); |
816 |
|
code.visitLabel(iohandler); |
817 |
|
|
818 |
|
// throw new MarshalException(msg, ioexception); |
819 |
|
code.visitVarInsn(C.ASTORE, var.allocate("exception")); |
820 |
|
code.visitTypeInsn(C.NEW, typeArg(MarshalException.class)); |
821 |
|
code.visitInsn(C.DUP); |
822 |
|
code.visitLdcInsn("error marshalling arguments"); |
823 |
|
code.visitVarInsn(C.ALOAD, var.deallocate("exception")); |
824 |
|
code.visitMethodInsn |
825 |
|
(C.INVOKESPECIAL, |
826 |
|
Type.getInternalName(MarshalException.class), |
827 |
|
"<init>", |
828 |
|
Type.getMethodDescriptor |
829 |
|
(Type.VOID_TYPE, |
830 |
|
new Type[] { Type.getType(String.class), |
831 |
|
Type.getType(Exception.class) })); |
832 |
|
code.visitInsn(C.ATHROW); |
833 |
|
|
834 |
|
code.visitLabel(endArgumentTryBlock); |
835 |
|
code.visitTryCatchBlock |
836 |
|
(beginArgumentTryBlock, iohandler, iohandler, |
837 |
|
Type.getInternalName(IOException.class)); |
838 |
|
|
839 |
|
// this.ref.invoke(call) |
840 |
|
code.visitVarInsn(C.ALOAD, var.get("this")); |
841 |
|
code.visitFieldInsn |
842 |
|
(C.GETFIELD, Type.getInternalName(RemoteObject.class), |
843 |
|
"ref", Type.getDescriptor(RemoteRef.class)); |
844 |
|
code.visitVarInsn(C.ALOAD, var.get("call")); |
845 |
|
code.visitMethodInsn |
846 |
|
(C.INVOKEINTERFACE, |
847 |
|
Type.getInternalName(RemoteRef.class), |
848 |
|
"invoke", |
849 |
|
Type.getMethodDescriptor |
850 |
|
(Type.VOID_TYPE, |
851 |
|
new Type[] { Type.getType(RemoteCall.class) })); |
852 |
|
|
853 |
|
// handle return value |
854 |
|
boolean needcastcheck = false; |
855 |
|
|
856 |
|
Label beginReturnTryCatch = new Label(); |
857 |
|
code.visitLabel(beginReturnTryCatch); |
858 |
|
|
859 |
|
int returncode = returnOpcode(returntype); |
860 |
|
|
861 |
|
if (! returntype.equals(Void.TYPE)) |
862 |
|
{ |
863 |
|
// call.getInputStream() |
864 |
|
code.visitVarInsn(C.ALOAD, var.get("call")); |
865 |
|
code.visitMethodInsn |
866 |
|
(C.INVOKEINTERFACE, |
867 |
|
Type.getInternalName(RemoteCall.class), |
868 |
|
"getInputStream", |
869 |
|
Type.getMethodDescriptor |
870 |
|
(Type.getType(ObjectInput.class), new Type[] {})); |
871 |
|
|
872 |
|
Class readCls = |
873 |
|
returntype.isPrimitive() ? returntype : Object.class; |
874 |
|
code.visitMethodInsn |
875 |
|
(C.INVOKEINTERFACE, |
876 |
|
Type.getInternalName(ObjectInput.class), |
877 |
|
readMethod(returntype), |
878 |
|
Type.getMethodDescriptor |
879 |
|
(Type.getType(readCls), new Type[] {})); |
880 |
|
|
881 |
|
boolean castresult = false; |
882 |
|
|
883 |
|
if (! returntype.isPrimitive()) |
884 |
|
{ |
885 |
|
if (! returntype.equals(Object.class)) |
886 |
|
castresult = true; |
887 |
|
else |
888 |
|
needcastcheck = true; |
889 |
|
} |
890 |
|
|
891 |
|
if (castresult) |
892 |
|
code.visitTypeInsn(C.CHECKCAST, typeArg(returntype)); |
893 |
|
|
894 |
|
// leave result on stack for return |
895 |
|
} |
896 |
|
|
897 |
|
// this.ref.done(call) |
898 |
|
code.visitVarInsn(C.ALOAD, var.get("this")); |
899 |
|
code.visitFieldInsn |
900 |
|
(C.GETFIELD, |
901 |
|
Type.getInternalName(RemoteObject.class), |
902 |
|
"ref", |
903 |
|
Type.getDescriptor(RemoteRef.class)); |
904 |
|
code.visitVarInsn(C.ALOAD, var.deallocate("call")); |
905 |
|
code.visitMethodInsn |
906 |
|
(C.INVOKEINTERFACE, |
907 |
|
Type.getInternalName(RemoteRef.class), |
908 |
|
"done", |
909 |
|
Type.getMethodDescriptor |
910 |
|
(Type.VOID_TYPE, |
911 |
|
new Type[] { Type.getType(RemoteCall.class) })); |
912 |
|
|
913 |
|
// return; or return result; |
914 |
|
code.visitInsn(returncode); |
915 |
|
|
916 |
|
// exception handler |
917 |
|
Label handler = new Label(); |
918 |
|
code.visitLabel(handler); |
919 |
|
code.visitVarInsn(C.ASTORE, var.allocate("exception")); |
920 |
|
|
921 |
|
// throw new UnmarshalException(msg, e) |
922 |
|
code.visitTypeInsn(C.NEW, typeArg(UnmarshalException.class)); |
923 |
|
code.visitInsn(C.DUP); |
924 |
|
code.visitLdcInsn("error unmarshalling return"); |
925 |
|
code.visitVarInsn(C.ALOAD, var.deallocate("exception")); |
926 |
|
code.visitMethodInsn |
927 |
|
(C.INVOKESPECIAL, |
928 |
|
Type.getInternalName(UnmarshalException.class), |
929 |
|
"<init>", |
930 |
|
Type.getMethodDescriptor |
931 |
|
(Type.VOID_TYPE, |
932 |
|
new Type[] { Type.getType(String.class), |
933 |
|
Type.getType(Exception.class) })); |
934 |
|
code.visitInsn(C.ATHROW); |
935 |
|
|
936 |
|
Label endReturnTryCatch = new Label(); |
937 |
|
|
938 |
|
// catch IOException |
939 |
|
code.visitTryCatchBlock |
940 |
|
(beginReturnTryCatch, handler, handler, |
941 |
|
Type.getInternalName(IOException.class)); |
942 |
|
|
943 |
|
if (needcastcheck) |
944 |
|
{ |
945 |
|
// catch ClassNotFoundException |
946 |
|
code.visitTryCatchBlock |
947 |
|
(beginReturnTryCatch, handler, handler, |
948 |
|
Type.getInternalName(ClassNotFoundException.class)); |
949 |
|
} |
950 |
|
} |
951 |
|
|
952 |
|
Label rethrowHandler = new Label(); |
953 |
|
code.visitLabel(rethrowHandler); |
954 |
|
// rethrow declared exceptions |
955 |
|
code.visitInsn(C.ATHROW); |
956 |
|
|
957 |
|
boolean needgeneral = true; |
958 |
|
for (int j = 0; j < except.length; j++) |
959 |
|
{ |
960 |
|
if (except[j] == Exception.class) |
961 |
|
needgeneral = false; |
962 |
|
} |
963 |
|
|
964 |
|
for (int j = 0; j < except.length; j++) |
965 |
|
{ |
966 |
|
code.visitTryCatchBlock |
967 |
|
(methodTryBegin, rethrowHandler, rethrowHandler, |
968 |
|
Type.getInternalName(except[j])); |
969 |
|
} |
970 |
|
|
971 |
|
if (needgeneral) |
972 |
|
{ |
973 |
|
// rethrow unchecked exceptions |
974 |
|
code.visitTryCatchBlock |
975 |
|
(methodTryBegin, rethrowHandler, rethrowHandler, |
976 |
|
Type.getInternalName(RuntimeException.class)); |
977 |
|
|
978 |
|
Label generalHandler = new Label(); |
979 |
|
code.visitLabel(generalHandler); |
980 |
|
String msg = "undeclared checked exception"; |
981 |
|
|
982 |
|
// throw new java.rmi.UnexpectedException(msg, e) |
983 |
|
code.visitVarInsn(C.ASTORE, var.allocate("exception")); |
984 |
|
code.visitTypeInsn(C.NEW, typeArg(UnexpectedException.class)); |
985 |
|
code.visitInsn(C.DUP); |
986 |
|
code.visitLdcInsn(msg); |
987 |
|
code.visitVarInsn(C.ALOAD, var.deallocate("exception")); |
988 |
|
code.visitMethodInsn |
989 |
|
(C.INVOKESPECIAL, |
990 |
|
Type.getInternalName(UnexpectedException.class), |
991 |
|
"<init>", |
992 |
|
Type.getMethodDescriptor |
993 |
|
(Type.VOID_TYPE, |
994 |
|
new Type [] { Type.getType(String.class), |
995 |
|
Type.getType(Exception.class) })); |
996 |
|
code.visitInsn(C.ATHROW); |
997 |
|
|
998 |
|
code.visitTryCatchBlock |
999 |
|
(methodTryBegin, rethrowHandler, generalHandler, |
1000 |
|
Type.getInternalName(Exception.class)); |
1001 |
|
} |
1002 |
|
|
1003 |
|
code.visitMaxs(-1, -1); |
1004 |
|
} |
1005 |
|
|
1006 |
|
stub.visitEnd(); |
1007 |
|
byte[] classData = stub.toByteArray(); |
1008 |
|
if (file.exists()) |
1009 |
|
file.delete(); |
1010 |
|
if (file.getParentFile() != null) |
1011 |
|
file.getParentFile().mkdirs(); |
1012 |
|
FileOutputStream fos = new FileOutputStream(file); |
1013 |
|
fos.write(classData); |
1014 |
|
fos.flush(); |
1015 |
|
fos.close(); |
1016 |
} |
} |
1017 |
|
|
1018 |
private void generateSkel() throws IOException |
private void generateSkel() throws IOException |
1019 |
{ |
{ |
1020 |
skelname = fullclassname + "_Skel"; |
skelname = fullclassname + "_Skel"; |
1021 |
String skelclassname = classname + "_Skel"; |
String skelclassname = classname + "_Skel"; |
1022 |
ctrl = |
File file = new File(destination == null ? "" : destination |
1023 |
new TabbedWriter(new FileWriter((destination == null ? "" |
+ File.separator |
1024 |
: destination |
+ skelname.replace('.', File.separatorChar) |
1025 |
+ File.separator) |
+ ".class"); |
|
+ skelname.replace('.', |
|
|
File.separatorChar) |
|
|
+ ".java")); |
|
|
out = new PrintWriter(ctrl); |
|
|
|
|
1026 |
if (verbose) |
if (verbose) |
1027 |
System.out.println("[Generating class " + skelname + ".java]"); |
System.out.println("[Generating class " + skelname + "]"); |
1028 |
|
|
1029 |
|
final ClassWriter skel = new ClassWriter(true); |
1030 |
|
classInternalName = skelname.replace('.', '/'); |
1031 |
|
skel.visit |
1032 |
|
(C.V1_1, C.ACC_PUBLIC + C.ACC_FINAL, |
1033 |
|
classInternalName, Type.getInternalName(Object.class), |
1034 |
|
new String[] { Type.getType(Skeleton.class).getInternalName() }, null); |
1035 |
|
|
1036 |
|
skel.visitField |
1037 |
|
(C.ACC_PRIVATE + C.ACC_STATIC + C.ACC_FINAL, "interfaceHash", |
1038 |
|
Type.LONG_TYPE.getDescriptor(), |
1039 |
|
new Long(RMIHashes.getInterfaceHash(clazz)), |
1040 |
|
null); |
1041 |
|
|
1042 |
|
skel.visitField |
1043 |
|
(C.ACC_PRIVATE + C.ACC_STATIC + C.ACC_FINAL, "operations", |
1044 |
|
Type.getDescriptor(Operation[].class), null, null); |
1045 |
|
|
1046 |
|
CodeVisitor clinit = skel.visitMethod |
1047 |
|
(C.ACC_STATIC, "<clinit>", |
1048 |
|
Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}), null, null); |
1049 |
|
|
1050 |
|
fillOperationArray(clinit); |
1051 |
|
clinit.visitInsn(C.RETURN); |
1052 |
|
|
1053 |
|
clinit.visitMaxs(-1, -1); |
1054 |
|
|
1055 |
|
// no arg public constructor |
1056 |
|
CodeVisitor init = skel.visitMethod |
1057 |
|
(C.ACC_PUBLIC, "<init>", |
1058 |
|
Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {}), null, null); |
1059 |
|
init.visitVarInsn(C.ALOAD, 0); |
1060 |
|
init.visitMethodInsn |
1061 |
|
(C.INVOKESPECIAL, Type.getInternalName(Object.class), "<init>", |
1062 |
|
Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {})); |
1063 |
|
init.visitInsn(C.RETURN); |
1064 |
|
init.visitMaxs(-1, -1); |
1065 |
|
|
1066 |
|
/* |
1067 |
|
* public Operation[] getOperations() |
1068 |
|
* returns a clone of the operations array |
1069 |
|
*/ |
1070 |
|
CodeVisitor getOp = skel.visitMethod |
1071 |
|
(C.ACC_PUBLIC, "getOperations", |
1072 |
|
Type.getMethodDescriptor |
1073 |
|
(Type.getType(Operation[].class), new Type[] {}), |
1074 |
|
null, null); |
1075 |
|
getOp.visitFieldInsn |
1076 |
|
(C.GETSTATIC, classInternalName, "operations", |
1077 |
|
Type.getDescriptor(Operation[].class)); |
1078 |
|
getOp.visitMethodInsn |
1079 |
|
(C.INVOKEVIRTUAL, Type.getInternalName(Object.class), |
1080 |
|
"clone", Type.getMethodDescriptor(Type.getType(Object.class), |
1081 |
|
new Type[] {})); |
1082 |
|
getOp.visitTypeInsn(C.CHECKCAST, typeArg(Operation[].class)); |
1083 |
|
getOp.visitInsn(C.ARETURN); |
1084 |
|
getOp.visitMaxs(-1, -1); |
1085 |
|
|
1086 |
|
// public void dispatch(Remote, RemoteCall, int opnum, long hash) |
1087 |
|
CodeVisitor dispatch = skel.visitMethod |
1088 |
|
(C.ACC_PUBLIC, |
1089 |
|
"dispatch", |
1090 |
|
Type.getMethodDescriptor |
1091 |
|
(Type.VOID_TYPE, |
1092 |
|
new Type[] { Type.getType(Remote.class), |
1093 |
|
Type.getType(RemoteCall.class), |
1094 |
|
Type.INT_TYPE, Type.LONG_TYPE }), |
1095 |
|
new String[] { Type.getInternalName(Exception.class) }, |
1096 |
|
null); |
1097 |
|
|
1098 |
|
Variables var = new Variables(); |
1099 |
|
var.declare("this"); |
1100 |
|
var.declare("remoteobj"); |
1101 |
|
var.declare("remotecall"); |
1102 |
|
var.declare("opnum"); |
1103 |
|
var.declareWide("hash"); |
1104 |
|
|
1105 |
|
/* |
1106 |
|
* if opnum >= 0 |
1107 |
|
* XXX it is unclear why there is handling of negative opnums |
1108 |
|
*/ |
1109 |
|
dispatch.visitVarInsn(C.ILOAD, var.get("opnum")); |
1110 |
|
Label nonNegativeOpnum = new Label(); |
1111 |
|
Label opnumSet = new Label(); |
1112 |
|
dispatch.visitJumpInsn(C.IFGE, nonNegativeOpnum); |
1113 |
|
|
1114 |
out.println("// Skel class generated by rmic - DO NOT EDIT!"); |
for (int i = 0; i < remotemethods.length; i++) |
|
out.println(); |
|
|
if (fullclassname != classname) |
|
1115 |
{ |
{ |
1116 |
String pname = |
// assign opnum if hash matches supplied hash |
1117 |
fullclassname.substring(0, fullclassname.lastIndexOf('.')); |
dispatch.visitVarInsn(C.LLOAD, var.get("hash")); |
1118 |
out.println("package " + pname + ";"); |
dispatch.visitLdcInsn(new Long(remotemethods[i].hash)); |
1119 |
out.println(); |
Label notIt = new Label(); |
1120 |
} |
dispatch.visitInsn(C.LCMP); |
1121 |
|
dispatch.visitJumpInsn(C.IFNE, notIt); |
1122 |
|
|
1123 |
|
// opnum = <opnum> |
1124 |
|
dispatch.visitLdcInsn(new Integer(i)); |
1125 |
|
dispatch.visitVarInsn(C.ISTORE, var.get("opnum")); |
1126 |
|
dispatch.visitJumpInsn(C.GOTO, opnumSet); |
1127 |
|
dispatch.visitLabel(notIt); |
1128 |
|
} |
1129 |
|
|
1130 |
|
// throw new SkeletonMismatchException |
1131 |
|
Label mismatch = new Label(); |
1132 |
|
dispatch.visitJumpInsn(C.GOTO, mismatch); |
1133 |
|
|
1134 |
|
dispatch.visitLabel(nonNegativeOpnum); |
1135 |
|
|
1136 |
|
// if opnum is already set, check that the hash matches the interface |
1137 |
|
dispatch.visitVarInsn(C.LLOAD, var.get("hash")); |
1138 |
|
dispatch.visitFieldInsn |
1139 |
|
(C.GETSTATIC, classInternalName, |
1140 |
|
"interfaceHash", Type.LONG_TYPE.getDescriptor()); |
1141 |
|
dispatch.visitInsn(C.LCMP); |
1142 |
|
dispatch.visitJumpInsn(C.IFEQ, opnumSet); |
1143 |
|
|
1144 |
|
dispatch.visitLabel(mismatch); |
1145 |
|
dispatch.visitTypeInsn |
1146 |
|
(C.NEW, typeArg(SkeletonMismatchException.class)); |
1147 |
|
dispatch.visitInsn(C.DUP); |
1148 |
|
dispatch.visitLdcInsn("interface hash mismatch"); |
1149 |
|
dispatch.visitMethodInsn |
1150 |
|
(C.INVOKESPECIAL, |
1151 |
|
Type.getInternalName(SkeletonMismatchException.class), |
1152 |
|
"<init>", |
1153 |
|
Type.getMethodDescriptor |
1154 |
|
(Type.VOID_TYPE, new Type[] { Type.getType(String.class) })); |
1155 |
|
dispatch.visitInsn(C.ATHROW); |
1156 |
|
|
1157 |
|
// opnum has been set |
1158 |
|
dispatch.visitLabel(opnumSet); |
1159 |
|
|
1160 |
|
dispatch.visitVarInsn(C.ALOAD, var.get("remoteobj")); |
1161 |
|
dispatch.visitTypeInsn(C.CHECKCAST, typeArg(clazz)); |
1162 |
|
dispatch.visitVarInsn(C.ASTORE, var.get("remoteobj")); |
1163 |
|
|
1164 |
|
Label deflt = new Label(); |
1165 |
|
Label[] methLabels = new Label[remotemethods.length]; |
1166 |
|
for (int i = 0; i < methLabels.length; i++) |
1167 |
|
methLabels[i] = new Label(); |
1168 |
|
|
1169 |
|
// switch on opnum |
1170 |
|
dispatch.visitVarInsn(C.ILOAD, var.get("opnum")); |
1171 |
|
dispatch.visitTableSwitchInsn |
1172 |
|
(0, remotemethods.length - 1, deflt, methLabels); |
1173 |
|
|
1174 |
out.print("public final class " + skelclassname); |
// Method dispatch |
1175 |
ctrl.indent(); |
for (int i = 0; i < remotemethods.length; i++) |
1176 |
|
{ |
1177 |
|
dispatch.visitLabel(methLabels[i]); |
1178 |
|
Method m = remotemethods[i].meth; |
1179 |
|
generateMethodSkel(dispatch, m, var); |
1180 |
|
} |
1181 |
|
|
1182 |
|
dispatch.visitLabel(deflt); |
1183 |
|
dispatch.visitTypeInsn(C.NEW, typeArg(UnmarshalException.class)); |
1184 |
|
dispatch.visitInsn(C.DUP); |
1185 |
|
dispatch.visitLdcInsn("invalid method number"); |
1186 |
|
dispatch.visitMethodInsn |
1187 |
|
(C.INVOKESPECIAL, |
1188 |
|
Type.getInternalName(UnmarshalException.class), |
1189 |
|
"<init>", |
1190 |
|
Type.getMethodDescriptor |
1191 |
|
(Type.VOID_TYPE, new Type[] { Type.getType(String.class) })); |
1192 |
|
dispatch.visitInsn(C.ATHROW); |
1193 |
|
|
1194 |
|
dispatch.visitMaxs(-1, -1); |
1195 |
|
|
1196 |
|
skel.visitEnd(); |
1197 |
|
byte[] classData = skel.toByteArray(); |
1198 |
|
if (file.exists()) |
1199 |
|
file.delete(); |
1200 |
|
if (file.getParentFile() != null) |
1201 |
|
file.getParentFile().mkdirs(); |
1202 |
|
FileOutputStream fos = new FileOutputStream(file); |
1203 |
|
fos.write(classData); |
1204 |
|
fos.flush(); |
1205 |
|
fos.close(); |
1206 |
|
} |
1207 |
|
|
1208 |
// Output interfaces we implement |
private void generateMethodSkel(CodeVisitor cv, Method m, Variables var) |
1209 |
out.print("implements java.rmi.server.Skeleton"); |
{ |
1210 |
|
Class[] sig = m.getParameterTypes(); |
1211 |
|
|
1212 |
ctrl.unindent(); |
Label readArgs = new Label(); |
1213 |
out.print("{"); |
cv.visitLabel(readArgs); |
|
ctrl.indent(); |
|
1214 |
|
|
1215 |
// Interface hash - don't know how to calculate this - XXX |
boolean needcastcheck = false; |
|
out.println("private static final long interfaceHash = " |
|
|
+ RMIHashes.getInterfaceHash(clazz) + "L;"); |
|
|
out.println(); |
|
1216 |
|
|
1217 |
// Operation table |
// ObjectInput in = call.getInputStream(); |
1218 |
out.print("private static final java.rmi.server.Operation[] operations = {"); |
cv.visitVarInsn(C.ALOAD, var.get("remotecall")); |
1219 |
|
cv.visitMethodInsn |
1220 |
|
(C.INVOKEINTERFACE, |
1221 |
|
Type.getInternalName(RemoteCall.class), "getInputStream", |
1222 |
|
Type.getMethodDescriptor |
1223 |
|
(Type.getType(ObjectInput.class), new Type[] {})); |
1224 |
|
cv.visitVarInsn(C.ASTORE, var.allocate("objectinput")); |
1225 |
|
|
1226 |
|
for (int i = 0; i < sig.length; i++) |
1227 |
|
{ |
1228 |
|
// dup input stream |
1229 |
|
cv.visitVarInsn(C.ALOAD, var.get("objectinput")); |
1230 |
|
|
1231 |
|
Class readCls = sig[i].isPrimitive() ? sig[i] : Object.class; |
1232 |
|
|
1233 |
|
// in.readFoo() |
1234 |
|
cv.visitMethodInsn |
1235 |
|
(C.INVOKEINTERFACE, |
1236 |
|
Type.getInternalName(ObjectInput.class), |
1237 |
|
readMethod(sig[i]), |
1238 |
|
Type.getMethodDescriptor |
1239 |
|
(Type.getType(readCls), new Type [] {})); |
1240 |
|
|
1241 |
|
if (! sig[i].isPrimitive() && ! sig[i].equals(Object.class)) |
1242 |
|
{ |
1243 |
|
needcastcheck = true; |
1244 |
|
cv.visitTypeInsn(C.CHECKCAST, typeArg(sig[i])); |
1245 |
|
} |
1246 |
|
|
1247 |
|
// store arg in variable |
1248 |
|
cv.visitVarInsn |
1249 |
|
(storeOpcode(sig[i]), var.allocate(param(m, i), size(sig[i]))); |
1250 |
|
} |
1251 |
|
|
1252 |
|
var.deallocate("objectinput"); |
1253 |
|
|
1254 |
|
Label doCall = new Label(); |
1255 |
|
Label closeInput = new Label(); |
1256 |
|
|
1257 |
|
cv.visitJumpInsn(C.JSR, closeInput); |
1258 |
|
cv.visitJumpInsn(C.GOTO, doCall); |
1259 |
|
|
1260 |
|
// throw new UnmarshalException |
1261 |
|
Label handler = new Label(); |
1262 |
|
cv.visitLabel(handler); |
1263 |
|
cv.visitVarInsn(C.ASTORE, var.allocate("exception")); |
1264 |
|
cv.visitTypeInsn(C.NEW, typeArg(UnmarshalException.class)); |
1265 |
|
cv.visitInsn(C.DUP); |
1266 |
|
cv.visitLdcInsn("error unmarshalling arguments"); |
1267 |
|
cv.visitVarInsn(C.ALOAD, var.deallocate("exception")); |
1268 |
|
cv.visitMethodInsn |
1269 |
|
(C.INVOKESPECIAL, |
1270 |
|
Type.getInternalName(UnmarshalException.class), |
1271 |
|
"<init>", |
1272 |
|
Type.getMethodDescriptor |
1273 |
|
(Type.VOID_TYPE, new Type[] { Type.getType(String.class), |
1274 |
|
Type.getType(Exception.class) })); |
1275 |
|
cv.visitVarInsn(C.ASTORE, var.allocate("toThrow")); |
1276 |
|
cv.visitJumpInsn(C.JSR, closeInput); |
1277 |
|
cv.visitVarInsn(C.ALOAD, var.get("toThrow")); |
1278 |
|
cv.visitInsn(C.ATHROW); |
1279 |
|
|
1280 |
|
cv.visitTryCatchBlock |
1281 |
|
(readArgs, handler, handler, Type.getInternalName(IOException.class)); |
1282 |
|
if (needcastcheck) |
1283 |
|
{ |
1284 |
|
cv.visitTryCatchBlock |
1285 |
|
(readArgs, handler, handler, |
1286 |
|
Type.getInternalName(ClassCastException.class)); |
1287 |
|
} |
1288 |
|
|
1289 |
|
// finally block |
1290 |
|
cv.visitLabel(closeInput); |
1291 |
|
cv.visitVarInsn(C.ASTORE, var.allocate("retAddress")); |
1292 |
|
cv.visitVarInsn(C.ALOAD, var.get("remotecall")); |
1293 |
|
cv.visitMethodInsn |
1294 |
|
(C.INVOKEINTERFACE, |
1295 |
|
Type.getInternalName(RemoteCall.class), |
1296 |
|
"releaseInputStream", |
1297 |
|
Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {})); |
1298 |
|
cv.visitVarInsn(C.RET, var.deallocate("retAddress")); |
1299 |
|
var.deallocate("toThrow"); |
1300 |
|
|
1301 |
|
// do the call using args stored as variables |
1302 |
|
cv.visitLabel(doCall); |
1303 |
|
cv.visitVarInsn(C.ALOAD, var.get("remoteobj")); |
1304 |
|
for (int i = 0; i < sig.length; i++) |
1305 |
|
cv.visitVarInsn(loadOpcode(sig[i]), var.deallocate(param(m, i))); |
1306 |
|
cv.visitMethodInsn |
1307 |
|
(C.INVOKEVIRTUAL, Type.getInternalName(clazz), m.getName(), |
1308 |
|
Type.getMethodDescriptor(m)); |
1309 |
|
|
1310 |
|
Class returntype = m.getReturnType(); |
1311 |
|
if (! returntype.equals(Void.TYPE)) |
1312 |
|
{ |
1313 |
|
cv.visitVarInsn |
1314 |
|
(storeOpcode(returntype), var.allocate("result", size(returntype))); |
1315 |
|
} |
1316 |
|
|
1317 |
|
// write result to result stream |
1318 |
|
Label writeResult = new Label(); |
1319 |
|
cv.visitLabel(writeResult); |
1320 |
|
cv.visitVarInsn(C.ALOAD, var.get("remotecall")); |
1321 |
|
cv.visitInsn(C.ICONST_1); |
1322 |
|
cv.visitMethodInsn |
1323 |
|
(C.INVOKEINTERFACE, |
1324 |
|
Type.getInternalName(RemoteCall.class), |
1325 |
|
"getResultStream", |
1326 |
|
Type.getMethodDescriptor |
1327 |
|
(Type.getType(ObjectOutput.class), |
1328 |
|
new Type[] { Type.BOOLEAN_TYPE })); |
1329 |
|
|
1330 |
|
if (! returntype.equals(Void.TYPE)) |
1331 |
|
{ |
1332 |
|
// out.writeFoo(result) |
1333 |
|
cv.visitVarInsn(loadOpcode(returntype), var.deallocate("result")); |
1334 |
|
Class writeCls = returntype.isPrimitive() ? returntype : Object.class; |
1335 |
|
cv.visitMethodInsn |
1336 |
|
(C.INVOKEINTERFACE, |
1337 |
|
Type.getInternalName(ObjectOutput.class), |
1338 |
|
writeMethod(returntype), |
1339 |
|
Type.getMethodDescriptor |
1340 |
|
(Type.VOID_TYPE, new Type[] { Type.getType(writeCls) })); |
1341 |
|
} |
1342 |
|
|
1343 |
|
cv.visitInsn(C.RETURN); |
1344 |
|
|
1345 |
|
// throw new MarshalException |
1346 |
|
Label marshalHandler = new Label(); |
1347 |
|
cv.visitLabel(marshalHandler); |
1348 |
|
cv.visitVarInsn(C.ASTORE, var.allocate("exception")); |
1349 |
|
cv.visitTypeInsn(C.NEW, typeArg(MarshalException.class)); |
1350 |
|
cv.visitInsn(C.DUP); |
1351 |
|
cv.visitLdcInsn("error marshalling return"); |
1352 |
|
cv.visitVarInsn(C.ALOAD, var.deallocate("exception")); |
1353 |
|
cv.visitMethodInsn |
1354 |
|
(C.INVOKESPECIAL, |
1355 |
|
Type.getInternalName(MarshalException.class), |
1356 |
|
"<init>", |
1357 |
|
Type.getMethodDescriptor |
1358 |
|
(Type.VOID_TYPE, new Type[] { Type.getType(String.class), |
1359 |
|
Type.getType(Exception.class) })); |
1360 |
|
cv.visitInsn(C.ATHROW); |
1361 |
|
cv.visitTryCatchBlock |
1362 |
|
(writeResult, marshalHandler, marshalHandler, |
1363 |
|
Type.getInternalName(IOException.class)); |
1364 |
|
} |
1365 |
|
|
1366 |
ctrl.indent(); |
private static String typeArg(Class cls) |
1367 |
for (int i = 0; i < remotemethods.length; i++) |
{ |
1368 |
{ |
if (cls.isArray()) |
1369 |
Method m = remotemethods[i].meth; |
return Type.getDescriptor(cls); |
|
out.print("new java.rmi.server.Operation(\""); |
|
|
out.print(getPrettyName(m.getReturnType()) + " "); |
|
|
out.print(m.getName() + "("); |
|
|
// Output signature |
|
|
Class[] sig = m.getParameterTypes(); |
|
|
for (int j = 0; j < sig.length; j++) |
|
|
{ |
|
|
out.print(getPrettyName(sig[j])); |
|
|
if (j + 1 < sig.length) |
|
|
out.print(", "); |
|
|
} |
|
|
out.print("\")"); |
|
|
if (i + 1 < remotemethods.length) |
|
|
out.println(","); |
|
|
} |
|
|
ctrl.unindent(); |
|
|
out.println("};"); |
|
|
|
|
|
out.println(); |
|
|
|
|
|
// getOperations method |
|
|
out.print("public java.rmi.server.Operation[] getOperations() {"); |
|
|
ctrl.indent(); |
|
|
out.print("return ((java.rmi.server.Operation[]) operations.clone());"); |
|
|
ctrl.unindent(); |
|
|
out.println("}"); |
|
|
|
|
|
out.println(); |
|
|
|
|
|
// Dispatch method |
|
|
out.print("public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int opnum, long hash) throws java.lang.Exception {"); |
|
|
ctrl.indent(); |
|
1370 |
|
|
1371 |
out.print("if (opnum < 0) {"); |
return Type.getInternalName(cls); |
1372 |
ctrl.indent(); |
} |
1373 |
|
|
1374 |
for (int i = 0; i < remotemethods.length; i++) |
private static String readMethod(Class cls) |
1375 |
{ |
{ |
1376 |
out.print("if (hash == " + Long.toString(remotemethods[i].hash) |
if (cls.equals(Void.TYPE)) |
1377 |
+ "L) {"); |
throw new IllegalArgumentException("can not read void"); |
|
ctrl.indent(); |
|
|
out.print("opnum = " + i + ";"); |
|
|
ctrl.unindent(); |
|
|
out.println("}"); |
|
|
out.print("else "); |
|
|
} |
|
|
out.print("{"); |
|
|
ctrl.indent(); |
|
|
out.print("throw new java.rmi.server.SkeletonMismatchException(\"interface hash mismatch\");"); |
|
|
ctrl.unindent(); |
|
|
out.print("}"); |
|
|
|
|
|
ctrl.unindent(); |
|
|
out.println("}"); |
|
|
out.print("else if (hash != interfaceHash) {"); |
|
|
ctrl.indent(); |
|
|
out.print("throw new java.rmi.server.SkeletonMismatchException(\"interface hash mismatch\");"); |
|
|
ctrl.unindent(); |
|
|
out.println("}"); |
|
1378 |
|
|
1379 |
out.println(); |
String method; |
1380 |
|
if (cls.equals(Boolean.TYPE)) |
1381 |
|
method = "readBoolean"; |
1382 |
|
else if (cls.equals(Byte.TYPE)) |
1383 |
|
method = "readByte"; |
1384 |
|
else if (cls.equals(Character.TYPE)) |
1385 |
|
method = "readChar"; |
1386 |
|
else if (cls.equals(Short.TYPE)) |
1387 |
|
method = "readShort"; |
1388 |
|
else if (cls.equals(Integer.TYPE)) |
1389 |
|
method = "readInt"; |
1390 |
|
else if (cls.equals(Long.TYPE)) |
1391 |
|
method = "readLong"; |
1392 |
|
else if (cls.equals(Float.TYPE)) |
1393 |
|
method = "readFloat"; |
1394 |
|
else if (cls.equals(Double.TYPE)) |
1395 |
|
method = "readDouble"; |
1396 |
|
else |
1397 |
|
method = "readObject"; |
1398 |
|
|
1399 |
out.println(fullclassname + " server = (" + fullclassname + ")obj;"); |
return method; |
1400 |
out.println("switch (opnum) {"); |
} |
1401 |
|
|
1402 |
// Method dispatch |
private static String writeMethod(Class cls) |
1403 |
for (int i = 0; i < remotemethods.length; i++) |
{ |
1404 |
{ |
if (cls.equals(Void.TYPE)) |
1405 |
Method m = remotemethods[i].meth; |
throw new IllegalArgumentException("can not read void"); |
|
out.println("case " + i + ":"); |
|
|
out.print("{"); |
|
|
ctrl.indent(); |
|
1406 |
|
|
1407 |
Class[] sig = m.getParameterTypes(); |
String method; |
1408 |
for (int j = 0; j < sig.length; j++) |
if (cls.equals(Boolean.TYPE)) |
1409 |
{ |
method = "writeBoolean"; |
1410 |
out.print(getPrettyName(sig[j])); |
else if (cls.equals(Byte.TYPE)) |
1411 |
out.println(" $param_" + j + ";"); |
method = "writeByte"; |
1412 |
} |
else if (cls.equals(Character.TYPE)) |
1413 |
|
method = "writeChar"; |
1414 |
|
else if (cls.equals(Short.TYPE)) |
1415 |
|
method = "writeShort"; |
1416 |
|
else if (cls.equals(Integer.TYPE)) |
1417 |
|
method = "writeInt"; |
1418 |
|
else if (cls.equals(Long.TYPE)) |
1419 |
|
method = "writeLong"; |
1420 |
|
else if (cls.equals(Float.TYPE)) |
1421 |
|
method = "writeFloat"; |
1422 |
|
else if (cls.equals(Double.TYPE)) |
1423 |
|
method = "writeDouble"; |
1424 |
|
else |
1425 |
|
method = "writeObject"; |
1426 |
|
|
1427 |
out.print("try {"); |
return method; |
1428 |
boolean needcastcheck = false; |
} |
|
ctrl.indent(); |
|
|
out.println("java.io.ObjectInput in = call.getInputStream();"); |
|
|
for (int j = 0; j < sig.length; j++) |
|
|
{ |
|
|
out.print("$param_" + j + " = "); |
|
|
if (sig[j] == Boolean.TYPE) |
|
|
out.print("in.readBoolean();"); |
|
|
else if (sig[j] == Byte.TYPE) |
|
|
out.print("in.readByte();"); |
|
|
else if (sig[j] == Character.TYPE) |
|
|
out.print("in.readChar();"); |
|
|
else if (sig[j] == Short.TYPE) |
|
|
out.print("in.readShort();"); |
|
|
else if (sig[j] == Integer.TYPE) |
|
|
out.print("in.readInt();"); |
|
|
else if (sig[j] == Long.TYPE) |
|
|
out.print("in.readLong();"); |
|
|
else if (sig[j] == Float.TYPE) |
|
|
out.print("in.readFloat();"); |
|
|
else if (sig[j] == Double.TYPE) |
|
|
out.print("in.readDouble();"); |
|
|
else |
|
|
{ |
|
|
if (sig[j] != Object.class) |
|
|
{ |
|
|
out.print("(" + getPrettyName(sig[j]) + ")"); |
|
|
needcastcheck = true; |
|
|
} |
|
|
out.print("in.readObject();"); |
|
|
} |
|
|
out.println(); |
|
|
} |
|
|
ctrl.unindent(); |
|
|
out.println("}"); |
|
|
out.print("catch (java.io.IOException e) {"); |
|
|
ctrl.indent(); |
|
|
out.print("throw new java.rmi.UnmarshalException(\"error unmarshalling arguments\", e);"); |
|
|
ctrl.unindent(); |
|
|
out.println("}"); |
|
|
if (needcastcheck) |
|
|
{ |
|
|
out.print("catch (java.lang.ClassCastException e) {"); |
|
|
ctrl.indent(); |
|
|
out.print("throw new java.rmi.UnmarshalException(\"error unmarshalling arguments\", e);"); |
|
|
ctrl.unindent(); |
|
|
out.println("}"); |
|
|
} |
|
|
out.print("finally {"); |
|
|
ctrl.indent(); |
|
|
out.print("call.releaseInputStream();"); |
|
|
ctrl.unindent(); |
|
|
out.println("}"); |
|
|
|
|
|
Class returntype = m.getReturnType(); |
|
|
if (returntype != Void.TYPE) |
|
|
out.print(getPrettyName(returntype) + " $result = "); |
|
|
out.print("server." + m.getName() + "("); |
|
|
for (int j = 0; j < sig.length; j++) |
|
|
{ |
|
|
out.print("$param_" + j); |
|
|
if (j + 1 < sig.length) |
|
|
out.print(", "); |
|
|
} |
|
|
out.println(");"); |
|
1429 |
|
|
1430 |
out.print("try {"); |
private static int returnOpcode(Class cls) |
1431 |
ctrl.indent(); |
{ |
1432 |
out.print("java.io.ObjectOutput out = call.getResultStream(true);"); |
int returncode; |
1433 |
if (returntype != Void.TYPE) |
if (cls.equals(Boolean.TYPE)) |
1434 |
{ |
returncode = C.IRETURN; |
1435 |
out.println(); |
else if (cls.equals(Byte.TYPE)) |
1436 |
if (returntype == Boolean.TYPE) |
returncode = C.IRETURN; |
1437 |
out.print("out.writeBoolean($result);"); |
else if (cls.equals(Character.TYPE)) |
1438 |
else if (returntype == Byte.TYPE) |
returncode = C.IRETURN; |
1439 |
out.print("out.writeByte($result);"); |
else if (cls.equals(Short.TYPE)) |
1440 |
else if (returntype == Character.TYPE) |
returncode = C.IRETURN; |
1441 |
out.print("out.writeChar($result);"); |
else if (cls.equals(Integer.TYPE)) |
1442 |
else if (returntype == Short.TYPE) |
returncode = C.IRETURN; |
1443 |
out.print("out.writeShort($result);"); |
else if (cls.equals(Long.TYPE)) |
1444 |
else if (returntype == Integer.TYPE) |
returncode = C.LRETURN; |
1445 |
out.print("out.writeInt($result);"); |
else if (cls.equals(Float.TYPE)) |
1446 |
else if (returntype == Long.TYPE) |
returncode = C.FRETURN; |
1447 |
out.print("out.writeLong($result);"); |
else if (cls.equals(Double.TYPE)) |
1448 |
else if (returntype == Float.TYPE) |
returncode = C.DRETURN; |
1449 |
out.print("out.writeFloat($result);"); |
else if (cls.equals(Void.TYPE)) |
1450 |
else if (returntype == Double.TYPE) |
returncode = C.RETURN; |
1451 |
out.print("out.writeDouble($result);"); |
else |
1452 |
else |
returncode = C.ARETURN; |
|
out.print("out.writeObject($result);"); |
|
|
} |
|
|
ctrl.unindent(); |
|
|
out.println("}"); |
|
|
out.print("catch (java.io.IOException e) {"); |
|
|
ctrl.indent(); |
|
|
out.print("throw new java.rmi.MarshalException(\"error marshalling return\", e);"); |
|
|
ctrl.unindent(); |
|
|
out.println("}"); |
|
|
out.print("break;"); |
|
1453 |
|
|
1454 |
ctrl.unindent(); |
return returncode; |
1455 |
out.println("}"); |
} |
|
out.println(); |
|
|
} |
|
1456 |
|
|
1457 |
out.print("default:"); |
private static int loadOpcode(Class cls) |
1458 |
ctrl.indent(); |
{ |
1459 |
out.print("throw new java.rmi.UnmarshalException(\"invalid method number\");"); |
if (cls.equals(Void.TYPE)) |
1460 |
ctrl.unindent(); |
throw new IllegalArgumentException("can not load void"); |
|
out.print("}"); |
|
1461 |
|
|
1462 |
ctrl.unindent(); |
int loadcode; |
1463 |
out.print("}"); |
if (cls.equals(Boolean.TYPE)) |
1464 |
|
loadcode = C.ILOAD; |
1465 |
|
else if (cls.equals(Byte.TYPE)) |
1466 |
|
loadcode = C.ILOAD; |
1467 |
|
else if (cls.equals(Character.TYPE)) |
1468 |
|
loadcode = C.ILOAD; |
1469 |
|
else if (cls.equals(Short.TYPE)) |
1470 |
|
loadcode = C.ILOAD; |
1471 |
|
else if (cls.equals(Integer.TYPE)) |
1472 |
|
loadcode = C.ILOAD; |
1473 |
|
else if (cls.equals(Long.TYPE)) |
1474 |
|
loadcode = C.LLOAD; |
1475 |
|
else if (cls.equals(Float.TYPE)) |
1476 |
|
loadcode = C.FLOAD; |
1477 |
|
else if (cls.equals(Double.TYPE)) |
1478 |
|
loadcode = C.DLOAD; |
1479 |
|
else |
1480 |
|
loadcode = C.ALOAD; |
1481 |
|
|
1482 |
|
return loadcode; |
1483 |
|
} |
1484 |
|
|
1485 |
ctrl.unindent(); |
private static int storeOpcode(Class cls) |
1486 |
out.println("}"); |
{ |
1487 |
|
if (cls.equals(Void.TYPE)) |
1488 |
|
throw new IllegalArgumentException("can not load void"); |
1489 |
|
|
1490 |
out.close(); |
int storecode; |
1491 |
|
if (cls.equals(Boolean.TYPE)) |
1492 |
|
storecode = C.ISTORE; |
1493 |
|
else if (cls.equals(Byte.TYPE)) |
1494 |
|
storecode = C.ISTORE; |
1495 |
|
else if (cls.equals(Character.TYPE)) |
1496 |
|
storecode = C.ISTORE; |
1497 |
|
else if (cls.equals(Short.TYPE)) |
1498 |
|
storecode = C.ISTORE; |
1499 |
|
else if (cls.equals(Integer.TYPE)) |
1500 |
|
storecode = C.ISTORE; |
1501 |
|
else if (cls.equals(Long.TYPE)) |
1502 |
|
storecode = C.LSTORE; |
1503 |
|
else if (cls.equals(Float.TYPE)) |
1504 |
|
storecode = C.FSTORE; |
1505 |
|
else if (cls.equals(Double.TYPE)) |
1506 |
|
storecode = C.DSTORE; |
1507 |
|
else |
1508 |
|
storecode = C.ASTORE; |
1509 |
|
|
1510 |
|
return storecode; |
1511 |
} |
} |
1512 |
|
|
1513 |
private void compile(String name) throws Exception |
private static String unboxMethod(Class primitive) |
1514 |
{ |
{ |
1515 |
Compiler comp = Compiler.getInstance(); |
if (! primitive.isPrimitive()) |
1516 |
if (verbose) |
throw new IllegalArgumentException("can not unbox nonprimitive"); |
1517 |
System.out.println("[Compiling class " + name + "]"); |
|
1518 |
comp.setDestination(destination); |
String method; |
1519 |
comp.compile(name); |
if (primitive.equals(Boolean.TYPE)) |
1520 |
|
method = "booleanValue"; |
1521 |
|
else if (primitive.equals(Byte.TYPE)) |
1522 |
|
method = "byteValue"; |
1523 |
|
else if (primitive.equals(Character.TYPE)) |
1524 |
|
method = "charValue"; |
1525 |
|
else if (primitive.equals(Short.TYPE)) |
1526 |
|
method = "shortValue"; |
1527 |
|
else if (primitive.equals(Integer.TYPE)) |
1528 |
|
method = "intValue"; |
1529 |
|
else if (primitive.equals(Long.TYPE)) |
1530 |
|
method = "longValue"; |
1531 |
|
else if (primitive.equals(Float.TYPE)) |
1532 |
|
method = "floatValue"; |
1533 |
|
else if (primitive.equals(Double.TYPE)) |
1534 |
|
method = "doubleValue"; |
1535 |
|
else |
1536 |
|
throw new IllegalStateException("unknown primitive class " + primitive); |
1537 |
|
|
1538 |
|
return method; |
1539 |
} |
} |
1540 |
|
|
1541 |
private static String getPrettyName(Class cls) |
public static Class box(Class cls) |
1542 |
{ |
{ |
1543 |
StringBuffer str = new StringBuffer(); |
if (! cls.isPrimitive()) |
1544 |
for (int count = 0;; count++) |
throw new IllegalArgumentException("can only box primitive"); |
1545 |
{ |
|
1546 |
if (! cls.isArray()) |
Class box; |
1547 |
{ |
if (cls.equals(Boolean.TYPE)) |
1548 |
str.append(cls.getName()); |
box = Boolean.class; |
1549 |
for (; count > 0; count--) |
else if (cls.equals(Byte.TYPE)) |
1550 |
str.append("[]"); |
box = Byte.class; |
1551 |
return (str.toString()); |
else if (cls.equals(Character.TYPE)) |
1552 |
} |
box = Character.class; |
1553 |
cls = cls.getComponentType(); |
else if (cls.equals(Short.TYPE)) |
1554 |
} |
box = Short.class; |
1555 |
|
else if (cls.equals(Integer.TYPE)) |
1556 |
|
box = Integer.class; |
1557 |
|
else if (cls.equals(Long.TYPE)) |
1558 |
|
box = Long.class; |
1559 |
|
else if (cls.equals(Float.TYPE)) |
1560 |
|
box = Float.class; |
1561 |
|
else if (cls.equals(Double.TYPE)) |
1562 |
|
box = Double.class; |
1563 |
|
else |
1564 |
|
throw new IllegalStateException("unknown primitive type " + cls); |
1565 |
|
|
1566 |
|
return box; |
1567 |
|
} |
1568 |
|
|
1569 |
|
private static int size(Class cls) { |
1570 |
|
if (cls.equals(Long.TYPE) || cls.equals(Double.TYPE)) |
1571 |
|
return 2; |
1572 |
|
else |
1573 |
|
return 1; |
1574 |
} |
} |
1575 |
|
|
1576 |
/** |
/** |
1577 |
* Sort exceptions so the most general go last. |
* Sort exceptions so the most general go last. |
1578 |
*/ |
*/ |
1579 |
private Class[] sortExceptions(Class[] except) |
private Class[] sortExceptions(Class[] except) |
1580 |
{ |
{ |
1581 |
for (int i = 0; i < except.length; i++) |
for (int i = 0; i < except.length; i++) |
1593 |
return (except); |
return (except); |
1594 |
} |
} |
1595 |
|
|
1596 |
/** |
/** |
1597 |
* Process the options until we find the first argument. |
* Process the options until we find the first argument. |
1598 |
*/ |
*/ |
1599 |
private void parseOptions() |
private void parseOptions() |
1600 |
{ |
{ |
1601 |
for (;;) |
for (;;) |
1642 |
else if (arg.equals("-nocompile")) |
else if (arg.equals("-nocompile")) |
1643 |
compile = false; |
compile = false; |
1644 |
else if (arg.equals("-classpath")) |
else if (arg.equals("-classpath")) |
1645 |
next++; |
{ |
1646 |
|
classpath = args[next]; |
1647 |
|
next++; |
1648 |
|
StringTokenizer st = |
1649 |
|
new StringTokenizer(classpath, File.pathSeparator); |
1650 |
|
URL[] u = new URL[st.countTokens()]; |
1651 |
|
for (int i = 0; i < u.length; i++) |
1652 |
|
{ |
1653 |
|
String path = st.nextToken(); |
1654 |
|
File f = new File(path); |
1655 |
|
try |
1656 |
|
{ |
1657 |
|
u[i] = f.toURL(); |
1658 |
|
} |
1659 |
|
catch (java.net.MalformedURLException mue) |
1660 |
|
{ |
1661 |
|
error("malformed classpath component " + path); |
1662 |
|
} |
1663 |
|
} |
1664 |
|
loader = new URLClassLoader(u); |
1665 |
|
} |
1666 |
else if (arg.equals("-help")) |
else if (arg.equals("-help")) |
1667 |
usage(); |
usage(); |
1668 |
else if (arg.equals("-version")) |
else if (arg.equals("-version")) |
1688 |
} |
} |
1689 |
} |
} |
1690 |
|
|
1691 |
/** |
private void findRemoteMethods() { |
1692 |
* Looks for the java.rmi.Remote interface that that is implemented by theClazz. |
List rmeths = new ArrayList(); |
1693 |
* @param theClazz the class to look in |
for (Class cur = clazz; cur != null; cur = cur.getSuperclass()) |
1694 |
* @return the Remote interface of theClazz or null if theClazz does not implement a Remote interface |
{ |
1695 |
*/ |
Class[] interfaces = cur.getInterfaces(); |
1696 |
private Class getRemoteInterface(Class theClazz) |
for (int i = 0; i < interfaces.length; i++) |
1697 |
{ |
{ |
1698 |
Class[] interfaces = theClazz.getInterfaces(); |
if (java.rmi.Remote.class.isAssignableFrom(interfaces[i])) |
1699 |
for (int i = 0; i < interfaces.length; i++) |
{ |
1700 |
{ |
Class remoteInterface = interfaces[i]; |
1701 |
if (java.rmi.Remote.class.isAssignableFrom(interfaces[i])) |
if (verbose) |
1702 |
return interfaces[i]; |
System.out.println |
1703 |
} |
("[implements " + remoteInterface.getName() + "]"); |
1704 |
logError("Class " + theClazz.getName() |
|
1705 |
+ " is not a remote object. It does not implement an interface that is a java.rmi.Remote-interface."); |
// check if the methods declare RemoteExceptions |
1706 |
return null; |
Method[] meths = remoteInterface.getMethods(); |
1707 |
} |
for (int j = 0; j < meths.length; j++) |
1708 |
|
{ |
1709 |
/** |
Method m = meths[j]; |
1710 |
* Prints an error to System.err and increases the error count. |
Class[] exs = m.getExceptionTypes(); |
1711 |
* @param theError |
|
1712 |
*/ |
boolean throwsRemote = false; |
1713 |
|
for (int k = 0; k < exs.length; k++) |
1714 |
|
{ |
1715 |
|
if (exs[k].isAssignableFrom(RemoteException.class)) |
1716 |
|
throwsRemote = true; |
1717 |
|
} |
1718 |
|
|
1719 |
|
if (! throwsRemote) |
1720 |
|
{ |
1721 |
|
logError("Method " + m |
1722 |
|
+ " does not throw a RemoteException"); |
1723 |
|
continue; |
1724 |
|
} |
1725 |
|
|
1726 |
|
rmeths.add(m); |
1727 |
|
} |
1728 |
|
|
1729 |
|
mRemoteInterfaces.add(remoteInterface); |
1730 |
|
} |
1731 |
|
} |
1732 |
|
} |
1733 |
|
|
1734 |
|
// intersect exceptions for doubly inherited methods |
1735 |
|
boolean[] skip = new boolean[rmeths.size()]; |
1736 |
|
for (int i = 0; i < skip.length; i++) |
1737 |
|
skip[i] = false; |
1738 |
|
List methrefs = new ArrayList(); |
1739 |
|
for (int i = 0; i < rmeths.size(); i++) |
1740 |
|
{ |
1741 |
|
if (skip[i]) continue; |
1742 |
|
Method current = (Method) rmeths.get(i); |
1743 |
|
MethodRef ref = new MethodRef(current); |
1744 |
|
for (int j = i+1; j < rmeths.size(); j++) |
1745 |
|
{ |
1746 |
|
Method other = (Method) rmeths.get(j); |
1747 |
|
if (ref.isMatch(other)) |
1748 |
|
{ |
1749 |
|
ref.intersectExceptions(other); |
1750 |
|
skip[j] = true; |
1751 |
|
} |
1752 |
|
} |
1753 |
|
methrefs.add(ref); |
1754 |
|
} |
1755 |
|
|
1756 |
|
// Convert into a MethodRef array and sort them |
1757 |
|
remotemethods = (MethodRef[]) |
1758 |
|
methrefs.toArray(new MethodRef[methrefs.size()]); |
1759 |
|
Arrays.sort(remotemethods); |
1760 |
|
} |
1761 |
|
|
1762 |
|
/** |
1763 |
|
* Prints an error to System.err and increases the error count. |
1764 |
|
* @param theError |
1765 |
|
*/ |
1766 |
private void logError(String theError) |
private void logError(String theError) |
1767 |
{ |
{ |
1768 |
errorCount++; |
errorCount++; |
1779 |
private static void usage() |
private static void usage() |
1780 |
{ |
{ |
1781 |
System.out.println("Usage: rmic [OPTION]... CLASS...\n" + "\n" |
System.out.println("Usage: rmic [OPTION]... CLASS...\n" + "\n" |
1782 |
+ " -keep Don't delete any intermediate files\n" |
+ " -keep * Don't delete any intermediate files\n" |
1783 |
+ " -keepgenerated Same as -keep\n" |
+ " -keepgenerated * Same as -keep\n" |
1784 |
+ " -v1.1 Java 1.1 style stubs only\n" |
+ " -v1.1 Java 1.1 style stubs only\n" |
1785 |
+ " -vcompat Java 1.1 & Java 1.2 stubs\n" |
+ " -vcompat Java 1.1 & Java 1.2 stubs\n" |
1786 |
+ " -v1.2 Java 1.2 style stubs only\n" |
+ " -v1.2 Java 1.2 style stubs only\n" |
1787 |
+ " -g * Generated debugging information\n" |
+ " -g * Generated debugging information\n" |
1788 |
+ " -depend * Recompile out-of-date files\n" |
+ " -depend * Recompile out-of-date files\n" |
1789 |
+ " -nowarn * Suppress warning messages\n" |
+ " -nowarn * Suppress warning messages\n" |
1790 |
+ " -nocompile Don't compile the generated files\n" |
+ " -nocompile * Don't compile the generated files\n" |
1791 |
+ " -verbose Output what's going on\n" |
+ " -verbose Output what's going on\n" |
1792 |
+ " -classpath <path> * Use given path as classpath\n" |
+ " -classpath <path> Use given path as classpath\n" |
1793 |
+ " -d <directory> Specify where to place generated classes\n" |
+ " -d <directory> Specify where to place generated classes\n" |
1794 |
+ " -J<flag> * Pass flag to Java\n" |
+ " -J<flag> * Pass flag to Java\n" |
1795 |
+ " -help Print this help, then exit\n" |
+ " -help Print this help, then exit\n" |
1799 |
System.exit(0); |
System.exit(0); |
1800 |
} |
} |
1801 |
|
|
1802 |
static class MethodRef |
private static String getPrettyName(Class cls) |
1803 |
|
{ |
1804 |
|
StringBuffer str = new StringBuffer(); |
1805 |
|
for (int count = 0;; count++) |
1806 |
|
{ |
1807 |
|
if (! cls.isArray()) |
1808 |
|
{ |
1809 |
|
str.append(cls.getName()); |
1810 |
|
for (; count > 0; count--) |
1811 |
|
str.append("[]"); |
1812 |
|
return (str.toString()); |
1813 |
|
} |
1814 |
|
cls = cls.getComponentType(); |
1815 |
|
} |
1816 |
|
} |
1817 |
|
|
1818 |
|
private static class MethodRef |
1819 |
implements Comparable |
implements Comparable |
1820 |
{ |
{ |
1821 |
Method meth; |
Method meth; |
|
String sig; |
|
1822 |
long hash; |
long hash; |
1823 |
|
List exceptions; |
1824 |
|
private String sig; |
1825 |
|
|
1826 |
MethodRef(Method m) |
MethodRef(Method m) { |
|
{ |
|
1827 |
meth = m; |
meth = m; |
1828 |
// We match on the name - but what about overloading? - XXX |
sig = Type.getMethodDescriptor(meth); |
|
sig = m.getName(); |
|
1829 |
hash = RMIHashes.getMethodHash(m); |
hash = RMIHashes.getMethodHash(m); |
1830 |
|
// add exceptions removing subclasses |
1831 |
|
exceptions = removeSubclasses(m.getExceptionTypes()); |
1832 |
} |
} |
1833 |
|
|
1834 |
public int compareTo(Object obj) |
public int compareTo(Object obj) { |
|
{ |
|
1835 |
MethodRef that = (MethodRef) obj; |
MethodRef that = (MethodRef) obj; |
1836 |
return (this.sig.compareTo(that.sig)); |
int name = this.meth.getName().compareTo(that.meth.getName()); |
1837 |
|
if (name == 0) { |
1838 |
|
return this.sig.compareTo(that.sig); |
1839 |
|
} |
1840 |
|
return name; |
1841 |
|
} |
1842 |
|
|
1843 |
|
public boolean isMatch(Method m) |
1844 |
|
{ |
1845 |
|
if (!meth.getName().equals(m.getName())) |
1846 |
|
return false; |
1847 |
|
|
1848 |
|
Class[] params1 = meth.getParameterTypes(); |
1849 |
|
Class[] params2 = m.getParameterTypes(); |
1850 |
|
if (params1.length != params2.length) |
1851 |
|
return false; |
1852 |
|
|
1853 |
|
for (int i = 0; i < params1.length; i++) |
1854 |
|
if (!params1[i].equals(params2[i])) return false; |
1855 |
|
|
1856 |
|
return true; |
1857 |
|
} |
1858 |
|
|
1859 |
|
private static List removeSubclasses(Class[] classes) |
1860 |
|
{ |
1861 |
|
List list = new ArrayList(); |
1862 |
|
for (int i = 0; i < classes.length; i++) |
1863 |
|
{ |
1864 |
|
Class candidate = classes[i]; |
1865 |
|
boolean add = true; |
1866 |
|
for (int j = 0; j < classes.length; j++) |
1867 |
|
{ |
1868 |
|
if (classes[j].equals(candidate)) |
1869 |
|
continue; |
1870 |
|
else if (classes[j].isAssignableFrom(candidate)) |
1871 |
|
add = false; |
1872 |
|
} |
1873 |
|
if (add) list.add(candidate); |
1874 |
|
} |
1875 |
|
|
1876 |
|
return list; |
1877 |
|
} |
1878 |
|
|
1879 |
|
public void intersectExceptions(Method m) |
1880 |
|
{ |
1881 |
|
List incoming = removeSubclasses(m.getExceptionTypes()); |
1882 |
|
|
1883 |
|
List updated = new ArrayList(); |
1884 |
|
|
1885 |
|
for (int i = 0; i < exceptions.size(); i++) |
1886 |
|
{ |
1887 |
|
Class outer = (Class) exceptions.get(i); |
1888 |
|
boolean addOuter = false; |
1889 |
|
for (int j = 0; j < incoming.size(); j++) |
1890 |
|
{ |
1891 |
|
Class inner = (Class) incoming.get(j); |
1892 |
|
|
1893 |
|
if (inner.equals(outer) || inner.isAssignableFrom(outer)) |
1894 |
|
addOuter = true; |
1895 |
|
else if (outer.isAssignableFrom(inner)) |
1896 |
|
updated.add(inner); |
1897 |
|
} |
1898 |
|
|
1899 |
|
if (addOuter) |
1900 |
|
updated.add(outer); |
1901 |
|
} |
1902 |
|
|
1903 |
|
exceptions = updated; |
1904 |
} |
} |
1905 |
} |
} |
1906 |
} |
} |