gcc/
[official-gcc.git] / libjava / java / lang / VMCompiler.java
blob1f600f12e90eebcef1b1ee5ac9b38ba3528ee005
1 /* VMClassLoader.java -- Reference implementation of compiler interface
2 Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
38 package java.lang;
40 import java.io.File;
41 import java.io.FileOutputStream;
42 import java.io.InputStreamReader;
43 import java.security.MessageDigest;
44 import java.security.ProtectionDomain;
45 import java.security.NoSuchAlgorithmException;
46 import java.util.WeakHashMap;
47 import java.util.HashSet;
48 import java.util.Enumeration;
49 import java.util.StringTokenizer;
50 import java.util.Vector;
51 import gnu.gcj.runtime.SharedLibHelper;
52 import gnu.gcj.runtime.PersistentByteMap;
53 import gnu.java.security.hash.MD5;
55 /**
56 * This class is just a per-VM reflection of java.lang.Compiler.
57 * All methods are defined identically.
59 final class VMCompiler
61 // True if we want to use gcj-jit.
62 public static boolean useCompiler = true;
64 // True if we're able to use gcj-jit.
65 public static final boolean canUseCompiler;
67 // Compiler to use.
68 public static String gcjJitCompiler;
70 // Compiler options.
71 public static String gcjJitCompilerOptions;
73 // Temporary directory to use.
74 public static String gcjJitTmpdir;
76 public static boolean precompiles()
78 return (canUseCompiler & useCompiler);
81 // This maps a ClassLoader to a set of SharedLibHelper objects that
82 // it has used. We do things this way to ensure that a
83 // SharedLibHelper is collected if and only if the ClassLoader is.
84 private static WeakHashMap sharedHelperMap = new WeakHashMap();
86 private static Vector precompiledMapFiles;
88 // We create a single MD5 engine and then clone it whenever we want
89 // a new one.
91 // We don't use
93 // md5Digest = MessageDigest.getInstance("MD5");
95 // here because that loads a great deal of security provider code as
96 // interpreted bytecode -- before we're able to use this class to
97 // load precompiled classes.
99 private static final MD5 md5Digest
100 = new gnu.java.security.hash.MD5();
102 static
104 gcjJitCompiler = System.getProperty("gnu.gcj.jit.compiler");
105 if (gcjJitCompiler == null)
106 canUseCompiler = false;
107 else
109 gcjJitCompilerOptions = System.getProperty("gnu.gcj.jit.options",
110 "-g");
111 gcjJitTmpdir = System.getProperty("gnu.gcj.jit.cachedir");
112 // Note that we *don't* choose java.io.tmpdir as a default --
113 // that would allow easy attacks against the VM.
114 if (gcjJitTmpdir == null)
115 canUseCompiler = false;
116 else
117 canUseCompiler = true;
120 String prop = System.getProperty ("gnu.gcj.precompiled.db.path");
121 if (prop != null)
123 precompiledMapFiles = new Vector();
124 // Add the
125 StringTokenizer st
126 = new StringTokenizer (prop,
127 System.getProperty ("path.separator", ":"));
129 while (st.hasMoreElements ())
131 String e = st.nextToken ();
134 PersistentByteMap map
135 = new PersistentByteMap
136 (e, PersistentByteMap.AccessMode.READ_ONLY);
137 precompiledMapFiles.add(map);
139 catch (IllegalArgumentException _)
141 // Not a map file
143 catch (java.io.IOException _)
146 catch (java.nio.BufferUnderflowException _)
148 // Invalid map file.
156 * Don't allow new `Compiler's to be made.
158 private VMCompiler()
162 private static Class loadSharedLibrary(ClassLoader loader,
163 String fileName,
164 ProtectionDomain domain,
165 String className)
167 Class c = null;
168 SharedLibHelper helper
169 = SharedLibHelper.findHelper (loader, fileName, domain.getCodeSource(),
170 domain, false);
171 c = helper.findClass (className);
172 if (c != null)
174 HashSet hs = (HashSet) sharedHelperMap.get(loader);
175 if (hs == null)
177 hs = new HashSet();
178 sharedHelperMap.put(loader, hs);
180 hs.add(helper);
182 return c;
186 * Compile a class given the bytes for it. Returns the Class, or
187 * null if compilation failed or otherwise could not be done.
189 public static Class compileClass(ClassLoader loader,
190 String name, byte[] data,
191 int offset, int len,
192 ProtectionDomain domain)
194 if (precompiledMapFiles == null && !precompiles())
195 return null;
197 byte digest[];
201 MD5 md = (MD5) md5Digest.clone();
202 md.update(data);
203 digest = md.digest();
205 catch (NullPointerException _)
207 // If md5Digest==null -- but really this should never happen
208 // either, since the MD5 digest is in libgcj.
209 return null;
212 // We use lookaside cache files to determine whether these bytes
213 // correspond to a class file that is part of a precompiled DSO.
214 if (precompiledMapFiles != null)
218 Enumeration elements = precompiledMapFiles.elements();
219 while (elements.hasMoreElements())
221 PersistentByteMap map = (PersistentByteMap)elements.nextElement();
222 byte[] soName = map.get(digest);
223 if (soName != null)
224 return loadSharedLibrary(loader,
225 new String(soName),
226 domain, name);
229 catch (Exception _)
232 catch (UnknownError _)
234 // SharedLibHelper will throw UnknownError if the dlopen
235 // fails for some reason. We ignore it and continue on.
239 if (!precompiles())
240 return null;
244 // FIXME: Make sure that the class represented by the
245 // bytes in DATA really is the class named in NAME. Make
246 // sure it's not "java.*".
247 StringBuffer hexBytes = new StringBuffer(gcjJitTmpdir);
248 hexBytes.append(File.separatorChar);
249 int digestLength = digest.length;
250 for (int i = 0; i < digestLength; ++i)
252 int v = digest[i] & 0xff;
253 if (v < 16)
254 hexBytes.append('0');
255 hexBytes.append(Integer.toHexString(v));
258 // FIXME: use System.mapLibraryName?
259 // I'm thinking we should use that, plus a class specified
260 // via a property that determines lookup policy.
261 File soFile = new File(hexBytes + ".so");
262 if (soFile.isFile())
263 return loadSharedLibrary (loader, soFile.toString(), domain,
264 name);
266 File classFile = new File(hexBytes + ".class");
267 classFile.delete();
268 if (classFile.createNewFile() != true)
269 return null;
271 FileOutputStream f = new FileOutputStream (classFile);
272 // FIXME: race condition if bytes change... ?
273 f.write(data, offset, len);
275 // Invoke the compiler.
276 StringBuffer command = new StringBuffer(gcjJitCompiler);
277 command.append(" ");
278 command.append(classFile);
279 command.append(" ");
280 command.append(gcjJitCompilerOptions);
281 // These options are required.
282 command.append(" -findirect-dispatch -fjni -shared -fPIC -o ");
283 command.append(soFile);
284 Process p = Runtime.getRuntime().exec(command.toString());
286 // Read the process' stderr into a string.
287 StringBuffer err = new StringBuffer();
288 InputStreamReader stderr = new InputStreamReader (p.getErrorStream());
289 char[] inBuf = new char[500];
290 int bytesRead;
291 while ((bytesRead = stderr.read (inBuf)) != -1)
292 err.append(inBuf, 0, bytesRead);
294 if (p.waitFor() != 0)
296 // FIXME: we could log err.toString() somewhere...
297 return null;
300 return loadSharedLibrary(loader, soFile.toString(), domain, name);
302 catch (Exception _)
304 return null;
309 * Compile the class named by <code>oneClass</code>.
311 * @param oneClass the class to compile
312 * @return <code>false</code> if no compiler is available or
313 * compilation failed, <code>true</code> if compilation succeeded
314 * @throws NullPointerException if oneClass is null
316 public static boolean compileClass(Class oneClass)
318 // Never succeed.
319 return false;
323 * Compile the classes whose name matches <code>classNames</code>.
325 * @param classNames the name of classes to compile
326 * @return <code>false</code> if no compiler is available or
327 * compilation failed, <code>true</code> if compilation succeeded
328 * @throws NullPointerException if classNames is null
330 public static boolean compileClasses(String classNames)
332 // Note the incredibly lame interface. Always fail.
333 return false;
337 * This method examines the argument and performs an operation
338 * according to the compilers documentation. No specific operation
339 * is required.
341 * @param arg a compiler-specific argument
342 * @return a compiler-specific value, including null
343 * @throws NullPointerException if the compiler doesn't like a null arg
345 public static Object command(Object arg)
347 // Our implementation defines this to a no-op.
348 return null;
352 * Calling <code>Compiler.enable()</code> will cause the compiler
353 * to resume operation if it was previously disabled; provided that a
354 * compiler even exists.
356 public static void enable()
358 useCompiler = true;
362 * Calling <code>Compiler.disable()</code> will cause the compiler
363 * to be suspended; provided that a compiler even exists.
365 public static void disable()
367 useCompiler = false;