This commit is contained in:
jfrijters 2005-02-16 11:20:43 +00:00
Родитель 5380a91247
Коммит 90982544bd
12 изменённых файлов: 159 добавлений и 113 удалений

Просмотреть файл

@ -2419,6 +2419,7 @@ sun/misc/Ref.java
../../classpath/javax/swing/SizeRequirements.java
../../classpath/javax/swing/SizeSequence.java
../../classpath/javax/swing/SortingFocusTraversalPolicy.java
../../classpath/javax/swing/SpinnerDateModel.java
../../classpath/javax/swing/SpinnerListModel.java
../../classpath/javax/swing/SpinnerModel.java
../../classpath/javax/swing/SpinnerNumberModel.java
@ -2734,7 +2735,7 @@ sun/misc/Ref.java
../../classpath/gnu/xml/aelfred2/XmlReader.java
../../classpath/gnu/xml/dom/Consumer.java
../../classpath/gnu/xml/dom/DomAttr.java
../../classpath/gnu/xml/dom/DomCDATA.java
../../classpath/gnu/xml/dom/DomCDATASection.java
../../classpath/gnu/xml/dom/DomCharacterData.java
../../classpath/gnu/xml/dom/DomComment.java
../../classpath/gnu/xml/dom/DomDoctype.java
@ -2742,13 +2743,13 @@ sun/misc/Ref.java
../../classpath/gnu/xml/dom/DomDocumentBuilder.java
../../classpath/gnu/xml/dom/DomDocumentBuilderFactory.java
../../classpath/gnu/xml/dom/DomDocumentConfiguration.java
../../classpath/gnu/xml/dom/DomDocumentFragment.java
../../classpath/gnu/xml/dom/DomDOMException.java
../../classpath/gnu/xml/dom/DomElement.java
../../classpath/gnu/xml/dom/DomEntity.java
../../classpath/gnu/xml/dom/DomEntityReference.java
../../classpath/gnu/xml/dom/DomEvent.java
../../classpath/gnu/xml/dom/DomEx.java
../../classpath/gnu/xml/dom/DomExtern.java
../../classpath/gnu/xml/dom/DomFragment.java
../../classpath/gnu/xml/dom/DomImpl.java
../../classpath/gnu/xml/dom/DomIterator.java
../../classpath/gnu/xml/dom/DomNamedNodeMap.java
@ -2757,7 +2758,7 @@ sun/misc/Ref.java
../../classpath/gnu/xml/dom/DomNotation.java
../../classpath/gnu/xml/dom/DomNsNode.java
../../classpath/gnu/xml/dom/DomNSResolverContext.java
../../classpath/gnu/xml/dom/DomPI.java
../../classpath/gnu/xml/dom/DomProcessingInstruction.java
../../classpath/gnu/xml/dom/DomText.java
../../classpath/gnu/xml/dom/DomXPathExpression.java
../../classpath/gnu/xml/dom/DomXPathNSResolver.java
@ -2767,7 +2768,7 @@ sun/misc/Ref.java
../../classpath/gnu/xml/dom/ImplementationList.java
../../classpath/gnu/xml/dom/ImplementationSource.java
../../classpath/gnu/xml/dom/JAXPFactory.java
../../classpath/gnu/xml/dom/ls/DomLSEx.java
../../classpath/gnu/xml/dom/ls/DomLSException.java
../../classpath/gnu/xml/dom/ls/DomLSInput.java
../../classpath/gnu/xml/dom/ls/DomLSOutput.java
../../classpath/gnu/xml/dom/ls/DomLSParser.java

Просмотреть файл

