diff options
author | Tom Tromey <tromey@gcc.gnu.org> | 2004-11-25 03:47:08 +0000 |
---|---|---|
committer | Tom Tromey <tromey@gcc.gnu.org> | 2004-11-25 03:47:08 +0000 |
commit | 367390404d26b7bfc400d77893579e83e2a19fb9 (patch) | |
tree | 477abdf83653e20b0e74447d6ca47eb67b0511b8 /libjava/java | |
parent | ec0641f612862498e829fdaf040a201c0ba68762 (diff) | |
download | gcc-367390404d26b7bfc400d77893579e83e2a19fb9.tar.gz |
* Merged gcj-abi-2-dev-branch to trunk.
(Actual changes too large to list in the commit message;
see ChangeLog.)
From-SVN: r91270
Diffstat (limited to 'libjava/java')
-rw-r--r-- | libjava/java/io/ObjectInputStream.java | 25 | ||||
-rw-r--r-- | libjava/java/io/ObjectOutputStream.java | 12 | ||||
-rw-r--r-- | libjava/java/lang/Class.h | 139 | ||||
-rw-r--r-- | libjava/java/lang/ClassLoader.java | 18 | ||||
-rw-r--r-- | libjava/java/lang/Compiler.java | 13 | ||||
-rw-r--r-- | libjava/java/lang/SecurityManager.java | 6 | ||||
-rw-r--r-- | libjava/java/lang/VMClassLoader.java | 47 | ||||
-rw-r--r-- | libjava/java/lang/VMCompiler.java | 332 | ||||
-rw-r--r-- | libjava/java/lang/VMSecurityManager.java | 3 | ||||
-rw-r--r-- | libjava/java/lang/natClass.cc | 1133 | ||||
-rw-r--r-- | libjava/java/lang/natClassLoader.cc | 194 | ||||
-rw-r--r-- | libjava/java/lang/natRuntime.cc | 11 | ||||
-rw-r--r-- | libjava/java/lang/natString.cc | 17 | ||||
-rw-r--r-- | libjava/java/lang/natVMClassLoader.cc | 136 | ||||
-rw-r--r-- | libjava/java/lang/reflect/natField.cc | 4 | ||||
-rw-r--r-- | libjava/java/lang/reflect/natMethod.cc | 9 | ||||
-rw-r--r-- | libjava/java/net/URLClassLoader.java | 151 |
17 files changed, 907 insertions, 1343 deletions
diff --git a/libjava/java/io/ObjectInputStream.java b/libjava/java/io/ObjectInputStream.java index 646eaebe4c7..0c79d332700 100644 --- a/libjava/java/io/ObjectInputStream.java +++ b/libjava/java/io/ObjectInputStream.java @@ -121,15 +121,15 @@ public class ObjectInputStream extends InputStream */ public final Object readObject() throws ClassNotFoundException, IOException { - if (callersClassLoader == null) - { - callersClassLoader = getCallersClassLoader (); - if (Configuration.DEBUG && dump) - { - dumpElementln ("CallersClassLoader = " + callersClassLoader); - } - } - + if (callersClassLoader == null) + { + callersClassLoader = getCallersClassLoader (); + if (Configuration.DEBUG && dump) + { + dumpElementln ("CallersClassLoader = " + callersClassLoader); + } + } + if (this.useSubclassMethod) return readObjectOverride(); @@ -271,7 +271,7 @@ public class ObjectInputStream extends InputStream readArrayElements(array, componentType); if(dump) for (int i = 0, len = Array.getLength(array); i < len; i++) - dumpElementln(" ELEMENT[" + i + "]=" + Array.get(array, i)); + dumpElementln(" ELEMENT[" + i + "]=" + Array.get(array, i)); ret_val = processResolution(null, array, handle); break; } @@ -398,6 +398,8 @@ public class ObjectInputStream extends InputStream setBlockDataMode(old_mode); this.isDeserializing = was_deserializing; + + depth -= 2; depth -= 2; @@ -1806,6 +1808,7 @@ public class ObjectInputStream extends InputStream * @param sm SecurityManager instance which should be called. * @return The current class loader in the calling stack. */ + private static native ClassLoader currentClassLoader (SecurityManager sm); private native ClassLoader getCallersClassLoader(); @@ -1875,7 +1878,7 @@ public class ObjectInputStream extends InputStream private int depth = 0; private void dumpElement (String msg) - { + { System.out.print(msg); } diff --git a/libjava/java/io/ObjectOutputStream.java b/libjava/java/io/ObjectOutputStream.java index 6a5eed7a24c..3482225232a 100644 --- a/libjava/java/io/ObjectOutputStream.java +++ b/libjava/java/io/ObjectOutputStream.java @@ -347,8 +347,8 @@ public class ObjectOutputStream extends OutputStream fieldsAlreadyWritten = false; if (currentObjectStreamClass.hasWriteMethod()) { - if (dump) - dumpElementln ("WRITE METHOD CALLED FOR: " + obj); + if (dump) + dumpElementln ("WRITE METHOD CALLED FOR: " + obj); setBlockDataMode(true); callWriteMethod(obj, currentObjectStreamClass); setBlockDataMode(false); @@ -358,10 +358,10 @@ public class ObjectOutputStream extends OutputStream } else { - if (dump) - dumpElementln ("WRITE FIELDS CALLED FOR: " + obj); - writeFields(obj, currentObjectStreamClass); - } + if (dump) + dumpElementln ("WRITE FIELDS CALLED FOR: " + obj); + writeFields(obj, currentObjectStreamClass); + } } this.currentObject = prevObject; diff --git a/libjava/java/lang/Class.h b/libjava/java/lang/Class.h index a60e80a22d9..320b09965d0 100644 --- a/libjava/java/lang/Class.h +++ b/libjava/java/lang/Class.h @@ -42,13 +42,15 @@ enum JV_STATE_PRELOADING = 1, // Can do _Jv_FindClass. JV_STATE_LOADING = 3, // Has super installed. - JV_STATE_COMPILED = 5, // This was a compiled class. + JV_STATE_READ = 4, // Has been completely defined. + JV_STATE_LOADED = 5, // Has Miranda methods defined. + + JV_STATE_COMPILED = 6, // This was a compiled class. - JV_STATE_LOADED = 6, // Is complete. JV_STATE_PREPARED = 7, // Layout & static init done. JV_STATE_LINKED = 9, // Strings interned. - JV_STATE_IN_PROGRESS = 10, // <Clinit> running. + JV_STATE_IN_PROGRESS = 10, // <clinit> running. JV_STATE_ERROR = 12, @@ -59,6 +61,9 @@ struct _Jv_Field; struct _Jv_VTable; union _Jv_word; struct _Jv_ArrayVTable; +class _Jv_ExecutionEngine; +class _Jv_CompiledEngine; +class _Jv_InterpreterEngine; struct _Jv_Constants { @@ -106,7 +111,7 @@ union _Jv_IDispatchTable } iface; }; -// Used by _Jv_GetInterfaces () +// Used by _Jv_Linker::get_interfaces () struct _Jv_ifaces { jclass *list; @@ -139,6 +144,23 @@ struct _Jv_CatchClass _Jv_Utf8Const *classname; }; +// Possible values for the assertion_code field in the type assertion table. +enum +{ + JV_ASSERT_END_OF_TABLE = 0, + JV_ASSERT_TYPES_COMPATIBLE = 1, + JV_ASSERT_IS_INSTANTIABLE = 2 +}; + +// Entry in the type assertion table, used to validate type constraints +// for binary compatibility. +struct _Jv_TypeAssertion +{ + jint assertion_code; + _Jv_Utf8Const *op1; + _Jv_Utf8Const *op2; +}; + #define JV_PRIMITIVE_VTABLE ((_Jv_VTable *) -1) #define JV_CLASS(Obj) ((jclass) (*(_Jv_VTable **) Obj)->clas) @@ -149,11 +171,11 @@ struct _Jv_CatchClass _Jv_Method *_Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name, _Jv_Utf8Const *signature); jboolean _Jv_IsAssignableFrom (jclass, jclass); +jboolean _Jv_IsAssignableFromSlow (jclass, jclass); jboolean _Jv_InterfaceAssignableFrom (jclass, jclass); -void _Jv_InitClass (jclass klass); _Jv_Method* _Jv_LookupDeclaredMethod (jclass, _Jv_Utf8Const *, - _Jv_Utf8Const*); + _Jv_Utf8Const*, jclass * = NULL); jfieldID JvGetFirstInstanceField (jclass); jint JvNumInstanceFields (jclass); jfieldID JvGetFirstStaticField (jclass); @@ -183,10 +205,6 @@ class java::io::ObjectOutputStream; class java::io::ObjectInputStream; class java::io::ObjectStreamClass; -void _Jv_WaitForState (jclass, int); -void _Jv_RegisterClasses (const jclass *classes); -void _Jv_RegisterClasses_Counted (const jclass *classes, - size_t count); void _Jv_RegisterClassHookDefault (jclass klass); void _Jv_RegisterInitiatingLoader (jclass,java::lang::ClassLoader*); void _Jv_UnregisterClass (jclass); @@ -205,19 +223,7 @@ void _Jv_InitNewClassFields (jclass klass); // Friend functions and classes in prims.cc void _Jv_InitPrimClass (jclass, char *, char, int); -void _Jv_PrepareCompiledClass (jclass); -void _Jv_PrepareConstantTimeTables (jclass); -jshort _Jv_GetInterfaces (jclass, _Jv_ifaces *); -void _Jv_GenerateITable (jclass, _Jv_ifaces *, jshort *); jstring _Jv_GetMethodString (jclass, _Jv_Utf8Const *); -jshort _Jv_AppendPartialITable (jclass, jclass, void **, jshort); -jshort _Jv_FindIIndex (jclass *, jshort *, jshort); -void _Jv_LinkSymbolTable (jclass); -void _Jv_LayoutInterfaceMethods (jclass); -void _Jv_LayoutVTableMethods (jclass klass); -void _Jv_SetVTableEntries (jclass, _Jv_VTable *, jboolean *); -void _Jv_MakeVTable (jclass); -void _Jv_linkExceptionClassTable (jclass); jboolean _Jv_CheckAccess (jclass self_klass, jclass other_klass, jint flags); @@ -225,25 +231,14 @@ jclass _Jv_GetArrayClass (jclass klass, java::lang::ClassLoader *loader); #ifdef INTERPRETER jboolean _Jv_IsInterpretedClass (jclass); -void _Jv_InitField (jobject, jclass, _Jv_Field*); void _Jv_InitField (jobject, jclass, int); -_Jv_word _Jv_ResolvePoolEntry (jclass, int); -_Jv_Method *_Jv_SearchMethodInClass (jclass cls, jclass klass, - _Jv_Utf8Const *method_name, - _Jv_Utf8Const *method_signature); -void _Jv_PrepareClass (jclass); -void _Jv_PrepareMissingMethods (jclass base, jclass iface_class); - -void _Jv_Defer_Resolution (void *cl, _Jv_Method *meth, void **); - class _Jv_ClassReader; class _Jv_InterpClass; class _Jv_InterpMethod; #endif class _Jv_BytecodeVerifier; -class _Jv_StackTrace; class gnu::gcj::runtime::StackTrace; class java::io::VMObjectStreamClass; @@ -316,9 +311,14 @@ public: void setSigners(JArray<jobject> *); inline jclass getSuperclass (void) - { - return superclass; - } + { + return superclass; + } + + inline jclass getInterface (jint n) + { + return interfaces[n]; + } inline jboolean isArray (void) { @@ -351,9 +351,16 @@ public: // FIXME: this probably shouldn't be public. jint size (void) - { - return size_in_bytes; - } + { + return size_in_bytes; + } + + // The index of the first method we declare ourself (as opposed to + // inheriting). + inline jint firstMethodIndex (void) + { + return vtable_method_count - method_count; + } // finalization void finalize (); @@ -372,10 +379,17 @@ private: static jstring getPackagePortion (jstring); + void set_state (jint nstate) + { + state = nstate; + notifyAll (); + } + // Friend functions implemented in natClass.cc. friend _Jv_Method *::_Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name, _Jv_Utf8Const *signature); friend jboolean (::_Jv_IsAssignableFrom) (jclass, jclass); + friend jboolean (::_Jv_IsAssignableFromSlow) (jclass, jclass); friend jboolean (::_Jv_InterfaceAssignableFrom) (jclass, jclass); friend void *::_Jv_LookupInterfaceMethodIdx (jclass klass, jclass iface, int method_idx); @@ -383,7 +397,7 @@ private: friend void ::_Jv_InitClass (jclass klass); friend _Jv_Method* ::_Jv_LookupDeclaredMethod (jclass, _Jv_Utf8Const *, - _Jv_Utf8Const*); + _Jv_Utf8Const*, jclass *); friend jfieldID (::JvGetFirstInstanceField) (jclass); friend jint (::JvNumInstanceFields) (jclass); friend jfieldID (::JvGetFirstStaticField) (jclass); @@ -413,7 +427,6 @@ private: friend class java::io::ObjectInputStream; friend class java::io::ObjectStreamClass; - friend void ::_Jv_WaitForState (jclass, int); friend void ::_Jv_RegisterClasses (const jclass *classes); friend void ::_Jv_RegisterClasses_Counted (const jclass *classes, size_t count); @@ -436,40 +449,22 @@ private: // in prims.cc friend void ::_Jv_InitPrimClass (jclass, char *, char, int); - friend void ::_Jv_PrepareCompiledClass (jclass); - friend void ::_Jv_PrepareConstantTimeTables (jclass); - friend jshort (::_Jv_GetInterfaces) (jclass, _Jv_ifaces *); - friend void ::_Jv_GenerateITable (jclass, _Jv_ifaces *, jshort *); friend jstring (::_Jv_GetMethodString) (jclass, _Jv_Utf8Const *); - friend jshort (::_Jv_AppendPartialITable) (jclass, jclass, void **, jshort); - friend jshort (::_Jv_FindIIndex) (jclass *, jshort *, jshort); - friend void ::_Jv_LinkSymbolTable (jclass); - friend void ::_Jv_LayoutInterfaceMethods (jclass); - friend void ::_Jv_LayoutVTableMethods (jclass klass); - friend void ::_Jv_SetVTableEntries (jclass, _Jv_VTable *, jboolean *); - friend void ::_Jv_MakeVTable (jclass); - friend void ::_Jv_linkExceptionClassTable (jclass); friend jboolean (::_Jv_CheckAccess) (jclass self_klass, jclass other_klass, jint flags); + + friend bool _Jv_getInterfaceMethod(jclass, jclass&, int&, + const _Jv_Utf8Const*, + const _Jv_Utf8Const*); friend jclass (::_Jv_GetArrayClass) (jclass klass, java::lang::ClassLoader *loader); #ifdef INTERPRETER friend jboolean (::_Jv_IsInterpretedClass) (jclass); - friend void ::_Jv_InitField (jobject, jclass, _Jv_Field*); friend void ::_Jv_InitField (jobject, jclass, int); - friend _Jv_word (::_Jv_ResolvePoolEntry) (jclass, int); - friend _Jv_Method *::_Jv_SearchMethodInClass (jclass cls, jclass klass, - _Jv_Utf8Const *method_name, - _Jv_Utf8Const *method_signature); - friend void ::_Jv_PrepareClass (jclass); - friend void ::_Jv_PrepareMissingMethods (jclass base, jclass iface_class); - - friend void ::_Jv_Defer_Resolution (void *cl, _Jv_Method *meth, void **); - friend class ::_Jv_ClassReader; friend class ::_Jv_InterpClass; friend class ::_Jv_InterpMethod; @@ -480,10 +475,14 @@ private: #endif friend class ::_Jv_BytecodeVerifier; - friend class ::_Jv_StackTrace; friend class gnu::gcj::runtime::StackTrace; friend class java::io::VMObjectStreamClass; + friend class _Jv_Linker; + friend class _Jv_ExecutionEngine; + friend class _Jv_CompiledEngine; + friend class _Jv_InterpreterEngine; + friend void ::_Jv_sharedlib_register_hook (jclass klass); // Chain for class pool. @@ -518,8 +517,12 @@ private: _Jv_OffsetTable *otable; // Offset table symbols. _Jv_MethodSymbol *otable_syms; + // Address table _Jv_AddressTable *atable; _Jv_MethodSymbol *atable_syms; + // Interface table + _Jv_AddressTable *itable; + _Jv_MethodSymbol *itable_syms; _Jv_CatchClass *catch_classes; // Interfaces implemented by this class. jclass *interfaces; @@ -542,13 +545,17 @@ private: jclass arrayclass; // Security Domain to which this class belongs (or null). java::security::ProtectionDomain *protectionDomain; + // Pointer to the type assertion table for this class. + _Jv_TypeAssertion *assertion_table; // Signers of this class (or null). JArray<jobject> *hack_signers; // Used by Jv_PopClass and _Jv_PushClass to communicate with StackTrace. jclass chain; - // Additional data, specific to the generator (JIT, native, interpreter) of this - // class. + // Additional data, specific to the generator (JIT, native, + // interpreter) of this class. void *aux_info; + // Execution engine. + _Jv_ExecutionEngine *engine; }; // Inline functions that are friends of java::lang::Class diff --git a/libjava/java/lang/ClassLoader.java b/libjava/java/lang/ClassLoader.java index 75f07169f39..648afca5435 100644 --- a/libjava/java/lang/ClassLoader.java +++ b/libjava/java/lang/ClassLoader.java @@ -288,6 +288,8 @@ public abstract class ClassLoader if (c != null) return c; + ClassNotFoundException ex = null; + // Can the class be loaded by a parent? try { @@ -304,9 +306,20 @@ public abstract class ClassLoader } catch (ClassNotFoundException e) { + ex = e; } // Still not found, we have to do it ourself. - c = findClass(name); + try + { + c = findClass(name); + } + catch (ClassNotFoundException cause) + { + if (ex != null) + throw new ClassNotFoundException(ex.toString(), cause); + else + throw cause; + } if (resolve) resolveClass(c); return c; @@ -435,8 +448,9 @@ public abstract class ClassLoader domain = defaultProtectionDomain; if (! initialized) throw new SecurityException("attempt to define class from uninitialized class loader"); + Class retval = VMClassLoader.defineClass(this, name, data, - offset, len, domain); + offset, len, domain); loadedClasses.put(retval.getName(), retval); return retval; } diff --git a/libjava/java/lang/Compiler.java b/libjava/java/lang/Compiler.java index f520a7e0dda..858f63ee993 100644 --- a/libjava/java/lang/Compiler.java +++ b/libjava/java/lang/Compiler.java @@ -1,5 +1,5 @@ /* Compiler.java -- placeholder for Java-to-native runtime compilers - Copyright (C) 1998, 1999, 2001, 2002 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2001, 2002, 2004 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -76,8 +76,7 @@ public final class Compiler */ public static boolean compileClass(Class oneClass) { - // Never succeed. - return false; + return VMCompiler.compileClass(oneClass); } /** @@ -90,8 +89,7 @@ public final class Compiler */ public static boolean compileClasses(String classNames) { - // Note the incredibly lame interface. Always fail. - return false; + return VMCompiler.compileClasses(classNames); } /** @@ -105,8 +103,7 @@ public final class Compiler */ public static Object command(Object arg) { - // Our implementation defines this to a no-op. - return null; + return VMCompiler.command(arg); } /** @@ -116,6 +113,7 @@ public final class Compiler */ public static void enable() { + VMCompiler.enable(); } /** @@ -124,5 +122,6 @@ public final class Compiler */ public static void disable() { + VMCompiler.disable(); } } diff --git a/libjava/java/lang/SecurityManager.java b/libjava/java/lang/SecurityManager.java index 2e82a475b5f..972b312d943 100644 --- a/libjava/java/lang/SecurityManager.java +++ b/libjava/java/lang/SecurityManager.java @@ -324,7 +324,7 @@ public class SecurityManager public void checkPermission(Permission perm) { // XXX Should be: AccessController.checkPermission(perm); - throw new SecurityException("Operation not allowed"); + //.throw new SecurityException("Operation not allowed"); } /** @@ -553,7 +553,7 @@ public class SecurityManager // throw new SecurityException("Missing context"); // AccessControlContext ac = (AccessControlContext) context; // ac.checkPermission(new FilePermission(filename, "read")); - throw new SecurityException("Cannot read files via file names."); + // throw new SecurityException("Cannot read files via file names."); } /** @@ -677,7 +677,7 @@ public class SecurityManager // // Use the toString() hack to do the null check. // ac.checkPermission(new SocketPermission(host.toString + ":" +port, // "connect")); - throw new SecurityException("Cannot make network connections."); + // throw new SecurityException("Cannot make network connections."); } /** diff --git a/libjava/java/lang/VMClassLoader.java b/libjava/java/lang/VMClassLoader.java index ac7a05e3cd9..8f78f9bb666 100644 --- a/libjava/java/lang/VMClassLoader.java +++ b/libjava/java/lang/VMClassLoader.java @@ -97,44 +97,31 @@ final class VMClassLoader ProtectionDomain pd) throws ClassFormatError; - static final native void linkClass0 (Class klass); - static final native void markClassErrorState0 (Class klass); - /** * Helper to resolve all references to other classes from this class. * * @param c the class to resolve */ - static final void resolveClass(Class clazz) + static final native void resolveClass(Class clazz); + + static final void transformException(Class clazz, Throwable x) { - synchronized (clazz) + LinkageError e; + if (x instanceof LinkageError) + e = (LinkageError) x; + else if (x instanceof ClassNotFoundException) { - try - { - linkClass0 (clazz); - } - catch (Throwable x) - { - markClassErrorState0 (clazz); - - LinkageError e; - if (x instanceof LinkageError) - e = (LinkageError) x; - else if (x instanceof ClassNotFoundException) - { - e = new NoClassDefFoundError("while resolving class: " - + clazz.getName()); - e.initCause (x); - } - else - { - e = new LinkageError ("unexpected exception during linking: " - + clazz.getName()); - e.initCause (x); - } - throw e; - } + e = new NoClassDefFoundError("while resolving class: " + + clazz.getName()); + e.initCause (x); + } + else + { + e = new LinkageError ("unexpected exception during linking: " + + clazz.getName()); + e.initCause (x); } + throw e; } /** diff --git a/libjava/java/lang/VMCompiler.java b/libjava/java/lang/VMCompiler.java new file mode 100644 index 00000000000..98efc7ee44f --- /dev/null +++ b/libjava/java/lang/VMCompiler.java @@ -0,0 +1,332 @@ +/* VMClassLoader.java -- Reference implementation of compiler interface + Copyright (C) 2004 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.lang; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStreamReader; +import java.security.MessageDigest; +import java.security.ProtectionDomain; +import java.security.NoSuchAlgorithmException; +import java.util.WeakHashMap; +import java.util.HashSet; +import java.util.Enumeration; +import java.util.StringTokenizer; +import java.util.Vector; +import gnu.gcj.runtime.SharedLibHelper; +import gnu.gcj.runtime.PersistentByteMap; + +/** + * This class is just a per-VM reflection of java.lang.Compiler. + * All methods are defined identically. + */ +final class VMCompiler +{ + // True if we want to use gcj-jit. + public static boolean useCompiler = true; + + // True if we're able to use gcj-jit. + public static final boolean canUseCompiler; + + // Compiler to use. + public static String gcjJitCompiler; + + // Compiler options. + public static String gcjJitCompilerOptions; + + // Temporary directory to use. + public static String gcjJitTmpdir; + + // This maps a ClassLoader to a set of SharedLibHelper objects that + // it has used. We do things this way to ensure that a + // SharedLibHelper is collected if and only if the ClassLoader is. + private static WeakHashMap sharedHelperMap = new WeakHashMap(); + + private static Vector precompiledMapFiles; + + static + { + gcjJitCompiler = System.getProperty("gnu.gcj.jit.compiler"); + if (gcjJitCompiler == null) + canUseCompiler = false; + else + { + gcjJitCompilerOptions = System.getProperty("gnu.gcj.jit.options", + "-g"); + gcjJitTmpdir = System.getProperty("gnu.gcj.jit.cachedir"); + // Note that we *don't* choose java.io.tmpdir as a default -- + // that would allow easy attacks against the VM. + if (gcjJitTmpdir == null) + canUseCompiler = false; + else + canUseCompiler = true; + } + + String prop = System.getProperty ("gnu.gcj.precompiled.db.path"); + if (prop != null) + { + precompiledMapFiles = new Vector(); + // Add the + StringTokenizer st + = new StringTokenizer (prop, + System.getProperty ("path.separator", ":")); + { + while (st.hasMoreElements ()) + { + String e = st.nextToken (); + try + { + PersistentByteMap map + = new PersistentByteMap + (e, PersistentByteMap.AccessMode.READ_ONLY); + precompiledMapFiles.add(map); + } + catch (IllegalArgumentException _) + { + // Not a map file + } + catch (java.io.IOException _) + { + } + } + } + } + } + + /** + * Don't allow new `Compiler's to be made. + */ + private VMCompiler() + { + } + + private static Class loadSharedLibrary(ClassLoader loader, + String fileName, + ProtectionDomain domain, + String className) + { + Class c = null; + SharedLibHelper helper + = SharedLibHelper.findHelper (loader, fileName, domain.getCodeSource()); + c = helper.findClass (className); + if (c != null) + { + HashSet hs = (HashSet) sharedHelperMap.get(loader); + if (hs == null) + { + hs = new HashSet(); + sharedHelperMap.put(loader, hs); + } + hs.add(helper); + } + return c; + } + + /** + * Compile a class given the bytes for it. Returns the Class, or + * null if compilation failed or otherwise could not be done. + */ + public static Class compileClass(ClassLoader loader, + String name, byte[] data, + int offset, int len, + ProtectionDomain domain) + { + if (precompiledMapFiles == null + && (! useCompiler || ! canUseCompiler)) + return null; + + byte digest[]; + + try + { + MessageDigest md = MessageDigest.getInstance("MD5"); + digest = md.digest(data); + } + catch (NoSuchAlgorithmException _) + { + return null; + } + + // We use lookaside cache files to determine whether these bytes + // correspond to a class file that is part of a precompiled DSO. + if (precompiledMapFiles != null) + { + try + { + Enumeration elements = precompiledMapFiles.elements(); + while (elements.hasMoreElements()) + { + PersistentByteMap map = (PersistentByteMap)elements.nextElement(); + byte[] soName = map.get(digest); + if (soName != null) + return loadSharedLibrary(loader, + new String(soName), + domain, name); + } + } + catch (Exception _) + { + } + } + + if (! useCompiler || ! canUseCompiler) + return null; + + try + { + // FIXME: Make sure that the class represented by the + // bytes in DATA really is the class named in NAME. Make + // sure it's not "java.*". + StringBuffer hexBytes = new StringBuffer(gcjJitTmpdir); + hexBytes.append(File.separatorChar); + int digestLength = digest.length; + for (int i = 0; i < digestLength; ++i) + hexBytes.append(Integer.toHexString(digest[i] & 0xff)); + + // FIXME: use System.mapLibraryName? + // I'm thinking we should use that, plus a class specified + // via a property that determines lookup policy. + File soFile = new File(hexBytes + ".so"); + if (soFile.isFile()) + return loadSharedLibrary (loader, soFile.toString(), domain, + name); + + File classFile = new File(hexBytes + ".class"); + classFile.delete(); + if (classFile.createNewFile() != true) + return null; + + FileOutputStream f = new FileOutputStream (classFile); + // FIXME: race condition if bytes change... ? + f.write(data, offset, len); + + // Invoke the compiler. + StringBuffer command = new StringBuffer(gcjJitCompiler); + command.append(" "); + command.append(classFile); + command.append(" "); + command.append(gcjJitCompilerOptions); + // These options are required. + command.append(" -findirect-dispatch -fjni -shared -fPIC -o "); + command.append(soFile); + Process p = Runtime.getRuntime().exec(command.toString()); + + // Read the process' stderr into a string. + StringBuffer err = new StringBuffer(); + InputStreamReader stderr = new InputStreamReader (p.getErrorStream()); + char[] inBuf = new char[500]; + int bytesRead; + while ((bytesRead = stderr.read (inBuf)) != -1) + err.append(inBuf, 0, bytesRead); + + if (p.waitFor() != 0) + { + // FIXME: we could log err.toString() somewhere... + return null; + } + + return loadSharedLibrary(loader, soFile.toString(), domain, name); + } + catch (Exception _) + { + return null; + } + } + + /** + * Compile the class named by <code>oneClass</code>. + * + * @param oneClass the class to compile + * @return <code>false</code> if no compiler is available or + * compilation failed, <code>true</code> if compilation succeeded + * @throws NullPointerException if oneClass is null + */ + public static boolean compileClass(Class oneClass) + { + // Never succeed. + return false; + } + + /** + * Compile the classes whose name matches <code>classNames</code>. + * + * @param classNames the name of classes to compile + * @return <code>false</code> if no compiler is available or + * compilation failed, <code>true</code> if compilation succeeded + * @throws NullPointerException if classNames is null + */ + public static boolean compileClasses(String classNames) + { + // Note the incredibly lame interface. Always fail. + return false; + } + + /** + * This method examines the argument and performs an operation + * according to the compilers documentation. No specific operation + * is required. + * + * @param arg a compiler-specific argument + * @return a compiler-specific value, including null + * @throws NullPointerException if the compiler doesn't like a null arg + */ + public static Object command(Object arg) + { + // Our implementation defines this to a no-op. + return null; + } + + /** + * Calling <code>Compiler.enable()</code> will cause the compiler + * to resume operation if it was previously disabled; provided that a + * compiler even exists. + */ + public static void enable() + { + useCompiler = true; + } + + /** + * Calling <code>Compiler.disable()</code> will cause the compiler + * to be suspended; provided that a compiler even exists. + */ + public static void disable() + { + useCompiler = false; + } +} diff --git a/libjava/java/lang/VMSecurityManager.java b/libjava/java/lang/VMSecurityManager.java index f6f0645ac75..604f8ecb428 100644 --- a/libjava/java/lang/VMSecurityManager.java +++ b/libjava/java/lang/VMSecurityManager.java @@ -54,11 +54,12 @@ class VMSecurityManager // The docs above are wrong. See the online docs. // FIXME this implementation is a bit wrong too -- the docs say we // must also consider ancestors of the system class loader. + ClassLoader systemClassLoader = VMClassLoader.getSystemClassLoader(); Class[] classStack = getClassContext (); for (int i = 0; i < classStack.length; i++) { ClassLoader loader = classStack[i].getClassLoader(); - if (loader != null) + if (loader != null && loader != systemClassLoader) return loader; } diff --git a/libjava/java/lang/natClass.cc b/libjava/java/lang/natClass.cc index 920245cd586..0e9c26c7b4f 100644 --- a/libjava/java/lang/natClass.cc +++ b/libjava/java/lang/natClass.cc @@ -14,6 +14,7 @@ details. */ #include <limits.h> #include <string.h> #include <stddef.h> +#include <stdio.h> #pragma implementation "Class.h" @@ -56,16 +57,17 @@ details. */ #include <gcj/method.h> #include <gnu/gcj/runtime/MethodRef.h> #include <gnu/gcj/RawData.h> +#include <java/lang/VerifyError.h> #include <java-cpool.h> #include <java-interp.h> +#include <java-assert.h> +#include <execution.h> using namespace gcj; -bool gcj::verbose_class_flag; - jclass java::lang::Class::forName (jstring className, jboolean initialize, java::lang::ClassLoader *loader) @@ -485,7 +487,12 @@ java::lang::Class::getInterfaces (void) jobjectArray r = JvNewObjectArray (interface_count, getClass (), NULL); jobject *data = elements (r); for (int i = 0; i < interface_count; ++i) - data[i] = interfaces[i]; + { + typedef unsigned int uaddr __attribute__ ((mode (pointer))); + data[i] = interfaces[i]; + if ((uaddr)data[i] < (uaddr)constants.size) + fprintf (stderr, "ERROR !!!\n"); + } return reinterpret_cast<JArray<jclass> *> (r); } @@ -495,7 +502,8 @@ java::lang::Class::_getMethod (jstring name, JArray<jclass> *param_types) jstring partial_sig = getSignature (param_types, false); jint p_len = partial_sig->length(); _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name); - for (Class *klass = this; klass; klass = klass->getSuperclass()) + + for (Class *klass = this; klass; klass = klass->getSuperclass()) { int i = klass->isPrimitive () ? 0 : klass->method_count; while (--i >= 0) @@ -699,10 +707,7 @@ java::lang::Class::newInstance (void) void java::lang::Class::finalize (void) { -#ifdef INTERPRETER - JvAssert (_Jv_IsInterpretedClass (this)); - _Jv_UnregisterClass (this); -#endif + engine->unregister(this); } // This implements the initialization process for a class. From Spec @@ -710,67 +715,37 @@ java::lang::Class::finalize (void) void java::lang::Class::initializeClass (void) { - // short-circuit to avoid needless locking. + // Short-circuit to avoid needless locking. if (state == JV_STATE_DONE) return; - // Step 1. - _Jv_MonitorEnter (this); + // Step 1. We introduce a new scope so we can synchronize more + // easily. + { + JvSynchronize sync (this); - if (state < JV_STATE_LINKED) - { -#ifdef INTERPRETER - if (_Jv_IsInterpretedClass (this)) - { - // this can throw exceptions, so exit the monitor as a precaution. - _Jv_MonitorExit (this); - java::lang::VMClassLoader::resolveClass (this); - _Jv_MonitorEnter (this); - } - else -#endif - { - _Jv_PrepareCompiledClass (this); - } - } - - // Step 2. - java::lang::Thread *self = java::lang::Thread::currentThread(); - // FIXME: `self' can be null at startup. Hence this nasty trick. - self = (java::lang::Thread *) ((long) self | 1); - while (state == JV_STATE_IN_PROGRESS && thread && thread != self) - wait (); - - // Steps 3 & 4. - if (state == JV_STATE_DONE) - { - _Jv_MonitorExit (this); - return; - } - if (state == JV_STATE_IN_PROGRESS) - { - _Jv_MonitorExit (this); + if (state < JV_STATE_LINKED) + java::lang::VMClassLoader::resolveClass (this); - /* Initialization in progress. The class is linked now, - so ensure internal tables are built. */ - _Jv_PrepareConstantTimeTables (this); - _Jv_MakeVTable(this); - _Jv_LinkSymbolTable(this); + // Step 2. + java::lang::Thread *self = java::lang::Thread::currentThread(); + self = (java::lang::Thread *) ((long) self | 1); + while (state == JV_STATE_IN_PROGRESS && thread && thread != self) + wait (); + // Steps 3 & 4. + if (state == JV_STATE_DONE || state == JV_STATE_IN_PROGRESS) return; - } - // Step 5. - if (state == JV_STATE_ERROR) - { - _Jv_MonitorExit (this); + // Step 5. + if (state == JV_STATE_ERROR) throw new java::lang::NoClassDefFoundError (getName()); - } - // Step 6. - thread = self; - state = JV_STATE_IN_PROGRESS; - _Jv_MonitorExit (this); + // Step 6. + thread = self; + _Jv_Linker::wait_for_state (this, JV_STATE_LINKED); + state = JV_STATE_IN_PROGRESS; + } // Step 7. if (! isInterface () && superclass) @@ -782,24 +757,13 @@ java::lang::Class::initializeClass (void) catch (java::lang::Throwable *except) { // Caught an exception. - _Jv_MonitorEnter (this); + JvSynchronize sync (this); state = JV_STATE_ERROR; notifyAll (); - _Jv_MonitorExit (this); throw except; } } - _Jv_PrepareConstantTimeTables (this); - - if (vtable == NULL) - _Jv_MakeVTable(this); - - if (otable || atable) - _Jv_LinkSymbolTable(this); - - _Jv_linkExceptionClassTable (this); - // Steps 8, 9, 10, 11. try { @@ -821,17 +785,91 @@ java::lang::Class::initializeClass (void) except = t; } } - _Jv_MonitorEnter (this); + + JvSynchronize sync (this); state = JV_STATE_ERROR; notifyAll (); - _Jv_MonitorExit (this); throw except; } - _Jv_MonitorEnter (this); + JvSynchronize sync (this); state = JV_STATE_DONE; notifyAll (); - _Jv_MonitorExit (this); +} + +// Only used by serialization +java::lang::reflect::Field * +java::lang::Class::getPrivateField (jstring name) +{ + int hash = name->hashCode (); + + java::lang::reflect::Field* rfield; + for (int i = 0; i < field_count; i++) + { + _Jv_Field *field = &fields[i]; + if (! _Jv_equal (field->name, name, hash)) + continue; + rfield = new java::lang::reflect::Field (); + rfield->offset = (char*) field - (char*) fields; + rfield->declaringClass = this; + rfield->name = name; + return rfield; + } + jclass superclass = getSuperclass(); + if (superclass == NULL) + return NULL; + rfield = superclass->getPrivateField(name); + for (int i = 0; i < interface_count && rfield == NULL; ++i) + rfield = interfaces[i]->getPrivateField (name); + return rfield; +} + +// Only used by serialization +java::lang::reflect::Method * +java::lang::Class::getPrivateMethod (jstring name, JArray<jclass> *param_types) +{ + jstring partial_sig = getSignature (param_types, false); + jint p_len = partial_sig->length(); + _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name); + for (Class *klass = this; klass; klass = klass->getSuperclass()) + { + int i = klass->isPrimitive () ? 0 : klass->method_count; + while (--i >= 0) + { + if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name) + && _Jv_equaln (klass->methods[i].signature, partial_sig, p_len)) + { + // Found it. + using namespace java::lang::reflect; + + Method *rmethod = new Method (); + rmethod->offset = ((char *) (&klass->methods[i]) + - (char *) klass->methods); + rmethod->declaringClass = klass; + return rmethod; + } + } + } + throw new java::lang::NoSuchMethodException (name); +} + +// Private accessor method for Java code to retrieve the protection domain. +java::security::ProtectionDomain * +java::lang::Class::getProtectionDomain0 () +{ + return protectionDomain; +} + +JArray<jobject> * +java::lang::Class::getSigners() +{ + return hack_signers; +} + +void +java::lang::Class::setSigners(JArray<jobject> *s) +{ + hack_signers = s; } @@ -857,14 +895,19 @@ _Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name, _Jv_Method * _Jv_LookupDeclaredMethod (jclass klass, _Jv_Utf8Const *name, - _Jv_Utf8Const *signature) + _Jv_Utf8Const *signature, + jclass *declarer_result) { for (; klass; klass = klass->getSuperclass()) { _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature); if (meth) - return meth; + { + if (declarer_result) + *declarer_result = klass; + return meth; + } } return NULL; @@ -886,7 +929,7 @@ _Jv_FindMethodInCache (jclass klass, _Jv_Utf8Const *name, _Jv_Utf8Const *signature) { - int index = name->hash16() & MCACHE_SIZE; + int index = name->hash16 () & MCACHE_SIZE; _Jv_mcache *mc = method_cache + index; _Jv_Method *m = mc->method; @@ -904,7 +947,7 @@ _Jv_AddMethodToCache (jclass klass, { _Jv_MonitorEnter (&java::lang::Class::class$); - int index = method->name->hash16() & MCACHE_SIZE; + int index = method->name->hash16 () & MCACHE_SIZE; method_cache[index].method = method; method_cache[index].klass = klass; @@ -1085,898 +1128,104 @@ _Jv_CheckArrayStore (jobject arr, jobject obj) } } -#define INITIAL_IOFFSETS_LEN 4 -#define INITIAL_IFACES_LEN 4 - -static _Jv_IDispatchTable null_idt = { {SHRT_MAX, 0, NULL} }; - -// Generate tables for constant-time assignment testing and interface -// method lookup. This implements the technique described by Per Bothner -// <per@bothner.com> on the java-discuss mailing list on 1999-09-02: -// http://gcc.gnu.org/ml/java/1999-q3/msg00377.html -void -_Jv_PrepareConstantTimeTables (jclass klass) -{ - if (klass->isPrimitive () || klass->isInterface ()) - return; - - // Short-circuit in case we've been called already. - if ((klass->idt != NULL) || klass->depth != 0) - return; - - // Calculate the class depth and ancestor table. The depth of a class - // is how many "extends" it is removed from Object. Thus the depth of - // java.lang.Object is 0, but the depth of java.io.FilterOutputStream - // is 2. Depth is defined for all regular and array classes, but not - // interfaces or primitive types. - - jclass klass0 = klass; - jboolean has_interfaces = 0; - while (klass0 != &java::lang::Object::class$) - { - has_interfaces += klass0->interface_count; - klass0 = klass0->superclass; - klass->depth++; - } - - // We do class member testing in constant time by using a small table - // of all the ancestor classes within each class. The first element is - // a pointer to the current class, and the rest are pointers to the - // classes ancestors, ordered from the current class down by decreasing - // depth. We do not include java.lang.Object in the table of ancestors, - // since it is redundant. - - klass->ancestors = (jclass *) _Jv_Malloc (klass->depth * sizeof (jclass)); - klass0 = klass; - for (int index = 0; index < klass->depth; index++) - { - klass->ancestors[index] = klass0; - klass0 = klass0->superclass; - } - - if (java::lang::reflect::Modifier::isAbstract (klass->accflags)) - return; - - // Optimization: If class implements no interfaces, use a common - // predefined interface table. - if (!has_interfaces) - { - klass->idt = &null_idt; - return; - } - - klass->idt = - (_Jv_IDispatchTable *) _Jv_Malloc (sizeof (_Jv_IDispatchTable)); - - _Jv_ifaces ifaces; - - ifaces.count = 0; - ifaces.len = INITIAL_IFACES_LEN; - ifaces.list = (jclass *) _Jv_Malloc (ifaces.len * sizeof (jclass *)); - - int itable_size = _Jv_GetInterfaces (klass, &ifaces); - - if (ifaces.count > 0) - { - klass->idt->cls.itable = - (void **) _Jv_Malloc (itable_size * sizeof (void *)); - klass->idt->cls.itable_length = itable_size; - - jshort *itable_offsets = - (jshort *) _Jv_Malloc (ifaces.count * sizeof (jshort)); - - _Jv_GenerateITable (klass, &ifaces, itable_offsets); - - jshort cls_iindex = - _Jv_FindIIndex (ifaces.list, itable_offsets, ifaces.count); - - for (int i=0; i < ifaces.count; i++) - { - ifaces.list[i]->idt->iface.ioffsets[cls_iindex] = - itable_offsets[i]; - } - - klass->idt->cls.iindex = cls_iindex; - - _Jv_Free (ifaces.list); - _Jv_Free (itable_offsets); - } - else - { - klass->idt->cls.iindex = SHRT_MAX; - } -} - -// Return index of item in list, or -1 if item is not present. -inline jshort -_Jv_IndexOf (void *item, void **list, jshort list_len) +jboolean +_Jv_IsAssignableFromSlow (jclass target, jclass source) { - for (int i=0; i < list_len; i++) + // First, strip arrays. + while (target->isArray ()) { - if (list[i] == item) - return i; + // If target is array, source must be as well. + if (! source->isArray ()) + return false; + target = target->getComponentType (); + source = source->getComponentType (); } - return -1; -} -// Find all unique interfaces directly or indirectly implemented by klass. -// Returns the size of the interface dispatch table (itable) for klass, which -// is the number of unique interfaces plus the total number of methods that -// those interfaces declare. May extend ifaces if required. -jshort -_Jv_GetInterfaces (jclass klass, _Jv_ifaces *ifaces) -{ - jshort result = 0; - - for (int i=0; i < klass->interface_count; i++) - { - jclass iface = klass->interfaces[i]; - - /* Make sure interface is linked. */ - _Jv_WaitForState(iface, JV_STATE_LINKED); + // Quick success. + if (target == &java::lang::Object::class$) + return true; - if (_Jv_IndexOf (iface, (void **) ifaces->list, ifaces->count) == -1) - { - if (ifaces->count + 1 >= ifaces->len) - { - /* Resize ifaces list */ - ifaces->len = ifaces->len * 2; - ifaces->list = (jclass *) _Jv_Realloc (ifaces->list, - ifaces->len * sizeof(jclass)); - } - ifaces->list[ifaces->count] = iface; - ifaces->count++; + // Ensure that the classes have their supers installed. + _Jv_Linker::wait_for_state (source, JV_STATE_LOADING); + _Jv_Linker::wait_for_state (target, JV_STATE_LOADING); - result += _Jv_GetInterfaces (klass->interfaces[i], ifaces); - } - } - - if (klass->isInterface()) - { - result += klass->method_count + 1; - } - else + do { - if (klass->superclass) - { - result += _Jv_GetInterfaces (klass->superclass, ifaces); - } + if (source == target) + return true; + + if (target->isPrimitive () || source->isPrimitive ()) + return false; + + if (target->isInterface ()) + { + for (int i = 0; i < source->interface_count; ++i) + { + // We use a recursive call because we also need to + // check superinterfaces. + if (_Jv_IsAssignableFromSlow (target, source->getInterface (i))) + return true; + } + } + source = source->getSuperclass (); } - return result; -} - -// Fill out itable in klass, resolving method declarations in each ifaces. -// itable_offsets is filled out with the position of each iface in itable, -// such that itable[itable_offsets[n]] == ifaces.list[n]. -void -_Jv_GenerateITable (jclass klass, _Jv_ifaces *ifaces, jshort *itable_offsets) -{ - void **itable = klass->idt->cls.itable; - jshort itable_pos = 0; - - for (int i=0; i < ifaces->count; i++) - { - jclass iface = ifaces->list[i]; - itable_offsets[i] = itable_pos; - itable_pos = _Jv_AppendPartialITable (klass, iface, itable, itable_pos); - - /* Create interface dispatch table for iface */ - if (iface->idt == NULL) - { - iface->idt = - (_Jv_IDispatchTable *) _Jv_Malloc (sizeof (_Jv_IDispatchTable)); - - // The first element of ioffsets is its length (itself included). - jshort *ioffsets = - (jshort *) _Jv_Malloc (INITIAL_IOFFSETS_LEN * sizeof (jshort)); - ioffsets[0] = INITIAL_IOFFSETS_LEN; - for (int i=1; i < INITIAL_IOFFSETS_LEN; i++) - ioffsets[i] = -1; - - iface->idt->iface.ioffsets = ioffsets; - } - } -} - -// Format method name for use in error messages. -jstring -_Jv_GetMethodString (jclass klass, _Jv_Utf8Const *name) -{ - jstring r = klass->name->toString(); - r = r->concat (JvNewStringUTF (".")); - r = r->concat (name->toString()); - return r; -} - -void -_Jv_ThrowNoSuchMethodError () -{ - throw new java::lang::NoSuchMethodError; -} - -// Each superinterface of a class (i.e. each interface that the class -// directly or indirectly implements) has a corresponding "Partial -// Interface Dispatch Table" whose size is (number of methods + 1) words. -// The first word is a pointer to the interface (i.e. the java.lang.Class -// instance for that interface). The remaining words are pointers to the -// actual methods that implement the methods declared in the interface, -// in order of declaration. -// -// Append partial interface dispatch table for "iface" to "itable", at -// position itable_pos. -// Returns the offset at which the next partial ITable should be appended. -jshort -_Jv_AppendPartialITable (jclass klass, jclass iface, void **itable, - jshort pos) -{ - using namespace java::lang::reflect; - - itable[pos++] = (void *) iface; - _Jv_Method *meth; - - for (int j=0; j < iface->method_count; j++) - { - meth = NULL; - for (jclass cl = klass; cl; cl = cl->getSuperclass()) - { - meth = _Jv_GetMethodLocal (cl, iface->methods[j].name, - iface->methods[j].signature); - - if (meth) - break; - } + while (source != NULL); - if (meth && (meth->name->first() == '<')) - { - // leave a placeholder in the itable for hidden init methods. - itable[pos] = NULL; - } - else if (meth) - { - if (Modifier::isStatic(meth->accflags)) - throw new java::lang::IncompatibleClassChangeError - (_Jv_GetMethodString (klass, meth->name)); - if (Modifier::isAbstract(meth->accflags)) - throw new java::lang::AbstractMethodError - (_Jv_GetMethodString (klass, meth->name)); - if (! Modifier::isPublic(meth->accflags)) - throw new java::lang::IllegalAccessError - (_Jv_GetMethodString (klass, meth->name)); - - itable[pos] = meth->ncode; - } - else - { - // The method doesn't exist in klass. Binary compatibility rules - // permit this, so we delay the error until runtime using a pointer - // to a method which throws an exception. - itable[pos] = (void *) _Jv_ThrowNoSuchMethodError; - } - pos++; - } - - return pos; + return false; } -static _Jv_Mutex_t iindex_mutex; -static bool iindex_mutex_initialized = false; - -// We need to find the correct offset in the Class Interface Dispatch -// Table for a given interface. Once we have that, invoking an interface -// method just requires combining the Method's index in the interface -// (known at compile time) to get the correct method. Doing a type test -// (cast or instanceof) is the same problem: Once we have a possible Partial -// Interface Dispatch Table, we just compare the first element to see if it -// matches the desired interface. So how can we find the correct offset? -// Our solution is to keep a vector of candiate offsets in each interface -// (idt->iface.ioffsets), and in each class we have an index -// (idt->cls.iindex) used to select the correct offset from ioffsets. +// Lookup an interface method by name. This is very similar to +// purpose to _getMethod, but the interfaces are quite different. It +// might be a good idea for _getMethod to call this function. // -// Calculate and return iindex for a new class. -// ifaces is a vector of num interfaces that the class implements. -// offsets[j] is the offset in the interface dispatch table for the -// interface corresponding to ifaces[j]. -// May extend the interface ioffsets if required. -jshort -_Jv_FindIIndex (jclass *ifaces, jshort *offsets, jshort num) -{ - int i; - int j; - - // Acquire a global lock to prevent itable corruption in case of multiple - // classes that implement an intersecting set of interfaces being linked - // simultaneously. We can assume that the mutex will be initialized - // single-threaded. - if (! iindex_mutex_initialized) - { - _Jv_MutexInit (&iindex_mutex); - iindex_mutex_initialized = true; - } - - _Jv_MutexLock (&iindex_mutex); - - for (i=1;; i++) /* each potential position in ioffsets */ - { - for (j=0;; j++) /* each iface */ - { - if (j >= num) - goto found; - if (i >= ifaces[j]->idt->iface.ioffsets[0]) - continue; - int ioffset = ifaces[j]->idt->iface.ioffsets[i]; - /* We can potentially share this position with another class. */ - if (ioffset >= 0 && ioffset != offsets[j]) - break; /* Nope. Try next i. */ - } - } - found: - for (j = 0; j < num; j++) - { - int len = ifaces[j]->idt->iface.ioffsets[0]; - if (i >= len) - { - /* Resize ioffsets. */ - int newlen = 2 * len; - if (i >= newlen) - newlen = i + 3; - jshort *old_ioffsets = ifaces[j]->idt->iface.ioffsets; - jshort *new_ioffsets = (jshort *) _Jv_Realloc (old_ioffsets, - newlen * sizeof(jshort)); - new_ioffsets[0] = newlen; - - while (len < newlen) - new_ioffsets[len++] = -1; - - ifaces[j]->idt->iface.ioffsets = new_ioffsets; - } - ifaces[j]->idt->iface.ioffsets[i] = offsets[j]; - } - - _Jv_MutexUnlock (&iindex_mutex); - - return i; -} - -// Only used by serialization -java::lang::reflect::Field * -java::lang::Class::getPrivateField (jstring name) +// Return true of the method is found, with the class in FOUND_CLASS +// and the index in INDEX. +bool +_Jv_getInterfaceMethod (jclass search_class, jclass &found_class, int &index, + const _Jv_Utf8Const *utf_name, + const _Jv_Utf8Const *utf_sig) { - int hash = name->hashCode (); - - java::lang::reflect::Field* rfield; - for (int i = 0; i < field_count; i++) + for (jclass klass = search_class; klass; klass = klass->getSuperclass()) { - _Jv_Field *field = &fields[i]; - if (! _Jv_equal (field->name, name, hash)) - continue; - rfield = new java::lang::reflect::Field (); - rfield->offset = (char*) field - (char*) fields; - rfield->declaringClass = this; - rfield->name = name; - return rfield; - } - jclass superclass = getSuperclass(); - if (superclass == NULL) - return NULL; - rfield = superclass->getPrivateField(name); - for (int i = 0; i < interface_count && rfield == NULL; ++i) - rfield = interfaces[i]->getPrivateField (name); - return rfield; -} - -// Only used by serialization -java::lang::reflect::Method * -java::lang::Class::getPrivateMethod (jstring name, JArray<jclass> *param_types) -{ - jstring partial_sig = getSignature (param_types, false); - jint p_len = partial_sig->length(); - _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name); - for (Class *klass = this; klass; klass = klass->getSuperclass()) - { - int i = klass->isPrimitive () ? 0 : klass->method_count; + // FIXME: Throw an exception? + if (!klass->isInterface ()) + return false; + + int i = klass->method_count; while (--i >= 0) { if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name) - && _Jv_equaln (klass->methods[i].signature, partial_sig, p_len)) + && _Jv_equalUtf8Consts (klass->methods[i].signature, utf_sig)) { // Found it. using namespace java::lang::reflect; - Method *rmethod = new Method (); - rmethod->offset = ((char *) (&klass->methods[i]) - - (char *) klass->methods); - rmethod->declaringClass = klass; - return rmethod; - } - } - } - throw new java::lang::NoSuchMethodException (name); -} - -// Private accessor method for Java code to retrieve the protection domain. -java::security::ProtectionDomain * -java::lang::Class::getProtectionDomain0 () -{ - return protectionDomain; -} - -JArray<jobject> * -java::lang::Class::getSigners() -{ - return hack_signers; -} - -void -java::lang::Class::setSigners(JArray<jobject> *s) -{ - hack_signers = s; -} - -// Functions for indirect dispatch (symbolic virtual binding) support. - -// There are two tables, atable and otable. atable is an array of -// addresses, and otable is an array of offsets, and these are used -// for static and virtual members respectively. - -// {a,o}table_syms is an array of _Jv_MethodSymbols. Each such symbol -// is a tuple of {classname, member name, signature}. -// _Jv_LinkSymbolTable() scans these two arrays and fills in the -// corresponding atable and otable with the addresses of static -// members and the offsets of virtual members. - -// The offset (in bytes) for each resolved method or field is placed -// at the corresponding position in the virtual method offset table -// (klass->otable). - -// The same otable and atable may be shared by many classes. - -void -_Jv_LinkSymbolTable(jclass klass) -{ - //// FIXME: Need to lock the tables //// - - int index = 0; - _Jv_MethodSymbol sym; - if (klass->otable == NULL - || klass->otable->state != 0) - goto atable; - - klass->otable->state = 1; - - for (index = 0; sym = klass->otable_syms[index], sym.name != NULL; index++) - { - // FIXME: Why are we passing NULL as the class loader? - jclass target_class = _Jv_FindClass (sym.class_name, NULL); - _Jv_Method *meth = NULL; - - const _Jv_Utf8Const *signature = sym.signature; - - { - static char *bounce = (char *)_Jv_ThrowNoSuchMethodError; - ptrdiff_t offset = (char *)(klass->vtable) - bounce; - klass->otable->offsets[index] = offset; - } - - if (target_class == NULL) - continue; - - if (target_class->isInterface()) - { - // FIXME: This does not yet fully conform to binary compatibility - // rules. It will break if a declaration is moved into a - // superinterface. - for (jclass cls = target_class; cls != 0; cls = cls->getSuperclass ()) - { - for (int i=0; i < cls->method_count; i++) - { - meth = &cls->methods[i]; - if (_Jv_equalUtf8Consts (sym.name, meth->name) - && _Jv_equalUtf8Consts (signature, meth->signature)) - { - klass->otable->offsets[index] = i + 1; - goto found; - } - } - - } - found: - continue; - } - - // We're looking for a field or a method, and we can tell - // which is needed by looking at the signature. - if (signature->first() == '(' && signature->len() >= 2) - { - // If the target class does not have a vtable_method_count yet, - // then we can't tell the offsets for its methods, so we must lay - // it out now. - if (target_class->vtable_method_count == -1) - { - JvSynchronize sync (target_class); - _Jv_LayoutVTableMethods (target_class); - } - - meth = _Jv_LookupDeclaredMethod(target_class, sym.name, - sym.signature); - - if (meth != NULL) - { - klass->otable->offsets[index] = - _Jv_VTable::idx_to_offset (meth->index); - } - - continue; - } - - // try fields - { - _Jv_Field *the_field = NULL; - - for (jclass cls = target_class; cls != 0; cls = cls->getSuperclass ()) - { - for (int i = 0; i < cls->field_count; i++) - { - _Jv_Field *field = &cls->fields[i]; - if (! _Jv_equalUtf8Consts (field->name, sym.name)) - continue; - - // FIXME: What access checks should we perform here? -// if (_Jv_CheckAccess (klass, cls, field->flags)) -// { - - if (!field->isResolved ()) - _Jv_ResolveField (field, cls->loader); - -// if (field_type != 0 && field->type != field_type) -// throw new java::lang::LinkageError -// (JvNewStringLatin1 -// ("field type mismatch with different loaders")); - - the_field = field; - goto end_of_field_search; - } - } - end_of_field_search: - if (the_field != NULL) - { - if (the_field->flags & 0x0008 /* Modifier::STATIC */) - { - throw new java::lang::IncompatibleClassChangeError; - } - else - { - klass->otable->offsets[index] = the_field->u.boffset; - } - } - else - { - throw new java::lang::NoSuchFieldError - (_Jv_NewStringUtf8Const (sym.name)); - } - } - } - - atable: - if (klass->atable == NULL - || klass->atable->state != 0) - return; - - klass->atable->state = 1; - - for (index = 0; sym = klass->atable_syms[index], sym.name != NULL; index++) - { - // FIXME: Why are we passing NULL as the class loader? - jclass target_class = _Jv_FindClass (sym.class_name, NULL); - _Jv_Method *meth = NULL; - const _Jv_Utf8Const *signature = sym.signature; - - // ??? Setting this pointer to null will at least get us a - // NullPointerException - klass->atable->addresses[index] = NULL; - - if (target_class == NULL) - continue; - - // We're looking for a static field or a static method, and we - // can tell which is needed by looking at the signature. - if (signature->first() == '(' && signature->len() >= 2) - { - // If the target class does not have a vtable_method_count yet, - // then we can't tell the offsets for its methods, so we must lay - // it out now. - if (target_class->vtable_method_count == -1) - { - JvSynchronize sync (target_class); - _Jv_LayoutVTableMethods (target_class); - } - - meth = _Jv_LookupDeclaredMethod(target_class, sym.name, - sym.signature); - - if (meth != NULL) - { - if (meth->ncode) // Maybe abstract? - klass->atable->addresses[index] = meth->ncode; -#ifdef INTERPRETER - else if (_Jv_IsInterpretedClass (target_class)) - _Jv_Defer_Resolution (target_class, meth, - &klass->atable->addresses[index]); -#endif - } - else - klass->atable->addresses[index] = (void *)_Jv_ThrowNoSuchMethodError; - - continue; - } - - // try fields - { - _Jv_Field *the_field = NULL; - - for (jclass cls = target_class; cls != 0; cls = cls->getSuperclass ()) - { - for (int i = 0; i < cls->field_count; i++) - { - _Jv_Field *field = &cls->fields[i]; - if (! _Jv_equalUtf8Consts (field->name, sym.name)) - continue; - - // FIXME: What access checks should we perform here? -// if (_Jv_CheckAccess (klass, cls, field->flags)) -// { - - if (!field->isResolved ()) - _Jv_ResolveField (field, cls->loader); - -// if (field_type != 0 && field->type != field_type) -// throw new java::lang::LinkageError -// (JvNewStringLatin1 -// ("field type mismatch with different loaders")); - - the_field = field; - goto end_of_static_field_search; - } - } - end_of_static_field_search: - if (the_field != NULL) - { - if (the_field->flags & 0x0008 /* Modifier::STATIC */) - { - klass->atable->addresses[index] = the_field->u.addr; - } - else - { - throw new java::lang::IncompatibleClassChangeError; - } - } - else - { - throw new java::lang::NoSuchFieldError - (_Jv_NewStringUtf8Const (sym.name)); - } - } - } -} - - -// For each catch_record in the list of caught classes, fill in the -// address field. -void -_Jv_linkExceptionClassTable (jclass self) -{ - struct _Jv_CatchClass *catch_record = self->catch_classes; - if (!catch_record || catch_record->classname) - return; - catch_record++; - while (catch_record->classname) - { - jclass target_class = _Jv_FindClass (catch_record->classname, - self->getClassLoaderInternal ()); - *catch_record->address = target_class; - catch_record++; - } - self->catch_classes->classname = (_Jv_Utf8Const *)-1; -} - -// This is put in empty vtable slots. -static void -_Jv_abstractMethodError (void) -{ - throw new java::lang::AbstractMethodError(); -} - -// Set itable method indexes for members of interface IFACE. -void -_Jv_LayoutInterfaceMethods (jclass iface) -{ - if (! iface->isInterface()) - return; - - // itable indexes start at 1. - // FIXME: Static initalizers currently get a NULL placeholder entry in the - // itable so they are also assigned an index here. - for (int i = 0; i < iface->method_count; i++) - iface->methods[i].index = i + 1; -} - -// Prepare virtual method declarations in KLASS, and any superclasses as -// required, by determining their vtable index, setting method->index, and -// finally setting the class's vtable_method_count. Must be called with the -// lock for KLASS held. -void -_Jv_LayoutVTableMethods (jclass klass) -{ - if (klass->vtable != NULL || klass->isInterface() - || klass->vtable_method_count != -1) - return; - - jclass superclass = klass->superclass; - - typedef unsigned int uaddr __attribute__ ((mode (pointer))); + // FIXME: Method must be public. Throw an exception? + if (! Modifier::isPublic (klass->methods[i].accflags)) + break; - // If superclass looks like a constant pool entry, - // resolve it now. - if ((uaddr) superclass < (uaddr) klass->constants.size) - { - if (klass->state < JV_STATE_LINKED) - { - _Jv_Utf8Const *name = klass->constants.data[(uaddr) superclass].utf8; - superclass = _Jv_FindClass (name, klass->loader); - if (! superclass) - { - throw new java::lang::NoClassDefFoundError (name->toString()); + found_class = klass; + // Interface method indexes count from 1. + index = i+1; + return true; } } - else - superclass = klass->constants.data[(uaddr) superclass].clazz; - } - - if (superclass != NULL && superclass->vtable_method_count == -1) - { - JvSynchronize sync (superclass); - _Jv_LayoutVTableMethods (superclass); - } - - int index = (superclass == NULL ? 0 : superclass->vtable_method_count); - - for (int i = 0; i < klass->method_count; ++i) - { - _Jv_Method *meth = &klass->methods[i]; - _Jv_Method *super_meth = NULL; - - if (! _Jv_isVirtualMethod (meth)) - continue; - - // FIXME: Must check that we don't override: - // - Package-private method where superclass is in different package. - // - Final or less-accessible declaration in superclass (check binary - // spec, do we allocate new vtable entry or put throw node in vtable?) - // - Static or private method in superclass. - - if (superclass != NULL) - { - super_meth = _Jv_LookupDeclaredMethod (superclass, meth->name, - meth->signature); - } - - if (super_meth) - meth->index = super_meth->index; - else - meth->index = index++; - } - - klass->vtable_method_count = index; -} - -// Set entries in VTABLE for virtual methods declared in KLASS. If -// KLASS has an immediate abstract parent, recursively do its methods -// first. FLAGS is used to determine which slots we've actually set. -void -_Jv_SetVTableEntries (jclass klass, _Jv_VTable *vtable, jboolean *flags) -{ - using namespace java::lang::reflect; - - jclass superclass = klass->getSuperclass(); - - if (superclass != NULL && (superclass->getModifiers() & Modifier::ABSTRACT)) - _Jv_SetVTableEntries (superclass, vtable, flags); - - for (int i = klass->method_count - 1; i >= 0; i--) - { - _Jv_Method *meth = &klass->methods[i]; - if (meth->index == (_Jv_ushort) -1) - continue; - if ((meth->accflags & Modifier::ABSTRACT)) - { - vtable->set_method(meth->index, (void *) &_Jv_abstractMethodError); - flags[meth->index] = false; - } - else - { - vtable->set_method(meth->index, meth->ncode); - flags[meth->index] = true; - } } -} - -// Allocate and lay out the virtual method table for KLASS. This will also -// cause vtables to be generated for any non-abstract superclasses, and -// virtual method layout to occur for any abstract superclasses. Must be -// called with monitor lock for KLASS held. -void -_Jv_MakeVTable (jclass klass) -{ - using namespace java::lang::reflect; - if (klass->vtable != NULL || klass->isInterface() - || (klass->accflags & Modifier::ABSTRACT)) - return; - - // Class must be laid out before we can create a vtable. - if (klass->vtable_method_count == -1) - _Jv_LayoutVTableMethods (klass); - - // Allocate the new vtable. - _Jv_VTable *vtable = _Jv_VTable::new_vtable (klass->vtable_method_count); - klass->vtable = vtable; - - jboolean flags[klass->vtable_method_count]; - for (int i = 0; i < klass->vtable_method_count; ++i) - flags[i] = false; - - // Copy the vtable of the closest non-abstract superclass. - jclass superclass = klass->superclass; - if (superclass != NULL) + // If we haven't found a match, and this class is an interface, then + // check all the superinterfaces. + if (search_class->isInterface()) { - while ((superclass->accflags & Modifier::ABSTRACT) != 0) - superclass = superclass->superclass; - - if (superclass->vtable == NULL) - { - JvSynchronize sync (superclass); - _Jv_MakeVTable (superclass); - } - - for (int i = 0; i < superclass->vtable_method_count; ++i) + for (int i = 0; i < search_class->interface_count; ++i) { - vtable->set_method (i, superclass->vtable->get_method (i)); - flags[i] = true; + using namespace java::lang::reflect; + bool found = _Jv_getInterfaceMethod (search_class->interfaces[i], + found_class, index, + utf_name, utf_sig); + if (found) + return true; } } - // Set the class pointer and GC descriptor. - vtable->clas = klass; - vtable->gc_descr = _Jv_BuildGCDescr (klass); - - // For each virtual declared in klass and any immediate abstract - // superclasses, set new vtable entry or override an old one. - _Jv_SetVTableEntries (klass, vtable, flags); - - // It is an error to have an abstract method in a concrete class. - if (! (klass->accflags & Modifier::ABSTRACT)) - { - for (int i = 0; i < klass->vtable_method_count; ++i) - if (! flags[i]) - { - using namespace java::lang; - while (klass != NULL) - { - for (int j = 0; j < klass->method_count; ++j) - { - if (klass->methods[i].index == i) - { - StringBuffer *buf = new StringBuffer (); - buf->append (_Jv_NewStringUtf8Const (klass->methods[i].name)); - buf->append ((jchar) ' '); - buf->append (_Jv_NewStringUtf8Const (klass->methods[i].signature)); - throw new AbstractMethodError (buf->toString ()); - } - } - klass = klass->getSuperclass (); - } - // Couldn't find the name, which is weird. - // But we still must throw the error. - throw new AbstractMethodError (); - } - } + return false; } diff --git a/libjava/java/lang/natClassLoader.cc b/libjava/java/lang/natClassLoader.cc index 5a0898a93c4..dd5cd463cfa 100644 --- a/libjava/java/lang/natClassLoader.cc +++ b/libjava/java/lang/natClassLoader.cc @@ -18,6 +18,7 @@ details. */ #include <gcj/cni.h> #include <jvm.h> +#include <execution.h> #include <java-threads.h> #include <java-interp.h> @@ -33,6 +34,7 @@ details. */ #include <java/lang/ClassNotFoundException.h> #include <java/lang/ClassCircularityError.h> #include <java/lang/IncompatibleClassChangeError.h> +#include <java/lang/ClassFormatError.h> #include <java/lang/VirtualMachineError.h> #include <java/lang/VMClassLoader.h> #include <java/lang/reflect/Modifier.h> @@ -41,156 +43,6 @@ details. */ #include <java/io/Serializable.h> #include <java/lang/Cloneable.h> -void -_Jv_WaitForState (jclass klass, int state) -{ - if (klass->state >= state) - return; - - _Jv_MonitorEnter (klass) ; - - if (klass->state == JV_STATE_COMPILED) - { - klass->state = JV_STATE_LOADED; - if (gcj::verbose_class_flag) - fprintf (stderr, "[Loaded (pre-compiled) %s]\n", klass->name->chars()); - } - if (state == JV_STATE_LINKED) - { - // Must call _Jv_PrepareCompiledClass while holding the class - // mutex. -#ifdef INTERPRETER - if (_Jv_IsInterpretedClass (klass)) - _Jv_PrepareClass (klass); -#endif - _Jv_PrepareCompiledClass (klass); - _Jv_MonitorExit (klass); - return; - } - - java::lang::Thread *self = java::lang::Thread::currentThread(); - - // this is similar to the strategy for class initialization. - // if we already hold the lock, just leave. - while (klass->state <= state - && klass->thread - && klass->thread != self) - klass->wait (); - - _Jv_MonitorExit (klass); - - if (klass->state == JV_STATE_ERROR) - throw new java::lang::LinkageError; -} - -typedef unsigned int uaddr __attribute__ ((mode (pointer))); - -/** This function does class-preparation for compiled classes. - NOTE: It contains replicated functionality from - _Jv_ResolvePoolEntry, and this is intentional, since that function - lives in resolve.cc which is entirely conditionally compiled. - */ -void -_Jv_PrepareCompiledClass (jclass klass) -{ - jint state = klass->state; - if (state >= JV_STATE_LINKED) - return; - - // Short-circuit, so that mutually dependent classes are ok. - klass->state = JV_STATE_LINKED; - - _Jv_Constants *pool = &klass->constants; - - // Resolve class constants first, since other constant pool - // entries may rely on these. - for (int index = 1; index < pool->size; ++index) - { - if (pool->tags[index] == JV_CONSTANT_Class) - { - _Jv_Utf8Const *name = pool->data[index].utf8; - - jclass found; - if (name->first() == '[') - found = _Jv_FindClassFromSignature (name->chars(), - klass->loader); - else - found = _Jv_FindClass (name, klass->loader); - - if (! found) - { - jstring str = name->toString(); - throw new java::lang::NoClassDefFoundError (str); - } - - pool->data[index].clazz = found; - pool->tags[index] |= JV_CONSTANT_ResolvedFlag; - } - } - - // If superclass looks like a constant pool entry, - // resolve it now. - if ((uaddr) klass->superclass < pool->size) - klass->superclass = pool->data[(uaddr) klass->superclass].clazz; - - // Likewise for interfaces. - for (int i = 0; i < klass->interface_count; i++) - if ((uaddr) klass->interfaces[i] < pool->size) - klass->interfaces[i] = pool->data[(uaddr) klass->interfaces[i]].clazz; - - // Resolve the remaining constant pool entries. - for (int index = 1; index < pool->size; ++index) - { - if (pool->tags[index] == JV_CONSTANT_String) - { - jstring str; - - str = _Jv_NewStringUtf8Const (pool->data[index].utf8); - pool->data[index].o = str; - pool->tags[index] |= JV_CONSTANT_ResolvedFlag; - } - } - -#ifdef INTERPRETER - // FIXME: although the comment up top says that this function is - // only called for compiled classes, it is actually called for every - // class. - if (! _Jv_IsInterpretedClass (klass)) - { -#endif /* INTERPRETER */ - jfieldID f = JvGetFirstStaticField (klass); - for (int n = JvNumStaticFields (klass); n > 0; --n) - { - int mod = f->getModifiers (); - // If we have a static String field with a non-null initial - // value, we know it points to a Utf8Const. - _Jv_ResolveField(f, klass->loader); - if (f->getClass () == &java::lang::String::class$ - && java::lang::reflect::Modifier::isStatic (mod)) - { - jstring *strp = (jstring *) f->u.addr; - if (*strp) - *strp = _Jv_NewStringUtf8Const ((_Jv_Utf8Const *) *strp); - } - f = f->getNextField (); - } -#ifdef INTERPRETER - } -#endif /* INTERPRETER */ - - if (klass->isInterface ()) - _Jv_LayoutInterfaceMethods (klass); - - if (state == JV_STATE_COMPILED && gcj::verbose_class_flag) - fprintf (stderr, "[Loaded (pre-compiled) %s]\n", - klass->name->chars()); - - klass->notifyAll (); - - _Jv_PushClass (klass); -} - - // // A single class can have many "initiating" class loaders, // and a single "defining" class loader. The Defining @@ -221,6 +73,8 @@ static _Jv_LoaderInfo *initiated_classes[HASH_LEN]; static jclass loaded_classes[HASH_LEN]; // This is the root of a linked list of classes +static jclass stack_head; + @@ -323,11 +177,6 @@ _Jv_RegisterClasses (const jclass *classes) jclass klass = *classes; (*_Jv_RegisterClassHook) (klass); - - // registering a compiled class causes - // it to be immediately "prepared". - if (klass->state == JV_STATE_NOTHING) - klass->state = JV_STATE_COMPILED; } } @@ -341,11 +190,6 @@ _Jv_RegisterClasses_Counted (const jclass * classes, size_t count) jclass klass = classes[i]; (*_Jv_RegisterClassHook) (klass); - - // registering a compiled class causes - // it to be immediately "prepared". - if (klass->state == JV_STATE_NOTHING) - klass->state = JV_STATE_COMPILED; } } @@ -354,8 +198,10 @@ _Jv_RegisterClassHookDefault (jclass klass) { jint hash = HASH_UTF (klass->name); - jclass check_class = loaded_classes[hash]; - + // The BC ABI makes this check unnecessary: we always resolve all + // data references via the appropriate class loader, so the kludge + // that required this check has gone. +#if 0 // If the class is already registered, don't re-register it. while (check_class != NULL) { @@ -381,7 +227,11 @@ _Jv_RegisterClassHookDefault (jclass klass) check_class = check_class->next; } +#endif + // FIXME: this is really bogus! + if (! klass->engine) + klass->engine = &_Jv_soleCompiledEngine; klass->next = loaded_classes[hash]; loaded_classes[hash] = klass; } @@ -442,7 +292,7 @@ _Jv_FindClass (_Jv_Utf8Const *name, java::lang::ClassLoader *loader) { // we need classes to be in the hash while // we're loading, so that they can refer to themselves. - _Jv_WaitForState (klass, JV_STATE_LOADED); + _Jv_Linker::wait_for_state (klass, JV_STATE_LOADED); } return klass; @@ -555,7 +405,7 @@ _Jv_NewArrayClass (jclass element, java::lang::ClassLoader *loader, // cache one and reuse it. It is not necessary to synchronize this. if (!array_idt) { - _Jv_PrepareConstantTimeTables (array_class); + _Jv_Linker::wait_for_state(array_class, JV_STATE_PREPARED); array_idt = array_class->idt; array_depth = array_class->depth; array_ancestors = array_class->ancestors; @@ -569,19 +419,19 @@ _Jv_NewArrayClass (jclass element, java::lang::ClassLoader *loader, using namespace java::lang::reflect; { - // Array classes are "abstract final"... - _Jv_ushort accflags = Modifier::FINAL | Modifier::ABSTRACT; - // ... and inherit accessibility from element type, per vmspec 5.3.3.2 - accflags |= (element->accflags & Modifier::PUBLIC); - accflags |= (element->accflags & Modifier::PROTECTED); - accflags |= (element->accflags & Modifier::PRIVATE); + // Array classes are "abstract final" and inherit accessibility + // from element type, per vmspec 5.3.3.2 + _Jv_ushort accflags = (Modifier::FINAL | Modifier::ABSTRACT + | (element->accflags + & (Modifier::PUBLIC | Modifier::PROTECTED + | Modifier::PRIVATE))); array_class->accflags = accflags; } // An array class has no visible instance fields. "length" is invisible to // reflection. - // say this class is initialized and ready to go! + // Say this class is initialized and ready to go! array_class->state = JV_STATE_DONE; // vmspec, section 5.3.3 describes this @@ -591,8 +441,6 @@ _Jv_NewArrayClass (jclass element, java::lang::ClassLoader *loader, element->arrayclass = array_class; } -static jclass stack_head; - // These two functions form a stack of classes. When a class is loaded // it is pushed onto the stack by the class loader; this is so that // StackTrace can quickly determine which classes have been loaded. diff --git a/libjava/java/lang/natRuntime.cc b/libjava/java/lang/natRuntime.cc index 1e57f50113d..332f2c7b625 100644 --- a/libjava/java/lang/natRuntime.cc +++ b/libjava/java/lang/natRuntime.cc @@ -1,6 +1,6 @@ // natRuntime.cc - Implementation of native side of Runtime class. -/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation This file is part of libgcj. @@ -388,8 +388,11 @@ java::lang::Runtime::insertSystemProperties (java::util::Properties *newprops) newprops->put(JvNewStringLatin1 (Prop), JvNewStringLatin1 (Val)) // A mixture of the Java Product Versioning Specification - // (introduced in 1.2), and earlier versioning properties. - SET ("java.version", GCJVERSION); + // (introduced in 1.2), and earlier versioning properties. Some + // programs rely on seeing values that they expect, so we claim to + // be a 1.4-ish VM for their sake. + SET ("java.version", "1.4.2"); + SET ("java.runtime.version", "1.4.2"); SET ("java.vendor", "Free Software Foundation, Inc."); SET ("java.vendor.url", "http://gcc.gnu.org/java/"); SET ("java.class.version", "46.0"); @@ -399,7 +402,7 @@ java::lang::Runtime::insertSystemProperties (java::util::Properties *newprops) SET ("java.vm.version", __VERSION__); SET ("java.vm.vendor", "Free Software Foundation, Inc."); SET ("java.vm.name", "GNU libgcj"); - SET ("java.specification.version", "1.3"); + SET ("java.specification.version", "1.4"); SET ("java.specification.name", "Java(tm) Platform API Specification"); SET ("java.specification.vendor", "Sun Microsystems Inc."); diff --git a/libjava/java/lang/natString.cc b/libjava/java/lang/natString.cc index cba0976bd95..e2558f4f747 100644 --- a/libjava/java/lang/natString.cc +++ b/libjava/java/lang/natString.cc @@ -1,7 +1,6 @@ // natString.cc - Implementation of java.lang.String native methods. -/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 - Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation This file is part of libgcj. @@ -57,7 +56,7 @@ static int strhash_size = 0; /* Number of slots available in strhash. jstring* _Jv_StringFindSlot (jchar* data, jint len, jint hash) { - JvSynchronize sync (&StringClass); + JvSynchronize sync (&java::lang::String::class$); int start_index = hash & (strhash_size - 1); int deleted_index = -1; @@ -120,7 +119,7 @@ _Jv_StringGetSlot (jstring str) static void rehash () { - JvSynchronize sync (&StringClass); + JvSynchronize sync (&java::lang::String::class$); if (strhash == NULL) { @@ -167,7 +166,7 @@ rehash () jstring java::lang::String::intern() { - JvSynchronize sync (&StringClass); + JvSynchronize sync (&java::lang::String::class$); if (3 * strhash_count >= 2 * strhash_size) rehash(); jstring* ptr = _Jv_StringGetSlot(this); @@ -194,7 +193,7 @@ java::lang::String::intern() void _Jv_FinalizeString (jobject obj) { - JvSynchronize sync (&StringClass); + JvSynchronize sync (&java::lang::String::class$); // We might not actually have intern()d any strings at all, if // we're being called from Reference. @@ -286,9 +285,9 @@ _Jv_NewStringUtf8Const (Utf8Const* str) } chrs -= length; - JvSynchronize sync (&StringClass); + JvSynchronize sync (&java::lang::String::class$); if (3 * strhash_count >= 2 * strhash_size) - rehash (); + rehash(); jstring* ptr = _Jv_StringFindSlot (chrs, length, hash); if (*ptr != NULL && *ptr != DELETED_STRING) return (jstring) UNMASK_PTR (*ptr); @@ -527,7 +526,7 @@ java::lang::String::equals(jobject anObject) return false; if (anObject == this) return true; - if (anObject->getClass() != &StringClass) + if (anObject->getClass() != &java::lang::String::class$) return false; jstring other = (jstring) anObject; if (count != other->count) diff --git a/libjava/java/lang/natVMClassLoader.cc b/libjava/java/lang/natVMClassLoader.cc index 1ed3851fbb3..841b3e0789e 100644 --- a/libjava/java/lang/natVMClassLoader.cc +++ b/libjava/java/lang/natVMClassLoader.cc @@ -22,6 +22,7 @@ details. */ #include <java-interp.h> #include <java/lang/VMClassLoader.h> +#include <java/lang/VMCompiler.h> #include <gnu/gcj/runtime/VMClassLoader.h> #include <java/lang/ClassLoader.h> #include <java/lang/Class.h> @@ -29,6 +30,21 @@ details. */ #include <java/security/ProtectionDomain.h> #include <java/lang/ClassFormatError.h> +void +java::lang::VMClassLoader::resolveClass (jclass klass) +{ + JvSynchronize sync (klass); + try + { + _Jv_Linker::wait_for_state (klass, JV_STATE_LINKED); + } + catch (java::lang::Throwable *x) + { + klass->set_state(JV_STATE_ERROR); + transformException(klass, x); + } +} + java::lang::Class * java::lang::VMClassLoader::defineClass (java::lang::ClassLoader *loader, jstring name, @@ -37,72 +53,61 @@ java::lang::VMClassLoader::defineClass (java::lang::ClassLoader *loader, jint length, java::security::ProtectionDomain *pd) { -#ifdef INTERPRETER - jclass klass; - klass = new java::lang::Class (); - klass->aux_info = (void *) _Jv_AllocBytes (sizeof (_Jv_InterpClass)); - - // Synchronize on the class, so that it is not attempted initialized - // until we're done loading. - JvSynchronize sync (klass); - - // Record the defining loader. For the system class loader, we - // record NULL. - if (loader != java::lang::ClassLoader::getSystemClassLoader()) - klass->loader = loader; - - if (name != 0) - { - _Jv_Utf8Const *name2 = _Jv_makeUtf8Const (name); - - if (! _Jv_VerifyClassName (name2)) - throw new java::lang::ClassFormatError - (JvNewStringLatin1 ("erroneous class name")); - - klass->name = name2; - } + jclass klass = VMCompiler::compileClass(loader, name, data, + offset, length, pd); - try + if (klass != NULL) { - _Jv_DefineClass (klass, data, offset, length); + JvSynchronize sync (&java::lang::Class::class$); + _Jv_RegisterClass (klass); } - catch (java::lang::Throwable *ex) +#ifdef INTERPRETER + else { - klass->state = JV_STATE_ERROR; - klass->notifyAll (); - - _Jv_UnregisterClass (klass); - - // If EX is not a ClassNotFoundException, that's ok, because we - // account for the possibility in defineClass(). - throw ex; + klass = new java::lang::Class (); + + // Synchronize on the class, so that it is not attempted initialized + // until we're done loading. + JvSynchronize sync (klass); + + // Record the defining loader. For the system class loader, we + // record NULL. + if (loader != java::lang::ClassLoader::getSystemClassLoader()) + klass->loader = loader; + + if (name != 0) + { + _Jv_Utf8Const *name2 = _Jv_makeUtf8Const (name); + + if (! _Jv_VerifyClassName (name2)) + throw new java::lang::ClassFormatError + (JvNewStringLatin1 ("erroneous class name")); + + klass->name = name2; + } + + try + { + _Jv_DefineClass (klass, data, offset, length, pd); + } + catch (java::lang::Throwable *ex) + { + klass->state = JV_STATE_ERROR; + klass->notifyAll (); + + _Jv_UnregisterClass (klass); + + // If EX is not a ClassNotFoundException, that's ok, because we + // account for the possibility in defineClass(). + throw ex; + } + + // if everything proceeded sucessfully, we're loaded. + JvAssert (klass->state == JV_STATE_LOADED); } - - klass->protectionDomain = pd; - - // if everything proceeded sucessfully, we're loaded. - JvAssert (klass->state == JV_STATE_LOADED); +#endif // INTERPRETER return klass; - -#else // INTERPRETER - - return 0; -#endif -} - -// Finish linking a class. Only called from ClassLoader::resolveClass. -void -java::lang::VMClassLoader::linkClass0 (java::lang::Class *klass) -{ - _Jv_WaitForState (klass, JV_STATE_LINKED); -} - -void -java::lang::VMClassLoader::markClassErrorState0 (java::lang::Class *klass) -{ - klass->state = JV_STATE_ERROR; - klass->notifyAll (); } java::lang::ClassLoader * @@ -125,9 +130,16 @@ jclass java::lang::VMClassLoader::loadClass(jstring name, jboolean resolve) { _Jv_Utf8Const *utf = _Jv_makeUtf8Const (name); - // FIXME: we culd make _Jv_FindClassFromSignature a template. jclass klass = _Jv_FindClassInCache (utf, NULL); - if (klass && resolve) - _Jv_InitClass (klass); + if (klass) + { + // We never want to return a class without its supers linked. + // It isn't clear from the spec, but this is what other + // implementations do in practice. + if (resolve) + _Jv_InitClass (klass); + else + _Jv_Linker::wait_for_state (klass, JV_STATE_LOADING); + } return klass; } diff --git a/libjava/java/lang/reflect/natField.cc b/libjava/java/lang/reflect/natField.cc index 469cf74de8e..7eb032227ab 100644 --- a/libjava/java/lang/reflect/natField.cc +++ b/libjava/java/lang/reflect/natField.cc @@ -1,6 +1,6 @@ // natField.cc - Implementation of java.lang.reflect.Field native methods. -/* Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004 Free Software Foundation This file is part of libgcj. @@ -47,7 +47,7 @@ java::lang::reflect::Field::getType () { jfieldID fld = _Jv_FromReflectedField (this); JvSynchronize sync (declaringClass); - _Jv_ResolveField (fld, declaringClass->getClassLoaderInternal ()); + _Jv_Linker::resolve_field (fld, declaringClass->getClassLoaderInternal ()); return fld->type; } diff --git a/libjava/java/lang/reflect/natMethod.cc b/libjava/java/lang/reflect/natMethod.cc index 8c6efc487cd..b194067300b 100644 --- a/libjava/java/lang/reflect/natMethod.cc +++ b/libjava/java/lang/reflect/natMethod.cc @@ -1,6 +1,6 @@ // natMethod.cc - Native code for Method class. -/* Copyright (C) 1998, 1999, 2000, 2001 , 2002, 2003 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001 , 2002, 2003, 2004 Free Software Foundation This file is part of libgcj. @@ -149,7 +149,6 @@ java::lang::reflect::Method::invoke (jobject obj, jobjectArray args) getType (); jmethodID meth = _Jv_FromReflectedMethod (this); - jclass objClass; if (Modifier::isStatic(meth->accflags)) { @@ -157,12 +156,10 @@ java::lang::reflect::Method::invoke (jobject obj, jobjectArray args) // here and not in _Jv_CallAnyMethodA because JNI initializes a // class whenever a method lookup is done. _Jv_InitClass (declaringClass); - objClass = declaringClass; } else { - objClass = JV_CLASS (obj); - + jclass objClass = JV_CLASS (obj); if (! _Jv_IsAssignableFrom (declaringClass, objClass)) throw new java::lang::IllegalArgumentException; } @@ -184,7 +181,7 @@ java::lang::reflect::Method::invoke (jobject obj, jobjectArray args) { } - if (! _Jv_CheckAccess(caller, objClass, meth->accflags)) + if (! _Jv_CheckAccess(caller, declaringClass, meth->accflags)) throw new IllegalAccessException; } diff --git a/libjava/java/net/URLClassLoader.java b/libjava/java/net/URLClassLoader.java index 4ffd4c532db..3efc5dca76f 100644 --- a/libjava/java/net/URLClassLoader.java +++ b/libjava/java/net/URLClassLoader.java @@ -54,6 +54,8 @@ import java.security.SecureClassLoader; import java.security.cert.Certificate; import java.util.Enumeration; import java.util.HashMap; +import java.util.Iterator; +import java.util.StringTokenizer; import java.util.Vector; import java.util.jar.Attributes; import java.util.jar.JarEntry; @@ -144,9 +146,10 @@ public class URLClassLoader extends SecureClassLoader private final Vector urls = new Vector(); /** - * Store pre-parsed information for each url into this vector - * each element is a URL loader, corresponding to the URL of - * the same index in "urls" + * Store pre-parsed information for each url into this vector: each + * element is a URL loader. A jar file has its own class-path + * attribute which adds to the URLs that will be searched, but this + * does not add to the list of urls. */ private final Vector urlinfos = new Vector(); @@ -189,9 +192,14 @@ public class URLClassLoader extends SecureClassLoader URLLoader(URLClassLoader classloader, URL baseURL) { + this(classloader, baseURL, baseURL); + } + + URLLoader(URLClassLoader classloader, URL baseURL, URL overrideURL) + { this.classloader = classloader; this.baseURL = baseURL; - this.noCertCodeSource = new CodeSource(baseURL, null); + this.noCertCodeSource = new CodeSource(overrideURL, null); } /** @@ -221,6 +229,11 @@ public class URLClassLoader extends SecureClassLoader { return null; } + + Vector getClassPath() + { + return null; + } } /** @@ -290,6 +303,10 @@ public class URLClassLoader extends SecureClassLoader final JarFile jarfile; // The jar file for this url final URL baseJarURL; // Base jar: url for all resources loaded from jar + Vector classPath; // The "Class-Path" attribute of this Jar's manifest + + SoURLLoader soURLLoader; + public JarURLLoader(URLClassLoader classloader, URL baseURL) { super(classloader, baseURL); @@ -302,25 +319,87 @@ public class URLClassLoader extends SecureClassLoader sb.append("!/"); String jarURL = sb.toString(); + this.soURLLoader = null; + this.classPath = null; URL baseJarURL = null; JarFile jarfile = null; try - { - baseJarURL = - new URL(null, jarURL, classloader.getURLStreamHandler("jar")); - - jarfile = - ((JarURLConnection) baseJarURL.openConnection()).getJarFile(); - } + { + baseJarURL + = new URL(null, jarURL, classloader.getURLStreamHandler("jar")); + jarfile + = ((JarURLConnection) baseJarURL.openConnection()).getJarFile(); + + if (jarfile != null) + { + String fileName = baseURL.getFile(); + if (fileName != null) + { + File f = new File(fileName); + String libDirName = f.getCanonicalFile().getParent() + + File.separator + "GCJLIBS"; + File libDir = new File(libDirName); + if (libDir != null && (libDir.isDirectory())) + { + File soFile = new File (libDirName + + File.separator + f.getName() + + ".so"); + if (soFile != null && soFile.isFile()) + this.soURLLoader + = new SoURLLoader (classloader, soFile.toURL(), + baseURL); + } + } + + Manifest manifest; + Attributes attributes; + String classPathString; + + if ((manifest = jarfile.getManifest()) != null + && (attributes = manifest.getMainAttributes()) != null + && ((classPathString + = attributes.getValue(Attributes.Name.CLASS_PATH)) + != null)) + { + this.classPath = new Vector(); + + StringTokenizer st + = new StringTokenizer + (classPathString, + System.getProperty ("path.separator", ":")); + + while (st.hasMoreElements ()) + { + String e = st.nextToken (); + try + { + URL url = new URL(baseURL, e); + this.classPath.add(url); + } + catch (java.net.MalformedURLException xx) + { + // Give up + } + } + } + } + } catch (IOException ioe) { - /* ignored */ + /* ignored */ } this.baseJarURL = baseJarURL; this.jarfile = jarfile; } + Class getClass(String className) + { + if (soURLLoader != null) + return soURLLoader.getClass(className); + return null; + } + /** get resource with the name "name" in the jar url */ Resource getResource(String name) { @@ -337,6 +416,11 @@ public class URLClassLoader extends SecureClassLoader return null; } + public String toString () + { + return "jarfile " + jarfile.getName(); + } + Manifest getManifest() { try @@ -348,6 +432,11 @@ public class URLClassLoader extends SecureClassLoader return null; } } + + Vector getClassPath() + { + return classPath; + } } static final class JarURLResource extends Resource @@ -486,7 +575,12 @@ public class URLClassLoader extends SecureClassLoader SoURLLoader(URLClassLoader classloader, URL url) { - super(classloader, url); + this(classloader, url, url); + } + + SoURLLoader(URLClassLoader classloader, URL url, URL overrideURL) + { + super(classloader, url, overrideURL); helper = SharedLibHelper.findHelper(classloader, url.getFile(), noCertCodeSource); } @@ -577,6 +671,11 @@ public class URLClassLoader extends SecureClassLoader return (int) file.length(); } + public String toString () + { + return "file " +file.getAbsolutePath(); + } + public URL getURL() { try @@ -729,6 +828,7 @@ public class URLClassLoader extends SecureClassLoader */ protected void addURL(URL newUrl) { + urls.add(newUrl); addURLImpl(newUrl); } @@ -761,8 +861,21 @@ public class URLClassLoader extends SecureClassLoader urlloaders.put(newUrl, loader); } - urls.add(newUrl); - urlinfos.add(loader); + urlinfos.add(loader); + + Vector extraUrls = loader.getClassPath(); + if (extraUrls != null) + { + Iterator it = extraUrls.iterator(); + while (it.hasNext()) + { + URL url = (URL)it.next(); + URLLoader extraLoader = (URLLoader) urlloaders.get(url); + if (! urlinfos.contains (extraLoader)) + addURLImpl(url); + } + } + } } @@ -773,7 +886,7 @@ public class URLClassLoader extends SecureClassLoader private void addURLs(URL[] newUrls) { for (int i = 0; i < newUrls.length; i++) - addURLImpl(newUrls[i]); + addURL(newUrls[i]); } /** @@ -830,7 +943,7 @@ public class URLClassLoader extends SecureClassLoader { // Just try to find the resource by the (almost) same name String resourceName = className.replace('.', '/') + ".class"; - int max = urls.size(); + int max = urlinfos.size(); Resource resource = null; for (int i = 0; i < max && resource == null; i++) { @@ -939,7 +1052,7 @@ public class URLClassLoader extends SecureClassLoader */ private Resource findURLResource(String resourceName) { - int max = urls.size(); + int max = urlinfos.size(); for (int i = 0; i < max; i++) { URLLoader loader = (URLLoader) urlinfos.elementAt(i); @@ -1010,7 +1123,7 @@ public class URLClassLoader extends SecureClassLoader throws IOException { Vector resources = new Vector(); - int max = urls.size(); + int max = urlinfos.size(); for (int i = 0; i < max; i++) { URLLoader loader = (URLLoader) urlinfos.elementAt(i); |