private void InitializeJavaClassLoader(JavaClassLoaderConstructionInProgress jclcip, Type customClassLoaderClass) { Assembly assembly = assemblyLoader.Assembly; { if (customClassLoaderClass != null) { try { if (!customClassLoaderClass.IsPublic && !customClassLoaderClass.Assembly.Equals(assembly)) { throw new Exception("Type not accessible"); } ConstructorInfo customClassLoaderCtor = customClassLoaderClass.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(Assembly) }, null); if (customClassLoaderCtor == null) { throw new Exception("No constructor"); } if (!customClassLoaderCtor.IsPublic && !customClassLoaderClass.Assembly.Equals(assembly)) { customClassLoaderCtor = null; throw new Exception("Constructor not accessible"); } // NOTE we're creating an uninitialized instance of the custom class loader here, so that getClassLoader will return the proper object // when it is called during the construction of the custom class loader later on. This still doesn't make it safe to use the custom // class loader before it is constructed, but at least the object instance is available and should anyone cache it, they will get the // right object to use later on. // Note that creating the unitialized instance will (unfortunately) trigger the static initializer. The static initializer can // trigger a call to getClassLoader(), which means we can end up here recursively. java.lang.ClassLoader newJavaClassLoader = (java.lang.ClassLoader)GetUninitializedObject(customClassLoaderClass); if (jclcip.javaClassLoader == null) // check if we weren't invoked recursively and the nested invocation already did the work { jclcip.javaClassLoader = newJavaClassLoader; SetWrapperForClassLoader(jclcip.javaClassLoader, this); DoPrivileged(new CustomClassLoaderCtorCaller(customClassLoaderCtor, jclcip.javaClassLoader, assembly)); Tracer.Info(Tracer.Runtime, "Created custom assembly class loader {0} for assembly {1}", customClassLoaderClass.FullName, assembly); } else { // we didn't initialize the object, so there is no need to finalize it GC.SuppressFinalize(newJavaClassLoader); } } catch (Exception x) { Tracer.Error(Tracer.Runtime, "Unable to create custom assembly class loader {0} for {1}: {2}", customClassLoaderClass.FullName, assembly, x); } } } if (jclcip.javaClassLoader == null) { jclcip.javaClassLoader = new ikvm.runtime.AssemblyClassLoader(); SetWrapperForClassLoader(jclcip.javaClassLoader, this); } // finally we publish the class loader for other threads to see Thread.MemoryBarrier(); javaClassLoader = jclcip.javaClassLoader; }
private java.lang.ClassLoader WaitInitializeJavaClassLoader(Type customClassLoader) { Interlocked.CompareExchange(ref jclcip, new JavaClassLoaderConstructionInProgress(), null); JavaClassLoaderConstructionInProgress curr = jclcip; if (curr != null) { if (curr.Thread == Thread.CurrentThread) { if (curr.javaClassLoader != null) { // we were recursively invoked during the class loader construction, // so we have to return the partialy constructed class loader return curr.javaClassLoader; } curr.recursion++; try { if (javaClassLoader == null) { InitializeJavaClassLoader(curr, customClassLoader); } } finally { // We only publish the class loader from the outer most invocation, otherwise // an invocation of getClassLoader in the static initializer or constructor // of the custom class loader would result in prematurely publishing it. if (--curr.recursion == 0) { lock (this) { jclcip = null; Monitor.PulseAll(this); } } } } else { lock (this) { while (jclcip != null) { Monitor.Wait(this); } } } } return javaClassLoader; }