@ -37,7 +37,7 @@
</target>
<target name="IKVM.GNU.Classpath.dll" depends="classes">
<exec program="${nant.project.basedir}/../bin/ikvmc.exe" useruntimeengine="true" commandline="-version:0.11.* ${signoption} -monoBugWorkaround -opt:fields -nojni -out:IKVM.GNU.Classpath.dll -remap:map.xml -exclude:exclude.lst -target:library -recurse:./*.class -recurse:${Classpath.dir}/*.class -recurse:${Classpath.dir}/resource/*.properties mscorlib.jar System.jar System.Xml.jar -resource:lib/security/classpath.security=classpath.security" />
<exec program="${nant.project.basedir}/../bin/ikvmc.exe" useruntimeengine="true" commandline="-version:0.11.* ${signoption} -monoBugWorkaround -enabletls -opt:fields -nojni -out:IKVM.GNU.Classpath.dll -remap:map.xml -exclude:exclude.lst -target:library -recurse:./*.class -recurse:${Classpath.dir}/*.class -recurse:${Classpath.dir}/resource/*.properties mscorlib.jar System.jar System.Xml.jar -resource:lib/security/classpath.security=classpath.security" />
<copy file="IKVM.GNU.Classpath.dll" tofile="../bin/IKVM.GNU.Classpath.dll.new" />
<if propertytrue="nant.platform.win32">
<call target="peverify-classpath"/>

Просмотреть файл

@ -174,37 +174,34 @@ final class VMClassLoader
*/
static Enumeration getResources(String name) throws IOException
{
synchronized(nestedGetResourcesHack)
{
if(cli.System.Threading.Thread.GetData(nestedGetResourcesHack) != null)
if(__tls_nestedGetResourcesHack)
{
return gnu.java.util.EmptyEnumeration.getInstance();
}
__tls_nestedGetResourcesHack = true;
try
{
Assembly[] assemblies = findResourceAssemblies(name);
java.util.Vector v = new java.util.Vector();
for(int i = 0; i < assemblies.length; i++)
{
return gnu.java.util.EmptyEnumeration.getInstance();
v.addElement(new URL("ikvmres", assemblies[i].get_FullName(), -1, "/" + name));
}
cli.System.Threading.Thread.SetData(nestedGetResourcesHack, "");
try
Enumeration e = v.elements();
ClassLoader bootstrap = getBootstrapClassLoader();
if(bootstrap != null)
{
Assembly[] assemblies = findResourceAssemblies(name);
java.util.Vector v = new java.util.Vector();
for(int i = 0; i < assemblies.length; i++)
{
v.addElement(new URL("ikvmres", assemblies[i].get_FullName(), -1, "/" + name));
}
Enumeration e = v.elements();
ClassLoader bootstrap = getBootstrapClassLoader();
if(bootstrap != null)
{
e = new DoubleEnumeration(e, bootstrap.getResources(name));
}
return e;
e = new DoubleEnumeration(e, bootstrap.getResources(name));
}
finally
{
cli.System.Threading.Thread.SetData(nestedGetResourcesHack, null);
}
}
return e;
}
finally
{
__tls_nestedGetResourcesHack = false;
}
}
private static cli.System.LocalDataStoreSlot nestedGetResourcesHack = cli.System.Threading.Thread.AllocateDataSlot();
private static boolean __tls_nestedGetResourcesHack;
/**
* Helper to get a package from the bootstrap class loader. The default
@ -252,15 +249,9 @@ final class VMClassLoader
if(packages == null)
{
ClassLoader boot = getBootstrapClassLoader();
if(boot != null)
if(boot != null && __tls_nestedGetResourcesHack)
{
synchronized(nestedGetResourcesHack)
{
if(cli.System.Threading.Thread.GetData(nestedGetResourcesHack) != null)
{
return new Package[0];
}
}
return new Package[0];
}
HashMap h = new HashMap();
Assembly[] assemblies = AppDomain.get_CurrentDomain().GetAssemblies();
@ -283,17 +274,14 @@ final class VMClassLoader
if(boot != null)
{
Package[] pkgboot;
synchronized(nestedGetResourcesHack)
__tls_nestedGetResourcesHack = true;
try
{
cli.System.Threading.Thread.SetData(nestedGetResourcesHack, "");
try
{
pkgboot = boot.getPackages();
}
finally
{
cli.System.Threading.Thread.SetData(nestedGetResourcesHack, null);
}
pkgboot = boot.getPackages();
}
finally
{
__tls_nestedGetResourcesHack = false;
}
Collection c = h.values();
packages = new Package[c.size() + pkgboot.length];

Просмотреть файл

@ -6,7 +6,8 @@ final class VMThread
{
private static final Object countLock = new Object();
private static int nonDaemonCount;
private static final cli.System.LocalDataStoreSlot localDataStoreSlot = cli.System.Threading.Thread.AllocateDataSlot();
private static Thread __tls_javaThread;
private static Object __tls_cleanup;
private cli.System.WeakReference nativeThreadReference;
// Note: when this thread dies, this reference is *not* cleared
@ -122,7 +123,8 @@ final class VMThread
synchronized(vmthread)
{
vmthread.cleanup();
cli.System.Threading.Thread.SetData(localDataStoreSlot, null);
__tls_javaThread = null;
__tls_cleanup = null;
VMThread joinWaiter = vmthread.firstJoinWaiter;
while(joinWaiter != null)
{
@ -163,8 +165,7 @@ final class VMThread
static void setThreadGroup(ThreadGroup group)
{
Thread javaThread = (Thread)cli.System.Threading.Thread.GetData(localDataStoreSlot);
if(javaThread == null)
if(__tls_javaThread == null)
{
newThread(group);
}
@ -283,7 +284,7 @@ final class VMThread
{
public void Invoke()
{
cli.System.Threading.Thread.SetData(localDataStoreSlot, thread);
__tls_javaThread = thread;
run();
}
});
@ -508,8 +509,8 @@ final class VMThread
}
}
vmThread.thread = javaThread;
cli.System.Threading.Thread.SetData(localDataStoreSlot, javaThread);
cli.System.Threading.Thread.SetData(cli.System.Threading.Thread.GetNamedDataSlot("ikvm-thread-hack"), new CleanupHack(javaThread));
__tls_javaThread = javaThread;
__tls_cleanup = new CleanupHack(javaThread);
javaThread.group = group;
javaThread.group.addThread(javaThread);
InheritableThreadLocal.newChildThread(javaThread);
@ -518,10 +519,10 @@ final class VMThread
static Thread currentThread()
{
Thread javaThread = (Thread)cli.System.Threading.Thread.GetData(localDataStoreSlot);
Thread javaThread = __tls_javaThread;
if(javaThread == null)
{
javaThread = newThread(ThreadGroup.root);
__tls_javaThread = javaThread = newThread(ThreadGroup.root);
}
return javaThread;
}

Просмотреть файл

@ -57,14 +57,14 @@ final class VMAccessController
* call stack. We use this to remember which context object corresponds to
* which call.
*/
private static final cli.System.LocalDataStoreSlot contexts = cli.System.Threading.Thread.AllocateDataSlot();
private static LinkedList __tls_contexts;
/**
* This is a Boolean that, if set, tells getContext that it has already
* been called once, allowing us to handle recursive permission checks
* caused by methods getContext calls.
*/
private static final cli.System.LocalDataStoreSlot inGetContext = cli.System.Threading.Thread.AllocateDataSlot();
private static boolean __tls_inGetContext;
/**
* And we return this all-permissive context to ensure that privileged
@ -111,11 +111,11 @@ final class VMAccessController
{
if (DEBUG)
debug("pushing " + acc);
LinkedList stack = (LinkedList) cli.System.Threading.Thread.GetData(contexts);
LinkedList stack = __tls_contexts;
if (stack == null)
{
stack = new LinkedList();
cli.System.Threading.Thread.SetData(contexts, stack);
__tls_contexts = stack;
}
stack.addFirst(acc);
}
@ -133,12 +133,12 @@ final class VMAccessController
// Stack should never be null, nor should it be empty, if this method
// and its counterpart has been called properly.
LinkedList stack = (LinkedList) cli.System.Threading.Thread.GetData(contexts);
LinkedList stack = __tls_contexts;
if (stack != null)
{
stack.removeFirst();
if (stack.isEmpty())
cli.System.Threading.Thread.SetData(contexts, null);
__tls_contexts = null;
}
}
@ -157,15 +157,14 @@ final class VMAccessController
//
// XXX is this necessary? We should verify if there are any calls in
// the stack below this method that require permission checks.
Boolean inCall = (Boolean) cli.System.Threading.Thread.GetData(inGetContext);
if (inCall != null && inCall.booleanValue())
if (__tls_inGetContext)
{
if (DEBUG)
debug("already in getContext");
return DEFAULT_CONTEXT;
}
cli.System.Threading.Thread.SetData(inGetContext, Boolean.TRUE);
__tls_inGetContext = true;
Object[][] stack = getStack();
Class[] classes = (Class[]) stack[0];
@ -210,7 +209,7 @@ final class VMAccessController
{
// If there was a call to doPrivileged with a supplied context,
// return that context.
LinkedList l = (LinkedList) cli.System.Threading.Thread.GetData(contexts);
LinkedList l = __tls_contexts;
if (l != null)
context = (AccessControlContext) l.getFirst();
privileged = 1;
@ -245,7 +244,7 @@ final class VMAccessController
else
context = new AccessControlContext(result);
cli.System.Threading.Thread.SetData(inGetContext, Boolean.FALSE);
__tls_inGetContext = false;
return context;
}

Просмотреть файл

@ -120,6 +120,8 @@ class Compiler
Console.Error.WriteLine(" -Xtrace:<string> Displays all tracepoints with the given name");
Console.Error.WriteLine(" -Xmethodtrace:<string> Build tracing into the specified output methods");
Console.Error.WriteLine(" -monoBugWorkaround Workaround metadata bug in Mono 1.0.5 and 1.1.3");
Console.Error.WriteLine(" -enabletls Apply ThreadStaticAttribute to fields starting");
Console.Error.WriteLine(" with __tls_");
return 1;
}
foreach(string s in arglist)
@ -359,6 +361,10 @@ class Compiler
{
options.monoBugWorkaround = true;
}
else if(s == "-enabletls")
{
options.enableTls = true;
}
else if(s == "-opt:fields")
{
options.removeUnusedFields = true;

Просмотреть файл

@ -370,16 +370,22 @@ namespace IKVM.Runtime
sealed class JniHelper
{
//[DllImport("ikvm-native", EntryPoint="_ikvm_LoadLibrary@4")]
[DllImport("ikvm-native")]
private static extern IntPtr ikvm_LoadLibrary(string filename);
//[DllImport("ikvm-native", EntryPoint="_ikvm_FreeLibrary@4")]
[DllImport("ikvm-native")]
private static extern void ikvm_FreeLibrary(IntPtr handle);
//[DllImport("ikvm-native", EntryPoint="_ikvm_GetProcAddress@12")]
[DllImport("ikvm-native")]
internal static extern IntPtr ikvm_GetProcAddress(IntPtr handle, string name, int argc);
//[DllImport("ikvm-native", EntryPoint="_ikvm_CallOnLoad@12")]
[DllImport("ikvm-native")]
private unsafe static extern int ikvm_CallOnLoad(IntPtr method, void* jvm, void* reserved);
//[DllImport("ikvm-native", EntryPoint="_ikvm_GetJNIEnvVTable@0")]
[DllImport("ikvm-native")]
internal unsafe static extern void** ikvm_GetJNIEnvVTable();
//[DllImport("ikvm-native", EntryPoint="_ikvm_MarshalDelegate@4")]
[DllImport("ikvm-native")]
internal unsafe static extern void* ikvm_MarshalDelegate(Delegate d);
@ -1639,13 +1645,18 @@ namespace IKVM.Runtime
{
TypeWrapper wrapper = IKVM.NativeCode.java.lang.VMClass.getWrapperFromClass(pEnv->UnwrapRef(clazz));
wrapper.Finish();
MethodWrapper mw = wrapper.GetMethodWrapper(StringFromUTF8(name), StringFromUTF8(sig).Replace('/', '.'), true);
if(mw != null)
string methodsig = StringFromUTF8(sig);
// don't allow dotted names!
if(methodsig.IndexOf('.') < 0)
{
if(mw.IsStatic == isstatic)
MethodWrapper mw = wrapper.GetMethodWrapper(StringFromUTF8(name), methodsig.Replace('/', '.'), true);
if(mw != null)
{
mw.Link();
return mw.Cookie;
if(mw.IsStatic == isstatic)
{
mw.Link();
return mw.Cookie;
}
}
}
SetPendingException(pEnv, JavaException.NoSuchMethodError("{0}{1}", StringFromUTF8(name), StringFromUTF8(sig).Replace('/', '.')));
@ -1852,12 +1863,17 @@ namespace IKVM.Runtime
{
TypeWrapper wrapper = IKVM.NativeCode.java.lang.VMClass.getWrapperFromClass(pEnv->UnwrapRef(clazz));
wrapper.Finish();
FieldWrapper fw = wrapper.GetFieldWrapper(StringFromUTF8(name), StringFromUTF8(sig).Replace('/', '.'));
if(fw != null)
string fieldsig = StringFromUTF8(sig);
// don't allow dotted names!
if(fieldsig.IndexOf('.') < 0)
{
if(fw.IsStatic == isstatic)
FieldWrapper fw = wrapper.GetFieldWrapper(StringFromUTF8(name), fieldsig.Replace('/', '.'));
if(fw != null)
{
return fw.Cookie;
if(fw.IsStatic == isstatic)
{
return fw.Cookie;
}
}
}
SetPendingException(pEnv, JavaException.NoSuchFieldError(StringFromUTF8(name)));
@ -2872,8 +2888,14 @@ namespace IKVM.Runtime
wrapper.Finish();
for(int i = 0; i < nMethods; i++)
{
// TODO this won't work when we're putting the JNI methods in jniproxy.dll
FieldInfo fi = wrapper.TypeAsTBD.GetField(JNI.METHOD_PTR_FIELD_PREFIX + StringFromUTF8(methods[i].name) + StringFromUTF8(methods[i].signature).Replace('/', '.') + ">", BindingFlags.Static | BindingFlags.NonPublic);
string methodsig = StringFromUTF8(methods[i].signature);
FieldInfo fi = null;
// don't allow dotted names!
if(methodsig.IndexOf('.') < 0)
{
// TODO this won't work when we're putting the JNI methods in jniproxy.dll
fi = wrapper.TypeAsTBD.GetField(JNI.METHOD_PTR_FIELD_PREFIX + StringFromUTF8(methods[i].name) + methodsig.Replace('/', '.') + ">", BindingFlags.Static | BindingFlags.NonPublic);
}
if(fi == null)
{
SetPendingException(pEnv, JavaException.NoSuchMethodError(StringFromUTF8(methods[i].name)));
@ -3139,7 +3161,8 @@ namespace IKVM.Runtime
{
for(int i = 0; i < GlobalRefs.weakRefs.Length; i++)
{
if(!GlobalRefs.weakRefs[i].IsAllocated)
// MONOBUG GCHandle.IsAllocated is horribly broken, so we also check the value of the handle
if(!GlobalRefs.weakRefs[i].IsAllocated || (IntPtr)GlobalRefs.weakRefs[i] == IntPtr.Zero)
{
GlobalRefs.weakRefs[i] = GCHandle.Alloc(o, GCHandleType.WeakTrackResurrection);
return (IntPtr)(- (i | (1 << 30)));

Просмотреть файл

@ -74,7 +74,8 @@ class MemberWrapper
{
lock(this)
{
if(!handle.IsAllocated)
// MONOBUG GCHandle.IsAllocated is horribly broken, so we also check the value of the handle
if(!handle.IsAllocated || (IntPtr)handle == IntPtr.Zero)
{
handle = System.Runtime.InteropServices.GCHandle.Alloc(this, System.Runtime.InteropServices.GCHandleType.Weak);
}

Просмотреть файл

@ -89,9 +89,9 @@ class EmitHelper
ilgen.Emit(OpCodes.Isinst, type);
ilgen.Emit(OpCodes.Dup);
Label ok = ilgen.DefineLabel();
ilgen.Emit(OpCodes.Brtrue, ok);
ilgen.Emit(OpCodes.Brtrue_S, ok);
ilgen.Emit(OpCodes.Ldloc, lb);
ilgen.Emit(OpCodes.Brfalse, ok); // handle null
ilgen.Emit(OpCodes.Brfalse_S, ok); // handle null
ilgen.Emit(OpCodes.Ldtoken, type);
ilgen.Emit(OpCodes.Ldloc, lb);
ilgen.Emit(OpCodes.Call, verboseCastFailure);
@ -102,6 +102,23 @@ class EmitHelper
ilgen.Emit(OpCodes.Castclass, type);
}
}
// This is basically the same as Castclass, except that it
// throws an IncompatibleClassChangeError on failure.
internal static void EmitAssertType(ILGenerator ilgen, Type type)
{
LocalBuilder lb = ilgen.DeclareLocal(typeof(object));
ilgen.Emit(OpCodes.Stloc, lb);
ilgen.Emit(OpCodes.Ldloc, lb);
ilgen.Emit(OpCodes.Isinst, type);
ilgen.Emit(OpCodes.Dup);
Label ok = ilgen.DefineLabel();
ilgen.Emit(OpCodes.Brtrue_S, ok);
ilgen.Emit(OpCodes.Ldloc, lb);
ilgen.Emit(OpCodes.Brfalse_S, ok); // handle null
EmitHelper.Throw(ilgen, "java.lang.IncompatibleClassChangeError");
ilgen.MarkLabel(ok);
}
}
class AttributeHelper
@ -1391,7 +1408,8 @@ abstract class TypeWrapper
// for any interface reference
else if(IsInterfaceOrInterfaceArray && (sourceType == null || sourceType.IsUnloadable || !sourceType.IsAssignableTo(this)))
{
ilgen.Emit(OpCodes.Castclass, TypeAsTBD);
EmitHelper.EmitAssertType(ilgen, TypeAsTBD);
Profiler.Count("InterfaceDownCast");
}
else if(IsNonPrimitiveValueType)
{
@ -2720,6 +2738,11 @@ sealed class DynamicTypeWrapper : TypeWrapper
setModifiers = true;
}
field = typeBuilder.DefineField(fieldName, type, attribs);
if(JVM.IsTlsEnabled && fieldName.StartsWith("__tls_"))
{
CustomAttributeBuilder threadStaticAttrib = new CustomAttributeBuilder(typeof(ThreadStaticAttribute).GetConstructor(Type.EmptyTypes), new object[0]);
field.SetCustomAttribute(threadStaticAttrib);
}
if(fld.IsTransient)
{
CustomAttributeBuilder transientAttrib = new CustomAttributeBuilder(typeof(NonSerializedAttribute).GetConstructor(Type.EmptyTypes), new object[0]);

Просмотреть файл

@ -1987,6 +1987,9 @@ class Compiler
}
else
{
// NOTE for verifiability it is expressly *not* required that the
// value matches the array type, so we don't need to handle interface
// references here.
ilGenerator.Emit(OpCodes.Stelem_Ref);
}
}
@ -2789,8 +2792,7 @@ class Compiler
TypeWrapper tw = ma.GetRawStackTypeWrapper(instructionIndex, args.Length - 1 - i);
if(tw.IsUnloadable || (args[i].IsInterfaceOrInterfaceArray && !tw.IsAssignableTo(args[i])))
{
// TODO ideally, instead of an InvalidCastException, the castclass should throw a IncompatibleClassChangeError
ilGenerator.Emit(OpCodes.Castclass, args[i].TypeAsTBD);
EmitHelper.EmitAssertType(ilGenerator, args[i].TypeAsTBD);
Profiler.Count("InterfaceDownCast");
}
}

Просмотреть файл

@ -145,7 +145,7 @@ namespace IKVM.Internal.MapXml
}
if(tw.IsGhost)
{
tw.EmitConvStackTypeToSignatureType(ilgen, tw);
tw.EmitConvStackTypeToSignatureType(ilgen, null);
}
temps[j] = ilgen.DeclareLocal(tw.TypeAsSignatureType);
ilgen.Emit(OpCodes.Stloc, temps[j]);

Просмотреть файл

@ -45,12 +45,8 @@ namespace IKVM.Runtime
{
}
public static string[] Glob(string arg)
private static string[] Glob(string arg)
{
if(IKVM.Internal.JVM.IsUnix)
{
return new string[] { arg };
}
try
{
string dir = Path.GetDirectoryName(arg);
@ -77,14 +73,7 @@ namespace IKVM.Runtime
public static string[] Glob()
{
if(IKVM.Internal.JVM.IsUnix)
{
return Environment.GetCommandLineArgs();
}
else
{
return Glob(1);
}
return Glob(1);
}
public static string[] Glob(int skip)
@ -163,7 +152,13 @@ namespace IKVM.Runtime
{
if(Thread.CurrentThread.Name == null)
{
Thread.CurrentThread.Name = "main";
try
{
Thread.CurrentThread.Name = "main";
}
catch(InvalidOperationException)
{
}
}
}
@ -172,17 +167,9 @@ namespace IKVM.Runtime
// FXBUG when the main thread ends, it doesn't actually die, it stays around to manage the lifetime
// of the CLR, but in doing so it also keeps alive the thread local storage for this thread and we
// use the TLS as a hack to track when the thread dies (if the object stored in the TLS is finalized,
// we know the thread is dead). So to make that work for the main thread, we explicitly clear the TLS
// slot that contains our hack object.
try
{
Thread.SetData(Thread.GetNamedDataSlot("ikvm-thread-hack"), null);
}
catch(NullReferenceException)
{
// MONOBUG Thread.SetData throws a NullReferenceException on Mono
// if the slot hadn't already been allocated
}
// we know the thread is dead). So to make that work for the main thread, we use jniDetach which
// explicitly cleans up our thread.
IKVM.Internal.JVM.Library.jniDetach();
}
}
@ -296,6 +283,7 @@ namespace IKVM.Internal
private static bool noJniStubs;
private static bool isStaticCompiler;
private static bool noStackTraceInfo;
private static bool isTlsEnabled;
private static bool compilationPhase1;
private static string sourcePath;
private static bool monoBugWorkaround;
@ -381,6 +369,18 @@ namespace IKVM.Internal
}
}
internal static bool IsTlsEnabled
{
get
{
return isTlsEnabled;
}
set
{
isTlsEnabled = value;
}
}
internal static bool CompileInnerClassesAsNestedTypes
{
get
@ -1948,6 +1948,7 @@ namespace IKVM.Internal
public bool nostacktraceinfo;
public bool removeUnusedFields;
public bool monoBugWorkaround;
public bool enableTls;
}
public static int Compile(CompilerOptions options)
@ -1957,6 +1958,7 @@ namespace IKVM.Internal
noJniStubs = options.nojni;
noStackTraceInfo = options.nostacktraceinfo;
monoBugWorkaround = options.monoBugWorkaround;
isTlsEnabled = options.enableTls;
foreach(string r in options.references)
{
try