Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/ikvm-fork.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjfrijters <jfrijters>2002-12-18 19:00:25 +0300
committerjfrijters <jfrijters>2002-12-18 19:00:25 +0300
commit59d175f0205a15dec48c593c215d6b6f560e9097 (patch)
tree3e25ec05e2f6156c193113937af3c453bbed36bb
Initial revision
-rw-r--r--IK.VM.JNI/AssemblyInfo.cpp81
-rw-r--r--IK.VM.JNI/IK.VM.JNI.vcproj144
-rw-r--r--IK.VM.JNI/Stdafx.cpp5
-rw-r--r--IK.VM.JNI/Stdafx.h9
-rw-r--r--IK.VM.JNI/ik.vm.jni.build6
-rw-r--r--IK.VM.JNI/jni.cpp178
-rw-r--r--IK.VM.JNI/jni.h245
-rw-r--r--IK.VM.JNI/jnienv.cpp1097
-rw-r--r--IK.VM.JNI/jnienv.h440
-rw-r--r--IK.VM.NET/AssemblyInfo.cs81
-rw-r--r--IK.VM.NET/BigEndianBinaryReader.cs177
-rw-r--r--IK.VM.NET/ByteCode.cs676
-rw-r--r--IK.VM.NET/ByteCodeHelper.cs72
-rw-r--r--IK.VM.NET/ClassFile.cs1579
-rw-r--r--IK.VM.NET/ClassLoaderWrapper.cs900
-rw-r--r--IK.VM.NET/DoubleToString.cs539
-rw-r--r--IK.VM.NET/ExceptionHelper.cs659
-rw-r--r--IK.VM.NET/IK.VM.NET.csproj192
-rw-r--r--IK.VM.NET/JavaException.cs148
-rw-r--r--IK.VM.NET/ObjectHelper.cs133
-rw-r--r--IK.VM.NET/StringHelper.cs369
-rw-r--r--IK.VM.NET/TypeWrapper.cs3253
-rw-r--r--IK.VM.NET/WeakHashtable.cs214
-rw-r--r--IK.VM.NET/attributes.cs260
-rw-r--r--IK.VM.NET/classpath.cs1636
-rw-r--r--IK.VM.NET/compiler.cs2450
-rw-r--r--IK.VM.NET/ik.vm.net.build14
-rw-r--r--IK.VM.NET/map.xml446
-rw-r--r--IK.VM.NET/profiler.cs79
-rw-r--r--IK.VM.NET/remapper.cs387
-rw-r--r--IK.VM.NET/verifier.cs2185
-rw-r--r--IK.VM.NET/vm.cs195
-rw-r--r--awt/AssemblyInfo.cs58
-rw-r--r--awt/awt.build14
-rw-r--r--awt/awt.csproj113
-rw-r--r--awt/toolkit.cs850
-rw-r--r--bin/lib/security/classpath.security39
-rw-r--r--classpath/System.Xml.jarbin0 -> 121709 bytes
-rw-r--r--classpath/System.jarbin0 -> 288598 bytes
-rw-r--r--classpath/allsources.lst1488
-rw-r--r--classpath/classpath.build33
-rw-r--r--classpath/gnu/classpath/Configuration.java98
-rw-r--r--classpath/gnu/java/net/protocol/ikvmres/Handler.java103
-rw-r--r--classpath/ikvm/awt/NetToolkit.java316
-rw-r--r--classpath/java/io/FileDescriptor.java249
-rw-r--r--classpath/java/io/FileInputStream.java396
-rw-r--r--classpath/java/io/FileOutputStream.java339
-rw-r--r--classpath/java/io/RandomAccessFile.java1197
-rw-r--r--classpath/java/lang/Thread.java1005
-rw-r--r--classpath/java/lang/VMClassLoader.java271
-rw-r--r--classpath/java/lang/reflect/Constructor.java282
-rw-r--r--classpath/java/lang/reflect/Field.java646
-rw-r--r--classpath/java/lang/reflect/Method.java376
-rw-r--r--classpath/java/net/PlainDatagramSocketImpl.java312
-rw-r--r--classpath/java/net/PlainSocketImpl.java327
-rw-r--r--classpath/mscorlib.jarbin0 -> 518720 bytes
-rw-r--r--classpath/sun/misc/Ref.java66
-rw-r--r--ikvm.build19
-rw-r--r--ikvm.sln51
-rw-r--r--ikvm/AssemblyInfo.cs81
-rw-r--r--ikvm/bin/Debug/lib/security/classpath.security39
-rw-r--r--ikvm/bin/Release/lib/security/classpath.security39
-rw-r--r--ikvm/ikvm.build14
-rw-r--r--ikvm/ikvm.csproj103
-rw-r--r--ikvm/starter.cs249
-rw-r--r--ikvmc/AssemblyInfo.cs81
-rw-r--r--ikvmc/Compiler.cs244
-rw-r--r--ikvmc/bin/Release/native.txt4
-rw-r--r--ikvmc/ikvmc.build14
-rw-r--r--ikvmc/ikvmc.csproj103
-rw-r--r--netexp/AssemblyInfo.cs81
-rw-r--r--netexp/ClassFileWriter.cs632
-rw-r--r--netexp/NetExp.cs474
-rw-r--r--netexp/netexp.build14
-rw-r--r--netexp/netexp.csproj108
75 files changed, 29777 insertions, 0 deletions
diff --git a/IK.VM.JNI/AssemblyInfo.cpp b/IK.VM.JNI/AssemblyInfo.cpp
new file mode 100644
index 00000000..0c14df55
--- /dev/null
+++ b/IK.VM.JNI/AssemblyInfo.cpp
@@ -0,0 +1,81 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+#include "stdafx.h"
+
+using namespace System::Reflection;
+using namespace System::Runtime::CompilerServices;
+
+//
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//
+[assembly:AssemblyTitleAttribute("")];
+[assembly:AssemblyDescriptionAttribute("")];
+[assembly:AssemblyConfigurationAttribute("")];
+[assembly:AssemblyCompanyAttribute("")];
+[assembly:AssemblyProductAttribute("")];
+[assembly:AssemblyCopyrightAttribute("")];
+[assembly:AssemblyTrademarkAttribute("")];
+[assembly:AssemblyCultureAttribute("")];
+
+//
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the value or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+
+[assembly:AssemblyVersionAttribute("1.0.1060.22610")];
+
+//
+// In order to sign your assembly you must specify a key to use. Refer to the
+// Microsoft .NET Framework documentation for more information on assembly signing.
+//
+// Use the attributes below to control which key is used for signing.
+//
+// Notes:
+// (*) If no key is specified, the assembly is not signed.
+// (*) KeyName refers to a key that has been installed in the Crypto Service
+// Provider (CSP) on your machine. KeyFile refers to a file which contains
+// a key.
+// (*) If the KeyFile and the KeyName values are both specified, the
+// following processing occurs:
+// (1) If the KeyName can be found in the CSP, that key is used.
+// (2) If the KeyName does not exist and the KeyFile does exist, the key
+// in the KeyFile is installed into the CSP and used.
+// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
+// When specifying the KeyFile, the location of the KeyFile should be
+// relative to the project directory.
+// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
+// documentation for more information on this.
+//
+[assembly:AssemblyDelaySignAttribute(false)];
+[assembly:AssemblyKeyFileAttribute("")];
+[assembly:AssemblyKeyNameAttribute("")];
+
diff --git a/IK.VM.JNI/IK.VM.JNI.vcproj b/IK.VM.JNI/IK.VM.JNI.vcproj
new file mode 100644
index 00000000..7e6d9e18
--- /dev/null
+++ b/IK.VM.JNI/IK.VM.JNI.vcproj
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding = "Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.00"
+ Name="IK.VM.JNI"
+ ProjectGUID="{4D400F9D-68A1-4066-95F6-85AF0E58B710}"
+ Keyword="ManagedCProj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="Debug"
+ IntermediateDirectory="Debug"
+ ConfigurationType="2"
+ CharacterSet="2"
+ ManagedExtensions="TRUE">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG"
+ MinimalRebuild="FALSE"
+ BasicRuntimeChecks="0"
+ RuntimeLibrary="1"
+ TreatWChar_tAsBuiltInType="TRUE"
+ ForceConformanceInForLoopScope="TRUE"
+ UsePrecompiledHeader="3"
+ WarningLevel="3"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/IK.VM.JNI.dll"
+ LinkIncremental="2"
+ GenerateDebugInformation="TRUE"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="Release"
+ IntermediateDirectory="Release"
+ ConfigurationType="2"
+ CharacterSet="2"
+ ManagedExtensions="TRUE">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ PreprocessorDefinitions="WIN32;NDEBUG"
+ MinimalRebuild="FALSE"
+ TreatWChar_tAsBuiltInType="TRUE"
+ ForceConformanceInForLoopScope="TRUE"
+ UsePrecompiledHeader="3"
+ WarningLevel="3"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/IK.VM.JNI.dll"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ </Configuration>
+ </Configurations>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm">
+ <File
+ RelativePath="AssemblyInfo.cpp">
+ </File>
+ <File
+ RelativePath="Stdafx.cpp">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="jni.cpp">
+ </File>
+ <File
+ RelativePath="jnienv.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc">
+ <File
+ RelativePath="Stdafx.h">
+ </File>
+ <File
+ RelativePath="jni.h">
+ </File>
+ <File
+ RelativePath="jnienv.h">
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;r">
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/IK.VM.JNI/Stdafx.cpp b/IK.VM.JNI/Stdafx.cpp
new file mode 100644
index 00000000..42f1745b
--- /dev/null
+++ b/IK.VM.JNI/Stdafx.cpp
@@ -0,0 +1,5 @@
+// stdafx.cpp : source file that includes just the standard includes
+// jni.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
diff --git a/IK.VM.JNI/Stdafx.h b/IK.VM.JNI/Stdafx.h
new file mode 100644
index 00000000..91e9cc50
--- /dev/null
+++ b/IK.VM.JNI/Stdafx.h
@@ -0,0 +1,9 @@
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently,
+// but are changed infrequently
+
+#pragma once
+
+#using <mscorlib.dll>
+
+#include <windows.h>
diff --git a/IK.VM.JNI/ik.vm.jni.build b/IK.VM.JNI/ik.vm.jni.build
new file mode 100644
index 00000000..170781be
--- /dev/null
+++ b/IK.VM.JNI/ik.vm.jni.build
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<project name="ik.vm.jni" default="ik.vm.jni">
+ <target name="ik.vm.jni">
+ <echo message="*** TODO ***" />
+ </target>
+</project>
diff --git a/IK.VM.JNI/jni.cpp b/IK.VM.JNI/jni.cpp
new file mode 100644
index 00000000..cd1a3ecc
--- /dev/null
+++ b/IK.VM.JNI/jni.cpp
@@ -0,0 +1,178 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+
+#include "stdafx.h"
+#include <malloc.h>
+#include "jnienv.h"
+#include "jni.h"
+
+#pragma managed
+
+#include <stdio.h>
+
+using namespace System;
+using namespace System::Collections;
+using namespace System::Runtime::InteropServices;
+
+int JNI::LoadNativeLibrary(String* name)
+{
+ HMODULE hMod = LoadLibrary(name);
+ if(!hMod)
+ {
+ return 0;
+ }
+ libs->Add(__box((int)hMod));
+ return 1;
+}
+
+jobject JNI::MakeGlobalRef(Object* o)
+{
+ if(!o)
+ {
+ return 0;
+ }
+ // TODO search for an empty slot before adding it to the end...
+ return (jobject)-(globalRefs->Add(o) + 1);
+}
+
+void JNI::DeleteGlobalRef(jobject o)
+{
+ if(o)
+ {
+ int i = int(o);
+ if(i < 0)
+ {
+ globalRefs->Item[(-i) - 1] = 0;
+ return;
+ }
+ DebugBreak();
+ }
+}
+
+Object* JNI::UnwrapGlobalRef(jobject o)
+{
+ if(!o)
+ {
+ return 0;
+ }
+ int i = int(o);
+ if(i < 0)
+ {
+ return globalRefs->Item[(-i) - 1];
+ }
+ DebugBreak();
+ return 0;
+}
+
+IntPtr JNI::GetJniFuncPtr(String* method, String* sig, String* clazz)
+{
+ System::Text::StringBuilder* mangledSig = new System::Text::StringBuilder();
+ int sp = 0;
+ for(int i = 1; sig->Chars[i] != ')'; i++)
+ {
+ switch(sig->Chars[i])
+ {
+ case '[':
+ mangledSig->Append(S"_3");
+ sp += 4;
+ while(sig->Chars[++i] == '[')
+ {
+ mangledSig->Append(S"_3");
+ }
+ mangledSig->Append(sig->Chars[i]);
+ if(sig->Chars[i] == 'L')
+ {
+ while(sig->Chars[++i] != ';')
+ {
+ if(sig->Chars[i] == '/')
+ {
+ mangledSig->Append(S"_");
+ }
+ else
+ {
+ mangledSig->Append(sig->Chars[i]);
+ }
+ }
+ mangledSig->Append(S"_2");
+ }
+ break;
+ case 'L':
+ sp += 4;
+ mangledSig->Append(S"L");
+ while(sig->Chars[++i] != ';')
+ {
+ if(sig->Chars[i] == '/')
+ {
+ mangledSig->Append(S"_");
+ }
+ else
+ {
+ mangledSig->Append(sig->Chars[i]);
+ }
+ }
+ mangledSig->Append(S"_2");
+ break;
+ case 'J':
+ case 'D':
+ mangledSig->Append(sig->Chars[i]);
+ sp += 8;
+ break;
+ case 'F':
+ case 'I':
+ case 'C':
+ case 'Z':
+ case 'S':
+ case 'B':
+ mangledSig->Append(sig->Chars[i]);
+ sp += 4;
+ break;
+ default:
+ DebugBreak();
+ throw new NotImplementedException();
+ }
+ }
+ void* func = 0;
+ // TODO implement this correctly
+ String* methodName = String::Format(S"_Java_{0}_{1}@{2}", clazz->Replace(S"_", S"_1")->Replace('/', '_'), method->Replace(S"_", S"_1"), __box(sp + 8));
+ for(int i = 0; i < libs->Count; i++)
+ {
+ HMODULE hMod = (HMODULE)__unbox<int>(libs->Item[i]);
+ func = GetProcAddress(hMod, methodName);
+ if(func)
+ {
+ return (IntPtr)func;
+ }
+ }
+ methodName = String::Concat(String::Format(S"_Java_{0}_{1}__{2}@", clazz->Replace(S"_", S"_1")->Replace('/', '_'), method->Replace(S"_", S"_1"), mangledSig), __box(sp + 8));
+ for(int i = 0; i < libs->Count; i++)
+ {
+ HMODULE hMod = (HMODULE)__unbox<int>(libs->Item[i]);
+ func = GetProcAddress(hMod, methodName);
+ if(func)
+ {
+ return (IntPtr)func;
+ }
+ }
+ throw VM::UnsatisfiedLinkError(methodName);
+}
diff --git a/IK.VM.JNI/jni.h b/IK.VM.JNI/jni.h
new file mode 100644
index 00000000..5248f25b
--- /dev/null
+++ b/IK.VM.JNI/jni.h
@@ -0,0 +1,245 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+
+#pragma once
+
+using namespace System;
+using namespace System::Collections;
+using namespace System::Runtime::InteropServices;
+using namespace System::Reflection;
+
+class JNIEnv;
+
+#pragma managed
+
+public __value class LocalRefStruct;
+
+// NOTE this __value type needs to have the *exact* same layout as the unmanaged JNIENv class
+__value struct JNIEnvContainer
+{
+ void* pVtable;
+ LocalRefStruct __nogc* pLocalRefStruct;
+};
+
+public __value class LocalRefStruct
+{
+ [ThreadStatic]
+ static JNIEnvContainer jniEnv;
+ LocalRefStruct __nogc* pPrevLocalRefCache;
+ Object* loc1;
+ Object* loc2;
+ Object* loc3;
+ Object* loc4;
+ Object* loc5;
+ Object* loc6;
+ Object* loc7;
+ Object* loc8;
+ Object* loc9;
+ Object* loc10;
+ Object* overflow __gc[];
+ Exception* pendingException;
+public:
+
+ static JNIEnv* GetEnv()
+ {
+ if(jniEnv.pVtable != 0)
+ {
+ return (JNIEnv*)(void*)&jniEnv;
+ }
+ return 0;
+ }
+
+ IntPtr Enter()
+ {
+ if(jniEnv.pVtable == 0)
+ {
+ // HACK initialize the vtable ptr
+ JNIEnv env;
+ jniEnv.pVtable = *((void**)&env);
+ }
+ pPrevLocalRefCache = jniEnv.pLocalRefStruct;
+ // NOTE since this __value type can (should) only be allocated on the stack,
+ // it is "safe" to store the this pointer in a __nogc*, but the compiler
+ // doesn't know this, so we have to use a __pin* to bypass its checks.
+ LocalRefStruct __pin* pPinHack = this;
+ jniEnv.pLocalRefStruct = pPinHack;
+ return (IntPtr)&jniEnv;
+ }
+
+ void Leave()
+ {
+ jniEnv.pLocalRefStruct = pPrevLocalRefCache;
+ if(pendingException)
+ {
+ // TODO retain the stack trace of the exception object
+ throw pendingException;
+ }
+ }
+
+ __property Exception* get_PendingException()
+ {
+ return pendingException;
+ }
+
+ __property void set_PendingException(Exception* exception)
+ {
+ pendingException = exception;
+ }
+
+ IntPtr MakeLocalRef(Object* o)
+ {
+ if(o == 0)
+ {
+ return 0;
+ }
+ Object** p = &loc1;
+ for(int i = 0; i < 10; i++)
+ {
+ if(p[i] == 0)
+ {
+ p[i] = o;
+ return i + 1;
+ }
+ }
+ if(!overflow)
+ {
+ // HACK we use a very large dynamic table size, because we don't yet support growing it
+ overflow = new Object* __gc[256];
+ }
+ for(int i = 0; i < overflow->Length; i++)
+ {
+ if(overflow[i] == 0)
+ {
+ overflow[i] = o;
+ return i + 11;
+ }
+ }
+ throw new NotImplementedException(S"Growing the localref table is not implemented");
+ }
+
+ void DeleteLocalRef(jobject o)
+ {
+ int i = (int)o;
+ if(i < 0)
+ {
+ DebugBreak();
+ }
+ if(i > 0)
+ {
+ if(i <= 10)
+ {
+ Object** p = &loc1;
+ p[i - 1] = 0;
+ }
+ else
+ {
+ overflow[i - 11] = 0;
+ }
+ }
+ }
+
+ Object* UnwrapLocalRef(IntPtr localref)
+ {
+ if(localref == 0)
+ {
+ return 0;
+ }
+ if(int(localref) <= 10)
+ {
+ Object** p = &loc1;
+ return p[int(localref) - 1];
+ }
+ else
+ {
+ return overflow[int(localref) - 11];
+ }
+ }
+};
+
+public __gc class JNI
+{
+ static ArrayList* libs = new ArrayList();
+ static ArrayList* globalRefs = new ArrayList();
+ [DllImport("kernel32")]
+ [System::Security::SuppressUnmanagedCodeSecurityAttribute]
+ static HMODULE LoadLibrary(String* lpLibFileName);
+ [DllImport("kernel32")]
+ [System::Security::SuppressUnmanagedCodeSecurityAttribute]
+ static void* GetProcAddress(HMODULE hMod, String* lpProcName);
+public:
+ static int LoadNativeLibrary(String* name);
+ static IntPtr GetJniFuncPtr(String* method, String* sig, String* clazz);
+ static jobject MakeGlobalRef(Object* o);
+ static void DeleteGlobalRef(jobject o);
+ static Object* UnwrapGlobalRef(jobject o);
+};
+
+public __gc interface IJniHack
+{
+public:
+ virtual MethodBase* GetMethod(Object* clazz, String* name, String* sig, bool isStatic)=0;
+ virtual FieldInfo* GetField(Object* clazz, String* name, String* sig, bool isStatic)=0;
+ virtual Object* FindClass(String* name)=0;
+ virtual Exception* UnsatisfiedLinkError(String* msg)=0;
+ virtual Object* GetClassFromType(Type* type)=0;
+};
+
+public __gc class VM
+{
+private:
+ static IJniHack* pJniHack = 0;
+ static VM()
+ {
+ pJniHack = __try_cast<IJniHack*>(Activator::CreateInstance(Assembly::Load(S"ik.vm.net")->GetType(S"JniHack")));
+ }
+public:
+ // NOTE we use this nasty construct to avoid a compile time dependency on JVM.DLL (which already has a compile time
+ // dependency on us)
+ static MethodBase* GetMethod(Object* clazz, String* name, String* sig, bool isStatic)
+ {
+ return pJniHack->GetMethod(clazz, name, sig, isStatic);
+ }
+ static FieldInfo* GetField(Object* clazz, String* name, String* sig, bool isStatic)
+ {
+ return pJniHack->GetField(clazz, name, sig, isStatic);
+ }
+ static Object* FindClass(String* javaName)
+ {
+ return pJniHack->FindClass(javaName);
+ }
+ static Exception* UnsatisfiedLinkError(String* msg)
+ {
+ return pJniHack->UnsatisfiedLinkError(msg);
+ }
+ static Object* GetClassFromType(Type* type)
+ {
+ return pJniHack->GetClassFromType(type);
+ }
+};
+
+template<class T> T __unbox(Object* o)
+{
+ // HACK the MC++ compiler has a bug when unboxing, the static_cast<> is to work around that bug
+ return *(static_cast<T __gc*>(__try_cast<__box T*>(o)));
+}
diff --git a/IK.VM.JNI/jnienv.cpp b/IK.VM.JNI/jnienv.cpp
new file mode 100644
index 00000000..eed66174
--- /dev/null
+++ b/IK.VM.JNI/jnienv.cpp
@@ -0,0 +1,1097 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+
+#include "stdafx.h"
+#include "jnienv.h"
+#include "jni.h"
+#include <malloc.h>
+#include <stdarg.h>
+
+#define DEBUG
+#undef NDEBUG
+
+#include <assert.h>
+
+using namespace System;
+using namespace System::Runtime::InteropServices;
+using namespace System::Reflection;
+
+// this struct exists to ensure the right compile switch is used, if it fails
+// to compile, you must compile with /Zc:wchar_t
+struct wchar_t_must_be_builtin
+{
+ void foo(wchar_t t) {}
+ void foo(unsigned short t) {}
+};
+
+#pragma managed
+
+String* StringFromUTF8(const char* psz)
+{
+ // Sun's modified UTF8 encoding is not compatible with System::Text::Encoding::UTF8, so
+ // we need to roll our own
+ int len = 0;
+ while(psz[len]) len++;
+ System::Text::StringBuilder* sb = new System::Text::StringBuilder(len);
+ for(int i = 0; i < len; i++)
+ {
+ int c = (unsigned char)*psz++;
+ int char2, char3;
+ switch (c >> 4)
+ {
+ case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
+ // 0xxxxxxx
+ break;
+ case 12: case 13:
+ // 110x xxxx 10xx xxxx
+ char2 = *psz++;
+ i++;
+ c = (((c & 0x1F) << 6) | (char2 & 0x3F));
+ break;
+ case 14:
+ // 1110 xxxx 10xx xxxx 10xx xxxx
+ char2 = *psz++;
+ char3 = *psz++;
+ i++;
+ i++;
+ c = (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0));
+ break;
+ }
+ sb->Append((wchar_t)c);
+ }
+ return sb->ToString();
+}
+
+JNIEnv::JNIEnv()
+{
+}
+
+JNIEnv::~JNIEnv()
+{
+}
+
+Object* JNIEnv::UnwrapRef(jobject o)
+{
+ int i = (int)o;
+ if(i >= 0)
+ {
+ return pLocalRefs->UnwrapLocalRef(i);
+ }
+ return JNI::UnwrapGlobalRef(o);
+}
+
+jstring JNIEnv::NewStringUTF(const char *psz)
+{
+ return (jstring)(void*)pLocalRefs->MakeLocalRef(StringFromUTF8(psz));
+}
+
+jstring JNIEnv::NewString(const jchar *unicode, jsize len)
+{
+ return (jstring)(void*)pLocalRefs->MakeLocalRef(new String((__wchar_t*)unicode, 0, len));
+}
+
+const char* JNIEnv::GetStringUTFChars(jstring str, jboolean *isCopy)
+{
+ String* s = __try_cast<String*>(UnwrapRef(str));
+ // TODO for now we use the upper limit on the number of possible bytes needed
+ char *buf = new char[s->Length * 3 + 1];
+ // TODO if memory allocation fails, handle it by "throwing" OutOfMemoryError and returning null
+ int j = 0;
+ for(int i = 0, e = s->Length; i < e; i++)
+ {
+ jchar ch = s->Chars[i];
+ if ((ch != 0) && (ch <=0x7f))
+ {
+ buf[j++] = (char)ch;
+ }
+ else if (ch <= 0x7FF)
+ {
+ /* 11 bits or less. */
+ unsigned char high_five = ch >> 6;
+ unsigned char low_six = ch & 0x3F;
+ buf[j++] = high_five | 0xC0; /* 110xxxxx */
+ buf[j++] = low_six | 0x80; /* 10xxxxxx */
+ }
+ else
+ {
+ /* possibly full 16 bits. */
+ char high_four = ch >> 12;
+ char mid_six = (ch >> 6) & 0x3F;
+ char low_six = ch & 0x3f;
+ buf[j++] = high_four | 0xE0; /* 1110xxxx */
+ buf[j++] = mid_six | 0x80; /* 10xxxxxx */
+ buf[j++] = low_six | 0x80; /* 10xxxxxx*/
+ }
+ }
+ buf[j] = 0;
+ if(isCopy)
+ {
+ *isCopy = JNI_TRUE;
+ }
+
+ return buf;
+}
+#pragma unmanaged
+
+void JNIEnv::ReleaseStringUTFChars(jstring str, const char* chars)
+{
+ delete[] chars;
+}
+
+#pragma managed
+jint JNIEnv::ThrowNew(jclass clazz, const char *msg)
+{
+ jstring str = NewStringUTF(msg);
+ jmethodID constructor = GetMethodID(clazz, "<init>", "(Ljava/lang/String;)V");
+ assert(constructor);
+ jobject exc = NewObject(clazz, constructor, str);
+ DeleteLocalRef(str);
+ Throw((jthrowable)exc);
+ DeleteLocalRef(exc);
+ return JNI_OK;
+}
+
+jint JNICALL JNIEnv::Throw(jthrowable obj)
+{
+ pLocalRefs->PendingException = __try_cast<Exception*>(UnwrapRef(obj));
+ return JNI_OK;
+}
+
+jthrowable JNICALL JNIEnv::ExceptionOccurred()
+{
+ return (jthrowable)(void*)pLocalRefs->MakeLocalRef(pLocalRefs->PendingException);
+}
+
+void JNICALL JNIEnv::ExceptionDescribe()
+{
+ if(pLocalRefs->PendingException)
+ {
+ // when calling JNI methods there cannot be an exception pending, so we clear the exception
+ // temporarily, while we print it
+ jobject exception = ExceptionOccurred();
+ Exception* pException = pLocalRefs->PendingException;
+ pLocalRefs->PendingException = 0;
+ jclass cls = FindClass("java/lang/Throwable");
+ jmethodID mid = GetMethodID(cls, "printStackTrace", "()V");
+ DeleteLocalRef(cls);
+ CallVoidMethod(exception, mid);
+ pLocalRefs->DeleteLocalRef(exception);
+ pLocalRefs->PendingException = pException;
+ }
+}
+
+void JNICALL JNIEnv::ExceptionClear()
+{
+ pLocalRefs->PendingException = 0;
+}
+
+#pragma unmanaged
+jclass JNICALL JNIEnv::DefineClass(const char *name, jobject loader, const jbyte *buf, jsize len)
+{
+ assert(false);
+ _asm int 3
+}
+
+#pragma managed
+jclass JNIEnv::FindClass(const char *utf)
+{
+ return (jclass)(void*)pLocalRefs->MakeLocalRef(VM::FindClass(StringFromUTF8(utf)));
+}
+#pragma unmanaged
+
+jobject JNIEnv::AllocObject(jclass cls)
+{
+ // wicked, I just realized that serialization should have a facility to construct uninitialized objects
+ // this can be implemented using FormatterServices.GetUninitializedObject, the only hitch is that this
+ // won't supports strings, so we may have to figure out a workaround for that, or decide just not to support it
+ assert(false);
+ _asm int 3
+}
+
+#pragma managed
+
+jmethodID JNIEnv::FindMethodID(jclass cls, const char* name, const char* sig, bool isstatic)
+{
+ MethodBase* m = VM::GetMethod(UnwrapRef(cls), StringFromUTF8(name), StringFromUTF8(sig), isstatic);
+ if(!m)
+ {
+ //Console::WriteLine("Method not found: {0}{1} (static = {2})", StringFromUTF8(name), StringFromUTF8(sig), __box(isstatic));
+ ThrowNew(FindClass("java/lang/NoSuchMethodError"), "");
+ return 0;
+ }
+ // TODO jmethodID must be cached and delete'd!!! As it stands, we have a huge leak...
+ // also, don't forget to Free the GCHandle...
+ jmethodID mid = new _jmethodID;
+ mid->method = (void*)(IntPtr)GCHandle::Alloc(m);
+ int argc = 0;
+ for(int i = 1; sig[i] != ')'; i++)
+ {
+ switch(sig[i])
+ {
+ case 'I':
+ case 'Z':
+ case 'S':
+ case 'C':
+ case 'B':
+ mid->args[argc++] = 'I';
+ break;
+ case 'L':
+ while(sig[i] != ';') i++;
+ mid->args[argc++] = 'L';
+ break;
+ case '[':
+ while(sig[i] == '[') i++;
+ if(sig[i] == 'L') while(sig[i] != ';') i++;
+ mid->args[argc++] = 'L';
+ break;
+ case 'D':
+ mid->args[argc++] = 'D';
+ break;
+ case 'F':
+ mid->args[argc++] = 'F';
+ break;
+ case 'J':
+ mid->args[argc++] = 'J';
+ break;
+ }
+ if(argc == 256)
+ {
+ // it isn't valid for a Java method to have more than 256 arguments,
+ // so this cannot happen for valid classes
+ throw new NotSupportedException();
+ }
+ }
+ mid->args[argc] = 0;
+ return mid;
+}
+
+jfieldID JNIEnv::FindFieldID(jclass cls, const char* name, const char* sig, bool isstatic)
+{
+ FieldInfo* f = VM::GetField(UnwrapRef(cls), StringFromUTF8(name), StringFromUTF8(sig), isstatic);
+ if(!f)
+ {
+ // TODO what is the proper handling of this
+ assert(false);
+ throw new NotImplementedException("field not found");
+ }
+ // TODO jfieldID must be cached and delete'd!!! As it stands, we have a huge leak...
+ // also, don't forget to Free the GCHandle...
+ jfieldID fid = new _jfieldID;
+ fid->field = (void*)(IntPtr)GCHandle::Alloc(f);
+ return fid;
+}
+
+jmethodID JNIEnv::GetStaticMethodID(jclass cls, const char *name, const char *sig)
+{
+ return FindMethodID(cls, name, sig, true);
+}
+
+Object* JNIEnv::InvokeHelper(jobject object, jmethodID methodID, jvalue* args)
+{
+ MethodBase* m = __try_cast<MethodBase*>(GCHandle::op_Explicit((IntPtr)methodID->method).Target);
+ ParameterInfo* p __gc[] = m->GetParameters();
+ Object* argarray __gc[] = new Object*[p->Length];
+ for(int i = 0; i < p->Length; i++)
+ {
+ if(p[i]->ParameterType == __typeof(bool))
+ {
+ argarray[i] = __box(args[i].z != JNI_FALSE);
+ }
+ else if(p[i]->ParameterType == __typeof(char))
+ {
+ argarray[i] = __box((char)args[i].b);
+ }
+ else if(p[i]->ParameterType == __typeof(__wchar_t))
+ {
+ argarray[i] = __box((__wchar_t)args[i].c);
+ }
+ else if(p[i]->ParameterType == __typeof(short))
+ {
+ argarray[i] = __box((short)args[i].s);
+ }
+ else if(p[i]->ParameterType == __typeof(int))
+ {
+ argarray[i] = __box((int)args[i].i);
+ }
+ else if(p[i]->ParameterType == __typeof(__int64))
+ {
+ argarray[i] = __box((__int64)args[i].j);
+ }
+ else if(p[i]->ParameterType == __typeof(float))
+ {
+ argarray[i] = __box((float)args[i].f);
+ }
+ else if(p[i]->ParameterType == __typeof(double))
+ {
+ argarray[i] = __box((double)args[i].d);
+ }
+ else if(!p[i]->ParameterType->IsValueType)
+ {
+ // If we have an object specified but the method is static, we have been redirected to
+ // a static helper, so we have to adjust
+ if(i == 0 && object && m->IsStatic)
+ {
+ argarray[i] = UnwrapRef(object);
+ object = 0;
+ // HACK fix up the args ptr to correct for the missing first argument
+ args--;
+ }
+ else
+ {
+ argarray[i] = UnwrapRef(args[i].l);
+ }
+ }
+ else
+ {
+ // this can't happen, so it probably should be an assertion
+ assert(false);
+ throw new NotImplementedException(p[i]->ParameterType->FullName);
+ }
+ }
+ try
+ {
+ Object* obj = 0;
+ if(object)
+ {
+ obj = UnwrapRef(object);
+ }
+ if(m->IsConstructor)
+ {
+ return __try_cast<ConstructorInfo*>(m)->Invoke(argarray);
+ }
+ return m->Invoke(obj, argarray);
+ }
+ catch(TargetInvocationException* x)
+ {
+ // TODO retain stack trace information
+ pLocalRefs->PendingException = x->InnerException;
+ return 0;
+ }
+}
+
+void JNICALL JNIEnv::CallStaticVoidMethodA(jclass cls, jmethodID methodID, jvalue* args)
+{
+ InvokeHelper(0, methodID, args);
+}
+#pragma unmanaged
+
+void JNICALL JNIEnv::CallStaticVoidMethodV(jclass clazz, jmethodID methodID, va_list args)
+{
+ int argc = strlen(methodID->args);
+ jvalue* argarray = (jvalue*)_alloca(argc * sizeof(jvalue));
+ for(int i = 0; i < argc; i++)
+ {
+ switch(methodID->args[i])
+ {
+ case 'I':
+ argarray[i].i = va_arg(args, int);
+ break;
+ case 'J':
+ argarray[i].j = va_arg(args, __int64);
+ break;
+ case 'L':
+ argarray[i].l = va_arg(args, jobject);
+ break;
+ case 'D':
+ argarray[i].d = va_arg(args, double);
+ break;
+ case 'F':
+ argarray[i].f = (float)va_arg(args, double);
+ break;
+ }
+ }
+ CallStaticVoidMethodA(clazz, methodID, argarray);
+}
+
+void JNIEnv::CallStaticVoidMethod(jclass clazz, jmethodID methodID, ...)
+{
+ va_list args;
+ va_start(args, methodID);
+ CallStaticVoidMethodV(clazz, methodID, args);
+ va_end(args);
+}
+
+#define STATIC_METHOD_IMPL(Type,type) \
+type JNICALL JNIEnv::CallStatic##Type##MethodV(jclass clazz, jmethodID methodID, va_list args)\
+{\
+ int argc = strlen(methodID->args);\
+ jvalue* argarray = (jvalue*)_alloca(argc * sizeof(jvalue));\
+ for(int i = 0; i < argc; i++)\
+ {\
+ switch(methodID->args[i])\
+ {\
+ case 'I':\
+ argarray[i].i = va_arg(args, int);\
+ break;\
+ case 'J':\
+ argarray[i].j = va_arg(args, __int64);\
+ break;\
+ case 'L':\
+ argarray[i].l = va_arg(args, jobject);\
+ break;\
+ case 'D':\
+ argarray[i].d = va_arg(args, double);\
+ break;\
+ case 'F':\
+ argarray[i].f = (float)va_arg(args, double);\
+ break;\
+ }\
+ }\
+ return CallStatic##Type##MethodA(clazz, methodID, argarray);\
+}\
+type JNIEnv::CallStatic##Type##Method(jclass clazz, jmethodID methodID, ...)\
+{\
+ va_list args;\
+ va_start(args, methodID);\
+ type ret = CallStatic##Type##MethodV(clazz, methodID, args);\
+ va_end(args);\
+ return ret;\
+}
+#define STATIC_METHOD_IMPL_MANAGED(Type,type,cpptype) \
+type JNICALL JNIEnv::CallStatic##Type##MethodA(jclass cls, jmethodID methodID, jvalue* args)\
+{\
+ Object* ret = InvokeHelper(0, methodID, args);\
+ if(ret) return __unbox<cpptype>(ret);\
+ return 0;\
+}
+
+STATIC_METHOD_IMPL(Object,jobject)
+STATIC_METHOD_IMPL(Boolean,jboolean)
+STATIC_METHOD_IMPL(Byte,jbyte)
+STATIC_METHOD_IMPL(Char,jchar)
+STATIC_METHOD_IMPL(Short,jshort)
+STATIC_METHOD_IMPL(Int,jint)
+STATIC_METHOD_IMPL(Long,jlong)
+STATIC_METHOD_IMPL(Float,jfloat)
+STATIC_METHOD_IMPL(Double,jdouble)
+#pragma managed
+STATIC_METHOD_IMPL_MANAGED(Boolean,jboolean,bool)
+STATIC_METHOD_IMPL_MANAGED(Byte,jbyte,System::SByte)
+STATIC_METHOD_IMPL_MANAGED(Char,jchar,wchar_t)
+STATIC_METHOD_IMPL_MANAGED(Short,jshort,short)
+STATIC_METHOD_IMPL_MANAGED(Int,jint,int)
+STATIC_METHOD_IMPL_MANAGED(Long,jlong,__int64)
+STATIC_METHOD_IMPL_MANAGED(Float,jfloat,float)
+STATIC_METHOD_IMPL_MANAGED(Double,jdouble,double)
+
+// special case for Object
+jobject JNICALL JNIEnv::CallStaticObjectMethodA(jclass cls, jmethodID methodID, jvalue* args)
+{
+ return (jobject)(void*)pLocalRefs->MakeLocalRef(InvokeHelper(0, methodID, args));
+}
+
+#pragma unmanaged
+jmethodID JNIEnv::GetMethodID(jclass cls, const char *name, const char *sig)
+{
+ return FindMethodID(cls, name, sig, false);
+}
+
+jfieldID JNICALL JNIEnv::GetFieldID(jclass cls, const char *name, const char *sig)
+{
+ return FindFieldID(cls, name, sig, false);
+}
+
+jfieldID JNICALL JNIEnv::GetStaticFieldID(jclass cls, const char *name, const char *sig)
+{
+ return FindFieldID(cls, name, sig, true);
+}
+
+#pragma managed
+#define GET_SET_FIELD(Type,type,cpptype) \
+void JNICALL JNIEnv::Set##Type##Field(jobject obj, jfieldID fieldID, type val)\
+{\
+ FieldInfo* pField = __try_cast<FieldInfo*>(GCHandle::op_Explicit((IntPtr)fieldID->field).Target);\
+ pField->SetValue(UnwrapRef(obj), __box((cpptype)val));\
+}\
+type JNICALL JNIEnv::Get##Type##Field(jobject obj, jfieldID fieldID)\
+{\
+ FieldInfo* pField = __try_cast<FieldInfo*>(GCHandle::op_Explicit((IntPtr)fieldID->field).Target);\
+ return __unbox<cpptype>(pField->GetValue(UnwrapRef(obj)));\
+}
+
+GET_SET_FIELD(Boolean,jboolean,bool)
+GET_SET_FIELD(Byte,jbyte,System::SByte)
+GET_SET_FIELD(Char,jchar,wchar_t)
+GET_SET_FIELD(Short,jshort,short)
+GET_SET_FIELD(Int,jint,int)
+GET_SET_FIELD(Long,jlong,__int64)
+GET_SET_FIELD(Float,jfloat,float)
+GET_SET_FIELD(Double,jdouble,double)
+
+void JNICALL JNIEnv::SetObjectField(jobject obj, jfieldID fieldID, jobject val)
+{
+ FieldInfo* pField = __try_cast<FieldInfo*>(GCHandle::op_Explicit((IntPtr)fieldID->field).Target);
+ pField->SetValue(UnwrapRef(obj), UnwrapRef(val));
+}
+
+jobject JNICALL JNIEnv::GetObjectField(jobject obj, jfieldID fieldID)
+{
+ FieldInfo* pField = __try_cast<FieldInfo*>(GCHandle::op_Explicit((IntPtr)fieldID->field).Target);
+ return (jobject)(void*)pLocalRefs->MakeLocalRef(pField->GetValue(UnwrapRef(obj)));
+}
+#pragma unmanaged
+
+void JNICALL JNIEnv::SetStaticObjectField(jclass cls, jfieldID fieldID, jobject value)
+{
+ assert(false);
+ _asm int 3
+}
+
+jobject JNICALL JNIEnv::GetStaticObjectField(jclass clazz, jfieldID fieldID)
+{
+ assert(false);
+ _asm int 3
+}
+
+jlong JNICALL JNIEnv::GetStaticLongField(jclass clazz, jfieldID fieldID)
+{
+ assert(false);
+ _asm int 3
+}
+
+#define METHOD_IMPL(Type,type) \
+type JNIEnv::Call##Type##Method(jobject obj, jmethodID methodID, ...) \
+{\
+ va_list args;\
+ va_start(args, methodID);\
+ type ret = Call##Type##MethodV(obj, methodID, args);\
+ va_end(args);\
+ return ret;\
+}\
+type JNICALL JNIEnv::Call##Type##MethodV(jobject obj, jmethodID methodID, va_list args)\
+{\
+ int argc = strlen(methodID->args);\
+ jvalue* argarray = (jvalue*)_alloca(argc * sizeof(jvalue));\
+ for(int i = 0; i < argc; i++)\
+ {\
+ switch(methodID->args[i])\
+ {\
+ case 'I':\
+ argarray[i].i = va_arg(args, int);\
+ break;\
+ case 'J':\
+ argarray[i].j = va_arg(args, __int64);\
+ break;\
+ case 'L':\
+ argarray[i].l = va_arg(args, jobject);\
+ break;\
+ case 'D':\
+ argarray[i].d = va_arg(args, double);\
+ break;\
+ case 'F':\
+ argarray[i].f = (float)va_arg(args, double);\
+ break;\
+ }\
+ }\
+ return Call##Type##MethodA(obj, methodID, argarray);\
+}
+
+#define METHOD_IMPL_MANAGED(Type,type,cpptype) \
+type JNICALL JNIEnv::Call##Type##MethodA(jobject obj, jmethodID methodID, jvalue* args)\
+{\
+ Object* ret = InvokeHelper(obj, methodID, args);\
+ if(ret) return __unbox<cpptype>(ret);\
+ return 0;\
+}
+
+#pragma unmanaged
+METHOD_IMPL(Object,jobject)
+METHOD_IMPL(Boolean,jboolean)
+METHOD_IMPL(Byte,jbyte)
+METHOD_IMPL(Char,jchar)
+METHOD_IMPL(Short,jshort)
+METHOD_IMPL(Int,jint)
+METHOD_IMPL(Long,jlong)
+METHOD_IMPL(Float,jfloat)
+METHOD_IMPL(Double,jdouble)
+#pragma managed
+METHOD_IMPL_MANAGED(Boolean,jboolean,bool)
+METHOD_IMPL_MANAGED(Byte,jbyte,System::SByte)
+METHOD_IMPL_MANAGED(Char,jchar,wchar_t)
+METHOD_IMPL_MANAGED(Short,jshort,short)
+METHOD_IMPL_MANAGED(Int,jint,int)
+METHOD_IMPL_MANAGED(Long,jlong,__int64)
+METHOD_IMPL_MANAGED(Float,jfloat,float)
+METHOD_IMPL_MANAGED(Double,jdouble,double)
+
+// special case for Object, because we need to convert the reference to a localref
+jobject JNICALL JNIEnv::CallObjectMethodA(jobject obj, jmethodID methodID, jvalue* args)
+{
+ return (jobject)(void*)pLocalRefs->MakeLocalRef(InvokeHelper(obj, methodID, args));
+}
+#pragma unmanaged
+
+void JNIEnv::CallVoidMethod(jobject obj, jmethodID methodID, ...)
+{
+ va_list args;
+ va_start(args, methodID);
+ CallVoidMethodV(obj, methodID, args);
+ va_end(args);
+}
+
+void JNICALL JNIEnv::CallVoidMethodV(jobject obj, jmethodID methodID, va_list args)
+{
+ int argc = strlen(methodID->args);
+ jvalue* argarray = (jvalue*)_alloca(argc * sizeof(jvalue));
+ for(int i = 0; i < argc; i++)
+ {
+ switch(methodID->args[i])
+ {
+ case 'I':
+ argarray[i].i = va_arg(args, int);
+ break;
+ case 'J':
+ argarray[i].j = va_arg(args, __int64);
+ break;
+ case 'L':
+ argarray[i].l = va_arg(args, jobject);
+ break;
+ case 'D':
+ argarray[i].d = va_arg(args, double);
+ break;
+ case 'F':
+ argarray[i].f = (float)va_arg(args, double);
+ break;
+ }
+ }
+ CallVoidMethodA(obj, methodID, argarray);
+}
+
+#pragma managed
+void JNICALL JNIEnv::CallVoidMethodA(jobject obj, jmethodID methodID, jvalue* args)
+{
+ InvokeHelper(obj, methodID, args);
+}
+#pragma unmanaged
+
+void JNICALL JNIEnv::CallNonvirtualVoidMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args)
+{
+ assert(false);
+ _asm int 3
+}
+
+void JNICALL JNIEnv::CallNonvirtualVoidMethod(jobject obj, jclass clazz, jmethodID methodID, ...)
+{
+ assert(false);
+ _asm int 3
+}
+
+#pragma managed
+jsize JNIEnv::GetStringLength(jstring str)
+{
+ String* s = __try_cast<String*>(UnwrapRef(str));
+ return s->Length;
+}
+
+const jchar* JNIEnv::GetStringChars(jstring str, jboolean *isCopy)
+{
+ String* s = __try_cast<String*>(UnwrapRef(str));
+ jchar* p = new jchar[s->Length];
+ for(int i = 0; i < s->Length; i++)
+ {
+ p[i] = s->Chars[i];
+ }
+ if(isCopy)
+ {
+ *isCopy = JNI_TRUE;
+ }
+ return p;
+}
+
+void JNIEnv::ReleaseStringChars(jstring str, const jchar *chars)
+{
+ delete[] chars;
+}
+
+jsize JNIEnv::GetArrayLength(jarray array)
+{
+ Array* ar = __try_cast<Array*>(UnwrapRef(array));
+ return ar->Length;
+}
+#pragma unmanaged
+
+jobjectArray JNIEnv::NewObjectArray(jsize len, jclass clazz, jobject init)
+{
+ assert(false);
+ _asm int 3
+}
+
+jcharArray JNICALL JNIEnv::NewCharArray(jsize len)
+{
+ assert(false);
+ _asm int 3
+}
+
+jbyteArray JNICALL JNIEnv::NewByteArray(jsize len)
+{
+ assert(false);
+ _asm int 3
+}
+
+#pragma managed
+jintArray JNICALL JNIEnv::NewIntArray(jsize len)
+{
+ return (jintArray)(void*)pLocalRefs->MakeLocalRef(new int __gc[len]);
+}
+
+#pragma unmanaged
+void JNIEnv::SetObjectArrayElement(jobjectArray array, jsize index, jobject val)
+{
+ assert(false);
+ _asm int 3
+}
+
+#pragma managed
+jobject JNIEnv::GetObjectArrayElement(jobjectArray array, jsize index)
+{
+ Object* ar __gc[] = __try_cast<Object* __gc[]>(UnwrapRef(array));
+ if(index >= ar->Length)
+ {
+ // TODO handle error
+ assert(false);
+ }
+ return (jobject)(void*)pLocalRefs->MakeLocalRef(ar[index]);
+}
+
+#define GET_SET_ARRAY_ELEMENTS(Type,type,cpptype) \
+type* JNIEnv::Get##Type##ArrayElements(type##Array array, jboolean *isCopy)\
+{\
+ cpptype ar __gc[] = __try_cast<cpptype __gc[]>(UnwrapRef(array));\
+ type* p = new type[ar->Length];\
+ for(int i = 0; i < ar->Length; i++)\
+ {\
+ p[i] = ar[i];\
+ }\
+ if(isCopy)\
+ {\
+ *isCopy = JNI_TRUE;\
+ }\
+ return p;\
+}\
+void JNIEnv::Release##Type##ArrayElements(type##Array array, type *elems, jint mode)\
+{\
+ if(mode == 0)\
+ {\
+ cpptype ar __gc[] = __try_cast<cpptype __gc[]>(UnwrapRef(array));\
+ for(int i = 0; i < ar->Length; i++)\
+ {\
+ ar[i] = elems[i];\
+ }\
+ delete[] elems;\
+ }\
+ else if(mode == JNI_COMMIT)\
+ {\
+ cpptype ar __gc[] = __try_cast<cpptype __gc[]>(UnwrapRef(array));\
+ for(int i = 0; i < ar->Length; i++)\
+ {\
+ ar[i] = elems[i];\
+ }\
+ }\
+ else if(mode == JNI_ABORT)\
+ {\
+ delete[] elems;\
+ }\
+}
+
+GET_SET_ARRAY_ELEMENTS(Boolean,jboolean,bool)
+GET_SET_ARRAY_ELEMENTS(Byte,jbyte,System::SByte)
+GET_SET_ARRAY_ELEMENTS(Char,jchar,wchar_t)
+GET_SET_ARRAY_ELEMENTS(Short,jshort,short)
+GET_SET_ARRAY_ELEMENTS(Int,jint,int)
+GET_SET_ARRAY_ELEMENTS(Long,jlong,__int64)
+GET_SET_ARRAY_ELEMENTS(Float,jfloat,float)
+GET_SET_ARRAY_ELEMENTS(Double,jdouble,double)
+
+#pragma unmanaged
+jobject JNICALL JNIEnv::NewObject(jclass clazz, jmethodID methodID, ...)
+{
+ va_list args;
+ va_start(args, methodID);
+ jobject o = NewObjectV(clazz, methodID, args);
+ va_end(args);
+ return o;
+}
+
+jobject JNICALL JNIEnv::NewObjectV(jclass clazz, jmethodID methodID, va_list args)
+{
+ int argc = strlen(methodID->args);
+ jvalue* argarray = (jvalue*)_alloca(argc * sizeof(jvalue));
+ for(int i = 0; i < argc; i++)
+ {
+ switch(methodID->args[i])
+ {
+ case 'I':
+ argarray[i].i = va_arg(args, int);
+ break;
+ case 'J':
+ argarray[i].j = va_arg(args, __int64);
+ break;
+ case 'L':
+ argarray[i].l = va_arg(args, jobject);
+ break;
+ case 'D':
+ argarray[i].d = va_arg(args, double);
+ break;
+ case 'F':
+ argarray[i].f = (float)va_arg(args, double);
+ break;
+ }
+ }
+ return NewObjectA(clazz, methodID, argarray);
+}
+
+#pragma managed
+jobject JNICALL JNIEnv::NewObjectA(jclass clazz, jmethodID methodID, jvalue *args)
+{
+ return (jobject)(void*)pLocalRefs->MakeLocalRef(InvokeHelper(0, methodID, args));
+}
+
+jclass JNICALL JNIEnv::GetObjectClass(jobject obj)
+{
+ if(obj == 0)
+ {
+ // TODO throw nullpointerexception
+ assert(false);
+ }
+ return (jclass)(void*)pLocalRefs->MakeLocalRef(VM::GetClassFromType(UnwrapRef(obj)->GetType()));
+}
+#pragma unmanaged
+
+jboolean JNICALL JNIEnv::IsInstanceOf(jobject obj, jclass clazz)
+{
+ assert(false);
+ _asm int 3
+}
+
+jboolean JNICALL JNIEnv::IsAssignableFrom(jclass sub, jclass sup)
+{
+ assert(false);
+ _asm int 3
+}
+
+#pragma managed
+jobject JNICALL JNIEnv::NewGlobalRef(jobject lobj)
+{
+ return JNI::MakeGlobalRef(UnwrapRef(lobj));
+}
+
+void JNICALL JNIEnv::DeleteGlobalRef(jobject gref)
+{
+ JNI::DeleteGlobalRef(gref);
+}
+
+void JNICALL JNIEnv::DeleteLocalRef(jobject obj)
+{
+ pLocalRefs->DeleteLocalRef(obj);
+}
+#pragma unmanaged
+
+jboolean JNICALL JNIEnv::IsSameObject(jobject obj1, jobject obj2)
+{
+ assert(false);
+ _asm int 3
+}
+
+jclass JNICALL JNIEnv::GetSuperclass(jclass sub)
+{
+ assert(false);
+ _asm int 3
+}
+
+jint JNICALL JNIEnv::MonitorEnter(jobject obj)
+{
+ assert(false);
+ _asm int 3
+}
+
+jint JNICALL JNIEnv::MonitorExit(jobject obj)
+{
+ assert(false);
+ _asm int 3
+}
+
+jint JNICALL JNIEnv::RegisterNatives(jclass clazz, const JNINativeMethod *methods, jint nMethods)
+{
+ assert(false);
+ _asm int 3
+}
+
+jint JNICALL JNIEnv::UnregisterNatives(jclass clazz)
+{
+ assert(false);
+ _asm int 3
+}
+
+jint JNICALL JNIEnv::GetJavaVM(JavaVM **vm)
+{
+ static JavaVM theVM;
+ *vm = &theVM;
+ return 0;
+}
+
+void JavaVM::reserved0() { assert(false); _asm int 3}
+void JavaVM::reserved1() { assert(false); _asm int 3}
+void JavaVM::reserved2() { assert(false); _asm int 3}
+
+jint JavaVM::DestroyJavaVM()
+{
+ assert(false);
+ _asm int 3
+}
+
+jint JavaVM::AttachCurrentThread(void **penv, void *args)
+{
+ assert(false);
+ _asm int 3
+}
+
+jint JavaVM::DetachCurrentThread()
+{
+ assert(false);
+ _asm int 3
+}
+
+#pragma managed
+jint JavaVM::GetEnv(void **penv, jint version)
+{
+ // TODO we should check the version
+ JNIEnv* p = LocalRefStruct::GetEnv();
+ if(p)
+ {
+ *penv = p;
+ return JNI_OK;
+ }
+ return JNI_EDETACHED;
+}
+#pragma unmanaged
+
+jint JavaVM::AttachCurrentThreadAsDaemon(void **penv, void *args)
+{
+ assert(false);
+ _asm int 3
+}
+
+////////////////////////////////////////////////////////////////////////////
+#pragma warning (disable : 4035)
+
+void JNIEnv::reserved0() { assert(false); _asm int 3}
+void JNIEnv::reserved1() { assert(false); _asm int 3}
+void JNIEnv::reserved2() { assert(false); _asm int 3}
+
+void JNIEnv::reserved3() { assert(false); _asm int 3}
+jint JNICALL JNIEnv::GetVersion() { assert(false); _asm int 3}
+
+void JNIEnv::reserved4() { assert(false); _asm int 3}
+void JNIEnv::reserved5() { assert(false); _asm int 3}
+void JNIEnv::reserved6() { assert(false); _asm int 3}
+
+void JNIEnv::reserved7() { assert(false); _asm int 3}
+
+void JNICALL JNIEnv::FatalError(const char *msg) { assert(false); _asm int 3}
+void JNIEnv::reserved8() { assert(false); _asm int 3}
+void JNIEnv::reserved9() { assert(false); _asm int 3}
+
+void JNIEnv::reserved10() { assert(false); _asm int 3}
+void JNIEnv::reserved11() { assert(false); _asm int 3}
+
+jobject JNICALL JNIEnv::CallNonvirtualObjectMethod(jobject obj, jclass clazz, jmethodID methodID, ...) { assert(false); _asm int 3}
+jobject JNICALL JNIEnv::CallNonvirtualObjectMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args) { assert(false); _asm int 3}
+jobject JNICALL JNIEnv::CallNonvirtualObjectMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue * args) { assert(false); _asm int 3}
+
+jboolean JNICALL JNIEnv::CallNonvirtualBooleanMethod(jobject obj, jclass clazz, jmethodID methodID, ...) { assert(false); _asm int 3}
+jboolean JNICALL JNIEnv::CallNonvirtualBooleanMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args) { assert(false); _asm int 3}
+jboolean JNICALL JNIEnv::CallNonvirtualBooleanMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue * args) { assert(false); _asm int 3}
+
+jbyte JNICALL JNIEnv::CallNonvirtualByteMethod(jobject obj, jclass clazz, jmethodID methodID, ...) { assert(false); _asm int 3}
+jbyte JNICALL JNIEnv::CallNonvirtualByteMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args) { assert(false); _asm int 3}
+jbyte JNICALL JNIEnv::CallNonvirtualByteMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue *args) { assert(false); _asm int 3}
+
+jchar JNICALL JNIEnv::CallNonvirtualCharMethod(jobject obj, jclass clazz, jmethodID methodID, ...) { assert(false); _asm int 3}
+jchar JNICALL JNIEnv::CallNonvirtualCharMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args) { assert(false); _asm int 3}
+jchar JNICALL JNIEnv::CallNonvirtualCharMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue *args) { assert(false); _asm int 3}
+
+jshort JNICALL JNIEnv::CallNonvirtualShortMethod(jobject obj, jclass clazz, jmethodID methodID, ...) { assert(false); _asm int 3}
+jshort JNICALL JNIEnv::CallNonvirtualShortMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args) { assert(false); _asm int 3}
+jshort JNICALL JNIEnv::CallNonvirtualShortMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue *args) { assert(false); _asm int 3}
+
+jint JNICALL JNIEnv::CallNonvirtualIntMethod(jobject obj, jclass clazz, jmethodID methodID, ...) { assert(false); _asm int 3}
+jint JNICALL JNIEnv::CallNonvirtualIntMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args) { assert(false); _asm int 3}
+jint JNICALL JNIEnv::CallNonvirtualIntMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue *args) { assert(false); _asm int 3}
+
+jlong JNICALL JNIEnv::CallNonvirtualLongMethod(jobject obj, jclass clazz, jmethodID methodID, ...) { assert(false); _asm int 3}
+jlong JNICALL JNIEnv::CallNonvirtualLongMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args) { assert(false); _asm int 3}
+jlong JNICALL JNIEnv::CallNonvirtualLongMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue *args) { assert(false); _asm int 3}
+
+jfloat JNICALL JNIEnv::CallNonvirtualFloatMethod(jobject obj, jclass clazz, jmethodID methodID, ...) { assert(false); _asm int 3}
+jfloat JNICALL JNIEnv::CallNonvirtualFloatMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args) { assert(false); _asm int 3}
+jfloat JNICALL JNIEnv::CallNonvirtualFloatMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue *args) { assert(false); _asm int 3}
+
+jdouble JNICALL JNIEnv::CallNonvirtualDoubleMethod(jobject obj, jclass clazz, jmethodID methodID, ...) { assert(false); _asm int 3}
+jdouble JNICALL JNIEnv::CallNonvirtualDoubleMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args) { assert(false); _asm int 3}
+jdouble JNICALL JNIEnv::CallNonvirtualDoubleMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue *args) { assert(false); _asm int 3}
+
+void JNICALL JNIEnv::CallNonvirtualVoidMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue * args) { assert(false); _asm int 3}
+
+jboolean JNICALL JNIEnv::GetStaticBooleanField(jclass clazz, jfieldID fieldID) { assert(false); _asm int 3}
+jbyte JNICALL JNIEnv::GetStaticByteField(jclass clazz, jfieldID fieldID) { assert(false); _asm int 3}
+jchar JNICALL JNIEnv::GetStaticCharField(jclass clazz, jfieldID fieldID) { assert(false); _asm int 3}
+jshort JNICALL JNIEnv::GetStaticShortField(jclass clazz, jfieldID fieldID) { assert(false); _asm int 3}
+jint JNICALL JNIEnv::GetStaticIntField(jclass clazz, jfieldID fieldID) { assert(false); _asm int 3}
+jfloat JNICALL JNIEnv::GetStaticFloatField(jclass clazz, jfieldID fieldID) { assert(false); _asm int 3}
+jdouble JNICALL JNIEnv::GetStaticDoubleField(jclass clazz, jfieldID fieldID) { assert(false); _asm int 3}
+
+void JNICALL JNIEnv::SetStaticBooleanField(jclass clazz, jfieldID fieldID, jboolean value) { assert(false); _asm int 3}
+void JNICALL JNIEnv::SetStaticByteField(jclass clazz, jfieldID fieldID, jbyte value) { assert(false); _asm int 3}
+void JNICALL JNIEnv::SetStaticCharField(jclass clazz, jfieldID fieldID, jchar value) { assert(false); _asm int 3}
+void JNICALL JNIEnv::SetStaticShortField(jclass clazz, jfieldID fieldID, jshort value) { assert(false); _asm int 3}
+void JNICALL JNIEnv::SetStaticIntField(jclass clazz, jfieldID fieldID, jint value) { assert(false); _asm int 3}
+void JNICALL JNIEnv::SetStaticLongField(jclass clazz, jfieldID fieldID, jlong value) { assert(false); _asm int 3}
+void JNICALL JNIEnv::SetStaticFloatField(jclass clazz, jfieldID fieldID, jfloat value) { assert(false); _asm int 3}
+void JNICALL JNIEnv::SetStaticDoubleField(jclass clazz, jfieldID fieldID, jdouble value) { assert(false); _asm int 3}
+
+jsize JNICALL JNIEnv::GetStringUTFLength(jstring str) { assert(false); _asm int 3}
+
+jbooleanArray JNICALL JNIEnv::NewBooleanArray(jsize len) { assert(false); _asm int 3}
+jshortArray JNICALL JNIEnv::NewShortArray(jsize len) { assert(false); _asm int 3}
+jlongArray JNICALL JNIEnv::NewLongArray(jsize len) { assert(false); _asm int 3}
+jfloatArray JNICALL JNIEnv::NewFloatArray(jsize len) { assert(false); _asm int 3}
+jdoubleArray JNICALL JNIEnv::NewDoubleArray(jsize len) { assert(false); _asm int 3}
+
+void JNICALL JNIEnv::GetBooleanArrayRegion(jbooleanArray array, jsize start, jsize l, jboolean *buf) { assert(false); _asm int 3}
+void JNICALL JNIEnv::GetByteArrayRegion(jbyteArray array, jsize start, jsize len, jbyte *buf) { assert(false); _asm int 3}
+void JNICALL JNIEnv::GetCharArrayRegion(jcharArray array, jsize start, jsize len, jchar *buf) { assert(false); _asm int 3}
+void JNICALL JNIEnv::GetShortArrayRegion(jshortArray array, jsize start, jsize len, jshort *buf) { assert(false); _asm int 3}
+void JNICALL JNIEnv::GetIntArrayRegion(jintArray array, jsize start, jsize len, jint *buf) { assert(false); _asm int 3}
+void JNICALL JNIEnv::GetLongArrayRegion(jlongArray array, jsize start, jsize len, jlong *buf) { assert(false); _asm int 3}
+void JNICALL JNIEnv::GetFloatArrayRegion(jfloatArray array, jsize start, jsize len, jfloat *buf) { assert(false); _asm int 3}
+void JNICALL JNIEnv::GetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len, jdouble *buf) { assert(false); _asm int 3}
+
+void JNICALL JNIEnv::SetBooleanArrayRegion(jbooleanArray array, jsize start, jsize l, jboolean *buf) { assert(false); _asm int 3}
+void JNICALL JNIEnv::SetByteArrayRegion(jbyteArray array, jsize start, jsize len, jbyte *buf) { assert(false); _asm int 3}
+void JNICALL JNIEnv::SetCharArrayRegion(jcharArray array, jsize start, jsize len, jchar *buf) { assert(false); _asm int 3}
+void JNICALL JNIEnv::SetShortArrayRegion(jshortArray array, jsize start, jsize len, jshort *buf) { assert(false); _asm int 3}
+void JNICALL JNIEnv::SetIntArrayRegion(jintArray array, jsize start, jsize len, jint *buf) { assert(false); _asm int 3}
+void JNICALL JNIEnv::SetLongArrayRegion(jlongArray array, jsize start, jsize len, jlong *buf) { assert(false); _asm int 3}
+void JNICALL JNIEnv::SetFloatArrayRegion(jfloatArray array, jsize start, jsize len, jfloat *buf) { assert(false); _asm int 3}
+void JNICALL JNIEnv::SetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len, jdouble *buf) { assert(false); _asm int 3}
diff --git a/IK.VM.JNI/jnienv.h b/IK.VM.JNI/jnienv.h
new file mode 100644
index 00000000..8fca4ff3
--- /dev/null
+++ b/IK.VM.JNI/jnienv.h
@@ -0,0 +1,440 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+
+#pragma unmanaged
+
+#define JNI_TRUE 1
+#define JNI_FALSE 0
+
+typedef struct {
+ char *name;
+ char *signature;
+ void *fnPtr;
+} JNINativeMethod;
+
+#define JNI_VERSION_1_1 0x00010001
+#define JNI_VERSION_1_2 0x00010002
+#define JNI_VERSION_1_4 0x00010004
+
+/*
+ * possible return values for JNI functions.
+ */
+
+#define JNI_OK 0
+#define JNI_ERR (-1)
+#define JNI_EDETACHED (-2)
+#define JNI_EVERSION (-3)
+/*
+ * used in ReleaseScalarArrayElements
+ */
+
+#define JNI_COMMIT 1
+#define JNI_ABORT 2
+
+class JavaVM;
+
+#define JNIEXPORT
+#define JNICALL __stdcall
+
+#ifndef _HELPERTYPES_
+#define _HELPERTYPES_
+class _jobject {};
+class _jclass : public _jobject {};
+class _jstring : public _jobject {};
+class _jthrowable : public _jobject {};
+class Array$ : public _jobject {};
+class ObjectArray$ : public Array$ {};
+class BooleanArray$ : public Array$ {};
+class ByteArray$ : public Array$ {};
+class CharArray$ : public Array$ {};
+class ShortArray$ : public Array$ {};
+class IntArray$ : public Array$ {};
+class LongArray$ : public Array$ {};
+class FloatArray$ : public Array$ {};
+class DoubleArray$ : public Array$ {};
+#endif //_HELPERTYPES_
+
+typedef class _jclass* jclass;
+typedef class _jobject* jobject;
+typedef class _jstring* jstring;
+typedef class _jthrowable* jthrowable;
+typedef class Array$* jarray;
+typedef class ObjectArray$* jobjectArray;
+typedef class BooleanArray$* jbooleanArray;
+typedef class ByteArray$* jbyteArray;
+typedef class CharArray$* jcharArray;
+typedef class ShortArray$* jshortArray;
+typedef class IntArray$* jintArray;
+typedef class LongArray$* jlongArray;
+typedef class FloatArray$* jfloatArray;
+typedef class DoubleArray$* jdoubleArray;
+typedef struct _jmethodID* jmethodID;
+typedef struct _jfieldID* jfieldID;
+
+struct _jmethodID
+{
+ void* method;
+ char args[257]; // 'I', 'J', 'L', 'D' or 'F', and terminated by '\0'
+};
+
+struct _jfieldID
+{
+ void* field;
+};
+
+/*
+ * JNI Types
+ */
+
+typedef unsigned char jboolean;
+typedef unsigned short jchar;
+typedef short jshort;
+typedef float jfloat;
+typedef double jdouble;
+
+typedef long jint;
+typedef __int64 jlong;
+typedef signed char jbyte;
+
+typedef jint jsize;
+
+typedef union jvalue {
+ jboolean z;
+ jbyte b;
+ jchar c;
+ jshort s;
+ jint i;
+ jlong j;
+ jfloat f;
+ jdouble d;
+ jobject l;
+} jvalue;
+
+public __value class LocalRefStruct;
+public __gc class System::Object;
+
+class JNIEnv
+{
+ LocalRefStruct __nogc* pLocalRefs;
+
+ System::Object __gc* UnwrapRef(jobject o);
+ jmethodID FindMethodID(jclass cls, const char* name, const char* sig, bool isstatic);
+ System::Object __gc* InvokeHelper(jobject object, jmethodID methodID, jvalue* args);
+ jfieldID FindFieldID(jclass cls, const char* name, const char* sig, bool isstatic);
+
+public:
+ JNIEnv();
+ ~JNIEnv();
+
+ virtual void JNICALL reserved0();
+ virtual void JNICALL reserved1();
+ virtual void JNICALL reserved2();
+
+ virtual void JNICALL reserved3();
+ virtual jint JNICALL GetVersion();
+
+ virtual jclass JNICALL DefineClass(const char *name, jobject loader, const jbyte *buf, jsize len);
+ virtual jclass JNICALL FindClass(const char *name);
+
+ virtual void JNICALL reserved4();
+ virtual void JNICALL reserved5();
+ virtual void JNICALL reserved6();
+
+ virtual jclass JNICALL GetSuperclass(jclass sub);
+ virtual jboolean JNICALL IsAssignableFrom(jclass sub, jclass sup);
+ virtual void JNICALL reserved7();
+
+ virtual jint JNICALL Throw(jthrowable obj);
+ virtual jint JNICALL ThrowNew(jclass clazz, const char *msg);
+ virtual jthrowable JNICALL ExceptionOccurred();
+ virtual void JNICALL ExceptionDescribe();
+ virtual void JNICALL ExceptionClear();
+ virtual void JNICALL FatalError(const char *msg);
+ virtual void JNICALL reserved8();
+ virtual void JNICALL reserved9();
+
+ virtual jobject JNICALL NewGlobalRef(jobject lobj);
+ virtual void JNICALL DeleteGlobalRef(jobject gref);
+ virtual void JNICALL DeleteLocalRef(jobject obj);
+ virtual jboolean JNICALL IsSameObject(jobject obj1, jobject obj2);
+ virtual void JNICALL reserved10();
+ virtual void JNICALL reserved11();
+
+ virtual jobject JNICALL AllocObject(jclass clazz);
+ virtual jobject JNICALL NewObject(jclass clazz, jmethodID methodID, ...);
+ virtual jobject JNICALL NewObjectV(jclass clazz, jmethodID methodID, va_list args);
+ virtual jobject JNICALL NewObjectA(jclass clazz, jmethodID methodID, jvalue *args);
+
+ virtual jclass JNICALL GetObjectClass(jobject obj);
+ virtual jboolean JNICALL IsInstanceOf(jobject obj, jclass clazz);
+
+ virtual jmethodID JNICALL GetMethodID(jclass clazz, const char *name, const char *sig);
+
+ virtual jobject JNICALL CallObjectMethod(jobject obj, jmethodID methodID, ...);
+ virtual jobject JNICALL CallObjectMethodV(jobject obj, jmethodID methodID, va_list args);
+ virtual jobject JNICALL CallObjectMethodA(jobject obj, jmethodID methodID, jvalue * args);
+
+ virtual jboolean JNICALL CallBooleanMethod(jobject obj, jmethodID methodID, ...);
+ virtual jboolean JNICALL CallBooleanMethodV(jobject obj, jmethodID methodID, va_list args);
+ virtual jboolean JNICALL CallBooleanMethodA(jobject obj, jmethodID methodID, jvalue * args);
+
+ virtual jbyte JNICALL CallByteMethod(jobject obj, jmethodID methodID, ...);
+ virtual jbyte JNICALL CallByteMethodV(jobject obj, jmethodID methodID, va_list args);
+ virtual jbyte JNICALL CallByteMethodA(jobject obj, jmethodID methodID, jvalue *args);
+
+ virtual jchar JNICALL CallCharMethod(jobject obj, jmethodID methodID, ...);
+ virtual jchar JNICALL CallCharMethodV(jobject obj, jmethodID methodID, va_list args);
+ virtual jchar JNICALL CallCharMethodA(jobject obj, jmethodID methodID, jvalue *args);
+
+ virtual jshort JNICALL CallShortMethod(jobject obj, jmethodID methodID, ...);
+ virtual jshort JNICALL CallShortMethodV(jobject obj, jmethodID methodID, va_list args);
+ virtual jshort JNICALL CallShortMethodA(jobject obj, jmethodID methodID, jvalue *args);
+
+ virtual jint JNICALL CallIntMethod(jobject obj, jmethodID methodID, ...);
+ virtual jint JNICALL CallIntMethodV(jobject obj, jmethodID methodID, va_list args);
+ virtual jint JNICALL CallIntMethodA(jobject obj, jmethodID methodID, jvalue *args);
+
+ virtual jlong JNICALL CallLongMethod(jobject obj, jmethodID methodID, ...);
+ virtual jlong JNICALL CallLongMethodV(jobject obj, jmethodID methodID, va_list args);
+ virtual jlong JNICALL CallLongMethodA(jobject obj, jmethodID methodID, jvalue *args);
+
+ virtual jfloat JNICALL CallFloatMethod(jobject obj, jmethodID methodID, ...);
+ virtual jfloat JNICALL CallFloatMethodV(jobject obj, jmethodID methodID, va_list args);
+ virtual jfloat JNICALL CallFloatMethodA(jobject obj, jmethodID methodID, jvalue *args);
+
+ virtual jdouble JNICALL CallDoubleMethod(jobject obj, jmethodID methodID, ...);
+ virtual jdouble JNICALL CallDoubleMethodV(jobject obj, jmethodID methodID, va_list args);
+ virtual jdouble JNICALL CallDoubleMethodA(jobject obj, jmethodID methodID, jvalue *args);
+
+ virtual void JNICALL CallVoidMethod(jobject obj, jmethodID methodID, ...);
+ virtual void JNICALL CallVoidMethodV(jobject obj, jmethodID methodID, va_list args);
+ virtual void JNICALL CallVoidMethodA(jobject obj, jmethodID methodID, jvalue * args);
+
+ virtual jobject JNICALL CallNonvirtualObjectMethod(jobject obj, jclass clazz, jmethodID methodID, ...);
+ virtual jobject JNICALL CallNonvirtualObjectMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args);
+ virtual jobject JNICALL CallNonvirtualObjectMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue * args);
+
+ virtual jboolean JNICALL CallNonvirtualBooleanMethod(jobject obj, jclass clazz, jmethodID methodID, ...);
+ virtual jboolean JNICALL CallNonvirtualBooleanMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args);
+ virtual jboolean JNICALL CallNonvirtualBooleanMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue * args);
+
+ virtual jbyte JNICALL CallNonvirtualByteMethod(jobject obj, jclass clazz, jmethodID methodID, ...);
+ virtual jbyte JNICALL CallNonvirtualByteMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args);
+ virtual jbyte JNICALL CallNonvirtualByteMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue *args);
+
+ virtual jchar JNICALL CallNonvirtualCharMethod(jobject obj, jclass clazz, jmethodID methodID, ...);
+ virtual jchar JNICALL CallNonvirtualCharMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args);
+ virtual jchar JNICALL CallNonvirtualCharMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue *args);
+
+ virtual jshort JNICALL CallNonvirtualShortMethod(jobject obj, jclass clazz, jmethodID methodID, ...);
+ virtual jshort JNICALL CallNonvirtualShortMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args);
+ virtual jshort JNICALL CallNonvirtualShortMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue *args);
+
+ virtual jint JNICALL CallNonvirtualIntMethod(jobject obj, jclass clazz, jmethodID methodID, ...);
+ virtual jint JNICALL CallNonvirtualIntMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args);
+ virtual jint JNICALL CallNonvirtualIntMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue *args);
+
+ virtual jlong JNICALL CallNonvirtualLongMethod(jobject obj, jclass clazz, jmethodID methodID, ...);
+ virtual jlong JNICALL CallNonvirtualLongMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args);
+ virtual jlong JNICALL CallNonvirtualLongMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue *args);
+
+ virtual jfloat JNICALL CallNonvirtualFloatMethod(jobject obj, jclass clazz, jmethodID methodID, ...);
+ virtual jfloat JNICALL CallNonvirtualFloatMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args);
+ virtual jfloat JNICALL CallNonvirtualFloatMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue *args);
+
+ virtual jdouble JNICALL CallNonvirtualDoubleMethod(jobject obj, jclass clazz, jmethodID methodID, ...);
+ virtual jdouble JNICALL CallNonvirtualDoubleMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args);
+ virtual jdouble JNICALL CallNonvirtualDoubleMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue *args);
+
+ virtual void JNICALL CallNonvirtualVoidMethod(jobject obj, jclass clazz, jmethodID methodID, ...);
+ virtual void JNICALL CallNonvirtualVoidMethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args);
+ virtual void JNICALL CallNonvirtualVoidMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue * args);
+
+ virtual jfieldID JNICALL GetFieldID(jclass clazz, const char *name, const char *sig);
+
+ virtual jobject JNICALL GetObjectField(jobject obj, jfieldID fieldID);
+ virtual jboolean JNICALL GetBooleanField(jobject obj, jfieldID fieldID);
+ virtual jbyte JNICALL GetByteField(jobject obj, jfieldID fieldID);
+ virtual jchar JNICALL GetCharField(jobject obj, jfieldID fieldID);
+ virtual jshort JNICALL GetShortField(jobject obj, jfieldID fieldID);
+ virtual jint JNICALL GetIntField(jobject obj, jfieldID fieldID);
+ virtual jlong JNICALL GetLongField(jobject obj, jfieldID fieldID);
+ virtual jfloat JNICALL GetFloatField(jobject obj, jfieldID fieldID);
+ virtual jdouble JNICALL GetDoubleField(jobject obj, jfieldID fieldID);
+
+ virtual void JNICALL SetObjectField(jobject obj, jfieldID fieldID, jobject val);
+ virtual void JNICALL SetBooleanField(jobject obj, jfieldID fieldID, jboolean val);
+ virtual void JNICALL SetByteField(jobject obj, jfieldID fieldID, jbyte val);
+ virtual void JNICALL SetCharField(jobject obj, jfieldID fieldID, jchar val);
+ virtual void JNICALL SetShortField(jobject obj, jfieldID fieldID, jshort val);
+ virtual void JNICALL SetIntField(jobject obj, jfieldID fieldID, jint val);
+ virtual void JNICALL SetLongField(jobject obj, jfieldID fieldID, jlong val);
+ virtual void JNICALL SetFloatField(jobject obj, jfieldID fieldID, jfloat val);
+ virtual void JNICALL SetDoubleField(jobject obj, jfieldID fieldID, jdouble val);
+
+ virtual jmethodID JNICALL GetStaticMethodID(jclass clazz, const char *name, const char *sig);
+
+ virtual jobject JNICALL CallStaticObjectMethod(jclass clazz, jmethodID methodID, ...);
+ virtual jobject JNICALL CallStaticObjectMethodV(jclass clazz, jmethodID methodID, va_list args);
+ virtual jobject JNICALL CallStaticObjectMethodA(jclass clazz, jmethodID methodID, jvalue *args);
+
+ virtual jboolean JNICALL CallStaticBooleanMethod(jclass clazz, jmethodID methodID, ...);
+ virtual jboolean JNICALL CallStaticBooleanMethodV(jclass clazz, jmethodID methodID, va_list args);
+ virtual jboolean JNICALL CallStaticBooleanMethodA(jclass clazz, jmethodID methodID, jvalue *args);
+
+ virtual jbyte JNICALL CallStaticByteMethod(jclass clazz, jmethodID methodID, ...);
+ virtual jbyte JNICALL CallStaticByteMethodV(jclass clazz, jmethodID methodID, va_list args);
+ virtual jbyte JNICALL CallStaticByteMethodA(jclass clazz, jmethodID methodID, jvalue *args);
+
+ virtual jchar JNICALL CallStaticCharMethod(jclass clazz, jmethodID methodID, ...);
+ virtual jchar JNICALL CallStaticCharMethodV(jclass clazz, jmethodID methodID, va_list args);
+ virtual jchar JNICALL CallStaticCharMethodA(jclass clazz, jmethodID methodID, jvalue *args);
+
+ virtual jshort JNICALL CallStaticShortMethod(jclass clazz, jmethodID methodID, ...);
+ virtual jshort JNICALL CallStaticShortMethodV(jclass clazz, jmethodID methodID, va_list args);
+ virtual jshort JNICALL CallStaticShortMethodA(jclass clazz, jmethodID methodID, jvalue *args);
+
+ virtual jint JNICALL CallStaticIntMethod(jclass clazz, jmethodID methodID, ...);
+ virtual jint JNICALL CallStaticIntMethodV(jclass clazz, jmethodID methodID, va_list args);
+ virtual jint JNICALL CallStaticIntMethodA(jclass clazz, jmethodID methodID, jvalue *args);
+
+ virtual jlong JNICALL CallStaticLongMethod(jclass clazz, jmethodID methodID, ...);
+ virtual jlong JNICALL CallStaticLongMethodV(jclass clazz, jmethodID methodID, va_list args);
+ virtual jlong JNICALL CallStaticLongMethodA(jclass clazz, jmethodID methodID, jvalue *args);
+
+ virtual jfloat JNICALL CallStaticFloatMethod(jclass clazz, jmethodID methodID, ...);
+ virtual jfloat JNICALL CallStaticFloatMethodV(jclass clazz, jmethodID methodID, va_list args);
+ virtual jfloat JNICALL CallStaticFloatMethodA(jclass clazz, jmethodID methodID, jvalue *args);
+
+ virtual jdouble JNICALL CallStaticDoubleMethod(jclass clazz, jmethodID methodID, ...);
+ virtual jdouble JNICALL CallStaticDoubleMethodV(jclass clazz, jmethodID methodID, va_list args);
+ virtual jdouble JNICALL CallStaticDoubleMethodA(jclass clazz, jmethodID methodID, jvalue *args);
+
+ virtual void JNICALL CallStaticVoidMethod(jclass cls, jmethodID methodID, ...);
+ virtual void JNICALL CallStaticVoidMethodV(jclass cls, jmethodID methodID, va_list args);
+ virtual void JNICALL CallStaticVoidMethodA(jclass cls, jmethodID methodID, jvalue * args);
+
+ virtual jfieldID JNICALL GetStaticFieldID(jclass clazz, const char *name, const char *sig);
+ virtual jobject JNICALL GetStaticObjectField(jclass clazz, jfieldID fieldID);
+ virtual jboolean JNICALL GetStaticBooleanField(jclass clazz, jfieldID fieldID);
+ virtual jbyte JNICALL GetStaticByteField(jclass clazz, jfieldID fieldID);
+ virtual jchar JNICALL GetStaticCharField(jclass clazz, jfieldID fieldID);
+ virtual jshort JNICALL GetStaticShortField(jclass clazz, jfieldID fieldID);
+ virtual jint JNICALL GetStaticIntField(jclass clazz, jfieldID fieldID);
+ virtual jlong JNICALL GetStaticLongField(jclass clazz, jfieldID fieldID);
+ virtual jfloat JNICALL GetStaticFloatField(jclass clazz, jfieldID fieldID);
+ virtual jdouble JNICALL GetStaticDoubleField(jclass clazz, jfieldID fieldID);
+
+ virtual void JNICALL SetStaticObjectField(jclass clazz, jfieldID fieldID, jobject value);
+ virtual void JNICALL SetStaticBooleanField(jclass clazz, jfieldID fieldID, jboolean value);
+ virtual void JNICALL SetStaticByteField(jclass clazz, jfieldID fieldID, jbyte value);
+ virtual void JNICALL SetStaticCharField(jclass clazz, jfieldID fieldID, jchar value);
+ virtual void JNICALL SetStaticShortField(jclass clazz, jfieldID fieldID, jshort value);
+ virtual void JNICALL SetStaticIntField(jclass clazz, jfieldID fieldID, jint value);
+ virtual void JNICALL SetStaticLongField(jclass clazz, jfieldID fieldID, jlong value);
+ virtual void JNICALL SetStaticFloatField(jclass clazz, jfieldID fieldID, jfloat value);
+ virtual void JNICALL SetStaticDoubleField(jclass clazz, jfieldID fieldID, jdouble value);
+
+ virtual jstring JNICALL NewString(const jchar *unicode, jsize len);
+ virtual jsize JNICALL GetStringLength(jstring str);
+ virtual const jchar *JNICALL GetStringChars(jstring str, jboolean *isCopy);
+ virtual void JNICALL ReleaseStringChars(jstring str, const jchar *chars);
+
+ virtual jstring JNICALL NewStringUTF(const char *utf);
+ virtual jsize JNICALL GetStringUTFLength(jstring str);
+ virtual const char* JNICALL GetStringUTFChars(jstring str, jboolean *isCopy);
+ virtual void JNICALL ReleaseStringUTFChars(jstring str, const char* chars);
+
+ virtual jsize JNICALL GetArrayLength(jarray array);
+
+ virtual jobjectArray JNICALL NewObjectArray(jsize len, jclass clazz, jobject init);
+ virtual jobject JNICALL GetObjectArrayElement(jobjectArray array, jsize index);
+ virtual void JNICALL SetObjectArrayElement(jobjectArray array, jsize index, jobject val);
+
+ virtual jbooleanArray JNICALL NewBooleanArray(jsize len);
+ virtual jbyteArray JNICALL NewByteArray(jsize len);
+ virtual jcharArray JNICALL NewCharArray(jsize len);
+ virtual jshortArray JNICALL NewShortArray(jsize len);
+ virtual jintArray JNICALL NewIntArray(jsize len);
+ virtual jlongArray JNICALL NewLongArray(jsize len);
+ virtual jfloatArray JNICALL NewFloatArray(jsize len);
+ virtual jdoubleArray JNICALL NewDoubleArray(jsize len);
+
+ virtual jboolean * JNICALL GetBooleanArrayElements(jbooleanArray array, jboolean *isCopy);
+ virtual jbyte * JNICALL GetByteArrayElements(jbyteArray array, jboolean *isCopy);
+ virtual jchar * JNICALL GetCharArrayElements(jcharArray array, jboolean *isCopy);
+ virtual jshort * JNICALL GetShortArrayElements(jshortArray array, jboolean *isCopy);
+ virtual jint * JNICALL GetIntArrayElements(jintArray array, jboolean *isCopy);
+ virtual jlong * JNICALL GetLongArrayElements(jlongArray array, jboolean *isCopy);
+ virtual jfloat * JNICALL GetFloatArrayElements(jfloatArray array, jboolean *isCopy);
+ virtual jdouble * JNICALL GetDoubleArrayElements(jdoubleArray array, jboolean *isCopy);
+
+ virtual void JNICALL ReleaseBooleanArrayElements(jbooleanArray array, jboolean *elems, jint mode);
+ virtual void JNICALL ReleaseByteArrayElements(jbyteArray array, jbyte *elems, jint mode);
+ virtual void JNICALL ReleaseCharArrayElements(jcharArray array, jchar *elems, jint mode);
+ virtual void JNICALL ReleaseShortArrayElements(jshortArray array, jshort *elems, jint mode);
+ virtual void JNICALL ReleaseIntArrayElements(jintArray array, jint *elems, jint mode);
+ virtual void JNICALL ReleaseLongArrayElements(jlongArray array, jlong *elems, jint mode);
+ virtual void JNICALL ReleaseFloatArrayElements(jfloatArray array, jfloat *elems, jint mode);
+ virtual void JNICALL ReleaseDoubleArrayElements(jdoubleArray array, jdouble *elems, jint mode);
+
+ virtual void JNICALL GetBooleanArrayRegion(jbooleanArray array, jsize start, jsize l, jboolean *buf);
+ virtual void JNICALL GetByteArrayRegion(jbyteArray array, jsize start, jsize len, jbyte *buf);
+ virtual void JNICALL GetCharArrayRegion(jcharArray array, jsize start, jsize len, jchar *buf);
+ virtual void JNICALL GetShortArrayRegion(jshortArray array, jsize start, jsize len, jshort *buf);
+ virtual void JNICALL GetIntArrayRegion(jintArray array, jsize start, jsize len, jint *buf);
+ virtual void JNICALL GetLongArrayRegion(jlongArray array, jsize start, jsize len, jlong *buf);
+ virtual void JNICALL GetFloatArrayRegion(jfloatArray array, jsize start, jsize len, jfloat *buf);
+ virtual void JNICALL GetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len, jdouble *buf);
+
+ virtual void JNICALL SetBooleanArrayRegion(jbooleanArray array, jsize start, jsize l, jboolean *buf);
+ virtual void JNICALL SetByteArrayRegion(jbyteArray array, jsize start, jsize len, jbyte *buf);
+ virtual void JNICALL SetCharArrayRegion(jcharArray array, jsize start, jsize len, jchar *buf);
+ virtual void JNICALL SetShortArrayRegion(jshortArray array, jsize start, jsize len, jshort *buf);
+ virtual void JNICALL SetIntArrayRegion(jintArray array, jsize start, jsize len, jint *buf);
+ virtual void JNICALL SetLongArrayRegion(jlongArray array, jsize start, jsize len, jlong *buf);
+ virtual void JNICALL SetFloatArrayRegion(jfloatArray array, jsize start, jsize len, jfloat *buf);
+ virtual void JNICALL SetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len, jdouble *buf);
+
+ virtual jint JNICALL RegisterNatives(jclass clazz, const JNINativeMethod *methods, jint nMethods);
+ virtual jint JNICALL UnregisterNatives(jclass clazz);
+
+ virtual jint JNICALL MonitorEnter(jobject obj);
+ virtual jint JNICALL MonitorExit(jobject obj);
+
+ virtual jint JNICALL GetJavaVM(JavaVM **vm);
+};
+
+class JavaVM
+{
+public:
+ virtual void JNICALL reserved0();
+ virtual void JNICALL reserved1();
+ virtual void JNICALL reserved2();
+ virtual jint JNICALL DestroyJavaVM();
+ virtual jint JNICALL AttachCurrentThread(void **penv, void *args);
+ virtual jint JNICALL DetachCurrentThread();
+ virtual jint JNICALL GetEnv(void **penv, jint version);
+ virtual jint JNICALL AttachCurrentThreadAsDaemon(void **penv, void *args);
+};
diff --git a/IK.VM.NET/AssemblyInfo.cs b/IK.VM.NET/AssemblyInfo.cs
new file mode 100644
index 00000000..1853cb9f
--- /dev/null
+++ b/IK.VM.NET/AssemblyInfo.cs
@@ -0,0 +1,81 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+//
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//
+[assembly: AssemblyTitle("IK.VM.NET")]
+[assembly: AssemblyDescription("JVM for .NET")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("Copyright (C) 2002 Jeroen Frijters")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+//
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+
+[assembly: AssemblyVersion("1.0.*")]
+
+//
+// In order to sign your assembly you must specify a key to use. Refer to the
+// Microsoft .NET Framework documentation for more information on assembly signing.
+//
+// Use the attributes below to control which key is used for signing.
+//
+// Notes:
+// (*) If no key is specified, the assembly is not signed.
+// (*) KeyName refers to a key that has been installed in the Crypto Service
+// Provider (CSP) on your machine. KeyFile refers to a file which contains
+// a key.
+// (*) If the KeyFile and the KeyName values are both specified, the
+// following processing occurs:
+// (1) If the KeyName can be found in the CSP, that key is used.
+// (2) If the KeyName does not exist and the KeyFile does exist, the key
+// in the KeyFile is installed into the CSP and used.
+// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
+// When specifying the KeyFile, the location of the KeyFile should be
+// relative to the project output directory which is
+// %Project Directory%\obj\<configuration>. For example, if your KeyFile is
+// located in the project directory, you would specify the AssemblyKeyFile
+// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
+// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
+// documentation for more information on this.
+//
+[assembly: AssemblyDelaySign(false)]
+[assembly: AssemblyKeyFile("")]
+[assembly: AssemblyKeyName("")]
diff --git a/IK.VM.NET/BigEndianBinaryReader.cs b/IK.VM.NET/BigEndianBinaryReader.cs
new file mode 100644
index 00000000..105b4c95
--- /dev/null
+++ b/IK.VM.NET/BigEndianBinaryReader.cs
@@ -0,0 +1,177 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+using System.IO;
+
+sealed class BigEndianBinaryReader
+{
+ private byte[] buf;
+ private int pos;
+
+ internal BigEndianBinaryReader(byte[] buf)
+ : this(buf, 0)
+ {
+ }
+
+ internal BigEndianBinaryReader(byte[] buf, int offset)
+ {
+ this.buf = buf;
+ this.pos = offset;
+ }
+
+ internal BigEndianBinaryReader Duplicate()
+ {
+ return new BigEndianBinaryReader(buf, pos);
+ }
+
+ internal int Position
+ {
+ get
+ {
+ return pos;
+ }
+ }
+
+ internal void Skip(int count)
+ {
+ pos += count;
+ }
+
+ internal byte ReadByte()
+ {
+ return buf[pos++];
+ }
+
+ internal sbyte ReadSByte()
+ {
+ return (sbyte)buf[pos++];
+ }
+
+ internal double ReadDouble()
+ {
+ return BitConverter.Int64BitsToDouble(ReadInt64());
+ }
+
+ internal short ReadInt16()
+ {
+ short s = (short)((buf[pos] << 8) + buf[pos + 1]);
+ pos += 2;
+ return s;
+ }
+
+ internal int ReadInt32()
+ {
+ int i = (int)((buf[pos] << 24) + (buf[pos + 1] << 16) + (buf[pos + 2] << 8) + buf[pos + 3]);
+ pos += 4;
+ return i;
+ }
+
+ internal long ReadInt64()
+ {
+ uint i1 = (uint)((buf[pos] << 24) + (buf[pos + 1] << 16) + (buf[pos + 2] << 8) + buf[pos + 3]);
+ uint i2 = (uint)((buf[pos + 4] << 24) + (buf[pos + 5] << 16) + (buf[pos + 6] << 8) + buf[pos + 7]);
+ long l = (((long)i1) << 32) + i2;
+ pos += 8;
+ return l;
+ }
+
+ internal float ReadSingle()
+ {
+ return BitConverter.ToSingle(BitConverter.GetBytes(ReadInt32()), 0);
+ }
+
+ internal string ReadString()
+ {
+ int len = ReadUInt16();
+ // special code path for ASCII strings (which occur *very* frequently)
+ for(int j = 0; j < len; j++)
+ {
+ if(buf[pos + j] >= 128)
+ {
+ // NOTE we *cannot* use System.Text.UTF8Encoding, because this is *not* compatible
+ // (esp. for embedded nulls)
+ char[] ch = new char[len];
+ int l = 0;
+ for(int i = 0; i < len; i++)
+ {
+ int c = buf[pos + i];
+ int char2, char3;
+ switch (c >> 4)
+ {
+ case 0:
+ if(c == 0)
+ {
+ throw new FormatException();
+ }
+ break;
+ case 1: case 2: case 3: case 4: case 5: case 6: case 7:
+ // 0xxxxxxx
+ break;
+ case 12: case 13:
+ // 110x xxxx 10xx xxxx
+ char2 = buf[pos + ++i];
+ if((char2 & 0xc0) != 0x80)
+ {
+ throw new FormatException();
+ }
+ c = (((c & 0x1F) << 6) | (char2 & 0x3F));
+ break;
+ case 14:
+ // 1110 xxxx 10xx xxxx 10xx xxxx
+ char2 = buf[pos + ++i];
+ char3 = buf[pos + ++i];
+ if((char2 & 0xc0) != 0x80 || (char3 & 0xc0) != 0x80)
+ {
+ throw new FormatException();
+ }
+ c = (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0));
+ break;
+ default:
+ throw new FormatException();
+ }
+ ch[l++] = (char)c;
+ }
+ pos += len;
+ return new String(ch, 0, l);
+ }
+ }
+ string s = System.Text.ASCIIEncoding.ASCII.GetString(buf, pos, len);
+ pos += len;
+ return s;
+ }
+
+ internal ushort ReadUInt16()
+ {
+ ushort s = (ushort)((buf[pos] << 8) + buf[pos + 1]);
+ pos += 2;
+ return s;
+ }
+
+ internal uint ReadUInt32()
+ {
+ uint i = (uint)((buf[pos] << 24) + (buf[pos + 1] << 16) + (buf[pos + 2] << 8) + buf[pos + 3]);
+ pos += 4;
+ return i;
+ }
+}
diff --git a/IK.VM.NET/ByteCode.cs b/IK.VM.NET/ByteCode.cs
new file mode 100644
index 00000000..d8836158
--- /dev/null
+++ b/IK.VM.NET/ByteCode.cs
@@ -0,0 +1,676 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+
+enum ByteCode
+{
+ __nop = 0,
+ __aconst_null = 1,
+ __iconst_m1 = 2,
+ __iconst_0 = 3,
+ __iconst_1 = 4,
+ __iconst_2 = 5,
+ __iconst_3 = 6,
+ __iconst_4 = 7,
+ __iconst_5 = 8,
+ __lconst_0 = 9,
+ __lconst_1 = 10,
+ __fconst_0 = 11,
+ __fconst_1 = 12,
+ __fconst_2 = 13,
+ __dconst_0 = 14,
+ __dconst_1 = 15,
+ __bipush = 16,
+ __sipush = 17,
+ __ldc = 18,
+ __ldc_w = 19,
+ __ldc2_w = 20,
+ __iload = 21,
+ __lload = 22,
+ __fload = 23,
+ __dload = 24,
+ __aload = 25,
+ __iload_0 = 26,
+ __iload_1 = 27,
+ __iload_2 = 28,
+ __iload_3 = 29,
+ __lload_0 = 30,
+ __lload_1 = 31,
+ __lload_2 = 32,
+ __lload_3 = 33,
+ __fload_0 = 34,
+ __fload_1 = 35,
+ __fload_2 = 36,
+ __fload_3 = 37,
+ __dload_0 = 38,
+ __dload_1 = 39,
+ __dload_2 = 40,
+ __dload_3 = 41,
+ __aload_0 = 42,
+ __aload_1 = 43,
+ __aload_2 = 44,
+ __aload_3 = 45,
+ __iaload = 46,
+ __laload = 47,
+ __faload = 48,
+ __daload = 49,
+ __aaload = 50,
+ __baload = 51,
+ __caload = 52,
+ __saload = 53,
+ __istore = 54,
+ __lstore = 55,
+ __fstore = 56,
+ __dstore = 57,
+ __astore = 58,
+ __istore_0 = 59,
+ __istore_1 = 60,
+ __istore_2 = 61,
+ __istore_3 = 62,
+ __lstore_0 = 63,
+ __lstore_1 = 64,
+ __lstore_2 = 65,
+ __lstore_3 = 66,
+ __fstore_0 = 67,
+ __fstore_1 = 68,
+ __fstore_2 = 69,
+ __fstore_3 = 70,
+ __dstore_0 = 71,
+ __dstore_1 = 72,
+ __dstore_2 = 73,
+ __dstore_3 = 74,
+ __astore_0 = 75,
+ __astore_1 = 76,
+ __astore_2 = 77,
+ __astore_3 = 78,
+ __iastore = 79,
+ __lastore = 80,
+ __fastore = 81,
+ __dastore = 82,
+ __aastore = 83,
+ __bastore = 84,
+ __castore = 85,
+ __sastore = 86,
+ __pop = 87,
+ __pop2 = 88,
+ __dup = 89,
+ __dup_x1 = 90,
+ __dup_x2 = 91,
+ __dup2 = 92,
+ __dup2_x1 = 93,
+ __dup2_x2 = 94,
+ __swap = 95,
+ __iadd = 96,
+ __ladd = 97,
+ __fadd = 98,
+ __dadd = 99,
+ __isub = 100,
+ __lsub = 101,
+ __fsub = 102,
+ __dsub = 103,
+ __imul = 104,
+ __lmul = 105,
+ __fmul = 106,
+ __dmul = 107,
+ __idiv = 108,
+ __ldiv = 109,
+ __fdiv = 110,
+ __ddiv = 111,
+ __irem = 112,
+ __lrem = 113,
+ __frem = 114,
+ __drem = 115,
+ __ineg = 116,
+ __lneg = 117,
+ __fneg = 118,
+ __dneg = 119,
+ __ishl = 120,
+ __lshl = 121,
+ __ishr = 122,
+ __lshr = 123,
+ __iushr = 124,
+ __lushr = 125,
+ __iand = 126,
+ __land = 127,
+ __ior = 128,
+ __lor = 129,
+ __ixor = 130,
+ __lxor = 131,
+ __iinc = 132,
+ __i2l = 133,
+ __i2f = 134,
+ __i2d = 135,
+ __l2i = 136,
+ __l2f = 137,
+ __l2d = 138,
+ __f2i = 139,
+ __f2l = 140,
+ __f2d = 141,
+ __d2i = 142,
+ __d2l = 143,
+ __d2f = 144,
+ __i2b = 145,
+ __i2c = 146,
+ __i2s = 147,
+ __lcmp = 148,
+ __fcmpl = 149,
+ __fcmpg = 150,
+ __dcmpl = 151,
+ __dcmpg = 152,
+ __ifeq = 153,
+ __ifne = 154,
+ __iflt = 155,
+ __ifge = 156,
+ __ifgt = 157,
+ __ifle = 158,
+ __if_icmpeq = 159,
+ __if_icmpne = 160,
+ __if_icmplt = 161,
+ __if_icmpge = 162,
+ __if_icmpgt = 163,
+ __if_icmple = 164,
+ __if_acmpeq = 165,
+ __if_acmpne = 166,
+ __goto = 167,
+ __jsr = 168,
+ __ret = 169,
+ __tableswitch = 170,
+ __lookupswitch = 171,
+ __ireturn = 172,
+ __lreturn = 173,
+ __freturn = 174,
+ __dreturn = 175,
+ __areturn = 176,
+ __return = 177,
+ __getstatic = 178,
+ __putstatic = 179,
+ __getfield = 180,
+ __putfield = 181,
+ __invokevirtual = 182,
+ __invokespecial = 183,
+ __invokestatic = 184,
+ __invokeinterface = 185,
+ __xxxunusedxxx = 186,
+ __new = 187,
+ __newarray = 188,
+ __anewarray = 189,
+ __arraylength = 190,
+ __athrow = 191,
+ __checkcast = 192,
+ __instanceof = 193,
+ __monitorenter = 194,
+ __monitorexit = 195,
+ __wide = 196,
+ __multianewarray = 197,
+ __ifnull = 198,
+ __ifnonnull = 199,
+ __goto_w = 200,
+ __jsr_w = 201
+}
+
+enum NormalizedByteCode
+{
+ __nop = 0,
+ __aconst_null = 1,
+ __iconst = -1,
+ __lconst_0 = 9,
+ __lconst_1 = 10,
+ __fconst_0 = 11,
+ __fconst_1 = 12,
+ __fconst_2 = 13,
+ __dconst_0 = 14,
+ __dconst_1 = 15,
+ __ldc = 18,
+ __iload = 21,
+ __lload = 22,
+ __fload = 23,
+ __dload = 24,
+ __aload = 25,
+ __iaload = 46,
+ __laload = 47,
+ __faload = 48,
+ __daload = 49,
+ __aaload = 50,
+ __baload = 51,
+ __caload = 52,
+ __saload = 53,
+ __istore = 54,
+ __lstore = 55,
+ __fstore = 56,
+ __dstore = 57,
+ __astore = 58,
+ __iastore = 79,
+ __lastore = 80,
+ __fastore = 81,
+ __dastore = 82,
+ __aastore = 83,
+ __bastore = 84,
+ __castore = 85,
+ __sastore = 86,
+ __pop = 87,
+ __pop2 = 88,
+ __dup = 89,
+ __dup_x1 = 90,
+ __dup_x2 = 91,
+ __dup2 = 92,
+ __dup2_x1 = 93,
+ __dup2_x2 = 94,
+ __swap = 95,
+ __iadd = 96,
+ __ladd = 97,
+ __fadd = 98,
+ __dadd = 99,
+ __isub = 100,
+ __lsub = 101,
+ __fsub = 102,
+ __dsub = 103,
+ __imul = 104,
+ __lmul = 105,
+ __fmul = 106,
+ __dmul = 107,
+ __idiv = 108,
+ __ldiv = 109,
+ __fdiv = 110,
+ __ddiv = 111,
+ __irem = 112,
+ __lrem = 113,
+ __frem = 114,
+ __drem = 115,
+ __ineg = 116,
+ __lneg = 117,
+ __fneg = 118,
+ __dneg = 119,
+ __ishl = 120,
+ __lshl = 121,
+ __ishr = 122,
+ __lshr = 123,
+ __iushr = 124,
+ __lushr = 125,
+ __iand = 126,
+ __land = 127,
+ __ior = 128,
+ __lor = 129,
+ __ixor = 130,
+ __lxor = 131,
+ __iinc = 132,
+ __i2l = 133,
+ __i2f = 134,
+ __i2d = 135,
+ __l2i = 136,
+ __l2f = 137,
+ __l2d = 138,
+ __f2i = 139,
+ __f2l = 140,
+ __f2d = 141,
+ __d2i = 142,
+ __d2l = 143,
+ __d2f = 144,
+ __i2b = 145,
+ __i2c = 146,
+ __i2s = 147,
+ __lcmp = 148,
+ __fcmpl = 149,
+ __fcmpg = 150,
+ __dcmpl = 151,
+ __dcmpg = 152,
+ __ifeq = 153,
+ __ifne = 154,
+ __iflt = 155,
+ __ifge = 156,
+ __ifgt = 157,
+ __ifle = 158,
+ __if_icmpeq = 159,
+ __if_icmpne = 160,
+ __if_icmplt = 161,
+ __if_icmpge = 162,
+ __if_icmpgt = 163,
+ __if_icmple = 164,
+ __if_acmpeq = 165,
+ __if_acmpne = 166,
+ __goto = 167,
+ __jsr = 168,
+ __ret = 169,
+ __lookupswitch = 171,
+ __ireturn = 172,
+ __lreturn = 173,
+ __freturn = 174,
+ __dreturn = 175,
+ __areturn = 176,
+ __return = 177,
+ __getstatic = 178,
+ __putstatic = 179,
+ __getfield = 180,
+ __putfield = 181,
+ __invokevirtual = 182,
+ __invokespecial = 183,
+ __invokestatic = 184,
+ __invokeinterface = 185,
+ __new = 187,
+ __newarray = 188,
+ __anewarray = 189,
+ __arraylength = 190,
+ __athrow = 191,
+ __checkcast = 192,
+ __instanceof = 193,
+ __monitorenter = 194,
+ __monitorexit = 195,
+ __multianewarray = 197,
+ __ifnull = 198,
+ __ifnonnull = 199,
+}
+
+enum ByteCodeMode
+{
+ Unused,
+ Simple,
+ Constant_1,
+ Constant_2,
+ Branch_2,
+ Local_1,
+ Local_2,
+ Constant_2_1_1,
+ Immediate_1,
+ Immediate_2,
+ Local_1_Immediate_1,
+ Local_2_Immediate_2,
+ Tableswitch,
+ Lookupswitch,
+ Constant_2_Immediate_1,
+ Branch_4
+}
+
+struct ByteCodeMetaData
+{
+ private static ByteCodeMetaData[] data = new ByteCodeMetaData[202];
+ private ByteCodeMode reg;
+ private ByteCodeMode wide;
+ private NormalizedByteCode normbc;
+ private int arg;
+ private bool hasFixedArg;
+
+ private ByteCodeMetaData(ByteCode bc, ByteCodeMode reg, ByteCodeMode wide)
+ {
+ this.reg = reg;
+ this.wide = wide;
+ this.normbc = (NormalizedByteCode)Enum.Parse(typeof(NormalizedByteCode), bc.ToString());
+ this.arg = 0;
+ this.hasFixedArg = false;
+ data[(int)bc] = this;
+ }
+
+ private ByteCodeMetaData(ByteCode bc, NormalizedByteCode normbc, ByteCodeMode reg, ByteCodeMode wide)
+ {
+ this.reg = reg;
+ this.wide = wide;
+ this.normbc = normbc;
+ this.arg = 0;
+ this.hasFixedArg = false;
+ data[(int)bc] = this;
+ }
+
+ private ByteCodeMetaData(ByteCode bc, NormalizedByteCode normbc, int arg, ByteCodeMode reg, ByteCodeMode wide)
+ {
+ this.reg = reg;
+ this.wide = wide;
+ this.normbc = normbc;
+ this.arg = arg;
+ this.hasFixedArg = true;
+ data[(int)bc] = this;
+ }
+
+ internal static NormalizedByteCode GetNormalizedByteCode(ByteCode bc)
+ {
+ return data[(int)bc].normbc;
+ }
+
+ internal static int GetArg(ByteCode bc, int arg)
+ {
+ if(data[(int)bc].hasFixedArg)
+ {
+ return data[(int)bc].arg;
+ }
+ return arg;
+ }
+
+ internal static ByteCodeMode GetMode(ByteCode bc)
+ {
+ return data[(int)bc].reg;
+ }
+
+ internal static ByteCodeMode GetWideMode(ByteCode bc)
+ {
+ ByteCodeMode m = data[(int)bc].wide;
+ if(m == ByteCodeMode.Unused)
+ {
+ throw new ArgumentException("Wide version of " + bc + " is not a valid instruction", "bc");
+ }
+ return m;
+ }
+
+ static ByteCodeMetaData()
+ {
+ new ByteCodeMetaData(ByteCode.__nop, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__aconst_null, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__iconst_m1, NormalizedByteCode.__iconst, -1, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__iconst_0, NormalizedByteCode.__iconst, 0, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__iconst_1, NormalizedByteCode.__iconst, 1, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__iconst_2, NormalizedByteCode.__iconst, 2, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__iconst_3, NormalizedByteCode.__iconst, 3, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__iconst_4, NormalizedByteCode.__iconst, 4, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__iconst_5, NormalizedByteCode.__iconst, 5, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__lconst_0, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__lconst_1, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__fconst_0, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__fconst_1, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__fconst_2, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__dconst_0, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__dconst_1, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__bipush, NormalizedByteCode.__iconst, ByteCodeMode.Immediate_1, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__sipush, NormalizedByteCode.__iconst, ByteCodeMode.Immediate_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__ldc, ByteCodeMode.Constant_1, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__ldc_w, NormalizedByteCode.__ldc, ByteCodeMode.Constant_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__ldc2_w, NormalizedByteCode.__ldc, ByteCodeMode.Constant_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__iload, ByteCodeMode.Local_1, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__lload, ByteCodeMode.Local_1, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__fload, ByteCodeMode.Local_1, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__dload, ByteCodeMode.Local_1, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__aload, ByteCodeMode.Local_1, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__iload_0, NormalizedByteCode.__iload, 0, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__iload_1, NormalizedByteCode.__iload, 1, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__iload_2, NormalizedByteCode.__iload, 2, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__iload_3, NormalizedByteCode.__iload, 3, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__lload_0, NormalizedByteCode.__lload, 0, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__lload_1, NormalizedByteCode.__lload, 1, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__lload_2, NormalizedByteCode.__lload, 2, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__lload_3, NormalizedByteCode.__lload, 3, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__fload_0, NormalizedByteCode.__fload, 0, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__fload_1, NormalizedByteCode.__fload, 1, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__fload_2, NormalizedByteCode.__fload, 2, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__fload_3, NormalizedByteCode.__fload, 3, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__dload_0, NormalizedByteCode.__dload, 0, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__dload_1, NormalizedByteCode.__dload, 1, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__dload_2, NormalizedByteCode.__dload, 2, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__dload_3, NormalizedByteCode.__dload, 3, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__aload_0, NormalizedByteCode.__aload, 0, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__aload_1, NormalizedByteCode.__aload, 1, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__aload_2, NormalizedByteCode.__aload, 2, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__aload_3, NormalizedByteCode.__aload, 3, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__iaload, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__laload, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__faload, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__daload, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__aaload, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__baload, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__caload, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__saload, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__istore, ByteCodeMode.Local_1, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__lstore, ByteCodeMode.Local_1, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__fstore, ByteCodeMode.Local_1, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__dstore, ByteCodeMode.Local_1, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__astore, ByteCodeMode.Local_1, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__istore_0, NormalizedByteCode.__istore, 0, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__istore_1, NormalizedByteCode.__istore, 1, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__istore_2, NormalizedByteCode.__istore, 2, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__istore_3, NormalizedByteCode.__istore, 3, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__lstore_0, NormalizedByteCode.__lstore, 0, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__lstore_1, NormalizedByteCode.__lstore, 1, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__lstore_2, NormalizedByteCode.__lstore, 2, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__lstore_3, NormalizedByteCode.__lstore, 3, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__fstore_0, NormalizedByteCode.__fstore, 0, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__fstore_1, NormalizedByteCode.__fstore, 1, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__fstore_2, NormalizedByteCode.__fstore, 2, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__fstore_3, NormalizedByteCode.__fstore, 3, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__dstore_0, NormalizedByteCode.__dstore, 0, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__dstore_1, NormalizedByteCode.__dstore, 1, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__dstore_2, NormalizedByteCode.__dstore, 2, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__dstore_3, NormalizedByteCode.__dstore, 3, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__astore_0, NormalizedByteCode.__astore, 0, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__astore_1, NormalizedByteCode.__astore, 1, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__astore_2, NormalizedByteCode.__astore, 2, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__astore_3, NormalizedByteCode.__astore, 3, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__iastore, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__lastore, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__fastore, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__dastore, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__aastore, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__bastore, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__castore, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__sastore, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__pop, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__pop2, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__dup, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__dup_x1, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__dup_x2, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__dup2, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__dup2_x1, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__dup2_x2, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__swap, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__iadd, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__ladd, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__fadd, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__dadd, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__isub, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__lsub, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__fsub, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__dsub, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__imul, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__lmul, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__fmul, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__dmul, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__idiv, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__ldiv, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__fdiv, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__ddiv, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__irem, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__lrem, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__frem, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__drem, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__ineg, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__lneg, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__fneg, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__dneg, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__ishl, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__lshl, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__ishr, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__lshr, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__iushr, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__lushr, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__iand, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__land, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__ior, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__lor, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__ixor, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__lxor, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__iinc, ByteCodeMode.Local_1_Immediate_1, ByteCodeMode.Local_2_Immediate_2);
+ new ByteCodeMetaData(ByteCode.__i2l, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__i2f, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__i2d, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__l2i, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__l2f, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__l2d, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__f2i, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__f2l, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__f2d, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__d2i, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__d2l, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__d2f, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__i2b, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__i2c, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__i2s, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__lcmp, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__fcmpl, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__fcmpg, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__dcmpl, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__dcmpg, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__ifeq, ByteCodeMode.Branch_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__ifne, ByteCodeMode.Branch_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__iflt, ByteCodeMode.Branch_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__ifge, ByteCodeMode.Branch_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__ifgt, ByteCodeMode.Branch_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__ifle, ByteCodeMode.Branch_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__if_icmpeq, ByteCodeMode.Branch_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__if_icmpne, ByteCodeMode.Branch_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__if_icmplt, ByteCodeMode.Branch_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__if_icmpge, ByteCodeMode.Branch_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__if_icmpgt, ByteCodeMode.Branch_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__if_icmple, ByteCodeMode.Branch_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__if_acmpeq, ByteCodeMode.Branch_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__if_acmpne, ByteCodeMode.Branch_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__goto, ByteCodeMode.Branch_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__jsr, ByteCodeMode.Branch_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__ret, ByteCodeMode.Local_1, ByteCodeMode.Local_2);
+ new ByteCodeMetaData(ByteCode.__tableswitch, NormalizedByteCode.__lookupswitch, ByteCodeMode.Tableswitch, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__lookupswitch, ByteCodeMode.Lookupswitch, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__ireturn, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__lreturn, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__freturn, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__dreturn, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__areturn, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__return, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__getstatic, ByteCodeMode.Constant_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__putstatic, ByteCodeMode.Constant_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__getfield, ByteCodeMode.Constant_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__putfield, ByteCodeMode.Constant_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__invokevirtual, ByteCodeMode.Constant_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__invokespecial, ByteCodeMode.Constant_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__invokestatic, ByteCodeMode.Constant_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__invokeinterface, ByteCodeMode.Constant_2_1_1, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__xxxunusedxxx, NormalizedByteCode.__nop, ByteCodeMode.Unused, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__new, ByteCodeMode.Constant_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__newarray, ByteCodeMode.Immediate_1, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__anewarray, ByteCodeMode.Constant_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__arraylength, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__athrow, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__checkcast, ByteCodeMode.Constant_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__instanceof, ByteCodeMode.Constant_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__monitorenter, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__monitorexit, ByteCodeMode.Simple, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__wide, NormalizedByteCode.__nop, ByteCodeMode.Unused, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__multianewarray, ByteCodeMode.Constant_2_Immediate_1, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__ifnull, ByteCodeMode.Branch_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__ifnonnull, ByteCodeMode.Branch_2, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__goto_w, NormalizedByteCode.__goto, ByteCodeMode.Branch_4, ByteCodeMode.Unused);
+ new ByteCodeMetaData(ByteCode.__jsr_w, NormalizedByteCode.__jsr, ByteCodeMode.Branch_4, ByteCodeMode.Unused);
+ }
+}
diff --git a/IK.VM.NET/ByteCodeHelper.cs b/IK.VM.NET/ByteCodeHelper.cs
new file mode 100644
index 00000000..01477844
--- /dev/null
+++ b/IK.VM.NET/ByteCodeHelper.cs
@@ -0,0 +1,72 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+
+public class ByteCodeHelper
+{
+ public static object multianewarray(RuntimeTypeHandle typeHandle, int[] lengths)
+ {
+ for(int i = 0; i < lengths.Length; i++)
+ {
+ if(lengths[i] < 0)
+ {
+ throw JavaException.NegativeArraySizeException();
+ }
+ }
+ return MultianewarrayHelper(Type.GetTypeFromHandle(typeHandle).GetElementType(), lengths, 0);
+ }
+
+ private static object MultianewarrayHelper(Type elemType, int[] lengths, int index)
+ {
+ object o = Array.CreateInstance(elemType, lengths[index++]);
+ if(index < lengths.Length)
+ {
+ elemType = elemType.GetElementType();
+ object[] a = (object[])o;
+ for(int i = 0; i < a.Length; i++)
+ {
+ a[i] = MultianewarrayHelper(elemType, lengths, index);
+ }
+ }
+ return o;
+ }
+
+ public static void monitorenter(object o)
+ {
+ if(o == null)
+ {
+ throw new NullReferenceException();
+ }
+ System.Threading.Monitor.Enter(o);
+ }
+
+ public static void monitorexit(object o)
+ {
+ if(o == null)
+ {
+ throw new NullReferenceException();
+ }
+ System.Threading.Monitor.Exit(o);
+ }
+}
diff --git a/IK.VM.NET/ClassFile.cs b/IK.VM.NET/ClassFile.cs
new file mode 100644
index 00000000..c823feb8
--- /dev/null
+++ b/IK.VM.NET/ClassFile.cs
@@ -0,0 +1,1579 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+using System.IO;
+using System.Collections;
+
+[Flags]
+public enum Modifiers : short
+{
+ Public = 0x0001,
+ Private = 0x0002,
+ Protected = 0x0004,
+ Static = 0x0008,
+ Final = 0x0010,
+ Super = 0x0020,
+ Synchronized = 0x0020,
+ Volatile = 0x0040,
+ Transient = 0x0080,
+ Native = 0x0100,
+ Interface = 0x0200,
+ Abstract = 0x0400,
+ Strictfp = 0x0800,
+ Synthetic = -1 // we use this to record the fact that we created the method/field/property
+ // so the member should not be visible through reflection
+}
+
+class ClassFile
+{
+ private ConstantPoolItem[] constantpool;
+ private Modifiers access_flags;
+ private string name;
+ private string supername;
+ private string[] interfaces;
+ private Field[] fields;
+ private Method[] methods;
+ private Attribute[] attributes;
+ private string sourceFile;
+ private bool sourceFileCached;
+ private static readonly char[] illegalcharacters = { '<', '>' };
+
+ internal ClassFile(byte[] buf, int offset, int length, string inputClassName)
+ {
+ try
+ {
+ BigEndianBinaryReader br = new BigEndianBinaryReader(buf, offset);
+ if(br.ReadUInt32() != 0xCAFEBABE)
+ {
+ throw JavaException.ClassFormatError("Bad magic number");
+ }
+ int minor = br.ReadUInt16();
+ int major = br.ReadUInt16();
+ if(major < 45 || major > 48)
+ {
+ throw JavaException.UnsupportedClassVersionError(major + "." + minor);
+ }
+ int constantpoolcount = br.ReadUInt16();
+ constantpool = new ConstantPoolItem[constantpoolcount];
+ for(int i = 1; i < constantpoolcount; i++)
+ {
+ constantpool[i] = ConstantPoolItem.Read(inputClassName, br);
+ // LONG and DOUBLE items take up two slots...
+ if(constantpool[i].IsWide)
+ {
+ i++;
+ }
+ }
+ for(int i = 1; i < constantpoolcount; i++)
+ {
+ if(constantpool[i] != null)
+ {
+ try
+ {
+ constantpool[i].Resolve(this);
+ }
+ catch(IndexOutOfRangeException)
+ {
+ throw JavaException.ClassFormatError("{0} (Invalid constant pool item #{1})", inputClassName, i);
+ }
+ catch(InvalidCastException)
+ {
+ throw JavaException.ClassFormatError("{0} (Invalid constant pool item #{1})", inputClassName, i);
+ }
+ }
+ }
+ access_flags = (Modifiers)br.ReadUInt16();
+ // NOTE although the vmspec says (in 4.1) that interfaces must be marked abstract, earlier versions of
+ // javac (JDK 1.1) didn't do this, so the VM doesn't enforce this rule
+ // NOTE although the vmspec implies (in 4.1) that ACC_SUPER is illegal on interfaces, it doesn't enforce this
+ if((IsInterface && IsFinal) || (IsAbstract && IsFinal))
+ {
+ throw JavaException.ClassFormatError("{0} (Illegal class modifiers 0x{1:X})", inputClassName, access_flags);
+ }
+ int this_class = br.ReadUInt16();
+ try
+ {
+ name = ((ConstantPoolItemClass)constantpool[this_class]).Name;
+ }
+ catch(Exception)
+ {
+ throw JavaException.ClassFormatError("{0} (Class name has bad constant pool index)", inputClassName);
+ }
+ int super_class = br.ReadUInt16();
+ // NOTE for convenience we allow parsing java/lang/Object (which has no super class), so
+ // we check for super_class != 0
+ if(super_class != 0)
+ {
+ try
+ {
+ supername = ((ConstantPoolItemClass)constantpool[super_class]).Name;
+ }
+ catch(Exception)
+ {
+ throw JavaException.ClassFormatError("{0} (Bad superclass constant pool index)", inputClassName);
+ }
+ }
+ else
+ {
+ if(this.Name != "java/lang/Object")
+ {
+ throw JavaException.ClassFormatError("{0} (Bad superclass index)", Name);
+ }
+ }
+ if(IsInterface && (super_class == 0 || supername != "java/lang/Object"))
+ {
+ throw JavaException.ClassFormatError("{0} (Interfaces must have java.lang.Object as superclass)", Name);
+ }
+ int interfaces_count = br.ReadUInt16();
+ interfaces = new string[interfaces_count];
+ Hashtable interfaceNames = new Hashtable();
+ for(int i = 0; i < interfaces_count; i++)
+ {
+ int index = br.ReadUInt16();
+ if(index == 0 || index >= constantpool.Length)
+ {
+ throw JavaException.ClassFormatError("{0} (Illegal constant pool index)", Name);
+ }
+ ConstantPoolItemClass cpi = constantpool[index] as ConstantPoolItemClass;
+ if(cpi == null)
+ {
+ throw JavaException.ClassFormatError("{0} (Interface name has bad constant type)", Name);
+ }
+ interfaces[i] = ((ConstantPoolItemClass)GetConstantPoolItem(index)).Name;
+ if(interfaceNames.ContainsKey(interfaces[i]))
+ {
+ throw JavaException.ClassFormatError("{0} (Repetitive interface name)", Name);
+ }
+ interfaceNames.Add(interfaces[i], interfaces[i]);
+ }
+ int fields_count = br.ReadUInt16();
+ fields = new Field[fields_count];
+ Hashtable fieldNameSigs = new Hashtable();
+ for(int i = 0; i < fields_count; i++)
+ {
+ fields[i] = new Field(this, br);
+ string name = fields[i].Name;
+ // NOTE It's not in the vmspec (as far as I can tell), but Sun's VM doens't allow names that
+ // contain '<' or '>'
+ if(name.Length == 0 || name.IndexOfAny(illegalcharacters) != -1)
+ {
+ throw JavaException.ClassFormatError("{0} (Illegal field name \"{1}\")", Name, name);
+ }
+ string nameSig = name + fields[i].Signature;
+ if(fieldNameSigs.ContainsKey(nameSig))
+ {
+ throw JavaException.ClassFormatError("{0} (Repetitive field name/signature)", Name);
+ }
+ fieldNameSigs.Add(nameSig, nameSig);
+ }
+ int methods_count = br.ReadUInt16();
+ methods = new Method[methods_count];
+ Hashtable methodNameSigs = new Hashtable();
+ for(int i = 0; i < methods_count; i++)
+ {
+ methods[i] = new Method(this, br);
+ string name = methods[i].Name;
+ string sig = methods[i].Signature;
+ if(name.Length == 0 || (name.IndexOfAny(illegalcharacters) != -1 && name != "<init>" && name != "<clinit>"))
+ {
+ throw JavaException.ClassFormatError("{0} (Illegal method name \"{1}\")", Name, name);
+ }
+ if((name == "<init>" || name == "<clinit>") && !sig.EndsWith("V"))
+ {
+ throw JavaException.ClassFormatError("{0} (Method \"{1}\" has illegal signature \"{2}\")", Name, name, sig);
+ }
+ string nameSig = name + sig;
+ if(methodNameSigs.ContainsKey(nameSig))
+ {
+ throw JavaException.ClassFormatError("{0} (Repetitive method name/signature)", Name);
+ }
+ methodNameSigs.Add(nameSig, nameSig);
+ }
+ int attributes_count = br.ReadUInt16();
+ attributes = new Attribute[attributes_count];
+ for(int i = 0; i < attributes_count; i++)
+ {
+ attributes[i] = Attribute.Read(this, br);
+ }
+ if(br.Position != offset + length)
+ {
+ if(br.Position > offset + length)
+ {
+ throw JavaException.ClassFormatError("Truncated class file");
+ }
+ else
+ {
+ throw JavaException.ClassFormatError("Extra bytes at the end of the class file");
+ }
+ }
+ }
+ catch(IndexOutOfRangeException)
+ {
+ throw JavaException.ClassFormatError("Truncated class file");
+ }
+// catch(Exception)
+// {
+// FileStream fs = File.Create(inputClassName + ".broken");
+// fs.Write(buf, offset, length);
+// fs.Close();
+// throw;
+// }
+ }
+
+ internal Modifiers Modifiers
+ {
+ get
+ {
+ return access_flags;
+ }
+ }
+
+ internal bool IsAbstract
+ {
+ get
+ {
+ return (access_flags & Modifiers.Abstract) != 0;
+ }
+ }
+
+ internal bool IsFinal
+ {
+ get
+ {
+ return (access_flags & Modifiers.Final) != 0;
+ }
+ }
+
+ internal bool IsPublic
+ {
+ get
+ {
+ return (access_flags & Modifiers.Public) != 0;
+ }
+ }
+
+ internal bool IsInterface
+ {
+ get
+ {
+ return (access_flags & Modifiers.Interface) != 0;
+ }
+ }
+
+ internal bool IsSuper
+ {
+ get
+ {
+ return (access_flags & Modifiers.Super) != 0;
+ }
+ }
+
+ internal ConstantPoolItemFieldref GetFieldref(int index)
+ {
+ return (ConstantPoolItemFieldref)constantpool[index];
+ }
+
+ // NOTE this returns an FMI, because it used for both normal methods and interface methods
+ internal ConstantPoolItemFMI GetMethodref(int index)
+ {
+ return (ConstantPoolItemFMI)constantpool[index];
+ }
+
+ private ConstantPoolItem GetConstantPoolItem(int index)
+ {
+ return constantpool[index];
+ }
+
+ internal string GetConstantPoolClass(int index)
+ {
+ return ((ConstantPoolItemClass)constantpool[index]).Name;
+ }
+
+ private string GetConstantPoolString(int index)
+ {
+ return ((ConstantPoolItemString)constantpool[index]).Value;
+ }
+
+ private string GetConstantPoolUtf8(int index)
+ {
+ return ((ConstantPoolItemUtf8)constantpool[index]).Value;
+ }
+
+ internal object GetConstantPoolConstant(int index)
+ {
+ ConstantPoolItem cpi = constantpool[index];
+ if(cpi is ConstantPoolItemDouble)
+ {
+ return ((ConstantPoolItemDouble)cpi).Value;
+ }
+ else if(cpi is ConstantPoolItemFloat)
+ {
+ return ((ConstantPoolItemFloat)cpi).Value;
+ }
+ else if(cpi is ConstantPoolItemInteger)
+ {
+ return ((ConstantPoolItemInteger)cpi).Value;
+ }
+ else if(cpi is ConstantPoolItemLong)
+ {
+ return ((ConstantPoolItemLong)cpi).Value;
+ }
+ else if(cpi is ConstantPoolItemString)
+ {
+ return ((ConstantPoolItemString)cpi).Value;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ internal string Name
+ {
+ get
+ {
+ return name;
+ }
+ }
+
+ internal string PackageName
+ {
+ get
+ {
+ int index = name.LastIndexOf('/');
+ if(index == -1)
+ {
+ return "";
+ }
+ return name.Substring(0, index);
+ }
+ }
+
+ internal string SuperClass
+ {
+ get
+ {
+ return supername;
+ }
+ }
+
+ internal Field[] Fields
+ {
+ get
+ {
+ return fields;
+ }
+ }
+
+ internal Method[] Methods
+ {
+ get
+ {
+ return methods;
+ }
+ }
+
+ internal string[] Interfaces
+ {
+ get
+ {
+ return interfaces;
+ }
+ }
+
+ private Attribute GetAttribute(string name)
+ {
+ for(int i = 0; i < attributes.Length; i++)
+ {
+ if(attributes[i].Name == name)
+ {
+ return attributes[i];
+ }
+ }
+ return null;
+ }
+
+ internal string SourceFileAttribute
+ {
+ get
+ {
+ if(!sourceFileCached)
+ {
+ sourceFileCached = true;
+ Attribute attr = GetAttribute("SourceFile");
+ if(attr != null)
+ {
+ sourceFile = ((ConstantPoolItemUtf8)GetConstantPoolItem(attr.Data.ReadUInt16())).Value;
+ }
+ }
+ return sourceFile;
+ }
+ }
+
+ internal string NetExpTypeAttribute
+ {
+ get
+ {
+ Attribute attr = GetAttribute("IK.VM.NET.Type");
+ if(attr != null)
+ {
+ return ((ConstantPoolItemUtf8)GetConstantPoolItem(attr.Data.ReadUInt16())).Value;
+ }
+ return null;
+ }
+ }
+
+ internal abstract class ConstantPoolItem
+ {
+ internal virtual bool IsWide
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ internal virtual void Resolve(ClassFile classFile)
+ {
+ }
+
+ internal static ConstantPoolItem Read(string inputClassName, BigEndianBinaryReader br)
+ {
+ byte tag = br.ReadByte();
+ switch((Constant)tag)
+ {
+ case Constant.Class:
+ return new ConstantPoolItemClass(br);
+ case Constant.Double:
+ return new ConstantPoolItemDouble(br);
+ case Constant.Fieldref:
+ return new ConstantPoolItemFieldref(br);
+ case Constant.Float:
+ return new ConstantPoolItemFloat(br);
+ case Constant.Integer:
+ return new ConstantPoolItemInteger(br);
+ case Constant.InterfaceMethodref:
+ return new ConstantPoolItemInterfaceMethodref(br);
+ case Constant.Long:
+ return new ConstantPoolItemLong(br);
+ case Constant.Methodref:
+ return new ConstantPoolItemMethodref(br);
+ case Constant.NameAndType:
+ return new ConstantPoolItemNameAndType(br);
+ case Constant.String:
+ return new ConstantPoolItemString(br);
+ case Constant.Utf8:
+ return new ConstantPoolItemUtf8(inputClassName, br);
+ default:
+ throw JavaException.ClassFormatError("{0} (Illegal constant pool type 0x{1:X})", inputClassName, tag);
+ }
+ }
+ }
+
+ private class ConstantPoolItemClass : ConstantPoolItem
+ {
+ private ushort name_index;
+ private string name;
+
+ internal ConstantPoolItemClass(BigEndianBinaryReader br)
+ {
+ name_index = br.ReadUInt16();
+ }
+
+ internal override void Resolve(ClassFile classFile)
+ {
+ name = ((ConstantPoolItemUtf8)classFile.GetConstantPoolItem(name_index)).Value;;
+ }
+
+ internal string Name
+ {
+ get
+ {
+ return name;
+ }
+ }
+ }
+
+ private class ConstantPoolItemDouble : ConstantPoolItem
+ {
+ private double d;
+
+ internal ConstantPoolItemDouble(BigEndianBinaryReader br)
+ {
+ d = br.ReadDouble();
+ }
+
+ internal double Value
+ {
+ get
+ {
+ return d;
+ }
+ }
+
+ internal override bool IsWide
+ {
+ get
+ {
+ return true;
+ }
+ }
+ }
+
+ internal class ConstantPoolItemFMI : ConstantPoolItem
+ {
+ private ushort class_index;
+ private ushort name_and_type_index;
+ private string name;
+ private string signature;
+ private string clazz;
+
+ internal ConstantPoolItemFMI(BigEndianBinaryReader br)
+ {
+ class_index = br.ReadUInt16();
+ name_and_type_index = br.ReadUInt16();
+ }
+
+ internal override void Resolve(ClassFile classFile)
+ {
+ ConstantPoolItemNameAndType nat = (ConstantPoolItemNameAndType)classFile.GetConstantPoolItem(name_and_type_index);
+ nat.Resolve(classFile);
+ name = nat.Name;
+ signature = nat.Type;
+ ConstantPoolItemClass cls = (ConstantPoolItemClass)classFile.GetConstantPoolItem(class_index);
+ cls.Resolve(classFile);
+ clazz = cls.Name;
+ }
+
+ internal string Name
+ {
+ get
+ {
+ return name;
+ }
+ }
+
+ internal string Signature
+ {
+ get
+ {
+ return signature;
+ }
+ }
+
+ internal string Class
+ {
+ get
+ {
+ return clazz;
+ }
+ }
+ }
+
+ internal class ConstantPoolItemFieldref : ConstantPoolItemFMI
+ {
+ internal ConstantPoolItemFieldref(BigEndianBinaryReader br) : base(br)
+ {
+ }
+ }
+
+ internal class ConstantPoolItemMethodref : ConstantPoolItemFMI
+ {
+ internal ConstantPoolItemMethodref(BigEndianBinaryReader br) : base(br)
+ {
+ }
+ }
+
+ internal class ConstantPoolItemInterfaceMethodref : ConstantPoolItemFMI
+ {
+ internal ConstantPoolItemInterfaceMethodref(BigEndianBinaryReader br) : base(br)
+ {
+ }
+ }
+
+ private class ConstantPoolItemFloat : ConstantPoolItem
+ {
+ private float v;
+
+ internal ConstantPoolItemFloat(BigEndianBinaryReader br)
+ {
+ v = br.ReadSingle();
+ }
+
+ internal float Value
+ {
+ get
+ {
+ return v;
+ }
+ }
+ }
+
+ private class ConstantPoolItemInteger : ConstantPoolItem
+ {
+ private int v;
+
+ internal ConstantPoolItemInteger(BigEndianBinaryReader br)
+ {
+ v = br.ReadInt32();
+ }
+
+ internal int Value
+ {
+ get
+ {
+ return v;
+ }
+ }
+ }
+
+ private class ConstantPoolItemLong : ConstantPoolItem
+ {
+ private long l;
+
+ internal ConstantPoolItemLong(BigEndianBinaryReader br)
+ {
+ l = br.ReadInt64();
+ }
+
+ internal long Value
+ {
+ get
+ {
+ return l;
+ }
+ }
+
+ internal override bool IsWide
+ {
+ get
+ {
+ return true;
+ }
+ }
+ }
+
+ private class ConstantPoolItemNameAndType : ConstantPoolItem
+ {
+ private ushort name_index;
+ private ushort descriptor_index;
+ private string name;
+ private string descriptor;
+
+ internal ConstantPoolItemNameAndType(BigEndianBinaryReader br)
+ {
+ name_index = br.ReadUInt16();
+ descriptor_index = br.ReadUInt16();
+ }
+
+ internal override void Resolve(ClassFile classFile)
+ {
+ ConstantPoolItemUtf8 nameUtf8 = (ConstantPoolItemUtf8)classFile.GetConstantPoolItem(name_index);
+ nameUtf8.Resolve(classFile);
+ name = nameUtf8.Value;
+ ConstantPoolItemUtf8 descriptorUtf8 = (ConstantPoolItemUtf8)classFile.GetConstantPoolItem(descriptor_index);
+ descriptorUtf8.Resolve(classFile);
+ descriptor = descriptorUtf8.Value;
+ }
+
+ internal string Name
+ {
+ get
+ {
+ return name;
+ }
+ }
+
+ internal string Type
+ {
+ get
+ {
+ return descriptor;
+ }
+ }
+ }
+
+ private class ConstantPoolItemString : ConstantPoolItem
+ {
+ private ushort string_index;
+ private string s;
+
+ internal ConstantPoolItemString(BigEndianBinaryReader br)
+ {
+ string_index = br.ReadUInt16();
+ }
+
+ internal override void Resolve(ClassFile classFile)
+ {
+ ConstantPoolItemUtf8 utf8 = (ConstantPoolItemUtf8)classFile.GetConstantPoolItem(string_index);
+ utf8.Resolve(classFile);
+ s = utf8.Value;
+ }
+
+ internal string Value
+ {
+ get
+ {
+ return s;
+ }
+ }
+ }
+
+ private class ConstantPoolItemUtf8 : ConstantPoolItem
+ {
+ private string s;
+
+ internal ConstantPoolItemUtf8(string inputClassName, BigEndianBinaryReader br)
+ {
+ try
+ {
+ s = br.ReadString();
+ }
+ catch(FormatException)
+ {
+ throw JavaException.ClassFormatError("{0} (Illegal UTF8 string in constant pool)", inputClassName);
+ }
+ }
+
+ internal string Value
+ {
+ get
+ {
+ return s;
+ }
+ }
+ }
+
+ private enum Constant
+ {
+ Utf8 = 1,
+ Integer = 3,
+ Float = 4,
+ Long = 5,
+ Double = 6,
+ Class = 7,
+ String = 8,
+ Fieldref = 9,
+ Methodref = 10,
+ InterfaceMethodref = 11,
+ NameAndType = 12
+ }
+
+ internal class Attribute
+ {
+ private string name;
+ private BigEndianBinaryReader data;
+
+ private Attribute()
+ {
+ }
+
+ internal static Attribute Read(ClassFile classFile, BigEndianBinaryReader br)
+ {
+ try
+ {
+ int name_index = br.ReadUInt16();
+ string name = classFile.GetConstantPoolUtf8(name_index);
+ int attribute_length = br.ReadInt32();
+ Attribute a = new Attribute();
+ a.name = name;
+ a.data = br.Duplicate();
+ br.Skip(attribute_length);
+ return a;
+ }
+ catch(InvalidCastException)
+ {
+ }
+ catch(NullReferenceException)
+ {
+ }
+ catch(IndexOutOfRangeException)
+ {
+ }
+ throw JavaException.ClassFormatError("{0} (Attribute name invalid type)", classFile.Name);
+ }
+
+ internal string Name
+ {
+ get
+ {
+ return name;
+ }
+ }
+
+ internal BigEndianBinaryReader Data
+ {
+ get
+ {
+ return data.Duplicate();
+ }
+ }
+ }
+
+ internal class FieldOrMethod
+ {
+ private ClassFile classFile;
+ protected Modifiers access_flags;
+ private ushort name_index;
+ private ushort descriptor_index;
+ private Attribute[] attributes;
+
+ internal FieldOrMethod(ClassFile classFile, BigEndianBinaryReader br)
+ {
+ this.classFile = classFile;
+ access_flags = (Modifiers)br.ReadUInt16();
+ // TODO check that name is ConstantPoolItemUtf8
+ name_index = br.ReadUInt16();
+ // TODO check that descriptor is ConstantPoolItemUtf8 and validate the descriptor
+ descriptor_index = br.ReadUInt16();
+ int attributes_count = br.ReadUInt16();
+ attributes = new Attribute[attributes_count];
+ for(int i = 0; i < attributes_count; i++)
+ {
+ attributes[i] = Attribute.Read(classFile, br);
+ }
+ }
+
+ internal string Name
+ {
+ get
+ {
+ return classFile.GetConstantPoolUtf8(name_index);
+ }
+ }
+
+ internal string Signature
+ {
+ get
+ {
+ return classFile.GetConstantPoolUtf8(descriptor_index);
+ }
+ }
+
+ internal Modifiers Modifiers
+ {
+ get
+ {
+ return (Modifiers)access_flags;
+ }
+ }
+
+ internal bool IsAbstract
+ {
+ get
+ {
+ return (access_flags & Modifiers.Abstract) != 0;
+ }
+ }
+
+ internal bool IsFinal
+ {
+ get
+ {
+ return (access_flags & Modifiers.Final) != 0;
+ }
+ }
+
+ internal bool IsPublic
+ {
+ get
+ {
+ return (access_flags & Modifiers.Public) != 0;
+ }
+ }
+
+ internal bool IsPrivate
+ {
+ get
+ {
+ return (access_flags & Modifiers.Private) != 0;
+ }
+ }
+
+ internal bool IsProtected
+ {
+ get
+ {
+ return (access_flags & Modifiers.Protected) != 0;
+ }
+ }
+
+ internal bool IsStatic
+ {
+ get
+ {
+ return (access_flags & Modifiers.Static) != 0;
+ }
+ }
+
+ internal bool IsSynchronized
+ {
+ get
+ {
+ return (access_flags & Modifiers.Synchronized) != 0;
+ }
+ }
+
+ internal bool IsVolatile
+ {
+ get
+ {
+ return (access_flags & Modifiers.Volatile) != 0;
+ }
+ }
+
+ internal bool IsTransient
+ {
+ get
+ {
+ return (access_flags & Modifiers.Transient) != 0;
+ }
+ }
+
+ internal bool IsNative
+ {
+ get
+ {
+ return (access_flags & Modifiers.Native) != 0;
+ }
+ }
+
+ protected Attribute GetAttribute(string name)
+ {
+ foreach(Attribute attr in attributes)
+ {
+ if(attr.Name == name)
+ {
+ return attr;
+ }
+ }
+ return null;
+ }
+
+ internal ClassFile ClassFile
+ {
+ get
+ {
+ return classFile;
+ }
+ }
+ }
+
+ internal class Field : FieldOrMethod
+ {
+ private object constantValue;
+
+ internal Field(ClassFile classFile, BigEndianBinaryReader br) : base(classFile, br)
+ {
+ if((IsPrivate && IsPublic) || (IsPrivate && IsProtected) || (IsPublic && IsProtected)
+ || (IsFinal && IsVolatile)
+ || (classFile.IsInterface && (!IsPublic || !IsStatic || !IsFinal || IsTransient)))
+ {
+ throw JavaException.ClassFormatError("{0} (Illegal field modifiers: 0x{1:X})", classFile.Name, access_flags);
+ }
+ Attribute attr = GetAttribute("ConstantValue");
+ if(attr != null)
+ {
+ ushort index = attr.Data.ReadUInt16();
+ try
+ {
+ object o = classFile.GetConstantPoolConstant(index);
+ if(o == null)
+ {
+ throw JavaException.ClassFormatError("{0} (Bad index into constant pool)", classFile.Name);
+ }
+ switch(Signature)
+ {
+ case "I":
+ constantValue = (int)o;
+ break;
+ case "S":
+ constantValue = (short)(int)o;
+ break;
+ case "B":
+ constantValue = (sbyte)(int)o;
+ break;
+ case "C":
+ constantValue = (char)(int)o;
+ break;
+ case "Z":
+ constantValue = ((int)o) != 0;
+ break;
+ case "J":
+ constantValue = (long)o;
+ break;
+ case "F":
+ constantValue = (float)o;
+ break;
+ case "D":
+ constantValue = (double)o;
+ break;
+ case "Ljava/lang/String;":
+ constantValue = (string)o;
+ break;
+ default:
+ throw JavaException.ClassFormatError("{0} (Invalid signature for constant)", classFile.Name);
+ }
+ }
+ catch(InvalidCastException)
+ {
+ throw JavaException.ClassFormatError("{0} (Bad index into constant pool)", classFile.Name);
+ }
+ catch(IndexOutOfRangeException)
+ {
+ throw JavaException.ClassFormatError("{0} (Bad index into constant pool)", classFile.Name);
+ }
+ }
+ }
+
+ internal object ConstantValue
+ {
+ get
+ {
+ return constantValue;
+ }
+ }
+ }
+
+ internal class Method : FieldOrMethod
+ {
+ private Code code;
+
+ internal Method(ClassFile classFile, BigEndianBinaryReader br) : base(classFile, br)
+ {
+ // vmspec 4.6 says that all flags, except ACC_STRICT are ignored on <clinit>
+ if(Name == "<clinit>")
+ {
+ access_flags &= Modifiers.Strictfp;
+ access_flags |= (Modifiers.Static | Modifiers.Private);
+ }
+ else
+ {
+ if((Name == "<init>" && (IsStatic || IsSynchronized || IsFinal || IsAbstract))
+ || (IsPrivate && IsPublic) || (IsPrivate && IsProtected) || (IsPublic && IsProtected)
+ || (IsAbstract && (IsFinal || IsNative || IsPrivate || IsStatic || IsStrict || IsSynchronized))
+ || (classFile.IsInterface && (!IsPublic || !IsAbstract)))
+ {
+ throw JavaException.ClassFormatError("{0} (Illegal method modifiers: 0x{1:X})", classFile.Name, access_flags);
+ }
+ }
+ // TODO if the method is abstract or native it may not have a Code attribute (right?)
+ // and if it is not abstract or native, it must have a Code attribute
+ }
+
+ internal bool IsStrict
+ {
+ get
+ {
+ return (access_flags & Modifiers.Strictfp) != 0;
+ }
+ }
+
+ internal string[] NetExpSigAttribute
+ {
+ get
+ {
+ Attribute attr = GetAttribute("IK.VM.NET.Sig");
+ if(attr != null)
+ {
+ string s = ClassFile.GetConstantPoolUtf8(attr.Data.ReadUInt16());
+ if(s.Length == 0)
+ {
+ return new string[0];
+ }
+ return s.Split('|');
+ }
+ return null;
+ }
+ }
+
+ internal Code CodeAttribute
+ {
+ get
+ {
+ if(code == null)
+ {
+ Attribute attr = GetAttribute("Code");
+ if(attr != null)
+ {
+ code = new Code(this, attr);
+ }
+ }
+ return code;
+ }
+ }
+
+ internal class Code
+ {
+ private Method method;
+ private ushort max_stack;
+ private ushort max_locals;
+ private Instruction[] instructions;
+ private int[] pcIndexMap;
+ private ExceptionTableEntry[] exception_table;
+ private Attribute[] codeAttributes;
+ private int[] argmap;
+ private LineNumberTableEntry[] lineNumberTable;
+ private bool lineNumberTableCached;
+ private LocalVariableTableEntry[] localVariableTable;
+ private bool localVariableTableCached;
+
+ internal Code(Method method, Attribute attr)
+ {
+ this.method = method;
+ BigEndianBinaryReader br = attr.Data;
+ max_stack = br.ReadUInt16();
+ max_locals = br.ReadUInt16();
+ uint code_length = br.ReadUInt32();
+ ArrayList instructions = new ArrayList();
+ int basePosition = br.Position;
+ while(br.Position - basePosition < code_length)
+ {
+ instructions.Add(Instruction.Read(this, br.Position - basePosition, br));
+ }
+ // we add an additional nop instruction to make it easier for consumers of the code array
+ instructions.Add(new Instruction(this, br.Position - basePosition, ByteCode.__nop));
+ this.instructions = (Instruction[])instructions.ToArray(typeof(Instruction));
+ ushort exception_table_length = br.ReadUInt16();
+ exception_table = new ExceptionTableEntry[exception_table_length];
+ for(int i = 0; i < exception_table_length; i++)
+ {
+ exception_table[i] = new ExceptionTableEntry();
+ exception_table[i].start_pc = br.ReadUInt16();
+ exception_table[i].end_pc = br.ReadUInt16();
+ exception_table[i].handler_pc = br.ReadUInt16();
+ exception_table[i].catch_type = br.ReadUInt16();
+ exception_table[i].ordinal = i;
+ }
+ ushort attributes_count = br.ReadUInt16();
+ codeAttributes = new Attribute[attributes_count];
+ for(int i = 0; i < attributes_count; i++)
+ {
+ codeAttributes[i] = Attribute.Read(method.ClassFile, br);
+ }
+ // build the pcIndexMap
+ pcIndexMap = new int[this.instructions[this.instructions.Length - 1].PC + 1];
+ for(int i = 0; i < pcIndexMap.Length; i++)
+ {
+ pcIndexMap[i] = -1;
+ }
+ for(int i = 0; i < this.instructions.Length; i++)
+ {
+ pcIndexMap[this.instructions[i].PC] = i;
+ }
+ }
+
+ // maps argument 'slot' (as encoded in the xload/xstore instructions) into the ordinal
+ internal int[] ArgMap
+ {
+ get
+ {
+ if(argmap == null)
+ {
+ string sig = method.Signature;
+ ArrayList args = new ArrayList();
+ int pos = 0;
+ if(!method.IsStatic)
+ {
+ args.Add(pos++);
+ }
+ for(int i = 1; sig[i] != ')'; i++)
+ {
+ args.Add(pos++);
+ switch(sig[i])
+ {
+ case 'L':
+ i = sig.IndexOf(';', i);
+ break;
+ case 'D':
+ case 'J':
+ args.Add(-1);
+ break;
+ case '[':
+ {
+ while(sig[i] == '[')
+ {
+ i++;
+ }
+ if(sig[i] == 'L')
+ {
+ i = sig.IndexOf(';', i);
+ }
+ break;
+ }
+ }
+ }
+ argmap = new int[args.Count];
+ args.CopyTo(argmap);
+ }
+ return argmap;
+ }
+ }
+
+ internal Method Method
+ {
+ get
+ {
+ return method;
+ }
+ }
+
+ internal int MaxStack
+ {
+ get
+ {
+ return max_stack;
+ }
+ }
+
+ internal int MaxLocals
+ {
+ get
+ {
+ return max_locals;
+ }
+ }
+
+ internal Instruction[] Instructions
+ {
+ get
+ {
+ return instructions;
+ }
+ }
+
+ // maps a PC to an index in the Instruction[], invalid PCs return -1
+ internal int[] PcIndexMap
+ {
+ get
+ {
+ return pcIndexMap;
+ }
+ }
+
+ internal ExceptionTableEntry[] ExceptionTable
+ {
+ get
+ {
+ return exception_table;
+ }
+ }
+
+ private Attribute GetAttribute(string name)
+ {
+ foreach(Attribute attr in codeAttributes)
+ {
+ if(attr.Name == name)
+ {
+ return attr;
+ }
+ }
+ return null;
+ }
+
+ internal LineNumberTableEntry[] LineNumberTableAttribute
+ {
+ get
+ {
+ if(!lineNumberTableCached)
+ {
+ lineNumberTableCached = true;
+ Attribute attr = GetAttribute("LineNumberTable");
+ if(attr != null)
+ {
+ BigEndianBinaryReader rdr = attr.Data;
+ int count = rdr.ReadUInt16();
+ lineNumberTable = new LineNumberTableEntry[count];
+ for(int i = 0; i < count; i++)
+ {
+ lineNumberTable[i].start_pc = rdr.ReadUInt16();
+ lineNumberTable[i].line_number = rdr.ReadUInt16();
+ }
+ }
+ }
+ return lineNumberTable;
+ }
+ }
+
+ internal LocalVariableTableEntry[] LocalVariableTableAttribute
+ {
+ get
+ {
+ if(!localVariableTableCached)
+ {
+ localVariableTableCached = true;
+ Attribute attr = GetAttribute("LocalVariableTable");
+ if(attr != null)
+ {
+ BigEndianBinaryReader rdr = attr.Data;
+ int count = rdr.ReadUInt16();
+ localVariableTable = new LocalVariableTableEntry[count];
+ for(int i = 0; i < count; i++)
+ {
+ localVariableTable[i].start_pc = rdr.ReadUInt16();
+ localVariableTable[i].length = rdr.ReadUInt16();
+ localVariableTable[i].name = method.ClassFile.GetConstantPoolUtf8(rdr.ReadUInt16());
+ localVariableTable[i].descriptor = method.ClassFile.GetConstantPoolUtf8(rdr.ReadUInt16());
+ localVariableTable[i].index = rdr.ReadUInt16();
+ }
+ }
+ }
+ return localVariableTable;
+ }
+ }
+ }
+
+ internal class ExceptionTableEntry
+ {
+ internal ushort start_pc;
+ internal ushort end_pc;
+ internal ushort handler_pc;
+ internal ushort catch_type;
+ internal int ordinal;
+ }
+
+ internal class Instruction
+ {
+ private Method.Code method;
+ private int pc;
+ private ByteCode opcode;
+ private int arg1;
+ private int arg2;
+ private int default_offset;
+ private int[] values;
+ private int[] target_offsets;
+
+ internal Instruction(Method.Code method, int pc, ByteCode opcode)
+ : this(method, pc, opcode, 0)
+ {
+ }
+
+ private Instruction(Method.Code method, int pc, ByteCode opcode, int arg1)
+ : this(method, pc, opcode, arg1, 0)
+ {
+ }
+
+ private Instruction(Method.Code method, int pc, ByteCode opcode, int arg1, int arg2)
+ {
+ this.method = method;
+ this.pc = pc;
+ this.opcode = opcode;
+ this.arg1 = arg1;
+ this.arg2 = arg2;
+ }
+
+ private Instruction(Method.Code method, int pc, ByteCode opcode, int default_offset, int[] values, int[] target_offsets)
+ : this(method, pc, opcode)
+ {
+ this.default_offset = default_offset;
+ this.values = values;
+ this.target_offsets = target_offsets;
+ }
+
+ internal static Instruction Read(Method.Code method, int pc, BigEndianBinaryReader br)
+ {
+ ByteCode bc = (ByteCode)br.ReadByte();
+ ByteCodeMode mode = ByteCodeMetaData.GetMode(bc);
+ if(bc == ByteCode.__wide)
+ {
+ bc = (ByteCode)br.ReadByte();
+ // NOTE the PC of a wide instruction is actually the PC of the
+ // wide prefix, not the following instruction (vmspec 4.9.2)
+ mode = ByteCodeMetaData.GetWideMode(bc);
+ }
+ switch(mode)
+ {
+ case ByteCodeMode.Simple:
+ return new Instruction(method, pc, bc);
+ case ByteCodeMode.Constant_1:
+ case ByteCodeMode.Local_1:
+ return new Instruction(method, pc, bc, br.ReadByte());
+ case ByteCodeMode.Constant_2:
+ case ByteCodeMode.Local_2:
+ return new Instruction(method, pc, bc, br.ReadUInt16());
+ case ByteCodeMode.Branch_2:
+ return new Instruction(method, pc, bc, br.ReadInt16());
+ case ByteCodeMode.Branch_4:
+ return new Instruction(method, pc, bc, br.ReadInt32());
+ case ByteCodeMode.Constant_2_1_1:
+ {
+ Instruction instr = new Instruction(method, pc, bc, br.ReadUInt16());
+ // TODO validate these
+ br.ReadByte(); // count
+ br.ReadByte(); // unused
+ return instr;
+ }
+ case ByteCodeMode.Immediate_1:
+ return new Instruction(method, pc, bc, br.ReadSByte());
+ case ByteCodeMode.Immediate_2:
+ return new Instruction(method, pc, bc, br.ReadInt16());
+ case ByteCodeMode.Local_1_Immediate_1:
+ return new Instruction(method, pc, bc, br.ReadByte(), br.ReadSByte());
+ case ByteCodeMode.Local_2_Immediate_2:
+ return new Instruction(method, pc, bc, br.ReadUInt16(), br.ReadInt16());
+ case ByteCodeMode.Constant_2_Immediate_1:
+ return new Instruction(method, pc, bc, br.ReadUInt16(), br.ReadSByte());
+ case ByteCodeMode.Tableswitch:
+ {
+ // skip the padding
+ int p = pc + 1;
+ int align = ((p + 3) & 0x7ffffffc) - p;
+ for(int i = 0; i < align; i++)
+ {
+ br.ReadByte();
+ }
+ int default_offset = br.ReadInt32();
+ int low = br.ReadInt32();
+ int high = br.ReadInt32();
+ int[] values = new int[high - low + 1];
+ int[] target_offset = new int[high - low + 1];
+ for(int i = low; i <= high; i++)
+ {
+ values[i - low] = i;
+ target_offset[i - low] = br.ReadInt32();
+ }
+ return new Instruction(method, pc, bc, default_offset, values, target_offset);
+ }
+ case ByteCodeMode.Lookupswitch:
+ {
+ // skip the padding
+ int p = pc + 1;
+ int align = ((p + 3) & 0x7ffffffc) - p;
+ for(int i = 0; i < align; i++)
+ {
+ br.ReadByte();
+ }
+ int default_offset = br.ReadInt32();
+ int count = br.ReadInt32();
+ int[] values = new int[count];
+ int[] target_offset = new int[count];
+ for(int i = 0; i < count; i++)
+ {
+ values[i] = br.ReadInt32();
+ target_offset[i] = br.ReadInt32();
+ }
+ return new Instruction(method, pc, bc, default_offset, values, target_offset);
+ }
+ default:
+ throw JavaException.ClassFormatError("Invalid opcode: {0}", bc);
+ }
+ }
+
+ internal int PC
+ {
+ get
+ {
+ return pc;
+ }
+ }
+
+ internal ByteCode OpCode
+ {
+ get
+ {
+ return opcode;
+ }
+ }
+
+ internal NormalizedByteCode NormalizedOpCode
+ {
+ get
+ {
+ return ByteCodeMetaData.GetNormalizedByteCode(opcode);
+ }
+ }
+
+ internal int Arg1
+ {
+ get
+ {
+ return arg1;
+ }
+ }
+
+ internal int Arg2
+ {
+ get
+ {
+ return arg2;
+ }
+ }
+
+ internal int NormalizedArg1
+ {
+ get
+ {
+ return ByteCodeMetaData.GetArg(opcode, arg1);
+ }
+ }
+
+ internal int DefaultOffset
+ {
+ get
+ {
+ return default_offset;
+ }
+ }
+
+ internal int[] Values
+ {
+ get
+ {
+ return values;
+ }
+ }
+
+ internal int[] TargetOffsets
+ {
+ get
+ {
+ return target_offsets;
+ }
+ }
+
+ internal Method.Code MethodCode
+ {
+ get
+ {
+ return method;
+ }
+ }
+ }
+
+ internal struct LineNumberTableEntry
+ {
+ internal int start_pc;
+ internal int line_number;
+ }
+
+ internal struct LocalVariableTableEntry
+ {
+ internal int start_pc;
+ internal int length;
+ internal string name;
+ internal string descriptor;
+ internal int index;
+ }
+ }
+}
diff --git a/IK.VM.NET/ClassLoaderWrapper.cs b/IK.VM.NET/ClassLoaderWrapper.cs
new file mode 100644
index 00000000..b4c6ea77
--- /dev/null
+++ b/IK.VM.NET/ClassLoaderWrapper.cs
@@ -0,0 +1,900 @@
+#define DEBUG
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+using System.Reflection.Emit;
+using System.Reflection;
+using System.IO;
+using System.Collections;
+using System.Xml;
+using System.Diagnostics;
+
+class ClassLoaderWrapper
+{
+ private static bool arrayConstructionHack;
+ private static ArrayList ikvmAssemblies = new ArrayList();
+ private static Hashtable assemblyToClassLoaderWrapper = new Hashtable();
+ private static Hashtable javaClassLoaderToClassLoaderWrapper = new Hashtable();
+ private static ArrayList classLoaders = new ArrayList();
+ private static Hashtable dynamicTypes = new Hashtable();
+ // TODO typeToTypeWrapper should be an identity hashtable
+ private static Hashtable typeToTypeWrapper = new Hashtable();
+ private static ClassLoaderWrapper bootstrapClassLoader;
+ private object javaClassLoader;
+ private MethodInfo loadClassMethod;
+ private Hashtable types = new Hashtable();
+ private Hashtable nativeMethods;
+ // HACK moduleBuilder is static, because multiple dynamic assemblies is broken (TypeResolve doesn't fire)
+ // so for the time being, we share one dynamic assembly among all classloaders
+ private static ModuleBuilder moduleBuilder;
+
+ // HACK this is used by the ahead-of-time compiler to overrule the bootstrap classloader
+ internal static void SetBootstrapClassLoader(ClassLoaderWrapper bootstrapClassLoader)
+ {
+ if(ClassLoaderWrapper.bootstrapClassLoader != null)
+ {
+ throw new InvalidOperationException();
+ }
+ ClassLoaderWrapper.bootstrapClassLoader = bootstrapClassLoader;
+ }
+
+ static ClassLoaderWrapper()
+ {
+ AppDomain.CurrentDomain.TypeResolve += new ResolveEventHandler(OnTypeResolve);
+ AppDomain.CurrentDomain.AssemblyLoad += new AssemblyLoadEventHandler(OnAssemblyLoad);
+ foreach(Assembly a in AppDomain.CurrentDomain.GetAssemblies())
+ {
+ if(a.IsDefined(typeof(IKVMAssemblyAttribute), false) && !(a is AssemblyBuilder))
+ {
+ ikvmAssemblies.Add(a);
+ }
+ }
+ }
+
+ private static void OnAssemblyLoad(object sender, AssemblyLoadEventArgs e)
+ {
+ if(e.LoadedAssembly.IsDefined(typeof(IKVMAssemblyAttribute), false) && !(e.LoadedAssembly is AssemblyBuilder))
+ {
+ ikvmAssemblies.Add(e.LoadedAssembly);
+ }
+ }
+
+ private static Assembly OnTypeResolve(object sender, ResolveEventArgs args)
+ {
+ //Console.WriteLine("OnTypeResolve: " + args.Name);
+ if(arrayConstructionHack)
+ {
+ return null;
+ }
+ try
+ {
+ TypeWrapper type = (TypeWrapper)dynamicTypes[args.Name];
+ if(type == null)
+ {
+ return null;
+ }
+ type.Finish();
+ return type.Type.Assembly;
+ }
+ catch(Exception x)
+ {
+ // TODO don't catch the exception here... But, the problem is that Type.GetType() swallows all exceptions
+ // that occur here, unless throwOnError is set, but in some (most?) cases you don't want the exception if it only
+ // means that the class cannot be found...
+ Console.WriteLine(x);
+ Console.WriteLine(new StackTrace(true));
+ throw;
+ }
+ }
+
+ internal ClassLoaderWrapper(object javaClassLoader)
+ {
+ this.javaClassLoader = javaClassLoader;
+ if(javaClassLoader != null)
+ {
+ loadClassMethod = javaClassLoader.GetType().GetMethod("loadClass", BindingFlags.Public | BindingFlags.Instance, null, CallingConventions.Standard, new Type[] { typeof(string) }, null);
+ if(loadClassMethod == null)
+ {
+ throw new InvalidOperationException();
+ }
+ }
+ classLoaders.Add(this);
+ }
+
+ internal void LoadRemappedTypes()
+ {
+ nativeMethods = new Hashtable();
+ // TODO interfaces have java/lang/Object as the base type (do they really?)
+ types["java.lang.Cloneable"] = new RemappedTypeWrapper(ModifiersAttribute.GetModifiers(typeof(java.lang.Cloneable)), "java/lang/Cloneable", typeof(java.lang.Cloneable), new TypeWrapper[0], null);
+ typeToTypeWrapper.Add(typeof(java.lang.Cloneable), types["java.lang.Cloneable"]);
+ types["java.io.Serializable"] = new RemappedTypeWrapper(ModifiersAttribute.GetModifiers(typeof(java.io.Serializable)), "java/io/Serializable", typeof(java.io.Serializable), new TypeWrapper[0], null);
+ typeToTypeWrapper.Add(typeof(java.io.Serializable), types["java.io.Serializable"]);
+ MapXml.Root map = null;
+ using(Stream s = Assembly.GetExecutingAssembly().GetManifestResourceStream("map.xml"))
+ {
+ // TODO the XmlSerializer generates a bunch of C# code and compiles that. This is very slow, we probably
+ // shouldn't use it.
+ System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(typeof(MapXml.Root));
+ map = (MapXml.Root)ser.Deserialize(s);
+ }
+ foreach(MapXml.Class c in map.remappings)
+ {
+ TypeWrapper baseWrapper = null;
+ // HACK need to resolve the base type or put it in the XML
+ if(c.Type != "System.Object")
+ {
+ baseWrapper = (TypeWrapper)types["java.lang.Object"];
+ }
+ string name = c.Name;
+ Modifiers modifiers = (Modifiers)c.Modifiers;
+ // TODO specify interfaces
+ TypeWrapper tw = new RemappedTypeWrapper(modifiers, name.Replace('.', '/'), Type.GetType(c.Type, true), new TypeWrapper[0], baseWrapper);
+ types.Add(name, tw);
+ typeToTypeWrapper.Add(tw.Type, tw);
+ }
+ foreach(MapXml.Class c in map.remappings)
+ {
+ ((RemappedTypeWrapper)types[c.Name]).LoadRemappings(c);
+ }
+ // native methods
+ foreach(MapXml.Class c in map.nativeMethods)
+ {
+ string className = c.Name;
+ foreach(MapXml.Method method in c.Methods)
+ {
+ string methodName = method.Name;
+ string methodSig = method.Sig;
+ nativeMethods[className + "." + methodName + methodSig] = method;
+ }
+ }
+ }
+
+ internal TypeWrapper LoadClassBySlashedName(string name)
+ {
+ // OPTIMIZE
+ return LoadClassByDottedName(name.Replace('/', '.'));
+ }
+
+ // TODO implement vmspec 5.3.4 Loading Constraints
+ internal TypeWrapper LoadClassByDottedName(string name)
+ {
+ TypeWrapper type = (TypeWrapper)types[name];
+ if(type != null)
+ {
+ return type;
+ }
+ if(name.Length > 1 && name[0] == '[')
+ {
+ int dims = 1;
+ while(name[dims] == '[')
+ {
+ dims++;
+ }
+ switch(name[dims])
+ {
+ case 'L':
+ {
+ type = LoadClassByDottedName(name.Substring(dims + 1, name.IndexOf(';', dims) - dims - 1));
+ type = type.GetClassLoader().CreateArrayType(name, type.Type, dims);
+ return type;
+ }
+ case 'B':
+ return GetBootstrapClassLoader().CreateArrayType(name, typeof(sbyte), dims);
+ case 'C':
+ return GetBootstrapClassLoader().CreateArrayType(name, typeof(char), dims);
+ case 'D':
+ return GetBootstrapClassLoader().CreateArrayType(name, typeof(double), dims);
+ case 'F':
+ return GetBootstrapClassLoader().CreateArrayType(name, typeof(float), dims);
+ case 'I':
+ return GetBootstrapClassLoader().CreateArrayType(name, typeof(int), dims);
+ case 'J':
+ return GetBootstrapClassLoader().CreateArrayType(name, typeof(long), dims);
+ case 'S':
+ return GetBootstrapClassLoader().CreateArrayType(name, typeof(short), dims);
+ case 'Z':
+ return GetBootstrapClassLoader().CreateArrayType(name, typeof(bool), dims);
+ default:
+ // TODO I'm not sure this is the right exception here (instead we could throw a NoClassDefFoundError)
+ throw JavaException.ClassNotFoundException(name);
+ }
+ }
+ if(javaClassLoader == null)
+ {
+ // HACK if the name contains a comma, we assume it is an assembly qualified name
+ if(name.IndexOf(',') != -1)
+ {
+ Type t = Type.GetType(name);
+ if(t != null)
+ {
+ return GetCompiledTypeWrapper(t);
+ }
+ }
+ type = GetBootstrapType(name);
+ if(type != null)
+ {
+ return type;
+ }
+ throw JavaException.ClassNotFoundException(name);
+ }
+ else
+ {
+ // OPTIMIZE this should be optimized
+ try
+ {
+ object clazz;
+ // NOTE just like Java does (I think), we take the classloader lock before calling the loadClass method
+ lock(javaClassLoader)
+ {
+ clazz = loadClassMethod.Invoke(javaClassLoader, new object[] { name });
+ }
+ type = (TypeWrapper)clazz.GetType().GetField("wrapper", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(clazz);
+ if(type == null)
+ {
+ Type t = (Type)clazz.GetType().GetField("type", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(clazz);
+ ClassLoaderWrapper loader = GetClassLoader(t);
+ type = (TypeWrapper)loader.types[name];
+ if(type == null)
+ {
+ // this shouldn't be possible
+ throw new InvalidOperationException(name + ", this = " + javaClassLoader);
+ }
+ }
+ // NOTE we're caching types loaded by parent classloaders as well!
+ // TODO not sure if this is correct
+ if(type.GetClassLoader() != this)
+ {
+ if(types[name] != type)
+ {
+ types.Add(name, type);
+ }
+ }
+ return type;
+ }
+ catch(TargetInvocationException x)
+ {
+ ExceptionHelper.MapExceptionFast(x);
+ throw x.InnerException;
+ }
+ }
+ }
+
+ private TypeWrapper GetCompiledTypeWrapper(Type type)
+ {
+ Debug.Assert(!(type is TypeBuilder));
+ // only the bootstrap classloader can own compiled types
+ Debug.Assert(javaClassLoader == null);
+ string name = NativeCode.java.lang.Class.getName(type);
+ TypeWrapper wrapper = (TypeWrapper)types[name];
+ if(wrapper == null)
+ {
+ TypeWrapper baseType;
+ if(type.BaseType == null)
+ {
+ baseType = LoadClassByDottedName("java.lang.Object");
+ }
+ else
+ {
+ baseType = GetWrapperFromType(type.BaseType);
+ }
+ wrapper = new CompiledTypeWrapper(name.Replace('.', '/'), type, baseType);
+ types.Add(name, wrapper);
+ // TODO shouldn't we add the <type,wrapper> to the typeToTypeWrapper hashtable?
+ }
+ return wrapper;
+ }
+
+ internal virtual Type GetBootstrapTypeRaw(string name)
+ {
+ // TODO consider the thread safety aspects of this (if another thread triggers a load of an IKVM assembly,
+ // the collection enumerator will throw a version exception)
+ foreach(Assembly a in ikvmAssemblies)
+ {
+ Type t = a.GetType(name);
+ if(t != null)
+ {
+ return t;
+ }
+ }
+ return null;
+ }
+
+ internal virtual TypeWrapper GetBootstrapType(string name)
+ {
+ Type t = GetBootstrapTypeRaw(name);
+ if(t != null)
+ {
+ return GetCompiledTypeWrapper(t);
+ }
+ return null;
+ }
+
+ private TypeWrapper CreateArrayType(string name, Type elementType, int dims)
+ {
+ // TODO array accessibility should be the same as the elementType's accessibility
+ // (and this should be enforced)
+ TypeWrapper wrapper = (TypeWrapper)types[name];
+ if(wrapper == null)
+ {
+ String netname = "[]";
+ for(int i = 1; i < dims; i++)
+ {
+ netname += "[]";
+ }
+ Type array;
+ if(elementType.Module is ModuleBuilder)
+ {
+ // HACK ModuleBuilder.GetType() is broken (I think), it fires a TypeResolveEvent when
+ // you try to construct an array type from an unfinished type. I don't think it should
+ // do that. We have to work around that by setting a global flag (yuck) to prevent us
+ // from responding to the TypeResolveEvent.
+ arrayConstructionHack = true;
+ try
+ {
+ array = ((ModuleBuilder)elementType.Module).GetType(elementType.FullName + netname);
+ }
+ finally
+ {
+ arrayConstructionHack = false;
+ }
+ }
+ else
+ {
+ array = elementType.Assembly.GetType(elementType.FullName + netname, true);
+ }
+ TypeWrapper[] interfaces = new TypeWrapper[2];
+ interfaces[0] = GetBootstrapClassLoader().LoadClassByDottedName("java.lang.Cloneable");
+ interfaces[1] = GetBootstrapClassLoader().LoadClassByDottedName("java.io.Serializable");
+ MethodDescriptor mdClone = new MethodDescriptor(GetBootstrapClassLoader(), "clone", "()Ljava/lang/Object;");
+ Modifiers modifiers = Modifiers.Final | Modifiers.Public;
+ // TODO copy accessibility from element type
+ wrapper = new RemappedTypeWrapper(modifiers, name, array, interfaces, GetBootstrapClassLoader().LoadClassByDottedName("java.lang.Object"));
+ MethodInfo clone = typeof(Array).GetMethod("Clone");
+ MethodWrapper mw = new MethodWrapper(wrapper, mdClone, clone, Modifiers.Public);
+ mw.EmitCall = CodeEmitter.Create(OpCodes.Callvirt, clone);
+ mw.EmitCallvirt = CodeEmitter.Create(OpCodes.Callvirt, clone);
+ wrapper.AddMethod(mw);
+ types.Add(name, wrapper);
+ }
+ return wrapper;
+ }
+
+ // TODO make sure class isn't defined already
+ // TODO check for circularity
+ // TODO disallow anyone other than the bootstrap classloader defining classes in the "java." package
+ internal TypeWrapper DefineClass(ClassFile f)
+ {
+ // TODO shouldn't this check be in ClassFile.cs?
+ if(f.Name.Length == 0 || f.Name[0] == '[')
+ {
+ throw JavaException.ClassFormatError("Bad name");
+ }
+ TypeWrapper type;
+ // TODO if the class doesn't exist, LoadClassBySlashedName throws a ClassNotFoundException, but
+ // we need to catch that and throw a NoClassDefFoundError (because that is unchecked)
+ // TODO also figure out what should happen if LoadClassBySlashedName throws another exception (custom class loaders
+ // can throw whatever exception they want)
+ TypeWrapper baseType = LoadClassBySlashedName(f.SuperClass);
+ // if the base type isn't public, it must be in the same package
+ if(!baseType.IsPublic)
+ {
+ if(baseType.GetClassLoader() != this || f.PackageName != baseType.PackageName)
+ {
+ throw JavaException.IllegalAccessError("Class {0} cannot access its superclass {1}", f.Name, baseType.Name);
+ }
+ }
+ if(baseType.IsFinal)
+ {
+ throw JavaException.VerifyError("Cannot inherit from final class");
+ }
+ if(baseType.IsInterface)
+ {
+ throw JavaException.IncompatibleClassChangeError("Class {0} has interface {1} as superclass", f.Name, baseType.Name);
+ }
+ string dotnetType = f.NetExpTypeAttribute;
+ if(dotnetType != null)
+ {
+ type = new NetExpTypeWrapper(f, dotnetType, baseType);
+ }
+ else
+ {
+ type = new DynamicTypeWrapper(f.Name, f, baseType, this, nativeMethods);
+ dynamicTypes.Add(f.Name.Replace('/', '.'), type);
+ }
+ types.Add(f.Name.Replace('/', '.'), type);
+ return type;
+ }
+
+ internal object GetJavaClassLoader()
+ {
+ return javaClassLoader;
+ }
+
+ internal static void SaveDebugImage(object mainClass)
+ {
+ // HACK we iterate 3 times, in the hopes that that will be enough. We really should let FinishAll return a boolean whether
+ // anything was done, and continue iterating until all FinishAlls return false.
+ for(int i = 0; i < 3; i++)
+ {
+ foreach(ClassLoaderWrapper wrapper in classLoaders)
+ {
+ wrapper.FinishAll();
+ }
+ }
+ // HACK use reflection to get the type from the class
+ Type mainType = NativeCode.java.lang.Class.getType(mainClass);
+ MethodInfo main = mainType.GetMethod("main", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(string[]) }, null);
+ AssemblyBuilder asm = ((AssemblyBuilder)moduleBuilder.Assembly);
+ asm.SetEntryPoint(main, PEFileKinds.ConsoleApplication);
+ asm.Save(moduleBuilder.Name);
+ }
+
+ // this version isn't used at the moment, because multi assembly type references are broken in the CLR
+ internal static void SaveDebugImage__MultiAssemblyVersion(object mainClass)
+ {
+ // HACK we iterate 3 times, in the hopes that that will be enough. We really should let FinishAll return a boolean whether
+ // anything was done, and continue iterating until all FinishAlls return false.
+ for(int i = 0; i < 3; i++)
+ {
+ foreach(DictionaryEntry entry in assemblyToClassLoaderWrapper)
+ {
+ AssemblyBuilder asm = (AssemblyBuilder)entry.Key;
+ ClassLoaderWrapper loader = (ClassLoaderWrapper)entry.Value;
+ loader.FinishAll();
+ }
+ }
+ // HACK use reflection to get the type from the class
+ Type mainType = NativeCode.java.lang.Class.getType(mainClass);
+ MethodInfo main = mainType.GetMethod("main", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(string[]) }, null);
+ foreach(DictionaryEntry entry in ClassLoaderWrapper.assemblyToClassLoaderWrapper)
+ {
+ AssemblyBuilder asm = (AssemblyBuilder)entry.Key;
+ ClassLoaderWrapper loader = (ClassLoaderWrapper)entry.Value;
+ if(mainType.Assembly.Equals(asm))
+ {
+ asm.SetEntryPoint(main, PEFileKinds.ConsoleApplication);
+ }
+ asm.Save(asm.GetName().Name);
+ }
+ }
+
+ internal void FinishAll()
+ {
+ int prevCount = -1;
+ while(prevCount != types.Count)
+ {
+ prevCount = types.Count;
+ ArrayList l = new ArrayList();
+ foreach(TypeWrapper t in types.Values)
+ {
+ l.Add(t);
+ }
+ foreach(TypeWrapper t in l)
+ {
+ t.Finish();
+ }
+ }
+ }
+
+ internal ModuleBuilder ModuleBuilder
+ {
+ get
+ {
+ lock(this)
+ {
+ if(moduleBuilder == null)
+ {
+ moduleBuilder = CreateModuleBuilder();
+ lock(assemblyToClassLoaderWrapper.SyncRoot)
+ {
+ assemblyToClassLoaderWrapper[moduleBuilder.Assembly] = this;
+ }
+ }
+ return moduleBuilder;
+ }
+ }
+ }
+
+ protected virtual ModuleBuilder CreateModuleBuilder()
+ {
+ AssemblyName name = new AssemblyName();
+ name.Name = "ikvm_dynamic_assembly__" + (javaClassLoader == null ? "bootstrap" : javaClassLoader);
+ AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave);
+ ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(name.Name, JVM.Debug);
+ if(JVM.Debug)
+ {
+ CustomAttributeBuilder debugAttr = new CustomAttributeBuilder(typeof(DebuggableAttribute).GetConstructor(new Type[] { typeof(bool), typeof(bool) }), new object[] { true, true });
+ moduleBuilder.SetCustomAttribute(debugAttr);
+ }
+ return moduleBuilder;
+ }
+
+ internal Type ExpressionType(string type)
+ {
+ // HACK to ease the burden of the compiler, we support the Lret pseudo type here
+ if(type.StartsWith("Lret;"))
+ {
+ return typeof(int);
+ }
+ if(type == "Lnull")
+ {
+ throw new InvalidOperationException("ExpressionType for Lnull requested");
+ }
+ int index = 0;
+ return SigDecoder(ref index, type);
+ }
+
+ // NOTE: this will ignore anything following the sig marker (so that it can be used to decode method signatures)
+ private Type SigDecoder(ref int index, string sig)
+ {
+ switch(sig[index++])
+ {
+ case 'B':
+ return typeof(sbyte);
+ case 'C':
+ return typeof(char);
+ case 'D':
+ return typeof(double);
+ case 'F':
+ return typeof(float);
+ case 'I':
+ return typeof(int);
+ case 'J':
+ return typeof(long);
+ case 'L':
+ {
+ int pos = index;
+ index = sig.IndexOf(';', index) + 1;
+ return LoadClassBySlashedName(sig.Substring(pos, index - pos - 1)).Type;
+ }
+ case 'S':
+ return typeof(short);
+ case 'Z':
+ return typeof(bool);
+ case 'V':
+ return typeof(void);
+ case '[':
+ {
+ // TODO this can be optimized
+ string array = "[";
+ while(sig[index] == '[')
+ {
+ index++;
+ array += "[";
+ }
+ switch(sig[index])
+ {
+ case 'L':
+ {
+ int pos = index;
+ index = sig.IndexOf(';', index) + 1;
+ return LoadClassBySlashedName(array + sig.Substring(pos, index - pos)).Type;
+ }
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'F':
+ case 'I':
+ case 'J':
+ case 'S':
+ case 'Z':
+ return LoadClassBySlashedName(array + sig[index++]).Type;
+ default:
+ throw new InvalidOperationException(sig.Substring(index));
+ }
+ }
+ default:
+ throw new InvalidOperationException("Invalid at " + index + " in " + sig);
+ }
+ }
+
+ internal Type RetTypeFromSig(string sig)
+ {
+ int index = sig.IndexOf(')') + 1;
+ return SigDecoder(ref index, sig);
+ }
+
+ internal Type[] ArgTypeListFromSig(string sig)
+ {
+ if(sig[1] == ')')
+ {
+ return Type.EmptyTypes;
+ }
+ ArrayList list = new ArrayList();
+ for(int i = 1; sig[i] != ')';)
+ {
+ list.Add(SigDecoder(ref i, sig));
+ }
+ Type[] types = new Type[list.Count];
+ list.CopyTo(types);
+ return types;
+ }
+
+ // NOTE: this will ignore anything following the sig marker (so that it can be used to decode method signatures)
+ private TypeWrapper SigDecoderWrapper(ref int index, string sig)
+ {
+ switch(sig[index++])
+ {
+ case 'B':
+ return PrimitiveTypeWrapper.BYTE;
+ case 'C':
+ return PrimitiveTypeWrapper.CHAR;
+ case 'D':
+ return PrimitiveTypeWrapper.DOUBLE;
+ case 'F':
+ return PrimitiveTypeWrapper.FLOAT;
+ case 'I':
+ return PrimitiveTypeWrapper.INT;
+ case 'J':
+ return PrimitiveTypeWrapper.LONG;
+ case 'L':
+ {
+ int pos = index;
+ index = sig.IndexOf(';', index) + 1;
+ return LoadClassBySlashedName(sig.Substring(pos, index - pos - 1));
+ }
+ case 'S':
+ return PrimitiveTypeWrapper.SHORT;
+ case 'Z':
+ return PrimitiveTypeWrapper.BOOLEAN;
+ case 'V':
+ return PrimitiveTypeWrapper.VOID;
+ case '[':
+ {
+ // TODO this can be optimized
+ string array = "[";
+ while(sig[index] == '[')
+ {
+ index++;
+ array += "[";
+ }
+ switch(sig[index])
+ {
+ case 'L':
+ {
+ int pos = index;
+ index = sig.IndexOf(';', index) + 1;
+ return LoadClassBySlashedName(array + sig.Substring(pos, index - pos));
+ }
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'F':
+ case 'I':
+ case 'J':
+ case 'S':
+ case 'Z':
+ return LoadClassBySlashedName(array + sig[index++]);
+ default:
+ throw new InvalidOperationException(sig.Substring(index));
+ }
+ }
+ default:
+ throw new InvalidOperationException(sig.Substring(index));
+ }
+ }
+
+ internal TypeWrapper RetTypeWrapperFromSig(string sig)
+ {
+ int index = sig.IndexOf(')') + 1;
+ return SigDecoderWrapper(ref index, sig);
+ }
+
+ internal TypeWrapper[] ArgTypeWrapperListFromSig(string sig)
+ {
+ if(sig[1] == ')')
+ {
+ return new TypeWrapper[0];
+ }
+ ArrayList list = new ArrayList();
+ for(int i = 1; sig[i] != ')';)
+ {
+ list.Add(SigDecoderWrapper(ref i, sig));
+ }
+ TypeWrapper[] types = new TypeWrapper[list.Count];
+ list.CopyTo(types);
+ return types;
+ }
+
+ // subType and baseType are Java class name (e.g. java/lang/Object)
+ internal bool IsSubType(string subType, string baseType)
+ {
+ return LoadClassBySlashedName(subType).IsSubTypeOf(LoadClassBySlashedName(baseType));
+ }
+
+ internal string FindCommonBaseType(string type1, string type2)
+ {
+ TypeWrapper t1 = LoadClassBySlashedName(type1);
+ TypeWrapper t2 = LoadClassBySlashedName(type2);
+ if(t1 == t2)
+ {
+ return type1;
+ }
+ if(t1.IsInterface || t2.IsInterface)
+ {
+ // TODO I don't know how finding the common base for interfaces is defined, but
+ // for now I'm just doing the naive thing
+ // UPDATE according to a paper by Alessandro Coglio & Allen Goldberg titled
+ // "Type Safety in the JVM: Some Problems in Java 2 SDK 1.2 and Proposed Solutions"
+ // the common base of two interfaces is java/lang/Object, and there is special
+ // treatment for java/lang/Object types that allow it to be assigned to any interface
+ // type, the JVM's typesafety then depends on the invokeinterface instruction to make
+ // sure that the reference actually implements the interface.
+ // So strictly speaking, the code below isn't correct, but it works, so for now it stays in.
+ if(t1.ImplementsInterface(t2))
+ {
+ return t2.Name;
+ }
+ if(t2.ImplementsInterface(t1))
+ {
+ return t1.Name;
+ }
+ return "java/lang/Object";
+ }
+ Stack st1 = new Stack();
+ Stack st2 = new Stack();
+ while(t1 != null)
+ {
+ st1.Push(t1);
+ t1 = t1.BaseTypeWrapper;
+ }
+ while(t2 != null)
+ {
+ st2.Push(t2);
+ t2 = t2.BaseTypeWrapper;
+ }
+ TypeWrapper type = null;
+ for(;;)
+ {
+ t1 = st1.Count > 0 ? (TypeWrapper)st1.Pop() : null;
+ t2 = st2.Count > 0 ? (TypeWrapper)st2.Pop() : null;
+ if(t1 != t2)
+ {
+ return type.Name;
+ }
+ type = t1;
+ }
+ }
+
+ internal static ClassLoaderWrapper GetBootstrapClassLoader()
+ {
+ if(bootstrapClassLoader == null)
+ {
+ bootstrapClassLoader = new ClassLoaderWrapper(null);
+ bootstrapClassLoader.LoadRemappedTypes();
+ }
+ return bootstrapClassLoader;
+ }
+
+ internal static ClassLoaderWrapper GetClassLoaderWrapper(object javaClassLoader)
+ {
+ if(javaClassLoader == null)
+ {
+ return GetBootstrapClassLoader();
+ }
+ ClassLoaderWrapper wrapper = (ClassLoaderWrapper)javaClassLoaderToClassLoaderWrapper[javaClassLoader];
+ if(wrapper == null)
+ {
+ wrapper = new ClassLoaderWrapper(javaClassLoader);
+ javaClassLoaderToClassLoaderWrapper[javaClassLoader] = wrapper;
+ }
+ return wrapper;
+ }
+
+ internal static ClassLoaderWrapper GetClassLoader(Type type)
+ {
+ Debug.Assert(!(type is TypeBuilder));
+ TypeWrapper wrapper = GetWrapperFromTypeFast(type);
+ if(wrapper != null)
+ {
+ return wrapper.GetClassLoader();
+ }
+ return GetBootstrapClassLoader();
+// ClassLoaderWrapper loader = (ClassLoaderWrapper)assemblyToClassLoaderWrapper[type.Assembly];
+// if(loader == null)
+// {
+// loader = GetBootstrapClassLoader();
+// }
+// return loader;
+ }
+
+ // This only returns the wrapper for a Type if that wrapper has already been created, otherwise
+ // it returns null
+ // If the wrapper doesn't exist, that means that the type is either a .NET type or a pre-compiled Java class
+ internal static TypeWrapper GetWrapperFromTypeFast(Type type)
+ {
+ Debug.Assert(!(type is TypeBuilder));
+ return (TypeWrapper)typeToTypeWrapper[type];
+ }
+
+ internal static TypeWrapper GetWrapperFromType(Type type)
+ {
+ Debug.Assert(!(type is TypeBuilder));
+ TypeWrapper wrapper = GetWrapperFromTypeFast(type);
+ if(wrapper == null)
+ {
+ // if the wrapper doesn't already exist, that must mean that the type
+ // is a .NET type (or a pre-compiled Java class), which means that it
+ // was "loaded" by the bootstrap classloader
+ // TODO think up a scheme to deal with .NET types that have the same name. Since all .NET types
+ // appear in the boostrap classloader, we need to devise a scheme to mangle the class name
+ if(type.IsPrimitive || type == typeof(void))
+ {
+ if(type == typeof(void))
+ {
+ return PrimitiveTypeWrapper.VOID;
+ }
+ else if(type == typeof(sbyte))
+ {
+ return PrimitiveTypeWrapper.BYTE;
+ }
+ else if(type == typeof(char))
+ {
+ return PrimitiveTypeWrapper.CHAR;
+ }
+ else if(type == typeof(double))
+ {
+ return PrimitiveTypeWrapper.DOUBLE;
+ }
+ else if(type == typeof(float))
+ {
+ return PrimitiveTypeWrapper.FLOAT;
+ }
+ else if(type == typeof(int))
+ {
+ return PrimitiveTypeWrapper.INT;
+ }
+ else if(type == typeof(long))
+ {
+ return PrimitiveTypeWrapper.LONG;
+ }
+ else if(type == typeof(short))
+ {
+ return PrimitiveTypeWrapper.SHORT;
+ }
+ else if(type == typeof(bool))
+ {
+ return PrimitiveTypeWrapper.BOOLEAN;
+ }
+ }
+ wrapper = GetBootstrapClassLoader().GetCompiledTypeWrapper(type);
+ }
+ return wrapper;
+ }
+
+ internal static void SetWrapperForType(Type type, TypeWrapper wrapper)
+ {
+ Debug.Assert(!(type is TypeBuilder));
+ typeToTypeWrapper.Add(type, wrapper);
+ }
+
+ // name is dot separated (e.g. java.lang.Object)
+ internal static Type GetType(string name)
+ {
+ TypeWrapper wrapper = GetBootstrapClassLoader().LoadClassByDottedName(name);
+ // TODO think about this Finish here
+ wrapper.Finish();
+ return wrapper.Type;
+ }
+}
diff --git a/IK.VM.NET/DoubleToString.cs b/IK.VM.NET/DoubleToString.cs
new file mode 100644
index 00000000..1078c761
--- /dev/null
+++ b/IK.VM.NET/DoubleToString.cs
@@ -0,0 +1,539 @@
+// NOTE this code was adapted from source code accompanying the article
+// http://www.onjava.com/pub/a/onjava/2000/12/15/formatting_doubles.html?page=2
+// by Jack Shirazi
+
+using System;
+using System.Text;
+
+public class DoubleToString
+{
+ //Hardcode some arrays to make them quickly available
+ private static readonly string[] ZEROS = new string[] {
+ "",
+ "0",
+ "00",
+ "000",
+ "0000",
+ "00000",
+ "000000",
+ "0000000",
+ "00000000",
+ "000000000",
+ "0000000000",
+ "00000000000",
+ "000000000000",
+ "0000000000000",
+ "00000000000000",
+ "000000000000000",
+ "0000000000000000",
+ "00000000000000000",
+ "000000000000000000",
+ "0000000000000000000",
+ "00000000000000000000"
+ };
+
+ private static readonly char[] charForDigit = new char[] {
+ '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h',
+ 'i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'
+ };
+
+ //And required double related constants.
+ private const long DoubleSignMask = long.MinValue;
+ private const long DoubleExpMask = 0x7ff0000000000000L;
+ private const long DoubleFractMask= ~(DoubleSignMask|DoubleExpMask);
+ private const int DoubleExpShift = 52;
+ private const int DoubleExpBias = 1023;
+
+ private static readonly double[] d_tenthPowers = new double[] {
+ 1e-323D, 1e-322D, 1e-321D, 1e-320D, 1e-319D, 1e-318D, 1e-317D, 1e-316D, 1e-315D, 1e-314D,
+ 1e-313D, 1e-312D, 1e-311D, 1e-310D, 1e-309D, 1e-308D, 1e-307D, 1e-306D, 1e-305D, 1e-304D,
+ 1e-303D, 1e-302D, 1e-301D, 1e-300D, 1e-299D, 1e-298D, 1e-297D, 1e-296D, 1e-295D, 1e-294D,
+ 1e-293D, 1e-292D, 1e-291D, 1e-290D, 1e-289D, 1e-288D, 1e-287D, 1e-286D, 1e-285D, 1e-284D,
+ 1e-283D, 1e-282D, 1e-281D, 1e-280D, 1e-279D, 1e-278D, 1e-277D, 1e-276D, 1e-275D, 1e-274D,
+ 1e-273D, 1e-272D, 1e-271D, 1e-270D, 1e-269D, 1e-268D, 1e-267D, 1e-266D, 1e-265D, 1e-264D,
+ 1e-263D, 1e-262D, 1e-261D, 1e-260D, 1e-259D, 1e-258D, 1e-257D, 1e-256D, 1e-255D, 1e-254D,
+ 1e-253D, 1e-252D, 1e-251D, 1e-250D, 1e-249D, 1e-248D, 1e-247D, 1e-246D, 1e-245D, 1e-244D,
+ 1e-243D, 1e-242D, 1e-241D, 1e-240D, 1e-239D, 1e-238D, 1e-237D, 1e-236D, 1e-235D, 1e-234D,
+ 1e-233D, 1e-232D, 1e-231D, 1e-230D, 1e-229D, 1e-228D, 1e-227D, 1e-226D, 1e-225D, 1e-224D,
+ 1e-223D, 1e-222D, 1e-221D, 1e-220D, 1e-219D, 1e-218D, 1e-217D, 1e-216D, 1e-215D, 1e-214D,
+ 1e-213D, 1e-212D, 1e-211D, 1e-210D, 1e-209D, 1e-208D, 1e-207D, 1e-206D, 1e-205D, 1e-204D,
+ 1e-203D, 1e-202D, 1e-201D, 1e-200D, 1e-199D, 1e-198D, 1e-197D, 1e-196D, 1e-195D, 1e-194D,
+ 1e-193D, 1e-192D, 1e-191D, 1e-190D, 1e-189D, 1e-188D, 1e-187D, 1e-186D, 1e-185D, 1e-184D,
+ 1e-183D, 1e-182D, 1e-181D, 1e-180D, 1e-179D, 1e-178D, 1e-177D, 1e-176D, 1e-175D, 1e-174D,
+ 1e-173D, 1e-172D, 1e-171D, 1e-170D, 1e-169D, 1e-168D, 1e-167D, 1e-166D, 1e-165D, 1e-164D,
+ 1e-163D, 1e-162D, 1e-161D, 1e-160D, 1e-159D, 1e-158D, 1e-157D, 1e-156D, 1e-155D, 1e-154D,
+ 1e-153D, 1e-152D, 1e-151D, 1e-150D, 1e-149D, 1e-148D, 1e-147D, 1e-146D, 1e-145D, 1e-144D,
+ 1e-143D, 1e-142D, 1e-141D, 1e-140D, 1e-139D, 1e-138D, 1e-137D, 1e-136D, 1e-135D, 1e-134D,
+ 1e-133D, 1e-132D, 1e-131D, 1e-130D, 1e-129D, 1e-128D, 1e-127D, 1e-126D, 1e-125D, 1e-124D,
+ 1e-123D, 1e-122D, 1e-121D, 1e-120D, 1e-119D, 1e-118D, 1e-117D, 1e-116D, 1e-115D, 1e-114D,
+ 1e-113D, 1e-112D, 1e-111D, 1e-110D, 1e-109D, 1e-108D, 1e-107D, 1e-106D, 1e-105D, 1e-104D,
+ 1e-103D, 1e-102D, 1e-101D, 1e-100D, 1e-99D, 1e-98D, 1e-97D, 1e-96D, 1e-95D, 1e-94D,
+ 1e-93D, 1e-92D, 1e-91D, 1e-90D, 1e-89D, 1e-88D, 1e-87D, 1e-86D, 1e-85D, 1e-84D,
+ 1e-83D, 1e-82D, 1e-81D, 1e-80D, 1e-79D, 1e-78D, 1e-77D, 1e-76D, 1e-75D, 1e-74D,
+ 1e-73D, 1e-72D, 1e-71D, 1e-70D, 1e-69D, 1e-68D, 1e-67D, 1e-66D, 1e-65D, 1e-64D,
+ 1e-63D, 1e-62D, 1e-61D, 1e-60D, 1e-59D, 1e-58D, 1e-57D, 1e-56D, 1e-55D, 1e-54D,
+ 1e-53D, 1e-52D, 1e-51D, 1e-50D, 1e-49D, 1e-48D, 1e-47D, 1e-46D, 1e-45D, 1e-44D,
+ 1e-43D, 1e-42D, 1e-41D, 1e-40D, 1e-39D, 1e-38D, 1e-37D, 1e-36D, 1e-35D, 1e-34D,
+ 1e-33D, 1e-32D, 1e-31D, 1e-30D, 1e-29D, 1e-28D, 1e-27D, 1e-26D, 1e-25D, 1e-24D,
+ 1e-23D, 1e-22D, 1e-21D, 1e-20D, 1e-19D, 1e-18D, 1e-17D, 1e-16D, 1e-15D, 1e-14D,
+ 1e-13D, 1e-12D, 1e-11D, 1e-10D, 1e-9D, 1e-8D, 1e-7D, 1e-6D, 1e-5D, 1e-4D,
+ 1e-3D, 1e-2D, 1e-1D, 1e0D, 1e1D, 1e2D, 1e3D, 1e4D,
+ 1e5D, 1e6D, 1e7D, 1e8D, 1e9D, 1e10D, 1e11D, 1e12D, 1e13D, 1e14D,
+ 1e15D, 1e16D, 1e17D, 1e18D, 1e19D, 1e20D, 1e21D, 1e22D, 1e23D, 1e24D,
+ 1e25D, 1e26D, 1e27D, 1e28D, 1e29D, 1e30D, 1e31D, 1e32D, 1e33D, 1e34D,
+ 1e35D, 1e36D, 1e37D, 1e38D, 1e39D, 1e40D, 1e41D, 1e42D, 1e43D, 1e44D,
+ 1e45D, 1e46D, 1e47D, 1e48D, 1e49D, 1e50D, 1e51D, 1e52D, 1e53D, 1e54D,
+ 1e55D, 1e56D, 1e57D, 1e58D, 1e59D, 1e60D, 1e61D, 1e62D, 1e63D, 1e64D,
+ 1e65D, 1e66D, 1e67D, 1e68D, 1e69D, 1e70D, 1e71D, 1e72D, 1e73D, 1e74D,
+ 1e75D, 1e76D, 1e77D, 1e78D, 1e79D, 1e80D, 1e81D, 1e82D, 1e83D, 1e84D,
+ 1e85D, 1e86D, 1e87D, 1e88D, 1e89D, 1e90D, 1e91D, 1e92D, 1e93D, 1e94D,
+ 1e95D, 1e96D, 1e97D, 1e98D, 1e99D, 1e100D, 1e101D, 1e102D, 1e103D, 1e104D,
+ 1e105D, 1e106D, 1e107D, 1e108D, 1e109D, 1e110D, 1e111D, 1e112D, 1e113D, 1e114D,
+ 1e115D, 1e116D, 1e117D, 1e118D, 1e119D, 1e120D, 1e121D, 1e122D, 1e123D, 1e124D,
+ 1e125D, 1e126D, 1e127D, 1e128D, 1e129D, 1e130D, 1e131D, 1e132D, 1e133D, 1e134D,
+ 1e135D, 1e136D, 1e137D, 1e138D, 1e139D, 1e140D, 1e141D, 1e142D, 1e143D, 1e144D,
+ 1e145D, 1e146D, 1e147D, 1e148D, 1e149D, 1e150D, 1e151D, 1e152D, 1e153D, 1e154D,
+ 1e155D, 1e156D, 1e157D, 1e158D, 1e159D, 1e160D, 1e161D, 1e162D, 1e163D, 1e164D,
+ 1e165D, 1e166D, 1e167D, 1e168D, 1e169D, 1e170D, 1e171D, 1e172D, 1e173D, 1e174D,
+ 1e175D, 1e176D, 1e177D, 1e178D, 1e179D, 1e180D, 1e181D, 1e182D, 1e183D, 1e184D,
+ 1e185D, 1e186D, 1e187D, 1e188D, 1e189D, 1e190D, 1e191D, 1e192D, 1e193D, 1e194D,
+ 1e195D, 1e196D, 1e197D, 1e198D, 1e199D, 1e200D, 1e201D, 1e202D, 1e203D, 1e204D,
+ 1e205D, 1e206D, 1e207D, 1e208D, 1e209D, 1e210D, 1e211D, 1e212D, 1e213D, 1e214D,
+ 1e215D, 1e216D, 1e217D, 1e218D, 1e219D, 1e220D, 1e221D, 1e222D, 1e223D, 1e224D,
+ 1e225D, 1e226D, 1e227D, 1e228D, 1e229D, 1e230D, 1e231D, 1e232D, 1e233D, 1e234D,
+ 1e235D, 1e236D, 1e237D, 1e238D, 1e239D, 1e240D, 1e241D, 1e242D, 1e243D, 1e244D,
+ 1e245D, 1e246D, 1e247D, 1e248D, 1e249D, 1e250D, 1e251D, 1e252D, 1e253D, 1e254D,
+ 1e255D, 1e256D, 1e257D, 1e258D, 1e259D, 1e260D, 1e261D, 1e262D, 1e263D, 1e264D,
+ 1e265D, 1e266D, 1e267D, 1e268D, 1e269D, 1e270D, 1e271D, 1e272D, 1e273D, 1e274D,
+ 1e275D, 1e276D, 1e277D, 1e278D, 1e279D, 1e280D, 1e281D, 1e282D, 1e283D, 1e284D,
+ 1e285D, 1e286D, 1e287D, 1e288D, 1e289D, 1e290D, 1e291D, 1e292D, 1e293D, 1e294D,
+ 1e295D, 1e296D, 1e297D, 1e298D, 1e299D, 1e300D, 1e301D, 1e302D, 1e303D, 1e304D,
+ 1e305D, 1e306D, 1e307D, 1e308D
+ };
+
+
+ public void appendFormatted(StringBuilder s, double d, int numFractDigits,
+ char decimalPoint, char thousandsSeparator, int numDigitsSeparated,
+ char negativePrefix, char negativeSuffix)
+ {
+ //First check for the special cases, +/-infinity, Not-a-number and -0.0
+ if (d == double.NegativeInfinity)
+ {
+ //d == -Infinity
+ if (negativePrefix != '\uFFFF')
+ s.Append(negativePrefix);
+ s.Append("Infinity");
+ if (negativeSuffix != '\uFFFF')
+ s.Append(negativeSuffix);
+ }
+ else if (d == double.PositiveInfinity)
+ //d == Infinity
+ s.Append("Infinity");
+ else if (d != d)
+ //d == NaN
+ s.Append("NaN");
+ else if (d == 0.0)
+ {
+ if ( (BitConverter.DoubleToInt64Bits(d) & DoubleSignMask) != 0)
+ {
+ //d == -0.0
+ if (negativePrefix != '\uFFFF')
+ s.Append(negativePrefix);
+ s.Append('0').Append(decimalPoint).Append(ZEROS[numFractDigits]);
+ if (negativeSuffix != '\uFFFF')
+ s.Append(negativeSuffix);
+ }
+ else
+ //d == 0.0
+ s.Append('0').Append(decimalPoint).Append(ZEROS[numFractDigits]);
+ }
+ else
+ {
+ //convert to a positive format, and record whether we have a negative
+ //number so that we know later whether to add the negativeSuffix
+ bool negative = false;
+ if (d < 0)
+ {
+ //Even if the number is negative, we only need to set the
+ //negative flag if there is a printable negativeSuffix
+ if (negativeSuffix != '\uFFFF')
+ negative = true;
+ if (negativePrefix != '\uFFFF')
+ s.Append(negativePrefix);
+ d = -d;
+ }
+
+ //Find the magnitude. This is basically the exponent in normal form.
+ int mag = magnitude(d);
+
+ //First off, if the number is too small for the given format, we
+ //only print 0.0..., which makes this real quick
+ if ( (mag + numFractDigits) < 0)
+ {
+ appendNearlyZeroNumber(s, d, mag, numFractDigits, decimalPoint);
+ if (negative)
+ s.Append(negativeSuffix);
+ return;
+ }
+
+ long l;
+ //Now scale the double to the biggest long value we need
+ //We need to handle the smallest magnitudes differently because of rounding errors
+
+ //This test is unlikely to ever be true. It would require numFractDigits
+ //to be 305 or more, which is pretty unlikely.
+ if (mag < -305)
+ l = (long) ((d*1E18) / d_tenthPowers[mag + 324]);
+ else
+ l = (long) (d / d_tenthPowers[mag + 323 - 17]);
+
+ //And round up if necessary. Add one to the numFractDigits digit if the
+ //numFractDigits+1 digit is 5 or greater. It is useful to know that
+ //given a long, l, the nth digit is obtained using the formula
+ // nthDigit = (l/(tenthPower(l)/l_tenthPowers[n-1]))%10;
+
+ long l_tenthPower = tenthPower(l);
+ //The numFractDigits+1 digit of the double is the
+ //numFractDigits+1+magnitude digit of the long.
+ //We only need worry about digits within the long. Very large numbers are
+ //not rounded because all the digits after the decimal points are 0 anyway
+ if (numFractDigits+mag+1 < l_tenthPowers.Length)
+ {
+ long digit = (l/(l_tenthPower/l_tenthPowers[numFractDigits+mag+1]))%10;
+ if (digit >= 5)
+ {
+ l += l_tenthPower/l_tenthPowers[numFractDigits+mag];
+ }
+ }
+
+ //And now we just print out our long, with the decimal point character
+ //inserted in the right place, using as many places as we wanted.
+ appendAsDouble(s, l, l_tenthPower, mag, numFractDigits, decimalPoint, thousandsSeparator,
+ numDigitsSeparated, negativePrefix, negativeSuffix);
+
+ //Finally, append the negativeSuffix if necessary
+ if (negative)
+ s.Append(negativeSuffix);
+ }
+ }
+
+ public void appendAsDouble(StringBuilder s, long l, long l_mag, int d_magnitude,
+ int numFractDigits, char decimalPoint, char thousandsSeparator,
+ int numDigitsSeparated, char negativePrefix, char negativeSuffix)
+ {
+ //If the magnitude is negative, we have a 0.xxx number
+ if (d_magnitude < 0)
+ {
+ s.Append('0').Append(decimalPoint).Append(ZEROS[-d_magnitude-1]);
+ //And just print successive digits until we have reached numFractDigits
+ //First decrement numFractDigits by the number of digits already printed
+ numFractDigits += d_magnitude;
+
+ //get the magnitude of l
+ long c;
+ while(numFractDigits-- >= 0)
+ {
+ //Get the leading character (e.g. '62345/10000 = 6' using integer-divide)
+ c = l/l_mag;
+ //Append the digit character for this digit (e.g. number is 6, so character is '6')
+ s.Append(charForDigit[(int) c]);
+ //Multiply by the leading digit by the magnitude so that we can eliminate the leading digit
+ //(e.g. 6 * 10000 = 60000)
+ c *= l_mag;
+ //and eliminate the leading digit (e.g. 62345-60000 = 2345)
+ if ( c <= l)
+ l -= c;
+ //Decrease the magnitude by 10, and repeat the loop.
+ l_mag = l_mag/10;
+ }
+ }
+ else
+ {
+ //Just keep printing until magnitude is 0
+ long c;
+ while(d_magnitude-- >= 0)
+ {
+ if (l_mag == 0) {s.Append('0');continue;}
+ //Get the leading character (e.g. '62345/10000 = 6' using integer-divide)
+ c = l/l_mag;
+ //Append the digit character for this digit (e.g. number is 6, so character is '6')
+ s.Append(charForDigit[(int) c]);
+
+ //Don't forget about the thousands separator
+ if (d_magnitude % numDigitsSeparated == (numDigitsSeparated-1))
+ s.Append(thousandsSeparator);
+
+ //Multiply by the leading digit by the magnitude so that we can eliminate the leading digit
+ //(e.g. 6 * 10000 = 60000)
+ c *= l_mag;
+ //and eliminate the leading digit (e.g. 62345-60000 = 2345)
+ if ( c <= l)
+ l -= c;
+ //Decrease the magnitude by 10, and repeat the loop.
+ l_mag = l_mag/10;
+ }
+ s.Append(decimalPoint);
+ if (l_mag == 0)
+ s.Append(ZEROS[numFractDigits]);
+ else
+ {
+ while(numFractDigits-- > 0)
+ {
+ if (l_mag == 0) {s.Append('0');continue;}
+ //Get the leading character (e.g. '62345/10000 = 6' using integer-divide)
+ c = l/l_mag;
+ //Append the digit character for this digit (e.g. number is 6, so character is '6')
+ s.Append(charForDigit[(int) c]);
+ //Multiply by the leading digit by the magnitude so that we can eliminate the leading digit
+ //(e.g. 6 * 10000 = 60000)
+ c *= l_mag;
+ //and eliminate the leading digit (e.g. 62345-60000 = 2345)
+ if ( c <= l)
+ l -= c;
+ //Decrease the magnitude by 10, and repeat the loop.
+ l_mag = l_mag/10;
+ }
+ }
+ }
+ }
+
+ private void appendNearlyZeroNumber(StringBuilder s, double d, int d_magnitude,
+ int numFractDigits, char decimalPoint)
+ {
+ if (d_magnitude + numFractDigits == -1)
+ {
+ //Possibly too small, depends on whether the top digit is 5 or greater
+ //So we have to scale to get the leading digit
+ int i;
+ if (d_magnitude < -305)
+ //Probably not necessary. Who is going to print 305 places?
+ i = (int) ((d*1E19) / d_tenthPowers[d_magnitude + 324 + 18]);
+ else
+ i = (int) (d / d_tenthPowers[d_magnitude + 323]);
+
+ if (i >= 5)
+ {
+ //Not too small, we get to round up
+ s.Append('0').Append(decimalPoint).Append(ZEROS[numFractDigits-1]);
+ s.Append('1');
+ }
+ else
+ {
+ //Definitely too small. Just print zeros
+ s.Append('0').Append(decimalPoint).Append(ZEROS[numFractDigits]);
+ }
+ }
+ else
+ {
+ //Definitely too small
+ s.Append('0').Append(decimalPoint).Append(ZEROS[numFractDigits]);
+ }
+ }
+
+ /**
+ * Assumes i is positive. Returns the magnitude of i in base 10.
+ */
+ private static long tenthPower(long i)
+ {
+ if (i < 10L) return 1;
+ else if (i < 100L) return 10L;
+ else if (i < 1000L) return 100L;
+ else if (i < 10000L) return 1000L;
+ else if (i < 100000L) return 10000L;
+ else if (i < 1000000L) return 100000L;
+ else if (i < 10000000L) return 1000000L;
+ else if (i < 100000000L) return 10000000L;
+ else if (i < 1000000000L) return 100000000L;
+ else if (i < 10000000000L) return 1000000000L;
+ else if (i < 100000000000L) return 10000000000L;
+ else if (i < 1000000000000L) return 100000000000L;
+ else if (i < 10000000000000L) return 1000000000000L;
+ else if (i < 100000000000000L) return 10000000000000L;
+ else if (i < 1000000000000000L) return 100000000000000L;
+ else if (i < 10000000000000000L) return 1000000000000000L;
+ else if (i < 100000000000000000L) return 10000000000000000L;
+ else if (i < 1000000000000000000L) return 100000000000000000L;
+ else return 1000000000000000000L;
+ }
+
+ private static int magnitude(double d)
+ {
+ //It works. What else can I say.
+ long doubleToLongBits = BitConverter.DoubleToInt64Bits(d);
+ int magnitude =
+ (int) ((((doubleToLongBits & DoubleExpMask) >> DoubleExpShift) - DoubleExpBias) * 0.301029995663981);
+
+ if (magnitude < -323)
+ magnitude = -323;
+ else if (magnitude > 308)
+ magnitude = 308;
+
+ if (d >= d_tenthPowers[magnitude+323])
+ {
+ while(magnitude < 309 && d >= d_tenthPowers[magnitude+323])
+ magnitude++;
+ magnitude--;
+ return magnitude;
+ }
+ else
+ {
+ while(magnitude > -324 && d < d_tenthPowers[magnitude+323])
+ magnitude--;
+ return magnitude;
+ }
+ }
+
+ private static long[] l_tenthPowers = {
+ 1,
+ 10L,
+ 100L,
+ 1000L,
+ 10000L,
+ 100000L,
+ 1000000L,
+ 10000000L,
+ 100000000L,
+ 1000000000L,
+ 10000000000L,
+ 100000000000L,
+ 1000000000000L,
+ 10000000000000L,
+ 100000000000000L,
+ 1000000000000000L,
+ 10000000000000000L,
+ 100000000000000000L,
+ 1000000000000000000L,
+ };
+
+ public static void append(StringBuilder s, double d)
+ {
+ if (d == double.NegativeInfinity)
+ s.Append("-Infinity");
+ else if (d == double.PositiveInfinity)
+ s.Append("Infinity");
+ else if (d != d)
+ s.Append("NaN");
+ else if (d == 0.0)
+ {
+ if ( (BitConverter.DoubleToInt64Bits(d) & DoubleSignMask) != 0)
+ s.Append('-');
+ s.Append("0.0");
+ }
+ else
+ {
+ if (d < 0)
+ {
+ s.Append('-');
+ d = -d;
+ }
+
+ if (d >= 0.001 && d < 0.01)
+ {
+ long i = (long) (d * 1E20);
+ i = i%100 >= 50 ? (i/100) + 1 : i/100;
+ s.Append("0.00");
+ appendFractDigits(s, i,-1);
+ }
+ else if (d >= 0.01 && d < 0.1)
+ {
+ long i = (long) (d * 1E19);
+ i = i%100 >= 50 ? (i/100) + 1 : i/100;
+ s.Append("0.0");
+ appendFractDigits(s, i,-1);
+ }
+ else if (d >= 0.1 && d < 1)
+ {
+ long i = (long) (d * 1E18);
+ i = i%100 >= 50 ? (i/100) + 1 : i/100;
+ s.Append("0.");
+ appendFractDigits(s, i,-1);
+ }
+ else if (d >= 1 && d < 10)
+ {
+ long i = (long) (d * 1E17);
+ i = i%100 >= 50 ? (i/100) + 1 : i/100;
+ appendFractDigits(s, i,1);
+ }
+ else if (d >= 10 && d < 100)
+ {
+ long i = (long) (d * 1E16);
+ i = i%100 >= 50 ? (i/100) + 1 : i/100;
+ appendFractDigits(s, i,2);
+ }
+ else if (d >= 100 && d < 1000)
+ {
+ long i = (long) (d * 1E15);
+ i = i%100 >= 50 ? (i/100) + 1 : i/100;
+ appendFractDigits(s, i,3);
+ }
+ else if (d >= 1000 && d < 10000)
+ {
+ long i = (long) (d * 1E14);
+ i = i%100 >= 50 ? (i/100) + 1 : i/100;
+ appendFractDigits(s, i,4);
+ }
+ else if (d >= 10000 && d < 100000)
+ {
+ long i = (long) (d * 1E13);
+ i = i%100 >= 50 ? (i/100) + 1 : i/100;
+ appendFractDigits(s, i,5);
+ }
+ else if (d >= 100000 && d < 1000000)
+ {
+ long i = (long) (d * 1E12);
+ i = i%100 >= 50 ? (i/100) + 1 : i/100;
+ appendFractDigits(s, i,6);
+ }
+ else if (d >= 1000000 && d < 10000000)
+ {
+ long i = (long) (d * 1E11);
+ i = i%100 >= 50 ? (i/100) + 1 : i/100;
+ appendFractDigits(s, i,7);
+ }
+ else
+ {
+ int mag = magnitude(d);
+ long i;
+ if (mag < -305)
+ i = (long) (d*1E18 / d_tenthPowers[mag + 324]);
+ else
+ i = (long) (d / d_tenthPowers[mag + 323 - 17]);
+ i = i%100 >= 50 ? (i/100) + 1 : i/100;
+ appendFractDigits(s, i, 1);
+ s.Append('E');
+ append(s,mag);
+ }
+ }
+ }
+
+ private static void appendFractDigits(StringBuilder s, long i, int decimalOffset)
+ {
+ long mag = tenthPower(i);
+ long c;
+ while ( i > 0 )
+ {
+ c = i/mag;
+ s.Append(charForDigit[(int) c]);
+ decimalOffset--;
+ if (decimalOffset == 0)
+ s.Append('.');
+ c *= mag;
+ if ( c <= i)
+ i -= c;
+ mag = mag/10;
+ }
+ if (i != 0)
+ s.Append(charForDigit[(int) i]);
+ else if (decimalOffset > 0)
+ {
+ s.Append(ZEROS[decimalOffset]);
+ decimalOffset = 1;
+ }
+
+ decimalOffset--;
+ if (decimalOffset == 0)
+ s.Append(".0");
+ else if (decimalOffset == -1)
+ s.Append('0');
+ }
+}
diff --git a/IK.VM.NET/ExceptionHelper.cs b/IK.VM.NET/ExceptionHelper.cs
new file mode 100644
index 00000000..125ead50
--- /dev/null
+++ b/IK.VM.NET/ExceptionHelper.cs
@@ -0,0 +1,659 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+using System.Reflection;
+using System.Diagnostics;
+using System.Text;
+using System.Collections;
+using java.lang;
+using ClassHelper = NativeCode.java.lang.Class;
+
+public class ExceptionHelper
+{
+ // the contents of the NULL_STRING should be empty (because when the exception propagates to other .NET code
+ // it will return that text as the Message property), but it *must* be a copy, because we need to be
+ // able to distinguish it from a user specified blank string
+ private static readonly string NULL_STRING = string.Copy("");
+
+ private class ExceptionInfoHelper
+ {
+ private static readonly Exception CAUSE_NOT_SET = new Exception();
+ private ArrayList stackTrace = new ArrayList();
+ private Exception cause;
+
+ [StackTraceInfo(Hidden = true)]
+ internal ExceptionInfoHelper(Exception x)
+ {
+ Append(new StackTrace(x, true));
+ bool chopFirst = stackTrace.Count != 0;
+ Append(new StackTrace(true));
+ if(chopFirst && stackTrace.Count > 0 && JVM.CleanStackTraces)
+ {
+ stackTrace.RemoveAt(0);
+ }
+ cause = x.InnerException;
+ if(cause == null)
+ {
+ cause = CAUSE_NOT_SET;
+ }
+ }
+
+ internal Exception Cause
+ {
+ get
+ {
+ return cause == CAUSE_NOT_SET ? null : cause;
+ }
+ set
+ {
+ if(cause == CAUSE_NOT_SET)
+ {
+ cause = value;
+ }
+ else
+ {
+ throw JavaException.IllegalStateException("Throwable cause already initialized");
+ }
+ }
+ }
+
+ internal void ResetStackTrace()
+ {
+ stackTrace.Clear();
+ Append(new StackTrace(true));
+ }
+
+ private static bool IsPrivateScope(MethodBase mb)
+ {
+ // HACK shouldn't there be a better way to determine whether a method is privatescope?
+ return !mb.IsPrivate && !mb.IsFamily && !mb.IsFamilyAndAssembly && !mb.IsFamilyOrAssembly && !mb.IsPublic;
+ }
+
+ private void Append(StackTrace st)
+ {
+ if(st.FrameCount > 0)
+ {
+ int baseSize = stackTrace.Count;
+ for(int i = 0; i < st.FrameCount; i++)
+ {
+ StackFrame frame = st.GetFrame(i);
+ MethodBase m = frame.GetMethod();
+ // TODO I may need more safety checks like these
+ if(m.DeclaringType == null || m.ReflectedType == null)
+ {
+ continue;
+ }
+ if(m.DeclaringType == typeof(System.Runtime.CompilerServices.RuntimeHelpers)
+ || m.DeclaringType == typeof(JNI) // HACK we exclude the JNI class from the stack trace
+ || m.DeclaringType.IsSubclassOf(typeof(System.Reflection.MethodInfo))
+ || IsPrivateScope(m)) // NOTE we assume that privatescope methods are always stubs that we should exclude
+ {
+ if(JVM.CleanStackTraces)
+ {
+ continue;
+ }
+ }
+ string methodName = frame.GetMethod().Name;
+ if(methodName == ".ctor")
+ {
+ methodName = "<init>";
+ }
+ else if(methodName == ".cctor")
+ {
+ methodName = "<clinit>";
+ }
+ int lineNumber = frame.GetFileLineNumber();
+ if(lineNumber == 0)
+ {
+ lineNumber = -1;
+ }
+ string fileName = frame.GetFileName();
+ if(fileName != null)
+ {
+ fileName = new System.IO.FileInfo(fileName).Name;
+ }
+ string className = ClassHelper.getName(frame.GetMethod().ReflectedType);
+ bool native = false;
+ if(m.IsDefined(typeof(ModifiersAttribute), false))
+ {
+ object[] methodFlagAttribs = m.GetCustomAttributes(typeof(ModifiersAttribute), false);
+ if(methodFlagAttribs.Length == 1)
+ {
+ ModifiersAttribute modifiersAttrib = (ModifiersAttribute)methodFlagAttribs[0];
+ if(modifiersAttrib.IsSynthetic)
+ {
+ continue;
+ }
+ if((modifiersAttrib.Modifiers & Modifiers.Native) != 0)
+ {
+ native = true;
+ }
+ }
+ }
+ if(JVM.CleanStackTraces)
+ {
+ object[] attribs = m.DeclaringType.GetCustomAttributes(typeof(StackTraceInfoAttribute), false);
+ if(attribs.Length == 1)
+ {
+ StackTraceInfoAttribute sta = (StackTraceInfoAttribute)attribs[0];
+ if(sta.EatFrames > 0)
+ {
+ stackTrace.RemoveRange(stackTrace.Count - sta.EatFrames, sta.EatFrames);
+ }
+ if(sta.Hidden)
+ {
+ continue;
+ }
+ if(sta.Truncate)
+ {
+ stackTrace.RemoveRange(baseSize, stackTrace.Count - baseSize);
+ continue;
+ }
+ if(sta.Class != null)
+ {
+ className = sta.Class;
+ }
+ }
+ attribs = m.GetCustomAttributes(typeof(StackTraceInfoAttribute), false);
+ if(attribs.Length == 1)
+ {
+ StackTraceInfoAttribute sta = (StackTraceInfoAttribute)attribs[0];
+ if(sta.EatFrames > 0)
+ {
+ int eat = Math.Min(stackTrace.Count, sta.EatFrames);
+ stackTrace.RemoveRange(stackTrace.Count - eat, eat);
+ }
+ if(sta.Hidden)
+ {
+ continue;
+ }
+ if(sta.Truncate)
+ {
+ stackTrace.RemoveRange(baseSize, stackTrace.Count - baseSize);
+ continue;
+ }
+ if(sta.Class != null)
+ {
+ className = sta.Class;
+ }
+ }
+ }
+ stackTrace.Add(new StackTraceElement(fileName, lineNumber, className, methodName, native));
+ }
+ if(JVM.CleanStackTraces)
+ {
+ int chop = 0;
+ for(int i = stackTrace.Count - 1; i >= 0; i--)
+ {
+ StackTraceElement ste = (StackTraceElement)stackTrace[i];
+ if(ste.getClassName() == "System.Reflection.RuntimeMethodInfo")
+ {
+ // skip method invocation by reflection, if it is at the top of the stack
+ chop++;
+ }
+ else
+ {
+ break;
+ }
+ }
+ stackTrace.RemoveRange(stackTrace.Count - chop, chop);
+ }
+ }
+ }
+
+ internal StackTraceElement[] StackTrace
+ {
+ get
+ {
+ return (StackTraceElement[])stackTrace.ToArray(typeof(StackTraceElement));
+ }
+ set
+ {
+ stackTrace = new ArrayList(value);
+ }
+ }
+ }
+
+ // TODO this should be an "identity" hashtable instead of "equality"
+ private static WeakHashtable exceptions = new WeakHashtable();
+
+ public static void printStackTrace(Exception x)
+ {
+ if(x == null)
+ {
+ throw new NullReferenceException();
+ }
+ Type type = ClassLoaderWrapper.GetType("java.lang.System");
+ object err = type.GetProperty("err").GetValue(null, null);
+ printStackTrace(x, err);
+ }
+
+ public static void printStackTrace(Exception x, object printStreamOrWriter)
+ {
+ if(x == null)
+ {
+ throw new NullReferenceException();
+ }
+ StringBuilder sb = new StringBuilder();
+ sb.Append(toString_Virtual(x)).Append(Environment.NewLine);
+ StackTraceElement[] stack = getStackTrace_Virtual(x);
+ for(int i = 0; i < stack .Length; i++)
+ {
+ sb.Append("\tat ").Append(stack[i]).Append(Environment.NewLine);
+ }
+ Exception cause = getCause_Virtual(x);
+ while(cause != null)
+ {
+ sb.Append("Caused by: ").Append(toString_Virtual(cause)).Append(Environment.NewLine);
+
+ // Cause stacktrace
+ StackTraceElement[] parentStack = stack;
+ stack = getStackTrace_Virtual(cause);
+ bool equal = false; // Is rest of stack equal to parent frame?
+ for(int i = 0; i < stack.Length && !equal; i++)
+ {
+ // Check if we already printed the rest of the stack
+ // since it was the tail of the parent stack
+ int remaining = stack.Length - i;
+ int element = i;
+ int parentElement = parentStack.Length - remaining;
+ equal = parentElement >= 0
+ && parentElement < parentStack.Length; // be optimistic
+ while(equal && element < stack.Length)
+ {
+ if(stack[element].Equals(parentStack[parentElement]))
+ {
+ element++;
+ parentElement++;
+ }
+ else
+ {
+ equal = false;
+ }
+ }
+ // Print stacktrace element or indicate the rest is equal
+ if(!equal)
+ {
+ sb.Append("\tat ").Append(stack[i]).Append(Environment.NewLine);
+ }
+ else
+ {
+ sb.Append("\t... ").Append(remaining).Append(" more").Append(Environment.NewLine);
+ break; // from stack printing for loop
+ }
+ }
+ cause = getCause_Virtual(cause);
+ }
+ // NOTE since we use reflection to lookup the print method each time, we can use this one method for both
+ // the printStackTrace(..., PrintStream) & printStackTrace(..., PrintWriter) versions
+ MethodInfo write = printStreamOrWriter.GetType().GetMethod("print", BindingFlags.Public | BindingFlags.Instance, null, CallingConventions.Standard, new Type[] { typeof(string) }, null);
+ write.Invoke(printStreamOrWriter, new object[] { sb.ToString() });
+ }
+
+ public static Exception initCause(Exception x, Exception cause)
+ {
+ if(x == null)
+ {
+ throw new NullReferenceException();
+ }
+ if(cause == x)
+ {
+ throw JavaException.IllegalArgumentException("Cause cannot be self");
+ }
+ ExceptionInfoHelper eih = (ExceptionInfoHelper)exceptions[x];
+ if(eih == null)
+ {
+ eih = new ExceptionInfoHelper(x);
+ exceptions[x] = eih;
+ }
+ eih.Cause = cause;
+ return x;
+ }
+
+ public static Exception getCause(Exception x)
+ {
+ if(x == null)
+ {
+ throw new NullReferenceException();
+ }
+ ExceptionInfoHelper eih = (ExceptionInfoHelper)exceptions[x];
+ if(eih == null)
+ {
+ return x.InnerException;
+ }
+ return eih.Cause;
+ }
+
+ public static StackTraceElement[] getStackTrace(Exception x)
+ {
+ if(x == null)
+ {
+ throw new NullReferenceException();
+ }
+ ExceptionInfoHelper ei = (ExceptionInfoHelper)exceptions[x];
+ if(ei == null)
+ {
+ return new StackTraceElement[0];
+ }
+ return ei.StackTrace;
+ }
+
+ public static void setStackTrace(Exception x, StackTraceElement[] stackTrace)
+ {
+ if(x == null)
+ {
+ throw new NullReferenceException();
+ }
+ for(int i = 0; i < stackTrace.Length; i++)
+ {
+ if(stackTrace[i] == null)
+ {
+ throw new NullReferenceException();
+ }
+ }
+ ExceptionInfoHelper ei = (ExceptionInfoHelper)exceptions[x];
+ if(ei == null)
+ {
+ ei = new ExceptionInfoHelper(x);
+ exceptions[x] = ei;
+ }
+ ei.StackTrace = stackTrace;
+ }
+
+ public static string NullString
+ {
+ get
+ {
+ return NULL_STRING;
+ }
+ }
+
+ public static string FilterMessage(string message)
+ {
+ if(message == null)
+ {
+ message = NULL_STRING;
+ }
+ return message;
+ }
+
+ public static string GetMessageFromCause(Exception cause)
+ {
+ if(cause == null)
+ {
+ return NULL_STRING;
+ }
+ return toString_Virtual(cause);
+ }
+
+ public static string getMessage(Exception x)
+ {
+ if(x == null)
+ {
+ throw new NullReferenceException();
+ }
+ string message = x.Message;
+ if(message == NULL_STRING)
+ {
+ message = null;
+ }
+ return message;
+ }
+
+ public static string getLocalizedMessage(Exception x)
+ {
+ if(x == null)
+ {
+ throw new NullReferenceException();
+ }
+ return getMessage_Virtual(x);
+ }
+
+ [StackTraceInfo(Hidden = true)]
+ public static Exception fillInStackTrace(Exception x)
+ {
+ if(x == null)
+ {
+ throw new NullReferenceException();
+ }
+ ExceptionInfoHelper eih = (ExceptionInfoHelper)exceptions[x];
+ if(eih == null)
+ {
+ eih = new ExceptionInfoHelper(x);
+ exceptions[x] = eih;
+ }
+ else
+ {
+ eih.ResetStackTrace();
+ }
+ return x;
+ }
+
+ [StackTraceInfo(Hidden = true)]
+ public static Exception MapExceptionFast(Exception t)
+ {
+ if(exceptions.ContainsKey(t))
+ {
+ return t;
+ }
+ return MapException(t, typeof(Exception));
+ }
+
+ [StackTraceInfo(Truncate = true)]
+ public static Exception MapException(Exception t, Type handler)
+ {
+ //Console.WriteLine("MapException: {0}, {1}", t, handler);
+ //Console.WriteLine(new StackTrace(t));
+ Exception org = t;
+ Type type = t.GetType();
+ // TODO don't remap if the exception already has associated ExceptionInfoHelper object (this means
+ // that the .NET exception was thrown from Java code, explicitly).
+ if(type == typeof(NullReferenceException))
+ {
+ t = (Exception)Activator.CreateInstance(ClassLoaderWrapper.GetType("java.lang.NullPointerException"));
+ }
+ else if(type == typeof(IndexOutOfRangeException))
+ {
+ t = (Exception)Activator.CreateInstance(ClassLoaderWrapper.GetType("java.lang.ArrayIndexOutOfBoundsException"));
+ }
+ else if(type == typeof(InvalidCastException))
+ {
+ t = (Exception)Activator.CreateInstance(ClassLoaderWrapper.GetType("java.lang.ClassCastException"));
+ }
+ else if(type == typeof(TypeInitializationException))
+ {
+ t = (Exception)MapExceptionFast(t.InnerException);
+ if(!ClassLoaderWrapper.GetType("java.lang.Error").IsInstanceOfType(t))
+ {
+ ConstructorInfo constructor = ClassLoaderWrapper.GetType("java.lang.ExceptionInInitializerError").GetConstructor(new Type[] { typeof(Exception) });
+ t = (Exception)constructor.Invoke(new object[] { t });
+ }
+ }
+ else if(type == typeof(System.Threading.SynchronizationLockException))
+ {
+ t = (Exception)Activator.CreateInstance(ClassLoaderWrapper.GetType("java.lang.IllegalMonitorStateException"));
+ }
+ else if(type == typeof(System.Threading.ThreadInterruptedException))
+ {
+ t = (Exception)Activator.CreateInstance(ClassLoaderWrapper.GetType("java.lang.InterruptedException"));
+ }
+ else if(type == typeof(OutOfMemoryException))
+ {
+ t = (Exception)Activator.CreateInstance(ClassLoaderWrapper.GetType("java.lang.OutOfMemoryError"));
+ }
+ else if(type == typeof(DivideByZeroException))
+ {
+ t = (Exception)Activator.CreateInstance(ClassLoaderWrapper.GetType("java.lang.ArithmeticException"), new object[] { "/ by zero" });
+ }
+ else if(type == typeof(ArrayTypeMismatchException))
+ {
+ t = (Exception)Activator.CreateInstance(ClassLoaderWrapper.GetType("java.lang.ArrayStoreException"));
+ }
+ else if(type == typeof(StackOverflowException))
+ {
+ t = (Exception)Activator.CreateInstance(ClassLoaderWrapper.GetType("java.lang.StackOverflowError"));
+ }
+ else if(type == typeof(System.Security.VerificationException))
+ {
+ t = (Exception)Activator.CreateInstance(ClassLoaderWrapper.GetType("java.lang.VerifyError"));
+ }
+ else if(type == typeof(System.Threading.ThreadAbortException))
+ {
+ System.Threading.ThreadAbortException abort = (System.Threading.ThreadAbortException)t;
+ if(abort.ExceptionState is Exception)
+ {
+ t = (Exception)abort.ExceptionState;
+ }
+ else
+ {
+ t = (Exception)Activator.CreateInstance(ClassLoaderWrapper.GetType("java.lang.ThreadDeath"));
+ }
+ System.Threading.Thread.ResetAbort();
+ }
+ else if(type == typeof(OverflowException))
+ {
+ // TODO make sure the originating method was from an IK.VM.NET generated assembly, because if it was
+ // generated by non-Java code, this remapping is obviously bogus.
+ t = (Exception)Activator.CreateInstance(ClassLoaderWrapper.GetType("java.lang.NegativeArraySizeException"));
+ }
+ else if(type.FullName.StartsWith("System.") && type != typeof(TargetInvocationException))
+ {
+ // TODO this is just for debugging
+ Console.WriteLine("caught: {0}, handler: {1}", t.GetType().FullName, handler.FullName);
+ Console.WriteLine(t);
+ }
+ if(!exceptions.ContainsKey(t))
+ {
+ exceptions.Add(t, new ExceptionInfoHelper(org));
+ Exception inner = org.InnerException;
+ if(inner != null && !exceptions.ContainsKey(inner))
+ {
+ exceptions.Add(inner, new ExceptionInfoHelper(inner));
+ }
+ }
+ return handler.IsInstanceOfType(t) ? t : null;
+ }
+
+ public static string toString(Exception x)
+ {
+ if(x == null)
+ {
+ throw new NullReferenceException();
+ }
+ string message = getLocalizedMessage_Virtual(x);
+ if(message == null)
+ {
+ return ClassHelper.getName(x.GetType());
+ }
+ return ClassHelper.getName(x.GetType()) + ": " + message;
+ }
+
+ // below are some helper properties to support calling virtual methods on Throwable
+
+ private delegate string toString_Delegate(Exception x);
+ private static toString_Delegate toString_Virtual_;
+
+ private static toString_Delegate toString_Virtual
+ {
+ get
+ {
+ if(toString_Virtual_ == null)
+ {
+ MethodInfo method = ClassLoaderWrapper.GetType("java.lang.Throwable$VirtualMethodsHelper").GetMethod("toString");
+ toString_Virtual_ = (toString_Delegate)Delegate.CreateDelegate(typeof(toString_Delegate), method);
+ }
+ return toString_Virtual_;
+ }
+ }
+
+ private delegate string getMessage_Delegate(Exception x);
+ private static getMessage_Delegate getMessage_Virtual_;
+
+ private static getMessage_Delegate getMessage_Virtual
+ {
+ get
+ {
+ if(getMessage_Virtual_ == null)
+ {
+ MethodInfo method = ClassLoaderWrapper.GetType("java.lang.Throwable$VirtualMethodsHelper").GetMethod("getMessage");
+ getMessage_Virtual_ = (getMessage_Delegate)Delegate.CreateDelegate(typeof(getMessage_Delegate), method);
+ }
+ return getMessage_Virtual_;
+ }
+ }
+
+ private delegate StackTraceElement[] getStackTrace_Delegate(Exception x);
+ private static getStackTrace_Delegate getStackTrace_Virtual_;
+
+ private static getStackTrace_Delegate getStackTrace_Virtual
+ {
+ get
+ {
+ if(getStackTrace_Virtual_ == null)
+ {
+ MethodInfo method = ClassLoaderWrapper.GetType("java.lang.Throwable$VirtualMethodsHelper").GetMethod("getStackTrace");
+ getStackTrace_Virtual_ = (getStackTrace_Delegate)Delegate.CreateDelegate(typeof(getStackTrace_Delegate), method);
+ }
+ return getStackTrace_Virtual_;
+ }
+ }
+
+ private delegate Exception getCause_Delegate(Exception x);
+ private static getCause_Delegate getCause_Virtual_;
+
+ private static getCause_Delegate getCause_Virtual
+ {
+ get
+ {
+ if(getCause_Virtual_ == null)
+ {
+ MethodInfo method = ClassLoaderWrapper.GetType("java.lang.Throwable$VirtualMethodsHelper").GetMethod("getCause");
+ getCause_Virtual_ = (getCause_Delegate)Delegate.CreateDelegate(typeof(getCause_Delegate), method);
+ }
+ return getCause_Virtual_;
+ }
+ }
+
+ private delegate string getLocalizedMessage_Delegate(Exception x);
+ private static getLocalizedMessage_Delegate getLocalizedMessage_Virtual_;
+
+ private static getLocalizedMessage_Delegate getLocalizedMessage_Virtual
+ {
+ get
+ {
+ if(getLocalizedMessage_Virtual_ == null)
+ {
+ MethodInfo method = ClassLoaderWrapper.GetType("java.lang.Throwable$VirtualMethodsHelper").GetMethod("getLocalizedMessage");
+ getLocalizedMessage_Virtual_ = (getLocalizedMessage_Delegate)Delegate.CreateDelegate(typeof(getLocalizedMessage_Delegate), method);
+ }
+ return getLocalizedMessage_Virtual_;
+ }
+ }
+
+ [StackTraceInfo(Hidden = true)]
+ public static void ThrowHack(Exception x)
+ {
+ throw x;
+ }
+}
diff --git a/IK.VM.NET/IK.VM.NET.csproj b/IK.VM.NET/IK.VM.NET.csproj
new file mode 100644
index 00000000..a39ee5a0
--- /dev/null
+++ b/IK.VM.NET/IK.VM.NET.csproj
@@ -0,0 +1,192 @@
+<VisualStudioProject>
+ <CSHARP
+ ProjectType = "Local"
+ ProductVersion = "7.0.9466"
+ SchemaVersion = "1.0"
+ ProjectGuid = "{F5C7B588-0403-4AF2-A4DE-5697DE21BC2C}"
+ >
+ <Build>
+ <Settings
+ ApplicationIcon = ""
+ AssemblyKeyContainerName = ""
+ AssemblyName = "IK.VM.NET"
+ AssemblyOriginatorKeyFile = ""
+ DefaultClientScript = "JScript"
+ DefaultHTMLPageLayout = "Grid"
+ DefaultTargetSchema = "IE50"
+ DelaySign = "false"
+ OutputType = "Library"
+ RootNamespace = ""
+ StartupObject = ""
+ >
+ <Config
+ Name = "Debug"
+ AllowUnsafeBlocks = "false"
+ BaseAddress = "285212672"
+ CheckForOverflowUnderflow = "false"
+ ConfigurationOverrideFile = ""
+ DefineConstants = "DEBUG;TRACE"
+ DocumentationFile = ""
+ DebugSymbols = "true"
+ FileAlignment = "4096"
+ IncrementalBuild = "true"
+ Optimize = "false"
+ OutputPath = "bin\Debug\"
+ RegisterForComInterop = "false"
+ RemoveIntegerChecks = "false"
+ TreatWarningsAsErrors = "false"
+ WarningLevel = "4"
+ />
+ <Config
+ Name = "Release"
+ AllowUnsafeBlocks = "false"
+ BaseAddress = "285212672"
+ CheckForOverflowUnderflow = "false"
+ ConfigurationOverrideFile = ""
+ DefineConstants = "TRACE"
+ DocumentationFile = ""
+ DebugSymbols = "true"
+ FileAlignment = "4096"
+ IncrementalBuild = "false"
+ Optimize = "true"
+ OutputPath = "bin\Release\"
+ RegisterForComInterop = "false"
+ RemoveIntegerChecks = "false"
+ TreatWarningsAsErrors = "false"
+ WarningLevel = "4"
+ />
+ </Settings>
+ <References>
+ <Reference
+ Name = "System"
+ AssemblyName = "System"
+ HintPath = "..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.dll"
+ />
+ <Reference
+ Name = "System.Data"
+ AssemblyName = "System.Data"
+ HintPath = "..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Data.dll"
+ />
+ <Reference
+ Name = "System.XML"
+ AssemblyName = "System.Xml"
+ HintPath = "..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.XML.dll"
+ />
+ <Reference
+ Name = "IK.VM.JNI"
+ Project = "{4D400F9D-68A1-4066-95F6-85AF0E58B710}"
+ Package = "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}"
+ />
+ </References>
+ </Build>
+ <Files>
+ <Include>
+ <File
+ RelPath = "AssemblyInfo.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "attributes.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "BigEndianBinaryReader.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "ByteCode.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "ByteCodeHelper.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "ClassFile.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "ClassLoaderWrapper.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "classpath.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "compiler.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "DoubleToString.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "ExceptionHelper.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "JavaException.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "map.xml"
+ BuildAction = "EmbeddedResource"
+ />
+ <File
+ RelPath = "ObjectHelper.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "profiler.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "remapper.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "StringHelper.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "TypeWrapper.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "verifier.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "vm.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "WeakHashtable.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ </Include>
+ </Files>
+ </CSHARP>
+</VisualStudioProject>
+
diff --git a/IK.VM.NET/JavaException.cs b/IK.VM.NET/JavaException.cs
new file mode 100644
index 00000000..7e7cdb26
--- /dev/null
+++ b/IK.VM.NET/JavaException.cs
@@ -0,0 +1,148 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+using System.Reflection;
+
+sealed class JavaException
+{
+ private JavaException() {}
+
+ internal static Exception ClassFormatError(string s, params object[] args)
+ {
+ s = String.Format(s, args);
+ ConstructorInfo ci = ClassLoaderWrapper.GetType("java.lang.ClassFormatError").GetConstructor(new Type[] { typeof(string) });
+ return (Exception)ci.Invoke(new object[] { s });
+ }
+
+ internal static Exception UnsupportedClassVersionError(string s, params object[] args)
+ {
+ s = String.Format(s, args);
+ ConstructorInfo ci = ClassLoaderWrapper.GetType("java.lang.UnsupportedClassVersionError").GetConstructor(new Type[] { typeof(string) });
+ return (Exception)ci.Invoke(new object[] { s });
+ }
+
+ internal static Exception IllegalAccessError(string s, params object[] args)
+ {
+ s = String.Format(s, args);
+ ConstructorInfo ci = ClassLoaderWrapper.GetType("java.lang.IllegalAccessError").GetConstructor(new Type[] { typeof(string) });
+ return (Exception)ci.Invoke(new object[] { s });
+ }
+
+ internal static Exception VerifyError(string s, params object[] args)
+ {
+ s = String.Format(s, args);
+ ConstructorInfo ci = ClassLoaderWrapper.GetType("java.lang.VerifyError").GetConstructor(new Type[] { typeof(string) });
+ return (Exception)ci.Invoke(new object[] { s });
+ }
+
+ internal static Exception IncompatibleClassChangeError(string s, params object[] args)
+ {
+ s = String.Format(s, args);
+ ConstructorInfo ci = ClassLoaderWrapper.GetType("java.lang.IncompatibleClassChangeError").GetConstructor(new Type[] { typeof(string) });
+ return (Exception)ci.Invoke(new object[] { s });
+ }
+
+ [ThreadStatic]
+ private static bool classNotFound;
+
+ private class BootstrapClassMissing : Exception {}
+
+ internal static Exception ClassNotFoundException(string s, params object[] args)
+ {
+ // HACK if java.lang.ClassNotFoundException is not found, this method would recurse until the
+ // stack overflows, so in order to prevent that, we use this hack
+ if(JVM.IsStaticCompiler && classNotFound)
+ {
+ throw new BootstrapClassMissing();
+ }
+ try
+ {
+ classNotFound = true;
+ //Console.WriteLine("ClassNotFoundException: " + s);
+ s = String.Format(s, args);
+ ConstructorInfo ci = ClassLoaderWrapper.GetType("java.lang.ClassNotFoundException").GetConstructor(new Type[] { typeof(string) });
+ return (Exception)ci.Invoke(new object[] { s });
+ }
+ catch(BootstrapClassMissing)
+ {
+ throw new TypeLoadException("ClassNotFoundException: " + s);
+ }
+ finally
+ {
+ classNotFound = false;
+ }
+ }
+
+ internal static Exception NoClassDefFoundError(string s, params object[] args)
+ {
+ s = String.Format(s, args);
+ ConstructorInfo ci = ClassLoaderWrapper.GetType("java.lang.NoClassDefFoundError").GetConstructor(new Type[] { typeof(string) });
+ return (Exception)ci.Invoke(new object[] { s });
+ }
+
+ internal static Exception UnsatisfiedLinkError(string s, params object[] args)
+ {
+ s = String.Format(s, args);
+ ConstructorInfo ci = ClassLoaderWrapper.GetType("java.lang.UnsatisfiedLinkError").GetConstructor(new Type[] { typeof(string) });
+ return (Exception)ci.Invoke(new object[] { s });
+ }
+
+ internal static Exception IllegalStateException(string s, params object[] args)
+ {
+ s = String.Format(s, args);
+ ConstructorInfo ci = ClassLoaderWrapper.GetType("java.lang.IllegalStateException").GetConstructor(new Type[] { typeof(string) });
+ return (Exception)ci.Invoke(new object[] { s });
+ }
+
+ internal static Exception IllegalArgumentException(string s, params object[] args)
+ {
+ s = String.Format(s, args);
+ ConstructorInfo ci = ClassLoaderWrapper.GetType("java.lang.IllegalArgumentException").GetConstructor(new Type[] { typeof(string) });
+ return (Exception)ci.Invoke(new object[] { s });
+ }
+
+ internal static Exception NegativeArraySizeException()
+ {
+ return (Exception)Activator.CreateInstance(ClassLoaderWrapper.GetType("java.lang.NegativeArraySizeException"));
+ }
+
+ internal static Exception InvocationTargetException(Exception x)
+ {
+ return (Exception)Activator.CreateInstance(ClassLoaderWrapper.GetType("java.lang.reflect.InvocationTargetException"), new object[] { x });
+ }
+
+ internal static Exception IOException(string s, params object[] args)
+ {
+ s = String.Format(s, args);
+ ConstructorInfo ci = ClassLoaderWrapper.GetType("java.io.IOException").GetConstructor(new Type[] { typeof(string) });
+ return (Exception)ci.Invoke(new object[] { s });
+ }
+
+ internal static Exception UnknownHostException(string s, params object[] args)
+ {
+ s = String.Format(s, args);
+ ConstructorInfo ci = ClassLoaderWrapper.GetType("java.net.UnknownHostException").GetConstructor(new Type[] { typeof(string) });
+ return (Exception)ci.Invoke(new object[] { s });
+ }
+}
diff --git a/IK.VM.NET/ObjectHelper.cs b/IK.VM.NET/ObjectHelper.cs
new file mode 100644
index 00000000..adf9da1e
--- /dev/null
+++ b/IK.VM.NET/ObjectHelper.cs
@@ -0,0 +1,133 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+
+public class ObjectHelper
+{
+ public static void notify(object o)
+ {
+ if(o == null)
+ {
+ throw new NullReferenceException();
+ }
+ System.Threading.Monitor.Pulse(o);
+ }
+
+ public static void notifyAll(object o)
+ {
+ if(o == null)
+ {
+ throw new NullReferenceException();
+ }
+ System.Threading.Monitor.PulseAll(o);
+ }
+
+ public static void wait(object o)
+ {
+ if(o == null)
+ {
+ throw new NullReferenceException();
+ }
+ System.Threading.Monitor.Wait(o);
+ }
+
+ public static void wait(object o, long timeout)
+ {
+ wait(o, timeout, 0);
+ }
+
+ public static void wait(object o, long timeout, int nanos)
+ {
+ if(o == null)
+ {
+ throw new NullReferenceException();
+ }
+ if(timeout == 0 && nanos == 0)
+ {
+ System.Threading.Monitor.Wait(o);
+ }
+ else
+ {
+ System.Threading.Monitor.Wait(o, new TimeSpan(timeout * 10000 + (nanos + 99) / 100));
+ }
+ }
+
+ public static void clonecheck(object o)
+ {
+ if(!(o is java.lang.Cloneable))
+ {
+ throw (Exception)Activator.CreateInstance(ClassLoaderWrapper.GetType("java.lang.CloneNotSupportedException"));
+ }
+ }
+
+ public static object virtualclone(object o)
+ {
+ // TODO because Object.clone() is protected it is accessible from other classes in the java.lang package,
+ // so when they clone an array, we end up here (instead of being redirected to System.Array.Clone(), which
+ // the compiler normally does because Object.clone() is inaccessible)
+ if(o is Array)
+ {
+ return ((Array)o).Clone();
+ }
+ clonecheck(o);
+ // TODO this doesn't happen very often, the only sensible pattern that I can think of that produces code
+ // that ends up here is as follows:
+ // class Base {
+ // public Base CloneMe() { return (Base)clone(); }
+ // }
+ // case Derived extends Base {
+ // protected object clone() { ... }
+ // }
+ // One way of implementing this is by calling the clone method thru reflection, not very fast, but
+ // since this is an uncommon scenario, we might be able to get away with it
+ throw new NotImplementedException("virtual clone invocation not implemented");
+ }
+
+ public static string toStringVirtual(object o)
+ {
+ if(o is Array)
+ {
+ return toStringSpecial(o);
+ }
+ try
+ {
+ return o.ToString();
+ }
+ catch(NullReferenceException)
+ {
+ return o.GetType().FullName;
+ }
+ }
+
+ public static string toStringSpecial(object o)
+ {
+ // TODO hex string should be formatted differently
+ return NativeCode.java.lang.Class.getName(o.GetType()) + "@" + o.GetHashCode().ToString("X");
+ }
+
+ public static object getClass(object o)
+ {
+ return NativeCode.java.lang.Class.getClassFromType(o.GetType());
+ }
+}
diff --git a/IK.VM.NET/StringHelper.cs b/IK.VM.NET/StringHelper.cs
new file mode 100644
index 00000000..102c665a
--- /dev/null
+++ b/IK.VM.NET/StringHelper.cs
@@ -0,0 +1,369 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+using System.Text;
+using System.Reflection;
+
+public class StringHelper
+{
+ public static string NewString(char[] data, int offset, int count, bool dont_copy)
+ {
+ return new String(data, offset, count);
+ }
+
+ public static string NewString(sbyte[] sdata)
+ {
+ return NewString(sdata, 0, sdata.Length);
+ }
+
+ public static string NewString(sbyte[] sdata, int hibyte)
+ {
+ return NewString(sdata, hibyte, 0, sdata.Length);
+ }
+
+ public static string NewString(sbyte[] sdata, int offset, int count)
+ {
+ // TODO what encoding should this use?
+ // TODO could use the unsafe constructor that takes sbyte*, but I don't know if that is worthwhile to be unsafe for
+ byte[] data = new byte[sdata.Length];
+ for(int i = 0; i < data.Length; i++)
+ {
+ data[i] = (byte)sdata[i];
+ }
+ return System.Text.Encoding.ASCII.GetString(data, offset, count);
+ }
+
+ public static string NewString(sbyte[] sdata, int hibyte, int offset, int count)
+ {
+ // TODO benchmark this versus using a stringbuilder instead of a char[]
+ hibyte <<= 8;
+ char[] data = new char[count];
+ for(int i = 0; i < count; i++)
+ {
+ // TODO what happens for negative bytes?
+ data[i] = (char)(((byte)sdata[i + offset]) | hibyte);
+ }
+ return new String(data);
+ }
+
+ public static string NewString(sbyte[] sdata, string charsetName)
+ {
+ return NewString(sdata, 0, sdata.Length, charsetName);
+ }
+
+ public static string NewString(sbyte[] sdata, int offset, int count, string charsetName)
+ {
+ // HACK special case for UTF8, I really need to implement this by
+ // redirecting to the classpath character encoding support
+ if(charsetName == "UTF8")
+ {
+ char[] ch = new Char[count];
+ int l = 0;
+ for(int i = 0; i < count; i++)
+ {
+ int c = (byte)sdata[offset + i];
+ int char2, char3;
+ switch (c >> 4)
+ {
+ case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
+ // 0xxxxxxx
+ break;
+ case 12: case 13:
+ // 110x xxxx 10xx xxxx
+ char2 = (byte)sdata[offset + ++i];
+ c = (((c & 0x1F) << 6) | (char2 & 0x3F));
+ break;
+ case 14:
+ // 1110 xxxx 10xx xxxx 10xx xxxx
+ char2 = (byte)sdata[offset + ++i];
+ char3 = (byte)sdata[offset + ++i];
+ c = (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0));
+ break;
+ }
+ ch[l++] = (char)c;
+ }
+ return new String(ch, 0, l);
+ }
+ // TODO don't use reflection, but write a Java helper class and redirect this method there
+ Type t = ClassLoaderWrapper.GetType("gnu.java.io.EncodingManager");
+ object decoder = t.InvokeMember("getDecoder", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, null, null, new object[] { charsetName });
+ return new String((char[])decoder.GetType().InvokeMember("convertToChars", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, null, decoder, new object[] { sdata, offset, count }));
+ }
+
+ public static string valueOf(bool b)
+ {
+ return b ? "true" : "false";
+ }
+
+ public static string valueOf(int i)
+ {
+ return i.ToString();
+ }
+
+ public static string valueOf(long l)
+ {
+ return l.ToString();
+ }
+
+ public static string valueOf(char c)
+ {
+ return c.ToString();
+ }
+
+ public static string valueOf(float f)
+ {
+ StringBuilder sb = new StringBuilder();
+ return StringBufferHelper.append(sb, f).ToString();
+ }
+
+ public static string valueOf(double d)
+ {
+ StringBuilder sb = new StringBuilder();
+ return StringBufferHelper.append(sb, d).ToString();
+ }
+
+ public static string valueOf(object o)
+ {
+ if(o == null)
+ {
+ return "null";
+ }
+ return ObjectHelper.toStringVirtual(o);
+ }
+
+ public static string substring(string s, int off, int end)
+ {
+ return s.Substring(off, end - off);
+ }
+
+ public static bool startsWith(string s, string prefix, int toffset)
+ {
+ // TODO
+ throw new NotImplementedException();
+ }
+
+ public static void getChars(string s, int srcBegin, int srcEnd, char[] dst, int dstBegin)
+ {
+ s.CopyTo(srcBegin, dst, dstBegin, srcEnd - srcBegin);
+ }
+
+ public static int GetCountField(string s)
+ {
+ return s.Length;
+ }
+
+ public static char[] GetValueField(string s)
+ {
+ return s.ToCharArray();
+ }
+
+ public static int GetOffsetField(string s)
+ {
+ return 0;
+ }
+
+ public static bool equalsIgnoreCase(string s1, string s2)
+ {
+ return String.Compare(s1, s2, true) == 0;
+ }
+
+ public static int compareToIgnoreCase(string s1, string s2)
+ {
+ return String.Compare(s1, s2, true);
+ }
+
+ public static sbyte[] getBytes(string s)
+ {
+ byte[] data = System.Text.Encoding.ASCII.GetBytes(s);
+ sbyte[] sdata = new sbyte[data.Length];
+ for(int i = 0; i < data.Length; i++)
+ {
+ sdata[i] = (sbyte)data[i];
+ }
+ return sdata;
+ }
+
+ public static sbyte[] getBytes(string s, string charsetName)
+ {
+ // TODO don't use reflection, but write a Java helper class and redirect this method there
+ char[] ch = s.ToCharArray();
+ Type t = ClassLoaderWrapper.GetType("gnu.java.io.EncodingManager");
+ object encoder = t.InvokeMember("getEncoder", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, null, null, new object[] { charsetName });
+ return (sbyte[])encoder.GetType().InvokeMember("convertToBytes", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, null, encoder, new object[] { ch, 0, ch.Length });
+ }
+
+ public static void getBytes(string s, int srcBegin, int srcEnd, sbyte[] dst, int dstBegin)
+ {
+ for(int i = 0; i < (srcEnd - srcBegin); i++)
+ {
+ dst[i + dstBegin] = (sbyte)s[i + srcBegin];
+ }
+ }
+
+ public static object subSequence(string s, int offset, int count)
+ {
+ // TODO
+ throw new NotImplementedException();
+ }
+
+ public static bool regionMatches(string s, int toffset, string other, int ooffset, int len)
+ {
+ return regionMatches(s, false, toffset, other, ooffset, len);
+ }
+
+ public static bool regionMatches(string s, bool ignoreCase, int toffset, string other, int ooffset, int len)
+ {
+ if(toffset < 0 || ooffset < 0 || toffset + len > s.Length || ooffset + len > other.Length)
+ {
+ return false;
+ }
+ while(--len >= 0)
+ {
+ char c1 = s[toffset++];
+ char c2 = other[ooffset++];
+ if(c1 != c2 && (!ignoreCase || (Char.ToLower(c1) != Char.ToLower(c2) && (Char.ToUpper(c1) != Char.ToUpper(c2)))))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // NOTE argument is of type object, because otherwise the code that calls this function
+ // has to be much more complex
+ public static int hashCode(object s)
+ {
+ int h = 0;
+ foreach(char c in (string)s)
+ {
+ h = h * 31 + c;
+ }
+ return h;
+ }
+
+ public static string toUpperCase(string s, object locale)
+ {
+ // TODO
+ return s.ToUpper();
+ }
+}
+
+public class StringBufferHelper
+{
+ public static StringBuilder append(StringBuilder thiz, object o)
+ {
+ if(o == null)
+ {
+ o = "null";
+ }
+ return thiz.Append(ObjectHelper.toStringVirtual(o));
+ }
+
+ public static StringBuilder append(StringBuilder thiz, string s)
+ {
+ if(s == null)
+ {
+ s = "null";
+ }
+ return thiz.Append(s);
+ }
+
+ public static StringBuilder append(StringBuilder thiz, bool b)
+ {
+ if(b)
+ {
+ return thiz.Append("true");
+ }
+ else
+ {
+ return thiz.Append("false");
+ }
+ }
+
+ public static StringBuilder append(StringBuilder thiz, float f)
+ {
+ // TODO this is not correct, we need to use the Java algorithm of converting a float to string
+ if(float.IsNaN(f))
+ {
+ thiz.Append("NaN");
+ return thiz;
+ }
+ if(float.IsNegativeInfinity(f))
+ {
+ thiz.Append("-Infinity");
+ return thiz;
+ }
+ if(float.IsPositiveInfinity(f))
+ {
+ thiz.Append("Infinity");
+ return thiz;
+ }
+ // HACK really lame hack to apprioximate the Java behavior a little bit
+ string s = f.ToString(System.Globalization.CultureInfo.InvariantCulture);
+ thiz.Append(s);
+ if(s.IndexOf('.') == -1)
+ {
+ thiz.Append(".0");
+ }
+ return thiz;
+ }
+
+ public static StringBuilder append(StringBuilder thiz, double d)
+ {
+ DoubleToString.append(thiz, d);
+ return thiz;
+ }
+
+ public static StringBuilder insert(StringBuilder thiz, int index, string s)
+ {
+ if(s == null)
+ {
+ s = "null";
+ }
+ return thiz.Insert(index, s);
+ }
+
+ public static string substring(StringBuilder thiz, int start, int end)
+ {
+ return thiz.ToString(start, end - start);
+ }
+
+ public static string substring(StringBuilder thiz, int start)
+ {
+ return thiz.ToString(start, thiz.Length - start);
+ }
+
+ public static StringBuilder replace(StringBuilder thiz, int start, int end, string str)
+ {
+ // OPTIMIZE this could be done a little more efficient
+ thiz.Remove(start, end - start);
+ thiz.Insert(start, str);
+ return thiz;
+ }
+
+ public static StringBuilder delete(StringBuilder thiz, int start, int end)
+ {
+ return thiz.Remove(start, end - start);
+ }
+}
diff --git a/IK.VM.NET/TypeWrapper.cs b/IK.VM.NET/TypeWrapper.cs
new file mode 100644
index 00000000..396e59f1
--- /dev/null
+++ b/IK.VM.NET/TypeWrapper.cs
@@ -0,0 +1,3253 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+using System.Collections;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Diagnostics;
+
+sealed class MethodDescriptor
+{
+ private ClassLoaderWrapper classLoader;
+ private string name;
+ private string sig;
+ private Type[] args;
+ private Type ret;
+
+ internal MethodDescriptor(ClassLoaderWrapper classLoader, string name, string sig)
+ {
+ if(classLoader == null)
+ {
+ throw new ArgumentNullException();
+ }
+ this.classLoader = classLoader;
+ this.name = name;
+ this.sig = sig;
+ // class name in the sig should be slashed instead of dotted
+ Debug.Assert(sig.IndexOf('.') < 0);
+ }
+
+ internal string Name
+ {
+ get
+ {
+ return name;
+ }
+ }
+
+ internal string Signature
+ {
+ get
+ {
+ return sig;
+ }
+ }
+
+ internal Type[] ArgTypes
+ {
+ get
+ {
+ if(args == null)
+ {
+ args = classLoader.ArgTypeListFromSig(sig);
+ }
+ return args;
+ }
+ }
+
+ internal Type RetType
+ {
+ get
+ {
+ if(ret == null)
+ {
+ ret = classLoader.RetTypeFromSig(sig);
+ }
+ return ret;
+ }
+ }
+
+ public override bool Equals(object o)
+ {
+ // TODO instead of comparing the signature strings, we should compare the actual types
+ // (because, in the face of multiple class loaders, there can be multiple classes with the same name)
+ MethodDescriptor md = o as MethodDescriptor;
+ return md != null && md.name == name && md.sig == sig;
+ }
+
+ public override int GetHashCode()
+ {
+ return name.GetHashCode() ^ sig.GetHashCode();
+ }
+
+ internal static string getSigName(Type type)
+ {
+ if(type.IsValueType)
+ {
+ if(type == typeof(void))
+ {
+ return "V";
+ }
+ else if(type == typeof(bool))
+ {
+ return "Z";
+ }
+ else if(type == typeof(sbyte))
+ {
+ return "B";
+ }
+ else if(type == typeof(char))
+ {
+ return "C";
+ }
+ else if(type == typeof(short))
+ {
+ return "S";
+ }
+ else if(type == typeof(int))
+ {
+ return "I";
+ }
+ else if(type == typeof(long))
+ {
+ return "J";
+ }
+ else if(type == typeof(float))
+ {
+ return "F";
+ }
+ else if(type == typeof(double))
+ {
+ return "D";
+ }
+ else
+ {
+ return "L" + type.FullName.Replace('.', '/') + ";";
+ }
+ }
+ else
+ {
+ string s = NativeCode.java.lang.Class.getName(type).Replace('.', '/');
+ if(s[0] != '[')
+ {
+ s = "L" + s + ";";
+ }
+ return s;
+ }
+ }
+
+ internal static MethodDescriptor FromMethodBase(MethodBase mb)
+ {
+ System.Text.StringBuilder sb = new System.Text.StringBuilder();
+ sb.Append('(');
+ foreach(ParameterInfo param in mb.GetParameters())
+ {
+ sb.Append(getSigName(param.ParameterType));
+ }
+ sb.Append(')');
+ if(mb is ConstructorInfo)
+ {
+ sb.Append('V');
+ return new MethodDescriptor(ClassLoaderWrapper.GetClassLoader(mb.DeclaringType), mb.IsStatic ? "<clinit>" : "<init>", sb.ToString());
+ }
+ else
+ {
+ sb.Append(getSigName(((MethodInfo)mb).ReturnType));
+ return new MethodDescriptor(ClassLoaderWrapper.GetClassLoader(mb.DeclaringType), mb.Name, sb.ToString());
+ }
+ }
+}
+
+abstract class TypeWrapper
+{
+ private ClassLoaderWrapper classLoader;
+ private string name; // java name (e.g. java/lang/Object)
+ private Modifiers modifiers;
+ protected Hashtable methods = new Hashtable();
+ private Hashtable fields = new Hashtable();
+ private TypeWrapper baseWrapper;
+
+ public TypeWrapper(Modifiers modifiers, string name, TypeWrapper baseWrapper, ClassLoaderWrapper classLoader)
+ {
+ this.modifiers = modifiers;
+ this.name = name;
+ this.baseWrapper = baseWrapper;
+ this.classLoader = classLoader;
+ }
+
+ internal Modifiers Modifiers
+ {
+ get
+ {
+ return modifiers;
+ }
+ }
+
+ internal bool IsPublic
+ {
+ get
+ {
+ return (modifiers & Modifiers.Public) != 0;
+ }
+ }
+
+ internal bool IsAbstract
+ {
+ get
+ {
+ return (modifiers & Modifiers.Abstract) != 0;
+ }
+ }
+
+ internal bool IsFinal
+ {
+ get
+ {
+ return (modifiers & Modifiers.Final) != 0;
+ }
+ }
+
+ internal ClassLoaderWrapper GetClassLoader()
+ {
+ return classLoader;
+ }
+
+ protected abstract FieldWrapper GetFieldImpl(string fieldName);
+
+ public FieldWrapper GetFieldWrapper(string fieldName)
+ {
+ FieldWrapper fae = (FieldWrapper)fields[fieldName];
+ if(fae == null)
+ {
+ fae = GetFieldImpl(fieldName);
+ if(fae == null)
+ {
+ if(baseWrapper != null)
+ {
+ return baseWrapper.GetFieldWrapper(fieldName);
+ }
+ return null;
+ }
+ fields[fieldName] = fae;
+ }
+ return fae;
+ }
+
+ // TODO figure out when it is safe to call this
+ // HACK for now we assume that the method hashtable has always been filled when this method is called (by java.lang.Class)
+ internal virtual MethodWrapper[] GetMethods()
+ {
+ MethodWrapper[] wrappers = new MethodWrapper[methods.Count];
+ methods.Values.CopyTo(wrappers, 0);
+ return wrappers;
+ }
+
+ // TODO figure out when it is safe to call this
+ // HACK for now we assume that the fields hashtable has always been filled when this method is called (by java.lang.Class)
+ internal virtual FieldWrapper[] GetFields()
+ {
+ FieldWrapper[] wrappers = new FieldWrapper[fields.Count];
+ fields.Values.CopyTo(wrappers, 0);
+ return wrappers;
+ }
+
+ protected abstract MethodWrapper GetMethodImpl(MethodDescriptor md);
+
+ public MethodWrapper GetMethodWrapper(MethodDescriptor md, bool inherit)
+ {
+ MethodWrapper mce = (MethodWrapper)methods[md];
+ if(mce == null)
+ {
+ mce = GetMethodImpl(md);
+ if(mce == null)
+ {
+ if(inherit && baseWrapper != null)
+ {
+ return baseWrapper.GetMethodWrapper(md, inherit);
+ }
+ return null;
+ }
+ methods[md] = mce;
+ }
+ return mce;
+ }
+
+ public void AddMethod(MethodWrapper method)
+ {
+ if(method == null)
+ {
+ throw new ArgumentNullException();
+ }
+ methods[method.Descriptor] = method;
+ }
+
+ public void AddField(FieldWrapper field)
+ {
+ if(field == null)
+ {
+ throw new ArgumentNullException();
+ }
+ fields[field.Name] = field;
+ }
+
+ public string Name
+ {
+ get
+ {
+ return name;
+ }
+ }
+
+ internal string PackageName
+ {
+ get
+ {
+ int index = name.LastIndexOf('/');
+ if(index == -1)
+ {
+ return "";
+ }
+ return name.Substring(0, index);
+ }
+ }
+
+ // returns true iff wrapper is allowed to access us
+ internal bool IsAccessibleFrom(TypeWrapper wrapper)
+ {
+ return IsPublic || IsInSamePackageAs(wrapper);
+ }
+
+ public bool IsInSamePackageAs(TypeWrapper wrapper)
+ {
+ if(GetClassLoader() == wrapper.GetClassLoader())
+ {
+ int index1 = name.LastIndexOf('/');
+ int index2 = wrapper.name.LastIndexOf('/');
+ if(index1 == -1 && index2 == -1)
+ {
+ return true;
+ }
+ if(index1 == -1 || index2 == -1)
+ {
+ return false;
+ }
+ string package1 = name.Substring(0, index1);
+ string package2 = wrapper.name.Substring(0, index2);
+ return package1 == package2;
+ }
+ return false;
+ }
+
+ public abstract Type Type
+ {
+ get;
+ }
+
+ public TypeWrapper BaseTypeWrapper
+ {
+ get
+ {
+ return baseWrapper;
+ }
+ }
+
+ public bool ImplementsInterface(TypeWrapper interfaceWrapper)
+ {
+ TypeWrapper typeWrapper = this;
+ while(typeWrapper != null)
+ {
+ for(int i = 0; i < typeWrapper.Interfaces.Length; i++)
+ {
+ if(typeWrapper.Interfaces[i] == interfaceWrapper)
+ {
+ return true;
+ }
+ if(typeWrapper.Interfaces[i].ImplementsInterface(interfaceWrapper))
+ {
+ return true;
+ }
+ }
+ typeWrapper = typeWrapper.BaseTypeWrapper;
+ }
+ return false;
+ }
+
+ public bool IsSubTypeOf(TypeWrapper baseType)
+ {
+ if(baseType.IsInterface)
+ {
+ if(baseType == this)
+ {
+ return true;
+ }
+ return ImplementsInterface(baseType);
+ }
+ TypeWrapper subType = this;
+ while(subType != baseType)
+ {
+ subType = subType.BaseTypeWrapper;
+ if(subType == null)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public abstract bool IsInterface
+ {
+ get;
+ }
+
+ public abstract TypeWrapper[] Interfaces
+ {
+ get;
+ }
+
+ public abstract void Finish();
+
+ private void ImplementInterfaceMethodStubImpl(MethodDescriptor md, MethodBase ifmethod, TypeBuilder typeBuilder, TypeWrapper wrapper)
+ {
+ CustomAttributeBuilder methodFlags = new CustomAttributeBuilder(typeof(ModifiersAttribute).GetConstructor(new Type[] { typeof(Modifiers) }), new object[] { Modifiers.Synthetic });
+ // HACK we're mangling the name to prevent subclasses from overriding this method (I think it is a bug
+ // the CLR that it tries to override privatescope methods, by name)
+ string mangledName = ifmethod.Name + "$" + wrapper.Name;
+ MethodWrapper mce = wrapper.GetMethodWrapper(md, true);
+ if(mce != null)
+ {
+ if(!mce.IsPublic)
+ {
+ // NOTE according to the ECMA spec it isn't legal for a privatescope method to be virtual, but this works and
+ // it makes sense, so I hope the spec is wrong
+ // UPDATE unfortunately, according to Serge Lidin the spec is correct, and it is not allowed to have virtual privatescope
+ // methods. Sigh! So I have to use private methods and mangle the name
+ MethodBuilder mb = typeBuilder.DefineMethod(mangledName, MethodAttributes.NewSlot | MethodAttributes.Private | MethodAttributes.Virtual | MethodAttributes.Final, md.RetType, md.ArgTypes);
+ mb.SetCustomAttribute(methodFlags);
+ ILGenerator ilGenerator = mb.GetILGenerator();
+ TypeWrapper exception = ClassLoaderWrapper.GetBootstrapClassLoader().LoadClassBySlashedName("java/lang/IllegalAccessError");
+ ilGenerator.Emit(OpCodes.Ldstr, wrapper.Name + "." + md.Name + md.Signature);
+ exception.GetMethodWrapper(new MethodDescriptor(ClassLoaderWrapper.GetBootstrapClassLoader(), "<init>", "(Ljava/lang/String;)V"), false).EmitNewobj.Emit(ilGenerator);
+ ilGenerator.Emit(OpCodes.Throw);
+ typeBuilder.DefineMethodOverride(mb, (MethodInfo)ifmethod);
+ }
+ else if(mce.GetMethod().Name != ifmethod.Name)
+ {
+ MethodBuilder mb = typeBuilder.DefineMethod(mangledName, MethodAttributes.NewSlot | MethodAttributes.Private | MethodAttributes.Virtual | MethodAttributes.Final, md.RetType, md.ArgTypes);
+ mb.SetCustomAttribute(methodFlags);
+ ILGenerator ilGenerator = mb.GetILGenerator();
+ ilGenerator.Emit(OpCodes.Ldarg_0);
+ int argc = md.ArgTypes.Length;
+ for(int n = 0; n < argc; n++)
+ {
+ ilGenerator.Emit(OpCodes.Ldarg_S, (byte)(n + 1));
+ }
+ mce.EmitCallvirt.Emit(ilGenerator);
+ ilGenerator.Emit(OpCodes.Ret);
+ typeBuilder.DefineMethodOverride(mb, (MethodInfo)ifmethod);
+ }
+ }
+ else
+ {
+ if(!wrapper.IsAbstract)
+ {
+ // the type doesn't implement the interface method and isn't abstract either. The JVM allows this, but the CLR doesn't,
+ // so we have to create a stub method that throws an AbstractMethodError
+ MethodBuilder mb = typeBuilder.DefineMethod(mangledName, MethodAttributes.NewSlot | MethodAttributes.Private | MethodAttributes.Virtual | MethodAttributes.Final, md.RetType, md.ArgTypes);
+ mb.SetCustomAttribute(methodFlags);
+ ILGenerator ilGenerator = mb.GetILGenerator();
+ TypeWrapper exception = ClassLoaderWrapper.GetBootstrapClassLoader().LoadClassBySlashedName("java/lang/AbstractMethodError");
+ ilGenerator.Emit(OpCodes.Ldstr, wrapper.Name + "." + md.Name + md.Signature);
+ exception.GetMethodWrapper(new MethodDescriptor(ClassLoaderWrapper.GetBootstrapClassLoader(), "<init>", "(Ljava/lang/String;)V"), false).EmitNewobj.Emit(ilGenerator);
+ ilGenerator.Emit(OpCodes.Throw);
+ typeBuilder.DefineMethodOverride(mb, (MethodInfo)ifmethod);
+ }
+ else
+ {
+ // because of a bug in the .NET 1.0 CLR, we have emit an abstract Miranda method, otherwise
+ // the class will not be loadable under some circumstances
+ // Example (compile with Jikes 1.18):
+ //interface __Shape
+ //{
+ // public abstract __Rectangle getBounds();
+ // public abstract __Rectangle2D getBounds2D();
+ //}
+ //
+ //abstract class __RectangularShape implements __Shape
+ //{
+ // public __Rectangle getBounds()
+ // {
+ // return null;
+ // }
+ //}
+ //
+ //abstract class __Rectangle2D extends __RectangularShape
+ //{
+ // public __Rectangle2D getBounds2D()
+ // {
+ // return null;
+ // }
+ //}
+ //
+ //class __Rectangle extends __Rectangle2D implements __Shape
+ //{
+ // public __Rectangle getBounds()
+ // {
+ // return null;
+ // }
+ //
+ // public __Rectangle2D getBounds2D()
+ // {
+ // return null;
+ // }
+ //}
+ MethodBuilder mb = typeBuilder.DefineMethod(md.Name, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Abstract, md.RetType, md.ArgTypes);
+ mb.SetCustomAttribute(methodFlags);
+ }
+ }
+ }
+
+ internal void ImplementInterfaceMethodStubs(TypeBuilder typeBuilder, TypeWrapper wrapper, Hashtable doneSet)
+ {
+ // TODO interfaces that implement other interfaces need to be handled as well...
+ if(!IsInterface)
+ {
+ throw new InvalidOperationException();
+ }
+ // make sure we don't do the same method twice
+ if(doneSet.ContainsKey(this))
+ {
+ return;
+ }
+ doneSet.Add(this, this);
+ Finish();
+ // NOTE for dynamic types it isn't legal to call Type.GetMethods() (because
+ // that might trigger finishing of types that are already in the process of
+ // being finished) and for RemappedTypeWrappers it makes no sense, so both
+ // of these (ab)use the methods hashtable to obtain a list of methods
+ // NOTE since the types have been finished, we know for sure that all methods
+ // are in fact in the methods cache
+ if(Type.Assembly is AssemblyBuilder || this is RemappedTypeWrapper)
+ {
+ foreach(MethodWrapper method in methods.Values)
+ {
+ MethodBase ifmethod = method.GetMethod();
+ if(!ifmethod.IsStatic)
+ {
+ ImplementInterfaceMethodStubImpl(method.Descriptor, ifmethod, typeBuilder, wrapper);
+ }
+ }
+ }
+ else
+ {
+ MethodInfo[] methods = Type.GetMethods();
+ for(int i = 0; i < methods.Length; i++)
+ {
+ MethodInfo ifmethod = methods[i];
+ if(!ifmethod.IsStatic)
+ {
+ ImplementInterfaceMethodStubImpl(MethodDescriptor.FromMethodBase(ifmethod), ifmethod, typeBuilder, wrapper);
+ }
+ }
+ }
+ TypeWrapper[] interfaces = Interfaces;
+ for(int i = 0; i < interfaces.Length; i++)
+ {
+ interfaces[i].ImplementInterfaceMethodStubs(typeBuilder, wrapper, doneSet);
+ }
+ }
+
+ internal virtual void ImplementOverrideStubsAndVirtuals(TypeBuilder typeBuilder, TypeWrapper wrapper, Hashtable methodLookup)
+ {
+ }
+}
+
+class PrimitiveTypeWrapper : TypeWrapper
+{
+ internal static readonly PrimitiveTypeWrapper BYTE = new PrimitiveTypeWrapper(typeof(sbyte));
+ internal static readonly PrimitiveTypeWrapper CHAR = new PrimitiveTypeWrapper(typeof(char));
+ internal static readonly PrimitiveTypeWrapper DOUBLE = new PrimitiveTypeWrapper(typeof(double));
+ internal static readonly PrimitiveTypeWrapper FLOAT = new PrimitiveTypeWrapper(typeof(float));
+ internal static readonly PrimitiveTypeWrapper INT = new PrimitiveTypeWrapper(typeof(int));
+ internal static readonly PrimitiveTypeWrapper LONG = new PrimitiveTypeWrapper(typeof(long));
+ internal static readonly PrimitiveTypeWrapper SHORT = new PrimitiveTypeWrapper(typeof(short));
+ internal static readonly PrimitiveTypeWrapper BOOLEAN = new PrimitiveTypeWrapper(typeof(bool));
+ internal static readonly PrimitiveTypeWrapper VOID = new PrimitiveTypeWrapper(typeof(void));
+
+ private Type type;
+
+ private PrimitiveTypeWrapper(Type type)
+ : base(Modifiers.Public | Modifiers.Abstract | Modifiers.Final, null, null, ClassLoaderWrapper.GetBootstrapClassLoader())
+ {
+ this.type = type;
+ }
+
+ public override Type Type
+ {
+ get
+ {
+ return type;
+ }
+ }
+
+ protected override FieldWrapper GetFieldImpl(string fieldName)
+ {
+ return null;
+ }
+
+ protected override MethodWrapper GetMethodImpl(MethodDescriptor md)
+ {
+ return null;
+ }
+
+ public override bool IsInterface
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public override TypeWrapper[] Interfaces
+ {
+ get
+ {
+ // TODO does a primitive implement any interfaces?
+ return new TypeWrapper[0];
+ }
+ }
+
+ public override void Finish()
+ {
+ }
+}
+
+class DynamicTypeWrapper : TypeWrapper
+{
+ private DynamicImpl impl;
+ private TypeWrapper[] interfaces;
+
+ internal DynamicTypeWrapper(string name, ClassFile f, TypeWrapper baseType, ClassLoaderWrapper classLoader, Hashtable nativeMethods)
+ : base(f.Modifiers, name, baseType, classLoader)
+ {
+ JavaTypeImpl impl = new JavaTypeImpl(f, this, baseType, nativeMethods);
+ this.impl = impl;
+ interfaces = impl.GetInterfaces();
+ }
+
+ protected override FieldWrapper GetFieldImpl(string fieldName)
+ {
+ return impl.GetFieldImpl(fieldName);
+ }
+
+ protected override MethodWrapper GetMethodImpl(MethodDescriptor md)
+ {
+ return impl.GetMethodImpl(md);
+ }
+
+ public override bool IsInterface
+ {
+ get
+ {
+ return impl.IsInterface;
+ }
+ }
+
+ public override TypeWrapper[] Interfaces
+ {
+ get
+ {
+ return interfaces;
+ }
+ }
+
+ public override Type Type
+ {
+ get
+ {
+ return impl.Type;
+ }
+ }
+
+ public override void Finish()
+ {
+ impl = impl.Finish();
+ }
+
+ private abstract class DynamicImpl
+ {
+ public abstract FieldWrapper GetFieldImpl(string fieldName);
+ public abstract MethodWrapper GetMethodImpl(MethodDescriptor md);
+ public abstract Type Type { get; }
+ public abstract bool IsInterface { get; }
+ public abstract DynamicImpl Finish();
+ }
+
+ private class JavaTypeImpl : DynamicImpl
+ {
+ private ClassFile classFile;
+ private DynamicTypeWrapper wrapper;
+ private TypeWrapper baseWrapper;
+ private TypeBuilder typeBuilder;
+ private TypeWrapper[] interfaces;
+ private MethodWrapper[] methods;
+ private FieldWrapper[] fields;
+ private Hashtable methodLookup;
+ private Hashtable fieldLookup;
+ private bool finishing;
+ private Hashtable nativeMethods;
+
+ internal JavaTypeImpl(ClassFile f, DynamicTypeWrapper wrapper, TypeWrapper baseWrapper, Hashtable nativeMethods)
+ {
+ // Console.WriteLine("constructing JavaTypeImpl for " + f.Name);
+ this.classFile = f;
+ this.wrapper = wrapper;
+ this.baseWrapper = baseWrapper;
+ this.nativeMethods = nativeMethods;
+
+ TypeAttributes typeAttribs = 0;
+ if(f.IsAbstract)
+ {
+ typeAttribs |= TypeAttributes.Abstract;
+ }
+ if(f.IsFinal)
+ {
+ typeAttribs |= TypeAttributes.Sealed;
+ }
+ if(f.IsPublic)
+ {
+ typeAttribs |= TypeAttributes.Public;
+ }
+ if(f.IsInterface)
+ {
+ typeAttribs |= TypeAttributes.Interface | TypeAttributes.Abstract;
+ typeBuilder = wrapper.GetClassLoader().ModuleBuilder.DefineType(f.Name.Replace('/', '.'), typeAttribs);
+ }
+ else
+ {
+ typeAttribs |= TypeAttributes.Class;
+ typeBuilder = wrapper.GetClassLoader().ModuleBuilder.DefineType(f.Name.Replace('/', '.'), typeAttribs, baseWrapper.Type);
+ }
+ interfaces = new TypeWrapper[f.Interfaces.Length];
+ for(int i = 0; i < f.Interfaces.Length; i++)
+ {
+ interfaces[i] = wrapper.GetClassLoader().LoadClassBySlashedName(f.Interfaces[i]);
+ if(!interfaces[i].IsInterface)
+ {
+ throw JavaException.IncompatibleClassChangeError("Implementing class");
+ }
+ if(!interfaces[i].IsAccessibleFrom(wrapper))
+ {
+ throw JavaException.IllegalAccessError("Class {0} cannot access its superinterface {1}", wrapper.Name, interfaces[i].Name);
+ }
+ typeBuilder.AddInterfaceImplementation(interfaces[i].Type);
+ }
+ }
+
+ internal TypeWrapper[] GetInterfaces()
+ {
+ return interfaces;
+ }
+
+ public override DynamicImpl Finish()
+ {
+ if(finishing)
+ {
+ throw new InvalidOperationException("Finishing already in progress, for type " + classFile.Name);
+ }
+ finishing = true;
+ // Console.WriteLine("finishing TypeFactory for " + classFile.Name);
+ if(fieldLookup == null)
+ {
+ fields = new FieldWrapper[classFile.Fields.Length];
+ fieldLookup = new Hashtable();
+ for(int i = 0; i < classFile.Fields.Length; i++)
+ {
+ fieldLookup[classFile.Fields[i].Name] = i;
+ }
+ }
+ for(int i = 0; i < fields.Length; i++)
+ {
+ if(fields[i] == null)
+ {
+ GenerateField(i);
+ wrapper.AddField(fields[i]);
+ }
+ }
+ MethodDescriptor[] methodDescriptors = new MethodDescriptor[classFile.Methods.Length];
+ for(int i = 0; i < classFile.Methods.Length; i++)
+ {
+ methodDescriptors[i] = new MethodDescriptor(wrapper.GetClassLoader(), classFile.Methods[i].Name, classFile.Methods[i].Signature);
+ }
+ if(methodLookup == null)
+ {
+ methods = new MethodWrapper[classFile.Methods.Length];
+ methodLookup = new Hashtable();
+ for(int i = 0; i < classFile.Methods.Length; i++)
+ {
+ methodLookup[methodDescriptors[i]] = i;
+ }
+ }
+ for(int i = 0; i < methods.Length; i++)
+ {
+ if(methods[i] == null)
+ {
+ GenerateMethod(i);
+ wrapper.AddMethod(methods[i]);
+ }
+ }
+ wrapper.BaseTypeWrapper.Finish();
+ bool basehasclinit = wrapper.BaseTypeWrapper.Type.GetConstructor(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, CallingConventions.Any, Type.EmptyTypes, null) != null;
+ bool hasclinit = false;
+ for(int i = 0; i < methods.Length; i++)
+ {
+ ILGenerator ilGenerator;
+ MethodBase mb = methods[i].GetMethod();
+ if(mb is ConstructorBuilder)
+ {
+ ilGenerator = ((ConstructorBuilder)mb).GetILGenerator();
+ if(basehasclinit && classFile.Methods[i].Name == "<clinit>" && classFile.Methods[i].Signature == "()V" && !classFile.IsInterface)
+ {
+ hasclinit = true;
+ ilGenerator.Emit(OpCodes.Ldtoken, Type.BaseType);
+ ilGenerator.Emit(OpCodes.Call, typeof(System.Runtime.CompilerServices.RuntimeHelpers).GetMethod("RunClassConstructor"));
+ }
+ }
+ else
+ {
+ ilGenerator = ((MethodBuilder)mb).GetILGenerator();
+ }
+ ClassFile.Method m = classFile.Methods[i];
+ if(m.IsAbstract)
+ {
+ // NOTE in the JVM it is apparently legal for a non-abstract class to have abstract methods, but
+ // the CLR doens't allow this, so we have to emit a method that throws an AbstractMethodError
+ if(!m.ClassFile.IsAbstract && !m.ClassFile.IsInterface)
+ {
+ TypeWrapper exceptionType = ClassLoaderWrapper.GetBootstrapClassLoader().LoadClassBySlashedName("java/lang/AbstractMethodError");
+ MethodWrapper method = exceptionType.GetMethodWrapper(new MethodDescriptor(ClassLoaderWrapper.GetBootstrapClassLoader(), "<init>", "(Ljava/lang/String;)V"), false);
+ ilGenerator.Emit(OpCodes.Ldstr, m.ClassFile.Name + "." + m.Name + m.Signature);
+ method.EmitNewobj.Emit(ilGenerator);
+ ilGenerator.Emit(OpCodes.Throw);
+ }
+ }
+ else if(m.IsNative)
+ {
+ CustomAttributeBuilder methodFlags = new CustomAttributeBuilder(typeof(ModifiersAttribute).GetConstructor(new Type[] { typeof(Modifiers) }), new object[] { m.Modifiers });
+ if(mb is ConstructorBuilder)
+ {
+ ((ConstructorBuilder)mb).SetCustomAttribute(methodFlags);
+ }
+ else
+ {
+ ((MethodBuilder)mb).SetCustomAttribute(methodFlags);
+ }
+ // do we have a native implementation in map.xml?
+ if(nativeMethods != null)
+ {
+ string key = classFile.Name.Replace('/', '.') + "." + m.Name + m.Signature;
+ CodeEmitter opcodes = (CodeEmitter)nativeMethods[key];
+ if(opcodes != null)
+ {
+ opcodes.Emit(ilGenerator);
+ continue;
+ }
+ }
+ // see if there exists a NativeCode class for this type
+ Type nativeCodeType = Type.GetType("NativeCode." + classFile.Name.Replace('/', '.'));
+ MethodInfo nativeMethod = null;
+ if(nativeCodeType != null)
+ {
+ // TODO use better resolution
+ nativeMethod = nativeCodeType.GetMethod(m.Name);
+ }
+ Type[] args = wrapper.GetClassLoader().ArgTypeListFromSig(m.Signature);
+ if(nativeMethod != null)
+ {
+ int add = 0;
+ if(!m.IsStatic)
+ {
+ ilGenerator.Emit(OpCodes.Ldarg_0);
+ add = 1;
+ }
+ for(int j = 0; j < args.Length; j++)
+ {
+ ilGenerator.Emit(OpCodes.Ldarg, j + add);
+ }
+ ilGenerator.Emit(OpCodes.Call, nativeMethod);
+ Type retType = wrapper.GetClassLoader().RetTypeFromSig(m.Signature);
+ if(!retType.Equals(nativeMethod.ReturnType))
+ {
+ ilGenerator.Emit(OpCodes.Castclass, retType);
+ }
+ }
+ else
+ {
+ if(JVM.NoJniStubs)
+ {
+ // TODO consider throwing a java.lang.UnsatisfiedLinkError here
+ //Console.WriteLine("Native method not implemented: " + classFile.Name + "." + m.Name + m.Signature);
+ ilGenerator.Emit(OpCodes.Ldstr, "Native method not implemented: " + classFile.Name + "." + m.Name + m.Signature);
+ ilGenerator.Emit(OpCodes.Newobj, typeof(NotImplementedException).GetConstructor(new Type[] { typeof(string) }));
+ ilGenerator.Emit(OpCodes.Throw);
+ continue;
+ }
+ //ilGenerator.EmitWriteLine(m.Name);
+ FieldBuilder methodPtr = typeBuilder.DefineField(m.Name + "$Ptr", typeof(IntPtr), FieldAttributes.Static | FieldAttributes.PrivateScope);
+ LocalBuilder localsref = ilGenerator.DeclareLocal(typeof(LocalRefStruct));
+ ilGenerator.Emit(OpCodes.Ldsfld, methodPtr);
+ Label oklabel = ilGenerator.DefineLabel();
+ ilGenerator.Emit(OpCodes.Brtrue, oklabel);
+ ilGenerator.Emit(OpCodes.Ldstr, m.Name);
+ ilGenerator.Emit(OpCodes.Ldstr, m.Signature);
+ ilGenerator.Emit(OpCodes.Ldstr, classFile.Name);
+ ilGenerator.Emit(OpCodes.Call, typeof(JNI).GetMethod("GetJniFuncPtr"));
+ ilGenerator.Emit(OpCodes.Stsfld, methodPtr);
+ ilGenerator.MarkLabel(oklabel);
+ Type retType = wrapper.GetClassLoader().RetTypeFromSig(m.Signature);
+ if(!retType.IsValueType)
+ {
+ // this one is for use after we return from "calli"
+ ilGenerator.Emit(OpCodes.Ldloca, localsref);
+ }
+ ilGenerator.Emit(OpCodes.Ldloca, localsref);
+ ilGenerator.Emit(OpCodes.Call, typeof(LocalRefStruct).GetMethod("Enter"));
+ Type[] modargs = new Type[args.Length + 2];
+ modargs[0] = typeof(IntPtr);
+ modargs[1] = typeof(IntPtr);
+ args.CopyTo(modargs, 2);
+ int add = 0;
+ if(!m.IsStatic)
+ {
+ ilGenerator.Emit(OpCodes.Ldloca, localsref);
+ ilGenerator.Emit(OpCodes.Ldarg_0);
+ ilGenerator.Emit(OpCodes.Call, typeof(LocalRefStruct).GetMethod("MakeLocalRef"));
+ add = 1;
+ }
+ else
+ {
+ ilGenerator.Emit(OpCodes.Ldloca, localsref);
+ ilGenerator.Emit(OpCodes.Ldtoken, this.Type);
+ ilGenerator.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
+ ilGenerator.Emit(OpCodes.Call, typeof(NativeCode.java.lang.Class).GetMethod("getClassFromType"));
+ ilGenerator.Emit(OpCodes.Call, typeof(LocalRefStruct).GetMethod("MakeLocalRef"));
+ }
+ for(int j = 0; j < args.Length; j++)
+ {
+ if(!args[j].IsValueType)
+ {
+ ilGenerator.Emit(OpCodes.Ldloca, localsref);
+ ilGenerator.Emit(OpCodes.Ldarg, j + add);
+ ilGenerator.Emit(OpCodes.Call, typeof(LocalRefStruct).GetMethod("MakeLocalRef"));
+ modargs[j + 2] = typeof(IntPtr);
+ }
+ else
+ {
+ ilGenerator.Emit(OpCodes.Ldarg, j + add);
+ }
+ }
+ ilGenerator.Emit(OpCodes.Ldsfld, methodPtr);
+ ilGenerator.EmitCalli(OpCodes.Calli, System.Runtime.InteropServices.CallingConvention.StdCall, retType.IsValueType ? retType : typeof(IntPtr), modargs);
+ ilGenerator.Emit(OpCodes.Ldloca, localsref);
+ // TODO we should use a try {} finally {} to make sure Leave is called, even if the native code throws an exception
+ ilGenerator.Emit(OpCodes.Call, typeof(LocalRefStruct).GetMethod("Leave"));
+ if(!retType.IsValueType)
+ {
+ ilGenerator.Emit(OpCodes.Call, typeof(LocalRefStruct).GetMethod("UnwrapLocalRef"));
+ ilGenerator.Emit(OpCodes.Castclass, retType);
+ }
+ }
+ ilGenerator.Emit(OpCodes.Ret);
+ }
+ else
+ {
+ Compiler.Compile(wrapper, m, ilGenerator, wrapper.GetClassLoader());
+ }
+ }
+ // if we don't have a <clinit> we need to inject one to call the base class <clinit>
+ if(basehasclinit && !hasclinit && !classFile.IsInterface)
+ {
+ ILGenerator ilGenerator = typeBuilder.DefineConstructor(MethodAttributes.Private | MethodAttributes.Static, CallingConventions.Standard, Type.EmptyTypes).GetILGenerator();
+ ilGenerator.Emit(OpCodes.Ldtoken, Type.BaseType);
+ ilGenerator.Emit(OpCodes.Call, typeof(System.Runtime.CompilerServices.RuntimeHelpers).GetMethod("RunClassConstructor"));
+ ilGenerator.Emit(OpCodes.Ret);
+ }
+
+ if(!classFile.IsInterface)
+ {
+ // here we loop thru all the interfaces to explicitly implement any methods that we inherit from
+ // base types that may have a different name from the name in the interface
+ // (e.g. interface that has an equals() method that should override System.Object.Equals())
+ // also deals with interface methods that aren't implemented (generate a stub that throws AbstractMethodError)
+ // and with methods that aren't public (generate a stub that throws IllegalAccessError)
+ Hashtable doneSet = new Hashtable();
+ for(int i = 0; i < interfaces.Length; i++)
+ {
+ interfaces[i].ImplementInterfaceMethodStubs(typeBuilder, wrapper, doneSet);
+ }
+ wrapper.BaseTypeWrapper.ImplementOverrideStubsAndVirtuals(typeBuilder, wrapper, methodLookup);
+ }
+
+ try
+ {
+ Type type = typeBuilder.CreateType();
+ ClassLoaderWrapper.SetWrapperForType(type, wrapper);
+ return new FinishedTypeImpl(type);
+ }
+ catch
+ {
+ Console.WriteLine("Exception caused by : " + wrapper.Name);
+ throw;
+ }
+ }
+
+ public override bool IsInterface
+ {
+ get
+ {
+ return typeBuilder.IsInterface;
+ }
+ }
+
+ public override FieldWrapper GetFieldImpl(string fieldName)
+ {
+ if(fieldLookup == null)
+ {
+ fields = new FieldWrapper[classFile.Fields.Length];
+ fieldLookup = new Hashtable();
+ for(int i = 0; i < classFile.Fields.Length; i++)
+ {
+ fieldLookup[classFile.Fields[i].Name] = i;
+ }
+ }
+ object index = fieldLookup[fieldName];
+ if(index != null)
+ {
+ int i = (int)index;
+ if(fields[i] == null)
+ {
+ GenerateField(i);
+ }
+ return fields[i];
+ }
+ return null;
+ }
+
+ private void GenerateField(int i)
+ {
+ FieldBuilder field;
+ ClassFile.Field fld = classFile.Fields[i];
+ Type type = wrapper.GetClassLoader().ExpressionType(fld.Signature);
+ FieldAttributes attribs = 0;
+ MethodAttributes methodAttribs = 0;
+ bool setModifiers = false;
+ if(fld.IsPrivate)
+ {
+ attribs |= FieldAttributes.Private;
+ }
+ else if(fld.IsProtected)
+ {
+ attribs |= FieldAttributes.FamORAssem;
+ methodAttribs |= MethodAttributes.FamORAssem;
+ }
+ else if(fld.IsPublic)
+ {
+ attribs |= FieldAttributes.Public;
+ methodAttribs |= MethodAttributes.Public;
+ }
+ else
+ {
+ attribs |= FieldAttributes.Assembly;
+ methodAttribs |= MethodAttributes.Assembly;
+ }
+ if(fld.IsStatic)
+ {
+ attribs |= FieldAttributes.Static;
+ methodAttribs |= MethodAttributes.Static;
+ }
+ // NOTE "constant" static finals are converted into literals
+ // TODO it would be possible for Java code to change the value of a non-blank static final, but I don't
+ // know if we want to support this (since the Java JITs don't really support it either)
+ object constantValue = fld.ConstantValue;
+ if(fld.IsStatic && fld.IsFinal && constantValue != null)
+ {
+ attribs |= FieldAttributes.Literal;
+ field = typeBuilder.DefineField(fld.Name, type, attribs);
+ field.SetConstant(constantValue);
+ fields[i] = FieldWrapper.Create(wrapper, field, fld.Signature, fld.Modifiers);
+ // NOTE even though you're not supposed to access a constant static final (the compiler is supposed
+ // to inline them), we have to support it (because it does happen, e.g. if the field becomes final
+ // after the referencing class was compiled)
+ if(constantValue is int || constantValue is short || constantValue is sbyte || constantValue is char || constantValue is bool)
+ {
+ fields[i].EmitGet = CodeEmitter.Create(OpCodes.Ldc_I4, ((IConvertible)constantValue).ToInt32(null));
+ }
+ else if(constantValue is string)
+ {
+ fields[i].EmitGet = CodeEmitter.Create(OpCodes.Ldstr, (string)constantValue);
+ }
+ else if(constantValue is float)
+ {
+ fields[i].EmitGet = CodeEmitter.Create(OpCodes.Ldc_R4, (float)constantValue);
+ }
+ else if(constantValue is double)
+ {
+ fields[i].EmitGet = CodeEmitter.Create(OpCodes.Ldc_R8, (double)constantValue);
+ }
+ else if(constantValue is long)
+ {
+ fields[i].EmitGet = CodeEmitter.Create(OpCodes.Ldc_I8, (long)constantValue);
+ }
+ else
+ {
+ throw new NotImplementedException(constantValue.GetType().FullName);
+ }
+ // TODO this should probably emit a IllegalAccessError (or whatever)
+ // TODO also check other field[x].EmitSet's for final fields
+ // UPDATE for other final fields this shouldn't happend, because the compiler will check access before
+ // calling EmitSet
+ // UPDATE when non-blank final fields are updated, the JIT normally doesn't see that (because the
+ // constant value is inlined), so we emulate that behavior by emitting a Nop
+ fields[i].EmitSet = CodeEmitter.Create(OpCodes.Nop);
+ }
+ else
+ {
+ if(fld.IsFinal)
+ {
+ // final doesn't make sense for private fields, so if the field is private we ignore final
+ if(!fld.IsPrivate && !wrapper.IsInterface)
+ {
+ // NOTE blank final fields get converted into a read-only property with a private field backing store
+ // we used to make the field privatescope, but that really serves no purpose (and it hinders serialization,
+ // which uses .NET reflection to get at the field)
+ attribs &= ~FieldAttributes.FieldAccessMask;
+ attribs |= FieldAttributes.Private;
+ setModifiers = true;
+ }
+ }
+ field = typeBuilder.DefineField(fld.Name, type, attribs);
+ if(fld.IsTransient)
+ {
+ CustomAttributeBuilder transientAttrib = new CustomAttributeBuilder(typeof(NonSerializedAttribute).GetConstructor(Type.EmptyTypes), new object[0]);
+ field.SetCustomAttribute(transientAttrib);
+ }
+ if(fld.IsVolatile)
+ {
+ // TODO the field should be marked as modreq(IsVolatile), but Reflection.Emit doesn't have a way of doing this
+ setModifiers = true;
+ }
+ if(fld.IsFinal && !fld.IsPrivate && !wrapper.IsInterface)
+ {
+ methodAttribs |= MethodAttributes.SpecialName;
+ // TODO we should ensure that the getter method name doesn't clash with an existing method
+ MethodBuilder getter = typeBuilder.DefineMethod("get_" + fld.Name, methodAttribs, CallingConventions.Standard, type, Type.EmptyTypes);
+ ModifiersAttribute.SetModifiers(getter, Modifiers.Synthetic);
+ ILGenerator ilgen = getter.GetILGenerator();
+ if(fld.IsVolatile)
+ {
+ ilgen.Emit(OpCodes.Volatile);
+ }
+ if(fld.IsStatic)
+ {
+ ilgen.Emit(OpCodes.Ldsfld, field);
+ }
+ else
+ {
+ ilgen.Emit(OpCodes.Ldarg_0);
+ ilgen.Emit(OpCodes.Ldfld, field);
+ }
+ ilgen.Emit(OpCodes.Ret);
+ PropertyBuilder pb = typeBuilder.DefineProperty(fld.Name, PropertyAttributes.None, type, Type.EmptyTypes);
+ pb.SetGetMethod(getter);
+ fields[i] = FieldWrapper.Create(wrapper, field, fld.Signature, fld.Modifiers);
+ fields[i].EmitGet = CodeEmitter.Create(OpCodes.Call, getter);
+ }
+ else
+ {
+ fields[i] = FieldWrapper.Create(wrapper, field, fld.Signature, fld.Modifiers);
+ }
+ }
+ // if the Java modifiers cannot be expressed in .NET, we emit the Modifiers attribute to store
+ // the Java modifiers
+ if(setModifiers)
+ {
+ ModifiersAttribute.SetModifiers(field, fld.Modifiers);
+ }
+ }
+
+ public override MethodWrapper GetMethodImpl(MethodDescriptor md)
+ {
+ if(methodLookup == null)
+ {
+ methods = new MethodWrapper[classFile.Methods.Length];
+ methodLookup = new Hashtable();
+ for(int i = 0; i < classFile.Methods.Length; i++)
+ {
+ methodLookup[new MethodDescriptor(wrapper.GetClassLoader(), classFile.Methods[i].Name, classFile.Methods[i].Signature)] = i;
+ }
+ }
+ object index = methodLookup[md];
+ if(index != null)
+ {
+ int i = (int)index;
+ if(methods[i] == null)
+ {
+ GenerateMethod(i);
+ }
+ return methods[i];
+ }
+ return null;
+ }
+
+ private void GenerateMethod(int index)
+ {
+ if(methods[index] != null)
+ {
+ throw new InvalidOperationException();
+ }
+ MethodBase method;
+ ClassFile.Method m = classFile.Methods[index];
+ Type[] args = wrapper.GetClassLoader().ArgTypeListFromSig(m.Signature);
+ MethodAttributes attribs = 0;
+ if(m.IsAbstract)
+ {
+ // only if the classfile is abstract, we make the CLR method abstract, otherwise,
+ // we have to generate a method that throws an AbstractMethodError (because the JVM
+ // allows abstract methods in non-abstract classes)
+ if(m.ClassFile.IsAbstract || m.ClassFile.IsInterface)
+ {
+ attribs |= MethodAttributes.Abstract;
+ }
+ }
+ if(m.IsFinal)
+ {
+ if(!m.IsStatic && !m.IsPrivate)
+ {
+ attribs |= MethodAttributes.Final;
+ }
+ }
+ if(m.IsPrivate)
+ {
+ attribs |= MethodAttributes.Private;
+ }
+ else if(m.IsProtected)
+ {
+ attribs |= MethodAttributes.FamORAssem;
+ }
+ else if(m.IsPublic)
+ {
+ attribs |= MethodAttributes.Public;
+ }
+ else
+ {
+ attribs |= MethodAttributes.Assembly;
+ }
+ if(m.IsStatic)
+ {
+ attribs |= MethodAttributes.Static;
+ }
+ if(m.Name == "<init>")
+ {
+ method = typeBuilder.DefineConstructor(attribs, CallingConventions.Standard, args);
+ }
+ else if(m.Name == "<clinit>" && m.Signature == "()V")
+ {
+ // I think this is a CLR bug, the verifier requires static inititializes of interfaces to be public
+ // TODO report this bug
+ if(classFile.IsInterface)
+ {
+ attribs &= ~MethodAttributes.MemberAccessMask;
+ attribs |= MethodAttributes.Public;
+ }
+ method = typeBuilder.DefineConstructor(attribs, CallingConventions.Standard, args);
+ }
+ else
+ {
+ if(!m.IsPrivate && !m.IsStatic)
+ {
+ attribs |= MethodAttributes.Virtual;
+ }
+ string name = m.Name;
+ MethodDescriptor md = new MethodDescriptor(wrapper.GetClassLoader(), name, m.Signature);
+ // if a method is virtual, we need to find the method it overrides (if any), for several reasons:
+ // - if we're overriding a method that has a different name (e.g. some of the virtual methods
+ // in System.Object [Equals <-> equals]) we need to add an explicit MethodOverride
+ // - if one of the base classes has a similar method that is private (or package) that we aren't
+ // overriding, we need to specify an explicit MethodOverride
+ MethodBase baseMethod = null;
+ bool explicitOverride = false;
+ if((attribs & MethodAttributes.Virtual) != 0 && !classFile.IsInterface)
+ {
+ TypeWrapper tw = baseWrapper;
+ while(tw != null)
+ {
+ MethodWrapper baseMce = tw.GetMethodWrapper(md, true);
+ if(baseMce == null)
+ {
+ break;
+ }
+ // here are the complex rules for determining wether this method overrides the method we found
+ // RULE 1: final methods may not be overriden
+ if(baseMce.IsFinal)
+ {
+ // NOTE we don't need to test for our method being private, because if it is
+ // we'll never get here (because private methods aren't virtual)
+ // TODO make sure the VerifyError is translated into a java.lang.VerifyError
+ throw new VerifyError();
+ }
+ // RULE 2: public & protected methods can be overridden (package methods are handled by RULE 4)
+ // (by public, protected & *package* methods [even if they are in a different package])
+ if(baseMce.IsPublic || baseMce.IsProtected)
+ {
+ // if we already encountered a package method, we cannot override the base method of
+ // that package method
+ if(explicitOverride)
+ {
+ explicitOverride = false;
+ break;
+ }
+ // if our method's accessibility is less than the method it overrides, we
+ // need to make our method more accessible, because the CLR doesn't allow reducing access
+ if((attribs & MethodAttributes.Public) == 0)
+ {
+ attribs &= ~MethodAttributes.MemberAccessMask;
+ if(baseMce.IsPublic)
+ {
+ attribs |= MethodAttributes.Public;
+ }
+ else
+ {
+ attribs |= MethodAttributes.FamORAssem;
+ }
+ }
+ baseMethod = baseMce.GetMethod();
+ break;
+ }
+ // RULE 3: private methods are ignored
+ if(!baseMce.IsPrivate)
+ {
+ // RULE 4: package methods can only be overridden in the same package
+ if(baseMce.DeclaringType.IsInSamePackageAs(wrapper))
+ {
+ baseMethod = baseMce.GetMethod();
+ break;
+ }
+ // since we encountered a method with the same name/signature that we aren't overriding,
+ // we need to specify an explicit override
+ // NOTE we only do this if baseMce isn't private, because if it is, Reflection.Emit
+ // will complain about the explicit MethodOverride (possibly a bug)
+ explicitOverride = true;
+ }
+ tw = baseMce.DeclaringType.BaseTypeWrapper;
+ }
+ if(baseMethod == null)
+ {
+ attribs |= MethodAttributes.NewSlot;
+ }
+ }
+ MethodBuilder mb = typeBuilder.DefineMethod(name, attribs, wrapper.GetClassLoader().RetTypeFromSig(m.Signature), args);
+ method = mb;
+ // since Java constructors (and static intializers?) aren't allowed to be synchronized, we only check this here
+ if(m.IsSynchronized)
+ {
+ mb.SetImplementationFlags(method.GetMethodImplementationFlags() | MethodImplAttributes.Synchronized);
+ }
+ if(baseMethod != null && (explicitOverride || baseMethod.Name != name))
+ {
+ // assert that the method we're overriding is in fact virtual and not final!
+ Debug.Assert(baseMethod.IsVirtual && !baseMethod.IsFinal);
+ typeBuilder.DefineMethodOverride(mb, (MethodInfo)baseMethod);
+ }
+ if(!wrapper.IsAbstract && m.IsPublic && !m.IsStatic)
+ {
+ // TODO this must be sped up...
+ // TODO process interfaces implemented by base classes (and interfaces implemented by interfaces)
+ foreach(TypeWrapper ifw in wrapper.BaseTypeWrapper.Interfaces)
+ {
+ MethodWrapper mw = ifw.GetMethodWrapper(md, false);
+ if(mw != null)
+ {
+ // TODO don't add explicit method override, unless it is required
+ typeBuilder.DefineMethodOverride(mb, (MethodInfo)mw.GetMethod());
+ }
+ }
+ }
+ }
+ methods[index] = MethodWrapper.Create(wrapper, new MethodDescriptor(wrapper.GetClassLoader(), m.Name, m.Signature), method, method, m.Modifiers);
+ }
+
+ public override Type Type
+ {
+ get
+ {
+ return typeBuilder;
+ }
+ }
+ }
+
+ private class FinishedTypeImpl : DynamicImpl
+ {
+ private Type type;
+
+ public FinishedTypeImpl(Type type)
+ {
+ this.type = type;
+ }
+
+ public override bool IsInterface
+ {
+ get
+ {
+ return type.IsInterface;
+ }
+ }
+
+ public override FieldWrapper GetFieldImpl(string fieldName)
+ {
+ return null;
+ }
+
+ public override MethodWrapper GetMethodImpl(MethodDescriptor md)
+ {
+ return null;
+ }
+
+ public override Type Type
+ {
+ get
+ {
+ return type;
+ }
+ }
+
+ public override DynamicImpl Finish()
+ {
+ return this;
+ }
+ }
+}
+
+class RemappedTypeWrapper : TypeWrapper
+{
+ private Type type;
+ private TypeWrapper[] interfaces;
+ private bool virtualsInterfaceBuilt;
+ private Type virtualsInterface;
+ private Type virtualsHelperHack;
+
+ public RemappedTypeWrapper(Modifiers modifiers, string name, Type type, TypeWrapper[] interfaces, TypeWrapper baseType)
+ : base(modifiers, name, baseType, ClassLoaderWrapper.GetBootstrapClassLoader())
+ {
+ this.type = type;
+ this.interfaces = interfaces;
+ }
+
+ public void LoadRemappings(MapXml.Class classMap)
+ {
+ bool hasOverrides = false;
+ ArrayList methods = new ArrayList();
+ if(classMap.Methods != null)
+ {
+ foreach(MapXml.Method method in classMap.Methods)
+ {
+ string name = method.Name;
+ string sig = method.Sig;
+ Modifiers modifiers = (Modifiers)method.Modifiers;
+ bool isStatic = (modifiers & Modifiers.Static) != 0;
+ MethodDescriptor md = new MethodDescriptor(GetClassLoader(), name, sig);
+ if(method.invokevirtual == null &&
+ method.invokespecial == null &&
+ method.invokestatic == null &&
+ method.redirect == null &&
+ method.@override == null)
+ {
+ // TODO use a better way to get the method
+ BindingFlags binding = BindingFlags.Public | BindingFlags.NonPublic;
+ if(isStatic)
+ {
+ binding |= BindingFlags.Static;
+ }
+ else
+ {
+ binding |= BindingFlags.Instance;
+ }
+ MethodBase mb = type.GetMethod(name, binding, null, CallingConventions.Standard, md.ArgTypes, null);
+ if(mb == null)
+ {
+ throw new InvalidOperationException("declared method: " + Name + "." + name + sig + " not found");
+ }
+ MethodWrapper mw = MethodWrapper.Create(this, md, mb, mb, modifiers);
+ AddMethod(mw);
+ methods.Add(mw);
+ }
+ else
+ {
+ CodeEmitter newopc = null;
+ CodeEmitter invokespecial = null;
+ CodeEmitter invokevirtual = null;
+ CodeEmitter retcast = null;
+ MethodBase redirect = null;
+ MethodBase overrideMethod = null;
+ if(method.redirect != null)
+ {
+ if(method.invokevirtual != null ||
+ method.invokespecial != null ||
+ method.invokestatic != null ||
+ method.@override != null)
+ {
+ throw new InvalidOperationException();
+ }
+ if(method.redirect.Name != null)
+ {
+ name = method.redirect.Name;
+ }
+ if(method.redirect.Sig != null)
+ {
+ sig = method.redirect.Sig;
+ }
+ string stype = isStatic ? "static" : "instance";
+ if(method.redirect.Type != null)
+ {
+ stype = method.redirect.Type;
+ }
+ MethodDescriptor redir = new MethodDescriptor(GetClassLoader(), name, sig);
+ BindingFlags binding = BindingFlags.Public | BindingFlags.NonPublic;
+ if(stype == "static")
+ {
+ binding |= BindingFlags.Static;
+ }
+ else
+ {
+ binding |= BindingFlags.Instance;
+ }
+ Type t = this.type;
+ if(method.redirect.Class != null)
+ {
+ t = Type.GetType(method.redirect.Class, true);
+ }
+ redirect = t.GetMethod(name, binding, null, CallingConventions.Standard, redir.ArgTypes, null);
+ if(redirect == null)
+ {
+ throw new InvalidOperationException("remapping method: " + name + sig + " not found");
+ }
+ string ret = md.Signature.Substring(md.Signature.IndexOf(')') + 1);
+ // when constructors are remapped, we have to assume that the type is correct because the original
+ // return type (of the constructor) is void.
+ if(ret[0] != 'V' && ret != redir.Signature.Substring(redir.Signature.IndexOf(')') + 1))
+ {
+ retcast = new CastEmitter(md.Signature);
+ }
+ if(BaseTypeWrapper != null && !Type.IsSealed)
+ {
+ MethodWrapper mce1 = BaseTypeWrapper.GetMethodWrapper(md, true);
+ if(mce1 != null)
+ {
+ MethodBase org = mce1.GetMethod();
+ if(org != null)
+ {
+ ParameterInfo[] paramInfo = org.GetParameters();
+ Type[] argTypes = new Type[paramInfo.Length];
+ for(int i = 0; i < argTypes.Length; i++)
+ {
+ argTypes[i] = paramInfo[i].ParameterType;
+ }
+ BindingFlags binding1 = BindingFlags.Public | BindingFlags.NonPublic;
+ if(isStatic)
+ {
+ // TODO this looks like total nonsense, a static method cannot override a method,
+ // so we shouldn't ever get here
+ binding1 |= BindingFlags.Static;
+ }
+ else
+ {
+ binding1 |= BindingFlags.Instance;
+ }
+ overrideMethod = type.GetMethod(org.Name, binding1, null, CallingConventions.Standard, argTypes, null);
+ }
+ }
+ }
+ // NOTE we abuse MethodWrapper.Create here to construct the emitters for us
+ MethodWrapper temp = MethodWrapper.Create(this, md, overrideMethod, redirect, modifiers);
+ newopc = temp.EmitNewobj;
+ invokespecial = temp.EmitCall;
+ invokevirtual = temp.EmitCallvirt;
+ }
+ else
+ {
+ if(method.@override != null)
+ {
+ MethodDescriptor redir = new MethodDescriptor(GetClassLoader(), method.@override.Name, sig);
+ BindingFlags binding = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
+ overrideMethod = type.GetMethod(redir.Name, binding, null, CallingConventions.Standard, redir.ArgTypes, null);
+ if(overrideMethod == null)
+ {
+ throw new InvalidOperationException("Override method not found: " + Name + "." + name + sig);
+ }
+ }
+ invokespecial = method.invokespecial;
+ invokevirtual = method.invokevirtual;
+ if(method.invokestatic != null)
+ {
+ invokespecial = method.invokestatic;
+ }
+ }
+ // if invokespecial isn't redefined, it means that the base class' implementation is correct,
+ // so we don't need to generate an override stub for this method
+ bool trivialOverride = (invokespecial == null);
+ if(overrideMethod != null)
+ {
+ if(invokespecial == null)
+ {
+ invokespecial = CodeEmitter.Create(OpCodes.Call, (MethodInfo)overrideMethod);
+ }
+ if(invokevirtual == null)
+ {
+ invokevirtual = CodeEmitter.Create(OpCodes.Callvirt, (MethodInfo)overrideMethod);
+ }
+ }
+ MethodWrapper mw = new MethodWrapper(this, md, overrideMethod, modifiers);
+ mw.EmitNewobj = newopc;
+ mw.EmitCall = invokespecial;
+ mw.EmitCallvirt = invokevirtual;
+ if(retcast != null)
+ {
+ mw.EmitNewobj += retcast;
+ mw.EmitCall += retcast;
+ mw.EmitCallvirt += retcast;
+ }
+ // don't generate override stubs for trivial methods (i.e. methods that are only renamed)
+ if(overrideMethod != null && !trivialOverride)
+ {
+ hasOverrides = true;
+ mw.IsRemappedOverride = true;
+ }
+ if(method.Type == "virtual")
+ {
+ // TODO we're overwriting the retcast (if there is any). We shouldn't do this.
+ mw.EmitCallvirt = new VirtualEmitter(md, this);
+ mw.IsRemappedVirtual = true;
+ }
+ AddMethod(mw);
+ methods.Add(mw);
+ }
+ }
+ }
+ if(classMap.Constructors != null)
+ {
+ foreach(MapXml.Constructor constructor in classMap.Constructors)
+ {
+ Modifiers modifiers = (Modifiers)constructor.Modifiers;
+ MethodDescriptor md = new MethodDescriptor(GetClassLoader(), "<init>", constructor.Sig);
+ if(constructor.invokespecial == null && constructor.newobj == null && constructor.redirect == null)
+ {
+ // TODO use a better way to get the method
+ BindingFlags binding = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
+ MethodBase method = type.GetConstructor(binding, null, CallingConventions.Standard, md.ArgTypes, null);
+ if(method == null)
+ {
+ throw new InvalidOperationException("declared constructor: " + classMap.Name + constructor.Sig + " not found");
+ }
+ MethodWrapper mw = MethodWrapper.Create(this, md, method, method, modifiers);
+ AddMethod(mw);
+ methods.Add(mw);
+ }
+ else
+ {
+ CodeEmitter newopc = null;
+ CodeEmitter invokespecial = null;
+ CodeEmitter retcast = null;
+ if(constructor.redirect != null)
+ {
+ if(constructor.invokespecial != null || constructor.newobj != null)
+ {
+ throw new InvalidOperationException();
+ }
+ string sig = constructor.Sig;
+ if(constructor.redirect.Sig != null)
+ {
+ sig = constructor.redirect.Sig;
+ }
+ MethodDescriptor redir = new MethodDescriptor(GetClassLoader(), "<init>", sig);
+ BindingFlags binding = BindingFlags.Public | BindingFlags.NonPublic;
+ if(constructor.redirect.Type == "static")
+ {
+ binding |= BindingFlags.Static;
+ if((classMap.Modifiers & MapXml.MapModifiers.Final) == 0)
+ {
+ // NOTE only final classes can have constructors redirected to static methods,
+ // because we don't have support for making the distinction between new and invokespecial
+ throw new InvalidOperationException();
+ }
+ }
+ else
+ {
+ binding |= BindingFlags.Instance;
+ }
+ Type t = this.type;
+ if(constructor.redirect.Class != null)
+ {
+ t = Type.GetType(constructor.redirect.Class, true);
+ }
+ MethodBase redirect = null;
+ if(constructor.redirect.Name != null)
+ {
+ redirect = t.GetMethod(constructor.redirect.Name, binding, null, CallingConventions.Standard, redir.ArgTypes, null);
+ }
+ else
+ {
+ redirect = t.GetConstructor(binding, null, CallingConventions.Standard, redir.ArgTypes, null);
+ }
+ if(redirect == null)
+ {
+ throw new InvalidOperationException("remapping constructor: " + classMap.Name + constructor.Sig + " not found");
+ }
+ string ret = md.Signature.Substring(md.Signature.IndexOf(')') + 1);
+ // when constructors are remapped, we have to assume that the type is correct because the original
+ // return type (of the constructor) is void.
+ // TODO we could look at return type of the redirected method and see if that matches the type of the
+ // object we're supposed to be constructing
+ if(ret[0] != 'V' && ret != redir.Signature.Substring(redir.Signature.IndexOf(')') + 1))
+ {
+ retcast = new CastEmitter(md.Signature);
+ }
+ // NOTE we abuse MethodWrapper.Create here to construct the emitters for us
+ MethodWrapper temp = MethodWrapper.Create(this, md, null, redirect, modifiers);
+ newopc = temp.EmitNewobj;
+ }
+ else
+ {
+ newopc = constructor.newobj;
+ invokespecial = constructor.invokespecial;
+ }
+ MethodWrapper mw = new MethodWrapper(this, md, null, modifiers);
+ mw.EmitNewobj = newopc;
+ mw.EmitCall = invokespecial;
+ if(retcast != null)
+ {
+ mw.EmitNewobj += retcast;
+ mw.EmitCall += retcast;
+ }
+ AddMethod(mw);
+ methods.Add(mw);
+ }
+ }
+ }
+ if(classMap.Fields != null)
+ {
+ foreach(MapXml.Field field in classMap.Fields)
+ {
+ string name = field.Name;
+ string sig = field.Sig;
+ string fieldName = name;
+ string fieldSig = sig;
+ Modifiers modifiers = (Modifiers)field.Modifiers;
+ bool isStatic = (modifiers & Modifiers.Static) != 0;
+ if(field.redirect == null)
+ {
+ throw new InvalidOperationException();
+ }
+ // NOTE when fields are redirected it's always to a method!
+ // NOTE only reading a field can be redirected!
+ if(field.redirect.Name != null)
+ {
+ name = field.redirect.Name;
+ }
+ if(field.redirect.Sig != null)
+ {
+ sig = field.redirect.Sig;
+ }
+ string stype = isStatic ? "static" : "instance";
+ if(field.redirect.Type != null)
+ {
+ stype = field.redirect.Type;
+ }
+ MethodDescriptor redir = new MethodDescriptor(GetClassLoader(), name, sig);
+ BindingFlags binding = BindingFlags.Public | BindingFlags.NonPublic;
+ if(stype == "static")
+ {
+ binding |= BindingFlags.Static;
+ }
+ else
+ {
+ binding |= BindingFlags.Instance;
+ }
+ Type t = this.type;
+ if(field.redirect.Class != null)
+ {
+ t = Type.GetType(field.redirect.Class, true);
+ }
+ MethodInfo method = t.GetMethod(name, binding, null, CallingConventions.Standard, redir.ArgTypes, null);
+ if(method == null)
+ {
+ throw new InvalidOperationException("remapping method: " + name + sig + " not found");
+ }
+ // TODO ensure that return type for redirected method matches with field type, or emit a castclass
+ FieldWrapper fw = new FieldWrapper(this, fieldName, fieldSig, modifiers);
+ fw.EmitGet = CodeEmitter.Create(OpCodes.Call, method);
+ fw.EmitSet = null;
+ AddField(fw);
+ }
+ }
+ // if the type has "overrides" we need to construct a stub class that actually overrides the methods
+ // (for when the type itself is instantiated, instead of a subtype [e.g. java.lang.Throwable])
+ if(hasOverrides)
+ {
+ //Console.WriteLine("constructing override stub for " + Name);
+ // HACK because we don't want to end up with System.Exception (which is the type that corresponds to the
+ // TypeWrapper that corresponds to the type of Throwable$OverrideStub) we have to use GetBootstrapTypeRaw,
+ // which was introduced specifically to deal with this problem
+ Type stubType = ClassLoaderWrapper.GetBootstrapClassLoader().GetBootstrapTypeRaw(Name.Replace('/', '.') + "$OverrideStub");
+ if(stubType != null)
+ {
+ foreach(MethodWrapper mw in methods)
+ {
+ MethodDescriptor md = mw.Descriptor;
+ if(md.Name == "<init>")
+ {
+ //Console.WriteLine("replacing newobj " + stubType.FullName + " to " + stubType.GetConstructor(md.ArgTypes));
+ // NOTE we only support public constructors here, as that correct?
+ mw.EmitNewobj = CodeEmitter.Create(OpCodes.Newobj, stubType.GetConstructor(md.ArgTypes));
+ }
+ }
+ }
+ else
+ {
+ // TODO we can ignore the normal ClassNotFoundException, what should we do with other exceptions?
+ TypeBuilder stub = GetClassLoader().ModuleBuilder.DefineType(Name.Replace('/', '.') + "$OverrideStub", type.Attributes, type);
+ CustomAttributeBuilder overrideStubAttrib = new CustomAttributeBuilder(typeof(OverrideStubTypeAttribute).GetConstructor(Type.EmptyTypes), new object[0]);
+ stub.SetCustomAttribute(overrideStubAttrib);
+ foreach(MethodWrapper mw in methods)
+ {
+ MethodDescriptor md = mw.Descriptor;
+ if(mw.IsRemappedOverride)
+ {
+ MethodBuilder mb = stub.DefineMethod(md.Name, mw.GetMethodAttributes(), CallingConventions.Standard, md.RetType, md.ArgTypes);
+ ILGenerator ilgen = mb.GetILGenerator();
+ ilgen.Emit(OpCodes.Ldarg_0);
+ int argc = md.ArgTypes.Length;
+ for(int n = 0; n < argc; n++)
+ {
+ ilgen.Emit(OpCodes.Ldarg, n + 1);
+ }
+ mw.EmitCall.Emit(ilgen);
+ ilgen.Emit(OpCodes.Ret);
+ // TODO only explicitly override if it is needed
+ stub.DefineMethodOverride(mb, (MethodInfo)mw.GetMethod());
+ }
+ else if(md.Name == "<init>")
+ {
+ ConstructorBuilder cb = stub.DefineConstructor(mw.GetMethodAttributes(), CallingConventions.Standard, md.ArgTypes);
+ ILGenerator ilgen = cb.GetILGenerator();
+ ilgen.Emit(OpCodes.Ldarg_0);
+ int argc = md.ArgTypes.Length;
+ for(int n = 0; n < argc; n++)
+ {
+ ilgen.Emit(OpCodes.Ldarg, n + 1);
+ }
+ mw.EmitCall.Emit(ilgen);
+ ilgen.Emit(OpCodes.Ret);
+ mw.EmitNewobj = CodeEmitter.Create(OpCodes.Newobj, cb);
+ }
+ }
+ // TODO consider post-poning this until the type is really needed
+ stub.CreateType();
+ }
+ }
+ }
+
+ public override bool IsInterface
+ {
+ get
+ {
+ return type.IsInterface;
+ }
+ }
+
+ public override TypeWrapper[] Interfaces
+ {
+ get
+ {
+ return interfaces;
+ }
+ }
+
+ public override Type Type
+ {
+ get
+ {
+ return type;
+ }
+ }
+
+ public override void Finish()
+ {
+ }
+
+ internal override void ImplementOverrideStubsAndVirtuals(TypeBuilder typeBuilder, TypeWrapper wrapper, Hashtable methodLookup)
+ {
+ MethodWrapper[] methods = new MethodWrapper[this.methods.Count];
+ this.methods.Values.CopyTo(methods, 0);
+ Type virtualsInterface = VirtualsInterface;
+ if(virtualsInterface != null)
+ {
+ typeBuilder.AddInterfaceImplementation(virtualsInterface);
+ }
+ for(int i = 0; i < methods.Length; i++)
+ {
+ MethodWrapper mce = methods[i];
+ if(mce.IsRemappedOverride)
+ {
+ MethodDescriptor md = mce.Descriptor;
+ if(!methodLookup.ContainsKey(md))
+ {
+ MethodBuilder mb = typeBuilder.DefineMethod(md.Name, mce.GetMethodAttributes(), CallingConventions.Standard, md.RetType, md.ArgTypes);
+ ILGenerator ilgen = mb.GetILGenerator();
+ ilgen.Emit(OpCodes.Ldarg_0);
+ int argc = md.ArgTypes.Length;
+ for(int n = 0; n < argc; n++)
+ {
+ ilgen.Emit(OpCodes.Ldarg, n + 1);
+ }
+ mce.EmitCall.Emit(ilgen);
+ ilgen.Emit(OpCodes.Ret);
+ // TODO only explicitly override if it is needed
+ typeBuilder.DefineMethodOverride(mb, (MethodInfo)mce.GetMethod());
+ // now add the method to methodLookup, to prevent the virtuals loop below from adding it again
+ methodLookup[md] = md;
+ }
+ }
+ if(mce.IsRemappedVirtual)
+ {
+ MethodDescriptor md = mce.Descriptor;
+ if(!methodLookup.ContainsKey(md))
+ {
+ // TODO the attributes aren't correct, but we cannot make the method non-public, because
+ // that would violate the interface contract. In other words, we need to find a different
+ // mechanism for implementing non-public virtuals.
+ MethodBuilder mb = typeBuilder.DefineMethod(md.Name, MethodAttributes.Virtual | MethodAttributes.Public, CallingConventions.Standard, md.RetType, md.ArgTypes);
+ ILGenerator ilgen = mb.GetILGenerator();
+ ilgen.Emit(OpCodes.Ldarg_0);
+ int argc = md.ArgTypes.Length;
+ for(int n = 0; n < argc; n++)
+ {
+ ilgen.Emit(OpCodes.Ldarg, n + 1);
+ }
+ mce.EmitCall.Emit(ilgen);
+ ilgen.Emit(OpCodes.Ret);
+ }
+ }
+ }
+ }
+
+ private MethodWrapper[] GetVirtuals()
+ {
+ ArrayList array = new ArrayList();
+ foreach(MethodWrapper mw in methods.Values)
+ {
+ if(mw.IsRemappedVirtual)
+ {
+ array.Add(mw);
+ }
+ }
+ return (MethodWrapper[])array.ToArray(typeof(MethodWrapper));
+ }
+
+ private Type VirtualsInterface
+ {
+ get
+ {
+ if(!virtualsInterfaceBuilt)
+ {
+ virtualsInterfaceBuilt = true;
+ MethodWrapper[] virtuals = GetVirtuals();
+ if(virtuals.Length > 0)
+ {
+ // if the virtualsinterface already exists in one of the bootstrap DLLs, we need to reference that one
+ // instead of creating another one, because creating a new type breaks compatibility with pre-compiled code
+ try
+ {
+ virtualsInterface = ClassLoaderWrapper.GetType(Name.Replace('/', '.') + "$VirtualMethods");
+ virtualsHelperHack = ClassLoaderWrapper.GetType(Name.Replace('/', '.') + "$VirtualMethodsHelper");
+ }
+ catch(Exception)
+ {
+ }
+ if(virtualsInterface != null && virtualsHelperHack != null)
+ {
+ return virtualsInterface;
+ }
+ // TODO since this construct makes all virtual methods public, we need to find another way of doing this,
+ // or split the methods in two interfaces, one public and one friendly (but how about protected?).
+ TypeBuilder typeBuilder = GetClassLoader().ModuleBuilder.DefineType(Name.Replace('/', '.') + "$VirtualMethods", TypeAttributes.Abstract | TypeAttributes.Interface | TypeAttributes.Public);
+ TypeBuilder tbStaticHack = GetClassLoader().ModuleBuilder.DefineType(Name.Replace('/', '.') + "$VirtualMethodsHelper", TypeAttributes.Class | TypeAttributes.Public);
+ foreach(MethodWrapper mw in virtuals)
+ {
+ MethodDescriptor md = mw.Descriptor;
+ MethodBuilder ifmethod = typeBuilder.DefineMethod(md.Name, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Abstract, md.RetType, md.ArgTypes);
+ Type[] args = new Type[md.ArgTypes.Length + 1];
+ md.ArgTypes.CopyTo(args, 1);
+ args[0] = this.Type;
+ MethodBuilder mb = tbStaticHack.DefineMethod(md.Name, MethodAttributes.Public | MethodAttributes.Static, md.RetType, args);
+ ILGenerator ilgen = mb.GetILGenerator();
+ ilgen.Emit(OpCodes.Ldarg_0);
+ ilgen.Emit(OpCodes.Isinst, typeBuilder);
+ ilgen.Emit(OpCodes.Dup);
+ Label label1 = ilgen.DefineLabel();
+ ilgen.Emit(OpCodes.Brtrue_S, label1);
+ ilgen.Emit(OpCodes.Pop);
+ for(int i = 0; i < args.Length; i++)
+ {
+ ilgen.Emit(OpCodes.Ldarg, i);
+ }
+ GetMethodWrapper(md, true).EmitCall.Emit(ilgen);
+ Label label2 = ilgen.DefineLabel();
+ ilgen.Emit(OpCodes.Br_S, label2);
+ ilgen.MarkLabel(label1);
+ for(int i = 1; i < args.Length; i++)
+ {
+ ilgen.Emit(OpCodes.Ldarg, i);
+ }
+ ilgen.Emit(OpCodes.Callvirt, ifmethod);
+ ilgen.MarkLabel(label2);
+ ilgen.Emit(OpCodes.Ret);
+ }
+ virtualsInterface = typeBuilder.CreateType();
+ virtualsHelperHack = tbStaticHack.CreateType();
+ }
+ }
+ return virtualsInterface;
+ }
+ }
+
+ // HACK since Reflection.Emit won't allow static methods on an interface (which is a bug), we create
+ // a separate type to contain the static helper methods
+ public Type VirtualsHelperHack
+ {
+ get
+ {
+ // make sure that the type has been created
+ object o = this.VirtualsInterface;
+ return virtualsHelperHack;
+ }
+ }
+
+ protected override FieldWrapper GetFieldImpl(string fieldName)
+ {
+ return null;
+ }
+
+ protected override MethodWrapper GetMethodImpl(MethodDescriptor md)
+ {
+ return null;
+ }
+}
+
+class NetExpTypeWrapper : TypeWrapper
+{
+ private ClassFile classFile;
+ private Type type;
+
+ // TODO consider constructing modifiers from .NET type instead of the netexp class
+ public NetExpTypeWrapper(ClassFile f, string dotnetType, TypeWrapper baseType)
+ : base(f.Modifiers, f.Name, baseType, ClassLoaderWrapper.GetBootstrapClassLoader())
+ {
+ this.classFile = f;
+ // TODO if the type isn't found, it should be handled differently
+ type = Type.GetType(dotnetType, true);
+ }
+
+ public override bool IsInterface
+ {
+ get
+ {
+ return type.IsInterface;
+ }
+ }
+
+ public override TypeWrapper[] Interfaces
+ {
+ get
+ {
+ // TODO resolve the interfaces!
+ return new TypeWrapper[0];
+ }
+ }
+
+ protected override FieldWrapper GetFieldImpl(string fieldName)
+ {
+ // HACK this is a totally broken quick & dirty implementation
+ // TODO clean this up, add error checking and whatnot
+ FieldInfo field = type.GetField(fieldName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
+ Modifiers modifiers = ModifiersAttribute.GetModifiers(field);
+ if(modifiers != Modifiers.Synthetic)
+ {
+ return FieldWrapper.Create(this, field, MethodDescriptor.getSigName(field.FieldType), modifiers);
+ }
+ return null;
+ }
+
+ private class DelegateConstructorEmitter : CodeEmitter
+ {
+ private ConstructorInfo delegateConstructor;
+ private MethodInfo method;
+
+ internal DelegateConstructorEmitter(ConstructorInfo delegateConstructor, MethodInfo method)
+ {
+ this.delegateConstructor = delegateConstructor;
+ this.method = method;
+ }
+
+ internal override void Emit(ILGenerator ilgen)
+ {
+ ilgen.Emit(OpCodes.Dup);
+ ilgen.Emit(OpCodes.Ldvirtftn, method);
+ ilgen.Emit(OpCodes.Newobj, delegateConstructor);
+ }
+ }
+
+ protected override MethodWrapper GetMethodImpl(MethodDescriptor md)
+ {
+ // special case for delegate constructors!
+ if(md.Name == "<init>" && type.IsSubclassOf(typeof(MulticastDelegate)))
+ {
+ // TODO set method flags
+ MethodWrapper method = new MethodWrapper(this, md, null, Modifiers.Public);
+ // TODO what class loader should we use?
+ TypeWrapper iface = ClassLoaderWrapper.GetBootstrapClassLoader().LoadClassBySlashedName(classFile.Name + "$Method");
+ iface.Finish();
+ method.EmitNewobj = new DelegateConstructorEmitter(type.GetConstructor(new Type[] { typeof(object), typeof(IntPtr) }), iface.Type.GetMethod("Invoke"));
+ return method;
+ }
+ // HACK this is a totally broken quick & dirty implementation
+ // TODO clean this up, add error checking and whatnot
+ ClassFile.Method[] methods = classFile.Methods;
+ for(int i = 0; i < methods.Length; i++)
+ {
+ if(methods[i].Name == md.Name && methods[i].Signature == md.Signature)
+ {
+ Type[] args;
+ string[] sig = methods[i].NetExpSigAttribute;
+ if(sig == null)
+ {
+ args = md.ArgTypes;
+ }
+ else
+ {
+ args = new Type[sig.Length];
+ for(int j = 0; j < sig.Length; j++)
+ {
+ args[j] = Type.GetType(sig[j], true);
+ }
+ }
+ MethodBase method;
+ if(md.Name == "<init>")
+ {
+ method = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, CallingConventions.Standard, args, null);
+ }
+ else
+ {
+ method = type.GetMethod(md.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance, null, CallingConventions.Standard, args, null);
+ }
+ if(method != null)
+ {
+ // TODO we can decode the actual method attributes, or we can use them from the NetExp class, what is
+ // preferred?
+ return MethodWrapper.Create(this, md, method, method, ModifiersAttribute.GetModifiers(method));
+ }
+ }
+ }
+ return null;
+ }
+
+ public override Type Type
+ {
+ get
+ {
+ return type;
+ }
+ }
+
+ public override void Finish()
+ {
+ }
+}
+
+class CompiledTypeWrapper : TypeWrapper
+{
+ private Type type;
+ private TypeWrapper[] interfaces;
+
+ // TODO consider resolving the baseType lazily
+ internal CompiledTypeWrapper(string name, Type type, TypeWrapper baseType)
+ : base(ModifiersAttribute.GetModifiers(type), name, baseType, ClassLoaderWrapper.GetBootstrapClassLoader())
+ {
+ this.type = type;
+ }
+
+ public override bool IsInterface
+ {
+ get
+ {
+ return type.IsInterface;
+ }
+ }
+
+ public override TypeWrapper[] Interfaces
+ {
+ get
+ {
+ if(interfaces == null)
+ {
+ // TODO instead of getting the interfaces list from Type, we should use a custom
+ // attribute to list the implemented interfaces (alternatively, we could check the assembly
+ // of each interface to make sure it is from an IKVM compiled assembly, but even if the
+ // interfaces doesn't come from an IKVM assembly we still must call GetWrapperFromTypeFast
+ // to handle remapped interfaces.
+ Type[] ifaces = type.GetInterfaces();
+ ArrayList wrappers = new ArrayList();
+ for(int i = 0; i < ifaces.Length; i++)
+ {
+ // HACK if the interface wrapper isn't found, we'll just ignore it (this happens for
+ // example for Throwable derived classes, which seem to implement ISerializable [because System.Exception does],
+ // but we cannot find a wrapper for this type)
+ try
+ {
+ wrappers.Add(ClassLoaderWrapper.GetWrapperFromType(ifaces[i]));
+ }
+ catch(Exception)
+ {
+ }
+ }
+ interfaces = (TypeWrapper[])wrappers.ToArray(typeof(TypeWrapper));
+ }
+ return interfaces;
+ }
+ }
+
+ // TODO there is an inconsistency here, this method returns regular FieldWrappers for final fields, while
+ // GetFieldImpl returns a FieldWrapper that is aware of the getter method. Currently this isn't a problem,
+ // because this method is used for reflection (which doesn't care about accessibility) and GetFieldImpl is used for
+ // compiled code (which does care about accessibility).
+ internal override FieldWrapper[] GetFields()
+ {
+ ArrayList list = new ArrayList();
+ FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
+ for(int i = 0; i < fields.Length; i++)
+ {
+ Modifiers modifiers = ModifiersAttribute.GetModifiers(fields[i]);
+ if(modifiers != Modifiers.Synthetic)
+ {
+ list.Add(CreateFieldWrapper(modifiers, fields[i].Name, fields[i].FieldType, fields[i], null));
+ }
+ }
+ return (FieldWrapper[])list.ToArray(typeof(FieldWrapper));
+ }
+
+ private FieldWrapper CreateFieldWrapper(Modifiers modifiers, string name, Type fieldType, FieldInfo field, MethodInfo getter)
+ {
+ FieldWrapper fieldWrapper = new FieldWrapper(this, name, MethodDescriptor.getSigName(fieldType), modifiers);
+ if((modifiers & Modifiers.Static) != 0)
+ {
+ if(getter != null)
+ {
+ fieldWrapper.EmitGet = CodeEmitter.Create(OpCodes.Call, getter);
+ }
+ else
+ {
+ // TODO if field is a literal, we should emit an ldc instead of a ldsfld
+ fieldWrapper.EmitGet = CodeEmitter.Create(OpCodes.Ldsfld, field);
+ }
+ if(field != null)
+ {
+ fieldWrapper.EmitSet = CodeEmitter.Create(OpCodes.Stsfld, field);
+ }
+ else
+ {
+ // TODO what happens when you try to set a final field?
+ // through reflection: java.lang.IllegalAccessException: Field is final
+ // through code: java.lang.IllegalAccessError: Field <class>.<field> is final
+ fieldWrapper.EmitSet = CodeEmitter.Create(OpCodes.Nop);
+ }
+ }
+ else
+ {
+ if(getter != null)
+ {
+ fieldWrapper.EmitGet = CodeEmitter.Create(OpCodes.Callvirt, getter);
+ }
+ else
+ {
+ // TODO is it possible to have literal instance fields?
+ fieldWrapper.EmitGet = CodeEmitter.Create(OpCodes.Ldfld, field);
+ }
+ if(field != null)
+ {
+ fieldWrapper.EmitSet = CodeEmitter.Create(OpCodes.Stfld, field);
+ }
+ else
+ {
+ // TODO what happens when you try to set a final field through reflection?
+ // see above
+ fieldWrapper.EmitSet = CodeEmitter.Create(OpCodes.Nop);
+ }
+ }
+ return fieldWrapper;
+ }
+
+ protected override FieldWrapper GetFieldImpl(string fieldName)
+ {
+ // TODO this is a crappy implementation, just to get going, but it needs to be revisited
+ MemberInfo[] members = type.GetMember(fieldName, MemberTypes.Field | MemberTypes.Property, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
+ if(members.Length > 2)
+ {
+ throw new NotImplementedException();
+ }
+ if(members.Length == 0)
+ {
+ return null;
+ }
+ if(members.Length == 2)
+ {
+ PropertyInfo prop;
+ FieldInfo field;
+ if(members[0] is PropertyInfo && !(members[1] is PropertyInfo))
+ {
+ prop = (PropertyInfo)members[0];
+ field = (FieldInfo)members[1];
+ }
+ else if(members[1] is PropertyInfo && !(members[0] is PropertyInfo))
+ {
+ prop = (PropertyInfo)members[1];
+ field = (FieldInfo)members[0];
+ }
+ else
+ {
+ throw new InvalidOperationException();
+ }
+ Modifiers modifiers = ModifiersAttribute.GetModifiers(field);
+ MethodInfo getter = prop.GetGetMethod(true);
+ MethodInfo setter = prop.GetSetMethod(true);
+ if(getter == null || setter != null)
+ {
+ throw new InvalidOperationException();
+ }
+ return CreateFieldWrapper(modifiers, field.Name, field.FieldType, field, getter);
+ }
+ else
+ {
+ FieldInfo fi = (FieldInfo)members[0];
+ return CreateFieldWrapper(ModifiersAttribute.GetModifiers(fi), fi.Name, fi.FieldType, fi, null);
+ }
+ }
+
+ // TODO this is broken
+ internal override MethodWrapper[] GetMethods()
+ {
+ ArrayList list = new ArrayList();
+ MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
+ for(int i = 0; i < methods.Length; i++)
+ {
+ MethodWrapper mw = CreateMethodWrapper(MethodDescriptor.FromMethodBase(methods[i]), methods[i]);
+ if(mw != null)
+ {
+ list.Add(mw);
+ }
+ }
+ ConstructorInfo[] constructors = type.GetConstructors(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
+ for(int i = 0; i < constructors.Length; i++)
+ {
+ MethodWrapper mw = CreateMethodWrapper(MethodDescriptor.FromMethodBase(constructors[i]), constructors[i]);
+ if(mw != null)
+ {
+ list.Add(mw);
+ }
+ }
+ return (MethodWrapper[])list.ToArray(typeof(MethodWrapper));
+ }
+
+ private MethodWrapper CreateMethodWrapper(MethodDescriptor md, MethodBase mb)
+ {
+ Modifiers modifiers = ModifiersAttribute.GetModifiers(mb);
+ if(modifiers == Modifiers.Synthetic)
+ {
+ return null;
+ }
+ MethodWrapper method = new MethodWrapper(this, md, mb, ModifiersAttribute.GetModifiers(mb));
+ if(mb is ConstructorInfo)
+ {
+ method.EmitCall = CodeEmitter.Create(OpCodes.Call, (ConstructorInfo)mb);
+ method.EmitNewobj = CodeEmitter.Create(OpCodes.Newobj, (ConstructorInfo)mb);
+ }
+ else
+ {
+ method.EmitCall = CodeEmitter.Create(OpCodes.Call, (MethodInfo)mb);
+ if(!mb.IsStatic)
+ {
+ method.EmitCallvirt = CodeEmitter.Create(OpCodes.Callvirt, (MethodInfo)mb);
+ }
+ }
+ return method;
+ }
+
+ protected override MethodWrapper GetMethodImpl(MethodDescriptor md)
+ {
+ // TODO this is a crappy implementation, just to get going, but it needs to be revisited
+ if(md.Name == "<init>")
+ {
+ ConstructorInfo ci = type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, md.ArgTypes, null);
+ if(ci != null)
+ {
+ return CreateMethodWrapper(md, ci);
+ }
+ }
+ else
+ {
+ MethodInfo mi = type.GetMethod(md.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static, null, CallingConventions.Standard, md.ArgTypes, null);
+ if(mi != null)
+ {
+ return CreateMethodWrapper(md, mi);
+ }
+ }
+ return null;
+ }
+
+ public override Type Type
+ {
+ get
+ {
+ return type;
+ }
+ }
+
+ public override void Finish()
+ {
+ }
+}
+
+public sealed class JniHack : IJniHack
+{
+ public override System.Reflection.MethodBase GetMethod(object clazz, string name, string sig, bool isStatic)
+ {
+ // TODO this is totally broken, because JNI needs to support redirection
+ TypeWrapper wrapper = ClassLoaderWrapper.GetWrapperFromType(NativeCode.java.lang.Class.getType(clazz));
+ wrapper.Finish();
+ MethodDescriptor md = new MethodDescriptor(wrapper.GetClassLoader(), name, sig);
+ BindingFlags bindings = BindingFlags.Public | BindingFlags.NonPublic;
+ if(isStatic)
+ {
+ bindings |= BindingFlags.Static;
+ }
+ else
+ {
+ bindings |= BindingFlags.Instance;
+ }
+ if(name == "<init>")
+ {
+ return wrapper.Type.GetConstructor(bindings, null, md.ArgTypes, null);
+ }
+ Type type = wrapper.Type;
+ while(type != null)
+ {
+ MethodInfo m = type.GetMethod(name, bindings, null, CallingConventions.Standard, md.ArgTypes, null);
+ if(m != null)
+ {
+ return m;
+ }
+ type = type.BaseType;
+ }
+ return null;
+ }
+
+ public override System.Reflection.FieldInfo GetField(object clazz, string name, string sig, bool isStatic)
+ {
+ // TODO this is totally broken, because JNI needs to support redirection
+ TypeWrapper wrapper = ClassLoaderWrapper.GetWrapperFromType(NativeCode.java.lang.Class.getType(clazz));
+ wrapper.Finish();
+ MethodDescriptor md = new MethodDescriptor(wrapper.GetClassLoader(), name, sig);
+ BindingFlags bindings = BindingFlags.Public | BindingFlags.NonPublic;
+ if(isStatic)
+ {
+ bindings |= BindingFlags.Static;
+ }
+ else
+ {
+ bindings |= BindingFlags.Instance;
+ }
+ return wrapper.Type.GetField(name, bindings);
+ }
+
+ public override object FindClass(string javaName)
+ {
+ TypeWrapper wrapper = ClassLoaderWrapper.GetBootstrapClassLoader().LoadClassBySlashedName(javaName);
+ wrapper.Finish();
+ return NativeCode.java.lang.Class.getClassFromWrapper(wrapper);
+ }
+
+ public override Exception UnsatisfiedLinkError(string msg)
+ {
+ return JavaException.UnsatisfiedLinkError(msg);
+ }
+
+ public override object GetClassFromType(Type type)
+ {
+ return NativeCode.java.lang.Class.getClassFromType(type);
+ }
+}
+
+public abstract class CodeEmitter
+{
+ internal abstract void Emit(ILGenerator ilgen);
+
+ private class ChainCodeEmitter : CodeEmitter
+ {
+ private CodeEmitter left;
+ private CodeEmitter right;
+
+ internal ChainCodeEmitter(CodeEmitter left, CodeEmitter right)
+ {
+ this.left = left;
+ this.right = right;
+ }
+
+ internal override void Emit(ILGenerator ilgen)
+ {
+ left.Emit(ilgen);
+ right.Emit(ilgen);
+ }
+ }
+
+ public static CodeEmitter operator+(CodeEmitter left, CodeEmitter right)
+ {
+ if(left == null)
+ {
+ return right;
+ }
+ return new ChainCodeEmitter(left, right);
+ }
+
+ private class MethodInfoCodeEmitter : CodeEmitter
+ {
+ private OpCode opcode;
+ private MethodInfo mi;
+
+ internal MethodInfoCodeEmitter(OpCode opcode, MethodInfo mi)
+ {
+ this.opcode = opcode;
+ this.mi = mi;
+ }
+
+ internal override void Emit(ILGenerator ilgen)
+ {
+ ilgen.Emit(opcode, mi);
+ }
+ }
+
+ internal static CodeEmitter Create(OpCode opcode, MethodInfo mi)
+ {
+ return new MethodInfoCodeEmitter(opcode, mi);
+ }
+
+ private class ConstructorInfoCodeEmitter : CodeEmitter
+ {
+ private OpCode opcode;
+ private ConstructorInfo ci;
+
+ internal ConstructorInfoCodeEmitter(OpCode opcode, ConstructorInfo ci)
+ {
+ this.opcode = opcode;
+ this.ci = ci;
+ }
+
+ internal override void Emit(ILGenerator ilgen)
+ {
+ ilgen.Emit(opcode, ci);
+ }
+ }
+
+ internal static CodeEmitter Create(OpCode opcode, ConstructorInfo ci)
+ {
+ return new ConstructorInfoCodeEmitter(opcode, ci);
+ }
+
+ private class FieldInfoCodeEmitter : CodeEmitter
+ {
+ private OpCode opcode;
+ private FieldInfo fi;
+
+ internal FieldInfoCodeEmitter(OpCode opcode, FieldInfo fi)
+ {
+ this.opcode = opcode;
+ this.fi = fi;
+ }
+
+ internal override void Emit(ILGenerator ilgen)
+ {
+ ilgen.Emit(opcode, fi);
+ }
+ }
+
+ internal static CodeEmitter Create(OpCode opcode, FieldInfo fi)
+ {
+ return new FieldInfoCodeEmitter(opcode, fi);
+ }
+
+ private class OpCodeEmitter : CodeEmitter
+ {
+ private OpCode opcode;
+
+ internal OpCodeEmitter(OpCode opcode)
+ {
+ this.opcode = opcode;
+ }
+
+ internal override void Emit(ILGenerator ilgen)
+ {
+ ilgen.Emit(opcode);
+ }
+ }
+
+ internal static CodeEmitter Create(OpCode opcode)
+ {
+ return new OpCodeEmitter(opcode);
+ }
+
+ private class TypeCodeEmitter : CodeEmitter
+ {
+ private OpCode opcode;
+ private Type type;
+
+ internal TypeCodeEmitter(OpCode opcode, Type type)
+ {
+ this.opcode = opcode;
+ this.type = type;
+ }
+
+ internal override void Emit(ILGenerator ilgen)
+ {
+ ilgen.Emit(opcode, type);
+ }
+ }
+
+ internal static CodeEmitter Create(OpCode opcode, Type type)
+ {
+ return new TypeCodeEmitter(opcode, type);
+ }
+
+ private class IntCodeEmitter : CodeEmitter
+ {
+ private OpCode opcode;
+ private int i;
+
+ internal IntCodeEmitter(OpCode opcode, int i)
+ {
+ this.opcode = opcode;
+ this.i = i;
+ }
+
+ internal override void Emit(ILGenerator ilgen)
+ {
+ ilgen.Emit(opcode, i);
+ }
+ }
+
+ internal static CodeEmitter Create(OpCode opcode, int i)
+ {
+ return new IntCodeEmitter(opcode, i);
+ }
+
+ private class FloatCodeEmitter : CodeEmitter
+ {
+ private OpCode opcode;
+ private float f;
+
+ internal FloatCodeEmitter(OpCode opcode, float f)
+ {
+ this.opcode = opcode;
+ this.f = f;
+ }
+
+ internal override void Emit(ILGenerator ilgen)
+ {
+ ilgen.Emit(opcode, f);
+ }
+ }
+
+ internal static CodeEmitter Create(OpCode opcode, float f)
+ {
+ return new FloatCodeEmitter(opcode, f);
+ }
+
+ private class DoubleCodeEmitter : CodeEmitter
+ {
+ private OpCode opcode;
+ private double d;
+
+ internal DoubleCodeEmitter(OpCode opcode, double d)
+ {
+ this.opcode = opcode;
+ this.d = d;
+ }
+
+ internal override void Emit(ILGenerator ilgen)
+ {
+ ilgen.Emit(opcode, d);
+ }
+ }
+
+ internal static CodeEmitter Create(OpCode opcode, double d)
+ {
+ return new DoubleCodeEmitter(opcode, d);
+ }
+
+ private class StringCodeEmitter : CodeEmitter
+ {
+ private OpCode opcode;
+ private string s;
+
+ internal StringCodeEmitter(OpCode opcode, string s)
+ {
+ this.opcode = opcode;
+ this.s = s;
+ }
+
+ internal override void Emit(ILGenerator ilgen)
+ {
+ ilgen.Emit(opcode, s);
+ }
+ }
+
+ internal static CodeEmitter Create(OpCode opcode, string s)
+ {
+ return new StringCodeEmitter(opcode, s);
+ }
+
+ private class LongCodeEmitter : CodeEmitter
+ {
+ private OpCode opcode;
+ private long l;
+
+ internal LongCodeEmitter(OpCode opcode, long l)
+ {
+ this.opcode = opcode;
+ this.l = l;
+ }
+
+ internal override void Emit(ILGenerator ilgen)
+ {
+ ilgen.Emit(opcode, l);
+ }
+ }
+
+ internal static CodeEmitter Create(OpCode opcode, long l)
+ {
+ return new LongCodeEmitter(opcode, l);
+ }
+}
+
+sealed class MethodWrapper
+{
+ private TypeWrapper declaringType;
+ private MethodDescriptor md;
+ private MethodBase originalMethod;
+ private Modifiers modifiers;
+ private bool isRemappedVirtual;
+ private bool isRemappedOverride;
+ internal CodeEmitter EmitCall;
+ internal CodeEmitter EmitCallvirt;
+ internal CodeEmitter EmitNewobj;
+
+ internal static MethodWrapper Create(TypeWrapper declaringType, MethodDescriptor md, MethodBase originalMethod, MethodBase method, Modifiers modifiers)
+ {
+ if(method == null)
+ {
+ throw new InvalidOperationException();
+ }
+ MethodWrapper wrapper = new MethodWrapper(declaringType, md, originalMethod, modifiers);
+ if(method is ConstructorInfo)
+ {
+ wrapper.EmitCall = CodeEmitter.Create(OpCodes.Call, (ConstructorInfo)method);
+ wrapper.EmitCallvirt = null;
+ wrapper.EmitNewobj = CodeEmitter.Create(OpCodes.Newobj, (ConstructorInfo)method);
+ }
+ else
+ {
+ wrapper.EmitCall = CodeEmitter.Create(OpCodes.Call, (MethodInfo)method);
+ if(originalMethod != null && originalMethod != method)
+ {
+ // if we're calling a virtual method that is redirected, that overrides an already
+ // existing method, we have to call it virtually, instead of redirecting
+ wrapper.EmitCallvirt = CodeEmitter.Create(OpCodes.Callvirt, (MethodInfo)originalMethod);
+ }
+ else if(method.IsStatic)
+ {
+ // because of redirection, it can be legal to call a static method with invokevirtual
+ wrapper.EmitCallvirt = CodeEmitter.Create(OpCodes.Call, (MethodInfo)method);
+ }
+ else
+ {
+ wrapper.EmitCallvirt = CodeEmitter.Create(OpCodes.Callvirt, (MethodInfo)method);
+ }
+ wrapper.EmitNewobj = CodeEmitter.Create(OpCodes.Call, (MethodInfo)method);
+ }
+ return wrapper;
+ }
+
+ internal MethodWrapper(TypeWrapper declaringType, MethodDescriptor md, MethodBase originalMethod, Modifiers modifiers)
+ {
+ this.declaringType = declaringType;
+ this.md = md;
+ // NOTE originalMethod may be null
+ this.originalMethod = originalMethod;
+ this.modifiers = modifiers;
+ }
+
+ internal TypeWrapper DeclaringType
+ {
+ get
+ {
+ return declaringType;
+ }
+ }
+
+ internal MethodDescriptor Descriptor
+ {
+ get
+ {
+ return md;
+ }
+ }
+
+ internal string Name
+ {
+ get
+ {
+ return md.Name;
+ }
+ }
+
+ internal TypeWrapper ReturnType
+ {
+ get
+ {
+ return declaringType.GetClassLoader().RetTypeWrapperFromSig(md.Signature);
+ }
+ }
+
+ internal TypeWrapper[] GetParameters()
+ {
+ return declaringType.GetClassLoader().ArgTypeWrapperListFromSig(md.Signature);
+ }
+
+ internal Modifiers Modifiers
+ {
+ get
+ {
+ return modifiers;
+ }
+ }
+
+ // IsRemappedOverride (only possible for remapped types) indicates whether the method in the
+ // remapped type overrides (i.e. replaces) the method from the underlying type
+ // Example: System.Object.ToString() is overriden by java.lang.Object.toString(),
+ // because java.lang.Object's toString() does something different from
+ // System.Object's ToString().
+ internal bool IsRemappedOverride
+ {
+ get
+ {
+ return isRemappedOverride;
+ }
+ set
+ {
+ isRemappedOverride = value;
+ }
+ }
+
+ // IsRemappedVirtual (only possible for remapped types) indicates that the method is virtual,
+ // but doesn't really exist in the underlying type (there is no vtable slot to reuse)
+ internal bool IsRemappedVirtual
+ {
+ get
+ {
+ return isRemappedVirtual;
+ }
+ set
+ {
+ isRemappedVirtual = value;
+ }
+ }
+
+ // we expose the underlying MethodBase object,
+ // for Java types, this is the method that contains the compiled Java bytecode
+ // for remapped types, this is the method that underlies the remapped method
+ internal MethodBase GetMethod()
+ {
+ return originalMethod;
+ }
+
+ // this returns the Java method's attributes in .NET terms (e.g. used to create stubs for this method)
+ internal MethodAttributes GetMethodAttributes()
+ {
+ MethodAttributes attribs = 0;
+ if(IsStatic)
+ {
+ attribs |= MethodAttributes.Static;
+ }
+ if(IsPublic)
+ {
+ attribs |= MethodAttributes.Public;
+ }
+ else if(IsPrivate)
+ {
+ attribs |= MethodAttributes.Private;
+ }
+ else if(IsProtected)
+ {
+ attribs |= MethodAttributes.FamORAssem;
+ }
+ else
+ {
+ attribs |= MethodAttributes.Family;
+ }
+ // constructors aren't virtual
+ if(!IsStatic && !IsPrivate && md.Name != "<init>")
+ {
+ attribs |= MethodAttributes.Virtual;
+ }
+ if(IsFinal)
+ {
+ attribs |= MethodAttributes.Final;
+ }
+ if(IsAbstract)
+ {
+ attribs |= MethodAttributes.Abstract;
+ }
+ return attribs;
+ }
+
+ internal bool IsStatic
+ {
+ get
+ {
+ return (modifiers & Modifiers.Static) != 0;
+ }
+ }
+
+ internal bool IsPublic
+ {
+ get
+ {
+ return (modifiers & Modifiers.Public) != 0;
+ }
+ }
+
+ internal bool IsPrivate
+ {
+ get
+ {
+ return (modifiers & Modifiers.Private) != 0;
+ }
+ }
+
+ internal bool IsProtected
+ {
+ get
+ {
+ return (modifiers & Modifiers.Protected) != 0;
+ }
+ }
+
+ internal bool IsFinal
+ {
+ get
+ {
+ return (modifiers & Modifiers.Final) != 0;
+ }
+ }
+
+ internal bool IsAbstract
+ {
+ get
+ {
+ return (modifiers & Modifiers.Abstract) != 0;
+ }
+ }
+}
+
+class CastEmitter : CodeEmitter
+{
+ private Type retType;
+ private string sig;
+
+ internal CastEmitter(string sig)
+ {
+ this.sig = sig;
+ }
+
+ internal override void Emit(ILGenerator ilgen)
+ {
+ if(retType == null)
+ {
+ retType = ClassLoaderWrapper.GetBootstrapClassLoader().RetTypeFromSig(sig);
+ }
+ ilgen.Emit(OpCodes.Castclass, retType);
+ }
+}
+
+class VirtualEmitter : CodeEmitter
+{
+ private MethodDescriptor md;
+ private RemappedTypeWrapper wrapper;
+ private MethodInfo method;
+
+ internal VirtualEmitter(MethodDescriptor md, RemappedTypeWrapper wrapper)
+ {
+ this.md = md;
+ this.wrapper = wrapper;
+ }
+
+ internal override void Emit(ILGenerator ilgen)
+ {
+ if(method == null)
+ {
+ Type[] args = new Type[md.ArgTypes.Length + 1];
+ md.ArgTypes.CopyTo(args, 1);
+ args[0] = wrapper.Type;
+ method = wrapper.VirtualsHelperHack.GetMethod(md.Name, BindingFlags.Public | BindingFlags.Static, null, CallingConventions.Standard, args, null);
+ }
+ ilgen.Emit(OpCodes.Call, method);
+ }
+}
+
+sealed class FieldWrapper
+{
+ private TypeWrapper declaringType;
+ private string name;
+ private string sig;
+ private Modifiers modifiers;
+ internal CodeEmitter EmitGet;
+ internal CodeEmitter EmitSet;
+
+ internal FieldWrapper(TypeWrapper declaringType, string name, string sig, Modifiers modifiers)
+ {
+ if(modifiers == Modifiers.Synthetic)
+ {
+ throw new InvalidOperationException();
+ }
+ this.declaringType = declaringType;
+ this.name = name;
+ this.sig = sig;
+ this.modifiers = modifiers;
+ }
+
+ internal TypeWrapper DeclaringType
+ {
+ get
+ {
+ return declaringType;
+ }
+ }
+
+ internal string Name
+ {
+ get
+ {
+ return name;
+ }
+ }
+
+ internal Type FieldType
+ {
+ get
+ {
+ return declaringType.GetClassLoader().ExpressionType(sig);
+ }
+ }
+
+ internal Modifiers Modifiers
+ {
+ get
+ {
+ return modifiers;
+ }
+ }
+
+ internal bool IsStatic
+ {
+ get
+ {
+ return (modifiers & Modifiers.Static) != 0;
+ }
+ }
+
+ internal bool IsPublic
+ {
+ get
+ {
+ return (modifiers & Modifiers.Public) != 0;
+ }
+ }
+
+ internal bool IsPrivate
+ {
+ get
+ {
+ return (modifiers & Modifiers.Private) != 0;
+ }
+ }
+
+ internal bool IsProtected
+ {
+ get
+ {
+ return (modifiers & Modifiers.Protected) != 0;
+ }
+ }
+
+ internal bool IsFinal
+ {
+ get
+ {
+ return (modifiers & Modifiers.Final) != 0;
+ }
+ }
+
+ internal bool IsVolatile
+ {
+ get
+ {
+ return (modifiers & Modifiers.Volatile) != 0;
+ }
+ }
+
+ private class VolatileLongDoubleGetter : CodeEmitter
+ {
+ private static MethodInfo getFieldFromHandle = typeof(FieldInfo).GetMethod("GetFieldFromHandle");
+ private static MethodInfo monitorEnter = typeof(System.Threading.Monitor).GetMethod("Enter");
+ private static MethodInfo monitorExit = typeof(System.Threading.Monitor).GetMethod("Exit");
+ private FieldInfo fi;
+
+ internal VolatileLongDoubleGetter(FieldInfo fi)
+ {
+ this.fi = fi;
+ }
+
+ internal override void Emit(ILGenerator ilgen)
+ {
+ if(!fi.IsStatic)
+ {
+ ilgen.Emit(OpCodes.Dup);
+ Label label = ilgen.DefineLabel();
+ ilgen.Emit(OpCodes.Brtrue, label);
+ ilgen.ThrowException(typeof(NullReferenceException));
+ ilgen.MarkLabel(label);
+ }
+ // HACK we lock on the FieldInfo object
+ ilgen.Emit(OpCodes.Ldtoken, fi);
+ ilgen.Emit(OpCodes.Call, getFieldFromHandle);
+ ilgen.Emit(OpCodes.Call, monitorEnter);
+ if(fi.IsStatic)
+ {
+ ilgen.Emit(OpCodes.Ldsfld, fi);
+ }
+ else
+ {
+ ilgen.Emit(OpCodes.Ldfld, fi);
+ }
+ ilgen.Emit(OpCodes.Ldtoken, fi);
+ ilgen.Emit(OpCodes.Call, getFieldFromHandle);
+ ilgen.Emit(OpCodes.Call, monitorExit);
+ }
+ }
+
+ private class VolatileLongDoubleSetter : CodeEmitter
+ {
+ private static MethodInfo getFieldFromHandle = typeof(FieldInfo).GetMethod("GetFieldFromHandle");
+ private static MethodInfo monitorEnter = typeof(System.Threading.Monitor).GetMethod("Enter");
+ private static MethodInfo monitorExit = typeof(System.Threading.Monitor).GetMethod("Exit");
+ private FieldInfo fi;
+
+ internal VolatileLongDoubleSetter(FieldInfo fi)
+ {
+ this.fi = fi;
+ }
+
+ internal override void Emit(ILGenerator ilgen)
+ {
+ if(!fi.IsStatic)
+ {
+ LocalBuilder local = ilgen.DeclareLocal(fi.FieldType);
+ ilgen.Emit(OpCodes.Stloc, local);
+ ilgen.Emit(OpCodes.Dup);
+ Label label = ilgen.DefineLabel();
+ ilgen.Emit(OpCodes.Brtrue, label);
+ ilgen.ThrowException(typeof(NullReferenceException));
+ ilgen.MarkLabel(label);
+ ilgen.Emit(OpCodes.Ldloc, local);
+ }
+ // HACK we lock on the FieldInfo object
+ ilgen.Emit(OpCodes.Ldtoken, fi);
+ ilgen.Emit(OpCodes.Call, getFieldFromHandle);
+ ilgen.Emit(OpCodes.Call, monitorEnter);
+ if(fi.IsStatic)
+ {
+ ilgen.Emit(OpCodes.Stsfld, fi);
+ }
+ else
+ {
+ ilgen.Emit(OpCodes.Stfld, fi);
+ }
+ ilgen.Emit(OpCodes.Ldtoken, fi);
+ ilgen.Emit(OpCodes.Call, getFieldFromHandle);
+ ilgen.Emit(OpCodes.Call, monitorExit);
+ }
+ }
+
+ internal static FieldWrapper Create(TypeWrapper declaringType, FieldInfo fi, string sig, Modifiers modifiers)
+ {
+ FieldWrapper field = new FieldWrapper(declaringType, fi.Name, sig, modifiers);
+ if(field.IsVolatile)
+ {
+ // long & double field accesses must be made atomic
+ if(fi.FieldType == typeof(long) || fi.FieldType == typeof(double))
+ {
+ field.EmitGet = new VolatileLongDoubleGetter(fi);
+ field.EmitSet = new VolatileLongDoubleSetter(fi);
+ return field;
+ }
+ field.EmitGet += CodeEmitter.Create(OpCodes.Volatile);
+ field.EmitSet += CodeEmitter.Create(OpCodes.Volatile);
+ }
+ if(field.IsStatic)
+ {
+ field.EmitGet += CodeEmitter.Create(OpCodes.Ldsfld, fi);
+ field.EmitSet += CodeEmitter.Create(OpCodes.Stsfld, fi);
+ }
+ else
+ {
+ field.EmitGet += CodeEmitter.Create(OpCodes.Ldfld, fi);
+ field.EmitSet += CodeEmitter.Create(OpCodes.Stfld, fi);
+ }
+ return field;
+ }
+}
diff --git a/IK.VM.NET/WeakHashtable.cs b/IK.VM.NET/WeakHashtable.cs
new file mode 100644
index 00000000..0db13142
--- /dev/null
+++ b/IK.VM.NET/WeakHashtable.cs
@@ -0,0 +1,214 @@
+using System;
+using System.Collections;
+
+// TODO implement this properly, instead of this quick hack
+public class WeakHashtable : IDictionary
+{
+ private struct KeyValue
+ {
+ public WeakReference Key;
+ public object Value;
+ }
+ private KeyValue[] items = new KeyValue[101];
+
+ public WeakHashtable()
+ {
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return this.GetEnumerator();
+ }
+
+ public IDictionaryEnumerator GetEnumerator()
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Remove(object key)
+ {
+ throw new NotImplementedException();
+ }
+
+ public bool Contains(object key)
+ {
+ return ContainsKey(key);
+ }
+
+ public bool ContainsKey(object key)
+ {
+ lock(this)
+ {
+ int index = FindKey(key);
+ return index != -1 && items[index].Key != null && items[index].Key.Target != null;
+ }
+ }
+
+ public void Clear()
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Add(object key, object value)
+ {
+ lock(this)
+ {
+ int index = FindKey(key);
+ if(index != -1 && items[index].Key != null && items[index].Key.Target != null)
+ {
+ throw new ArgumentException();
+ }
+ int newSize = items.Length;
+ while(index == -1)
+ {
+ Rehash(newSize);
+ newSize = items.Length * 2 - 1;
+ index = FindKey(key);
+ }
+ items[index].Key = new WeakReference(key);
+ items[index].Value = value;
+ }
+ }
+
+ public bool IsReadOnly
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ // this returns the slot containing the key,
+ // the empty slot that should contain the key, or -1 if the
+ // table is too full to contain the key
+ private int FindKey(object key)
+ {
+ int start = key.GetHashCode() % items.Length;
+ int end = (start + 5) % items.Length;
+ for(int index = start; ; index = (index + 1) % items.Length)
+ {
+ if(items[index].Key == null)
+ {
+ return index;
+ }
+ if(key.Equals(items[index].Key.Target))
+ {
+ return index;
+ }
+ if(index == end)
+ {
+ return -1;
+ }
+ }
+ }
+
+ private void Rehash(int newSize)
+ {
+ KeyValue[] curr = items;
+ restart:
+ items = new KeyValue[newSize];
+ for(int i = 0; i < curr.Length; i++)
+ {
+ if(curr[i].Key != null)
+ {
+ object key = curr[i].Key.Target;
+ if(key != null)
+ {
+ int index = FindKey(key);
+ if(index == -1)
+ {
+ newSize = newSize * 2 - 1;
+ goto restart;
+ }
+ items[index].Key = new WeakReference(key);
+ items[index].Value = curr[i].Value;
+ }
+ }
+ }
+ }
+
+ public object this[object key]
+ {
+ get
+ {
+ lock(this)
+ {
+ int index = FindKey(key);
+ if(index >= 0)
+ {
+ return items[index].Value;
+ }
+ return null;
+ }
+ }
+ set
+ {
+ lock(this)
+ {
+ int index = FindKey(key);
+ int newSize = items.Length;
+ while(index == -1)
+ {
+ Rehash(newSize);
+ newSize = items.Length * 2 - 1;
+ index = FindKey(key);
+ }
+ items[index].Key = new WeakReference(key);
+ items[index].Value = value;
+ }
+ }
+ }
+
+ public ICollection Values
+ {
+ get
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ public ICollection Keys
+ {
+ get
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ public bool IsFixedSize
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public void CopyTo(Array array, int index)
+ {
+ throw new NotImplementedException();
+ }
+
+ public bool IsSynchronized
+ {
+ get
+ {
+ return true;
+ }
+ }
+
+ public int Count
+ {
+ get
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ public object SyncRoot
+ {
+ get
+ {
+ return this;
+ }
+ }
+}
diff --git a/IK.VM.NET/attributes.cs b/IK.VM.NET/attributes.cs
new file mode 100644
index 00000000..93d7b7dd
--- /dev/null
+++ b/IK.VM.NET/attributes.cs
@@ -0,0 +1,260 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+using System.Reflection;
+using System.Reflection.Emit;
+
+[AttributeUsage(AttributeTargets.Class)]
+public class OverrideStubTypeAttribute : Attribute
+{
+}
+
+[AttributeUsage(AttributeTargets.Assembly)]
+public class IKVMAssemblyAttribute : Attribute
+{
+}
+
+[AttributeUsage(AttributeTargets.All)]
+public class ModifiersAttribute : Attribute
+{
+ private Modifiers modifiers;
+
+ public ModifiersAttribute(Modifiers modifiers)
+ {
+ this.modifiers = modifiers;
+ }
+
+ public bool IsSynthetic
+ {
+ get
+ {
+ return modifiers == Modifiers.Synthetic;
+ }
+ }
+
+ public Modifiers Modifiers
+ {
+ get
+ {
+ return modifiers;
+ }
+ }
+
+ public static Modifiers GetModifiers(MethodBase mb)
+ {
+ object[] customAttribute = mb.GetCustomAttributes(typeof(ModifiersAttribute), false);
+ if(customAttribute.Length == 1)
+ {
+ return ((ModifiersAttribute)customAttribute[0]).Modifiers;
+ }
+ Modifiers modifiers = 0;
+ if(mb.IsPublic)
+ {
+ modifiers |= Modifiers.Public;
+ }
+ if(mb.IsPrivate)
+ {
+ modifiers |= Modifiers.Private;
+ }
+ if(mb.IsFamily || mb.IsFamilyOrAssembly)
+ {
+ modifiers |= Modifiers.Protected;
+ }
+ // NOTE Java doesn't support non-virtual methods, but we set the Final modifier for
+ // non-virtual methods to approximate the semantics
+ if(mb.IsFinal || (!mb.IsStatic && !mb.IsVirtual))
+ {
+ modifiers |= Modifiers.Final;
+ }
+ if(mb.IsAbstract)
+ {
+ modifiers |= Modifiers.Abstract;
+ }
+ if(mb.IsStatic)
+ {
+ modifiers |= Modifiers.Static;
+ }
+ if((mb.GetMethodImplementationFlags() & MethodImplAttributes.Synchronized) != 0)
+ {
+ modifiers |= Modifiers.Synchronized;
+ }
+ if((mb.Attributes & MethodAttributes.PinvokeImpl) != 0)
+ {
+ modifiers |= Modifiers.Native;
+ }
+ return modifiers;
+ }
+
+ public static Modifiers GetModifiers(FieldInfo fi)
+ {
+ object[] customAttribute = fi.GetCustomAttributes(typeof(ModifiersAttribute), false);
+ if(customAttribute.Length == 1)
+ {
+ return ((ModifiersAttribute)customAttribute[0]).Modifiers;
+ }
+ // NOTE privatescope fields are always treated as synthetic (even when they are in a .NET type, because
+ // Java wouldn't be able to cope with them anyway, because of potential name clashes)
+ if((fi.Attributes & FieldAttributes.FieldAccessMask) == FieldAttributes.PrivateScope)
+ {
+ return Modifiers.Synthetic;
+ }
+ Modifiers modifiers = 0;
+ if(fi.IsPublic)
+ {
+ modifiers |= Modifiers.Public;
+ }
+ if(fi.IsPrivate)
+ {
+ modifiers |= Modifiers.Private;
+ }
+ if(fi.IsFamily || fi.IsFamilyOrAssembly)
+ {
+ modifiers |= Modifiers.Protected;
+ }
+ if(fi.IsInitOnly || fi.IsLiteral)
+ {
+ modifiers |= Modifiers.Final;
+ }
+ if(fi.IsNotSerialized)
+ {
+ modifiers |= Modifiers.Transient;
+ }
+ if(fi.IsStatic)
+ {
+ modifiers |= Modifiers.Static;
+ }
+ // TODO reflection doesn't support volatile
+ return modifiers;
+ }
+
+ public static Modifiers GetModifiers(Type type)
+ {
+ object[] customAttribute = type.GetCustomAttributes(typeof(ModifiersAttribute), false);
+ if(customAttribute.Length == 1)
+ {
+ return ((ModifiersAttribute)customAttribute[0]).Modifiers;
+ }
+ // only returns public, protected, private, final, static, abstract and interface (as per
+ // the documentation of Class.getModifiers())
+ Modifiers modifiers = 0;
+ if(type.IsPublic)
+ {
+ modifiers |= Modifiers.Public;
+ }
+ if(type.IsNestedPrivate)
+ {
+ modifiers |= Modifiers.Private;
+ }
+ if(type.IsNestedFamily || type.IsNestedFamORAssem)
+ {
+ modifiers |= Modifiers.Protected;
+ }
+ if(type.IsSealed)
+ {
+ modifiers |= Modifiers.Final;
+ }
+ if(type.DeclaringType != null)
+ {
+ modifiers |= Modifiers.Static;
+ }
+ if(type.IsAbstract)
+ {
+ modifiers |= Modifiers.Abstract;
+ }
+ if(type.IsInterface)
+ {
+ modifiers |= Modifiers.Interface;
+ }
+ return modifiers;
+ }
+
+ public static void SetModifiers(MethodBuilder mb, Modifiers modifiers)
+ {
+ CustomAttributeBuilder customAttributeBuilder = new CustomAttributeBuilder(typeof(ModifiersAttribute).GetConstructor(new Type[] { typeof(Modifiers) }), new object[] { modifiers });
+ mb.SetCustomAttribute(customAttributeBuilder);
+ }
+
+ public static void SetModifiers(FieldBuilder fb, Modifiers modifiers)
+ {
+ CustomAttributeBuilder customAttributeBuilder = new CustomAttributeBuilder(typeof(ModifiersAttribute).GetConstructor(new Type[] { typeof(Modifiers) }), new object[] { modifiers });
+ fb.SetCustomAttribute(customAttributeBuilder);
+ }
+}
+
+[AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Property | AttributeTargets.Class)]
+public class StackTraceInfoAttribute : Attribute
+{
+ private bool hidden;
+ private string className;
+ private bool truncate;
+ private int eatFrames;
+
+ public bool Hidden
+ {
+ get
+ {
+ return hidden;
+ }
+ set
+ {
+ hidden = value;
+ }
+ }
+
+ public int EatFrames
+ {
+ get
+ {
+ return eatFrames;
+ }
+ set
+ {
+ eatFrames = value;
+ }
+ }
+
+ public string Class
+ {
+ get
+ {
+ return className;
+ }
+ set
+ {
+ className = value;
+ }
+ }
+
+ public bool Truncate
+ {
+ get
+ {
+ return truncate;
+ }
+ set
+ {
+ truncate = value;
+ }
+ }
+}
diff --git a/IK.VM.NET/classpath.cs b/IK.VM.NET/classpath.cs
new file mode 100644
index 00000000..86667cb3
--- /dev/null
+++ b/IK.VM.NET/classpath.cs
@@ -0,0 +1,1636 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+using System.Collections;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using System.Text;
+using NetSystem = System;
+
+namespace java.lang
+{
+ public interface Cloneable
+ {
+ }
+
+ // TODO should be serializable
+ public sealed class StackTraceElement
+ {
+ private static readonly long serialVersionUID = 6992337162326171013L;
+ private string fileName;
+ private int lineNumber;
+ private string className;
+ private string methodName;
+ [NonSerialized]
+ private bool isNative;
+
+ internal long bogus_method_to_prevent_warning()
+ {
+ return serialVersionUID;
+ }
+
+ internal StackTraceElement(string fileName, int lineNumber, string className, string methodName, bool isNative)
+ {
+ this.fileName = fileName;
+ this.lineNumber = lineNumber;
+ this.className = className;
+ this.methodName = methodName;
+ this.isNative = isNative;
+ }
+
+ public string getFileName()
+ {
+ return fileName;
+ }
+
+ public int getLineNumber()
+ {
+ return lineNumber;
+ }
+
+ public string getClassName()
+ {
+ return className;
+ }
+
+ public string getMethodName()
+ {
+ return methodName;
+ }
+
+ public bool isNativeMethod()
+ {
+ return isNative;
+ }
+
+ public override string ToString()
+ {
+ StringBuilder sb = new StringBuilder();
+ if(className != null)
+ {
+ sb.Append(className);
+ if(methodName != null)
+ {
+ sb.Append('.');
+ }
+ }
+ if(methodName != null)
+ {
+ sb.Append(methodName);
+ }
+ sb.Append('(');
+ if(fileName != null)
+ {
+ sb.Append(fileName);
+ }
+ else
+ {
+ sb.Append(isNative ? "Native Method" : "Unknown Source");
+ }
+ if(lineNumber >= 0)
+ {
+ sb.Append(':').Append(lineNumber);
+ }
+ sb.Append(')');
+ return sb.ToString();
+ }
+
+ public override bool Equals(object o)
+ {
+ if(o != null && o.GetType() == GetType())
+ {
+ StackTraceElement ste = (StackTraceElement)o;
+ return ste.className == className &&
+ ste.fileName == fileName &&
+ ste.lineNumber == lineNumber &&
+ ste.methodName == methodName;
+ }
+ return false;
+ }
+
+ public override int GetHashCode()
+ {
+ return GetHashCode(className) ^ GetHashCode(fileName) ^ GetHashCode(methodName) ^ lineNumber;
+ }
+
+ private static int GetHashCode(string o)
+ {
+ if(o == null)
+ {
+ return 0;
+ }
+ return o.GetHashCode();
+ }
+ }
+}
+
+namespace java.io
+{
+ public interface Serializable
+ {
+ }
+}
+
+namespace NativeCode.java
+{
+ namespace lang
+ {
+ namespace reflect
+ {
+ public class Array
+ {
+ public static object createObjectArray(object clazz, int dim)
+ {
+ if(dim >= 0)
+ {
+ return NetSystem.Array.CreateInstance(Class.getType(clazz), dim);
+ }
+ throw JavaException.NegativeArraySizeException();
+ }
+ }
+
+ public class Method
+ {
+ public static String GetName(object methodCookie)
+ {
+ MethodWrapper wrapper = (MethodWrapper)methodCookie;
+ return wrapper.Name;
+ }
+
+ public static int GetModifiers(object methodCookie)
+ {
+ MethodWrapper wrapper = (MethodWrapper)methodCookie;
+ return (int)wrapper.Modifiers;
+ }
+
+ public static object GetReturnType(object methodCookie)
+ {
+ MethodWrapper wrapper = (MethodWrapper)methodCookie;
+ return Class.getClassFromWrapper(wrapper.ReturnType);
+ }
+
+ public static object[] GetParameterTypes(object methodCookie)
+ {
+ MethodWrapper wrapper = (MethodWrapper)methodCookie;
+ TypeWrapper[] parameters = wrapper.GetParameters();
+ object[] parameterClasses = new object[parameters.Length];
+ for(int i = 0; i < parameters.Length; i++)
+ {
+ parameterClasses[i] = Class.getClassFromWrapper(parameters[i]);
+ }
+ return parameterClasses;
+ }
+
+ public static object[] GetExceptionTypes(object methodCookie)
+ {
+ MethodWrapper wrapper = (MethodWrapper)methodCookie;
+ // TODO
+ return new object[0];
+ }
+
+ public static object Invoke(object methodCookie, object o, object[] args)
+ {
+ // TODO this is a very lame implementation, no where near correct
+ MethodWrapper wrapper = (MethodWrapper)methodCookie;
+ wrapper.DeclaringType.Finish();
+ TypeWrapper[] argWrappers = wrapper.GetParameters();
+ Type[] argTypes = new Type[argWrappers.Length];
+ for(int i = 0; i < argTypes.Length; i++)
+ {
+ argWrappers[i].Finish();
+ argTypes[i] = argWrappers[i].Type;
+ if(argTypes[i].IsPrimitive)
+ {
+ if(argTypes[i] == typeof(int))
+ {
+ args[i] = ClassLoaderWrapper.GetType("java.lang.Integer").GetMethod("intValue").Invoke(args[i], new object[0]);
+ }
+ else if(argTypes[i] == typeof(bool))
+ {
+ args[i] = ClassLoaderWrapper.GetType("java.lang.Boolean").GetMethod("booleanValue").Invoke(args[i], new object[0]);
+ }
+ else if(argTypes[i] == typeof(short))
+ {
+ args[i] = ClassLoaderWrapper.GetType("java.lang.Short").GetMethod("shortValue").Invoke(args[i], new object[0]);
+ }
+ else
+ {
+ throw new NotImplementedException("argtype: " + argTypes[i].FullName);
+ }
+ }
+ }
+ try
+ {
+ if(wrapper.Name == "<init>")
+ {
+ if(o == null)
+ {
+ return wrapper.DeclaringType.Type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, argTypes, null).Invoke(args);
+ }
+ else
+ {
+ throw new NotImplementedException("invoking constructor on existing instance");
+ }
+ }
+ else
+ {
+ MethodInfo mi;
+ if(wrapper.GetMethod() is NetSystem.Reflection.Emit.MethodBuilder || wrapper.GetMethod() == null)
+ {
+ mi = wrapper.DeclaringType.Type.GetMethod(wrapper.Name, BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, argTypes, null);
+ }
+ else
+ {
+ mi = (MethodInfo)wrapper.GetMethod();
+ }
+ if(mi == null)
+ {
+ throw new InvalidOperationException("Method not found: " + wrapper.DeclaringType.Name + "." + wrapper.Name + wrapper.Descriptor.Signature);
+ }
+ object retval = mi.Invoke(o, args);
+ if(wrapper.ReturnType.Type.IsValueType)
+ {
+ if(wrapper.ReturnType.Type == typeof(int))
+ {
+ retval = Activator.CreateInstance(ClassLoaderWrapper.GetType("java.lang.Integer"), new object[] { (int)retval });
+ }
+ else if(wrapper.ReturnType.Type == typeof(bool))
+ {
+ retval = Activator.CreateInstance(ClassLoaderWrapper.GetType("java.lang.Boolean"), new object[] { (bool)retval });
+ }
+ else if(wrapper.ReturnType.Type == typeof(void))
+ {
+ // nothing to do
+ }
+ else
+ {
+ throw new NotImplementedException("rettype: " + wrapper.ReturnType.Type.FullName);
+ }
+ }
+ return retval;
+ }
+ }
+ catch(TargetInvocationException x)
+ {
+ throw JavaException.InvocationTargetException(ExceptionHelper.MapException(x.InnerException, typeof(Exception)));
+ }
+ }
+
+ // TODO remove this, it isn't used anymore
+ public static Exception mapException(Exception x)
+ {
+ return ExceptionHelper.MapException(x, typeof(Exception));
+ }
+ }
+
+ public class Field
+ {
+ public static string GetName(object fieldCookie)
+ {
+ FieldWrapper wrapper = (FieldWrapper)fieldCookie;
+ return wrapper.Name;
+ }
+
+ public static int GetModifiers(object fieldCookie)
+ {
+ FieldWrapper wrapper = (FieldWrapper)fieldCookie;
+ return (int)wrapper.Modifiers;
+ }
+
+ public static object GetFieldType(object fieldCookie)
+ {
+ FieldWrapper wrapper = (FieldWrapper)fieldCookie;
+ return Class.getClassFromType(wrapper.FieldType);
+ }
+
+ public static object GetValue(object fieldCookie, object o)
+ {
+ FieldWrapper wrapper = (FieldWrapper)fieldCookie;
+ wrapper.DeclaringType.Finish();
+ FieldInfo fi = wrapper.DeclaringType.Type.GetField(wrapper.Name, BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
+ if(fi.FieldType.IsValueType)
+ {
+ if(fi.FieldType == typeof(long))
+ {
+ return Activator.CreateInstance(ClassLoaderWrapper.GetType("java.lang.Long"), new object[] { fi.GetValue(o) });
+ }
+ else
+ {
+ throw new NotImplementedException("GetValue: " + fi.FieldType.FullName);
+ }
+ }
+ return fi.GetValue(o);
+ }
+
+ public static void SetValue(object fieldCookie, object o, object v)
+ {
+ // TODO this is a very lame implementation, no where near correct
+ FieldWrapper wrapper = (FieldWrapper)fieldCookie;
+ wrapper.DeclaringType.Finish();
+ FieldInfo fi = wrapper.DeclaringType.Type.GetField(wrapper.Name, BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
+ if(fi.FieldType.IsValueType)
+ {
+ throw new NotImplementedException("SetValue: " + fi.FieldType.FullName);
+ }
+ fi.SetValue(o, v);
+ }
+ }
+ }
+
+ public class Runtime
+ {
+ public static void insertSystemProperties(object properties)
+ {
+ MethodInfo m = properties.GetType().GetMethod("setProperty");
+ // TODO set all these properties to something useful
+ m.Invoke(properties, new string[] { "java.version", "1.1" });
+ m.Invoke(properties, new string[] { "java.vendor", "Jeroen Frijters" });
+ m.Invoke(properties, new string[] { "java.vendor.url", "http://jeroen.nu/" });
+ m.Invoke(properties, new string[] { "java.home", "" });
+ m.Invoke(properties, new string[] { "java.vm.specification.version", "" });
+ m.Invoke(properties, new string[] { "java.vm.specification.vendor", "" });
+ m.Invoke(properties, new string[] { "java.vm.specification.name", "" });
+ m.Invoke(properties, new string[] { "java.vm.version", "" });
+ m.Invoke(properties, new string[] { "java.vm.vendor", "" });
+ m.Invoke(properties, new string[] { "java.vm.name", "" });
+ m.Invoke(properties, new string[] { "java.specification.version", "" });
+ m.Invoke(properties, new string[] { "java.specification.vendor", "" });
+ m.Invoke(properties, new string[] { "java.specification.name", "" });
+ m.Invoke(properties, new string[] { "java.class.version", "" });
+ string classpath = Environment.GetEnvironmentVariable("CLASSPATH");
+ if(classpath == null)
+ {
+ classpath = ".";
+ }
+ m.Invoke(properties, new string[] { "java.class.path", classpath });
+ m.Invoke(properties, new string[] { "java.library.path", "." });
+ m.Invoke(properties, new string[] { "java.io.tmpdir", Path.GetTempPath() });
+ m.Invoke(properties, new string[] { "java.compiler", "" });
+ m.Invoke(properties, new string[] { "java.ext.dirs", "" });
+ m.Invoke(properties, new string[] { "os.name", "Windows" });
+ m.Invoke(properties, new string[] { "os.arch", "" });
+ m.Invoke(properties, new string[] { "os.version", Environment.OSVersion.ToString() });
+ m.Invoke(properties, new string[] { "file.separator", Path.DirectorySeparatorChar.ToString() });
+ m.Invoke(properties, new string[] { "path.separator", Path.PathSeparator.ToString() });
+ m.Invoke(properties, new string[] { "line.separator", Environment.NewLine });
+ m.Invoke(properties, new string[] { "user.name", Environment.UserName });
+ m.Invoke(properties, new string[] { "user.home", "" });
+ m.Invoke(properties, new string[] { "user.dir", Environment.CurrentDirectory });
+ m.Invoke(properties, new string[] { "awt.toolkit", "ikvm.awt.NetToolkit, awt, Version=1.0, Culture=neutral, PublicKeyToken=null" });
+ }
+
+ public static string nativeGetLibname(string pathname, string libname)
+ {
+ // TODO
+ return libname;
+ }
+
+ public static int nativeLoad(object obj, string filename)
+ {
+ return JNI.LoadNativeLibrary(filename);
+ }
+
+ public static void gc(object obj)
+ {
+ NetSystem.GC.Collect();
+ }
+
+ public static void runFinalization(object obj)
+ {
+ NetSystem.GC.WaitForPendingFinalizers();
+ }
+
+ public static void runFinalizersOnExitInternal(bool b)
+ {
+ // the CLR always runs the finalizers, so we can ignore this
+ }
+
+ public static void exitInternal(object obj, int rc)
+ {
+ NetSystem.Environment.Exit(rc);
+ }
+
+ public static int availableProcessors(object obj)
+ {
+ string s = NetSystem.Environment.GetEnvironmentVariable("NUMBER_OF_PROCESSORS");
+ if(s != null)
+ {
+ return int.Parse(s);
+ }
+ return 1;
+ }
+
+ public static object execInternal(object obj, string[] cmd, string[] env, object dir)
+ {
+ // TODO
+ throw new NotImplementedException();
+ }
+
+ public static long freeMemory(object obj)
+ {
+ // TODO figure out if there is anything meaningful we can return here
+ return 10 * 1024 * 1024;
+ }
+
+ public static long maxMemory(object obj)
+ {
+ return long.MaxValue;
+ }
+
+ public static long totalMemory(object obj)
+ {
+ // NOTE this really is a bogus number, but we have to return something
+ return NetSystem.GC.GetTotalMemory(false);
+ }
+
+ public static void traceInstructions(object obj, bool b)
+ {
+ // not supported
+ }
+
+ public static void traceMethodCalls(object obj, bool b)
+ {
+ // not supported
+ }
+ }
+
+ public class System
+ {
+ private static long timebase;
+
+ static System()
+ {
+ timebase = ((TimeZone.CurrentTimeZone.ToUniversalTime(DateTime.Now) - new DateTime(1970, 1, 1)).Ticks / 10000L) - Environment.TickCount;
+ }
+
+ public static bool isWordsBigEndian()
+ {
+ return !BitConverter.IsLittleEndian;
+ }
+
+ public static long currentTimeMillis()
+ {
+ // NOTE this wraps after 24.9 days, but it is much faster than calling DateTime.Now every time
+ return timebase + Environment.TickCount;
+ }
+
+ public static void setErr0(object printStream)
+ {
+ ClassLoaderWrapper.GetType("java.lang.System").GetField("err", BindingFlags.Static | BindingFlags.NonPublic).SetValue(null, printStream);
+ }
+
+ public static void setIn0(object inputStream)
+ {
+ ClassLoaderWrapper.GetType("java.lang.System").GetField("in", BindingFlags.Static | BindingFlags.NonPublic).SetValue(null, inputStream);
+ }
+
+ public static void setOut0(object printStream)
+ {
+ ClassLoaderWrapper.GetType("java.lang.System").GetField("out", BindingFlags.Static | BindingFlags.NonPublic).SetValue(null, printStream);
+ }
+ }
+
+ public class Math
+ {
+ public static double pow(double x, double y)
+ {
+ return NetSystem.Math.Pow(x, y);
+ }
+
+ public static double exp(double d)
+ {
+ return NetSystem.Math.Exp(d);
+ }
+
+ public static double rint(double d)
+ {
+ return NetSystem.Math.Round(d);
+ }
+
+ public static double IEEEremainder(double f1, double f2)
+ {
+ return NetSystem.Math.IEEERemainder(f1, f2);
+ }
+
+ public static double sqrt(double d)
+ {
+ return NetSystem.Math.Sqrt(d);
+ }
+
+ public static double floor(double d)
+ {
+ return NetSystem.Math.Floor(d);
+ }
+
+ public static double ceil(double d)
+ {
+ return NetSystem.Math.Ceiling(d);
+ }
+
+ public static double log(double d)
+ {
+ return NetSystem.Math.Log(d);
+ }
+
+ public static double sin(double d)
+ {
+ return NetSystem.Math.Sin(d);
+ }
+
+ public static double asin(double d)
+ {
+ return NetSystem.Math.Asin(d);
+ }
+
+ public static double cos(double d)
+ {
+ return NetSystem.Math.Cos(d);
+ }
+
+ public static double acos(double d)
+ {
+ return NetSystem.Math.Acos(d);
+ }
+
+ public static double tan(double d)
+ {
+ return NetSystem.Math.Tan(d);
+ }
+
+ public static double atan(double d)
+ {
+ return NetSystem.Math.Atan(d);
+ }
+
+ public static double atan2(double y, double x)
+ {
+ return NetSystem.Math.Atan2(y, x);
+ }
+ }
+
+ public class Double
+ {
+ public static void initIDs()
+ {
+ }
+
+ public static double parseDouble(string s)
+ {
+ // TODO I doubt that this is correct
+ return double.Parse(s);
+ }
+
+ public static long doubleToLongBits(double v)
+ {
+ if(double.IsNaN(v))
+ {
+ return 0x7ff8000000000000L;
+ }
+ return BitConverter.DoubleToInt64Bits(v);
+ }
+
+ public static long doubleToRawLongBits(double v)
+ {
+ return BitConverter.DoubleToInt64Bits(v);
+ }
+
+ public static double longBitsToDouble(long bits)
+ {
+ return BitConverter.Int64BitsToDouble(bits);
+ }
+
+ public static string toString(double d, bool isFloat)
+ {
+ return isFloat ? StringHelper.valueOf((float)d) : StringHelper.valueOf(d);
+ }
+ }
+
+ public class Float
+ {
+ public static float intBitsToFloat(int v)
+ {
+ return BitConverter.ToSingle(BitConverter.GetBytes(v), 0);
+ }
+
+ public static int floatToIntBits(float v)
+ {
+ if(float.IsNaN(v))
+ {
+ return 0x7fc00000;
+ }
+ return BitConverter.ToInt32(BitConverter.GetBytes(v), 0);
+ }
+
+ public static int floatToRawIntBits(float v)
+ {
+ return BitConverter.ToInt32(BitConverter.GetBytes(v), 0);
+ }
+ }
+
+ public class VMSecurityManager
+ {
+ public static object getClassContext()
+ {
+ ArrayList ar = new ArrayList();
+ NetSystem.Diagnostics.StackTrace st = new NetSystem.Diagnostics.StackTrace();
+ for(int i = 0; i < st.FrameCount; i++)
+ {
+ NetSystem.Diagnostics.StackFrame frame = st.GetFrame(i);
+ // HACK very insecure
+ // TODO handle reflection scenario
+ if(frame.GetMethod().Name != "getClassContext")
+ {
+ ar.Add(Class.getClassFromType(frame.GetMethod().DeclaringType));
+ }
+ }
+ return ar.ToArray(ClassLoaderWrapper.GetType("java.lang.Class"));
+ }
+
+ public static object currentClassLoader()
+ {
+ // TODO handle PrivilegedAction
+ NetSystem.Diagnostics.StackTrace st = new NetSystem.Diagnostics.StackTrace();
+ for(int i = 0; i < st.FrameCount; i++)
+ {
+ NetSystem.Diagnostics.StackFrame frame = st.GetFrame(i);
+ TypeWrapper wrapper = ClassLoaderWrapper.GetWrapperFromTypeFast(frame.GetMethod().DeclaringType);
+ if(wrapper != null && wrapper.GetClassLoader().GetJavaClassLoader() != null)
+ {
+ return wrapper.GetClassLoader().GetJavaClassLoader();
+ }
+ }
+ return null;
+ }
+ }
+
+ public class VMSystem
+ {
+ public static void arraycopy(object src, int srcStart, object dest, int destStart, int len)
+ {
+ // TODO
+ Array.Copy((Array)src, srcStart, (Array)dest, destStart, len);
+ }
+
+ private static MethodInfo hashCodeMethod;
+ private static object[] noargs = new object[0];
+
+ public static int identityHashCode(object arg)
+ {
+ if(arg == null)
+ {
+ return 0;
+ }
+ // TODO this should be optimized, using reflection is probably too slow
+ if(hashCodeMethod == null)
+ {
+ hashCodeMethod = typeof(object).GetMethod("GetHashCode");
+ }
+ return (int)hashCodeMethod.Invoke(arg, noargs);
+ }
+ }
+
+ public class VMClassLoader
+ {
+ public static Assembly findResourceAssembly(string name)
+ {
+ Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
+ for(int i = 0; i < assemblies.Length; i++)
+ {
+ if(!(assemblies[i] is NetSystem.Reflection.Emit.AssemblyBuilder))
+ {
+ if(assemblies[i].GetLoadedModules()[0].GetField(name) != null)
+ {
+ return assemblies[i];
+ }
+ }
+ }
+ return null;
+ }
+
+ public static Type getPrimitiveType(char type)
+ {
+ switch(type)
+ {
+ case 'Z':
+ return typeof(bool);
+ case 'B':
+ return typeof(sbyte);
+ case 'C':
+ return typeof(char);
+ case 'D':
+ return typeof(double);
+ case 'F':
+ return typeof(float);
+ case 'I':
+ return typeof(int);
+ case 'J':
+ return typeof(long);
+ case 'S':
+ return typeof(short);
+ case 'V':
+ return typeof(void);
+ default:
+ throw new InvalidOperationException();
+ }
+ }
+
+ public static object defineClass(object classLoader, string name, byte[] data, int offset, int length, object protectionDomain)
+ {
+ // TODO handle errors
+ ClassFile classFile = new ClassFile(data, offset, length, name);
+ if(name != null && classFile.Name.Replace('/', '.') != name)
+ {
+ throw JavaException.NoClassDefFoundError("{0} (wrong name: {1})", name, classFile.Name);
+ }
+// if(classFile.Name == "org/eclipse/core/internal/boot/InternalBootLoader")
+// {
+// using(FileStream fs = File.Create("internalbootloader.class"))
+// {
+// fs.Write(data, offset, length);
+// }
+// }
+ TypeWrapper type = ClassLoaderWrapper.GetClassLoaderWrapper(classLoader).DefineClass(classFile);
+ object clazz = Class.CreateInstance(null, type);
+ if(protectionDomain != null)
+ {
+ // TODO cache the FieldInfo
+ clazz.GetType().GetField("pd", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(clazz, protectionDomain);
+ }
+ return clazz;
+ }
+ }
+
+ public class Thread
+ {
+ public static void sleep(long millis, int nanos)
+ {
+ NetSystem.Threading.Thread.Sleep(new TimeSpan(millis * 10000 + (nanos + 99) / 100));
+ }
+
+ public static void joinInternal(NetSystem.Threading.Thread nativeThread, long millis, int nanos)
+ {
+ nativeThread.Join(new TimeSpan(millis * 10000 + (nanos + 99) / 100));
+ }
+ }
+
+ public class Class
+ {
+ private static Hashtable map = new Hashtable();
+ private static ConstructorInfo classConstructor;
+ private static MethodInfo getTypeMethod;
+
+ public static object loadBootstrapClass(string name, bool initialize)
+ {
+ TypeWrapper type = ClassLoaderWrapper.GetBootstrapClassLoader().LoadClassByDottedName(name);
+ type.Finish();
+ if(initialize)
+ {
+ RuntimeHelpers.RunClassConstructor(type.Type.TypeHandle);
+ }
+ return getClassFromType(type.Type);
+ }
+
+ internal static object CreateInstance(Type type, TypeWrapper wrapper)
+ {
+ if(classConstructor == null)
+ {
+ classConstructor = ClassLoaderWrapper.GetType("java.lang.Class").GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, CallingConventions.Standard, new Type[] { typeof(Type), typeof(object) }, null);
+ }
+ object clazz = classConstructor.Invoke(new object[] { type, wrapper });
+ lock(map.SyncRoot)
+ {
+ if(type != null)
+ {
+ map.Add(type, clazz);
+ }
+ if(wrapper != null)
+ {
+ map.Add(wrapper, clazz);
+ }
+ }
+ return clazz;
+ }
+
+ public static Type getTypeFromWrapper(object clazz, object wrapper)
+ {
+ ((TypeWrapper)wrapper).Finish();
+ Type type = ((TypeWrapper)wrapper).Type;
+ lock(map.SyncRoot)
+ {
+ // NOTE since this method can be called multiple times (or after getClassFromType has added
+ // the Class to the map), we don't use Add() here, but the indexer because that can handle
+ // "overwriting" the existing association (which should always be the same as the new one)
+ map[type] = clazz;
+ }
+ return type;
+ }
+
+ public static Type getType(object clazz)
+ {
+ if(getTypeMethod == null)
+ {
+ getTypeMethod = ClassLoaderWrapper.GetType("java.lang.Class").GetMethod("getType", BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null);
+ }
+ return (Type)getTypeMethod.Invoke(clazz, new object[0]);
+ }
+
+ internal static object getClassFromWrapper(TypeWrapper wrapper)
+ {
+ lock(map.SyncRoot)
+ {
+ object clazz = map[wrapper];
+ if(clazz == null)
+ {
+ // Maybe the Class object was already constructed from the type
+ clazz = map[wrapper.Type];
+ if(clazz == null)
+ {
+ clazz = CreateInstance(null, wrapper);
+ }
+ }
+ return clazz;
+ }
+ }
+
+ public static object getClassFromType(Type type)
+ {
+ if(type == null)
+ {
+ return null;
+ }
+ if(type is NetSystem.Reflection.Emit.TypeBuilder)
+ {
+ throw new InvalidOperationException();
+ }
+ lock(map.SyncRoot)
+ {
+ object clazz = map[type];
+ if(clazz == null)
+ {
+ // maybe the Class object was constructed from the wrapper
+ TypeWrapper wrapper = ClassLoaderWrapper.GetWrapperFromTypeFast(type);
+ if(wrapper != null)
+ {
+ clazz = map[wrapper];
+ if(clazz != null)
+ {
+ map.Add(type, clazz);
+ return clazz;
+ }
+ }
+ // NOTE we need to get the bootstrap classloader to trigger its construction (if it
+ // hasn't been created yet), because otherwise CreateInstance will do that and this
+ // causes the same class object to be created multiple times)
+ ClassLoaderWrapper.GetBootstrapClassLoader();
+ clazz = map[type];
+ if(clazz == null)
+ {
+ // if this type is an override stub (e.g. java.lang.Object), we need to return the
+ // class object for the parent type
+ if(type.IsDefined(typeof(OverrideStubTypeAttribute), false))
+ {
+ clazz = getClassFromType(type.BaseType);
+ map.Add(type, clazz);
+ }
+ else
+ {
+ // TODO should we specify the wrapper?
+ // NOTE CreateInstance adds the Class to the "map"
+ clazz = CreateInstance(type, null);
+ }
+ }
+ }
+ return clazz;
+ }
+ }
+
+ public static string getName(Type type)
+ {
+ return GetName(type, null);
+ }
+
+ public static string GetName(Type type, object wrapperType)
+ {
+ if(type == null)
+ {
+ string name = ((TypeWrapper)wrapperType).Name;
+ // HACK name is null for primitives
+ if(name != null)
+ {
+ return name.Replace('/', '.');
+ }
+ type = ((TypeWrapper)wrapperType).Type;
+ }
+ if(type.IsValueType)
+ {
+ if(type == typeof(void))
+ {
+ return "void";
+ }
+ else if(type == typeof(bool))
+ {
+ return "boolean";
+ }
+ else if(type == typeof(sbyte))
+ {
+ return "byte";
+ }
+ else if(type == typeof(char))
+ {
+ return "char";
+ }
+ else if(type == typeof(short))
+ {
+ return "short";
+ }
+ else if(type == typeof(int))
+ {
+ return "int";
+ }
+ else if(type == typeof(long))
+ {
+ return "long";
+ }
+ else if(type == typeof(float))
+ {
+ return "float";
+ }
+ else if(type == typeof(double))
+ {
+ return "double";
+ }
+ else
+ {
+ return type.FullName;
+ }
+ }
+ else if(type.IsArray)
+ {
+ StringBuilder sb = new StringBuilder();
+ while(type.IsArray)
+ {
+ sb.Append('[');
+ type = type.GetElementType();
+ }
+ if(type.IsValueType)
+ {
+ if(type == typeof(void))
+ {
+ sb.Append('V');
+ }
+ else if(type == typeof(bool))
+ {
+ sb.Append('Z');
+ }
+ else if(type == typeof(sbyte))
+ {
+ sb.Append('B');
+ }
+ else if(type == typeof(char))
+ {
+ sb.Append('C');
+ }
+ else if(type == typeof(short))
+ {
+ sb.Append('S');
+ }
+ else if(type == typeof(int))
+ {
+ sb.Append('I');
+ }
+ else if(type == typeof(long))
+ {
+ sb.Append('J');
+ }
+ else if(type == typeof(float))
+ {
+ sb.Append('F');
+ }
+ else if(type == typeof(double))
+ {
+ sb.Append('D');
+ }
+ else
+ {
+ sb.Append(type.FullName);
+ }
+ }
+ else
+ {
+ sb.Append('L').Append(GetName(type, null)).Append(';');
+ }
+ return sb.ToString();
+ }
+ else
+ {
+ while(type.IsDefined(typeof(OverrideStubTypeAttribute), false))
+ {
+ type = type.BaseType;
+ }
+ // TODO look for our custom attribute (which doesn't exist yet), that contains the real name of the type
+ TypeWrapper wrapper = ClassLoaderWrapper.GetWrapperFromTypeFast(type);
+ if(wrapper != null)
+ {
+ return wrapper.Name.Replace('/', '.');
+ }
+ return type.FullName;
+ }
+ }
+
+ [StackTraceInfo(Hidden = true)]
+ public static void initializeType(Type type)
+ {
+ RuntimeHelpers.RunClassConstructor(type.TypeHandle);
+ }
+
+ public static object getClassLoader0(Type type)
+ {
+ return ClassLoaderWrapper.GetClassLoader(type).GetJavaClassLoader();
+ }
+
+ public static object[] GetDeclaredMethods(Type type, object cwrapper)
+ {
+ TypeWrapper wrapper = (TypeWrapper)cwrapper;
+ if(wrapper == null)
+ {
+ wrapper = ClassLoaderWrapper.GetWrapperFromType(type);
+ }
+ // we need to finish the type otherwise all methods will not be in the method map yet
+ wrapper.Finish();
+ return wrapper.GetMethods();
+ }
+
+ public static object[] GetDeclaredFields(Type type, object cwrapper)
+ {
+ TypeWrapper wrapper = (TypeWrapper)cwrapper;
+ if(wrapper == null)
+ {
+ wrapper = ClassLoaderWrapper.GetWrapperFromType(type);
+ }
+ // we need to finish the type otherwise all fields will not be in the field map yet
+ wrapper.Finish();
+ return wrapper.GetFields();
+ }
+
+ public static object[] GetDeclaredClasses(Type type, object cwrapper)
+ {
+ // TODO
+ return new object[0];
+ }
+
+ public static object[] GetInterfaces(Type type, object cwrapper)
+ {
+ TypeWrapper wrapper = (TypeWrapper)cwrapper;
+ if(wrapper == null)
+ {
+ wrapper = ClassLoaderWrapper.GetWrapperFromType(type);
+ }
+ // we need to finish the type otherwise all fields will not be in the field map yet
+ wrapper.Finish();
+ TypeWrapper[] interfaceWrappers = wrapper.Interfaces;
+ object[] interfaces = new object[interfaceWrappers.Length];
+ for(int i = 0; i < interfaces.Length; i++)
+ {
+ interfaces[i] = getClassFromWrapper(interfaceWrappers[i]);
+ }
+ return interfaces;
+ }
+
+ public static int GetModifiers(Type type, Object cwrapper)
+ {
+ TypeWrapper wrapper = (TypeWrapper)cwrapper;
+ if(wrapper == null)
+ {
+ wrapper = ClassLoaderWrapper.GetWrapperFromType(type);
+ }
+ // only returns public, protected, private, final, static, abstract and interface (as per
+ // the documentation of Class.getModifiers())
+ Modifiers mask = Modifiers.Public | Modifiers.Protected | Modifiers.Private | Modifiers.Final |
+ Modifiers.Static | Modifiers.Abstract | Modifiers.Interface;
+ return (int)(wrapper.Modifiers & mask);
+ }
+ }
+ }
+
+ namespace io
+ {
+ public class File
+ {
+ internal static string DemanglePath(string path)
+ {
+ // HACK for some reason Java accepts: \c:\foo.txt
+ // I don't know what else, but for now lets just support this
+ if(path.Length > 3 && path[0] == '\\' && path[2] == ':')
+ {
+ path = path.Substring(1);
+ }
+ return path;
+ }
+
+ public static bool existsInternal(object obj, string path)
+ {
+ path = DemanglePath(path);
+ try
+ {
+ return NetSystem.IO.File.Exists(path) || NetSystem.IO.Directory.Exists(path);
+ }
+ catch(Exception)
+ {
+ return false;
+ }
+ }
+
+ public static bool isFileInternal(object obj, string path)
+ {
+ // TODO handle errors
+ // TODO make sure semantics are the same
+ try
+ {
+ return NetSystem.IO.File.Exists(DemanglePath(path));
+ }
+ catch(Exception)
+ {
+ return false;
+ }
+ }
+
+ public static bool isDirectoryInternal(object obj, string path)
+ {
+ // TODO handle errors
+ // TODO make sure semantics are the same
+ try
+ {
+ return NetSystem.IO.Directory.Exists(DemanglePath(path));
+ }
+ catch(Exception)
+ {
+ return false;
+ }
+ }
+
+ public static long lengthInternal(object obj, string path)
+ {
+ // TODO handle errors
+ try
+ {
+ return new NetSystem.IO.FileInfo(DemanglePath(path)).Length;
+ }
+ catch(Exception)
+ {
+ return 0;
+ }
+ }
+
+ public static bool mkdirInternal(object obj, string path)
+ {
+ // TODO handle errors
+ // TODO shouldn't we demangle the path?
+ if (!NetSystem.IO.Directory.Exists(NetSystem.IO.Directory.GetParent(path).FullName) ||
+ NetSystem.IO.Directory.Exists(path))
+ {
+ return false;
+ }
+ return NetSystem.IO.Directory.CreateDirectory(path) != null;
+ }
+
+ public static bool deleteInternal(object obj, string path)
+ {
+ // TODO handle errors
+ // TODO shouldn't we demangle the path?
+ if (NetSystem.IO.Directory.Exists(path))
+ {
+ NetSystem.IO.Directory.Delete(path);
+ }
+ else if (NetSystem.IO.File.Exists(path))
+ {
+ NetSystem.IO.File.Delete(path);
+ }
+ else
+ {
+ return false;
+ }
+ return true;
+ }
+
+ public static bool createInternal(string path)
+ {
+ // TODO handle errors
+ // TODO shouldn't we demangle the path?
+ try
+ {
+ NetSystem.IO.File.Open(path, FileMode.CreateNew).Close();
+ return true;
+ }
+ catch(Exception)
+ {
+ return false;
+ }
+ }
+
+ private static long DateTimeToJavaLongTime(DateTime datetime)
+ {
+ return (TimeZone.CurrentTimeZone.ToUniversalTime(datetime) - new DateTime(1970, 1, 1)).Ticks / 10000L;
+ }
+
+ public static DateTime JavaLongTimeToDateTime(long datetime)
+ {
+ return TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(new DateTime(1970, 1, 1).Ticks + datetime * 10000L));
+ }
+
+ public static long lastModifiedInternal(object obj, string path)
+ {
+ try
+ {
+ return DateTimeToJavaLongTime(NetSystem.IO.File.GetLastWriteTime(DemanglePath(path)));
+ }
+ catch(Exception)
+ {
+ return 0;
+ }
+ }
+
+ public static string[] listInternal(object obj, string dirname)
+ {
+ // TODO error handling
+ try
+ {
+ string[] l = NetSystem.IO.Directory.GetFileSystemEntries(dirname);
+ for(int i = 0; i < l.Length; i++)
+ {
+ int pos = l[i].LastIndexOf(Path.DirectorySeparatorChar);
+ if(pos >= 0)
+ {
+ l[i] = l[i].Substring(pos + 1);
+ }
+ }
+ return l;
+ }
+ catch(Exception)
+ {
+ return null;
+ }
+ }
+
+ public static bool canReadInternal(object obj, string file)
+ {
+ try
+ {
+ // HACK if file refers to a directory, we always return true
+ if(NetSystem.IO.Directory.Exists(file))
+ {
+ return true;
+ }
+ new FileInfo(file).Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite).Close();
+ return true;
+ }
+ catch(Exception)
+ {
+ return false;
+ }
+ }
+
+ public static bool canWriteInternal(object obj, string file)
+ {
+ try
+ {
+ // HACK if file refers to a directory, we always return true
+ if(NetSystem.IO.Directory.Exists(file))
+ {
+ return true;
+ }
+ new FileInfo(file).Open(FileMode.Open, FileAccess.Write, FileShare.ReadWrite).Close();
+ return true;
+ }
+ catch(Exception)
+ {
+ return false;
+ }
+ }
+
+ public static bool renameToInternal(object obj, string oldName, string newName)
+ {
+ try
+ {
+ new FileInfo(oldName).MoveTo(newName);
+ return true;
+ }
+ catch(Exception)
+ {
+ return false;
+ }
+ }
+
+ public static bool setLastModifiedInternal(object obj, string file, long lastModified)
+ {
+ try
+ {
+ new FileInfo(file).LastWriteTime = JavaLongTimeToDateTime(lastModified);
+ return true;
+ }
+ catch(Exception)
+ {
+ return false;
+ }
+ }
+
+ public static bool setReadOnlyInternal(object obj, string file)
+ {
+ try
+ {
+ new FileInfo(file).Attributes |= FileAttributes.ReadOnly;
+ return true;
+ }
+ catch(Exception)
+ {
+ return false;
+ }
+ }
+ }
+
+ public class ObjectInputStream
+ {
+ public static object currentClassLoader(object sm)
+ {
+ // TODO calling currentClassLoader in SecurityManager results in null being returned, so we use our own
+ // version for now, don't know what the security implications of this are
+ // SECURITY
+ return NativeCode.java.lang.VMSecurityManager.currentClassLoader();
+ }
+
+ public static void callReadMethod(object ois, object obj, object clazz)
+ {
+ Type type = NativeCode.java.lang.Class.getType(clazz);
+ MethodInfo mi = type.GetMethod("readObject", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { ois.GetType() }, null);
+ mi.Invoke(obj, new object[] { ois });
+ }
+
+ public static object allocateObject(object ois, object clazz)
+ {
+ Type type = NativeCode.java.lang.Class.getType(clazz);
+ return NetSystem.Runtime.Serialization.FormatterServices.GetUninitializedObject(type);
+ }
+
+ public static void callConstructor(object ois, object clazz, object obj)
+ {
+ Type type = NativeCode.java.lang.Class.getType(clazz);
+ type.GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null).Invoke(obj, null);
+ }
+
+ public static void setBooleanField(object ois, object obj, object clazz, string field_name, bool val)
+ {
+ SetFieldValue(obj, clazz, field_name, val);
+ }
+
+ public static void setByteField(object ois, object obj, object clazz, string field_name, sbyte val)
+ {
+ SetFieldValue(obj, clazz, field_name, val);
+ }
+
+ public static void setCharField(object ois, object obj, object clazz, string field_name, char val)
+ {
+ SetFieldValue(obj, clazz, field_name, val);
+ }
+
+ public static void setDoubleField(object ois, object obj, object clazz, string field_name, double val)
+ {
+ SetFieldValue(obj, clazz, field_name, val);
+ }
+
+ public static void setFloatField(object ois, object obj, object clazz, string field_name, float val)
+ {
+ SetFieldValue(obj, clazz, field_name, val);
+ }
+
+ public static void setIntField(object ois, object obj, object clazz, string field_name, int val)
+ {
+ SetFieldValue(obj, clazz, field_name, val);
+ }
+
+ public static void setLongField(object ois, object obj, object clazz, string field_name, long val)
+ {
+ SetFieldValue(obj, clazz, field_name, val);
+ }
+
+ public static void setShortField(object ois, object obj, object clazz, string field_name, short val)
+ {
+ SetFieldValue(obj, clazz, field_name, val);
+ }
+
+ public static void setObjectField(object ois, object obj, object clazz, string field_name, string type_code, object val)
+ {
+ SetFieldValue(obj, clazz, field_name, val);
+ }
+
+ private static void SetFieldValue(object obj, object clazz, string field_name, object val)
+ {
+ // TODO support overloaded field name
+ Type type = NativeCode.java.lang.Class.getType(clazz);
+// while(type != null)
+ {
+ FieldInfo fi = type.GetField(field_name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
+ if(fi != null)
+ {
+ fi.SetValue(obj, val);
+ return;
+ }
+ // NOTE if not found, we're moving up the hierarchy, even though I'd expect GetField to do that, it doesn't, at least
+ // not for private fields
+// type = type.BaseType;
+ }
+ throw new InvalidOperationException("SetFieldValue: field not found, field_name = " + field_name + ", obj = " + obj);
+ }
+ }
+
+ public class ObjectOutputStream
+ {
+ public static void callWriteMethod(object oos, object obj)
+ {
+ Type type = obj.GetType();
+ MethodInfo mi = type.GetMethod("writeObject", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { oos.GetType() }, null);
+ mi.Invoke(obj, new object[] { oos });
+ }
+
+ public static bool getBooleanField(object oos, object obj, object clazz, string field_name)
+ {
+ return (bool)GetFieldValue(obj, clazz, field_name);
+ }
+
+ public static sbyte getByteField(object oos, object obj, object clazz, string field_name)
+ {
+ return (sbyte)GetFieldValue(obj, clazz, field_name);
+ }
+
+ public static char getCharField(object oos, object obj, object clazz, string field_name)
+ {
+ return (char)GetFieldValue(obj, clazz, field_name);
+ }
+
+ public static double getDoubleField(object oos, object obj, object clazz, string field_name)
+ {
+ return (double)GetFieldValue(obj, clazz, field_name);
+ }
+
+ public static float getFloatField(object oos, object obj, object clazz, string field_name)
+ {
+ return (float)GetFieldValue(obj, clazz, field_name);
+ }
+
+ public static int getIntField(object oos, object obj, object clazz, string field_name)
+ {
+ return (int)GetFieldValue(obj, clazz, field_name);
+ }
+
+ public static long getLongField(object oos, object obj, object clazz, string field_name)
+ {
+ return (long)GetFieldValue(obj, clazz, field_name);
+ }
+
+ public static short getShortField(object oos, object obj, object clazz, string field_name)
+ {
+ return (short)GetFieldValue(obj, clazz, field_name);
+ }
+
+ public static object getObjectField(object oos, object obj, object clazz, string field_name, string type_code)
+ {
+ return GetFieldValue(obj, clazz, field_name);
+ }
+
+ private static object GetFieldValue(object obj, object clazz, string field_name)
+ {
+ // TODO support overloaded field name
+ Type type = NativeCode.java.lang.Class.getType(clazz);
+// while(type != null)
+ {
+ FieldInfo fi = type.GetField(field_name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
+ if(fi != null)
+ {
+ return fi.GetValue(obj);
+ }
+ // NOTE if not found, we're moving up the hierarchy, even though I'd expect GetField to do that, it doesn't, at least
+ // not for private fields
+// type = type.BaseType;
+ }
+ throw new InvalidOperationException("GetFieldValue: field not found, field_name = " + field_name + ", obj = " + obj);
+ }
+ }
+ }
+
+ namespace util
+ {
+ public class TimeZone
+ {
+ public static string getDefaultTimeZoneId()
+ {
+ // HACK return null, classpath then assumes GMT, which is fine by me, for the time being
+ return null;
+ }
+ }
+ }
+
+ namespace net
+ {
+ public class InetAddress
+ {
+ public static sbyte[] lookupInaddrAny()
+ {
+ return new sbyte[] { 0, 0, 0, 0 };
+ }
+
+ public static string getLocalHostName()
+ {
+ // TODO error handling
+ return NetSystem.Net.Dns.GetHostName();
+ }
+
+ public static int[][] getHostByName(string name)
+ {
+ // TODO error handling
+ try
+ {
+ NetSystem.Net.IPHostEntry he = NetSystem.Net.Dns.GetHostByName(name);
+ NetSystem.Net.IPAddress[] addresses = he.AddressList;
+ int[][] list = new int[addresses.Length][];
+ for(int i = 0; i < addresses.Length; i++)
+ {
+ list[i] = AddressToIntArray((int)addresses[i].Address);
+ }
+ return list;
+ }
+ catch(Exception x)
+ {
+ throw JavaException.UnknownHostException(x.Message);
+ }
+ }
+
+ public static string getHostByAddr(byte[] address)
+ {
+ return NetSystem.Net.Dns.GetHostByAddress(string.Format("{0}.{1}.{2}.{3}", address[0], address[1], address[2], address[3])).HostName;
+ }
+
+ private static int[] AddressToIntArray(int address)
+ {
+ // TODO check for correctness
+ return new int[] { address & 0xff, (address >> 8) & 0xff, (address >> 16) & 0xff, (address >> 24) & 0xff };
+ }
+ }
+
+ public class PlainDatagramSocketImpl
+ {
+ // TODO this method lives here, because UdpClient.Receive has a ByRef parameter and NetExp doesn't support that
+ // I have to figure out a way to support ref parameters from Java
+ public static void receive(object obj, object packet)
+ {
+ sbyte[] data = (sbyte[])packet.GetType().InvokeMember("getData", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, null, packet, new object[0]);
+ int length = (int)packet.GetType().InvokeMember("getLength", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, null, packet, new object[0]);
+ object s = obj.GetType().GetField("socket", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(obj);
+ NetSystem.Net.Sockets.UdpClient socket = (NetSystem.Net.Sockets.UdpClient)s;
+ NetSystem.Net.IPEndPoint remoteEP = new NetSystem.Net.IPEndPoint(0, 0);
+ byte[] buf = socket.Receive(ref remoteEP);
+ for(int i = 0; i < Math.Min(length, buf.Length); i++)
+ {
+ data[i] = (sbyte)buf[i];
+ }
+ packet.GetType().InvokeMember("setLength", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, null, packet, new object[] { buf.Length });
+ long remoteIP = remoteEP.Address.Address;
+ string remote = (remoteIP & 0xff) + "." + ((remoteIP >> 8) & 0xff) + "." + ((remoteIP >> 16) & 0xff) + "." + ((remoteIP >> 24) & 0xff);
+ object remoteAddress = ClassLoaderWrapper.GetType("java.net.InetAddress").GetMethod("getByName").Invoke(null, new object[] { remote });
+ packet.GetType().InvokeMember("setAddress", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, null, packet, new object[] { remoteAddress });
+ packet.GetType().InvokeMember("setPort", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, null, packet, new object[] { remoteEP.Port });
+ }
+ }
+ }
+}
+
+namespace NativeCode.gnu.java.net.protocol.ikvmres
+{
+ public class IkvmresURLConnection
+ {
+ public static void InitArray(sbyte[] buf, FieldInfo field)
+ {
+ NetSystem.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(buf, field.FieldHandle);
+ }
+ }
+}
diff --git a/IK.VM.NET/compiler.cs b/IK.VM.NET/compiler.cs
new file mode 100644
index 00000000..4cb61968
--- /dev/null
+++ b/IK.VM.NET/compiler.cs
@@ -0,0 +1,2450 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+using System.Collections;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Diagnostics.SymbolStore;
+using ExceptionTableEntry = ClassFile.Method.ExceptionTableEntry;
+using Instruction = ClassFile.Method.Instruction;
+
+class ReturnCookie
+{
+ public Label Stub;
+ public LocalBuilder Local;
+}
+
+class BranchCookie
+{
+ public Label Stub;
+ public int TargetIndex;
+ public Stack Stack = new Stack();
+}
+
+class ExceptionSorter : IComparer
+{
+ public int Compare(object x, object y)
+ {
+ ExceptionTableEntry e1 = (ExceptionTableEntry)x;
+ ExceptionTableEntry e2 = (ExceptionTableEntry)y;
+ if(e1.start_pc < e2.start_pc)
+ {
+ return -1;
+ }
+ if(e1.start_pc == e2.start_pc)
+ {
+ if(e1.end_pc == e2.end_pc)
+ {
+ if(e1.ordinal > e2.ordinal)
+ {
+ return -1;
+ }
+ return 1;
+ }
+ if(e1.end_pc > e2.end_pc)
+ {
+ return -1;
+ }
+ }
+ return 1;
+ }
+}
+
+class Compiler
+{
+ private static MethodInfo mapExceptionMethod = typeof(ExceptionHelper).GetMethod("MapException");
+ private static MethodInfo mapExceptionFastMethod = typeof(ExceptionHelper).GetMethod("MapExceptionFast");
+ private static MethodInfo fillInStackTraceMethod = typeof(ExceptionHelper).GetMethod("fillInStackTrace");
+ private static MethodInfo getTypeFromHandleMethod = typeof(Type).GetMethod("GetTypeFromHandle");
+ private static MethodInfo multiANewArrayMethod = typeof(ByteCodeHelper).GetMethod("multianewarray");
+ private static MethodInfo monitorEnterMethod = typeof(ByteCodeHelper).GetMethod("monitorenter");
+ private static MethodInfo monitorExitMethod = typeof(ByteCodeHelper).GetMethod("monitorexit");
+ private static MethodInfo throwHack = typeof(ExceptionHelper).GetMethod("ThrowHack");
+ private TypeWrapper clazz;
+ private ClassFile.Method.Code m;
+ private ILGenerator ilGenerator;
+ private ClassLoaderWrapper classLoader;
+ private MethodAnalyzer ma;
+ private Hashtable locals = new Hashtable();
+ private ClassFile.Method.ExceptionTableEntry[] exceptions;
+ private ISymbolDocumentWriter symboldocument;
+
+ private Compiler(TypeWrapper clazz, ClassFile.Method.Code m, ILGenerator ilGenerator, ClassLoaderWrapper classLoader)
+ {
+ this.clazz = clazz;
+ this.m = m;
+ this.ilGenerator = ilGenerator;
+ this.classLoader = classLoader;
+ if(JVM.Debug)
+ {
+ string sourcefile = m.Method.ClassFile.SourceFileAttribute;
+ if(sourcefile != null)
+ {
+ this.symboldocument = classLoader.ModuleBuilder.DefineDocument(sourcefile, Guid.Empty, Guid.Empty, Guid.Empty);
+ }
+ }
+ Profiler.Enter("MethodAnalyzer");
+ ma = new MethodAnalyzer(m, classLoader);
+ Profiler.Leave("MethodAnalyzer");
+ ArrayList ar = new ArrayList(m.ExceptionTable);
+// Console.WriteLine("before processing:");
+// foreach(ExceptionTableEntry e in ar)
+// {
+// Console.WriteLine("{0} to {1} handler {2}", e.start_pc, e.end_pc, e.handler_pc);
+// }
+ // TODO it's very bad practice to mess with ExceptionTableEntrys that are owned by the Method, yet we
+ // do that here, should be changed to use our own ETE class (which should also contain the ordinal, instead
+ // of the one in ClassFile.cs)
+ // OPTIMIZE there must be a more efficient algorithm to do this...
+ restart:
+ for(int i = 0; i < ar.Count; i++)
+ {
+ ExceptionTableEntry ei = (ExceptionTableEntry)ar[i];
+ for(int j = i + 1; j < ar.Count; j++)
+ {
+ ExceptionTableEntry ej = (ExceptionTableEntry)ar[j];
+ if(ei.start_pc <= ej.start_pc && ei.end_pc > ej.start_pc)
+ {
+ // try1.j
+ if(ej.end_pc > ei.end_pc)
+ {
+ ExceptionTableEntry emi = new ExceptionTableEntry();
+ emi.start_pc = ej.start_pc;
+ emi.end_pc = ei.end_pc;
+ emi.catch_type = ei.catch_type;
+ emi.handler_pc = ei.handler_pc;
+ ExceptionTableEntry emj = new ExceptionTableEntry();
+ emj.start_pc = ej.start_pc;
+ emj.end_pc = ei.end_pc;
+ emj.catch_type = ej.catch_type;
+ emj.handler_pc = ej.handler_pc;
+ ei.end_pc = emi.start_pc;
+ ej.start_pc = emj.end_pc;
+ ar.Insert(j, emj);
+ ar.Insert(i + 1, emi);
+ goto restart;
+ }
+ else if(ej.end_pc < ei.end_pc) // try2.j
+ {
+ ExceptionTableEntry emi = new ExceptionTableEntry();
+ emi.start_pc = ej.start_pc;
+ emi.end_pc = ej.end_pc;
+ emi.catch_type = ei.catch_type;
+ emi.handler_pc = ei.handler_pc;
+ ExceptionTableEntry eei = new ExceptionTableEntry();
+ eei.start_pc = ej.end_pc;
+ eei.end_pc = ei.end_pc;
+ eei.catch_type = ei.catch_type;
+ eei.handler_pc = ei.handler_pc;
+ ei.end_pc = emi.start_pc;
+ ar.Insert(i + 1, eei);
+ ar.Insert(i + 1, emi);
+ goto restart;
+ }
+ }
+ }
+ }
+ // __jsr inside a try block (to a PC outside the try block) causes the try
+ // block to be broken into two blocks surrounding the __jsr
+ // This is actually pretty common. Take, for example, the following code:
+ // class hello
+ // {
+ // public static void main(String[] args)
+ // {
+ // try
+ // {
+ // for(;;)
+ // {
+ // if(args.length == 0) return;
+ // }
+ // }
+ // finally
+ // {
+ // System.out.println("Hello, world!");
+ // }
+ // }
+ // }
+ restart_jsr:
+ for(int i = 0; i < ar.Count; i++)
+ {
+ ExceptionTableEntry ei = (ExceptionTableEntry)ar[i];
+ for(int j = FindPcIndex(ei.start_pc), e = FindPcIndex(ei.end_pc); j < e; j++)
+ {
+ if(m.Instructions[j].NormalizedOpCode == NormalizedByteCode.__jsr)
+ {
+ int targetPC = m.Instructions[j].NormalizedArg1 + m.Instructions[j].PC;
+ if(targetPC < ei.start_pc || targetPC >= ei.end_pc)
+ {
+ ExceptionTableEntry en = new ExceptionTableEntry();
+ en.catch_type = ei.catch_type;
+ en.handler_pc = ei.handler_pc;
+ en.start_pc = (ushort)m.Instructions[j + 1].PC;
+ en.end_pc = ei.end_pc;
+ ei.end_pc = (ushort)m.Instructions[j].PC;
+ ar.Insert(i + 1, en);
+ goto restart_jsr;
+ }
+ }
+ }
+ }
+ // Split try blocks at branch targets (branches from outside the try block)
+ for(int i = 0; i < ar.Count; i++)
+ {
+ ExceptionTableEntry ei = (ExceptionTableEntry)ar[i];
+ int start = FindPcIndex(ei.start_pc);
+ int end = FindPcIndex(ei.end_pc);
+ for(int j = 0; j < m.Instructions.Length; j++)
+ {
+ if(j < start || j >= end)
+ {
+ switch(m.Instructions[j].NormalizedOpCode)
+ {
+ case NormalizedByteCode.__lookupswitch:
+ // TODO if the switch branches out of the try block, that should be handled too
+// for(int j = 0; j < instr.Values.Length; j++)
+// {
+// state[FindPcIndex(instr.PC + instr.TargetOffsets[j])] += s;
+// }
+// state[FindPcIndex(instr.PC + instr.DefaultOffset)] += s;
+ break;
+ case NormalizedByteCode.__ifeq:
+ case NormalizedByteCode.__ifne:
+ case NormalizedByteCode.__iflt:
+ case NormalizedByteCode.__ifge:
+ case NormalizedByteCode.__ifgt:
+ case NormalizedByteCode.__ifle:
+ case NormalizedByteCode.__if_icmpeq:
+ case NormalizedByteCode.__if_icmpne:
+ case NormalizedByteCode.__if_icmplt:
+ case NormalizedByteCode.__if_icmpge:
+ case NormalizedByteCode.__if_icmpgt:
+ case NormalizedByteCode.__if_icmple:
+ case NormalizedByteCode.__if_acmpeq:
+ case NormalizedByteCode.__if_acmpne:
+ case NormalizedByteCode.__ifnull:
+ case NormalizedByteCode.__ifnonnull:
+ case NormalizedByteCode.__goto:
+ case NormalizedByteCode.__jsr:
+ {
+ int targetPC = m.Instructions[j].PC + m.Instructions[j].Arg1;
+ if(targetPC > ei.start_pc && targetPC < ei.end_pc)
+ {
+ ExceptionTableEntry en = new ExceptionTableEntry();
+ en.catch_type = ei.catch_type;
+ en.handler_pc = ei.handler_pc;
+ en.start_pc = (ushort)targetPC;
+ en.end_pc = ei.end_pc;
+ ei.end_pc = (ushort)targetPC;
+ ar.Insert(i + 1, en);
+ goto restart_jsr;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ // exception handlers are also a kind of jump, so we need to split try blocks around handlers as well
+ for(int i = 0; i < ar.Count; i++)
+ {
+ ExceptionTableEntry ei = (ExceptionTableEntry)ar[i];
+ // TODO verify that we don't need to start at j = 0
+ for(int j = i; j < ar.Count; j++)
+ {
+ ExceptionTableEntry ej = (ExceptionTableEntry)ar[j];
+ if(ej.handler_pc > ei.start_pc && ej.handler_pc < ei.end_pc)
+ {
+ ExceptionTableEntry en = new ExceptionTableEntry();
+ en.catch_type = ei.catch_type;
+ en.handler_pc = ei.handler_pc;
+ en.start_pc = (ushort)ej.handler_pc;
+ en.end_pc = ei.end_pc;
+ ei.end_pc = (ushort)ej.handler_pc;
+ ar.Insert(i + 1, en);
+ goto restart_jsr;
+ }
+ }
+ }
+ // filter out zero length try blocks
+ for(int i = 0; i < ar.Count; i++)
+ {
+ ExceptionTableEntry ei = (ExceptionTableEntry)ar[i];
+ if(ei.start_pc == ei.end_pc)
+ {
+ ar.RemoveAt(i);
+ i--;
+ }
+ }
+// Console.WriteLine("after processing:");
+// foreach(ExceptionTableEntry e in ar)
+// {
+// Console.WriteLine("{0} to {1} handler {2}", e.start_pc, e.end_pc, e.handler_pc);
+// }
+
+ exceptions = new ExceptionTableEntry[ar.Count];
+ ar.CopyTo(exceptions, 0);
+ for(int i = 0; i < exceptions.Length; i++)
+ {
+ exceptions[i].ordinal = i;
+ }
+ Array.Sort(exceptions, new ExceptionSorter());
+
+ // TODO remove these checks, if the above exception untangling is correct, this shouldn't ever
+ // be triggered
+ for(int i = 0; i < exceptions.Length; i++)
+ {
+ for(int j = i + 1; j < exceptions.Length; j++)
+ {
+ // check for partially overlapping try blocks (which is legal for the JVM, but not the CLR)
+ if(exceptions[i].start_pc < exceptions[j].start_pc &&
+ exceptions[j].start_pc < exceptions[i].end_pc &&
+ exceptions[i].end_pc < exceptions[j].end_pc)
+ {
+ throw new Exception("Partially overlapping try blocks is broken");
+ }
+ // check that we didn't destroy the ordering, when sorting
+ if(exceptions[i].start_pc <= exceptions[j].start_pc &&
+ exceptions[i].end_pc >= exceptions[j].end_pc &&
+ exceptions[i].ordinal < exceptions[j].ordinal)
+ {
+ throw new Exception("Non recursive try blocks is broken");
+ }
+ }
+ // make sure __jsr doesn't jump out of try block
+ for(int j = FindPcIndex(exceptions[i].start_pc), e = FindPcIndex(exceptions[i].end_pc); j < e; j++)
+ {
+ if(m.Instructions[j].NormalizedOpCode == NormalizedByteCode.__jsr)
+ {
+ int targetPC = m.Instructions[j].NormalizedArg1 + m.Instructions[j].PC;
+ if(targetPC < exceptions[i].start_pc || targetPC >= exceptions[i].end_pc)
+ {
+ Console.WriteLine("i = " + i);
+ Console.WriteLine("j = " + j);
+ Console.WriteLine("targetPC = " + targetPC);
+ throw new Exception("Try block splitting around __jsr is broken");
+ }
+ }
+ }
+ }
+ }
+
+ private struct DupHelper
+ {
+ private ClassLoaderWrapper classLoader;
+ private ILGenerator ilgen;
+ private bool[] isnull;
+ private LocalBuilder[] locals;
+
+ internal DupHelper(ClassLoaderWrapper classLoader, ILGenerator ilgen, int count)
+ {
+ this.classLoader = classLoader;
+ this.ilgen = ilgen;
+ isnull = new bool[count];
+ locals = new LocalBuilder[count];
+ }
+
+ internal DupHelper SetType(int i, string type)
+ {
+ if(type == "Lnull")
+ {
+ isnull[i] = true;
+ }
+ else if(type[0] != 'N')
+ {
+ // TODO handle class not found
+ locals[i] = ilgen.DeclareLocal(classLoader.ExpressionType(type));
+ }
+ return this;
+ }
+
+ internal DupHelper Load(int i)
+ {
+ if(isnull[i])
+ {
+ ilgen.Emit(OpCodes.Ldnull);
+ }
+ else if(locals[i] != null)
+ {
+ ilgen.Emit(OpCodes.Ldloc, locals[i]);
+ }
+ return this;
+ }
+
+ internal DupHelper Store(int i)
+ {
+ if(isnull[i])
+ {
+ ilgen.Emit(OpCodes.Pop);
+ }
+ else if(locals[i] != null)
+ {
+ ilgen.Emit(OpCodes.Stloc, locals[i]);
+ }
+ return this;
+ }
+ }
+
+ internal static void Compile(TypeWrapper clazz, ClassFile.Method m, ILGenerator ilGenerator, ClassLoaderWrapper classLoader)
+ {
+ Compiler c;
+ try
+ {
+ Profiler.Enter("new Compiler");
+ c = new Compiler(clazz, m.CodeAttribute, ilGenerator, classLoader);
+ Profiler.Leave("new Compiler");
+ }
+ catch(VerifyError x)
+ {
+ // because in Java the method is only verified if it is actually called,
+ // we generate code here to throw the VerificationError
+ Type verifyError = ClassLoaderWrapper.GetType("java.lang.VerifyError");
+ ilGenerator.Emit(OpCodes.Ldstr, string.Format("(class: {0}, method: {1}, signature: {2}, offset: {3}, instruction: {4}) {5}", x.Class, x.Method, x.Signature, x.ByteCodeOffset, x.Instruction, x.Message));
+ ilGenerator.Emit(OpCodes.Newobj, verifyError.GetConstructor(new Type[] { typeof(string) }));
+ ilGenerator.Emit(OpCodes.Throw);
+ return;
+ }
+ Profiler.Enter("Compile");
+ c.Compile(0, 0, null);
+ Profiler.Leave("Compile");
+ }
+
+ private void Compile(int initialInstructionIndex, int exceptionIndex, ArrayList exits)
+ {
+ int rangeBegin;
+ int rangeEnd; // NOTE points past the last instruction in the range
+ if(exceptionIndex == 0)
+ {
+ rangeBegin = 0;
+ // because the last instruction in the code array is always the additional __nop, put there
+ // by our classfile reader, this works
+ rangeEnd = m.Instructions[m.Instructions.Length - 1].PC;
+ }
+ else
+ {
+ rangeBegin = exceptions[exceptionIndex - 1].start_pc;
+ rangeEnd = exceptions[exceptionIndex - 1].end_pc;
+ }
+ object[] labels = new object[m.Instructions[m.Instructions.Length - 1].PC];
+ // used to track instructions that are 'live'
+ bool[] inuse = new bool[m.Instructions.Length];
+ // used to track instructions that have been compiled
+ bool[] done = new bool[m.Instructions.Length];
+ bool quit = false;
+ inuse[initialInstructionIndex] = true;
+ Instruction[] code = m.Instructions;
+ while(!quit)
+ {
+ quit = true;
+ for(int i = 0; i < code.Length; i++)
+ {
+ restart:
+ if(!inuse[i] || done[i])
+ {
+ continue;
+ }
+ quit = false;
+ done[i] = true;
+ Instruction instr = code[i];
+
+ // make sure we didn't branch into a try block
+ // NOTE this check is not strict enough
+ // UPDATE since we're now splitting try blocks around branch targets, this shouldn't be possible anymore
+ if(exceptionIndex < exceptions.Length &&
+ instr.PC > exceptions[exceptionIndex].start_pc &&
+ instr.PC < exceptions[exceptionIndex].end_pc)
+ {
+ throw new NotImplementedException("branch into try block not implemented: " + clazz.Name + "." + m.Method.Name + m.Method.Signature + " (index = " + exceptionIndex + ", pc = " + instr.PC + ")");
+ }
+
+ // every instruction has an associated label, for now
+ if(true)
+ {
+ object label = labels[instr.PC];
+ if(label == null)
+ {
+ label = ilGenerator.DefineLabel();
+ labels[instr.PC] = label;
+ }
+ ilGenerator.MarkLabel((Label)label);
+ if(symboldocument != null)
+ {
+ // TODO this needs to be done better
+ ClassFile.Method.LineNumberTableEntry[] table = m.LineNumberTableAttribute;
+ if(table != null)
+ {
+ for(int j = 0; j < table.Length; j++)
+ {
+ if(table[j].start_pc == instr.PC && table[j].line_number != 0)
+ {
+ ilGenerator.MarkSequencePoint(symboldocument, table[j].line_number, 0, table[j].line_number + 1, 0);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // handle the try block here
+ for(int j = exceptionIndex; j < exceptions.Length; j++)
+ {
+ if(exceptions[j].start_pc == instr.PC)
+ {
+ if(ma.GetStackHeight(i) != 0)
+ {
+ Stack stack = new Stack();
+ int stackHeight = ma.GetStackHeight(i);
+ for(int n = 0; n < stackHeight; n++)
+ {
+ // TODO handle class not found
+ string t = ma.GetRawStackType(i, n);
+ if(t.Length > 1 && t[0] == 'N')
+ {
+ // unitialized references aren't really there
+ continue;
+ }
+ if(t == "Lnull")
+ {
+ stack.Push(null);
+ }
+ else
+ {
+ LocalBuilder local = ilGenerator.DeclareLocal(classLoader.ExpressionType(t));
+ stack.Push(local);
+ ilGenerator.Emit(OpCodes.Stloc, local);
+ }
+ }
+ ilGenerator.BeginExceptionBlock();
+ while(stack.Count != 0)
+ {
+ LocalBuilder local = (LocalBuilder)stack.Pop();
+ if(local == null)
+ {
+ ilGenerator.Emit(OpCodes.Ldnull);
+ }
+ else
+ {
+ ilGenerator.Emit(OpCodes.Ldloc, local);
+ }
+ }
+ }
+ else
+ {
+ ilGenerator.BeginExceptionBlock();
+ }
+ ArrayList newExits = new ArrayList();
+ Compile(i, j + 1, newExits);
+ for(int k = 0; k < newExits.Count; k++)
+ {
+ object exit = newExits[k];
+ BranchCookie bc = exit as BranchCookie;
+ if(bc != null)
+ {
+ ilGenerator.MarkLabel(bc.Stub);
+ int stack = ma.GetStackHeight(bc.TargetIndex);
+ for(int n = 0; n < stack; n++)
+ {
+ // TODO handle class not found
+ string t = ma.GetRawStackType(bc.TargetIndex, n);
+ if((t.Length > 1 && t[0] == 'N') || t == "Lnull")
+ {
+ // unitialized references aren't really there, but at the push site we
+ // need to know that we have to skip this slot, so we push a null as well,
+ // and then at the push site we'll look at the stack type to figure out
+ // if it is a real null or an uniti
+ bc.Stack.Push(null);
+ }
+ else
+ {
+ LocalBuilder local = ilGenerator.DeclareLocal(classLoader.ExpressionType(t));
+ bc.Stack.Push(local);
+ ilGenerator.Emit(OpCodes.Stloc, local);
+ }
+ }
+ bc.Stub = ilGenerator.DefineLabel();
+ ilGenerator.Emit(OpCodes.Leave, bc.Stub);
+ }
+ }
+ Type excType;
+ if(exceptions[j].catch_type == 0)
+ {
+ excType = typeof(Exception);
+ }
+ else
+ {
+ // TODO handle class not found
+ excType = classLoader.LoadClassBySlashedName(m.Method.ClassFile.GetConstantPoolClass(exceptions[j].catch_type)).Type;
+ }
+ if(true)
+ {
+ ilGenerator.BeginCatchBlock(typeof(Exception));
+ Label label = ilGenerator.DefineLabel();
+ LocalBuilder local = ilGenerator.DeclareLocal(excType);
+ // special case for catch(Throwable) (and finally), that produces less code and
+ // should be faster
+ if(excType == typeof(Exception))
+ {
+ ilGenerator.Emit(OpCodes.Call, mapExceptionFastMethod);
+ ilGenerator.Emit(OpCodes.Stloc, local);
+ ilGenerator.Emit(OpCodes.Leave, label);
+ }
+ else
+ {
+ ilGenerator.Emit(OpCodes.Ldtoken, excType);
+ ilGenerator.Emit(OpCodes.Call, getTypeFromHandleMethod);
+ ilGenerator.Emit(OpCodes.Call, mapExceptionMethod);
+ ilGenerator.Emit(OpCodes.Castclass, excType);
+ ilGenerator.Emit(OpCodes.Stloc, local);
+ ilGenerator.Emit(OpCodes.Ldloc, local);
+ Label rethrow = ilGenerator.DefineLabel();
+ ilGenerator.Emit(OpCodes.Brfalse, rethrow);
+ ilGenerator.Emit(OpCodes.Leave, label);
+ ilGenerator.MarkLabel(rethrow);
+ ilGenerator.Emit(OpCodes.Rethrow);
+ }
+ ilGenerator.EndExceptionBlock();
+ ilGenerator.MarkLabel(label);
+ ilGenerator.Emit(OpCodes.Ldloc, local);
+ ilGenerator.Emit(OpCodes.Br, GetLabel(labels, exceptions[j].handler_pc, inuse, rangeBegin, rangeEnd, exits));
+ }
+ for(int k = 0; k < newExits.Count; k++)
+ {
+ object exit = newExits[k];
+ ReturnCookie rc = exit as ReturnCookie;
+ if(rc != null)
+ {
+ if(exceptionIndex == 0)
+ {
+ ilGenerator.MarkLabel(rc.Stub);
+ if(rc.Local != null)
+ {
+ ilGenerator.Emit(OpCodes.Ldloc, rc.Local);
+ }
+ ilGenerator.Emit(OpCodes.Ret);
+ }
+ else
+ {
+ ReturnCookie rc1 = new ReturnCookie();
+ rc1.Local = rc.Local;
+ rc1.Stub = ilGenerator.DefineLabel();
+ ilGenerator.MarkLabel(rc.Stub);
+ ilGenerator.Emit(OpCodes.Leave, rc1.Stub);
+ exits.Add(rc1);
+ }
+ }
+ else
+ {
+ BranchCookie bc = exit as BranchCookie;
+ if(bc != null)
+ {
+ ilGenerator.MarkLabel(bc.Stub);
+ int stack = ma.GetStackHeight(bc.TargetIndex);
+ for(int n = 0; n < stack; n++)
+ {
+ LocalBuilder local = (LocalBuilder)bc.Stack.Pop();
+ if(local == null)
+ {
+ if(ma.GetRawStackType(bc.TargetIndex, (stack - 1) - n) == "Lnull")
+ {
+ ilGenerator.Emit(OpCodes.Ldnull);
+ }
+ else
+ {
+ // if the type is not Lnull, it means it was an unitialized object reference,
+ // which don't really exist on our stack
+ }
+ }
+ else
+ {
+ ilGenerator.Emit(OpCodes.Ldloc, local);
+ }
+ }
+ ilGenerator.Emit(OpCodes.Br, GetLabel(labels, code[bc.TargetIndex].PC, inuse, rangeBegin, rangeEnd, exits));
+ }
+ }
+ }
+ goto restart;
+ }
+ }
+
+ switch(instr.NormalizedOpCode)
+ {
+ case NormalizedByteCode.__getstatic:
+ {
+ ClassFile.ConstantPoolItemFieldref cpi = m.Method.ClassFile.GetFieldref(instr.Arg1);
+ FieldWrapper field = GetField(cpi, true, null, false);
+ if(field != null)
+ {
+ field.EmitGet.Emit(ilGenerator);
+ }
+ else
+ {
+ EmitPlaceholder(cpi.Signature);
+ }
+ break;
+ }
+ case NormalizedByteCode.__putstatic:
+ {
+ ClassFile.ConstantPoolItemFieldref cpi = m.Method.ClassFile.GetFieldref(instr.Arg1);
+ FieldWrapper field = GetField(cpi, true, null, true);
+ if(field != null)
+ {
+ // because of the way interface merging works, an object reference is valid
+ // for any interface reference
+ if(field.FieldType != typeof(object) && ma.GetRawStackType(i, 0) == "Ljava/lang/Object;")
+ {
+ ilGenerator.Emit(OpCodes.Castclass, field.FieldType);
+ }
+ field.EmitSet.Emit(ilGenerator);
+ }
+ else
+ {
+ ilGenerator.Emit(OpCodes.Pop);
+ }
+ break;
+ }
+ case NormalizedByteCode.__getfield:
+ {
+ ClassFile.ConstantPoolItemFieldref cpi = m.Method.ClassFile.GetFieldref(instr.Arg1);
+ TypeWrapper thisType = LoadClass(SigTypeToClassName(ma.GetRawStackType(i, 0), cpi.Class));
+ if(thisType != null)
+ {
+ FieldWrapper field = GetField(cpi, false, thisType, false);
+ if(field != null)
+ {
+ field.EmitGet.Emit(ilGenerator);
+ break;
+ }
+ }
+ ilGenerator.Emit(OpCodes.Pop);
+ EmitPlaceholder(cpi.Signature);
+ break;
+ }
+ case NormalizedByteCode.__putfield:
+ {
+ ClassFile.ConstantPoolItemFieldref cpi = m.Method.ClassFile.GetFieldref(instr.Arg1);
+ TypeWrapper thisType = LoadClass(SigTypeToClassName(ma.GetRawStackType(i, 1), cpi.Class));
+ if(thisType != null)
+ {
+ FieldWrapper field = GetField(cpi, false, thisType, true);
+ if(field != null)
+ {
+ // because of the way interface merging works, an object reference is valid
+ // for any interface reference
+ if(field.FieldType != typeof(object) && ma.GetRawStackType(i, 0) == "Ljava/lang/Object;")
+ {
+ ilGenerator.Emit(OpCodes.Castclass, field.FieldType);
+ }
+ field.EmitSet.Emit(ilGenerator);
+ break;
+ }
+ }
+ ilGenerator.Emit(OpCodes.Pop);
+ ilGenerator.Emit(OpCodes.Pop);
+ break;
+ }
+ case NormalizedByteCode.__aconst_null:
+ ilGenerator.Emit(OpCodes.Ldnull);
+ break;
+ case NormalizedByteCode.__iconst:
+ switch(instr.NormalizedArg1)
+ {
+ case -1:
+ ilGenerator.Emit(OpCodes.Ldc_I4_M1);
+ break;
+ case 0:
+ ilGenerator.Emit(OpCodes.Ldc_I4_0);
+ break;
+ case 1:
+ ilGenerator.Emit(OpCodes.Ldc_I4_1);
+ break;
+ case 2:
+ ilGenerator.Emit(OpCodes.Ldc_I4_2);
+ break;
+ case 3:
+ ilGenerator.Emit(OpCodes.Ldc_I4_3);
+ break;
+ case 4:
+ ilGenerator.Emit(OpCodes.Ldc_I4_4);
+ break;
+ case 5:
+ ilGenerator.Emit(OpCodes.Ldc_I4_5);
+ break;
+ case 6:
+ ilGenerator.Emit(OpCodes.Ldc_I4_6);
+ break;
+ case 7:
+ ilGenerator.Emit(OpCodes.Ldc_I4_7);
+ break;
+ case 8:
+ ilGenerator.Emit(OpCodes.Ldc_I4_8);
+ break;
+ default:
+ if(instr.NormalizedArg1 >= -128 && instr.NormalizedArg1 <= 127)
+ {
+ ilGenerator.Emit(OpCodes.Ldc_I4_S, (sbyte)instr.NormalizedArg1);
+ }
+ else
+ {
+ ilGenerator.Emit(OpCodes.Ldc_I4, instr.NormalizedArg1);
+ }
+ break;
+ }
+ break;
+ case NormalizedByteCode.__lconst_0:
+ ilGenerator.Emit(OpCodes.Ldc_I8, 0L);
+ break;
+ case NormalizedByteCode.__lconst_1:
+ ilGenerator.Emit(OpCodes.Ldc_I8, 1L);
+ break;
+ case NormalizedByteCode.__fconst_0:
+ ilGenerator.Emit(OpCodes.Ldc_R4, 0.0f);
+ break;
+ case NormalizedByteCode.__fconst_1:
+ ilGenerator.Emit(OpCodes.Ldc_R4, 1.0f);
+ break;
+ case NormalizedByteCode.__fconst_2:
+ ilGenerator.Emit(OpCodes.Ldc_R4, 2.0f);
+ break;
+ case NormalizedByteCode.__dconst_0:
+ ilGenerator.Emit(OpCodes.Ldc_R8, 0.0d);
+ break;
+ case NormalizedByteCode.__dconst_1:
+ ilGenerator.Emit(OpCodes.Ldc_R8, 1.0d);
+ break;
+ case NormalizedByteCode.__ldc:
+ {
+ object o = instr.MethodCode.Method.ClassFile.GetConstantPoolConstant(instr.Arg1);
+ if(o is string)
+ {
+ ilGenerator.Emit(OpCodes.Ldstr, (string)o);
+ }
+ else if(o is float)
+ {
+ ilGenerator.Emit(OpCodes.Ldc_R4, (float)o);
+ }
+ else if(o is double)
+ {
+ ilGenerator.Emit(OpCodes.Ldc_R8, (double)o);
+ }
+ else if(o is int)
+ {
+ ilGenerator.Emit(OpCodes.Ldc_I4, (int)o);
+ }
+ else if(o is long)
+ {
+ ilGenerator.Emit(OpCodes.Ldc_I8, (long)o);
+ }
+ else
+ {
+ throw new NotImplementedException(o.GetType().Name);
+ }
+ break;
+ }
+ case NormalizedByteCode.__invokestatic:
+ {
+ ClassFile.ConstantPoolItemFMI cpi = m.Method.ClassFile.GetMethodref(instr.Arg1);
+ MethodWrapper method = GetMethod(cpi, null, NormalizedByteCode.__invokestatic);
+ if(method != null)
+ {
+ method.EmitCall.Emit(ilGenerator);
+ }
+ else
+ {
+ SigEnumerator sig = new SigEnumerator(cpi.Signature);
+ while(sig.MoveNext())
+ {
+ ilGenerator.Emit(OpCodes.Pop);
+ }
+ EmitPlaceholder(cpi.Signature.Substring(cpi.Signature.LastIndexOf(')') + 1));
+ }
+ break;
+ }
+ case NormalizedByteCode.__invokevirtual:
+ case NormalizedByteCode.__invokeinterface:
+ case NormalizedByteCode.__invokespecial:
+ {
+ // TODO invokespecial should check for null "this" reference
+ ClassFile.ConstantPoolItemFMI cpi = m.Method.ClassFile.GetMethodref(instr.Arg1);
+ SigEnumerator sig = new SigEnumerator(cpi.Signature);
+ int argcount = 0;
+ while(sig.MoveNext())
+ {
+ argcount++;
+ }
+ string type = ma.GetRawStackType(i, argcount);
+ TypeWrapper thisType = LoadClass(SigTypeToClassName(type, cpi.Class));
+ // invokeinterface needs to have special support for downcasting to the interface (because
+ // the verifier may not be able to merge two interfaces, but the resulting code would still be valid)
+ if(instr.NormalizedOpCode == NormalizedByteCode.__invokeinterface &&
+ thisType == ClassLoaderWrapper.GetBootstrapClassLoader().LoadClassBySlashedName("java/lang/Object"))
+ {
+ thisType = LoadClass(cpi.Class);
+ if(thisType != null)
+ {
+ DupHelper dup = new DupHelper(classLoader, ilGenerator, argcount);
+ for(int k = 0; k < argcount; k++)
+ {
+ dup.SetType(k, ma.GetRawStackType(i, k));
+ }
+ for(int k = 0; k < argcount; k++)
+ {
+ dup.Store(k);
+ }
+ // TODO this IncompatibleClassChangeError check should also be applied
+ // for other locations where we can "consume" an object reference in the
+ // place of an interface reference (putstatic / putfield / arguments for invoke*).
+ // TODO it turns out that when an interface ref is expected, *any* type will be accepted!
+ ilGenerator.Emit(OpCodes.Dup);
+ Label label = ilGenerator.DefineLabel();
+ ilGenerator.Emit(OpCodes.Brfalse_S, label);
+ ilGenerator.Emit(OpCodes.Isinst, thisType.Type);
+ ilGenerator.Emit(OpCodes.Dup);
+ ilGenerator.Emit(OpCodes.Brtrue_S, label);
+ EmitError("java.lang.IncompatibleClassChangeError", null);
+ ilGenerator.MarkLabel(label);
+ for(int k = argcount - 1; k >= 0; k--)
+ {
+ dup.Load(k);
+ }
+ }
+ }
+ else if(thisType != null && !thisType.IsSubTypeOf(LoadClass(cpi.Class)))
+ {
+ EmitError("java.lang.IncompatibleClassChangeError", null);
+ thisType = null;
+ }
+ MethodWrapper method = (thisType != null) ? GetMethod(cpi, thisType, instr.NormalizedOpCode) : null;
+ if(instr.NormalizedOpCode == NormalizedByteCode.__invokespecial)
+ {
+ if(cpi.Name == "<init>")
+ {
+ if(type[0] == 'N')
+ {
+ if(thisType != null && (thisType.IsAbstract || thisType.IsInterface))
+ {
+ // the CLR gets confused when we do a newobj on an abstract class,
+ // so we set method to null, to basically just comment out the constructor
+ // call (the InstantionError was already emitted at the "new" bytecode)
+ method = null;
+ }
+ // we have to construct a list of all the unitialized references to the object
+ // we're about to create on the stack, so that we can reconstruct the stack after
+ // the "newobj" instruction
+ int trivcount = 0;
+ bool nontrivial = false;
+ bool[] stackfix = new bool[ma.GetStackHeight(i) - (argcount + 1)];
+ bool[] localsfix = new bool[m.MaxLocals];
+ for(int j = 0; j < stackfix.Length; j++)
+ {
+ if(ma.GetRawStackType(i, argcount + 1 + j) == type)
+ {
+ stackfix[j] = true;
+ if(trivcount == j)
+ {
+ trivcount++;
+ }
+ else
+ {
+ // if there is other stuff on the stack between the new object
+ // references, we need to do more work to construct the proper stack
+ // layout after the newobj instruction
+ nontrivial = true;
+ }
+ }
+ }
+ for(int j = 0; j < localsfix.Length; j++)
+ {
+ if(ma.GetLocalType(i, j) == type)
+ {
+ localsfix[j] = true;
+ nontrivial = true;
+ }
+ }
+ if(method != null)
+ {
+ method.EmitNewobj.Emit(ilGenerator);
+ }
+ else
+ {
+ for(int j = 0; j < argcount; j++)
+ {
+ ilGenerator.Emit(OpCodes.Pop);
+ }
+ ilGenerator.Emit(OpCodes.Ldnull);
+ }
+ // TODO it is probably a better idea to do this in the constructor for each class
+ // derived from java.lang.Throwable, but if we do move this to the constructor, we
+ // should still call it here for non-Java exceptions (that aren't derived from Throwable)
+ Type t = ExpressionType(type.Substring(type.IndexOf(';') + 1));
+ if(t == null)
+ {
+ // If the type couldn't be loaded, we continue we object to make sure
+ // the code remains verifiable (the ExpressionType call above already generated
+ // code to throw an exception, but the remaing code still needs to be verifiable,
+ // even though it is unreachable).
+ t = typeof(object);
+ }
+ if(typeof(Exception).IsAssignableFrom(t))
+ {
+ ilGenerator.Emit(OpCodes.Dup);
+ ilGenerator.Emit(OpCodes.Call, fillInStackTraceMethod);
+ ilGenerator.Emit(OpCodes.Pop);
+ }
+ if(nontrivial)
+ {
+ // this could be done a little more efficiently, but since in practice this
+ // code never runs (for code compiled from Java source) it doesn't
+ // really matter
+ LocalBuilder newobj = ilGenerator.DeclareLocal(t);
+ ilGenerator.Emit(OpCodes.Stloc, newobj);
+ LocalBuilder[] tempstack = new LocalBuilder[stackfix.Length];
+ for(int j = 0; j < stackfix.Length; j++)
+ {
+ if(!stackfix[j])
+ {
+ string stacktype = ma.GetRawStackType(i, argcount + 1 + j);
+ // it could be another new object reference (not from current invokespecial <init>
+ // instruction)
+ if(stacktype[0] != 'N')
+ {
+ // TODO handle Lnull stack entries
+ // TODO handle class not found
+ LocalBuilder lb = ilGenerator.DeclareLocal(classLoader.ExpressionType(stacktype));
+ ilGenerator.Emit(OpCodes.Stloc, lb);
+ tempstack[j] = lb;
+ }
+ }
+ }
+ for(int j = stackfix.Length - 1; j >= 0; j--)
+ {
+ if(stackfix[j])
+ {
+ ilGenerator.Emit(OpCodes.Ldloc, newobj);
+ }
+ else if(tempstack[j] != null)
+ {
+ ilGenerator.Emit(OpCodes.Ldloc, tempstack[j]);
+ }
+ }
+ for(int j = 0; j < localsfix.Length; j++)
+ {
+ if(localsfix[j])
+ {
+ ilGenerator.Emit(OpCodes.Ldloc, newobj);
+ ilGenerator.Emit(OpCodes.Stloc, GetLocal(typeof(object), j));
+ }
+ }
+ }
+ else
+ {
+ if(trivcount == 0)
+ {
+ ilGenerator.Emit(OpCodes.Pop);
+ }
+ else
+ {
+ for(int j = 1; j < trivcount; j++)
+ {
+ ilGenerator.Emit(OpCodes.Dup);
+ }
+ }
+ }
+ }
+ else
+ {
+ if(method != null)
+ {
+ method.EmitCall.Emit(ilGenerator);
+ }
+ else
+ {
+ // if we're a constructor and the call to the base class constructor
+ // wasn't accessible, we need make sure that there is no code path that
+ // returns from the constructor, otherwise the method will be not verifiable
+ // TODO this isn't anywhere near a proper solution, but for the time being it works
+ // some things to consider:
+ // - only pull this full when calls to the base class constructor fail
+ // - when control flow is complex, this trivial solution will not work
+ ilGenerator.Emit(OpCodes.Ldnull);
+ ilGenerator.Emit(OpCodes.Throw);
+ return;
+// for(int j = 0; j < argcount + 1; j++)
+// {
+// ilGenerator.Emit(OpCodes.Pop);
+// }
+// EmitPlaceholder(cpi.Signature.Substring(cpi.Signature.LastIndexOf(')') + 1));
+ }
+ }
+ }
+ else
+ {
+ if(method != null)
+ {
+ method.EmitCall.Emit(ilGenerator);
+ }
+ else
+ {
+ for(int j = 0; j < argcount + 1; j++)
+ {
+ ilGenerator.Emit(OpCodes.Pop);
+ }
+ EmitPlaceholder(cpi.Signature.Substring(cpi.Signature.LastIndexOf(')') + 1));
+ }
+ }
+ }
+ else
+ {
+ if(method != null)
+ {
+ method.EmitCallvirt.Emit(ilGenerator);
+ }
+ else
+ {
+ for(int j = 0; j < argcount + 1; j++)
+ {
+ ilGenerator.Emit(OpCodes.Pop);
+ }
+ EmitPlaceholder(cpi.Signature.Substring(cpi.Signature.LastIndexOf(')') + 1));
+ }
+ }
+ break;
+ }
+ case NormalizedByteCode.__return:
+ case NormalizedByteCode.__areturn:
+ case NormalizedByteCode.__ireturn:
+ case NormalizedByteCode.__lreturn:
+ case NormalizedByteCode.__freturn:
+ case NormalizedByteCode.__dreturn:
+ {
+ if(exceptionIndex != 0)
+ {
+ // if we're inside an exception block, copy TOS to local, emit "leave" and push item onto our "todo" list
+ ReturnCookie rc = new ReturnCookie();
+ if(instr.NormalizedOpCode != NormalizedByteCode.__return)
+ {
+ // TODO handle class not found
+ Type retType = classLoader.RetTypeFromSig(m.Method.Signature);
+ rc.Local = ilGenerator.DeclareLocal(retType);
+ // because of the way interface merging works, an object reference is valid
+ // for any interface reference
+ if(retType != typeof(object) && ma.GetRawStackType(i, 0) == "Ljava/lang/Object;")
+ {
+ ilGenerator.Emit(OpCodes.Castclass, retType);
+ }
+ ilGenerator.Emit(OpCodes.Stloc, rc.Local);
+ }
+ rc.Stub = ilGenerator.DefineLabel();
+ // NOTE leave automatically discards any junk that may be on the stack
+ ilGenerator.Emit(OpCodes.Leave, rc.Stub);
+ exits.Add(rc);
+ }
+ else
+ {
+ // if there is junk on the stack (other than the return value), we must pop it off
+ // because in .NET this is invalid (unlike in Java)
+ int stackHeight = ma.GetStackHeight(i);
+ if(instr.NormalizedOpCode == NormalizedByteCode.__return)
+ {
+ for(int j = 0; j < stackHeight; j++)
+ {
+ ilGenerator.Emit(OpCodes.Pop);
+ }
+ ilGenerator.Emit(OpCodes.Ret);
+ }
+ else
+ {
+ // TODO handle class not found
+ Type retType = classLoader.RetTypeFromSig(m.Method.Signature);
+ // because of the way interface merging works, an object reference is valid
+ // for any interface reference
+ if(retType != typeof(object) && ma.GetRawStackType(i, 0) == "Ljava/lang/Object;")
+ {
+ ilGenerator.Emit(OpCodes.Castclass, retType);
+ }
+ if(stackHeight != 1)
+ {
+ LocalBuilder local = ilGenerator.DeclareLocal(retType);
+ ilGenerator.Emit(OpCodes.Stloc, local);
+ for(int j = 1; j < stackHeight; j++)
+ {
+ ilGenerator.Emit(OpCodes.Pop);
+ }
+ ilGenerator.Emit(OpCodes.Ldloc, local);
+ }
+ ilGenerator.Emit(OpCodes.Ret);
+ }
+ }
+ break;
+ }
+ case NormalizedByteCode.__aload:
+ {
+ string type = ma.GetLocalType(i, instr.NormalizedArg1);
+ if(type == "Lnull")
+ {
+ // if the local is known to be null, we just emit a null
+ ilGenerator.Emit(OpCodes.Ldnull);
+ }
+ else if(type[0] == 'N')
+ {
+ // since new objects aren't represented on the stack, we don't need to do anything here
+ }
+ else if(type[0] == 'U')
+ {
+ // any unitialized reference has to be the this reference
+ // TODO when we get support for overwriting the this reference, this code
+ // needs to be aware of that (or, this overwriting should be handled specially for <init>)
+ ilGenerator.Emit(OpCodes.Ldarg_0);
+ }
+ else
+ {
+ Load(instr, typeof(object));
+ if(instr.NormalizedArg1 >= m.ArgMap.Length)
+ {
+ // HACK since, for now, all locals are of type object, we've got to cast them to the proper type
+ // UPDATE the above is no longer true, we now have at least some idea of the type of the local
+ if(type != ma.GetDeclaredLocalType(instr.NormalizedArg1))
+ {
+ // TODO handle class not found
+ ilGenerator.Emit(OpCodes.Castclass, classLoader.ExpressionType(ma.GetLocalType(i, instr.NormalizedArg1)));
+ }
+ }
+ }
+ break;
+ }
+ case NormalizedByteCode.__astore:
+ {
+ string type = ma.GetRawStackType(i, 0);
+ // HACK we use "int" to track the return address of a jsr
+ if(type.StartsWith("Lret;"))
+ {
+ Store(instr, typeof(int));
+ }
+ else if(type[0] == 'N')
+ {
+ // NOTE new objects aren't really on the stack, so we can't copy them into the local.
+ // We do store a null in the local, to prevent it from retaining an unintentional reference
+ // to whatever object reference happens to be there
+ ilGenerator.Emit(OpCodes.Ldnull);
+ Store(instr, typeof(object));
+ }
+ else if(type[0] == 'U')
+ {
+ // any unitialized reference, is always the this reference, we don't store anything
+ // here (because CLR wont allow unitialized references in locals) and then when
+ // the unitialized ref is loaded we redirect to the this reference
+ ilGenerator.Emit(OpCodes.Pop);
+ }
+ else
+ {
+ Store(instr, typeof(object));
+ }
+ break;
+ }
+ case NormalizedByteCode.__iload:
+ Load(instr, typeof(int));
+ break;
+ case NormalizedByteCode.__istore:
+ Store(instr, typeof(int));
+ break;
+ case NormalizedByteCode.__lload:
+ Load(instr, typeof(long));
+ break;
+ case NormalizedByteCode.__lstore:
+ Store(instr, typeof(long));
+ break;
+ case NormalizedByteCode.__fload:
+ Load(instr, typeof(float));
+ break;
+ case NormalizedByteCode.__fstore:
+ Store(instr, typeof(float));
+ break;
+ case NormalizedByteCode.__dload:
+ Load(instr, typeof(double));
+ break;
+ case NormalizedByteCode.__dstore:
+ Store(instr, typeof(double));
+ break;
+ case NormalizedByteCode.__new:
+ {
+ TypeWrapper wrapper = LoadClass(instr.MethodCode.Method.ClassFile.GetConstantPoolClass(instr.Arg1));
+ if(wrapper != null && (wrapper.IsAbstract || wrapper.IsInterface))
+ {
+ EmitError("java.lang.InstantiationError", wrapper.Name);
+ }
+ // we don't do anything here, the call to <init> will be converted into a newobj instruction
+ break;
+ }
+ case NormalizedByteCode.__multianewarray:
+ {
+ TypeWrapper wrapper = LoadClass(instr.MethodCode.Method.ClassFile.GetConstantPoolClass(instr.Arg1));
+ if(wrapper != null)
+ {
+ LocalBuilder localArray = ilGenerator.DeclareLocal(typeof(int[]));
+ LocalBuilder localInt = ilGenerator.DeclareLocal(typeof(int));
+ ilGenerator.Emit(OpCodes.Ldc_I4, instr.Arg2);
+ ilGenerator.Emit(OpCodes.Newarr, typeof(int));
+ ilGenerator.Emit(OpCodes.Stloc, localArray);
+ for(int j = 1; j <= instr.Arg2; j++)
+ {
+ ilGenerator.Emit(OpCodes.Stloc, localInt);
+ ilGenerator.Emit(OpCodes.Ldloc, localArray);
+ ilGenerator.Emit(OpCodes.Ldc_I4, instr.Arg2 - j);
+ ilGenerator.Emit(OpCodes.Ldloc, localInt);
+ ilGenerator.Emit(OpCodes.Stelem_I4);
+ }
+ Type type = wrapper.Type;
+ ilGenerator.Emit(OpCodes.Ldtoken, type);
+ ilGenerator.Emit(OpCodes.Ldloc, localArray);
+ ilGenerator.Emit(OpCodes.Call, multiANewArrayMethod);
+ ilGenerator.Emit(OpCodes.Castclass, type);
+ }
+ break;
+ }
+ case NormalizedByteCode.__anewarray:
+ {
+ TypeWrapper wrapper = LoadClass(instr.MethodCode.Method.ClassFile.GetConstantPoolClass(instr.Arg1));
+ if(wrapper != null)
+ {
+ ilGenerator.Emit(OpCodes.Newarr, wrapper.Type);
+ }
+ break;
+ }
+ case NormalizedByteCode.__newarray:
+ switch(instr.Arg1)
+ {
+ case 4:
+ ilGenerator.Emit(OpCodes.Newarr, typeof(bool));
+ break;
+ case 5:
+ ilGenerator.Emit(OpCodes.Newarr, typeof(char));
+ break;
+ case 6:
+ ilGenerator.Emit(OpCodes.Newarr, typeof(float));
+ break;
+ case 7:
+ ilGenerator.Emit(OpCodes.Newarr, typeof(double));
+ break;
+ case 8:
+ ilGenerator.Emit(OpCodes.Newarr, typeof(sbyte));
+ break;
+ case 9:
+ ilGenerator.Emit(OpCodes.Newarr, typeof(short));
+ break;
+ case 10:
+ ilGenerator.Emit(OpCodes.Newarr, typeof(int));
+ break;
+ case 11:
+ ilGenerator.Emit(OpCodes.Newarr, typeof(long));
+ break;
+ default:
+ throw new InvalidOperationException();
+ }
+ break;
+ case NormalizedByteCode.__checkcast:
+ {
+ TypeWrapper wrapper = LoadClass(instr.MethodCode.Method.ClassFile.GetConstantPoolClass(instr.Arg1));
+ if(wrapper != null)
+ {
+ ilGenerator.Emit(OpCodes.Castclass, wrapper.Type);
+ }
+ break;
+ }
+ case NormalizedByteCode.__instanceof:
+ {
+ TypeWrapper wrapper = LoadClass(instr.MethodCode.Method.ClassFile.GetConstantPoolClass(instr.Arg1));
+ if(wrapper != null)
+ {
+ ilGenerator.Emit(OpCodes.Isinst, wrapper.Type);
+ ilGenerator.Emit(OpCodes.Ldnull);
+ ilGenerator.Emit(OpCodes.Ceq);
+ ilGenerator.Emit(OpCodes.Ldc_I4_0);
+ ilGenerator.Emit(OpCodes.Ceq);
+ }
+ break;
+ }
+ case NormalizedByteCode.__aaload:
+ ilGenerator.Emit(OpCodes.Ldelem_Ref);
+ break;
+ case NormalizedByteCode.__baload:
+ // NOTE both the JVM and the CLR use signed bytes for boolean arrays (how convenient!)
+ ilGenerator.Emit(OpCodes.Ldelem_I1);
+ break;
+ case NormalizedByteCode.__bastore:
+ ilGenerator.Emit(OpCodes.Stelem_I1);
+ break;
+ case NormalizedByteCode.__caload:
+ ilGenerator.Emit(OpCodes.Ldelem_U2);
+ break;
+ case NormalizedByteCode.__castore:
+ ilGenerator.Emit(OpCodes.Stelem_I2);
+ break;
+ case NormalizedByteCode.__saload:
+ ilGenerator.Emit(OpCodes.Ldelem_I2);
+ break;
+ case NormalizedByteCode.__sastore:
+ ilGenerator.Emit(OpCodes.Stelem_I2);
+ break;
+ case NormalizedByteCode.__iaload:
+ ilGenerator.Emit(OpCodes.Ldelem_I4);
+ break;
+ case NormalizedByteCode.__iastore:
+ ilGenerator.Emit(OpCodes.Stelem_I4);
+ break;
+ case NormalizedByteCode.__laload:
+ ilGenerator.Emit(OpCodes.Ldelem_I8);
+ break;
+ case NormalizedByteCode.__lastore:
+ ilGenerator.Emit(OpCodes.Stelem_I8);
+ break;
+ case NormalizedByteCode.__faload:
+ ilGenerator.Emit(OpCodes.Ldelem_R4);
+ break;
+ case NormalizedByteCode.__fastore:
+ ilGenerator.Emit(OpCodes.Stelem_R4);
+ break;
+ case NormalizedByteCode.__daload:
+ ilGenerator.Emit(OpCodes.Ldelem_R8);
+ break;
+ case NormalizedByteCode.__dastore:
+ ilGenerator.Emit(OpCodes.Stelem_R8);
+ break;
+ case NormalizedByteCode.__aastore:
+ ilGenerator.Emit(OpCodes.Stelem_Ref);
+ break;
+ case NormalizedByteCode.__arraylength:
+ ilGenerator.Emit(OpCodes.Ldlen);
+ break;
+ case NormalizedByteCode.__lcmp:
+ {
+ LocalBuilder value1 = ilGenerator.DeclareLocal(typeof(long));
+ LocalBuilder value2 = ilGenerator.DeclareLocal(typeof(long));
+ ilGenerator.Emit(OpCodes.Stloc, value2);
+ ilGenerator.Emit(OpCodes.Stloc, value1);
+ ilGenerator.Emit(OpCodes.Ldloc, value1);
+ ilGenerator.Emit(OpCodes.Ldloc, value2);
+ Label res1 = ilGenerator.DefineLabel();
+ ilGenerator.Emit(OpCodes.Bgt_S, res1);
+ ilGenerator.Emit(OpCodes.Ldloc, value1);
+ ilGenerator.Emit(OpCodes.Ldloc, value2);
+ Label res0 = ilGenerator.DefineLabel();
+ ilGenerator.Emit(OpCodes.Beq_S, res0);
+ ilGenerator.Emit(OpCodes.Ldc_I4_M1);
+ Label end = ilGenerator.DefineLabel();
+ ilGenerator.Emit(OpCodes.Br_S, end);
+ ilGenerator.MarkLabel(res1);
+ ilGenerator.Emit(OpCodes.Ldc_I4_1);
+ ilGenerator.Emit(OpCodes.Br_S, end);
+ ilGenerator.MarkLabel(res0);
+ ilGenerator.Emit(OpCodes.Ldc_I4_0);
+ ilGenerator.MarkLabel(end);
+ break;
+ }
+ case NormalizedByteCode.__fcmpl:
+ {
+ LocalBuilder value1 = ilGenerator.DeclareLocal(typeof(float));
+ LocalBuilder value2 = ilGenerator.DeclareLocal(typeof(float));
+ ilGenerator.Emit(OpCodes.Stloc, value2);
+ ilGenerator.Emit(OpCodes.Stloc, value1);
+ ilGenerator.Emit(OpCodes.Ldloc, value1);
+ ilGenerator.Emit(OpCodes.Ldloc, value2);
+ Label res1 = ilGenerator.DefineLabel();
+ ilGenerator.Emit(OpCodes.Bgt_S, res1);
+ ilGenerator.Emit(OpCodes.Ldloc, value1);
+ ilGenerator.Emit(OpCodes.Ldloc, value2);
+ Label res0 = ilGenerator.DefineLabel();
+ ilGenerator.Emit(OpCodes.Beq_S, res0);
+ ilGenerator.Emit(OpCodes.Ldc_I4_M1);
+ Label end = ilGenerator.DefineLabel();
+ ilGenerator.Emit(OpCodes.Br_S, end);
+ ilGenerator.MarkLabel(res1);
+ ilGenerator.Emit(OpCodes.Ldc_I4_1);
+ ilGenerator.Emit(OpCodes.Br_S, end);
+ ilGenerator.MarkLabel(res0);
+ ilGenerator.Emit(OpCodes.Ldc_I4_0);
+ ilGenerator.MarkLabel(end);
+ break;
+ }
+ case NormalizedByteCode.__fcmpg:
+ {
+ LocalBuilder value1 = ilGenerator.DeclareLocal(typeof(float));
+ LocalBuilder value2 = ilGenerator.DeclareLocal(typeof(float));
+ ilGenerator.Emit(OpCodes.Stloc, value2);
+ ilGenerator.Emit(OpCodes.Stloc, value1);
+ ilGenerator.Emit(OpCodes.Ldloc, value1);
+ ilGenerator.Emit(OpCodes.Ldloc, value2);
+ Label resm1 = ilGenerator.DefineLabel();
+ ilGenerator.Emit(OpCodes.Blt_S, resm1);
+ ilGenerator.Emit(OpCodes.Ldloc, value1);
+ ilGenerator.Emit(OpCodes.Ldloc, value2);
+ Label res0 = ilGenerator.DefineLabel();
+ ilGenerator.Emit(OpCodes.Beq_S, res0);
+ ilGenerator.Emit(OpCodes.Ldc_I4_1);
+ Label end = ilGenerator.DefineLabel();
+ ilGenerator.Emit(OpCodes.Br_S, end);
+ ilGenerator.MarkLabel(resm1);
+ ilGenerator.Emit(OpCodes.Ldc_I4_M1);
+ ilGenerator.Emit(OpCodes.Br_S, end);
+ ilGenerator.MarkLabel(res0);
+ ilGenerator.Emit(OpCodes.Ldc_I4_0);
+ ilGenerator.MarkLabel(end);
+ break;
+ }
+ case NormalizedByteCode.__dcmpl:
+ {
+ LocalBuilder value1 = ilGenerator.DeclareLocal(typeof(double));
+ LocalBuilder value2 = ilGenerator.DeclareLocal(typeof(double));
+ ilGenerator.Emit(OpCodes.Stloc, value2);
+ ilGenerator.Emit(OpCodes.Stloc, value1);
+ ilGenerator.Emit(OpCodes.Ldloc, value1);
+ ilGenerator.Emit(OpCodes.Ldloc, value2);
+ Label res1 = ilGenerator.DefineLabel();
+ ilGenerator.Emit(OpCodes.Bgt_S, res1);
+ ilGenerator.Emit(OpCodes.Ldloc, value1);
+ ilGenerator.Emit(OpCodes.Ldloc, value2);
+ Label res0 = ilGenerator.DefineLabel();
+ ilGenerator.Emit(OpCodes.Beq_S, res0);
+ ilGenerator.Emit(OpCodes.Ldc_I4_M1);
+ Label end = ilGenerator.DefineLabel();
+ ilGenerator.Emit(OpCodes.Br_S, end);
+ ilGenerator.MarkLabel(res1);
+ ilGenerator.Emit(OpCodes.Ldc_I4_1);
+ ilGenerator.Emit(OpCodes.Br_S, end);
+ ilGenerator.MarkLabel(res0);
+ ilGenerator.Emit(OpCodes.Ldc_I4_0);
+ ilGenerator.MarkLabel(end);
+ break;
+ }
+ case NormalizedByteCode.__dcmpg:
+ {
+ LocalBuilder value1 = ilGenerator.DeclareLocal(typeof(double));
+ LocalBuilder value2 = ilGenerator.DeclareLocal(typeof(double));
+ ilGenerator.Emit(OpCodes.Stloc, value2);
+ ilGenerator.Emit(OpCodes.Stloc, value1);
+ ilGenerator.Emit(OpCodes.Ldloc, value1);
+ ilGenerator.Emit(OpCodes.Ldloc, value2);
+ Label resm1 = ilGenerator.DefineLabel();
+ ilGenerator.Emit(OpCodes.Blt, resm1);
+ ilGenerator.Emit(OpCodes.Ldloc, value1);
+ ilGenerator.Emit(OpCodes.Ldloc, value2);
+ Label res0 = ilGenerator.DefineLabel();
+ ilGenerator.Emit(OpCodes.Beq, res0);
+ ilGenerator.Emit(OpCodes.Ldc_I4_1);
+ Label end = ilGenerator.DefineLabel();
+ ilGenerator.Emit(OpCodes.Br, end);
+ ilGenerator.MarkLabel(resm1);
+ ilGenerator.Emit(OpCodes.Ldc_I4, -1);
+ ilGenerator.Emit(OpCodes.Br, end);
+ ilGenerator.MarkLabel(res0);
+ ilGenerator.Emit(OpCodes.Ldc_I4_0);
+ ilGenerator.MarkLabel(end);
+ break;
+ }
+ case NormalizedByteCode.__if_icmpeq:
+ ilGenerator.Emit(OpCodes.Beq, GetLabel(labels, instr.PC + instr.Arg1, inuse, rangeBegin, rangeEnd, exits));
+ break;
+ case NormalizedByteCode.__if_icmpne:
+ ilGenerator.Emit(OpCodes.Bne_Un, GetLabel(labels, instr.PC + instr.Arg1, inuse, rangeBegin, rangeEnd, exits));
+ break;
+ case NormalizedByteCode.__if_icmple:
+ ilGenerator.Emit(OpCodes.Ble, GetLabel(labels, instr.PC + instr.Arg1, inuse, rangeBegin, rangeEnd, exits));
+ break;
+ case NormalizedByteCode.__if_icmplt:
+ ilGenerator.Emit(OpCodes.Blt, GetLabel(labels, instr.PC + instr.Arg1, inuse, rangeBegin, rangeEnd, exits));
+ break;
+ case NormalizedByteCode.__if_icmpge:
+ ilGenerator.Emit(OpCodes.Bge, GetLabel(labels, instr.PC + instr.Arg1, inuse, rangeBegin, rangeEnd, exits));
+ break;
+ case NormalizedByteCode.__if_icmpgt:
+ ilGenerator.Emit(OpCodes.Bgt, GetLabel(labels, instr.PC + instr.Arg1, inuse, rangeBegin, rangeEnd, exits));
+ break;
+ case NormalizedByteCode.__ifle:
+ ilGenerator.Emit(OpCodes.Ldc_I4_0);
+ ilGenerator.Emit(OpCodes.Ble, GetLabel(labels, instr.PC + instr.Arg1, inuse, rangeBegin, rangeEnd, exits));
+ break;
+ case NormalizedByteCode.__iflt:
+ ilGenerator.Emit(OpCodes.Ldc_I4_0);
+ ilGenerator.Emit(OpCodes.Blt, GetLabel(labels, instr.PC + instr.Arg1, inuse, rangeBegin, rangeEnd, exits));
+ break;
+ case NormalizedByteCode.__ifge:
+ ilGenerator.Emit(OpCodes.Ldc_I4_0);
+ ilGenerator.Emit(OpCodes.Bge, GetLabel(labels, instr.PC + instr.Arg1, inuse, rangeBegin, rangeEnd, exits));
+ break;
+ case NormalizedByteCode.__ifgt:
+ ilGenerator.Emit(OpCodes.Ldc_I4_0);
+ ilGenerator.Emit(OpCodes.Bgt, GetLabel(labels, instr.PC + instr.Arg1, inuse, rangeBegin, rangeEnd, exits));
+ break;
+ case NormalizedByteCode.__ifne:
+ ilGenerator.Emit(OpCodes.Ldc_I4_0);
+ ilGenerator.Emit(OpCodes.Bne_Un, GetLabel(labels, instr.PC + instr.Arg1, inuse, rangeBegin, rangeEnd, exits));
+ break;
+ case NormalizedByteCode.__ifeq:
+ ilGenerator.Emit(OpCodes.Ldc_I4_0);
+ ilGenerator.Emit(OpCodes.Beq, GetLabel(labels, instr.PC + instr.Arg1, inuse, rangeBegin, rangeEnd, exits));
+ break;
+ case NormalizedByteCode.__ifnonnull:
+ ilGenerator.Emit(OpCodes.Brtrue, GetLabel(labels, instr.PC + instr.Arg1, inuse, rangeBegin, rangeEnd, exits));
+ break;
+ case NormalizedByteCode.__ifnull:
+ ilGenerator.Emit(OpCodes.Brfalse, GetLabel(labels, instr.PC + instr.Arg1, inuse, rangeBegin, rangeEnd, exits));
+ break;
+ case NormalizedByteCode.__if_acmpeq:
+ ilGenerator.Emit(OpCodes.Beq, GetLabel(labels, instr.PC + instr.Arg1, inuse, rangeBegin, rangeEnd, exits));
+ break;
+ case NormalizedByteCode.__if_acmpne:
+ ilGenerator.Emit(OpCodes.Bne_Un, GetLabel(labels, instr.PC + instr.Arg1, inuse, rangeBegin, rangeEnd, exits));
+ break;
+ case NormalizedByteCode.__goto:
+ ilGenerator.Emit(OpCodes.Br, GetLabel(labels, instr.PC + instr.Arg1, inuse, rangeBegin, rangeEnd, exits));
+ break;
+ case NormalizedByteCode.__ineg:
+ case NormalizedByteCode.__lneg:
+ case NormalizedByteCode.__fneg:
+ case NormalizedByteCode.__dneg:
+ ilGenerator.Emit(OpCodes.Neg);
+ break;
+ case NormalizedByteCode.__iadd:
+ case NormalizedByteCode.__ladd:
+ case NormalizedByteCode.__fadd:
+ case NormalizedByteCode.__dadd:
+ ilGenerator.Emit(OpCodes.Add);
+ break;
+ case NormalizedByteCode.__isub:
+ case NormalizedByteCode.__lsub:
+ case NormalizedByteCode.__fsub:
+ case NormalizedByteCode.__dsub:
+ ilGenerator.Emit(OpCodes.Sub);
+ break;
+ case NormalizedByteCode.__ixor:
+ case NormalizedByteCode.__lxor:
+ ilGenerator.Emit(OpCodes.Xor);
+ break;
+ case NormalizedByteCode.__ior:
+ case NormalizedByteCode.__lor:
+ ilGenerator.Emit(OpCodes.Or);
+ break;
+ case NormalizedByteCode.__iand:
+ case NormalizedByteCode.__land:
+ ilGenerator.Emit(OpCodes.And);
+ break;
+ case NormalizedByteCode.__imul:
+ case NormalizedByteCode.__lmul:
+ case NormalizedByteCode.__fmul:
+ case NormalizedByteCode.__dmul:
+ ilGenerator.Emit(OpCodes.Mul);
+ break;
+ case NormalizedByteCode.__idiv:
+ case NormalizedByteCode.__ldiv:
+ {
+ // we need to special case dividing by -1, because the CLR div instruction
+ // throws an OverflowException when dividing Int32.MinValue by -1, and
+ // Java just silently overflows
+ ilGenerator.Emit(OpCodes.Dup);
+ ilGenerator.Emit(OpCodes.Ldc_I4_M1);
+ if(instr.NormalizedOpCode == NormalizedByteCode.__ldiv)
+ {
+ ilGenerator.Emit(OpCodes.Conv_I8);
+ }
+ Label label = ilGenerator.DefineLabel();
+ ilGenerator.Emit(OpCodes.Bne_Un_S, label);
+ ilGenerator.Emit(OpCodes.Pop);
+ ilGenerator.Emit(OpCodes.Neg);
+ Label label2 = ilGenerator.DefineLabel();
+ ilGenerator.Emit(OpCodes.Br_S, label2);
+ ilGenerator.MarkLabel(label);
+ ilGenerator.Emit(OpCodes.Div);
+ ilGenerator.MarkLabel(label2);
+ break;
+ }
+ case NormalizedByteCode.__fdiv:
+ case NormalizedByteCode.__ddiv:
+ ilGenerator.Emit(OpCodes.Div);
+ break;
+ case NormalizedByteCode.__irem:
+ case NormalizedByteCode.__lrem:
+ {
+ // we need to special case taking the remainder of dividing by -1,
+ // because the CLR rem instruction throws an OverflowException when
+ // taking the remainder of dividing Int32.MinValue by -1, and
+ // Java just silently overflows
+ ilGenerator.Emit(OpCodes.Dup);
+ ilGenerator.Emit(OpCodes.Ldc_I4_M1);
+ if(instr.NormalizedOpCode == NormalizedByteCode.__lrem)
+ {
+ ilGenerator.Emit(OpCodes.Conv_I8);
+ }
+ Label label = ilGenerator.DefineLabel();
+ ilGenerator.Emit(OpCodes.Bne_Un_S, label);
+ ilGenerator.Emit(OpCodes.Pop);
+ ilGenerator.Emit(OpCodes.Pop);
+ ilGenerator.Emit(OpCodes.Ldc_I4_0);
+ if(instr.NormalizedOpCode == NormalizedByteCode.__lrem)
+ {
+ ilGenerator.Emit(OpCodes.Conv_I8);
+ }
+ Label label2 = ilGenerator.DefineLabel();
+ ilGenerator.Emit(OpCodes.Br_S, label2);
+ ilGenerator.MarkLabel(label);
+ ilGenerator.Emit(OpCodes.Rem);
+ ilGenerator.MarkLabel(label2);
+ break;
+ }
+ case NormalizedByteCode.__frem:
+ case NormalizedByteCode.__drem:
+ ilGenerator.Emit(OpCodes.Rem);
+ break;
+ case NormalizedByteCode.__ishl:
+ case NormalizedByteCode.__lshl:
+ ilGenerator.Emit(OpCodes.Shl);
+ break;
+ case NormalizedByteCode.__iushr:
+ case NormalizedByteCode.__lushr:
+ ilGenerator.Emit(OpCodes.Shr_Un);
+ break;
+ case NormalizedByteCode.__ishr:
+ case NormalizedByteCode.__lshr:
+ ilGenerator.Emit(OpCodes.Shr);
+ break;
+ case NormalizedByteCode.__swap:
+ new DupHelper(classLoader, ilGenerator, 2)
+ .SetType(0, ma.GetRawStackType(i, 0))
+ .SetType(1, ma.GetRawStackType(i, 1))
+ .Store(0)
+ .Store(1)
+ .Load(0)
+ .Load(1);
+ break;
+ case NormalizedByteCode.__dup:
+ // if the TOS contains a "new" object, it isn't really there, so we wont dup it either
+ if(ma.GetRawStackType(i, 0)[0] != 'N')
+ {
+ ilGenerator.Emit(OpCodes.Dup);
+ }
+ break;
+ case NormalizedByteCode.__dup2:
+ {
+ string type1 = ma.GetRawStackType(i, 0);
+ if(type1 == "D" || type1 == "J")
+ {
+ ilGenerator.Emit(OpCodes.Dup);
+ }
+ else
+ {
+ new DupHelper(classLoader, ilGenerator, 2)
+ .SetType(0, type1)
+ .SetType(1, ma.GetRawStackType(i, 1))
+ .Store(0)
+ .Store(1)
+ .Load(1)
+ .Load(0)
+ .Load(1)
+ .Load(0);
+ }
+ break;
+ }
+ case NormalizedByteCode.__dup_x1:
+ new DupHelper(classLoader, ilGenerator, 2)
+ .SetType(0, ma.GetRawStackType(i, 0))
+ .SetType(1, ma.GetRawStackType(i, 1))
+ .Store(0)
+ .Store(1)
+ .Load(0)
+ .Load(1)
+ .Load(0);
+ break;
+ case NormalizedByteCode.__dup2_x1:
+ {
+ string type1 = ma.GetRawStackType(i, 0);
+ if(type1 == "D" || type1 == "J")
+ {
+ new DupHelper(classLoader, ilGenerator, 2)
+ .SetType(0, type1)
+ .SetType(1, ma.GetRawStackType(i, 1))
+ .Store(0)
+ .Store(1)
+ .Load(0)
+ .Load(1)
+ .Load(0);
+ }
+ else
+ {
+ new DupHelper(classLoader, ilGenerator, 3)
+ .SetType(0, type1)
+ .SetType(1, ma.GetRawStackType(i, 1))
+ .SetType(2, ma.GetRawStackType(i, 2))
+ .Store(0)
+ .Store(1)
+ .Store(2)
+ .Load(1)
+ .Load(0)
+ .Load(2)
+ .Load(1)
+ .Load(0);
+ }
+ break;
+ }
+ case NormalizedByteCode.__dup2_x2:
+ {
+ string type1 = ma.GetRawStackType(i, 0);
+ string type2 = ma.GetRawStackType(i, 1);
+ if(type1 == "D" || type1 == "J")
+ {
+ if(type2 == "D" || type2 == "J")
+ {
+ // Form 4
+ new DupHelper(classLoader, ilGenerator, 2)
+ .SetType(0, type1)
+ .SetType(1, type2)
+ .Store(0)
+ .Store(1)
+ .Load(0)
+ .Load(1)
+ .Load(0);
+ }
+ else
+ {
+ // Form 2
+ new DupHelper(classLoader, ilGenerator, 3)
+ .SetType(0, type1)
+ .SetType(1, type2)
+ .SetType(2, ma.GetRawStackType(i, 2))
+ .Store(0)
+ .Store(1)
+ .Store(2)
+ .Load(0)
+ .Load(2)
+ .Load(1)
+ .Load(0);
+ }
+ }
+ else
+ {
+ string type3 = ma.GetRawStackType(i, 2);
+ if(type3 == "D" || type3 == "J")
+ {
+ // Form 3
+ new DupHelper(classLoader, ilGenerator, 3)
+ .SetType(0, type1)
+ .SetType(1, type2)
+ .SetType(2, type3)
+ .Store(0)
+ .Store(1)
+ .Store(2)
+ .Load(1)
+ .Load(0)
+ .Load(2)
+ .Load(1)
+ .Load(0);
+ }
+ else
+ {
+ // Form 1
+ new DupHelper(classLoader, ilGenerator, 4)
+ .SetType(0, type1)
+ .SetType(1, type2)
+ .SetType(2, type3)
+ .SetType(3, ma.GetRawStackType(i, 3))
+ .Store(0)
+ .Store(1)
+ .Store(2)
+ .Store(3)
+ .Load(1)
+ .Load(0)
+ .Load(3)
+ .Load(2)
+ .Load(1)
+ .Load(0);
+ }
+ }
+ break;
+ }
+ case NormalizedByteCode.__dup_x2:
+ new DupHelper(classLoader, ilGenerator, 3)
+ .SetType(0, ma.GetRawStackType(i, 0))
+ .SetType(1, ma.GetRawStackType(i, 1))
+ .SetType(2, ma.GetRawStackType(i, 2))
+ .Store(0)
+ .Store(1)
+ .Store(2)
+ .Load(0)
+ .Load(2)
+ .Load(1)
+ .Load(0);
+ break;
+ case NormalizedByteCode.__pop2:
+ {
+ string type1 = ma.GetRawStackType(i, 0);
+ if(type1 == "D" || type1 == "J")
+ {
+ ilGenerator.Emit(OpCodes.Pop);
+ }
+ else
+ {
+ if(type1[0] != 'N')
+ {
+ ilGenerator.Emit(OpCodes.Pop);
+ }
+ if(ma.GetRawStackType(i, 1)[0] != 'N')
+ {
+ ilGenerator.Emit(OpCodes.Pop);
+ }
+ }
+ break;
+ }
+ case NormalizedByteCode.__pop:
+ // if the TOS is a new object, it isn't really there, so we don't need to pop it
+ if(ma.GetRawStackType(i, 0)[0] != 'N')
+ {
+ ilGenerator.Emit(OpCodes.Pop);
+ }
+ break;
+ case NormalizedByteCode.__monitorenter:
+ ilGenerator.Emit(OpCodes.Call, monitorEnterMethod);
+ break;
+ case NormalizedByteCode.__monitorexit:
+ ilGenerator.Emit(OpCodes.Call, monitorExitMethod);
+ break;
+ case NormalizedByteCode.__athrow:
+ ilGenerator.Emit(OpCodes.Throw);
+ break;
+ case NormalizedByteCode.__lookupswitch:
+ // TODO use OpCodes.Switch
+ for(int j = 0; j < instr.Values.Length; j++)
+ {
+ ilGenerator.Emit(OpCodes.Dup);
+ ilGenerator.Emit(OpCodes.Ldc_I4, instr.Values[j]);
+ Label label = ilGenerator.DefineLabel();
+ ilGenerator.Emit(OpCodes.Bne_Un, label);
+ ilGenerator.Emit(OpCodes.Pop);
+ ilGenerator.Emit(OpCodes.Br, GetLabel(labels, instr.PC + instr.TargetOffsets[j], inuse, rangeBegin, rangeEnd, exits));
+ ilGenerator.MarkLabel(label);
+ }
+ ilGenerator.Emit(OpCodes.Pop);
+ ilGenerator.Emit(OpCodes.Br, GetLabel(labels, instr.PC + instr.DefaultOffset, inuse, rangeBegin, rangeEnd, exits));
+ break;
+ case NormalizedByteCode.__iinc:
+ Load(instr, typeof(int));
+ ilGenerator.Emit(OpCodes.Ldc_I4, instr.Arg2);
+ ilGenerator.Emit(OpCodes.Add);
+ Store(instr, typeof(int));
+ break;
+ case NormalizedByteCode.__i2b:
+ ilGenerator.Emit(OpCodes.Conv_I1);
+ break;
+ case NormalizedByteCode.__i2c:
+ ilGenerator.Emit(OpCodes.Conv_U2);
+ break;
+ case NormalizedByteCode.__i2s:
+ ilGenerator.Emit(OpCodes.Conv_I2);
+ break;
+ case NormalizedByteCode.__l2i:
+ case NormalizedByteCode.__f2i:
+ case NormalizedByteCode.__d2i:
+ ilGenerator.Emit(OpCodes.Conv_I4);
+ break;
+ case NormalizedByteCode.__i2l:
+ case NormalizedByteCode.__f2l:
+ case NormalizedByteCode.__d2l:
+ ilGenerator.Emit(OpCodes.Conv_I8);
+ break;
+ case NormalizedByteCode.__i2f:
+ case NormalizedByteCode.__l2f:
+ case NormalizedByteCode.__d2f:
+ ilGenerator.Emit(OpCodes.Conv_R4);
+ break;
+ case NormalizedByteCode.__i2d:
+ case NormalizedByteCode.__l2d:
+ case NormalizedByteCode.__f2d:
+ ilGenerator.Emit(OpCodes.Conv_R8);
+ break;
+ case NormalizedByteCode.__jsr:
+ {
+ int index = FindPcIndex(instr.PC + instr.Arg1);
+ int[] callsites = ma.GetCallSites(index);
+ for(int j = 0; j < callsites.Length; j++)
+ {
+ if(callsites[j] == i)
+ {
+ ilGenerator.Emit(OpCodes.Ldc_I4, j);
+ break;
+ }
+ }
+ ilGenerator.Emit(OpCodes.Br, GetLabel(labels, instr.PC + instr.Arg1, inuse, rangeBegin, rangeEnd, exits));
+ break;
+ }
+ case NormalizedByteCode.__ret:
+ {
+ // NOTE using a OpCodes.Switch here is not efficient, because 99 out of a 100 cases
+ // there are either one or two call sites.
+ string subid = ma.GetLocalType(i, instr.Arg1);
+ int[] callsites = ma.GetCallSites(int.Parse(subid.Substring("Lret;".Length)));
+ for(int j = 0; j < callsites.Length - 1; j++)
+ {
+ Load(instr, typeof(int));
+ ilGenerator.Emit(OpCodes.Ldc_I4, j);
+ ilGenerator.Emit(OpCodes.Beq, GetLabel(labels, m.Instructions[callsites[j] + 1].PC, inuse, rangeBegin, rangeEnd, exits));
+ }
+ ilGenerator.Emit(OpCodes.Br, GetLabel(labels, m.Instructions[callsites[callsites.Length - 1] + 1].PC, inuse, rangeBegin, rangeEnd, exits));
+ break;
+ }
+ case NormalizedByteCode.__nop:
+ ilGenerator.Emit(OpCodes.Nop);
+ break;
+ default:
+ throw new NotImplementedException(instr.NormalizedOpCode.ToString());
+ }
+ // mark next instruction as inuse
+ switch(instr.NormalizedOpCode)
+ {
+ case NormalizedByteCode.__lookupswitch:
+ case NormalizedByteCode.__goto:
+ case NormalizedByteCode.__jsr:
+ case NormalizedByteCode.__ret:
+ case NormalizedByteCode.__ireturn:
+ case NormalizedByteCode.__lreturn:
+ case NormalizedByteCode.__freturn:
+ case NormalizedByteCode.__dreturn:
+ case NormalizedByteCode.__areturn:
+ case NormalizedByteCode.__return:
+ case NormalizedByteCode.__athrow:
+ break;
+ default:
+ // don't fall through end of try block
+ if(m.Instructions[i + 1].PC == rangeEnd)
+ {
+ ilGenerator.Emit(OpCodes.Br, GetLabel(labels, m.Instructions[i + 1].PC, inuse, rangeBegin, rangeEnd, exits));
+ }
+ else
+ {
+ inuse[i + 1] = true;
+ if(done[i + 1])
+ {
+ // since we've already processed the code that is supposed to come next, we have
+ // to emit a branch to it
+ ilGenerator.Emit(OpCodes.Br, GetLabel(labels, m.Instructions[i + 1].PC, inuse, rangeBegin, rangeEnd, exits));
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ private FieldWrapper GetField(ClassFile.ConstantPoolItemFieldref cpi, bool isStatic, TypeWrapper thisType, bool write)
+ {
+ TypeWrapper wrapper = LoadClass(cpi.Class);
+ if(wrapper != null)
+ {
+ FieldWrapper field = wrapper.GetFieldWrapper(cpi.Name);
+ if(field != null)
+ {
+ if(field.IsStatic == isStatic)
+ {
+ if(field.IsPublic ||
+ (field.IsProtected && (isStatic ? clazz.IsSubTypeOf(field.DeclaringType) : clazz.IsSubTypeOf(thisType))) ||
+ (field.IsPrivate && clazz == wrapper) ||
+ (!(field.IsPublic || field.IsPrivate) && clazz.IsInSamePackageAs(field.DeclaringType)))
+ {
+ // are we trying to mutate a final field (they are read-only from outside of the defining class)
+ if(write && field.IsFinal && (isStatic ? clazz != wrapper : clazz != thisType))
+ {
+ EmitError("java.lang.IllegalAccessError", "Field " + cpi.Class + "." + cpi.Name + " is final");
+ }
+ else
+ {
+ return field;
+ }
+ }
+ else
+ {
+ EmitError("java.lang.IllegalAccessError", "Try to access field " + cpi.Class + "." + cpi.Name + " from class " + clazz.Name);
+ }
+ }
+ else
+ {
+ EmitError("java.lang.IncompatibleClassChangeError", null);
+ }
+ }
+ else
+ {
+ EmitError("java.lang.NoSuchFieldError", cpi.Class + "." + cpi.Name);
+ }
+ }
+ return null;
+ }
+
+ private static MethodWrapper GetInterfaceMethod(TypeWrapper wrapper, MethodDescriptor md)
+ {
+ MethodWrapper method = wrapper.GetMethodWrapper(md, false);
+ if(method != null)
+ {
+ return method;
+ }
+ TypeWrapper[] interfaces = wrapper.Interfaces;
+ for(int i = 0; i < interfaces.Length; i++)
+ {
+ method = GetInterfaceMethod(interfaces[i], md);
+ if(method != null)
+ {
+ return method;
+ }
+ }
+ return null;
+ }
+
+ private MethodWrapper GetMethod(ClassFile.ConstantPoolItemFMI cpi, TypeWrapper thisType, NormalizedByteCode invoke)
+ {
+ // TODO when there is an error resolving a call to the super class constructor (in the constructor of this type),
+ // we cannot use EmitError, because that will yield an invalid constructor (that doesn't call the superclass constructor)
+ TypeWrapper wrapper = LoadClass(cpi.Class);
+ if(wrapper != null)
+ {
+ if(wrapper.IsInterface != (invoke == NormalizedByteCode.__invokeinterface))
+ {
+ EmitError("java.lang.IncompatibleClassChangeError", null);
+ }
+ else
+ {
+ if(invoke == NormalizedByteCode.__invokespecial && m.Method.ClassFile.IsSuper && thisType != wrapper && thisType.IsSubTypeOf(wrapper))
+ {
+ wrapper = thisType.BaseTypeWrapper;
+ }
+ MethodDescriptor md = new MethodDescriptor(classLoader, cpi.Name, cpi.Signature);
+ MethodWrapper method = null;
+ if(invoke == NormalizedByteCode.__invokeinterface)
+ {
+ method = GetInterfaceMethod(wrapper, md);
+ // NOTE vmspec 5.4.3.4 clearly states that an interfacemethod may also refer to a method in Object
+ if(method == null)
+ {
+ method = ClassLoaderWrapper.GetBootstrapClassLoader().LoadClassBySlashedName("java/lang/Object").GetMethodWrapper(md, false);
+ }
+ }
+ else
+ {
+ method = wrapper.GetMethodWrapper(md, md.Name != "<init>");
+ // if the method is not found, we might have to simulate a Miranda method
+ if(method == null && invoke == NormalizedByteCode.__invokevirtual)
+ {
+ method = GetInterfaceMethod(wrapper, md);
+ }
+ }
+ if(method != null)
+ {
+ if(method.IsStatic == (invoke == NormalizedByteCode.__invokestatic))
+ {
+ if(method.IsAbstract && invoke == NormalizedByteCode.__invokespecial)
+ {
+ EmitError("java.lang.AbstractMethodError", cpi.Class + "." + cpi.Name + cpi.Signature);
+ }
+ else if(method.IsPublic ||
+ (method.IsProtected && (method.IsStatic ? clazz.IsSubTypeOf(method.DeclaringType) : clazz.IsSubTypeOf(thisType))) ||
+ (method.IsPrivate && clazz == method.DeclaringType) ||
+ (!(method.IsPublic || method.IsPrivate) && clazz.IsInSamePackageAs(method.DeclaringType)))
+ {
+ return method;
+ }
+ else
+ {
+ // HACK special case for incorrect invocation of Object.clone(), because this could mean
+ // we're calling clone() on an array
+ // (bug in javac, see http://developer.java.sun.com/developer/bugParade/bugs/4329886.html)
+ if(!method.IsStatic && cpi.Name == "clone" && wrapper.Type == typeof(object) && thisType.Type.IsArray)
+ {
+ method = thisType.GetMethodWrapper(new MethodDescriptor(classLoader, cpi.Name, cpi.Signature), false);
+ if(method != null && method.IsPublic)
+ {
+ return method;
+ }
+ }
+ EmitError("java.lang.IllegalAccessError", "Try to access method " + method.DeclaringType.Name + "." + cpi.Name + cpi.Signature + " from class " + clazz.Name);
+ }
+ }
+ else
+ {
+ EmitError("java.lang.IncompatibleClassChangeError", null);
+ }
+ }
+ else
+ {
+ EmitError("java.lang.NoSuchMethodError", cpi.Class + "." + cpi.Name + cpi.Signature);
+ }
+ }
+ }
+ return null;
+ }
+
+ private void EmitError(string errorType, string message)
+ {
+ if(message != null)
+ {
+ if(JVM.IsStaticCompiler)
+ {
+ Console.Error.WriteLine(errorType + ": " + message);
+ Console.Error.WriteLine("\tat " + m.Method.ClassFile.Name + "." + m.Method.Name + m.Method.Signature);
+ }
+ ilGenerator.Emit(OpCodes.Ldstr, message);
+ TypeWrapper type = classLoader.LoadClassByDottedName(errorType);
+ MethodWrapper method = type.GetMethodWrapper(new MethodDescriptor(classLoader, "<init>", "(Ljava/lang/String;)V"), false);
+ method.EmitNewobj.Emit(ilGenerator);
+ }
+ else
+ {
+ if(JVM.IsStaticCompiler)
+ {
+ Console.Error.WriteLine(errorType);
+ Console.Error.WriteLine("\tat " + m.Method.ClassFile.Name + "." + m.Method.Name + m.Method.Signature);
+ }
+ TypeWrapper type = classLoader.LoadClassByDottedName(errorType);
+ MethodWrapper method = type.GetMethodWrapper(new MethodDescriptor(classLoader, "<init>", "()V"), false);
+ method.EmitNewobj.Emit(ilGenerator);
+ }
+ // we emit a call to ThrowHack instead of a throw instruction, because otherwise the verifier will know
+ // that execution won't continue at the next instruction, and the emitted code won't be verifiable
+ ilGenerator.Emit(OpCodes.Call, throwHack);
+ }
+
+ private TypeWrapper LoadClass(string classname)
+ {
+ try
+ {
+ TypeWrapper type = classLoader.LoadClassBySlashedName(classname);
+ if(!type.IsPublic && !clazz.IsInSamePackageAs(type))
+ {
+ // TODO all classnames in error messages should be dotted instead of slashed
+ EmitError("java.lang.IllegalAccessError", "Try to access class " + classname + " from class " + clazz.Name);
+ return null;
+ }
+ return type;
+ }
+ catch(Exception)
+ {
+ // TODO we should freeze the exception here, instead of always throwing a NoClassDefFoundError
+ EmitError("java.lang.NoClassDefFoundError", classname);
+ return null;
+ }
+ }
+
+ private Type ExpressionType(string type)
+ {
+ try
+ {
+ return classLoader.ExpressionType(type);
+ }
+ catch(Exception)
+ {
+ // TODO we should freeze the exception here, instead of always throwing a NoClassDefFoundError
+ EmitError("java.lang.NoClassDefFoundError", type);
+ return null;
+ }
+ }
+
+ private static string SigTypeToClassName(string type, string nullType)
+ {
+ switch(type[0])
+ {
+ case 'N':
+ case 'U':
+ {
+ string chop = type.Substring(type.IndexOf(';') + 2);
+ return chop.Substring(0, chop.Length - 1);
+ }
+ case 'L':
+ if(type == "Lnull")
+ {
+ return nullType;
+ }
+ else
+ {
+ return type.Substring(1, type.Length - 2);
+ }
+ case '[':
+ return type;
+ default:
+ throw new InvalidOperationException();
+ }
+ }
+
+ private void EmitPlaceholder(string sig)
+ {
+ switch(sig[0])
+ {
+ case 'L':
+ case '[':
+ ilGenerator.Emit(OpCodes.Ldnull);
+ break;
+ case 'Z':
+ case 'B':
+ case 'S':
+ case 'C':
+ case 'I':
+ ilGenerator.Emit(OpCodes.Ldc_I4_0);
+ break;
+ case 'J':
+ ilGenerator.Emit(OpCodes.Ldc_I8, 0L);
+ break;
+ case 'F':
+ ilGenerator.Emit(OpCodes.Ldc_R4, 0.0f);
+ break;
+ case 'D':
+ ilGenerator.Emit(OpCodes.Ldc_R8, 0.0);
+ break;
+ case 'V':
+ break;
+ default:
+ throw new InvalidOperationException();
+ }
+ }
+
+ private int FindPcIndex(int target)
+ {
+ return m.PcIndexMap[target];
+ }
+
+ private void Load(ClassFile.Method.Instruction instr, Type type)
+ {
+ // TODO this check will become more complex, once we support changing the type of an argument 'local'
+ if(instr.NormalizedArg1 >= m.ArgMap.Length)
+ {
+ // OPTIMIZE use short form when possible
+ ilGenerator.Emit(OpCodes.Ldloc, GetLocal(type, instr.NormalizedArg1));
+ }
+ else
+ {
+ int i = m.ArgMap[instr.NormalizedArg1];
+ switch(i)
+ {
+ case 0:
+ ilGenerator.Emit(OpCodes.Ldarg_0);
+ break;
+ case 1:
+ ilGenerator.Emit(OpCodes.Ldarg_1);
+ break;
+ case 2:
+ ilGenerator.Emit(OpCodes.Ldarg_2);
+ break;
+ case 3:
+ ilGenerator.Emit(OpCodes.Ldarg_3);
+ break;
+ default:
+ if(i < 256)
+ {
+ ilGenerator.Emit(OpCodes.Ldarg_S, (byte)i);
+ }
+ else
+ {
+ ilGenerator.Emit(OpCodes.Ldarg, (ushort)i);
+ }
+ break;
+ }
+ }
+ }
+
+ private void Store(ClassFile.Method.Instruction instr, Type type)
+ {
+ // TODO this check will become more complex, once we support changing the type of an argument 'local'
+ if(instr.NormalizedArg1 >= m.ArgMap.Length)
+ {
+ ilGenerator.Emit(OpCodes.Stloc, GetLocal(type, instr.NormalizedArg1));
+ }
+ else
+ {
+ int i = m.ArgMap[instr.NormalizedArg1];
+ if(i < 256)
+ {
+ ilGenerator.Emit(OpCodes.Starg_S, (byte)i);
+ }
+ else
+ {
+ ilGenerator.Emit(OpCodes.Starg, (ushort)i);
+ }
+ }
+ }
+
+ private LocalBuilder GetLocal(Type type, int index)
+ {
+ string name;
+ if(type.IsValueType)
+ {
+ name = type.Name + index;
+ }
+ else
+ {
+ name = "Obj" + index;
+ string t = ma.GetDeclaredLocalType(index);
+ if(t != null && t != "Lnull")
+ {
+ // TODO handle class not found
+ type = classLoader.ExpressionType(t);
+ }
+ }
+ LocalBuilder lb = (LocalBuilder)locals[name];
+ if(lb == null)
+ {
+ lb = ilGenerator.DeclareLocal(type);
+ locals[name] = lb;
+ // the local variable table is disabled, because we need to have
+ // better support for overloaded indexes to make this usefull
+ if(JVM.Debug && false)
+ {
+ // TODO this should be done better
+ ClassFile.Method.LocalVariableTableEntry[] table = m.LocalVariableTableAttribute;
+ if(table != null)
+ {
+ for(int i = 0; i < table.Length; i++)
+ {
+ if(table[i].index == index)
+ {
+ lb.SetLocalSymInfo(table[i].name);
+ break;
+ }
+ }
+ }
+ }
+ }
+ return lb;
+ }
+
+ private Label GetLabel(object[] labels, int targetPC, bool[] inuse, int rangeBegin, int rangeEnd, ArrayList exits)
+ {
+ if(rangeBegin <= targetPC && targetPC < rangeEnd)
+ {
+ inuse[FindPcIndex(targetPC)] = true;
+ object l = labels[targetPC];
+ if(l == null)
+ {
+ l = ilGenerator.DefineLabel();
+ labels[targetPC] = l;
+ }
+ return (Label)l;
+ }
+ else
+ {
+ BranchCookie bc = new BranchCookie();
+ bc.TargetIndex = FindPcIndex(targetPC);
+ bc.Stub = ilGenerator.DefineLabel();
+ exits.Add(bc);
+ return bc.Stub;
+ }
+ }
+}
diff --git a/IK.VM.NET/ik.vm.net.build b/IK.VM.NET/ik.vm.net.build
new file mode 100644
index 00000000..8fbb00da
--- /dev/null
+++ b/IK.VM.NET/ik.vm.net.build
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<project name="ik.vm.net" default="ik.vm.net">
+ <target name="ik.vm.net">
+ <csc target="library" output="../bin/ik.vm.net.dll">
+ <sources>
+ <includes name="*.cs" />
+ </sources>
+ <references>
+ <includes name="../bin/IK.VM.JNI.dll" asis="true" />
+ </references>
+ <arg value="/resource:map.xml" />
+ </csc>
+ </target>
+</project>
diff --git a/IK.VM.NET/map.xml b/IK.VM.NET/map.xml
new file mode 100644
index 00000000..26334044
--- /dev/null
+++ b/IK.VM.NET/map.xml
@@ -0,0 +1,446 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+-->
+<root>
+ <remappings>
+ <class name="java.lang.Object" type="System.Object" modifiers="public">
+ <constructor sig="()V" modifiers="public" />
+ <method name="notifyAll" sig="()V" modifiers="public final">
+ <redirect class="ObjectHelper" name="notifyAll" sig="(Ljava/lang/Object;)V" type="static" />
+ </method>
+ <method name="notify" sig="()V" modifiers="public final">
+ <redirect class="ObjectHelper" name="notify" sig="(Ljava/lang/Object;)V" type="static" />
+ </method>
+ <method name="wait" sig="()V" modifiers="public final">
+ <redirect class="ObjectHelper" name="wait" sig="(Ljava/lang/Object;)V" type="static" />
+ </method>
+ <method name="wait" sig="(J)V" modifiers="public final">
+ <redirect class="ObjectHelper" name="wait" sig="(Ljava/lang/Object;J)V" type="static" />
+ </method>
+ <method name="wait" sig="(JI)V" modifiers="public final">
+ <redirect class="ObjectHelper" name="wait" sig="(Ljava/lang/Object;JI)V" type="static" />
+ </method>
+ <method name="getClass" sig="()Ljava/lang/Class;" modifiers="public final">
+ <redirect class="ObjectHelper" name="getClass" sig="(Ljava/lang/Object;)Ljava/lang/Object;" type="static" />
+ </method>
+ <method name="clone" sig="()Ljava/lang/Object;" modifiers="protected">
+ <invokespecial>
+ <!-- TODO if we already know statically that the type implements java/lang/Cloneable this check can be omitted -->
+ <dup />
+ <call class="ObjectHelper" name="clonecheck" />
+ <call class="System.Object" name="MemberwiseClone" />
+ </invokespecial>
+ <invokevirtual>
+ <call class="ObjectHelper" name="virtualclone" />
+ </invokevirtual>
+ </method>
+ <!-- virtual methods -->
+ <!-- TODO every object that doesn't override toString or hashCode will now be called through these
+ conditional constructs, this is unnecessary (and not very efficient), so I need to figure out a way
+ to prevent this -->
+ <method name="toString" sig="()Ljava/lang/String;" modifiers="public">
+ <override name="ToString" />
+ <invokespecial>
+ <call class="ObjectHelper" name="toStringSpecial" />
+ </invokespecial>
+ <invokevirtual>
+ <dup />
+ <isinst class="System.Array" />
+ <brfalse name="skip" />
+ <call class="ObjectHelper" name="toStringSpecial" />
+ <br name="end" />
+ <label name="skip" />
+ <callvirt class="System.Object" name="ToString" />
+ <label name="end" />
+ </invokevirtual>
+ </method>
+ <method name="hashCode" sig="()I" modifiers="public">
+ <override name="GetHashCode" />
+ <invokevirtual>
+ <dup />
+ <isinst class="System.String" />
+ <brfalse name="skip" />
+ <call class="StringHelper" name="hashCode" />
+ <br name="end" />
+ <label name="skip" />
+ <callvirt class="System.Object" name="GetHashCode" />
+ <label name="end" />
+ </invokevirtual>
+ </method>
+ <method name="equals" sig="(Ljava/lang/Object;)Z" modifiers="public">
+ <override name="Equals" />
+ </method>
+ <method name="finalize" sig="()V" modifiers="protected">
+ <override name="Finalize" />
+ </method>
+ </class>
+ <class name="java.lang.String" type="System.String" modifiers="public final">
+ <constructor sig="()V" modifiers="public">
+ <!-- TODO -->
+ <newobj>
+ <ldstr value="" />
+ <call class="System.String" name="Copy" />
+ </newobj>
+ </constructor>
+ <constructor sig="([C)V" modifiers="public" />
+ <constructor sig="([CII)V" modifiers="public" />
+ <!-- Package private constructor, that we redirect to static helper -->
+ <constructor sig="([CIIZ)V" modifiers="">
+ <redirect class="StringHelper" name="NewString" type="static" sig="([CIIZ)Ljava/lang/String;" />
+ </constructor>
+ <constructor sig="(Ljava/lang/String;)V" modifiers="public">
+ <redirect class="System.String" name="Copy" type="static" sig="(Ljava/lang/String;)Ljava/lang/String;" />
+ </constructor>
+ <constructor sig="(Ljava/lang/StringBuffer;)V" modifiers="public">
+ <redirect class="System.Text.StringBuilder" name="ToString" sig="()Ljava/lang/String;" />
+ </constructor>
+ <constructor sig="([B)V" modifiers="public">
+ <redirect class="StringHelper" name="NewString" type="static" sig="([B)Ljava/lang/String;" />
+ </constructor>
+ <constructor sig="([BI)V" modifiers="public">
+ <redirect class="StringHelper" name="NewString" type="static" sig="([BI)Ljava/lang/String;" />
+ </constructor>
+ <constructor sig="([BII)V" modifiers="public">
+ <redirect class="StringHelper" name="NewString" type="static" sig="([BII)Ljava/lang/String;" />
+ </constructor>
+ <constructor sig="([BIII)V" modifiers="public">
+ <redirect class="StringHelper" name="NewString" type="static" sig="([BIII)Ljava/lang/String;" />
+ </constructor>
+ <constructor sig="([BLjava/lang/String;)V" modifiers="public">
+ <redirect class="StringHelper" name="NewString" type="static" sig="([BLjava/lang/String;)Ljava/lang/String;" />
+ </constructor>
+ <constructor sig="([BIILjava/lang/String;)V" modifiers="public">
+ <redirect class="StringHelper" name="NewString" type="static" sig="([BIILjava/lang/String;)Ljava/lang/String;" />
+ </constructor>
+ <method name="hashCode" sig="()I" modifiers="public">
+ <redirect class="StringHelper" type="static" sig="(Ljava/lang/String;)I" />
+ </method>
+ <method name="valueOf" sig="(Z)Ljava/lang/String;" modifiers="public static">
+ <redirect class="StringHelper" />
+ </method>
+ <method name="valueOf" sig="(I)Ljava/lang/String;" modifiers="public static">
+ <redirect class="StringHelper" />
+ </method>
+ <method name="valueOf" sig="(J)Ljava/lang/String;" modifiers="public static">
+ <redirect class="StringHelper" />
+ </method>
+ <method name="valueOf" sig="(C)Ljava/lang/String;" modifiers="public static">
+ <redirect class="StringHelper" />
+ </method>
+ <method name="valueOf" sig="(F)Ljava/lang/String;" modifiers="public static">
+ <redirect class="StringHelper" />
+ </method>
+ <method name="valueOf" sig="(D)Ljava/lang/String;" modifiers="public static">
+ <redirect class="StringHelper" />
+ </method>
+ <method name="valueOf" sig="(Ljava/lang/Object;)Ljava/lang/String;" modifiers="public static">
+ <redirect class="StringHelper" />
+ </method>
+ <method name="substring" sig="(I)Ljava/lang/String;" modifiers="public">
+ <redirect name="Substring" />
+ </method>
+ <method name="length" sig="()I" modifiers="public">
+ <redirect name="get_Length" />
+ </method>
+ <method name="charAt" sig="(I)C" modifiers="public">
+ <redirect name="get_Chars" />
+ </method>
+ <method name="substring" sig="(II)Ljava/lang/String;" modifiers="public">
+ <redirect class="StringHelper" type="static" sig="(Ljava/lang/String;II)Ljava/lang/String;" />
+ </method>
+ <method name="indexOf" sig="(I)I" modifiers="public">
+ <redirect name="IndexOf" sig="(C)I" />
+ </method>
+ <method name="indexOf" sig="(II)I" modifiers="public">
+ <redirect name="IndexOf" sig="(CI)I" />
+ </method>
+ <method name="indexOf" sig="(Ljava/lang/String;)I" modifiers="public">
+ <redirect name="IndexOf" />
+ </method>
+ <method name="indexOf" sig="(Ljava/lang/String;I)I" modifiers="public">
+ <redirect name="IndexOf" />
+ </method>
+ <method name="lastIndexOf" sig="(I)I" modifiers="public">
+ <redirect name="LastIndexOf" sig="(C)I" />
+ </method>
+ <method name="lastIndexOf" sig="(II)I" modifiers="public">
+ <redirect name="LastIndexOf" sig="(CI)I" />
+ </method>
+ <method name="lastIndexOf" sig="(Ljava/lang/String;)I" modifiers="public">
+ <redirect name="LastIndexOf" />
+ </method>
+ <method name="toCharArray" sig="()[C" modifiers="public">
+ <redirect name="ToCharArray" />
+ </method>
+ <method name="getChars" sig="(II[CI)V" modifiers="public">
+ <redirect class="StringHelper" type="static" sig="(Ljava/lang/String;II[CI)V" />
+ </method>
+ <method name="startsWith" sig="(Ljava/lang/String;)Z" modifiers="public">
+ <redirect name="StartsWith" />
+ </method>
+ <method name="startsWith" sig="(Ljava/lang/String;I)Z" modifiers="public">
+ <redirect class="StringHelper" type="static" sig="(Ljava/lang/String;Ljava/lang/String;I)Z" />
+ </method>
+ <method name="endsWith" sig="(Ljava/lang/String;)Z" modifiers="public">
+ <redirect name="EndsWith" />
+ </method>
+ <method name="toUpperCase" sig="()Ljava/lang/String;" modifiers="public">
+ <redirect name="ToUpper" />
+ </method>
+ <method name="toUpperCase" sig="(Ljava/util/Locale;)Ljava/lang/String;" modifiers="public">
+ <redirect class="StringHelper" type="static" sig="(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;" />
+ </method>
+ <method name="toLowerCase" sig="()Ljava/lang/String;" modifiers="public">
+ <redirect name="ToLower" />
+ </method>
+ <method name="compareToIgnoreCase" sig="(Ljava/lang/String;)I" modifiers="public">
+ <redirect class="StringHelper" type="static" sig="(Ljava/lang/String;Ljava/lang/String;)I" />
+ </method>
+ <method name="equalsIgnoreCase" sig="(Ljava/lang/String;)Z" modifiers="public">
+ <redirect class="StringHelper" type="static" sig="(Ljava/lang/String;Ljava/lang/String;)Z" />
+ </method>
+ <method name="intern" sig="()Ljava/lang/String;" modifiers="public">
+ <redirect type="static" name="Intern" sig="(Ljava/lang/String;)Ljava/lang/String;" />
+ </method>
+ <method name="compareTo" sig="(Ljava/lang/String;)I" modifiers="public">
+ <redirect name="CompareTo" />
+ </method>
+ <method name="replace" sig="(CC)Ljava/lang/String;" modifiers="public">
+ <redirect name="Replace" />
+ </method>
+ <method name="getBytes" sig="()[B" modifiers="public">
+ <redirect class="StringHelper" type="static" sig="(Ljava/lang/String;)[B" />
+ </method>
+ <method name="getBytes" sig="(Ljava/lang/String;)[B" modifiers="public">
+ <redirect class="StringHelper" type="static" sig="(Ljava/lang/String;Ljava/lang/String;)[B" />
+ </method>
+ <method name="subSequence" sig="(II)Ljava/lang/CharSequence;" modifiers="public">
+ <redirect class="StringHelper" type="static" sig="(Ljava/lang/String;II)Ljava/lang/Object;" />
+ </method>
+ <method name="trim" sig="()Ljava/lang/String;" modifiers="public">
+ <redirect name="Trim" />
+ </method>
+ <method name="regionMatches" sig="(ZILjava/lang/String;II)Z" modifiers="public">
+ <redirect class="StringHelper" type="static" sig="(Ljava/lang/String;ZILjava/lang/String;II)Z" />
+ </method>
+ <method name="regionMatches" sig="(ILjava/lang/String;II)Z" modifiers="public">
+ <redirect class="StringHelper" type="static" sig="(Ljava/lang/String;ILjava/lang/String;II)Z" />
+ </method>
+ <method name="getBytes" sig="(II[BI)V" modifiers="public">
+ <redirect class="StringHelper" type="static" sig="(Ljava/lang/String;II[BI)V" />
+ </method>
+ <method name="concat" sig="(Ljava/lang/String;)Ljava/lang/String;" modifiers="public">
+ <redirect class="System.String" type="static" name="Concat" sig="(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;" />
+ </method>
+ <method name="copyValueOf" sig="([CII)Ljava/lang/String;" modifiers="public static">
+ <invokestatic>
+ <newobj class="System.String" name=".ctor" sig="([CII)V" />
+ </invokestatic>
+ </method>
+ <!-- NOTE we're redirecting fields to static methods here!
+ NOTE only reading fields can be redirected
+ -->
+ <field name="count" sig="I" modifiers="">
+ <redirect class="StringHelper" type="static" name="GetCountField" sig="(Ljava/lang/String;)I" />
+ </field>
+ <!-- Making a new char array instead of directly accessing the contents of the string, probably isn't
+ as efficient as the coder of this construct wished for, but hey ;-) At least it works...
+ TODO we should probably make StringBuffer a native class, to make it perform better
+ NOTE since StringBuffer is remapped to StringBuilder now, these might not be needed anymore
+ -->
+ <method name="zeroBasedStringValue" sig="(Ljava/lang/String;)[C" modifiers="static">
+ <redirect class="StringHelper" name="GetValueField" />
+ </method>
+ <field name="value" sig="[C" modifiers="">
+ <redirect class="StringHelper" type="static" name="GetValueField" sig="(Ljava/lang/String;)[C" />
+ </field>
+ <field name="offset" sig="I" modifiers="">
+ <redirect class="StringHelper" type="static" name="GetOffsetField" sig="(Ljava/lang/String;)I" />
+ </field>
+ </class>
+ <!-- TODO it is incorrect to map StringBuffer to StringBuilder, because StringBuffer is thread safe, puke! -->
+ <class name="java.lang.StringBuffer" type="System.Text.StringBuilder" modifiers="public final">
+ <constructor sig="()V" modifiers="public" />
+ <constructor sig="(Ljava/lang/String;)V" modifiers="public" />
+ <constructor sig="(I)V" modifiers="public" />
+ <method name="length" sig="()I" modifiers="public">
+ <redirect name="get_Length" />
+ </method>
+ <method name="setLength" sig="(I)V" modifiers="public">
+ <redirect name="set_Length" />
+ </method>
+ <method name="ensureCapacity" sig="(I)V" modifiers="public">
+ <invokevirtual>
+ <call class="System.Text.StringBuilder" name="EnsureCapacity" />
+ <pop />
+ </invokevirtual>
+ <invokespecial>
+ <call class="System.Text.StringBuilder" name="EnsureCapacity" />
+ <pop />
+ </invokespecial>
+ </method>
+ <method name="append" sig="(Ljava/lang/Object;)Ljava/lang/StringBuffer;" modifiers="public">
+ <redirect class="StringBufferHelper" type="static" sig="(Ljava/lang/StringBuffer;Ljava/lang/Object;)Ljava/lang/StringBuffer;" />
+ </method>
+ <method name="append" sig="(Ljava/lang/String;)Ljava/lang/StringBuffer;" modifiers="public">
+ <redirect class="StringBufferHelper" type="static" sig="(Ljava/lang/StringBuffer;Ljava/lang/String;)Ljava/lang/StringBuffer;" />
+ </method>
+ <method name="append" sig="(Z)Ljava/lang/StringBuffer;" modifiers="public">
+ <redirect class="StringBufferHelper" type="static" sig="(Ljava/lang/StringBuffer;Z)Ljava/lang/StringBuffer;" />
+ </method>
+ <method name="append" sig="(C)Ljava/lang/StringBuffer;" modifiers="public">
+ <redirect name="Append" />
+ </method>
+ <method name="append" sig="(I)Ljava/lang/StringBuffer;" modifiers="public">
+ <redirect name="Append" />
+ </method>
+ <method name="append" sig="(J)Ljava/lang/StringBuffer;" modifiers="public">
+ <redirect name="Append" />
+ </method>
+ <method name="append" sig="(F)Ljava/lang/StringBuffer;" modifiers="public">
+ <redirect class="StringBufferHelper" type="static" sig="(Ljava/lang/StringBuffer;F)Ljava/lang/StringBuffer;" />
+ </method>
+ <method name="append" sig="(D)Ljava/lang/StringBuffer;" modifiers="public">
+ <redirect class="StringBufferHelper" type="static" sig="(Ljava/lang/StringBuffer;D)Ljava/lang/StringBuffer;" />
+ </method>
+ <method name="append" sig="([C)Ljava/lang/StringBuffer;" modifiers="public">
+ <redirect name="Append" />
+ </method>
+ <method name="append" sig="([CII)Ljava/lang/StringBuffer;" modifiers="public">
+ <redirect name="Append" />
+ </method>
+ <method name="insert" sig="(IC)Ljava/lang/StringBuffer;" modifiers="public">
+ <redirect name="Insert" />
+ </method>
+ <method name="insert" sig="(ILjava/lang/String;)Ljava/lang/StringBuffer;" modifiers="public">
+ <redirect class="StringBufferHelper" type="static" sig="(Ljava/lang/StringBuffer;ILjava/lang/String;)Ljava/lang/StringBuffer;" />
+ </method>
+ <method name="replace" sig="(IILjava/lang/String;)Ljava/lang/StringBuffer;" modifiers="public">
+ <redirect class="StringBufferHelper" type="static" sig="(Ljava/lang/StringBuffer;IILjava/lang/String;)Ljava/lang/StringBuffer;" />
+ </method>
+ <method name="delete" sig="(II)Ljava/lang/StringBuffer;" modifiers="public">
+ <redirect class="StringBufferHelper" type="static" sig="(Ljava/lang/StringBuffer;II)Ljava/lang/StringBuffer;" />
+ </method>
+ <method name="setCharAt" sig="(IC)V" modifiers="public">
+ <redirect name="set_Chars" />
+ </method>
+ <method name="charAt" sig="(I)C" modifiers="public">
+ <redirect name="get_Chars" />
+ </method>
+ <method name="substring" sig="(II)Ljava/lang/String;" modifiers="public">
+ <redirect class="StringBufferHelper" type="static" sig="(Ljava/lang/StringBuffer;II)Ljava/lang/String;" />
+ </method>
+ <method name="substring" sig="(I)Ljava/lang/String;" modifiers="public">
+ <redirect class="StringBufferHelper" type="static" sig="(Ljava/lang/StringBuffer;I)Ljava/lang/String;" />
+ </method>
+ </class>
+ <class name="java.lang.Throwable" type="System.Exception" modifiers="public">
+ <constructor sig="()V" modifiers="public">
+ <invokespecial>
+ <call class="ExceptionHelper" name="get_NullString" />
+ <call class="System.Exception" name=".ctor" sig="(Ljava/lang/String;)V" />
+ </invokespecial>
+ </constructor>
+ <constructor sig="(Ljava/lang/String;)V" modifiers="public">
+ <invokespecial>
+ <call class="ExceptionHelper" name="FilterMessage" />
+ <call class="System.Exception" name=".ctor" sig="(Ljava/lang/String;)V" />
+ </invokespecial>
+ </constructor>
+ <constructor sig="(Ljava/lang/String;Ljava/lang/Throwable;)V" modifiers="public">
+ <invokespecial>
+ <stloc name="x" class="System.Exception" />
+ <call class="ExceptionHelper" name="FilterMessage" />
+ <ldloc name="x" />
+ <call class="System.Exception" name=".ctor" sig="(Ljava/lang/String;Ljava/lang/Throwable;)V" />
+ </invokespecial>
+ </constructor>
+ <constructor sig="(Ljava/lang/Throwable;)V" modifiers="public">
+ <invokespecial>
+ <stloc name="x" class="System.Exception" />
+ <ldloc name="x" />
+ <call class="ExceptionHelper" name="GetMessageFromCause" />
+ <ldloc name="x" />
+ <call class="System.Exception" name=".ctor" sig="(Ljava/lang/String;Ljava/lang/Throwable;)V" />
+ </invokespecial>
+ </constructor>
+ <method type="virtual" name="printStackTrace" sig="()V" modifiers="public">
+ <redirect class="ExceptionHelper" sig="(Ljava/lang/Throwable;)V" type="static" />
+ </method>
+ <method type="virtual" name="printStackTrace" sig="(Ljava/io/PrintStream;)V" modifiers="public">
+ <!-- NOTE both printStackTrace(Ljava/io/PrintStream;)V & printStackTrace(Ljava/io/PrintWriter;)V redirect
+ to the same method, this is not a bug -->
+ <redirect class="ExceptionHelper" sig="(Ljava/lang/Throwable;Ljava/lang/Object;)V" type="static" />
+ </method>
+ <method type="virtual" name="printStackTrace" sig="(Ljava/io/PrintWriter;)V" modifiers="public">
+ <!-- NOTE both printStackTrace(Ljava/io/PrintStream;)V & printStackTrace(Ljava/io/PrintWriter;)V redirect
+ to the same method, this is not a bug -->
+ <redirect class="ExceptionHelper" sig="(Ljava/lang/Throwable;Ljava/lang/Object;)V" type="static" />
+ </method>
+ <method type="virtual" name="getMessage" sig="()Ljava/lang/String;" modifiers="public">
+ <redirect class="ExceptionHelper" sig="(Ljava/lang/Throwable;)Ljava/lang/String;" type="static" />
+ </method>
+ <method type="virtual" name="getLocalizedMessage" sig="()Ljava/lang/String;" modifiers="public">
+ <redirect class="ExceptionHelper" sig="(Ljava/lang/Throwable;)Ljava/lang/String;" type="static" />
+ </method>
+ <method type="virtual" name="fillInStackTrace" sig="()Ljava/lang/Throwable;" modifiers="public">
+ <redirect class="ExceptionHelper" sig="(Ljava/lang/Throwable;)Ljava/lang/Throwable;" type="static" />
+ </method>
+ <method type="virtual" name="initCause" sig="(Ljava/lang/Throwable;)Ljava/lang/Throwable;" modifiers="public">
+ <redirect class="ExceptionHelper" sig="(Ljava/lang/Throwable;Ljava/lang/Throwable;)Ljava/lang/Throwable;" type="static" />
+ </method>
+ <method type="virtual" name="getCause" sig="()Ljava/lang/Throwable;" modifiers="public">
+ <redirect class="ExceptionHelper" sig="(Ljava/lang/Throwable;)Ljava/lang/Throwable;" type="static" />
+ </method>
+ <method type="virtual" name="getStackTrace" sig="()[Ljava/lang/StackTraceElement;" modifiers="public">
+ <redirect class="ExceptionHelper" sig="(Ljava/lang/Throwable;)[Ljava/lang/StackTraceElement;" type="static" />
+ </method>
+ <method type="virtual" name="setStackTrace" sig="([Ljava/lang/StackTraceElement;)V" modifiers="public">
+ <redirect class="ExceptionHelper" sig="(Ljava/lang/Throwable;[Ljava/lang/StackTraceElement;)V" type="static" />
+ </method>
+ <method type="virtual" name="toString" sig="()Ljava/lang/String;" modifiers="public">
+ <redirect class="ExceptionHelper" sig="(Ljava/lang/Throwable;)Ljava/lang/String;" type="static" />
+ </method>
+ </class>
+ <class name="java.lang.Comparable" type="System.IComparable" modifiers="public interface">
+ <method name="compareTo" sig="(Ljava/lang/Object;)I" modifiers="public">
+ <override name="CompareTo" />
+ </method>
+ </class>
+ <!-- TODO java.lang.StackTraceElement shouldn't be here, but it should be represented by a different TypeWrapper (that can take
+ a .NET type and present it as a Java type -->
+ <class name="java.lang.StackTraceElement" type="java.lang.StackTraceElement" modifiers="public final">
+ <!-- TODO fill out the methods -->
+ </class>
+ </remappings>
+ <nativeMethods>
+ <class name="java.lang.VMSystem">
+ <method name="identityHashCode" sig="(Ljava/lang/Object;)I">
+ <ldarg_0 />
+ <call class="System.Object" name="GetHashCode" />
+ <ret />
+ </method>
+ </class>
+ </nativeMethods>
+</root> \ No newline at end of file
diff --git a/IK.VM.NET/profiler.cs b/IK.VM.NET/profiler.cs
new file mode 100644
index 00000000..fb6f75fc
--- /dev/null
+++ b/IK.VM.NET/profiler.cs
@@ -0,0 +1,79 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+using System.Collections;
+using System.Diagnostics;
+
+class Profiler
+{
+ private static Profiler instance = new Profiler();
+ private static Hashtable counters = new Hashtable();
+ private static Stack stack = new Stack();
+
+ private class Entry
+ {
+ internal long Time;
+ internal long Count;
+ }
+
+ ~Profiler()
+ {
+ foreach(DictionaryEntry e in counters)
+ {
+ Console.WriteLine("{0} was executed {1} times for a total of {2} ms", e.Key, ((Entry)e.Value).Count, ((Entry)e.Value).Time / 10000);
+ }
+ }
+
+ [Conditional("PROFILE")]
+ internal static void Enter(string name)
+ {
+ long ticks = DateTime.Now.Ticks;
+ if(stack.Count > 0)
+ {
+ ((Entry)stack.Peek()).Time += ticks;
+ }
+ Entry e = (Entry)counters[name];
+ if(e == null)
+ {
+ e = new Entry();
+ counters[name] = e;
+ }
+ e.Count++;
+ e.Time -= ticks;
+ stack.Push(e);
+ }
+
+ [Conditional("PROFILE")]
+ internal static void Leave(string name)
+ {
+ long ticks = DateTime.Now.Ticks;
+ stack.Pop();
+ Entry e = (Entry)counters[name];
+ e.Time += ticks;
+ if(stack.Count > 0)
+ {
+ ((Entry)stack.Peek()).Time -= ticks;
+ }
+ }
+}
diff --git a/IK.VM.NET/remapper.cs b/IK.VM.NET/remapper.cs
new file mode 100644
index 00000000..8156717e
--- /dev/null
+++ b/IK.VM.NET/remapper.cs
@@ -0,0 +1,387 @@
+using System;
+using System.Xml.Serialization;
+using System.Collections;
+using System.Reflection;
+using System.Reflection.Emit;
+
+namespace MapXml
+{
+ public abstract class Instruction
+ {
+ internal abstract void Generate(Hashtable context, ILGenerator ilgen);
+ }
+
+ [XmlType("ldstr")]
+ public sealed class Ldstr : Instruction
+ {
+ [XmlAttribute("value")]
+ public string Value;
+
+ internal override void Generate(Hashtable context, ILGenerator ilgen)
+ {
+ ilgen.Emit(OpCodes.Ldstr, Value);
+ }
+ }
+
+ [XmlType("call")]
+ public class Call : Instruction
+ {
+ public Call() : this(OpCodes.Call)
+ {
+ }
+
+ internal Call(OpCode opcode)
+ {
+ this.opcode = opcode;
+ }
+
+ [XmlAttribute("class")]
+ public string Class;
+ [XmlAttribute("name")]
+ public string Name;
+ [XmlAttribute("sig")]
+ public string Sig;
+
+ private MethodBase method;
+ private OpCode opcode;
+
+ internal sealed override void Generate(Hashtable context, ILGenerator ilgen)
+ {
+ if(method == null)
+ {
+ string name = Name;
+ if(name == ".ctor")
+ {
+ string sig = Sig;
+ Type[] argTypes = ClassLoaderWrapper.GetBootstrapClassLoader().ArgTypeListFromSig(sig);
+ method = Type.GetType(Class, true).GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, CallingConventions.Standard, argTypes, null);
+ }
+ else
+ {
+ method = Type.GetType(Class, true).GetMethod(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
+ }
+ if(method == null)
+ {
+ throw new InvalidOperationException("method not found: " + name);
+ }
+ }
+ if(method.IsConstructor)
+ {
+ ilgen.Emit(opcode, (ConstructorInfo)method);
+ }
+ else
+ {
+ ilgen.Emit(opcode, (MethodInfo)method);
+ }
+ }
+ }
+
+ [XmlType("callvirt")]
+ public sealed class Callvirt : Call
+ {
+ public Callvirt() : base(OpCodes.Callvirt)
+ {
+ }
+ }
+
+ [XmlType("newobj")]
+ public sealed class NewObj : Call
+ {
+ public NewObj() : base(OpCodes.Newobj)
+ {
+ }
+ }
+
+ public abstract class Simple : Instruction
+ {
+ private OpCode opcode;
+
+ public Simple(OpCode opcode)
+ {
+ this.opcode = opcode;
+ }
+
+ internal sealed override void Generate(Hashtable context, ILGenerator ilgen)
+ {
+ ilgen.Emit(opcode);
+ }
+ }
+
+ [XmlType("dup")]
+ public sealed class Dup : Simple
+ {
+ public Dup() : base(OpCodes.Dup)
+ {
+ }
+ }
+
+ [XmlType("pop")]
+ public sealed class Pop : Simple
+ {
+ public Pop() : base(OpCodes.Pop)
+ {
+ }
+ }
+
+ [XmlType("isinst")]
+ public sealed class IsInst : Instruction
+ {
+ [XmlAttribute("class")]
+ public string Class;
+
+ private Type type;
+
+ internal override void Generate(Hashtable context, ILGenerator ilgen)
+ {
+ if(type == null)
+ {
+ type = Type.GetType(Class, true);
+ }
+ ilgen.Emit(OpCodes.Isinst, type);
+ }
+ }
+
+ public abstract class Branch : Instruction
+ {
+ private OpCode opcode;
+
+ public Branch(OpCode opcode)
+ {
+ this.opcode = opcode;
+ }
+
+ internal sealed override void Generate(Hashtable context, ILGenerator ilgen)
+ {
+ Label l;
+ if(context[Name] == null)
+ {
+ l = ilgen.DefineLabel();
+ context[Name] = l;
+ }
+ else
+ {
+ l = (Label)context[Name];
+ }
+ ilgen.Emit(opcode, l);
+ }
+
+ [XmlAttribute("name")]
+ public string Name;
+ }
+
+ [XmlType("brfalse")]
+ public sealed class BrFalse : Branch
+ {
+ public BrFalse() : base(OpCodes.Brfalse)
+ {
+ }
+ }
+
+ [XmlType("br")]
+ public sealed class Br : Branch
+ {
+ public Br() : base(OpCodes.Br)
+ {
+ }
+ }
+
+ [XmlType("label")]
+ public sealed class BrLabel : Instruction
+ {
+ [XmlAttribute("name")]
+ public string Name;
+
+ internal override void Generate(Hashtable context, ILGenerator ilgen)
+ {
+ Label l;
+ if(context[Name] == null)
+ {
+ l = ilgen.DefineLabel();
+ context[Name] = l;
+ }
+ else
+ {
+ l = (Label)context[Name];
+ }
+ ilgen.MarkLabel(l);
+ }
+ }
+
+ [XmlType("stloc")]
+ public sealed class StLoc : Instruction
+ {
+ [XmlAttribute("name")]
+ public string Name;
+ [XmlAttribute("class")]
+ public string Class;
+
+ private Type type;
+
+ internal override void Generate(Hashtable context, ILGenerator ilgen)
+ {
+ LocalBuilder lb = (LocalBuilder)context[Name];
+ if(lb == null)
+ {
+ if(type == null)
+ {
+ type = Type.GetType(Class, true);
+ }
+ lb = ilgen.DeclareLocal(type);
+ context[Name] = lb;
+ }
+ ilgen.Emit(OpCodes.Stloc, lb);
+ }
+ }
+
+ [XmlType("ldloc")]
+ public sealed class LdLoc : Instruction
+ {
+ [XmlAttribute("name")]
+ public string Name;
+
+ internal override void Generate(Hashtable context, ILGenerator ilgen)
+ {
+ ilgen.Emit(OpCodes.Ldloc, (LocalBuilder)context[Name]);
+ }
+ }
+
+ [XmlType("ldarg_0")]
+ public sealed class LdArg_0 : Simple
+ {
+ public LdArg_0() : base(OpCodes.Ldarg_0)
+ {
+ }
+ }
+
+ [XmlType("ret")]
+ public sealed class Ret : Simple
+ {
+ public Ret() : base(OpCodes.Ret)
+ {
+ }
+ }
+
+ public class InstructionList : CodeEmitter
+ {
+ [XmlElement(typeof(Ldstr))]
+ [XmlElement(typeof(Call))]
+ [XmlElement(typeof(Callvirt))]
+ [XmlElement(typeof(Dup))]
+ [XmlElement(typeof(Pop))]
+ [XmlElement(typeof(IsInst))]
+ [XmlElement(typeof(BrFalse))]
+ [XmlElement(typeof(Br))]
+ [XmlElement(typeof(BrLabel))]
+ [XmlElement(typeof(NewObj))]
+ [XmlElement(typeof(StLoc))]
+ [XmlElement(typeof(LdLoc))]
+ [XmlElement(typeof(LdArg_0))]
+ [XmlElement(typeof(Ret))]
+ public Instruction[] invoke;
+
+ internal sealed override void Emit(ILGenerator ilgen)
+ {
+ Hashtable context = new Hashtable();
+ for(int i = 0; i < invoke.Length; i++)
+ {
+ invoke[i].Generate(context, ilgen);
+ }
+ }
+ }
+
+ public class Constructor
+ {
+ [XmlAttribute("sig")]
+ public string Sig;
+ [XmlAttribute("modifiers")]
+ public MapModifiers Modifiers;
+ public InstructionList invokespecial;
+ public InstructionList newobj;
+ public Redirect redirect;
+ }
+
+ public class Redirect
+ {
+ [XmlAttribute("class")]
+ public string Class;
+ [XmlAttribute("name")]
+ public string Name;
+ [XmlAttribute("sig")]
+ public string Sig;
+ [XmlAttribute("type")]
+ public string Type;
+ }
+
+ public class Override
+ {
+ [XmlAttribute("name")]
+ public string Name;
+ }
+
+ public class Method : InstructionList
+ {
+ [XmlAttribute("name")]
+ public string Name;
+ [XmlAttribute("sig")]
+ public string Sig;
+ [XmlAttribute("modifiers")]
+ public MapModifiers Modifiers;
+ [XmlAttribute("type")]
+ public string Type;
+ public InstructionList invokevirtual;
+ public InstructionList invokespecial;
+ public InstructionList invokestatic;
+ public Redirect redirect;
+ public Override @override;
+ }
+
+ public class Field
+ {
+ [XmlAttribute("name")]
+ public string Name;
+ [XmlAttribute("sig")]
+ public string Sig;
+ [XmlAttribute("modifiers")]
+ public MapModifiers Modifiers;
+ public Redirect redirect;
+ }
+
+ [Flags]
+ public enum MapModifiers
+ {
+ [XmlEnum("public")]
+ Public = Modifiers.Public,
+ [XmlEnum("protected")]
+ Protected = Modifiers.Protected,
+ [XmlEnum("final")]
+ Final = Modifiers.Final,
+ [XmlEnum("interface")]
+ Interface = Modifiers.Interface,
+ [XmlEnum("static")]
+ Static = Modifiers.Static
+ }
+
+ [XmlType("class")]
+ public class Class
+ {
+ [XmlAttribute("name")]
+ public string Name;
+ [XmlAttribute("type")]
+ public string Type;
+ [XmlAttribute("modifiers")]
+ public MapModifiers Modifiers;
+ [XmlElement("constructor")]
+ public Constructor[] Constructors;
+ [XmlElement("method")]
+ public Method[] Methods;
+ [XmlElement("field")]
+ public Field[] Fields;
+ }
+
+ [XmlRoot("root")]
+ public class Root
+ {
+ public Class[] remappings;
+ public Class[] nativeMethods;
+ }
+}
diff --git a/IK.VM.NET/verifier.cs b/IK.VM.NET/verifier.cs
new file mode 100644
index 00000000..3913fc66
--- /dev/null
+++ b/IK.VM.NET/verifier.cs
@@ -0,0 +1,2185 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+using System.IO;
+using System.Collections;
+
+class VerifyError : ApplicationException
+{
+ internal int ByteCodeOffset;
+ internal string Class;
+ internal string Method;
+ internal string Signature;
+ internal string Instruction;
+
+ internal VerifyError()
+ {
+ }
+
+ internal VerifyError(string msg) : base(msg)
+ {
+ }
+}
+
+class Subroutine
+{
+ private int subroutineIndex;
+ private bool[] localsModified;
+
+ private Subroutine(int subroutineIndex, bool[] localsModified)
+ {
+ this.subroutineIndex = subroutineIndex;
+ this.localsModified = localsModified;
+ }
+
+ internal Subroutine(int subroutineIndex, int maxLocals)
+ {
+ this.subroutineIndex = subroutineIndex;
+ localsModified = new bool[maxLocals];
+ }
+
+ internal int SubroutineIndex
+ {
+ get
+ {
+ return subroutineIndex;
+ }
+ }
+
+ internal bool[] LocalsModified
+ {
+ get
+ {
+ return localsModified;
+ }
+ }
+
+ internal void SetLocalModified(int local)
+ {
+ localsModified[local] = true;
+ }
+
+ internal Subroutine Copy()
+ {
+ return new Subroutine(subroutineIndex, (bool[])localsModified.Clone());
+ }
+}
+
+class InstructionState
+{
+ private static ArrayList empty = new ArrayList();
+ private MethodAnalyzer ma;
+ private ArrayList stack; // each entry contains a string with a Java signature of the type
+ private string[] locals; // each entry contains a string with a Java signature of the type
+ private ArrayList subroutines;
+ private int callsites;
+ internal bool changed = true;
+
+ private InstructionState(MethodAnalyzer ma, ArrayList stack, string[] locals, ArrayList subroutines, int callsites)
+ {
+ this.ma = ma;
+ this.stack = stack;
+ this.locals = locals;
+ this.subroutines = subroutines;
+ this.callsites = callsites;
+ }
+
+ internal InstructionState(MethodAnalyzer ma, int maxLocals)
+ {
+ this.ma = ma;
+ this.stack = new ArrayList();
+ this.locals = new string[maxLocals];
+ this.subroutines = new ArrayList();
+ }
+
+ internal InstructionState Copy()
+ {
+ return new InstructionState(ma, (ArrayList)stack.Clone(), (string[])locals.Clone(), CopySubroutines(subroutines), callsites);
+ }
+
+ internal InstructionState CopyLocalsAndSubroutines()
+ {
+ return new InstructionState(ma, new ArrayList(), (string[])locals.Clone(), CopySubroutines(subroutines), callsites);
+ }
+
+ private ArrayList CopySubroutines(ArrayList l)
+ {
+ ArrayList n = new ArrayList(l.Count);
+ foreach(Subroutine s in l)
+ {
+ n.Add(s.Copy());
+ }
+ return n;
+ }
+
+ public static InstructionState operator+(InstructionState s1, InstructionState s2)
+ {
+ return Merge(s1, s2, null, null);
+ }
+
+ internal static InstructionState Merge(InstructionState s1, InstructionState s2, bool[] locals_modified, InstructionState s3)
+ {
+ if(s1 == null)
+ {
+ s2 = s2.Copy();
+ if(locals_modified != null)
+ {
+ for(int i = 0; i < s2.locals.Length; i++)
+ {
+ if(!locals_modified[i])
+ {
+ s2.locals[i] = s3.locals[i];
+ }
+ }
+ }
+ return s2;
+ }
+ if(s1.stack.Count != s2.stack.Count)
+ {
+ throw new VerifyError(string.Format("Inconsistent stack height: {0} != {1}", s1.stack.Count, s2.stack.Count));
+ }
+ InstructionState s = s1.Copy();
+ s.changed = s1.changed;
+ for(int i = 0; i < s.stack.Count; i++)
+ {
+ string type = (string)s.stack[i];
+ if(type == (string)s2.stack[i])
+ {
+ // perfect match, nothing to do
+ }
+ else if(type[0] == 'L' || type[0] == '[' || type[0] == 'U' || type[0] == 'N')
+ {
+ string baseType = s.FindCommonBaseType(type, (string)s2.stack[i]);
+ if(type != baseType)
+ {
+ s.stack[i] = baseType;
+ s.changed = true;
+ }
+ }
+ else
+ {
+ throw new VerifyError(string.Format("cannot merge {0} and {1}", type, s2.stack[i]));
+ }
+ }
+ for(int i = 0; i < s.locals.Length; i++)
+ {
+ string type = s.locals[i];
+ string type2;
+ if(locals_modified == null || locals_modified[i])
+ {
+ type2 = s2.locals[i];
+ }
+ else
+ {
+ type2 = s3.locals[i];
+ }
+ if(type == type2)
+ {
+ // perfect match, nothing to do
+ }
+ else if(type != null)
+ {
+ if(type[0] == 'L' || type[0] == '[' || type[0] == 'U' || type[0] == 'N')
+ {
+ string baseType = s2.FindCommonBaseType(type, type2);
+ if(type != baseType)
+ {
+ s.locals[i] = baseType;
+ s.changed = true;
+ }
+ }
+ else
+ {
+ // mark the slot as invalid
+ s.locals[i] = null;
+ s.changed = true;
+ }
+ }
+ }
+ foreach(Subroutine ss2 in s2.subroutines)
+ {
+ bool found = false;
+ foreach(Subroutine ss in s.subroutines)
+ {
+ if(ss.SubroutineIndex == ss2.SubroutineIndex)
+ {
+ for(int i = 0; i < ss.LocalsModified.Length; i++)
+ {
+ if(ss2.LocalsModified[i] && !ss.LocalsModified[i])
+ {
+ ss.LocalsModified[i] = true;
+ s.changed = true;
+ }
+ }
+ found = true;
+ }
+ }
+ if(!found)
+ {
+ s.subroutines.Add(ss2.Copy());
+ s.changed = true;
+ }
+ }
+ if(s2.callsites > s.callsites)
+ {
+ //Console.WriteLine("s2.callsites = {0}, s.callsites = {1}", s2.callsites, s.callsites);
+ s.callsites = s2.callsites;
+ s.changed = true;
+ }
+ return s;
+ }
+
+ internal void AddCallSite()
+ {
+ callsites++;
+ changed = true;
+ }
+
+ internal void SetSubroutineId(int subroutineIndex)
+ {
+ foreach(Subroutine s in subroutines)
+ {
+ if(s.SubroutineIndex == subroutineIndex)
+ {
+ // subroutines cannot recursivly call themselves
+ throw new VerifyError("subroutines cannot recurse");
+ }
+ }
+ subroutines.Add(new Subroutine(subroutineIndex, locals.Length));
+ }
+
+ internal bool[] ClearSubroutineId(int subroutineIndex)
+ {
+ foreach(Subroutine s in subroutines)
+ {
+ if(s.SubroutineIndex == subroutineIndex)
+ {
+ subroutines.Remove(s);
+ return s.LocalsModified;
+ }
+ }
+ throw new VerifyError();
+ }
+
+ internal void CheckSubroutineActive(int subroutineIndex)
+ {
+ foreach(Subroutine s in subroutines)
+ {
+ if(s.SubroutineIndex == subroutineIndex)
+ {
+ return;
+ }
+ }
+ throw new VerifyError();
+ }
+
+ private bool IsSubType(string subType, string baseType)
+ {
+ if(subType == baseType)
+ {
+ return true;
+ }
+ if(subType.Length == 1 || baseType.Length == 1)
+ {
+ // primitives can never be subtypes of another type
+ return false;
+ }
+ if(baseType == "Ljava/lang/Object;")
+ {
+ return true;
+ }
+ if(baseType[0] == '[')
+ {
+ if(subType[0] != '[')
+ {
+ return false;
+ }
+ int subDepth = 0;
+ while(subType[subDepth] == '[')
+ {
+ subDepth++;
+ }
+ int baseDepth = 0;
+ while(baseType[baseDepth] == '[')
+ {
+ baseDepth++;
+ }
+ if(baseDepth > subDepth)
+ {
+ return false;
+ }
+ if(subType[subDepth] == baseType[baseDepth])
+ {
+ if(subType[subDepth] != 'L')
+ {
+ return baseDepth == subDepth;
+ }
+ string baseElemType = baseType.Substring(baseDepth + 1, baseType.Length - baseDepth - 2);
+ if(baseElemType == "java/lang/Object")
+ {
+ return true;
+ }
+ if(baseDepth == subDepth)
+ {
+ string subElemType = subType.Substring(subDepth + 1, subType.Length - subDepth - 2);
+ return ma.classLoader.IsSubType(subElemType, baseElemType);
+ }
+ }
+ return false;
+ }
+ else if(subType[0] == '[')
+ {
+ return false;
+ }
+ return ma.classLoader.IsSubType(subType.Substring(1, subType.Length - 2), baseType.Substring(1, baseType.Length - 2));
+ }
+
+ internal string FindCommonBaseType(string type1, string type2)
+ {
+// Console.WriteLine("FindCommonBaseType: {0} v {1}", type1, type2);
+ if(type1 == "Lnull")
+ {
+ return type2;
+ }
+ if(type2 == "Lnull")
+ {
+ return type1;
+ }
+ if(type1 == type2)
+ {
+ return type1;
+ }
+ if(type1 == null || type2 == null)
+ {
+ return null;
+ }
+ if(type1.Length == 1 || type2.Length == 1)
+ {
+ return null;
+ }
+ if(type1[0] == '[' || type2[0] == '[')
+ {
+ int rank1 = 0;
+ while(type1[rank1] == '[')
+ {
+ rank1++;
+ }
+ int rank2 = 0;
+ while(type2[rank2] == '[')
+ {
+ rank2++;
+ }
+ if(rank1 == 0 || rank2 == 0)
+ {
+ return "Ljava/lang/Object;";
+ }
+ if(rank1 != rank2)
+ {
+ if(rank1 > rank2)
+ {
+ int temp = rank1;
+ rank1 = rank2;
+ rank2 = temp;
+ string temps = type1;
+ type1 = type2;
+ type2 = temps;
+ }
+ if(type1.EndsWith("Ljava/lang/Object;"))
+ {
+ return type1;
+ }
+ return "Ljava/lang/Object;";
+ }
+ else
+ {
+ if(type1[rank1] != type2[rank1])
+ {
+ // two different primitive arrays, or a primitive and a reference array
+ return "Ljava/lang/Object;";
+ }
+ return new String('[', rank1) + "L" + ma.classLoader.FindCommonBaseType(type1.Substring(1 + rank1, type1.Length - (2 + rank1)), type2.Substring(1 + rank2, type2.Length - (2 + rank2))) + ";";
+ }
+ }
+ if(type1.StartsWith("Lret;") || type2.StartsWith("Lret;"))
+ {
+ return null;
+ }
+ return "L" + ma.classLoader.FindCommonBaseType(type1.Substring(1, type1.Length - 2), type2.Substring(1, type2.Length - 2)) + ";";
+ }
+
+ private void SetLocal1(int index, string type)
+ {
+ if(index > 0 && (locals[index] == "D2" || locals[index] == "J2"))
+ {
+ locals[index - 1] = null;
+ }
+ locals[index] = type;
+ foreach(Subroutine s in subroutines)
+ {
+ s.SetLocalModified(index);
+ }
+ }
+
+ private void SetLocal2(int index, string type)
+ {
+ if(index > 0 && (locals[index] == "D2" || locals[index] == "J2"))
+ {
+ locals[index - 1] = null;
+ }
+ locals[index] = type;
+ locals[index + 1] = type[0] == 'D' ? "D2" : "J2";
+ foreach(Subroutine s in subroutines)
+ {
+ s.SetLocalModified(index);
+ s.SetLocalModified(index + 1);
+ }
+ }
+
+ internal void GetLocalInt(int index)
+ {
+ if(locals[index] != "I")
+ {
+ throw new VerifyError("Invalid local type");
+ }
+ }
+
+ internal void SetLocalInt(int index)
+ {
+ SetLocal1(index, "I");
+ }
+
+ internal void SetLocalLong(int index)
+ {
+ SetLocal2(index, "J");
+ }
+
+ internal void GetLocalLong(int index)
+ {
+ if(locals[index] != "J" || locals[index + 1] != "J2")
+ {
+ throw new VerifyError();
+ }
+ }
+
+ internal void GetLocalFloat(int index)
+ {
+ if(locals[index] != "F")
+ {
+ throw new VerifyError();
+ }
+ }
+
+ internal void SetLocalFloat(int index)
+ {
+ SetLocal1(index, "F");
+ }
+
+ internal void SetLocalDouble(int index)
+ {
+ SetLocal2(index, "D");
+ }
+
+ internal void GetLocalDouble(int index)
+ {
+ if(locals[index] != "D" || locals[index + 1] != "D2")
+ {
+ throw new VerifyError();
+ }
+ }
+
+ internal string GetLocalType(int index)
+ {
+ return locals[index];
+ }
+
+ internal int GetLocalRet(int index)
+ {
+ string type = locals[index];
+ if(!type.StartsWith("Lret;"))
+ {
+ throw new VerifyError();
+ }
+ return int.Parse(type.Substring(5));
+ }
+
+ internal string GetLocalObject(int index)
+ {
+ string s = locals[index];
+ if(s == null || (s[0] != 'L' && s[0] != '[' && s[0] != 'U' && s[0] != 'N') || s.StartsWith("Lret;"))
+ {
+ throw new VerifyError();
+ }
+ return s;
+ }
+
+ internal void SetLocalObject(int index, string type)
+ {
+ if(type[0] != 'L' && type[0] != '[' && type[0] != 'U' && type[0] != 'N')
+ {
+ throw new VerifyError();
+ }
+ SetLocal1(index, type);
+ }
+
+ internal void Push(string type)
+ {
+ if(type.Length == 1)
+ {
+ switch(type[0])
+ {
+ case 'Z':
+ case 'B':
+ case 'C':
+ case 'S':
+ type = "I";
+ break;
+ }
+ }
+ PushHelper(type);
+ }
+
+ internal void PushObject(string type)
+ {
+ if(type == null)
+ {
+ throw new VerifyError();
+ }
+ if(type[0] == 'L' || type[0] == '[' || type[0] == 'U' || type[0] == 'N')
+ {
+ PushHelper(type);
+ return;
+ }
+ throw new VerifyError();
+ }
+
+ internal void PushInt()
+ {
+ PushHelper("I");
+ }
+
+ internal void PushLong()
+ {
+ PushHelper("J");
+ }
+
+ internal void PushFloat()
+ {
+ PushHelper("F");
+ }
+
+ internal void PushDouble()
+ {
+ PushHelper("D");
+ }
+
+ internal void PopInt()
+ {
+ Pop('I');
+ }
+
+ internal void PopFloat()
+ {
+ Pop('F');
+ }
+
+ internal void PopDouble()
+ {
+ Pop('D');
+ }
+
+ internal void PopLong()
+ {
+ Pop('J');
+ }
+
+ internal string PopArray()
+ {
+ string s = PopHelper();
+ if(s[0] == '[' || s == "Lnull")
+ {
+ return s;
+ }
+ throw new VerifyError("Array type expected");
+ }
+
+ internal string PopUninitializedObject(string type)
+ {
+ string s = PopHelper();
+ string u = s;
+ if(s[0] != 'U' && s[0] != 'N')
+ {
+ throw new VerifyError("Expecting to find unitialized object on stack");
+ }
+ s = s.Substring(s.IndexOf(';') + 1);
+ if(s != type)
+ {
+ if(IsSubType(s, type))
+ {
+ // OK
+ }
+ else
+ {
+ throw new VerifyError(string.Format("popped {0} and expected {1}", s, type));
+ }
+ }
+ return u;
+ }
+
+ internal void Pop(string type)
+ {
+ if(type.Length == 1)
+ {
+ switch(type[0])
+ {
+ case 'Z':
+ case 'B':
+ case 'C':
+ case 'S':
+ Pop('I');
+ return;
+ }
+ }
+ string s = PopHelper();
+ if(s != type)
+ {
+ if((type[0] == 'L' || type[0] == '[') && s == "Lnull")
+ {
+ }
+ else if(IsSubType(s, type))
+ {
+ }
+ else
+ {
+ throw new VerifyError(string.Format("popped {0} and expected {1}", s, type));
+ }
+ }
+ }
+
+ internal string PopObject(string type)
+ {
+ string s = PopHelper();
+ if(s != type)
+ {
+ if(s == "Lnull")
+ {
+ // null can be used as any type
+ }
+ else if(s[0] == 'N' || s[0] == 'U')
+ {
+ throw new VerifyError("Unexpected unitialized objref " + s);
+ }
+ else if(IsSubType(s, type))
+ {
+ // OK
+ }
+ else
+ {
+ throw new VerifyError(string.Format("popped {0} and expected {1}", s, type));
+ }
+ }
+ return s;
+ }
+
+ internal string PopAny()
+ {
+ return PopHelper();
+ }
+
+ internal string Pop()
+ {
+ string type = PopHelper();
+ if(type == "D" || type == "J")
+ {
+ throw new VerifyError("Attempt to split long or double on the stack");
+ }
+ return type;
+ }
+
+ internal string Pop2()
+ {
+ string type = PopHelper();
+ if(type == "D" || type == "J")
+ {
+ return type;
+ }
+ type = PopHelper();
+ if(type == "D" || type == "J")
+ {
+ throw new VerifyError("Attempt to split long or double on the stack");
+ }
+ return type;
+ }
+
+ internal int GetStackHeight()
+ {
+ return stack.Count;
+ }
+
+ internal string GetStackSlot(int pos)
+ {
+ return (string)stack[stack.Count - 1 - pos];
+ }
+
+ internal string Peek()
+ {
+ if(stack.Count == 0)
+ {
+ // return null, if the stack is empty
+ return null;
+ }
+ return (string)stack[stack.Count - 1];
+ }
+
+ private string PopHelper()
+ {
+ if(stack.Count == 0)
+ {
+ throw new VerifyError("Unable to pop operand off an empty stack");
+ }
+ string s = (string)stack[stack.Count - 1];
+ stack.RemoveAt(stack.Count - 1);
+ return s;
+ }
+
+ private void PushHelper(string s)
+ {
+ if(s.IndexOf("L[") >= 0)
+ {
+ throw new VerifyError("Internal error: L[ type found");
+ }
+ stack.Add(s);
+ }
+
+ private string Pop(char type)
+ {
+ string s = PopHelper();
+ if(s[0] != type)
+ {
+ switch(type)
+ {
+ case 'I':
+ throw new VerifyError("Expecting to find int on stack");
+ case '[':
+ throw new VerifyError("Expecting to find array on stack");
+ case 'L':
+ throw new VerifyError("Expecting to find object on stack");
+ case 'F':
+ throw new VerifyError("Expecting to find float on stack");
+ case 'D':
+ throw new VerifyError("Expecting to find double on stack");
+ case 'J':
+ throw new VerifyError("Expecting to find long on stack");
+ default:
+ throw new VerifyError("Expecting to find " + type + " on stack");
+ }
+ }
+ return s;
+ }
+
+ internal void MarkInitialized(string type)
+ {
+ string initType = type.Substring(type.IndexOf(';') + 1);
+ for(int i = 0; i < locals.Length; i++)
+ {
+ if(locals[i] == type)
+ {
+ locals[i] = initType;
+ }
+ }
+ for(int i = 0; i < stack.Count; i++)
+ {
+ if((string)stack[i] == type)
+ {
+ stack[i] = initType;
+ }
+ }
+ }
+
+ internal void DumpLocals()
+ {
+ Console.Write("// ");
+ string sep = "";
+ for(int i = 0; i < locals.Length; i++)
+ {
+ Console.Write(sep);
+ Console.Write(locals[i]);
+ sep = ", ";
+ }
+ Console.WriteLine();
+ }
+
+ internal void DumpStack()
+ {
+ Console.Write("// ");
+ string sep = "";
+ for(int i = 0; i < stack.Count; i++)
+ {
+ Console.Write(sep);
+ Console.Write(stack[i]);
+ sep = ", ";
+ }
+ Console.WriteLine();
+ }
+
+ // this method ensures that no uninitialized object are in the locals for the current state
+ internal void CheckLocalsForUninitializedObjRefs()
+ {
+ for(int i = 0; i < locals.Length; i++)
+ {
+ if(locals[i] != null && (((locals[i])[0] == 'U') || ((locals[i])[0] == 'N')))
+ {
+ throw new VerifyError();
+ }
+ }
+ }
+
+ // this method ensures that no uninitialized object are in the current state
+ internal void CheckUninitializedObjRefs()
+ {
+ for(int i = 0; i < locals.Length; i++)
+ {
+ if(locals[i] != null && (((locals[i])[0] == 'U') || ((locals[i])[0] == 'N')))
+ {
+ throw new VerifyError();
+ }
+ }
+ for(int i = 0; i < stack.Count; i++)
+ {
+ if((((string)stack[i])[0] == 'U') || (((string)stack[i])[0] == 'N'))
+ {
+ throw new VerifyError();
+ }
+ }
+ }
+
+ // this method ensures that no uninitialized objects, of the specified type are in the current state
+ internal void CheckUninitializedObjRefs(string type)
+ {
+ for(int i = 0; i < locals.Length; i++)
+ {
+ if(locals[i] == type)
+ {
+ throw new VerifyError();
+ }
+ }
+ for(int i = 0; i < stack.Count; i++)
+ {
+ if((string)stack[i] == type)
+ {
+ throw new VerifyError();
+ }
+ }
+ }
+}
+
+class SigEnumerator
+{
+ private string sig;
+ private int pos;
+ private int length;
+
+ internal SigEnumerator(string sig)
+ {
+ this.sig = sig;
+ pos = 1;
+ length = 0;
+ }
+
+ internal bool MoveNext()
+ {
+ pos += length;
+ switch(sig[pos])
+ {
+ case 'L':
+ {
+ length = sig.IndexOf(';', pos) - pos + 1;
+ break;
+ }
+ case '[':
+ {
+ length = 0;
+ while(sig[pos + length] == '[') length++;
+ if(sig[pos + length] == 'L')
+ {
+ length = sig.IndexOf(';', pos) - pos;
+ }
+ length++;
+ break;
+ }
+ case ')':
+ length = 0;
+ return false;
+ default:
+ length = 1;
+ break;
+ }
+ return true;
+ }
+
+ internal string Current
+ {
+ get
+ {
+ return sig.Substring(pos, length);
+ }
+ }
+}
+
+class ReverseSigEnumerator
+{
+ private string[] items;
+ private int pos;
+
+ internal ReverseSigEnumerator(string sig)
+ {
+ ArrayList ar = new ArrayList();
+ SigEnumerator se = new SigEnumerator(sig);
+ while(se.MoveNext())
+ {
+ ar.Add(se.Current);
+ }
+ items = new String[ar.Count];
+ ar.CopyTo(items);
+ pos = items.Length;
+ }
+
+ internal bool MoveNext()
+ {
+ pos--;
+ return pos >= 0;
+ }
+
+ internal string Current
+ {
+ get
+ {
+ return items[pos];
+ }
+ }
+}
+
+class MethodAnalyzer
+{
+ internal readonly ClassLoaderWrapper classLoader;
+ private ClassFile.Method.Code method;
+ private InstructionState[] state;
+ private ArrayList[] callsites;
+ private string[] localTypes;
+
+ internal MethodAnalyzer(ClassFile.Method.Code method, ClassLoaderWrapper classLoader)
+ {
+ this.classLoader = classLoader;
+ this.method = method;
+ state = new InstructionState[method.Instructions.Length];
+ callsites = new ArrayList[method.Instructions.Length];
+ localTypes = new String[method.MaxLocals];
+
+ // start by computing the initial state, the stack is empty and the locals contain the arguments
+ state[0] = new InstructionState(this, method.MaxLocals);
+ int arg = 0;
+ if(!method.Method.IsStatic)
+ {
+ // this reference. If we're a constructor, the this reference is uninitialized.
+ if(method.Method.Name == "<init>")
+ {
+ state[0].SetLocalObject(arg++, "U0;L" + method.Method.ClassFile.Name + ";");
+ }
+ else
+ {
+ state[0].SetLocalObject(arg++, "L" + method.Method.ClassFile.Name + ";");
+ }
+ }
+ string sig = method.Method.Signature;
+ for(int i = 1; sig[i] != ')'; i++)
+ {
+ switch(sig[i])
+ {
+ case 'D':
+ state[0].SetLocalDouble(arg);
+ arg += 2;
+ break;
+ case 'J':
+ state[0].SetLocalLong(arg);
+ arg += 2;
+ break;
+ case 'L':
+ {
+ int pos = sig.IndexOf(';', i);
+ state[0].SetLocalObject(arg++, sig.Substring(i, pos - i + 1));
+ i = pos;
+ break;
+ }
+ case '[':
+ {
+ int start = i;
+ while(sig[i] == '[') i++;
+ if(sig[i] == 'L')
+ {
+ i = sig.IndexOf(';', i);
+ }
+ state[0].SetLocalObject(arg++, sig.Substring(start, i - start + 1));
+ break;
+ }
+ case 'F':
+ state[0].SetLocalFloat(arg++);
+ break;
+ case 'Z':
+ case 'B':
+ case 'S':
+ case 'C':
+ case 'I':
+ state[0].SetLocalInt(arg++);
+ break;
+ default:
+ throw new NotImplementedException();
+ }
+ }
+ bool done = false;
+ while(!done)
+ {
+ done = true;
+ for(int i = 0; i < method.Instructions.Length; i++)
+ {
+ if(state[i] != null && state[i].changed)
+ {
+ try
+ {
+ //Console.WriteLine(method.Instructions[i].PC + ": " + method.Instructions[i].OpCode.ToString());
+ done = false;
+ state[i].changed = false;
+ // mark the exception handlers reachable from this instruction
+ for(int j = 0; j < method.ExceptionTable.Length; j++)
+ {
+ if(method.ExceptionTable[j].start_pc <= method.Instructions[i].PC && method.ExceptionTable[j].end_pc > method.Instructions[i].PC)
+ {
+ state[i].CheckLocalsForUninitializedObjRefs();
+ InstructionState ex = state[i].CopyLocalsAndSubroutines();
+ int catch_type = method.ExceptionTable[j].catch_type;
+ if(catch_type == 0)
+ {
+ ex.PushObject("Ljava/lang/Throwable;");
+ }
+ else
+ {
+ ex.PushObject("L" + GetConstantPoolClass(catch_type) + ";");
+ }
+ int idx = method.PcIndexMap[method.ExceptionTable[j].handler_pc];
+ state[idx] += ex;
+ }
+ }
+ InstructionState s = state[i].Copy();
+ ClassFile.Method.Instruction instr = method.Instructions[i];
+ switch(instr.NormalizedOpCode)
+ {
+ case NormalizedByteCode.__aload:
+ s.PushObject(s.GetLocalObject(instr.NormalizedArg1));
+ break;
+ case NormalizedByteCode.__astore:
+ {
+ string type = s.Pop();
+ switch(type[0])
+ {
+ case 'L':
+ case '[':
+ case 'N':
+ case 'U':
+ s.SetLocalObject(instr.NormalizedArg1, type);
+ break;
+ default:
+ throw new VerifyError("Object reference expected");
+ }
+ break;
+ }
+ case NormalizedByteCode.__aconst_null:
+ s.PushObject("Lnull");
+ break;
+ case NormalizedByteCode.__aaload:
+ {
+ s.PopInt();
+ string type = s.PopArray();
+ if(type == "Lnull")
+ {
+ // if the array is null, we have use null as the element type, because
+ // otherwise the rest of the code will not verify correctly
+ s.PushObject(type);
+ }
+ else
+ {
+ s.PushObject(type.Substring(1));
+ }
+ break;
+ }
+ case NormalizedByteCode.__aastore:
+ {
+ string elem = s.PopObject("Ljava/lang/Object;");
+ s.PopInt();
+ string type = s.PopArray();
+ // TODO check that elem is assignable to the array
+ break;
+ }
+ case NormalizedByteCode.__baload:
+ {
+ s.PopInt();
+ string type = s.PopArray();
+ if(type[1] != 'B' && type[1] != 'Z' && type != "Lnull")
+ {
+ throw new VerifyError();
+ }
+ s.PushInt();
+ break;
+ }
+ case NormalizedByteCode.__bastore:
+ {
+ s.PopInt();
+ s.PopInt();
+ string type = s.PopArray();
+ if(type[1] != 'B' && type[1] != 'Z' && type != "Lnull")
+ {
+ throw new VerifyError();
+ }
+ break;
+ }
+ case NormalizedByteCode.__caload:
+ s.PopInt();
+ s.PopObject("[C");
+ s.PushInt();
+ break;
+ case NormalizedByteCode.__castore:
+ s.PopInt();
+ s.PopInt();
+ s.PopObject("[C");
+ break;
+ case NormalizedByteCode.__saload:
+ s.PopInt();
+ s.PopObject("[S");
+ s.PushInt();
+ break;
+ case NormalizedByteCode.__sastore:
+ s.PopInt();
+ s.PopInt();
+ s.PopObject("[S");
+ break;
+ case NormalizedByteCode.__iaload:
+ s.PopInt();
+ s.PopObject("[I");
+ s.PushInt();
+ break;
+ case NormalizedByteCode.__iastore:
+ s.PopInt();
+ s.PopInt();
+ s.PopObject("[I");
+ break;
+ case NormalizedByteCode.__laload:
+ s.PopInt();
+ s.PopObject("[J");
+ s.PushLong();
+ break;
+ case NormalizedByteCode.__lastore:
+ s.PopLong();
+ s.PopInt();
+ s.PopObject("[J");
+ break;
+ case NormalizedByteCode.__daload:
+ s.PopInt();
+ s.PopObject("[D");
+ s.PushDouble();
+ break;
+ case NormalizedByteCode.__dastore:
+ s.PopDouble();
+ s.PopInt();
+ s.PopObject("[D");
+ break;
+ case NormalizedByteCode.__faload:
+ s.PopInt();
+ s.PopObject("[F");
+ s.PushFloat();
+ break;
+ case NormalizedByteCode.__fastore:
+ s.PopFloat();
+ s.PopInt();
+ s.PopObject("[F");
+ break;
+ case NormalizedByteCode.__arraylength:
+ s.PopArray();
+ s.PushInt();
+ break;
+ case NormalizedByteCode.__iconst:
+ s.PushInt();
+ break;
+ case NormalizedByteCode.__if_icmpeq:
+ case NormalizedByteCode.__if_icmpne:
+ case NormalizedByteCode.__if_icmplt:
+ case NormalizedByteCode.__if_icmpge:
+ case NormalizedByteCode.__if_icmpgt:
+ case NormalizedByteCode.__if_icmple:
+ s.PopInt();
+ s.PopInt();
+ break;
+ case NormalizedByteCode.__ifeq:
+ case NormalizedByteCode.__ifge:
+ case NormalizedByteCode.__ifgt:
+ case NormalizedByteCode.__ifle:
+ case NormalizedByteCode.__iflt:
+ case NormalizedByteCode.__ifne:
+ s.PopInt();
+ break;
+ case NormalizedByteCode.__ifnonnull:
+ case NormalizedByteCode.__ifnull:
+ s.PopObject("Ljava/lang/Object;");
+ break;
+ case NormalizedByteCode.__if_acmpeq:
+ case NormalizedByteCode.__if_acmpne:
+ s.PopObject("Ljava/lang/Object;");
+ s.PopObject("Ljava/lang/Object;");
+ break;
+ case NormalizedByteCode.__getstatic:
+ s.Push((GetFieldref(instr.Arg1)).Signature);
+ break;
+ case NormalizedByteCode.__putstatic:
+ {
+ // HACK because of the way interface merging works, if the
+ // type on the stack is Object, it can be assigned to anything
+ // (the compiler will emit a cast)
+ string type = (GetFieldref(instr.Arg1)).Signature;
+ if(type[0] == 'L' && s.Peek() == "Ljava/lang/Object;")
+ {
+ s.Pop();
+ }
+ else
+ {
+ s.Pop(type);
+ }
+ break;
+ }
+ case NormalizedByteCode.__getfield:
+ s.PopObject("L" + (GetFieldref(instr.Arg1)).Class + ";");
+ s.Push((GetFieldref(instr.Arg1)).Signature);
+ break;
+ case NormalizedByteCode.__putfield:
+ {
+ // HACK because of the way interface merging works, if the
+ // type on the stack is Object, it can be assigned to anything
+ // (the compiler will emit a cast)
+ string type = (GetFieldref(instr.Arg1)).Signature;
+ if(type[0] == 'L' && s.Peek() == "Ljava/lang/Object;")
+ {
+ s.Pop();
+ }
+ else
+ {
+ s.Pop(type);
+ }
+ s.PopObject("L" + (GetFieldref(instr.Arg1)).Class + ";");
+ break;
+ }
+ case NormalizedByteCode.__ldc:
+ {
+ object o = GetConstantPoolConstant(instr.Arg1);
+ if(o is int)
+ {
+ s.PushInt();
+ }
+ else if(o is string)
+ {
+ s.PushObject("Ljava/lang/String;");
+ }
+ else if(o is long)
+ {
+ s.PushLong();
+ }
+ else if(o is float)
+ {
+ s.PushFloat();
+ }
+ else if(o is double)
+ {
+ s.PushDouble();
+ }
+ else
+ {
+ throw new InvalidOperationException(o.GetType().FullName);
+ }
+ break;
+ }
+ case NormalizedByteCode.__invokevirtual:
+ case NormalizedByteCode.__invokespecial:
+ case NormalizedByteCode.__invokeinterface:
+ case NormalizedByteCode.__invokestatic:
+ {
+ ClassFile.ConstantPoolItemFMI cpi = GetMethodref(instr.Arg1);
+ if((cpi is ClassFile.ConstantPoolItemInterfaceMethodref) != (instr.NormalizedOpCode == NormalizedByteCode.__invokeinterface))
+ {
+ throw new VerifyError("Illegal constant pool index");
+ }
+ if(instr.NormalizedOpCode != NormalizedByteCode.__invokespecial && cpi.Name == "<init>")
+ {
+ throw new VerifyError("Must call initializers using invokespecial");
+ }
+ if(cpi.Name == "<clinit>")
+ {
+ throw new VerifyError("Illegal call to internal method");
+ }
+ ReverseSigEnumerator rse = new ReverseSigEnumerator(cpi.Signature);
+ while(rse.MoveNext())
+ {
+ switch(rse.Current[0])
+ {
+ case 'Z':
+ case 'B':
+ case 'S':
+ case 'C':
+ case 'I':
+ s.PopInt();
+ break;
+ case 'J':
+ s.PopLong();
+ break;
+ case 'D':
+ s.PopDouble();
+ break;
+ case 'F':
+ s.PopFloat();
+ break;
+ case 'L':
+ case '[':
+ s.PopObject(rse.Current);
+ break;
+ default:
+ throw new NotImplementedException(rse.Current);
+ }
+ }
+ if(instr.NormalizedOpCode == NormalizedByteCode.__invokeinterface)
+ {
+ // TODO check arg (should match signature)
+ // error: "Inconsistent args size"
+ }
+ if(instr.NormalizedOpCode != NormalizedByteCode.__invokestatic)
+ {
+ if(cpi.Name == "<init>")
+ {
+ string type = s.PopUninitializedObject("L" + cpi.Class + ";");
+ if((type[0] == 'N' && !type.EndsWith("L" + cpi.Class + ";")) ||
+ (type[0] == 'U' && cpi.Class != method.Method.ClassFile.SuperClass && cpi.Class != method.Method.ClassFile.Name))
+ {
+ // TODO oddly enough, Java fails verification for the class without
+ // even running the constructor, so maybe constructors are always
+ // verified...
+ // NOTE when a constructor isn't verifiable, the static initializer
+ // doesn't run either (or so I believe)
+ throw new VerifyError("Call to wrong initialization method");
+ }
+ // after the constructor invocation, the uninitialized reference, is now
+ // suddenly initialized
+ s.MarkInitialized(type);
+ }
+ else
+ {
+ // NOTE previously we checked the type here, but it turns out that
+ // the JVM throws an IncompatibleClassChangeError at runtime instead
+ // of a VerifyError if this doesn't match
+ s.PopObject("Ljava/lang/Object;");
+ /*
+ string type = cpi.Class;
+ if(type[0] != '[')
+ {
+ type = "L" + type + ";";
+ }
+ // invokeinterface is allowed on java/lang/Object (because merging interfaces is
+ // complicated), this will generate a runtime cast in the compiler
+ if(instr.NormalizedOpCode == NormalizedByteCode.__invokeinterface &&
+ s.Peek() == "Ljava/lang/Object;")
+ {
+ s.PopAny();
+ }
+ else
+ {
+ // TODO if this fails it shouldn't generate a VerifyError, but instead
+ // an IncompatibleClassChangeError (at run time)
+ s.PopObject(type);
+ }
+ */
+ }
+ }
+ string ret = cpi.Signature.Substring(cpi.Signature.IndexOf(')') + 1);
+ switch(ret[0])
+ {
+ case 'Z':
+ case 'B':
+ case 'S':
+ case 'C':
+ case 'I':
+ s.PushInt();
+ break;
+ case 'J':
+ s.PushLong();
+ break;
+ case 'D':
+ s.PushDouble();
+ break;
+ case 'F':
+ s.PushFloat();
+ break;
+ case 'L':
+ case '[':
+ s.PushObject(ret);
+ break;
+ case 'V':
+ break;
+ default:
+ throw new NotImplementedException(ret);
+ }
+ break;
+ }
+ case NormalizedByteCode.__goto:
+ break;
+ case NormalizedByteCode.__istore:
+ s.PopInt();
+ s.SetLocalInt(instr.NormalizedArg1);
+ break;
+ case NormalizedByteCode.__iload:
+ s.GetLocalInt(instr.NormalizedArg1);
+ s.PushInt();
+ break;
+ case NormalizedByteCode.__ineg:
+ s.PopInt();
+ s.PushInt();
+ break;
+ case NormalizedByteCode.__iadd:
+ case NormalizedByteCode.__isub:
+ case NormalizedByteCode.__imul:
+ case NormalizedByteCode.__idiv:
+ case NormalizedByteCode.__irem:
+ case NormalizedByteCode.__iand:
+ case NormalizedByteCode.__ior:
+ case NormalizedByteCode.__ixor:
+ case NormalizedByteCode.__ishl:
+ case NormalizedByteCode.__ishr:
+ case NormalizedByteCode.__iushr:
+ s.PopInt();
+ s.PopInt();
+ s.PushInt();
+ break;
+ case NormalizedByteCode.__lneg:
+ s.PopLong();
+ s.PushLong();
+ break;
+ case NormalizedByteCode.__ladd:
+ case NormalizedByteCode.__lsub:
+ case NormalizedByteCode.__lmul:
+ case NormalizedByteCode.__ldiv:
+ case NormalizedByteCode.__lrem:
+ case NormalizedByteCode.__land:
+ case NormalizedByteCode.__lor:
+ case NormalizedByteCode.__lxor:
+ s.PopLong();
+ s.PopLong();
+ s.PushLong();
+ break;
+ case NormalizedByteCode.__lshl:
+ case NormalizedByteCode.__lshr:
+ case NormalizedByteCode.__lushr:
+ s.PopInt();
+ s.PopLong();
+ s.PushLong();
+ break;
+ case NormalizedByteCode.__fneg:
+ s.PopFloat();
+ s.PushFloat();
+ break;
+ case NormalizedByteCode.__fadd:
+ case NormalizedByteCode.__fsub:
+ case NormalizedByteCode.__fmul:
+ case NormalizedByteCode.__fdiv:
+ case NormalizedByteCode.__frem:
+ s.PopFloat();
+ s.PopFloat();
+ s.PushFloat();
+ break;
+ case NormalizedByteCode.__dneg:
+ s.PopDouble();
+ s.PushDouble();
+ break;
+ case NormalizedByteCode.__dadd:
+ case NormalizedByteCode.__dsub:
+ case NormalizedByteCode.__dmul:
+ case NormalizedByteCode.__ddiv:
+ case NormalizedByteCode.__drem:
+ s.PopDouble();
+ s.PopDouble();
+ s.PushDouble();
+ break;
+ case NormalizedByteCode.__new:
+ // mark the type, so that we can ascertain that it is a "new object"
+ s.PushObject(string.Format("N{0};L{1};", instr.PC, GetConstantPoolClass(instr.Arg1)));
+ break;
+ case NormalizedByteCode.__multianewarray:
+ {
+ if(instr.Arg2 < 1)
+ {
+ throw new VerifyError("Illegal dimension argument");
+ }
+ for(int j = 0; j < instr.Arg2; j++)
+ {
+ s.PopInt();
+ }
+ string type = GetConstantPoolClass(instr.Arg1);
+ if(!type.StartsWith(new String('[', instr.Arg2)))
+ {
+ throw new VerifyError("Illegal dimension argument");
+ }
+ s.PushObject(type);
+ break;
+ }
+ case NormalizedByteCode.__anewarray:
+ {
+ s.PopInt();
+ string type = GetConstantPoolClass(instr.Arg1);
+ if(type[0] != '[')
+ {
+ type = "L" + type + ";";
+ }
+ s.PushObject("[" + type);
+ break;
+ }
+ case NormalizedByteCode.__newarray:
+ s.PopInt();
+ switch(instr.Arg1)
+ {
+ case 4:
+ s.PushObject("[Z");
+ break;
+ case 5:
+ s.PushObject("[C");
+ break;
+ case 6:
+ s.PushObject("[F");
+ break;
+ case 7:
+ s.PushObject("[D");
+ break;
+ case 8:
+ s.PushObject("[B");
+ break;
+ case 9:
+ s.PushObject("[S");
+ break;
+ case 10:
+ s.PushObject("[I");
+ break;
+ case 11:
+ s.PushObject("[J");
+ break;
+ default:
+ throw new VerifyError("Bad type");
+ }
+ break;
+ case NormalizedByteCode.__swap:
+ {
+ string t1 = s.Pop();
+ string t2 = s.Pop();
+ s.Push(t1);
+ s.Push(t2);
+ break;
+ }
+ case NormalizedByteCode.__dup:
+ {
+ string t = s.Pop();
+ s.Push(t);
+ s.Push(t);
+ break;
+ }
+ case NormalizedByteCode.__dup2:
+ {
+ string t = s.PopAny();
+ if(t == "D" || t == "J")
+ {
+ s.Push(t);
+ s.Push(t);
+ }
+ else
+ {
+ string t2 = s.Pop();
+ s.Push(t2);
+ s.Push(t);
+ s.Push(t2);
+ s.Push(t);
+ }
+ break;
+ }
+ case NormalizedByteCode.__dup_x1:
+ {
+ string value1 = s.Pop();
+ string value2 = s.Pop();
+ s.Push(value1);
+ s.Push(value2);
+ s.Push(value1);
+ break;
+ }
+ case NormalizedByteCode.__dup2_x1:
+ {
+ string value1 = s.PopAny();
+ if(value1 == "D" || value1 == "J")
+ {
+ string value2 = s.Pop();
+ s.Push(value1);
+ s.Push(value2);
+ s.Push(value1);
+ }
+ else
+ {
+ string value2 = s.Pop();
+ string value3 = s.Pop();
+ s.Push(value2);
+ s.Push(value1);
+ s.Push(value3);
+ s.Push(value2);
+ s.Push(value1);
+ }
+ break;
+ }
+ case NormalizedByteCode.__dup_x2:
+ {
+ string value1 = s.Pop();
+ string value2 = s.Pop();
+ string value3 = s.Pop();
+ s.Push(value1);
+ s.Push(value3);
+ s.Push(value2);
+ s.Push(value1);
+ break;
+ }
+ case NormalizedByteCode.__dup2_x2:
+ {
+ string value1 = s.PopAny();
+ if(value1 == "D" || value1 == "J")
+ {
+ string value2 = s.PopAny();
+ if(value2 == "D" || value2 == "J")
+ {
+ // Form 4
+ s.Push(value1);
+ s.Push(value2);
+ s.Push(value1);
+ }
+ else
+ {
+ // Form 2
+ string value3 = s.Pop();
+ s.Push(value1);
+ s.Push(value3);
+ s.Push(value2);
+ s.Push(value1);
+ }
+ }
+ else
+ {
+ string value2 = s.Pop();
+ string value3 = s.PopAny();
+ if(value3 == "D" || value3 == "J")
+ {
+ // Form 3
+ s.Push(value2);
+ s.Push(value1);
+ s.Push(value3);
+ s.Push(value2);
+ s.Push(value1);
+ }
+ else
+ {
+ // Form 4
+ string value4 = s.Pop();
+ s.Push(value2);
+ s.Push(value1);
+ s.Push(value4);
+ s.Push(value3);
+ s.Push(value2);
+ s.Push(value1);
+ }
+ }
+ break;
+ }
+ case NormalizedByteCode.__pop:
+ s.Pop();
+ break;
+ case NormalizedByteCode.__pop2:
+ s.Pop2();
+ break;
+ case NormalizedByteCode.__monitorenter:
+ case NormalizedByteCode.__monitorexit:
+ s.PopObject("Ljava/lang/Object;");
+ break;
+ case NormalizedByteCode.__return:
+ if(method.Method.Signature.Substring(method.Method.Signature.IndexOf(')') + 1) != "V")
+ {
+ throw new VerifyError("Wrong return type in function");
+ }
+ break;
+ case NormalizedByteCode.__areturn:
+ {
+ // HACK we always allow object, because if the return type is an interface, this is legal
+ if(s.Peek() == "Ljava/lang/Object;")
+ {
+ s.Pop();
+ }
+ else
+ {
+ s.PopObject(method.Method.Signature.Substring(method.Method.Signature.IndexOf(')') + 1));
+ }
+ break;
+ }
+ case NormalizedByteCode.__ireturn:
+ s.PopInt();
+ switch(method.Method.Signature.Substring(method.Method.Signature.IndexOf(')') + 1))
+ {
+ case "Z":
+ case "B":
+ case "S":
+ case "C":
+ case "I":
+ break;
+ default:
+ throw new VerifyError("Wrong return type in function");
+ }
+ break;
+ case NormalizedByteCode.__lreturn:
+ s.PopLong();
+ if(method.Method.Signature.Substring(method.Method.Signature.IndexOf(')') + 1) != "J")
+ {
+ throw new VerifyError("Wrong return type in function");
+ }
+ break;
+ case NormalizedByteCode.__freturn:
+ s.PopFloat();
+ if(method.Method.Signature.Substring(method.Method.Signature.IndexOf(')') + 1) != "F")
+ {
+ throw new VerifyError("Wrong return type in function");
+ }
+ break;
+ case NormalizedByteCode.__dreturn:
+ s.PopDouble();
+ if(method.Method.Signature.Substring(method.Method.Signature.IndexOf(')') + 1) != "D")
+ {
+ throw new VerifyError("Wrong return type in function");
+ }
+ break;
+ case NormalizedByteCode.__fload:
+ s.GetLocalFloat(instr.NormalizedArg1);
+ s.PushFloat();
+ break;
+ case NormalizedByteCode.__fstore:
+ s.PopFloat();
+ s.SetLocalFloat(instr.NormalizedArg1);
+ break;
+ case NormalizedByteCode.__dload:
+ s.GetLocalDouble(instr.NormalizedArg1);
+ s.PushDouble();
+ break;
+ case NormalizedByteCode.__dstore:
+ s.PopDouble();
+ s.SetLocalDouble(instr.NormalizedArg1);
+ break;
+ case NormalizedByteCode.__lload:
+ s.GetLocalLong(instr.NormalizedArg1);
+ s.PushLong();
+ break;
+ case NormalizedByteCode.__lstore:
+ s.PopLong();
+ s.SetLocalLong(instr.NormalizedArg1);
+ break;
+ case NormalizedByteCode.__lconst_0:
+ case NormalizedByteCode.__lconst_1:
+ s.PushLong();
+ break;
+ case NormalizedByteCode.__fconst_0:
+ case NormalizedByteCode.__fconst_1:
+ case NormalizedByteCode.__fconst_2:
+ s.PushFloat();
+ break;
+ case NormalizedByteCode.__dconst_0:
+ case NormalizedByteCode.__dconst_1:
+ s.PushDouble();
+ break;
+ case NormalizedByteCode.__lcmp:
+ s.PopLong();
+ s.PopLong();
+ s.PushInt();
+ break;
+ case NormalizedByteCode.__fcmpl:
+ case NormalizedByteCode.__fcmpg:
+ s.PopFloat();
+ s.PopFloat();
+ s.PushInt();
+ break;
+ case NormalizedByteCode.__dcmpl:
+ case NormalizedByteCode.__dcmpg:
+ s.PopDouble();
+ s.PopDouble();
+ s.PushInt();
+ break;
+ case NormalizedByteCode.__checkcast:
+ {
+ s.PopObject("Ljava/lang/Object;");
+ string type = GetConstantPoolClass(instr.Arg1);
+ if(type[0] != '[')
+ {
+ type = "L" + type + ";";
+ }
+ s.PushObject(type);
+ break;
+ }
+ case NormalizedByteCode.__instanceof:
+ s.PopObject("Ljava/lang/Object;");
+ s.PushInt();
+ break;
+ case NormalizedByteCode.__iinc:
+ s.GetLocalInt(instr.Arg1);
+ break;
+ case NormalizedByteCode.__athrow:
+ s.PopObject("Ljava/lang/Throwable;");
+ break;
+ case NormalizedByteCode.__lookupswitch:
+ s.PopInt();
+ break;
+ case NormalizedByteCode.__i2b:
+ s.PopInt();
+ s.PushInt();
+ break;
+ case NormalizedByteCode.__i2c:
+ s.PopInt();
+ s.PushInt();
+ break;
+ case NormalizedByteCode.__i2s:
+ s.PopInt();
+ s.PushInt();
+ break;
+ case NormalizedByteCode.__i2l:
+ s.PopInt();
+ s.PushLong();
+ break;
+ case NormalizedByteCode.__i2f:
+ s.PopInt();
+ s.PushFloat();
+ break;
+ case NormalizedByteCode.__i2d:
+ s.PopInt();
+ s.PushDouble();
+ break;
+ case NormalizedByteCode.__l2i:
+ s.PopLong();
+ s.PushInt();
+ break;
+ case NormalizedByteCode.__l2f:
+ s.PopLong();
+ s.PushFloat();
+ break;
+ case NormalizedByteCode.__l2d:
+ s.PopLong();
+ s.PushDouble();
+ break;
+ case NormalizedByteCode.__f2i:
+ s.PopFloat();
+ s.PushInt();
+ break;
+ case NormalizedByteCode.__f2l:
+ s.PopFloat();
+ s.PushLong();
+ break;
+ case NormalizedByteCode.__f2d:
+ s.PopFloat();
+ s.PushDouble();
+ break;
+ case NormalizedByteCode.__d2i:
+ s.PopDouble();
+ s.PushInt();
+ break;
+ case NormalizedByteCode.__d2f:
+ s.PopDouble();
+ s.PushFloat();
+ break;
+ case NormalizedByteCode.__d2l:
+ s.PopDouble();
+ s.PushLong();
+ break;
+ case NormalizedByteCode.__jsr:
+ // TODO make sure we're not calling a subroutine we're already in
+ break;
+ case NormalizedByteCode.__ret:
+ {
+ // TODO if we're returning from a higher level subroutine, invalidate
+ // all the intermediate return addresses
+ int subroutineIndex = s.GetLocalRet(instr.Arg1);
+ s.CheckSubroutineActive(subroutineIndex);
+ break;
+ }
+ case NormalizedByteCode.__nop:
+ break;
+ default:
+ throw new NotImplementedException(instr.NormalizedOpCode.ToString());
+ }
+ if(s.GetStackHeight() > method.MaxStack)
+ {
+ throw new VerifyError("Stack size too large");
+ }
+ try
+ {
+ // another big switch to handle the opcode targets
+ switch(instr.NormalizedOpCode)
+ {
+ case NormalizedByteCode.__lookupswitch:
+ for(int j = 0; j < instr.Values.Length; j++)
+ {
+ state[method.PcIndexMap[instr.PC + instr.TargetOffsets[j]]] += s;
+ }
+ state[method.PcIndexMap[instr.PC + instr.DefaultOffset]] += s;
+ break;
+ case NormalizedByteCode.__ifeq:
+ case NormalizedByteCode.__ifne:
+ case NormalizedByteCode.__iflt:
+ case NormalizedByteCode.__ifge:
+ case NormalizedByteCode.__ifgt:
+ case NormalizedByteCode.__ifle:
+ case NormalizedByteCode.__if_icmpeq:
+ case NormalizedByteCode.__if_icmpne:
+ case NormalizedByteCode.__if_icmplt:
+ case NormalizedByteCode.__if_icmpge:
+ case NormalizedByteCode.__if_icmpgt:
+ case NormalizedByteCode.__if_icmple:
+ case NormalizedByteCode.__if_acmpeq:
+ case NormalizedByteCode.__if_acmpne:
+ case NormalizedByteCode.__ifnull:
+ case NormalizedByteCode.__ifnonnull:
+ if(instr.Arg1 < 0)
+ {
+ // backward branches cannot have uninitialized objects on
+ // the stack or in local variables
+ s.CheckUninitializedObjRefs();
+ }
+ state[i + 1] += s;
+ state[method.PcIndexMap[instr.PC + instr.Arg1]] += s;
+ break;
+ case NormalizedByteCode.__goto:
+ if(instr.Arg1 < 0)
+ {
+ // backward branches cannot have uninitialized objects on
+ // the stack or in local variables
+ s.CheckUninitializedObjRefs();
+ }
+ state[method.PcIndexMap[instr.PC + instr.Arg1]] += s;
+ break;
+ case NormalizedByteCode.__jsr:
+ {
+ int index = method.PcIndexMap[instr.PC + instr.Arg1];
+ s.Push("Lret;" + index);
+ s.SetSubroutineId(index);
+ state[index] += s;
+ AddCallSite(index, i);
+ break;
+ }
+ case NormalizedByteCode.__ret:
+ {
+ // HACK if the ret is processed before all of the jsr instructions to this subroutine
+ // we wouldn't be able to properly merge, so that is why we track the number of callsites
+ // for each subroutine instruction (see Instruction.AddCallSite())
+ int subroutineIndex = s.GetLocalRet(instr.Arg1);
+ int[] cs = GetCallSites(subroutineIndex);
+ bool[] locals_modified = s.ClearSubroutineId(subroutineIndex);
+ for(int j = 0; j < cs.Length; j++)
+ {
+ state[cs[j] + 1] = InstructionState.Merge(state[cs[j] + 1], s, locals_modified, state[cs[j]]);
+ }
+ break;
+ }
+ case NormalizedByteCode.__ireturn:
+ case NormalizedByteCode.__lreturn:
+ case NormalizedByteCode.__freturn:
+ case NormalizedByteCode.__dreturn:
+ case NormalizedByteCode.__areturn:
+ case NormalizedByteCode.__return:
+ case NormalizedByteCode.__athrow:
+ break;
+ default:
+ state[i + 1] += s;
+ break;
+ }
+ }
+ catch(IndexOutOfRangeException)
+ {
+ // we're going to assume that this always means that we have an invalid branch target
+ // NOTE because PcIndexMap returns -1 for illegal PCs (in the middle of an instruction) and
+ // we always use that value as an index into the state array, any invalid PC will result
+ // in an IndexOutOfRangeException
+ throw new VerifyError("Invalid branch target");
+ }
+ // HACK track the local types (but only for object references)
+ for(int j = 0; j < localTypes.Length ; j++)
+ {
+ string l = s.GetLocalType(j);
+ if(l != null && (l[0] == 'U' || l[0] == 'N' || l[0] == 'L' || l[0] == '[') && !l.StartsWith("Lret;"))
+ {
+ if(l[0] == 'U' || l[0] == 'N')
+ {
+ l = l.Substring(l.IndexOf(';') + 1);
+ }
+ if(localTypes[j] == null)
+ {
+ localTypes[j] = l;
+ }
+ else
+ {
+ localTypes[j] = s.FindCommonBaseType(localTypes[j], l);
+ }
+ }
+ }
+ }
+ catch(VerifyError x)
+ {
+ x.Class = method.Method.ClassFile.Name;
+ x.Method = method.Method.Name;
+ x.Signature = method.Method.Signature;
+ x.ByteCodeOffset = method.Instructions[i].PC;
+ string opcode = method.Instructions[i].OpCode.ToString();
+ if(opcode.StartsWith("__"))
+ {
+ opcode = opcode.Substring(2);
+ }
+ x.Instruction = opcode;
+ throw;
+ }
+ }
+ }
+ }
+/*
+ for(int i = 0; i < method.Instructions.Length; i++)
+ {
+ state[i].DumpLocals();
+ state[i].DumpStack();
+ Console.WriteLine("{0}: {1}", method.Instructions[i].PC, method.Instructions[i].OpCode.ToString());
+ }
+*/
+ }
+
+ private ClassFile.ConstantPoolItemFMI GetMethodref(int index)
+ {
+ try
+ {
+ ClassFile.ConstantPoolItemFMI item = method.Method.ClassFile.GetMethodref(index);
+ if(item != null && !(item is ClassFile.ConstantPoolItemFieldref))
+ {
+ return item;
+ }
+ }
+ catch(InvalidCastException)
+ {
+ }
+ catch(IndexOutOfRangeException)
+ {
+ }
+ throw new VerifyError("Illegal constant pool index");
+ }
+
+ private ClassFile.ConstantPoolItemFieldref GetFieldref(int index)
+ {
+ try
+ {
+ ClassFile.ConstantPoolItemFieldref item = method.Method.ClassFile.GetFieldref(index);
+ if(item != null)
+ {
+ return item;
+ }
+ }
+ catch(InvalidCastException)
+ {
+ }
+ catch(IndexOutOfRangeException)
+ {
+ }
+ throw new VerifyError("Illegal constant pool index");
+ }
+
+ private object GetConstantPoolConstant(int index)
+ {
+ try
+ {
+ return method.Method.ClassFile.GetConstantPoolConstant(index);
+ }
+ catch(IndexOutOfRangeException)
+ {
+ }
+ throw new VerifyError("Illegal constant pool index");
+ }
+
+ private string GetConstantPoolClass(int index)
+ {
+ try
+ {
+ return method.Method.ClassFile.GetConstantPoolClass(index);
+ }
+ catch(InvalidCastException)
+ {
+ }
+ catch(IndexOutOfRangeException)
+ {
+ }
+ throw new VerifyError("Illegal constant pool index");
+ }
+
+ private void AddCallSite(int subroutineIndex, int callSiteIndex)
+ {
+ if(callsites[subroutineIndex] == null)
+ {
+ callsites[subroutineIndex] = new ArrayList();
+ }
+ ArrayList l = (ArrayList)callsites[subroutineIndex];
+ if(l.IndexOf(callSiteIndex) == -1)
+ {
+ l.Add(callSiteIndex);
+ state[subroutineIndex].AddCallSite();
+ }
+ }
+
+ internal int[] GetCallSites(int subroutineIndex)
+ {
+ return (int[])((ArrayList)callsites[subroutineIndex]).ToArray(typeof(int));
+ }
+
+ internal int GetStackHeight(int index)
+ {
+ return state[index].GetStackHeight();
+ }
+
+ internal string GetRawStackType(int index, int pos)
+ {
+ return state[index].GetStackSlot(pos);
+ }
+
+ internal string GetLocalType(int index, int local)
+ {
+ return state[index].GetLocalType(local);
+ }
+
+ internal string GetDeclaredLocalType(int local)
+ {
+ return localTypes[local];
+ }
+}
diff --git a/IK.VM.NET/vm.cs b/IK.VM.NET/vm.cs
new file mode 100644
index 00000000..dd8da8c9
--- /dev/null
+++ b/IK.VM.NET/vm.cs
@@ -0,0 +1,195 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+using System.Reflection.Emit;
+using System.Reflection;
+using System.IO;
+using System.Collections;
+using System.Xml;
+using System.Diagnostics;
+
+public class JVM
+{
+ private static bool debug = false;
+ private static bool noJniStubs = false;
+ private static bool isStaticCompiler = false;
+
+ public static bool Debug
+ {
+ get
+ {
+ return debug;
+ }
+ set
+ {
+ debug = value;
+ }
+ }
+
+ public static bool NoJniStubs
+ {
+ get
+ {
+ return noJniStubs;
+ }
+ }
+
+ public static bool IsStaticCompiler
+ {
+ get
+ {
+ return isStaticCompiler;
+ }
+ }
+
+ public static bool CleanStackTraces
+ {
+ get
+ {
+ return true;
+ }
+ }
+
+ private class CompilerClassLoader : ClassLoaderWrapper
+ {
+ private Hashtable classes;
+ private string assembly;
+ private string path;
+ private AssemblyBuilder assemblyBuilder;
+ private ModuleBuilder moduleBuilder;
+
+ internal CompilerClassLoader(string path, string assembly, Hashtable classes)
+ : base(null)
+ {
+ this.classes = classes;
+ this.assembly = assembly;
+ this.path = path;
+ }
+
+ protected override ModuleBuilder CreateModuleBuilder()
+ {
+ AssemblyName name = new AssemblyName();
+ name.Name = assembly;
+ assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Save);
+ CustomAttributeBuilder ikvmAssemblyAttr = new CustomAttributeBuilder(typeof(IKVMAssemblyAttribute).GetConstructor(Type.EmptyTypes), new object[0]);
+ assemblyBuilder.SetCustomAttribute(ikvmAssemblyAttr);
+ moduleBuilder = assemblyBuilder.DefineDynamicModule(path, JVM.Debug);
+ if(JVM.Debug)
+ {
+ CustomAttributeBuilder debugAttr = new CustomAttributeBuilder(typeof(DebuggableAttribute).GetConstructor(new Type[] { typeof(bool), typeof(bool) }), new object[] { true, true });
+ moduleBuilder.SetCustomAttribute(debugAttr);
+ }
+ return moduleBuilder;
+ }
+
+ internal override TypeWrapper GetBootstrapType(string name)
+ {
+ TypeWrapper type = base.GetBootstrapType(name);
+ if(type == null)
+ {
+ ClassFile f = (ClassFile)classes[name];
+ if(f != null)
+ {
+ type = DefineClass(f);
+ }
+ }
+ return type;
+ }
+
+ internal void SetMain(MethodInfo m, PEFileKinds target)
+ {
+ assemblyBuilder.SetEntryPoint(m, target);
+ }
+
+ internal void Save()
+ {
+ FinishAll();
+ assemblyBuilder.Save(path);
+ }
+
+ internal void AddResources(Hashtable resources)
+ {
+ foreach(DictionaryEntry d in resources)
+ {
+ byte[] buf = (byte[])d.Value;
+ if(buf.Length > 0)
+ {
+ moduleBuilder.DefineInitializedData((string)d.Key, buf, FieldAttributes.Public | FieldAttributes.Static);
+ }
+ }
+ moduleBuilder.CreateGlobalFunctions();
+ }
+ }
+
+ public static void Compile(string path, string assembly, string mainClass, PEFileKinds target, byte[][] classes, string[] references, bool nojni, Hashtable resources)
+ {
+ isStaticCompiler = true;
+ noJniStubs = nojni;
+ Hashtable h = new Hashtable();
+ Console.WriteLine("Parsing class files");
+ for(int i = 0; i < classes.Length; i++)
+ {
+ ClassFile f = new ClassFile(classes[i], 0, classes[i].Length, null);
+ h[f.Name.Replace('/', '.')] = f;
+ }
+ Console.WriteLine("Constructing compiler");
+ CompilerClassLoader loader = new CompilerClassLoader(path, assembly, h);
+ ClassLoaderWrapper.SetBootstrapClassLoader(loader);
+ foreach(string r in references)
+ {
+ Assembly.LoadFrom(r);
+ }
+ Console.WriteLine("Loading remapped types");
+ loader.LoadRemappedTypes();
+ Console.WriteLine("Compiling class files (1)");
+ foreach(string s in h.Keys)
+ {
+ TypeWrapper wrapper = loader.LoadClassByDottedName(s);
+ if(s == mainClass)
+ {
+ MethodWrapper mw = wrapper.GetMethodWrapper(new MethodDescriptor(loader, "main", "([Ljava/lang/String;)V"), false);
+ if(mw == null)
+ {
+ Console.Error.WriteLine("Error: main method not found");
+ return;
+ }
+ MethodInfo method = mw.GetMethod() as MethodInfo;
+ if(method == null)
+ {
+ Console.Error.WriteLine("Error: redirected main method not supported");
+ return;
+ }
+ loader.SetMain(method, target);
+ }
+ }
+ Console.WriteLine("Compiling class files (2)");
+ loader.AddResources(resources);
+ loader.Save();
+ }
+
+ public static void SaveDebugImage(object mainClass)
+ {
+ ClassLoaderWrapper.SaveDebugImage(mainClass);
+ }
+}
diff --git a/awt/AssemblyInfo.cs b/awt/AssemblyInfo.cs
new file mode 100644
index 00000000..9f89a328
--- /dev/null
+++ b/awt/AssemblyInfo.cs
@@ -0,0 +1,58 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+//
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//
+[assembly: AssemblyTitle("")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+//
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+
+[assembly: AssemblyVersion("1.0.*")]
+
+//
+// In order to sign your assembly you must specify a key to use. Refer to the
+// Microsoft .NET Framework documentation for more information on assembly signing.
+//
+// Use the attributes below to control which key is used for signing.
+//
+// Notes:
+// (*) If no key is specified, the assembly is not signed.
+// (*) KeyName refers to a key that has been installed in the Crypto Service
+// Provider (CSP) on your machine. KeyFile refers to a file which contains
+// a key.
+// (*) If the KeyFile and the KeyName values are both specified, the
+// following processing occurs:
+// (1) If the KeyName can be found in the CSP, that key is used.
+// (2) If the KeyName does not exist and the KeyFile does exist, the key
+// in the KeyFile is installed into the CSP and used.
+// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
+// When specifying the KeyFile, the location of the KeyFile should be
+// relative to the project output directory which is
+// %Project Directory%\obj\<configuration>. For example, if your KeyFile is
+// located in the project directory, you would specify the AssemblyKeyFile
+// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
+// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
+// documentation for more information on this.
+//
+[assembly: AssemblyDelaySign(false)]
+[assembly: AssemblyKeyFile("")]
+[assembly: AssemblyKeyName("")]
diff --git a/awt/awt.build b/awt/awt.build
new file mode 100644
index 00000000..e33fc2fb
--- /dev/null
+++ b/awt/awt.build
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<project name="awt" default="awt">
+ <target name="awt">
+ <csc target="library" output="../bin/awt.dll">
+ <sources>
+ <includes name="*.cs" />
+ </sources>
+ <references>
+ <includes name="../bin/classpath.dll" asis="true" />
+ <includes name="../bin/ik.vm.net.dll" asis="true" />
+ </references>
+ </csc>
+ </target>
+</project>
diff --git a/awt/awt.csproj b/awt/awt.csproj
new file mode 100644
index 00000000..eee1e04a
--- /dev/null
+++ b/awt/awt.csproj
@@ -0,0 +1,113 @@
+<VisualStudioProject>
+ <CSHARP
+ ProjectType = "Local"
+ ProductVersion = "7.0.9466"
+ SchemaVersion = "1.0"
+ ProjectGuid = "{E00A0FA2-1FD7-4DD9-8C06-7202CE366102}"
+ >
+ <Build>
+ <Settings
+ ApplicationIcon = ""
+ AssemblyKeyContainerName = ""
+ AssemblyName = "awt"
+ AssemblyOriginatorKeyFile = ""
+ DefaultClientScript = "JScript"
+ DefaultHTMLPageLayout = "Grid"
+ DefaultTargetSchema = "IE50"
+ DelaySign = "false"
+ OutputType = "Library"
+ RootNamespace = "awt"
+ StartupObject = ""
+ >
+ <Config
+ Name = "Debug"
+ AllowUnsafeBlocks = "false"
+ BaseAddress = "285212672"
+ CheckForOverflowUnderflow = "false"
+ ConfigurationOverrideFile = ""
+ DefineConstants = "DEBUG;TRACE"
+ DocumentationFile = ""
+ DebugSymbols = "true"
+ FileAlignment = "4096"
+ IncrementalBuild = "true"
+ Optimize = "false"
+ OutputPath = "bin\Debug\"
+ RegisterForComInterop = "false"
+ RemoveIntegerChecks = "false"
+ TreatWarningsAsErrors = "false"
+ WarningLevel = "4"
+ />
+ <Config
+ Name = "Release"
+ AllowUnsafeBlocks = "false"
+ BaseAddress = "285212672"
+ CheckForOverflowUnderflow = "false"
+ ConfigurationOverrideFile = ""
+ DefineConstants = "TRACE"
+ DocumentationFile = ""
+ DebugSymbols = "false"
+ FileAlignment = "4096"
+ IncrementalBuild = "false"
+ Optimize = "true"
+ OutputPath = "bin\Release\"
+ RegisterForComInterop = "false"
+ RemoveIntegerChecks = "false"
+ TreatWarningsAsErrors = "false"
+ WarningLevel = "4"
+ />
+ </Settings>
+ <References>
+ <Reference
+ Name = "System"
+ AssemblyName = "System"
+ HintPath = "..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.dll"
+ />
+ <Reference
+ Name = "System.Data"
+ AssemblyName = "System.Data"
+ HintPath = "..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Data.dll"
+ />
+ <Reference
+ Name = "System.XML"
+ AssemblyName = "System.Xml"
+ HintPath = "..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.XML.dll"
+ />
+ <Reference
+ Name = "System.Windows.Forms"
+ AssemblyName = "System.Windows.Forms"
+ HintPath = "..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Windows.Forms.dll"
+ />
+ <Reference
+ Name = "System.Drawing"
+ AssemblyName = "System.Drawing"
+ HintPath = "..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Drawing.dll"
+ />
+ <Reference
+ Name = "IK.VM.NET"
+ Project = "{F5C7B588-0403-4AF2-A4DE-5697DE21BC2C}"
+ Package = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"
+ />
+ <Reference
+ Name = "classpath"
+ AssemblyName = "classpath"
+ HintPath = "..\classpath\classpath.dll"
+ />
+ </References>
+ </Build>
+ <Files>
+ <Include>
+ <File
+ RelPath = "AssemblyInfo.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "toolkit.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ </Include>
+ </Files>
+ </CSHARP>
+</VisualStudioProject>
+
diff --git a/awt/toolkit.cs b/awt/toolkit.cs
new file mode 100644
index 00000000..b0daf846
--- /dev/null
+++ b/awt/toolkit.cs
@@ -0,0 +1,850 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+
+using System;
+using System.Threading;
+using System.Windows.Forms;
+using System.Drawing;
+using System.ComponentModel;
+using java.awt.datatransfer;
+using java.awt.image;
+using java.awt.peer;
+using java.net;
+using java.util;
+
+namespace ikvm.awt
+{
+ delegate void SetVoid();
+ delegate void SetBool(bool b);
+ delegate void SetXYWH(int x, int y, int w, int h);
+ delegate void SetString(string s);
+ delegate string GetString();
+ delegate void SetStringInt(string s, int i);
+
+ public class NetToolkit : java.awt.Toolkit
+ {
+ private static java.awt.EventQueue eventQueue = new java.awt.EventQueue();
+ private static Form bogusForm;
+ private static Delegate createControlInstance;
+
+ private delegate Control CreateControlInstanceDelegate(Type type);
+
+ private static void MessageLoop()
+ {
+ createControlInstance = new CreateControlInstanceDelegate(CreateControlImpl);
+ Form form = new Form();
+ form.CreateControl();
+ // HACK I have no idea why this line is necessary...
+ IntPtr p = form.Handle;
+ bogusForm = form;
+ Application.Run();
+ }
+
+ private static Control CreateControlImpl(Type type)
+ {
+ Control control = (Control)Activator.CreateInstance(type);
+ control.CreateControl();
+ // HACK here we go again...
+ IntPtr p = control.Handle;
+ return control;
+ }
+
+ internal static Control CreateControl(Type type)
+ {
+ return (Control)bogusForm.Invoke(createControlInstance, new object[] { type });
+ }
+
+ public NetToolkit()
+ {
+ lock(typeof(NetToolkit))
+ {
+ if(bogusForm != null)
+ {
+ throw new InvalidOperationException();
+ }
+ Thread thread = new Thread(new ThreadStart(MessageLoop));
+ thread.Start();
+ // TODO don't use polling...
+ while(bogusForm == null)
+ {
+ Thread.Sleep(1);
+ }
+ }
+ }
+
+ protected override java.awt.peer.ButtonPeer createButton(java.awt.Button target)
+ {
+ return new NetButtonPeer(target, (Button)CreateControl(typeof(Button)));
+ }
+
+ protected override java.awt.peer.TextFieldPeer createTextField(java.awt.TextField target)
+ {
+ return new NetTextFieldPeer(target, (TextBox)CreateControl(typeof(TextBox)));
+ }
+
+ protected override java.awt.peer.LabelPeer createLabel(java.awt.Label target)
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override java.awt.peer.ListPeer createList(java.awt.List target)
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override java.awt.peer.CheckboxPeer createCheckbox(java.awt.Checkbox target)
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override java.awt.peer.ScrollbarPeer createScrollbar(java.awt.Scrollbar target)
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override java.awt.peer.ScrollPanePeer createScrollPane(java.awt.ScrollPane target)
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override java.awt.peer.TextAreaPeer createTextArea(java.awt.TextArea target)
+ {
+ return new NetTextAreaPeer(target, (TextBox)CreateControl(typeof(TextBox)));
+ }
+
+ protected override java.awt.peer.ChoicePeer createChoice(java.awt.Choice target)
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override java.awt.peer.FramePeer createFrame(java.awt.Frame target)
+ {
+ return new NetFramePeer(target, (Form)CreateControl(typeof(Form)));
+ }
+
+ protected override java.awt.peer.CanvasPeer createCanvas(java.awt.Canvas target)
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override java.awt.peer.PanelPeer createPanel(java.awt.Panel target)
+ {
+ return new NetPanelPeer(target, (ContainerControl)CreateControl(typeof(ContainerControl)));
+ }
+
+ protected override java.awt.peer.WindowPeer createWindow(java.awt.Window target)
+ {
+ throw new NotImplementedException();
+ }
+ protected override java.awt.peer.DialogPeer createDialog(java.awt.Dialog target)
+ {
+ throw new NotImplementedException();
+ }
+ protected override java.awt.peer.MenuBarPeer createMenuBar(java.awt.MenuBar target)
+ {
+ throw new NotImplementedException();
+ }
+ protected override java.awt.peer.MenuPeer createMenu(java.awt.Menu target)
+ {
+ throw new NotImplementedException();
+ }
+ protected override java.awt.peer.PopupMenuPeer createPopupMenu(java.awt.PopupMenu target)
+ {
+ throw new NotImplementedException();
+ }
+ protected override java.awt.peer.MenuItemPeer createMenuItem(java.awt.MenuItem target)
+ {
+ throw new NotImplementedException();
+ }
+ protected override java.awt.peer.FileDialogPeer createFileDialog(java.awt.FileDialog target)
+ {
+ throw new NotImplementedException();
+ }
+ protected override java.awt.peer.CheckboxMenuItemPeer createCheckboxMenuItem(java.awt.CheckboxMenuItem target)
+ {
+ throw new NotImplementedException();
+ }
+ protected override java.awt.peer.FontPeer getFontPeer(string name, int style)
+ {
+ throw new NotImplementedException();
+ }
+ public override java.awt.Dimension getScreenSize()
+ {
+ throw new NotImplementedException();
+ }
+ public override int getScreenResolution()
+ {
+ throw new NotImplementedException();
+ }
+ public override ColorModel getColorModel()
+ {
+ throw new NotImplementedException();
+ }
+ public override string[] getFontList()
+ {
+ throw new NotImplementedException();
+ }
+ public override java.awt.FontMetrics getFontMetrics(java.awt.Font font)
+ {
+ throw new NotImplementedException();
+ }
+ public override void sync()
+ {
+ throw new NotImplementedException();
+ }
+ public override java.awt.Image getImage(string filename)
+ {
+ throw new NotImplementedException();
+ }
+ public override java.awt.Image getImage(URL url)
+ {
+ throw new NotImplementedException();
+ }
+ public override java.awt.Image createImage(string filename)
+ {
+ throw new NotImplementedException();
+ }
+ public override java.awt.Image createImage(URL url)
+ {
+ throw new NotImplementedException();
+ }
+ public override bool prepareImage(java.awt.Image image,
+ int width,
+ int height,
+ java.awt.image.ImageObserver observer)
+ {
+ throw new NotImplementedException();
+ }
+ public override int checkImage(java.awt.Image image,
+ int width,
+ int height,
+ java.awt.image.ImageObserver observer)
+ {
+ throw new NotImplementedException();
+ }
+ public override java.awt.Image createImage(java.awt.image.ImageProducer producer)
+ {
+ throw new NotImplementedException();
+ }
+ public override java.awt.Image createImage(sbyte[] imagedata,
+ int imageoffset,
+ int imagelength)
+ {
+ throw new NotImplementedException();
+ }
+ public override java.awt.PrintJob getPrintJob(java.awt.Frame frame,
+ string jobtitle,
+ Properties props)
+ {
+ throw new NotImplementedException();
+ }
+ public override void beep()
+ {
+ throw new NotImplementedException();
+ }
+ public override java.awt.datatransfer.Clipboard getSystemClipboard()
+ {
+ throw new NotImplementedException();
+ }
+
+ protected override java.awt.EventQueue getSystemEventQueueImpl()
+ {
+ return eventQueue;
+ }
+
+ public override java.awt.dnd.peer.DragSourceContextPeer createDragSourceContextPeer(java.awt.dnd.DragGestureEvent dge)
+ {
+ throw new NotImplementedException();
+ }
+
+ public override Map mapInputMethodHighlight(java.awt.im.InputMethodHighlight highlight)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ class NetComponentPeer : ComponentPeer
+ {
+ internal readonly java.awt.Component component;
+ internal readonly Control control;
+
+ public NetComponentPeer(java.awt.Component component, Control control)
+ {
+ this.control = control;
+ this.component = component;
+ java.awt.Container parent = component.getParent();
+ if(parent != null)
+ {
+ control.Parent = ((NetComponentPeer)parent.getPeer()).control;
+ }
+ setEnabled(component.isEnabled());
+ component.invalidate();
+ //setBounds(component.getX(), component.getY(), component.getWidth(), component.getHeight());
+ control.Invoke(new SetVoid(Setup));
+ }
+
+ private void Setup()
+ {
+ // TODO we really only should hook these events when they are needed...
+ control.KeyDown += new KeyEventHandler(OnKeyDown);
+ control.KeyUp += new KeyEventHandler(OnKeyUp);
+ control.KeyPress += new KeyPressEventHandler(OnKeyPress);
+ }
+
+ private static int MapKeyCode(Keys key)
+ {
+ switch(key)
+ {
+ default:
+ return (int)key;
+ }
+ }
+
+ protected virtual void OnKeyDown(object sender, KeyEventArgs e)
+ {
+ // TODO set all this stuff...
+ long when = 0;
+ int modifiers = 0;
+ int keyCode = MapKeyCode(e.KeyCode);
+ char keyChar = ' ';
+ int keyLocation = 0;
+ postEvent(new java.awt.@event.KeyEvent(component, java.awt.@event.KeyEvent.KEY_PRESSED, when, modifiers, keyCode, keyChar, keyLocation));
+ }
+
+ protected virtual void OnKeyUp(object sender, KeyEventArgs e)
+ {
+ // TODO set all this stuff...
+ long when = 0;
+ int modifiers = 0;
+ int keyCode = MapKeyCode(e.KeyCode);
+ char keyChar = ' ';
+ int keyLocation = 0;
+ postEvent(new java.awt.@event.KeyEvent(component, java.awt.@event.KeyEvent.KEY_RELEASED, when, modifiers, keyCode, keyChar, keyLocation));
+ }
+
+ protected virtual void OnKeyPress(object sender, KeyPressEventArgs e)
+ {
+ // TODO set all this stuff...
+ long when = 0;
+ int modifiers = 0;
+ int keyCode = 0;
+ char keyChar = e.KeyChar;
+ int keyLocation = 0;
+ postEvent(new java.awt.@event.KeyEvent(component, java.awt.@event.KeyEvent.KEY_TYPED, when, modifiers, keyCode, keyChar, keyLocation));
+ }
+
+ protected void postEvent(java.awt.AWTEvent evt)
+ {
+ getToolkit().getSystemEventQueue().postEvent(evt);
+ }
+
+ public int checkImage(java.awt.Image img, int width, int height, java.awt.image.ImageObserver ob)
+ {
+ throw new NotImplementedException();
+ }
+ public java.awt.Image createImage(java.awt.image.ImageProducer prod)
+ {
+ throw new NotImplementedException();
+ }
+ public java.awt.Image createImage(int width, int height)
+ {
+ throw new NotImplementedException();
+ }
+ public void disable()
+ {
+ throw new NotImplementedException();
+ }
+ public void dispose()
+ {
+ throw new NotImplementedException();
+ }
+ public void enable()
+ {
+ throw new NotImplementedException();
+ }
+ public ColorModel getColorModel()
+ {
+ throw new NotImplementedException();
+ }
+ public java.awt.FontMetrics getFontMetrics(java.awt.Font f)
+ {
+ throw new NotImplementedException();
+ }
+ public java.awt.Graphics getGraphics()
+ {
+ throw new NotImplementedException();
+ }
+ public java.awt.Point getLocationOnScreen()
+ {
+ throw new NotImplementedException();
+ }
+ public java.awt.Dimension getMinimumSize()
+ {
+ throw new NotImplementedException();
+ }
+
+ public virtual java.awt.Dimension getPreferredSize()
+ {
+ Console.WriteLine("NOTE: NetComponentPeer.getPreferredSize not implemented");
+ return new java.awt.Dimension(0, 0);
+ }
+
+ public java.awt.Toolkit getToolkit()
+ {
+ return java.awt.Toolkit.getDefaultToolkit();
+ }
+
+ public void handleEvent(java.awt.AWTEvent e)
+ {
+ Console.WriteLine("NOTE: NetComponentPeer.handleEvent not implemented");
+ }
+ public void hide()
+ {
+ throw new NotImplementedException();
+ }
+ public bool isFocusTraversable()
+ {
+ throw new NotImplementedException();
+ }
+ public java.awt.Dimension minimumSize()
+ {
+ throw new NotImplementedException();
+ }
+
+ public java.awt.Dimension preferredSize()
+ {
+ Console.WriteLine("NOTE: NetComponentPeer.preferredSize not implemented");
+ return new java.awt.Dimension(0, 0);
+ }
+
+ public void paint(java.awt.Graphics graphics)
+ {
+ throw new NotImplementedException();
+ }
+ public bool prepareImage(java.awt.Image img, int width, int height, ImageObserver ob)
+ {
+ throw new NotImplementedException();
+ }
+ public void print(java.awt.Graphics graphics)
+ {
+ throw new NotImplementedException();
+ }
+ public void repaint(long tm, int x, int y, int width, int height)
+ {
+ throw new NotImplementedException();
+ }
+ public void requestFocus()
+ {
+ throw new NotImplementedException();
+ }
+ public void reshape(int x, int y, int width, int height)
+ {
+ throw new NotImplementedException();
+ }
+ public void setBackground(java.awt.Color color)
+ {
+ throw new NotImplementedException();
+ }
+
+ private void setBoundsImpl(int x, int y, int width, int height)
+ {
+ control.SetBounds(x, y, width, height);
+ }
+
+ public void setBounds(int x, int y, int width, int height)
+ {
+ control.Invoke(new SetXYWH(setBoundsImpl), new object[] { x, y, width, height });
+ }
+
+ public void setCursor(java.awt.Cursor cursor)
+ {
+ throw new NotImplementedException();
+ }
+
+ private void setEnabledImpl(bool enabled)
+ {
+ control.Enabled = enabled;
+ }
+
+ public void setEnabled(bool enabled)
+ {
+ control.Invoke(new SetBool(setEnabledImpl), new object[] { enabled });
+ }
+
+ public void setFont(java.awt.Font font)
+ {
+ throw new NotImplementedException();
+ }
+ public void setForeground(java.awt.Color color)
+ {
+ throw new NotImplementedException();
+ }
+
+ private void setVisibleImpl(bool visible)
+ {
+ control.Visible = visible;
+ }
+
+ public void setVisible(bool visible)
+ {
+ control.Invoke(new SetBool(setVisibleImpl), new object[] { visible });
+ }
+
+ public void show()
+ {
+ throw new NotImplementedException();
+ }
+ public java.awt.GraphicsConfiguration getGraphicsConfiguration()
+ {
+ throw new NotImplementedException();
+ }
+
+ public void setEventMask (long mask)
+ {
+ Console.WriteLine("NOTE: NetComponentPeer.setEventMask not implemented");
+ }
+ }
+
+ class NetButtonPeer : NetComponentPeer, ButtonPeer
+ {
+ public NetButtonPeer(java.awt.Button awtbutton, Button button)
+ : base(awtbutton, button)
+ {
+ setLabel(awtbutton.getLabel());
+ control.Invoke(new SetVoid(Setup));
+ }
+
+ private void Setup()
+ {
+ ((Button)control).Click += new EventHandler(OnClick);
+ }
+
+ private void OnClick(object sender, EventArgs e)
+ {
+ // TODO set all these properties correctly
+ string cmd = "";
+ long when = 0;
+ int modifiers = 0;
+ postEvent(new java.awt.@event.ActionEvent(component, java.awt.@event.ActionEvent.ACTION_PERFORMED, cmd, when, modifiers));
+ }
+
+ private void setLabelImpl(string label)
+ {
+ control.Text = label;
+ }
+
+ public void setLabel(string label)
+ {
+ control.Invoke(new SetString(setLabelImpl), new object[] { label });
+ }
+
+ public override java.awt.Dimension getPreferredSize()
+ {
+ // TODO get the size from somewhere...
+ return new java.awt.Dimension(80, 15);
+ }
+ }
+
+ class NetTextComponentPeer : NetComponentPeer, TextComponentPeer
+ {
+ public NetTextComponentPeer(java.awt.TextComponent textComponent, TextBox textBox)
+ : base(textComponent, textBox)
+ {
+ }
+
+ protected override void OnKeyPress(object sender, KeyPressEventArgs e)
+ {
+ base.OnKeyPress(sender, e);
+ // TODO for TextAreas this probably isn't the right behaviour
+ if(e.KeyChar == '\r')
+ {
+ // TODO set all these properties correctly
+ string cmd = "";
+ long when = 0;
+ int modifiers = 0;
+ postEvent(new java.awt.@event.ActionEvent(component, java.awt.@event.ActionEvent.ACTION_PERFORMED, cmd, when, modifiers));
+ }
+ }
+
+ public int getSelectionEnd()
+ {
+ throw new NotImplementedException();
+ }
+ public int getSelectionStart()
+ {
+ throw new NotImplementedException();
+ }
+
+ private string getTextImpl()
+ {
+ return control.Text;
+ }
+
+ public string getText()
+ {
+ return (string)control.Invoke(new GetString(getTextImpl));
+ }
+
+ private void setTextImpl(string text)
+ {
+ control.Text = text;
+ }
+
+ public void setText(string text)
+ {
+ control.Invoke(new SetString(setTextImpl), new object[] { text });
+ }
+
+ public void select(int start_pos, int end_pos)
+ {
+ throw new NotImplementedException();
+ }
+ public void setEditable(bool editable)
+ {
+ throw new NotImplementedException();
+ }
+ public int getCaretPosition()
+ {
+ throw new NotImplementedException();
+ }
+ public void setCaretPosition(int pos)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ class NetTextFieldPeer : NetTextComponentPeer, TextFieldPeer
+ {
+ public NetTextFieldPeer(java.awt.TextField textField, TextBox textBox)
+ : base(textField, textBox)
+ {
+ }
+
+ public java.awt.Dimension minimumSize(int len)
+ {
+ throw new NotImplementedException();
+ }
+ public java.awt.Dimension preferredSize(int len)
+ {
+ throw new NotImplementedException();
+ }
+ public java.awt.Dimension getMinimumSize(int len)
+ {
+ throw new NotImplementedException();
+ }
+
+ public java.awt.Dimension getPreferredSize(int len)
+ {
+ TextBox b = (TextBox)control;
+ // TODO use control.Invoke
+ return new java.awt.Dimension(200, b.PreferredHeight);
+ }
+
+ public void setEchoChar(char echo_char)
+ {
+ throw new NotImplementedException();
+ }
+ public void setEchoCharacter(char echo_char)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ class NetTextAreaPeer : NetTextComponentPeer, TextAreaPeer
+ {
+ public NetTextAreaPeer(java.awt.TextArea textArea, TextBox textBox)
+ : base(textArea, textBox)
+ {
+ control.Invoke(new SetVoid(Setup));
+ }
+
+ private void Setup()
+ {
+ ((TextBox)control).ReadOnly = !((java.awt.TextArea)component).isEditable();
+ ((TextBox)control).WordWrap = false;
+ ((TextBox)control).ScrollBars = ScrollBars.Both;
+ ((TextBox)control).Multiline = true;
+ }
+
+ private void insertImpl(string text, int pos)
+ {
+ ((TextBox)control).Text = ((TextBox)control).Text.Insert(pos, text);
+ }
+
+ public void insert(string text, int pos)
+ {
+ control.Invoke(new SetStringInt(insertImpl), new Object[] { text, pos });
+ }
+
+ public void insertText(string text, int pos)
+ {
+ throw new NotImplementedException();
+ }
+ public java.awt.Dimension minimumSize(int rows, int cols)
+ {
+ throw new NotImplementedException();
+ }
+ public java.awt.Dimension getMinimumSize(int rows, int cols)
+ {
+ throw new NotImplementedException();
+ }
+ public java.awt.Dimension preferredSize(int rows, int cols)
+ {
+ throw new NotImplementedException();
+ }
+
+ public java.awt.Dimension getPreferredSize(int rows, int cols)
+ {
+ Console.WriteLine("NOTE: NetTextAreaPeer.getPreferredSize not implemented");
+ return new java.awt.Dimension(10 * cols, 15 * rows);
+ }
+
+ public void replaceRange(string text, int start_pos, int end_pos)
+ {
+ throw new NotImplementedException();
+ }
+ public void replaceText(string text, int start_pos, int end_pos)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ class NetContainerPeer : NetComponentPeer, ContainerPeer
+ {
+ public NetContainerPeer(java.awt.Container awtcontainer, ContainerControl container)
+ : base(awtcontainer, container)
+ {
+ }
+
+ public java.awt.Insets insets()
+ {
+ throw new NotImplementedException();
+ }
+
+ public virtual java.awt.Insets getInsets()
+ {
+ Console.WriteLine("NOTE: NetContainerPeer.getInsets not implemented");
+ return new java.awt.Insets(0, 0, 0, 0);
+ }
+
+ public void beginValidate()
+ {
+ Console.WriteLine("NOTE: NetContainerPeer.beginValidate not implemented");
+ }
+
+ public void endValidate()
+ {
+ Console.WriteLine("NOTE: NetContainerPeer.endValidate not implemented");
+ }
+ }
+
+ class NetPanelPeer : NetContainerPeer, PanelPeer
+ {
+ public NetPanelPeer(java.awt.Panel panel, ContainerControl container)
+ : base(panel, container)
+ {
+ }
+ }
+
+ class NetWindowPeer : NetContainerPeer, WindowPeer
+ {
+ public NetWindowPeer(java.awt.Window window, Form form)
+ : base(window, form)
+ {
+ }
+
+ public void toBack()
+ {
+ throw new NotImplementedException();
+ }
+
+ public void toFront()
+ {
+ Console.WriteLine("NOTE: NetWindowPeer.toFront not implemented");
+ }
+ }
+
+ class NetFramePeer : NetWindowPeer, FramePeer
+ {
+ public NetFramePeer(java.awt.Frame frame, Form form)
+ : base(frame, form)
+ {
+ setTitle(frame.getTitle());
+ control.Invoke(new SetVoid(Setup));
+ }
+
+ private void Setup()
+ {
+ Form form = (Form)control;
+ form.Resize += new EventHandler(Resize);
+ form.Closing += new CancelEventHandler(Closing);
+ }
+
+ private void Closing(object sender, CancelEventArgs e)
+ {
+ e.Cancel = true;
+ postEvent(new java.awt.@event.WindowEvent((java.awt.Window)component, java.awt.@event.WindowEvent.WINDOW_CLOSING));
+ }
+
+ private void Resize(object sender, EventArgs e)
+ {
+ // TODO I have no clue what I should do here...
+ Rectangle r = control.Bounds;
+ component.setBounds(r.X, r.Y, r.Width, r.Height);
+ component.invalidate();
+ component.validate();
+ postEvent(new java.awt.@event.ComponentEvent(component, java.awt.@event.ComponentEvent.COMPONENT_RESIZED));
+ }
+
+ public void setIconImage(java.awt.Image image)
+ {
+ throw new NotImplementedException();
+ }
+ public void setMenuBar(java.awt.MenuBar mb)
+ {
+ throw new NotImplementedException();
+ }
+ public void setResizable(bool resizable)
+ {
+ throw new NotImplementedException();
+ }
+ private void setTitleImpl(string title)
+ {
+ control.Text = title;
+ }
+ public void setTitle(string title)
+ {
+ control.Invoke(new SetString(setTitleImpl), new object[] { title });
+ }
+
+ public override java.awt.Insets getInsets()
+ {
+ // NOTE that we're not returning the "real" insets, but the result is equivalent (I think)
+ // and it doesn't require me to remap the client coordinates
+ Rectangle client = control.ClientRectangle;
+ // TODO use control.Invoke
+ return new java.awt.Insets(0, 0, control.Height - client.Height, control.Width - client.Width);
+ }
+ }
+}
diff --git a/bin/lib/security/classpath.security b/bin/lib/security/classpath.security
new file mode 100644
index 00000000..cd1223be
--- /dev/null
+++ b/bin/lib/security/classpath.security
@@ -0,0 +1,39 @@
+# classpath.security
+# Copyright (C) 2002 Free Software Foundation, Inc.
+#
+# 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.
+
+
+security.provider.1=gnu.java.security.provider.Gnu
diff --git a/classpath/System.Xml.jar b/classpath/System.Xml.jar
new file mode 100644
index 00000000..4c7e5df4
--- /dev/null
+++ b/classpath/System.Xml.jar
Binary files differ
diff --git a/classpath/System.jar b/classpath/System.jar
new file mode 100644
index 00000000..f4161828
--- /dev/null
+++ b/classpath/System.jar
Binary files differ
diff --git a/classpath/allsources.lst b/classpath/allsources.lst
new file mode 100644
index 00000000..539d9b40
--- /dev/null
+++ b/classpath/allsources.lst
@@ -0,0 +1,1488 @@
+C:\vsp\ikvm\classpath\gnu\classpath\Configuration.java
+C:\vsp\ikvm\classpath\gnu\java\net\protocol\ikvmres\Handler.java
+C:\vsp\ikvm\classpath\java\io\FileDescriptor.java
+C:\vsp\ikvm\classpath\java\io\FileInputStream.java
+C:\vsp\ikvm\classpath\java\io\FileOutputStream.java
+C:\vsp\ikvm\classpath\java\io\RandomAccessFile.java
+C:\vsp\ikvm\classpath\java\lang\Thread.java
+C:\vsp\ikvm\classpath\java\lang\Class.java
+C:\vsp\ikvm\classpath\java\lang\VMClassLoader.java
+C:\vsp\ikvm\classpath\java\lang\reflect\Constructor.java
+C:\vsp\ikvm\classpath\java\lang\reflect\Method.java
+C:\vsp\ikvm\classpath\java\lang\reflect\Field.java
+C:\vsp\ikvm\classpath\java\net\PlainSocketImpl.java
+C:\vsp\ikvm\classpath\java\net\PlainDatagramSocketImpl.java
+C:\vsp\ikvm\classpath\sun\misc\Ref.java
+C:\classpath-0.04\com\sun\javadoc\ClassDoc.java
+C:\classpath-0.04\com\sun\javadoc\ConstructorDoc.java
+C:\classpath-0.04\com\sun\javadoc\Doc.java
+C:\classpath-0.04\com\sun\javadoc\DocErrorReporter.java
+C:\classpath-0.04\com\sun\javadoc\Doclet.java
+C:\classpath-0.04\com\sun\javadoc\ExecutableMemberDoc.java
+C:\classpath-0.04\com\sun\javadoc\FieldDoc.java
+C:\classpath-0.04\com\sun\javadoc\MemberDoc.java
+C:\classpath-0.04\com\sun\javadoc\MethodDoc.java
+C:\classpath-0.04\com\sun\javadoc\PackageDoc.java
+C:\classpath-0.04\com\sun\javadoc\Parameter.java
+C:\classpath-0.04\com\sun\javadoc\ParamTag.java
+C:\classpath-0.04\com\sun\javadoc\ProgramElementDoc.java
+C:\classpath-0.04\com\sun\javadoc\RootDoc.java
+C:\classpath-0.04\com\sun\javadoc\SeeTag.java
+C:\classpath-0.04\com\sun\javadoc\SerialFieldTag.java
+C:\classpath-0.04\com\sun\javadoc\Tag.java
+C:\classpath-0.04\com\sun\javadoc\ThrowsTag.java
+C:\classpath-0.04\com\sun\javadoc\Type.java
+C:\classpath-0.04\gnu\java\awt\BitMaskExtent.java
+C:\classpath-0.04\gnu\java\awt\Buffers.java
+C:\classpath-0.04\gnu\java\awt\ComponentDataBlitOp.java
+C:\classpath-0.04\gnu\java\awt\GLightweightPeer.java
+C:\classpath-0.04\gnu\java\awt\image\GdkPixbufDecoder.java
+C:\classpath-0.04\gnu\java\awt\image\GtkOffScreenDecoder.java
+C:\classpath-0.04\gnu\java\awt\image\ImageDecoder.java
+C:\classpath-0.04\gnu\java\awt\image\XBMDecoder.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GdkFontMetrics.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GdkGraphics.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkArg.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkArgList.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkButtonPeer.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkCanvasPeer.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkCheckboxMenuItemPeer.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkCheckboxPeer.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkChoicePeer.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkClipboard.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkComponentPeer.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkContainerPeer.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkDialogPeer.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkFileDialogPeer.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkFontPeer.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkFramePeer.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkGenericPeer.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkImage.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkImagePainter.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkLabelPeer.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkListPeer.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkMainThread.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkMenuBarPeer.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkMenuComponentPeer.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkMenuItemPeer.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkMenuPeer.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkOffScreenImage.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkPanelPeer.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkPopupMenuPeer.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkScrollbarPeer.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkScrollPanePeer.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkTextAreaPeer.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkTextComponentPeer.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkTextFieldPeer.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkToolkit.java
+C:\classpath-0.04\gnu\java\awt\peer\gtk\GtkWindowPeer.java
+C:\classpath-0.04\gnu\java\beans\BeanInfoEmbryo.java
+C:\classpath-0.04\gnu\java\beans\EmptyBeanInfo.java
+C:\classpath-0.04\gnu\java\beans\ExplicitBeanInfo.java
+C:\classpath-0.04\gnu\java\beans\IntrospectionIncubator.java
+C:\classpath-0.04\gnu\java\beans\editors\ColorEditor.java
+C:\classpath-0.04\gnu\java\beans\editors\FontEditor.java
+C:\classpath-0.04\gnu\java\beans\editors\NativeBooleanEditor.java
+C:\classpath-0.04\gnu\java\beans\editors\NativeByteEditor.java
+C:\classpath-0.04\gnu\java\beans\editors\NativeDoubleEditor.java
+C:\classpath-0.04\gnu\java\beans\editors\NativeFloatEditor.java
+C:\classpath-0.04\gnu\java\beans\editors\NativeIntEditor.java
+C:\classpath-0.04\gnu\java\beans\editors\NativeLongEditor.java
+C:\classpath-0.04\gnu\java\beans\editors\NativeShortEditor.java
+C:\classpath-0.04\gnu\java\beans\editors\StringEditor.java
+C:\classpath-0.04\gnu\java\beans\info\ComponentBeanInfo.java
+C:\classpath-0.04\gnu\java\io\ClassLoaderObjectInputStream.java
+C:\classpath-0.04\gnu\java\io\EncodingManager.java
+C:\classpath-0.04\gnu\java\io\NullOutputStream.java
+C:\classpath-0.04\gnu\java\io\ObjectIdentityWrapper.java
+C:\classpath-0.04\gnu\java\io\PlatformHelper.java
+C:\classpath-0.04\gnu\java\io\decode\Decoder.java
+C:\classpath-0.04\gnu\java\io\decode\Decoder8859_1.java
+C:\classpath-0.04\gnu\java\io\decode\Decoder8859_2.java
+C:\classpath-0.04\gnu\java\io\decode\Decoder8859_3.java
+C:\classpath-0.04\gnu\java\io\decode\Decoder8859_4.java
+C:\classpath-0.04\gnu\java\io\decode\Decoder8859_5.java
+C:\classpath-0.04\gnu\java\io\decode\DecoderEightBitLookup.java
+C:\classpath-0.04\gnu\java\io\decode\DecoderUTF8.java
+C:\classpath-0.04\gnu\java\io\encode\Encoder.java
+C:\classpath-0.04\gnu\java\io\encode\Encoder8859_1.java
+C:\classpath-0.04\gnu\java\io\encode\Encoder8859_2.java
+C:\classpath-0.04\gnu\java\io\encode\Encoder8859_3.java
+C:\classpath-0.04\gnu\java\io\encode\Encoder8859_4.java
+C:\classpath-0.04\gnu\java\io\encode\Encoder8859_5.java
+C:\classpath-0.04\gnu\java\io\encode\EncoderEightBitLookup.java
+C:\classpath-0.04\gnu\java\io\encode\EncoderUTF8.java
+C:\classpath-0.04\gnu\java\lang\ArrayHelper.java
+C:\classpath-0.04\gnu\java\lang\CharData.java
+C:\classpath-0.04\gnu\java\lang\ClassHelper.java
+C:\classpath-0.04\gnu\java\lang\ClassLoaderHelper.java
+C:\classpath-0.04\gnu\java\lang\ExecutionStack.java
+C:\classpath-0.04\gnu\java\lang\MainThread.java
+C:\classpath-0.04\gnu\java\lang\StackFrame.java
+C:\classpath-0.04\gnu\java\lang\SystemClassLoader.java
+C:\classpath-0.04\gnu\java\lang\reflect\TypeSignature.java
+C:\classpath-0.04\gnu\java\locale\Calendar.java
+C:\classpath-0.04\gnu\java\locale\Calendar_de.java
+C:\classpath-0.04\gnu\java\locale\Calendar_en.java
+C:\classpath-0.04\gnu\java\locale\Calendar_nl.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_af_ZA.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_ar_AE.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_ar_BH.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_ar_DZ.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_ar_EG.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_ar_IN.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_ar_IQ.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_ar_JO.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_ar_KW.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_ar_LB.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_ar_LY.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_ar_MA.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_ar_OM.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_ar_QA.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_ar_SD.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_ar_SY.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_ar_TN.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_ar_YE.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_be_BY.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_bn_IN.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_br_FR.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_bs_BA.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_ca_ES.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_cs_CZ.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_cy_GB.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_da_DK.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_de.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_de_AT.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_de_BE.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_de_CH.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_de_DE.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_de_LU.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_el_GR.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_en.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_en_AU.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_en_BW.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_en_CA.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_en_DK.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_en_GB.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_en_HK.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_en_IE.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_en_IN.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_en_NZ.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_en_PH.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_en_SG.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_en_US.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_en_ZA.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_en_ZW.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_es_AR.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_es_BO.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_es_CL.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_es_CO.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_es_CR.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_es_DO.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_es_EC.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_es_ES.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_es_GT.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_es_HN.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_es_MX.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_es_NI.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_es_PA.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_es_PE.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_es_PR.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_es_PY.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_es_SV.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_es_US.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_es_UY.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_es_VE.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_et_EE.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_eu_ES.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_fa_IR.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_fi_FI.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_fo_FO.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_fr_BE.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_fr_CA.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_fr_CH.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_fr_FR.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_fr_LU.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_ga_IE.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_gd_GB.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_gl_ES.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_gv_GB.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_he_IL.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_hi_IN.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_hr_HR.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_hu_HU.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_id_ID.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_it_CH.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_it_IT.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_iw_IL.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_ja_JP.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_ka_GE.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_kl_GL.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_ko_KR.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_kw_GB.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_lt_LT.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_lv_LV.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_mi_NZ.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_mk_MK.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_mr_IN.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_mt_MT.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_nl.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_nl_BE.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_nl_NL.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_nn_NO.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_no_NO.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_oc_FR.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_pl_PL.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_pt_BR.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_pt_PT.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_ro_RO.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_ru_RU.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_ru_UA.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_se_NO.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_sk_SK.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_sl_SI.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_sq_AL.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_sr_YU.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_sv_FI.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_sv_SE.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_ta_IN.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_te_IN.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_tg_TJ.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_tl_PH.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_tr_TR.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_uk_UA.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_ur_PK.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_uz_UZ.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_vi_VN.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_yi_US.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_zh_CN.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_zh_HK.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_zh_SG.java
+C:\classpath-0.04\gnu\java\locale\LocaleInformation_zh_TW.java
+C:\classpath-0.04\gnu\java\math\MPN.java
+C:\classpath-0.04\gnu\java\net\HeaderFieldHelper.java
+C:\classpath-0.04\gnu\java\net\content\text\plain.java
+C:\classpath-0.04\gnu\java\net\protocol\file\FileURLConnection.java
+C:\classpath-0.04\gnu\java\net\protocol\file\Handler.java
+C:\classpath-0.04\gnu\java\net\protocol\http\Handler.java
+C:\classpath-0.04\gnu\java\net\protocol\http\HttpURLConnection.java
+C:\classpath-0.04\gnu\java\net\protocol\jar\Handler.java
+C:\classpath-0.04\gnu\java\net\protocol\jar\JarURLConnection.java
+C:\classpath-0.04\gnu\java\nio\ByteBufferImpl.java
+C:\classpath-0.04\gnu\java\nio\CharBufferImpl.java
+C:\classpath-0.04\gnu\java\nio\DatagramChannelImpl.java
+C:\classpath-0.04\gnu\java\nio\DoubleBufferImpl.java
+C:\classpath-0.04\gnu\java\nio\FileChannelImpl.java
+C:\classpath-0.04\gnu\java\nio\FloatBufferImpl.java
+C:\classpath-0.04\gnu\java\nio\IntBufferImpl.java
+C:\classpath-0.04\gnu\java\nio\LongBufferImpl.java
+C:\classpath-0.04\gnu\java\nio\MappedByteFileBuffer.java
+C:\classpath-0.04\gnu\java\nio\MappedCharFileBuffer.java
+C:\classpath-0.04\gnu\java\nio\MappedDoubleFileBuffer.java
+C:\classpath-0.04\gnu\java\nio\MappedFloatFileBuffer.java
+C:\classpath-0.04\gnu\java\nio\MappedIntFileBuffer.java
+C:\classpath-0.04\gnu\java\nio\MappedLongFileBuffer.java
+C:\classpath-0.04\gnu\java\nio\MappedShortFileBuffer.java
+C:\classpath-0.04\gnu\java\nio\PipeImpl.java
+C:\classpath-0.04\gnu\java\nio\SelectionKeyImpl.java
+C:\classpath-0.04\gnu\java\nio\SelectorImpl.java
+C:\classpath-0.04\gnu\java\nio\SelectorProviderImpl.java
+C:\classpath-0.04\gnu\java\nio\ServerSocketChannelImpl.java
+C:\classpath-0.04\gnu\java\nio\ShortBufferImpl.java
+C:\classpath-0.04\gnu\java\nio\SocketChannelImpl.java
+C:\classpath-0.04\gnu\java\rmi\RMIMarshalledObjectInputStream.java
+C:\classpath-0.04\gnu\java\rmi\RMIMarshalledObjectOutputStream.java
+C:\classpath-0.04\gnu\java\rmi\dgc\DGCImpl.java
+C:\classpath-0.04\gnu\java\rmi\dgc\DGCImpl_Skel.java
+C:\classpath-0.04\gnu\java\rmi\dgc\DGCImpl_Stub.java
+C:\classpath-0.04\gnu\java\rmi\registry\RegistryImpl.java
+C:\classpath-0.04\gnu\java\rmi\registry\RegistryImpl_Skel.java
+C:\classpath-0.04\gnu\java\rmi\registry\RegistryImpl_Stub.java
+C:\classpath-0.04\gnu\java\rmi\rmic\Compiler.java
+C:\classpath-0.04\gnu\java\rmi\rmic\CompilerProcess.java
+C:\classpath-0.04\gnu\java\rmi\rmic\Compile_gcj.java
+C:\classpath-0.04\gnu\java\rmi\rmic\RMIC.java
+C:\classpath-0.04\gnu\java\rmi\rmic\TabbedWriter.java
+C:\classpath-0.04\gnu\java\rmi\server\ConnectionRunnerPool.java
+C:\classpath-0.04\gnu\java\rmi\server\ProtocolConstants.java
+C:\classpath-0.04\gnu\java\rmi\server\RMIDefaultSocketFactory.java
+C:\classpath-0.04\gnu\java\rmi\server\RMIHashes.java
+C:\classpath-0.04\gnu\java\rmi\server\RMIObjectInputStream.java
+C:\classpath-0.04\gnu\java\rmi\server\RMIObjectOutputStream.java
+C:\classpath-0.04\gnu\java\rmi\server\UnicastConnection.java
+C:\classpath-0.04\gnu\java\rmi\server\UnicastConnectionManager.java
+C:\classpath-0.04\gnu\java\rmi\server\UnicastRef.java
+C:\classpath-0.04\gnu\java\rmi\server\UnicastRemoteCall.java
+C:\classpath-0.04\gnu\java\rmi\server\UnicastRemoteStub.java
+C:\classpath-0.04\gnu\java\rmi\server\UnicastServer.java
+C:\classpath-0.04\gnu\java\rmi\server\UnicastServerRef.java
+C:\classpath-0.04\gnu\java\security\der\DEREncodingException.java
+C:\classpath-0.04\gnu\java\security\provider\DefaultPolicy.java
+C:\classpath-0.04\gnu\java\security\provider\DERReader.java
+C:\classpath-0.04\gnu\java\security\provider\DERWriter.java
+C:\classpath-0.04\gnu\java\security\provider\DSAKeyPairGenerator.java
+C:\classpath-0.04\gnu\java\security\provider\DSAParameterGenerator.java
+C:\classpath-0.04\gnu\java\security\provider\DSAParameters.java
+C:\classpath-0.04\gnu\java\security\provider\DSASignature.java
+C:\classpath-0.04\gnu\java\security\provider\Gnu.java
+C:\classpath-0.04\gnu\java\security\provider\GnuDSAPrivateKey.java
+C:\classpath-0.04\gnu\java\security\provider\GnuDSAPublicKey.java
+C:\classpath-0.04\gnu\java\security\provider\MD5.java
+C:\classpath-0.04\gnu\java\security\provider\SHA.java
+C:\classpath-0.04\gnu\java\security\provider\SHA1PRNG.java
+C:\classpath-0.04\gnu\java\security\util\Prime.java
+C:\classpath-0.04\gnu\java\text\BaseBreakIterator.java
+C:\classpath-0.04\gnu\java\text\CharacterBreakIterator.java
+C:\classpath-0.04\gnu\java\text\LineBreakIterator.java
+C:\classpath-0.04\gnu\java\text\SentenceBreakIterator.java
+C:\classpath-0.04\gnu\java\text\WordBreakIterator.java
+C:\classpath-0.04\gnu\java\util\DoubleEnumeration.java
+C:\classpath-0.04\gnu\java\util\EmptyEnumeration.java
+C:\classpath-0.04\gnu\java\util\prefs\FileBasedFactory.java
+C:\classpath-0.04\gnu\java\util\prefs\MemoryBasedFactory.java
+C:\classpath-0.04\gnu\java\util\prefs\MemoryBasedPreferences.java
+C:\classpath-0.04\gnu\java\util\prefs\NodeReader.java
+C:\classpath-0.04\gnu\java\util\prefs\NodeWriter.java
+C:\classpath-0.04\java\applet\Applet.java
+C:\classpath-0.04\java\applet\AppletContext.java
+C:\classpath-0.04\java\applet\AppletStub.java
+C:\classpath-0.04\java\applet\AudioClip.java
+C:\classpath-0.04\java\awt\ActiveEvent.java
+C:\classpath-0.04\java\awt\Adjustable.java
+C:\classpath-0.04\java\awt\AlphaComposite.java
+C:\classpath-0.04\java\awt\AttributeValue.java
+C:\classpath-0.04\java\awt\AWTError.java
+C:\classpath-0.04\java\awt\AWTEvent.java
+C:\classpath-0.04\java\awt\AWTEventMulticaster.java
+C:\classpath-0.04\java\awt\AWTException.java
+C:\classpath-0.04\java\awt\AWTKeyStroke.java
+C:\classpath-0.04\java\awt\AWTPermission.java
+C:\classpath-0.04\java\awt\BasicStroke.java
+C:\classpath-0.04\java\awt\BorderLayout.java
+C:\classpath-0.04\java\awt\BufferCapabilities.java
+C:\classpath-0.04\java\awt\Button.java
+C:\classpath-0.04\java\awt\Canvas.java
+C:\classpath-0.04\java\awt\CardLayout.java
+C:\classpath-0.04\java\awt\Checkbox.java
+C:\classpath-0.04\java\awt\CheckboxGroup.java
+C:\classpath-0.04\java\awt\CheckboxMenuItem.java
+C:\classpath-0.04\java\awt\Choice.java
+C:\classpath-0.04\java\awt\Color.java
+C:\classpath-0.04\java\awt\Component.java
+C:\classpath-0.04\java\awt\ComponentOrientation.java
+C:\classpath-0.04\java\awt\Composite.java
+C:\classpath-0.04\java\awt\CompositeContext.java
+C:\classpath-0.04\java\awt\Container.java
+C:\classpath-0.04\java\awt\ContainerOrderFocusTraversalPolicy.java
+C:\classpath-0.04\java\awt\Cursor.java
+C:\classpath-0.04\java\awt\DefaultFocusTraversalPolicy.java
+C:\classpath-0.04\java\awt\DefaultKeyboardFocusManager.java
+C:\classpath-0.04\java\awt\Dialog.java
+C:\classpath-0.04\java\awt\Dimension.java
+C:\classpath-0.04\java\awt\DisplayMode.java
+C:\classpath-0.04\java\awt\Event.java
+C:\classpath-0.04\java\awt\EventDispatchThread.java
+C:\classpath-0.04\java\awt\EventQueue.java
+C:\classpath-0.04\java\awt\FileDialog.java
+C:\classpath-0.04\java\awt\FlowLayout.java
+C:\classpath-0.04\java\awt\FocusTraversalPolicy.java
+C:\classpath-0.04\java\awt\Font.java
+C:\classpath-0.04\java\awt\FontFormatException.java
+C:\classpath-0.04\java\awt\FontMetrics.java
+C:\classpath-0.04\java\awt\Frame.java
+C:\classpath-0.04\java\awt\GradientPaint.java
+C:\classpath-0.04\java\awt\Graphics.java
+C:\classpath-0.04\java\awt\Graphics2D.java
+C:\classpath-0.04\java\awt\GraphicsConfigTemplate.java
+C:\classpath-0.04\java\awt\GraphicsConfiguration.java
+C:\classpath-0.04\java\awt\GraphicsDevice.java
+C:\classpath-0.04\java\awt\GraphicsEnvironment.java
+C:\classpath-0.04\java\awt\GridBagConstraints.java
+C:\classpath-0.04\java\awt\GridLayout.java
+C:\classpath-0.04\java\awt\HeadlessException.java
+C:\classpath-0.04\java\awt\IllegalComponentStateException.java
+C:\classpath-0.04\java\awt\Image.java
+C:\classpath-0.04\java\awt\ImageCapabilities.java
+C:\classpath-0.04\java\awt\Insets.java
+C:\classpath-0.04\java\awt\ItemSelectable.java
+C:\classpath-0.04\java\awt\JobAttributes.java
+C:\classpath-0.04\java\awt\KeyboardFocusManager.java
+C:\classpath-0.04\java\awt\KeyEventDispatcher.java
+C:\classpath-0.04\java\awt\KeyEventPostProcessor.java
+C:\classpath-0.04\java\awt\Label.java
+C:\classpath-0.04\java\awt\LayoutManager.java
+C:\classpath-0.04\java\awt\LayoutManager2.java
+C:\classpath-0.04\java\awt\List.java
+C:\classpath-0.04\java\awt\MediaTracker.java
+C:\classpath-0.04\java\awt\Menu.java
+C:\classpath-0.04\java\awt\MenuBar.java
+C:\classpath-0.04\java\awt\MenuComponent.java
+C:\classpath-0.04\java\awt\MenuContainer.java
+C:\classpath-0.04\java\awt\MenuItem.java
+C:\classpath-0.04\java\awt\MenuShortcut.java
+C:\classpath-0.04\java\awt\PageAttributes.java
+C:\classpath-0.04\java\awt\Paint.java
+C:\classpath-0.04\java\awt\PaintContext.java
+C:\classpath-0.04\java\awt\Panel.java
+C:\classpath-0.04\java\awt\Point.java
+C:\classpath-0.04\java\awt\Polygon.java
+C:\classpath-0.04\java\awt\PopupMenu.java
+C:\classpath-0.04\java\awt\PrintGraphics.java
+C:\classpath-0.04\java\awt\PrintJob.java
+C:\classpath-0.04\java\awt\Rectangle.java
+C:\classpath-0.04\java\awt\RenderingHints.java
+C:\classpath-0.04\java\awt\Robot.java
+C:\classpath-0.04\java\awt\Scrollbar.java
+C:\classpath-0.04\java\awt\ScrollPane.java
+C:\classpath-0.04\java\awt\ScrollPaneAdjustable.java
+C:\classpath-0.04\java\awt\Shape.java
+C:\classpath-0.04\java\awt\Stroke.java
+C:\classpath-0.04\java\awt\SystemColor.java
+C:\classpath-0.04\java\awt\TextArea.java
+C:\classpath-0.04\java\awt\TextComponent.java
+C:\classpath-0.04\java\awt\TextField.java
+C:\classpath-0.04\java\awt\TexturePaint.java
+C:\classpath-0.04\java\awt\Toolkit.java
+C:\classpath-0.04\java\awt\Transparency.java
+C:\classpath-0.04\java\awt\Window.java
+C:\classpath-0.04\java\awt\color\CMMException.java
+C:\classpath-0.04\java\awt\color\ColorSpace.java
+C:\classpath-0.04\java\awt\color\ICC_ColorSpace.java
+C:\classpath-0.04\java\awt\color\ICC_Profile.java
+C:\classpath-0.04\java\awt\color\ProfileDataException.java
+C:\classpath-0.04\java\awt\datatransfer\Clipboard.java
+C:\classpath-0.04\java\awt\datatransfer\ClipboardOwner.java
+C:\classpath-0.04\java\awt\datatransfer\DataFlavor.java
+C:\classpath-0.04\java\awt\datatransfer\FlavorMap.java
+C:\classpath-0.04\java\awt\datatransfer\MimeTypeParseException.java
+C:\classpath-0.04\java\awt\datatransfer\StringSelection.java
+C:\classpath-0.04\java\awt\datatransfer\SystemFlavorMap.java
+C:\classpath-0.04\java\awt\datatransfer\Transferable.java
+C:\classpath-0.04\java\awt\datatransfer\UnsupportedFlavorException.java
+C:\classpath-0.04\java\awt\dnd\DropTarget.java
+C:\classpath-0.04\java\awt\event\ActionEvent.java
+C:\classpath-0.04\java\awt\event\ActionListener.java
+C:\classpath-0.04\java\awt\event\AdjustmentEvent.java
+C:\classpath-0.04\java\awt\event\AdjustmentListener.java
+C:\classpath-0.04\java\awt\event\AWTEventListener.java
+C:\classpath-0.04\java\awt\event\AWTEventListenerProxy.java
+C:\classpath-0.04\java\awt\event\ComponentAdapter.java
+C:\classpath-0.04\java\awt\event\ComponentEvent.java
+C:\classpath-0.04\java\awt\event\ComponentListener.java
+C:\classpath-0.04\java\awt\event\ContainerAdapter.java
+C:\classpath-0.04\java\awt\event\ContainerEvent.java
+C:\classpath-0.04\java\awt\event\ContainerListener.java
+C:\classpath-0.04\java\awt\event\FocusAdapter.java
+C:\classpath-0.04\java\awt\event\FocusEvent.java
+C:\classpath-0.04\java\awt\event\FocusListener.java
+C:\classpath-0.04\java\awt\event\HierarchyBoundsAdapter.java
+C:\classpath-0.04\java\awt\event\HierarchyBoundsListener.java
+C:\classpath-0.04\java\awt\event\HierarchyEvent.java
+C:\classpath-0.04\java\awt\event\HierarchyListener.java
+C:\classpath-0.04\java\awt\event\InputEvent.java
+C:\classpath-0.04\java\awt\event\InputMethodEvent.java
+C:\classpath-0.04\java\awt\event\InputMethodListener.java
+C:\classpath-0.04\java\awt\event\InvocationEvent.java
+C:\classpath-0.04\java\awt\event\ItemEvent.java
+C:\classpath-0.04\java\awt\event\ItemListener.java
+C:\classpath-0.04\java\awt\event\KeyAdapter.java
+C:\classpath-0.04\java\awt\event\KeyEvent.java
+C:\classpath-0.04\java\awt\event\KeyListener.java
+C:\classpath-0.04\java\awt\event\MouseAdapter.java
+C:\classpath-0.04\java\awt\event\MouseEvent.java
+C:\classpath-0.04\java\awt\event\MouseListener.java
+C:\classpath-0.04\java\awt\event\MouseMotionAdapter.java
+C:\classpath-0.04\java\awt\event\MouseMotionListener.java
+C:\classpath-0.04\java\awt\event\MouseWheelEvent.java
+C:\classpath-0.04\java\awt\event\MouseWheelListener.java
+C:\classpath-0.04\java\awt\event\PaintEvent.java
+C:\classpath-0.04\java\awt\event\TextEvent.java
+C:\classpath-0.04\java\awt\event\TextListener.java
+C:\classpath-0.04\java\awt\event\WindowAdapter.java
+C:\classpath-0.04\java\awt\event\WindowEvent.java
+C:\classpath-0.04\java\awt\event\WindowFocusListener.java
+C:\classpath-0.04\java\awt\event\WindowListener.java
+C:\classpath-0.04\java\awt\event\WindowStateListener.java
+C:\classpath-0.04\java\awt\font\TextHitInfo.java
+C:\classpath-0.04\java\awt\geom\AffineTransform.java
+C:\classpath-0.04\java\awt\geom\Arc2D.java
+C:\classpath-0.04\java\awt\geom\Area.java
+C:\classpath-0.04\java\awt\geom\CubicCurve2D.java
+C:\classpath-0.04\java\awt\geom\Dimension2D.java
+C:\classpath-0.04\java\awt\geom\Ellipse2D.java
+C:\classpath-0.04\java\awt\geom\FlatteningPathIterator.java
+C:\classpath-0.04\java\awt\geom\GeneralPath.java
+C:\classpath-0.04\java\awt\geom\IllegalPathStateException.java
+C:\classpath-0.04\java\awt\geom\Line2D.java
+C:\classpath-0.04\java\awt\geom\NoninvertibleTransformException.java
+C:\classpath-0.04\java\awt\geom\PathIterator.java
+C:\classpath-0.04\java\awt\geom\Point2D.java
+C:\classpath-0.04\java\awt\geom\QuadCurve2D.java
+C:\classpath-0.04\java\awt\geom\Rectangle2D.java
+C:\classpath-0.04\java\awt\geom\RectangularShape.java
+C:\classpath-0.04\java\awt\geom\RoundRectangle2D.java
+C:\classpath-0.04\java\awt\im\InputContext.java
+C:\classpath-0.04\java\awt\im\InputMethodHighlight.java
+C:\classpath-0.04\java\awt\im\InputMethodRequests.java
+C:\classpath-0.04\java\awt\im\InputSubset.java
+C:\classpath-0.04\java\awt\im\spi\InputMethod.java
+C:\classpath-0.04\java\awt\im\spi\InputMethodContext.java
+C:\classpath-0.04\java\awt\im\spi\InputMethodDescriptor.java
+C:\classpath-0.04\java\awt\image\AreaAveragingScaleFilter.java
+C:\classpath-0.04\java\awt\image\BufferedImage.java
+C:\classpath-0.04\java\awt\image\BufferedImageOp.java
+C:\classpath-0.04\java\awt\image\BufferStrategy.java
+C:\classpath-0.04\java\awt\image\ColorModel.java
+C:\classpath-0.04\java\awt\image\ComponentColorModel.java
+C:\classpath-0.04\java\awt\image\ComponentSampleModel.java
+C:\classpath-0.04\java\awt\image\CropImageFilter.java
+C:\classpath-0.04\java\awt\image\DataBuffer.java
+C:\classpath-0.04\java\awt\image\DataBufferByte.java
+C:\classpath-0.04\java\awt\image\DataBufferInt.java
+C:\classpath-0.04\java\awt\image\DataBufferUShort.java
+C:\classpath-0.04\java\awt\image\DirectColorModel.java
+C:\classpath-0.04\java\awt\image\FilteredImageSource.java
+C:\classpath-0.04\java\awt\image\ImageConsumer.java
+C:\classpath-0.04\java\awt\image\ImageFilter.java
+C:\classpath-0.04\java\awt\image\ImageObserver.java
+C:\classpath-0.04\java\awt\image\ImageProducer.java
+C:\classpath-0.04\java\awt\image\ImagingOpException.java
+C:\classpath-0.04\java\awt\image\IndexColorModel.java
+C:\classpath-0.04\java\awt\image\MemoryImageSource.java
+C:\classpath-0.04\java\awt\image\PackedColorModel.java
+C:\classpath-0.04\java\awt\image\PixelGrabber.java
+C:\classpath-0.04\java\awt\image\Raster.java
+C:\classpath-0.04\java\awt\image\RasterFormatException.java
+C:\classpath-0.04\java\awt\image\RasterOp.java
+C:\classpath-0.04\java\awt\image\RenderedImage.java
+C:\classpath-0.04\java\awt\image\ReplicateScaleFilter.java
+C:\classpath-0.04\java\awt\image\RGBImageFilter.java
+C:\classpath-0.04\java\awt\image\SampleModel.java
+C:\classpath-0.04\java\awt\image\SinglePixelPackedSampleModel.java
+C:\classpath-0.04\java\awt\image\TileObserver.java
+C:\classpath-0.04\java\awt\image\VolatileImage.java
+C:\classpath-0.04\java\awt\image\WritableRaster.java
+C:\classpath-0.04\java\awt\image\WritableRenderedImage.java
+C:\classpath-0.04\java\awt\image\renderable\ContextualRenderedImageFactory.java
+C:\classpath-0.04\java\awt\image\renderable\ParameterBlock.java
+C:\classpath-0.04\java\awt\image\renderable\RenderableImage.java
+C:\classpath-0.04\java\awt\image\renderable\RenderableImageOp.java
+C:\classpath-0.04\java\awt\image\renderable\RenderableImageProducer.java
+C:\classpath-0.04\java\awt\image\renderable\RenderContext.java
+C:\classpath-0.04\java\awt\image\renderable\RenderedImageFactory.java
+C:\classpath-0.04\java\awt\peer\ButtonPeer.java
+C:\classpath-0.04\java\awt\peer\CanvasPeer.java
+C:\classpath-0.04\java\awt\peer\CheckboxMenuItemPeer.java
+C:\classpath-0.04\java\awt\peer\CheckboxPeer.java
+C:\classpath-0.04\java\awt\peer\ChoicePeer.java
+C:\classpath-0.04\java\awt\peer\ComponentPeer.java
+C:\classpath-0.04\java\awt\peer\ContainerPeer.java
+C:\classpath-0.04\java\awt\peer\DialogPeer.java
+C:\classpath-0.04\java\awt\peer\FileDialogPeer.java
+C:\classpath-0.04\java\awt\peer\FontPeer.java
+C:\classpath-0.04\java\awt\peer\FramePeer.java
+C:\classpath-0.04\java\awt\peer\LabelPeer.java
+C:\classpath-0.04\java\awt\peer\LightweightPeer.java
+C:\classpath-0.04\java\awt\peer\ListPeer.java
+C:\classpath-0.04\java\awt\peer\MenuBarPeer.java
+C:\classpath-0.04\java\awt\peer\MenuComponentPeer.java
+C:\classpath-0.04\java\awt\peer\MenuItemPeer.java
+C:\classpath-0.04\java\awt\peer\MenuPeer.java
+C:\classpath-0.04\java\awt\peer\PanelPeer.java
+C:\classpath-0.04\java\awt\peer\PopupMenuPeer.java
+C:\classpath-0.04\java\awt\peer\ScrollbarPeer.java
+C:\classpath-0.04\java\awt\peer\ScrollPanePeer.java
+C:\classpath-0.04\java\awt\peer\TextAreaPeer.java
+C:\classpath-0.04\java\awt\peer\TextComponentPeer.java
+C:\classpath-0.04\java\awt\peer\TextFieldPeer.java
+C:\classpath-0.04\java\awt\peer\WindowPeer.java
+C:\classpath-0.04\java\awt\print\Book.java
+C:\classpath-0.04\java\awt\print\Pageable.java
+C:\classpath-0.04\java\awt\print\PageFormat.java
+C:\classpath-0.04\java\awt\print\Paper.java
+C:\classpath-0.04\java\awt\print\Printable.java
+C:\classpath-0.04\java\awt\print\PrinterAbortException.java
+C:\classpath-0.04\java\awt\print\PrinterException.java
+C:\classpath-0.04\java\awt\print\PrinterGraphics.java
+C:\classpath-0.04\java\awt\print\PrinterIOException.java
+C:\classpath-0.04\java\awt\print\PrinterJob.java
+C:\classpath-0.04\java\beans\AppletInitializer.java
+C:\classpath-0.04\java\beans\BeanDescriptor.java
+C:\classpath-0.04\java\beans\BeanInfo.java
+C:\classpath-0.04\java\beans\Beans.java
+C:\classpath-0.04\java\beans\Customizer.java
+C:\classpath-0.04\java\beans\DesignMode.java
+C:\classpath-0.04\java\beans\EventSetDescriptor.java
+C:\classpath-0.04\java\beans\ExceptionListener.java
+C:\classpath-0.04\java\beans\FeatureDescriptor.java
+C:\classpath-0.04\java\beans\IndexedPropertyDescriptor.java
+C:\classpath-0.04\java\beans\IntrospectionException.java
+C:\classpath-0.04\java\beans\Introspector.java
+C:\classpath-0.04\java\beans\MethodDescriptor.java
+C:\classpath-0.04\java\beans\ParameterDescriptor.java
+C:\classpath-0.04\java\beans\PropertyChangeEvent.java
+C:\classpath-0.04\java\beans\PropertyChangeListener.java
+C:\classpath-0.04\java\beans\PropertyChangeListenerProxy.java
+C:\classpath-0.04\java\beans\PropertyChangeSupport.java
+C:\classpath-0.04\java\beans\PropertyDescriptor.java
+C:\classpath-0.04\java\beans\PropertyEditor.java
+C:\classpath-0.04\java\beans\PropertyEditorManager.java
+C:\classpath-0.04\java\beans\PropertyEditorSupport.java
+C:\classpath-0.04\java\beans\PropertyVetoException.java
+C:\classpath-0.04\java\beans\SimpleBeanInfo.java
+C:\classpath-0.04\java\beans\VetoableChangeListener.java
+C:\classpath-0.04\java\beans\VetoableChangeListenerProxy.java
+C:\classpath-0.04\java\beans\VetoableChangeSupport.java
+C:\classpath-0.04\java\beans\Visibility.java
+C:\classpath-0.04\java\beans\beancontext\BeanContext.java
+C:\classpath-0.04\java\beans\beancontext\BeanContextChild.java
+C:\classpath-0.04\java\beans\beancontext\BeanContextChildComponentProxy.java
+C:\classpath-0.04\java\beans\beancontext\BeanContextChildSupport.java
+C:\classpath-0.04\java\beans\beancontext\BeanContextContainerProxy.java
+C:\classpath-0.04\java\beans\beancontext\BeanContextEvent.java
+C:\classpath-0.04\java\beans\beancontext\BeanContextMembershipEvent.java
+C:\classpath-0.04\java\beans\beancontext\BeanContextMembershipListener.java
+C:\classpath-0.04\java\beans\beancontext\BeanContextProxy.java
+C:\classpath-0.04\java\beans\beancontext\BeanContextServiceAvailableEvent.java
+C:\classpath-0.04\java\beans\beancontext\BeanContextServiceProvider.java
+C:\classpath-0.04\java\beans\beancontext\BeanContextServiceProviderBeanInfo.java
+C:\classpath-0.04\java\beans\beancontext\BeanContextServiceRevokedEvent.java
+C:\classpath-0.04\java\beans\beancontext\BeanContextServiceRevokedListener.java
+C:\classpath-0.04\java\beans\beancontext\BeanContextServices.java
+C:\classpath-0.04\java\beans\beancontext\BeanContextServicesListener.java
+C:\classpath-0.04\java\io\BufferedInputStream.java
+C:\classpath-0.04\java\io\BufferedOutputStream.java
+C:\classpath-0.04\java\io\BufferedReader.java
+C:\classpath-0.04\java\io\BufferedWriter.java
+C:\classpath-0.04\java\io\ByteArrayInputStream.java
+C:\classpath-0.04\java\io\ByteArrayOutputStream.java
+C:\classpath-0.04\java\io\CharArrayReader.java
+C:\classpath-0.04\java\io\CharArrayWriter.java
+C:\classpath-0.04\java\io\CharConversionException.java
+C:\classpath-0.04\java\io\DataInput.java
+C:\classpath-0.04\java\io\DataInputStream.java
+C:\classpath-0.04\java\io\DataOutput.java
+C:\classpath-0.04\java\io\DataOutputStream.java
+C:\classpath-0.04\java\io\EOFException.java
+C:\classpath-0.04\java\io\Externalizable.java
+C:\classpath-0.04\java\io\File.java
+C:\classpath-0.04\java\io\FileFilter.java
+C:\classpath-0.04\java\io\FilenameFilter.java
+C:\classpath-0.04\java\io\FileNotFoundException.java
+C:\classpath-0.04\java\io\FilePermission.java
+C:\classpath-0.04\java\io\FileReader.java
+C:\classpath-0.04\java\io\FileWriter.java
+C:\classpath-0.04\java\io\FilterInputStream.java
+C:\classpath-0.04\java\io\FilterOutputStream.java
+C:\classpath-0.04\java\io\FilterReader.java
+C:\classpath-0.04\java\io\FilterWriter.java
+C:\classpath-0.04\java\io\InputStream.java
+C:\classpath-0.04\java\io\InputStreamReader.java
+C:\classpath-0.04\java\io\InterruptedIOException.java
+C:\classpath-0.04\java\io\InvalidClassException.java
+C:\classpath-0.04\java\io\InvalidObjectException.java
+C:\classpath-0.04\java\io\IOException.java
+C:\classpath-0.04\java\io\LineNumberInputStream.java
+C:\classpath-0.04\java\io\LineNumberReader.java
+C:\classpath-0.04\java\io\NotActiveException.java
+C:\classpath-0.04\java\io\NotSerializableException.java
+C:\classpath-0.04\java\io\ObjectInput.java
+C:\classpath-0.04\java\io\ObjectInputStream.java
+C:\classpath-0.04\java\io\ObjectInputValidation.java
+C:\classpath-0.04\java\io\ObjectOutput.java
+C:\classpath-0.04\java\io\ObjectOutputStream.java
+C:\classpath-0.04\java\io\ObjectStreamClass.java
+C:\classpath-0.04\java\io\ObjectStreamConstants.java
+C:\classpath-0.04\java\io\ObjectStreamException.java
+C:\classpath-0.04\java\io\ObjectStreamField.java
+C:\classpath-0.04\java\io\OptionalDataException.java
+C:\classpath-0.04\java\io\OutputStream.java
+C:\classpath-0.04\java\io\OutputStreamWriter.java
+C:\classpath-0.04\java\io\PipedInputStream.java
+C:\classpath-0.04\java\io\PipedOutputStream.java
+C:\classpath-0.04\java\io\PipedReader.java
+C:\classpath-0.04\java\io\PipedWriter.java
+C:\classpath-0.04\java\io\PrintStream.java
+C:\classpath-0.04\java\io\PrintWriter.java
+C:\classpath-0.04\java\io\PushbackInputStream.java
+C:\classpath-0.04\java\io\PushbackReader.java
+C:\classpath-0.04\java\io\Reader.java
+C:\classpath-0.04\java\io\SequenceInputStream.java
+C:\classpath-0.04\java\io\Serializable.java
+C:\classpath-0.04\java\io\SerializablePermission.java
+C:\classpath-0.04\java\io\StreamCorruptedException.java
+C:\classpath-0.04\java\io\StreamTokenizer.java
+C:\classpath-0.04\java\io\StringBufferInputStream.java
+C:\classpath-0.04\java\io\StringReader.java
+C:\classpath-0.04\java\io\StringWriter.java
+C:\classpath-0.04\java\io\SyncFailedException.java
+C:\classpath-0.04\java\io\UnsupportedEncodingException.java
+C:\classpath-0.04\java\io\UTFDataFormatException.java
+C:\classpath-0.04\java\io\WriteAbortedException.java
+C:\classpath-0.04\java\io\Writer.java
+C:\classpath-0.04\java\lang\AbstractMethodError.java
+C:\classpath-0.04\java\lang\ArithmeticException.java
+C:\classpath-0.04\java\lang\ArrayIndexOutOfBoundsException.java
+C:\classpath-0.04\java\lang\ArrayStoreException.java
+C:\classpath-0.04\java\lang\AssertionError.java
+C:\classpath-0.04\java\lang\Boolean.java
+C:\classpath-0.04\java\lang\Byte.java
+C:\classpath-0.04\java\lang\Character.java
+C:\classpath-0.04\java\lang\CharSequence.java
+C:\classpath-0.04\java\lang\ClassCastException.java
+C:\classpath-0.04\java\lang\ClassCircularityError.java
+C:\classpath-0.04\java\lang\ClassFormatError.java
+C:\classpath-0.04\java\lang\ClassLoader.java
+C:\classpath-0.04\java\lang\ClassNotFoundException.java
+C:\classpath-0.04\java\lang\Cloneable.java
+C:\classpath-0.04\java\lang\CloneNotSupportedException.java
+C:\classpath-0.04\java\lang\Comparable.java
+C:\classpath-0.04\java\lang\Compiler.java
+C:\classpath-0.04\java\lang\Double.java
+C:\classpath-0.04\java\lang\Error.java
+C:\classpath-0.04\java\lang\Exception.java
+C:\classpath-0.04\java\lang\ExceptionInInitializerError.java
+C:\classpath-0.04\java\lang\Float.java
+C:\classpath-0.04\java\lang\IllegalAccessError.java
+C:\classpath-0.04\java\lang\IllegalAccessException.java
+C:\classpath-0.04\java\lang\IllegalArgumentException.java
+C:\classpath-0.04\java\lang\IllegalMonitorStateException.java
+C:\classpath-0.04\java\lang\IllegalStateException.java
+C:\classpath-0.04\java\lang\IllegalThreadStateException.java
+C:\classpath-0.04\java\lang\IncompatibleClassChangeError.java
+C:\classpath-0.04\java\lang\IndexOutOfBoundsException.java
+C:\classpath-0.04\java\lang\InheritableThreadLocal.java
+C:\classpath-0.04\java\lang\InstantiationError.java
+C:\classpath-0.04\java\lang\InstantiationException.java
+C:\classpath-0.04\java\lang\Integer.java
+C:\classpath-0.04\java\lang\InternalError.java
+C:\classpath-0.04\java\lang\InterruptedException.java
+C:\classpath-0.04\java\lang\LinkageError.java
+C:\classpath-0.04\java\lang\Long.java
+C:\classpath-0.04\java\lang\Math.java
+C:\classpath-0.04\java\lang\NegativeArraySizeException.java
+C:\classpath-0.04\java\lang\NoClassDefFoundError.java
+C:\classpath-0.04\java\lang\NoSuchFieldError.java
+C:\classpath-0.04\java\lang\NoSuchFieldException.java
+C:\classpath-0.04\java\lang\NoSuchMethodError.java
+C:\classpath-0.04\java\lang\NoSuchMethodException.java
+C:\classpath-0.04\java\lang\NullPointerException.java
+C:\classpath-0.04\java\lang\Number.java
+C:\classpath-0.04\java\lang\NumberFormatException.java
+C:\classpath-0.04\java\lang\Object.java
+C:\classpath-0.04\java\lang\OutOfMemoryError.java
+C:\classpath-0.04\java\lang\Package.java
+C:\classpath-0.04\java\lang\Process.java
+C:\classpath-0.04\java\lang\Runnable.java
+C:\classpath-0.04\java\lang\RuntimeException.java
+C:\classpath-0.04\java\lang\RuntimePermission.java
+C:\classpath-0.04\java\lang\SecurityException.java
+C:\classpath-0.04\java\lang\SecurityManager.java
+C:\classpath-0.04\java\lang\Short.java
+C:\classpath-0.04\java\lang\StackOverflowError.java
+C:\classpath-0.04\java\lang\StackTraceElement.java
+C:\classpath-0.04\java\lang\StrictMath.java
+C:\classpath-0.04\java\lang\String.java
+C:\classpath-0.04\java\lang\StringBuffer.java
+C:\classpath-0.04\java\lang\StringIndexOutOfBoundsException.java
+C:\classpath-0.04\java\lang\System.java
+C:\classpath-0.04\java\lang\ThreadDeath.java
+C:\classpath-0.04\java\lang\ThreadGroup.java
+C:\classpath-0.04\java\lang\ThreadLocal.java
+C:\classpath-0.04\java\lang\UnknownError.java
+C:\classpath-0.04\java\lang\UnsatisfiedLinkError.java
+C:\classpath-0.04\java\lang\UnsupportedClassVersionError.java
+C:\classpath-0.04\java\lang\UnsupportedOperationException.java
+C:\classpath-0.04\java\lang\VerifyError.java
+C:\classpath-0.04\java\lang\VirtualMachineError.java
+C:\classpath-0.04\java\lang\Void.java
+C:\classpath-0.04\java\lang\ref\PhantomReference.java
+C:\classpath-0.04\java\lang\ref\Reference.java
+C:\classpath-0.04\java\lang\ref\ReferenceQueue.java
+C:\classpath-0.04\java\lang\ref\SoftReference.java
+C:\classpath-0.04\java\lang\ref\WeakReference.java
+C:\classpath-0.04\java\lang\reflect\AccessibleObject.java
+C:\classpath-0.04\java\lang\reflect\Array.java
+C:\classpath-0.04\java\lang\reflect\InvocationHandler.java
+C:\classpath-0.04\java\lang\reflect\InvocationTargetException.java
+C:\classpath-0.04\java\lang\reflect\Member.java
+C:\classpath-0.04\java\lang\reflect\Modifier.java
+C:\classpath-0.04\java\lang\reflect\Proxy.java
+C:\classpath-0.04\java\lang\reflect\ReflectPermission.java
+C:\classpath-0.04\java\lang\reflect\UndeclaredThrowableException.java
+C:\classpath-0.04\java\math\BigDecimal.java
+C:\classpath-0.04\java\math\BigInteger.java
+C:\classpath-0.04\java\net\Authenticator.java
+C:\classpath-0.04\java\net\BindException.java
+C:\classpath-0.04\java\net\ConnectException.java
+C:\classpath-0.04\java\net\ContentHandler.java
+C:\classpath-0.04\java\net\ContentHandlerFactory.java
+C:\classpath-0.04\java\net\DatagramPacket.java
+C:\classpath-0.04\java\net\DatagramSocket.java
+C:\classpath-0.04\java\net\DatagramSocketImpl.java
+C:\classpath-0.04\java\net\FileNameMap.java
+C:\classpath-0.04\java\net\HttpURLConnection.java
+C:\classpath-0.04\java\net\InetAddress.java
+C:\classpath-0.04\java\net\InetSocketAddress.java
+C:\classpath-0.04\java\net\JarURLConnection.java
+C:\classpath-0.04\java\net\MalformedURLException.java
+C:\classpath-0.04\java\net\MimeTypeMapper.java
+C:\classpath-0.04\java\net\MulticastSocket.java
+C:\classpath-0.04\java\net\NetPermission.java
+C:\classpath-0.04\java\net\NoRouteToHostException.java
+C:\classpath-0.04\java\net\PasswordAuthentication.java
+C:\classpath-0.04\java\net\PortUnreachableException.java
+C:\classpath-0.04\java\net\ProtocolException.java
+C:\classpath-0.04\java\net\ServerSocket.java
+C:\classpath-0.04\java\net\Socket.java
+C:\classpath-0.04\java\net\SocketAddress.java
+C:\classpath-0.04\java\net\SocketException.java
+C:\classpath-0.04\java\net\SocketImpl.java
+C:\classpath-0.04\java\net\SocketImplFactory.java
+C:\classpath-0.04\java\net\SocketInputStream.java
+C:\classpath-0.04\java\net\SocketOptions.java
+C:\classpath-0.04\java\net\SocketOutputStream.java
+C:\classpath-0.04\java\net\SocketPermission.java
+C:\classpath-0.04\java\net\SocketTimeoutException.java
+C:\classpath-0.04\java\net\UnknownHostException.java
+C:\classpath-0.04\java\net\UnknownServiceException.java
+C:\classpath-0.04\java\net\URISyntaxException.java
+C:\classpath-0.04\java\net\URL.java
+C:\classpath-0.04\java\net\URLClassLoader.java
+C:\classpath-0.04\java\net\URLConnection.java
+C:\classpath-0.04\java\net\URLDecoder.java
+C:\classpath-0.04\java\net\URLEncoder.java
+C:\classpath-0.04\java\net\URLStreamHandler.java
+C:\classpath-0.04\java\net\URLStreamHandlerFactory.java
+C:\classpath-0.04\java\nio\Buffer.java
+C:\classpath-0.04\java\nio\ByteBuffer.java
+C:\classpath-0.04\java\nio\ByteOrder.java
+C:\classpath-0.04\java\nio\CharBuffer.java
+C:\classpath-0.04\java\nio\DoubleBuffer.java
+C:\classpath-0.04\java\nio\FloatBuffer.java
+C:\classpath-0.04\java\nio\IntBuffer.java
+C:\classpath-0.04\java\nio\LongBuffer.java
+C:\classpath-0.04\java\nio\MappedByteBuffer.java
+C:\classpath-0.04\java\nio\ShortBuffer.java
+C:\classpath-0.04\java\nio\channels\AlreadyConnectedException.java
+C:\classpath-0.04\java\nio\channels\ByteChannel.java
+C:\classpath-0.04\java\nio\channels\Channel.java
+C:\classpath-0.04\java\nio\channels\Channels.java
+C:\classpath-0.04\java\nio\channels\ClosedChannelException.java
+C:\classpath-0.04\java\nio\channels\DatagramChannel.java
+C:\classpath-0.04\java\nio\channels\FileChannel.java
+C:\classpath-0.04\java\nio\channels\FileLock.java
+C:\classpath-0.04\java\nio\channels\GatheringByteChannel.java
+C:\classpath-0.04\java\nio\channels\InterruptibleChannel.java
+C:\classpath-0.04\java\nio\channels\Pipe.java
+C:\classpath-0.04\java\nio\channels\ReadableByteChannel.java
+C:\classpath-0.04\java\nio\channels\ScatteringByteChannel.java
+C:\classpath-0.04\java\nio\channels\SelectableChannel.java
+C:\classpath-0.04\java\nio\channels\SelectionKey.java
+C:\classpath-0.04\java\nio\channels\Selector.java
+C:\classpath-0.04\java\nio\channels\ServerSocketChannel.java
+C:\classpath-0.04\java\nio\channels\SocketChannel.java
+C:\classpath-0.04\java\nio\channels\WritableByteChannel.java
+C:\classpath-0.04\java\nio\channels\spi\AbstractInterruptibleChannel.java
+C:\classpath-0.04\java\nio\channels\spi\AbstractSelectableChannel.java
+C:\classpath-0.04\java\nio\channels\spi\AbstractSelectionKey.java
+C:\classpath-0.04\java\nio\channels\spi\AbstractSelector.java
+C:\classpath-0.04\java\nio\channels\spi\SelectorProvider.java
+C:\classpath-0.04\java\nio\charset\CharacterCodingException.java
+C:\classpath-0.04\java\nio\charset\Charset.java
+C:\classpath-0.04\java\nio\charset\CharsetDecoder.java
+C:\classpath-0.04\java\nio\charset\CharsetEncoder.java
+C:\classpath-0.04\java\nio\charset\CoderResult.java
+C:\classpath-0.04\java\nio\charset\CodingErrorAction.java
+C:\classpath-0.04\java\rmi\AccessException.java
+C:\classpath-0.04\java\rmi\AlreadyBoundException.java
+C:\classpath-0.04\java\rmi\ConnectException.java
+C:\classpath-0.04\java\rmi\ConnectIOException.java
+C:\classpath-0.04\java\rmi\MarshalException.java
+C:\classpath-0.04\java\rmi\MarshalledObject.java
+C:\classpath-0.04\java\rmi\Naming.java
+C:\classpath-0.04\java\rmi\NoSuchObjectException.java
+C:\classpath-0.04\java\rmi\NotBoundException.java
+C:\classpath-0.04\java\rmi\Remote.java
+C:\classpath-0.04\java\rmi\RemoteException.java
+C:\classpath-0.04\java\rmi\RMISecurityException.java
+C:\classpath-0.04\java\rmi\RMISecurityManager.java
+C:\classpath-0.04\java\rmi\ServerError.java
+C:\classpath-0.04\java\rmi\ServerException.java
+C:\classpath-0.04\java\rmi\ServerRuntimeException.java
+C:\classpath-0.04\java\rmi\StubNotFoundException.java
+C:\classpath-0.04\java\rmi\UnexpectedException.java
+C:\classpath-0.04\java\rmi\UnknownHostException.java
+C:\classpath-0.04\java\rmi\UnmarshalException.java
+C:\classpath-0.04\java\rmi\activation\Activatable.java
+C:\classpath-0.04\java\rmi\activation\ActivateFailedException.java
+C:\classpath-0.04\java\rmi\activation\ActivationDesc.java
+C:\classpath-0.04\java\rmi\activation\ActivationException.java
+C:\classpath-0.04\java\rmi\activation\ActivationGroup.java
+C:\classpath-0.04\java\rmi\activation\ActivationGroupDesc.java
+C:\classpath-0.04\java\rmi\activation\ActivationGroupID.java
+C:\classpath-0.04\java\rmi\activation\ActivationID.java
+C:\classpath-0.04\java\rmi\activation\ActivationInstantiator.java
+C:\classpath-0.04\java\rmi\activation\ActivationMonitor.java
+C:\classpath-0.04\java\rmi\activation\ActivationSystem.java
+C:\classpath-0.04\java\rmi\activation\Activator.java
+C:\classpath-0.04\java\rmi\activation\UnknownGroupException.java
+C:\classpath-0.04\java\rmi\activation\UnknownObjectException.java
+C:\classpath-0.04\java\rmi\dgc\DGC.java
+C:\classpath-0.04\java\rmi\dgc\Lease.java
+C:\classpath-0.04\java\rmi\dgc\VMID.java
+C:\classpath-0.04\java\rmi\registry\LocateRegistry.java
+C:\classpath-0.04\java\rmi\registry\Registry.java
+C:\classpath-0.04\java\rmi\registry\RegistryHandler.java
+C:\classpath-0.04\java\rmi\server\ExportException.java
+C:\classpath-0.04\java\rmi\server\LoaderHandler.java
+C:\classpath-0.04\java\rmi\server\LogStream.java
+C:\classpath-0.04\java\rmi\server\ObjID.java
+C:\classpath-0.04\java\rmi\server\Operation.java
+C:\classpath-0.04\java\rmi\server\RemoteCall.java
+C:\classpath-0.04\java\rmi\server\RemoteObject.java
+C:\classpath-0.04\java\rmi\server\RemoteRef.java
+C:\classpath-0.04\java\rmi\server\RemoteServer.java
+C:\classpath-0.04\java\rmi\server\RemoteStub.java
+C:\classpath-0.04\java\rmi\server\RMIClassLoader.java
+C:\classpath-0.04\java\rmi\server\RMIClientSocketFactory.java
+C:\classpath-0.04\java\rmi\server\RMIFailureHandler.java
+C:\classpath-0.04\java\rmi\server\RMIServerSocketFactory.java
+C:\classpath-0.04\java\rmi\server\RMISocketFactory.java
+C:\classpath-0.04\java\rmi\server\ServerCloneException.java
+C:\classpath-0.04\java\rmi\server\ServerNotActiveException.java
+C:\classpath-0.04\java\rmi\server\ServerRef.java
+C:\classpath-0.04\java\rmi\server\Skeleton.java
+C:\classpath-0.04\java\rmi\server\SkeletonMismatchException.java
+C:\classpath-0.04\java\rmi\server\SkeletonNotFoundException.java
+C:\classpath-0.04\java\rmi\server\SocketSecurityException.java
+C:\classpath-0.04\java\rmi\server\UID.java
+C:\classpath-0.04\java\rmi\server\UnicastRemoteObject.java
+C:\classpath-0.04\java\rmi\server\Unreferenced.java
+C:\classpath-0.04\java\security\AccessControlContext.java
+C:\classpath-0.04\java\security\AccessControlException.java
+C:\classpath-0.04\java\security\AccessController.java
+C:\classpath-0.04\java\security\AlgorithmParameterGenerator.java
+C:\classpath-0.04\java\security\AlgorithmParameterGeneratorSpi.java
+C:\classpath-0.04\java\security\AlgorithmParameters.java
+C:\classpath-0.04\java\security\AlgorithmParametersSpi.java
+C:\classpath-0.04\java\security\AllPermission.java
+C:\classpath-0.04\java\security\BasicPermission.java
+C:\classpath-0.04\java\security\Certificate.java
+C:\classpath-0.04\java\security\CodeSource.java
+C:\classpath-0.04\java\security\DigestException.java
+C:\classpath-0.04\java\security\DigestInputStream.java
+C:\classpath-0.04\java\security\DigestOutputStream.java
+C:\classpath-0.04\java\security\DomainCombiner.java
+C:\classpath-0.04\java\security\DummyKeyPairGenerator.java
+C:\classpath-0.04\java\security\DummyMessageDigest.java
+C:\classpath-0.04\java\security\DummySignature.java
+C:\classpath-0.04\java\security\GeneralSecurityException.java
+C:\classpath-0.04\java\security\Guard.java
+C:\classpath-0.04\java\security\GuardedObject.java
+C:\classpath-0.04\java\security\Identity.java
+C:\classpath-0.04\java\security\IdentityScope.java
+C:\classpath-0.04\java\security\InvalidAlgorithmParameterException.java
+C:\classpath-0.04\java\security\InvalidKeyException.java
+C:\classpath-0.04\java\security\InvalidParameterException.java
+C:\classpath-0.04\java\security\Key.java
+C:\classpath-0.04\java\security\KeyException.java
+C:\classpath-0.04\java\security\KeyFactory.java
+C:\classpath-0.04\java\security\KeyFactorySpi.java
+C:\classpath-0.04\java\security\KeyManagementException.java
+C:\classpath-0.04\java\security\KeyPair.java
+C:\classpath-0.04\java\security\KeyPairGenerator.java
+C:\classpath-0.04\java\security\KeyPairGeneratorSpi.java
+C:\classpath-0.04\java\security\KeyStore.java
+C:\classpath-0.04\java\security\KeyStoreException.java
+C:\classpath-0.04\java\security\KeyStoreSpi.java
+C:\classpath-0.04\java\security\MessageDigest.java
+C:\classpath-0.04\java\security\MessageDigestSpi.java
+C:\classpath-0.04\java\security\NoSuchAlgorithmException.java
+C:\classpath-0.04\java\security\NoSuchProviderException.java
+C:\classpath-0.04\java\security\Permission.java
+C:\classpath-0.04\java\security\PermissionCollection.java
+C:\classpath-0.04\java\security\Permissions.java
+C:\classpath-0.04\java\security\Policy.java
+C:\classpath-0.04\java\security\Principal.java
+C:\classpath-0.04\java\security\PrivateKey.java
+C:\classpath-0.04\java\security\PrivilegedAction.java
+C:\classpath-0.04\java\security\PrivilegedActionException.java
+C:\classpath-0.04\java\security\PrivilegedExceptionAction.java
+C:\classpath-0.04\java\security\ProtectionDomain.java
+C:\classpath-0.04\java\security\Provider.java
+C:\classpath-0.04\java\security\ProviderException.java
+C:\classpath-0.04\java\security\PublicKey.java
+C:\classpath-0.04\java\security\SecureClassLoader.java
+C:\classpath-0.04\java\security\SecureRandom.java
+C:\classpath-0.04\java\security\SecureRandomSpi.java
+C:\classpath-0.04\java\security\Security.java
+C:\classpath-0.04\java\security\SecurityPermission.java
+C:\classpath-0.04\java\security\Signature.java
+C:\classpath-0.04\java\security\SignatureException.java
+C:\classpath-0.04\java\security\SignatureSpi.java
+C:\classpath-0.04\java\security\SignedObject.java
+C:\classpath-0.04\java\security\Signer.java
+C:\classpath-0.04\java\security\UnrecoverableKeyException.java
+C:\classpath-0.04\java\security\UnresolvedPermission.java
+C:\classpath-0.04\java\security\acl\Acl.java
+C:\classpath-0.04\java\security\acl\AclEntry.java
+C:\classpath-0.04\java\security\acl\AclNotFoundException.java
+C:\classpath-0.04\java\security\acl\Group.java
+C:\classpath-0.04\java\security\acl\LastOwnerException.java
+C:\classpath-0.04\java\security\acl\NotOwnerException.java
+C:\classpath-0.04\java\security\acl\Owner.java
+C:\classpath-0.04\java\security\acl\Permission.java
+C:\classpath-0.04\java\security\cert\Certificate.java
+C:\classpath-0.04\java\security\cert\CertificateEncodingException.java
+C:\classpath-0.04\java\security\cert\CertificateException.java
+C:\classpath-0.04\java\security\cert\CertificateExpiredException.java
+C:\classpath-0.04\java\security\cert\CertificateFactory.java
+C:\classpath-0.04\java\security\cert\CertificateFactorySpi.java
+C:\classpath-0.04\java\security\cert\CertificateNotYetValidException.java
+C:\classpath-0.04\java\security\cert\CertificateParsingException.java
+C:\classpath-0.04\java\security\cert\CertPath.java
+C:\classpath-0.04\java\security\cert\CertPathBuilderException.java
+C:\classpath-0.04\java\security\cert\CertPathValidatorException.java
+C:\classpath-0.04\java\security\cert\CertStoreException.java
+C:\classpath-0.04\java\security\cert\CRL.java
+C:\classpath-0.04\java\security\cert\CRLException.java
+C:\classpath-0.04\java\security\cert\X509Certificate.java
+C:\classpath-0.04\java\security\cert\X509CRL.java
+C:\classpath-0.04\java\security\cert\X509CRLEntry.java
+C:\classpath-0.04\java\security\cert\X509Extension.java
+C:\classpath-0.04\java\security\interfaces\DSAKey.java
+C:\classpath-0.04\java\security\interfaces\DSAKeyPairGenerator.java
+C:\classpath-0.04\java\security\interfaces\DSAParams.java
+C:\classpath-0.04\java\security\interfaces\DSAPrivateKey.java
+C:\classpath-0.04\java\security\interfaces\DSAPublicKey.java
+C:\classpath-0.04\java\security\interfaces\RSAKey.java
+C:\classpath-0.04\java\security\interfaces\RSAPrivateCrtKey.java
+C:\classpath-0.04\java\security\interfaces\RSAPrivateKey.java
+C:\classpath-0.04\java\security\interfaces\RSAPublicKey.java
+C:\classpath-0.04\java\security\spec\AlgorithmParameterSpec.java
+C:\classpath-0.04\java\security\spec\DSAParameterSpec.java
+C:\classpath-0.04\java\security\spec\DSAPrivateKeySpec.java
+C:\classpath-0.04\java\security\spec\DSAPublicKeySpec.java
+C:\classpath-0.04\java\security\spec\EncodedKeySpec.java
+C:\classpath-0.04\java\security\spec\InvalidKeySpecException.java
+C:\classpath-0.04\java\security\spec\InvalidParameterSpecException.java
+C:\classpath-0.04\java\security\spec\KeySpec.java
+C:\classpath-0.04\java\security\spec\PKCS8EncodedKeySpec.java
+C:\classpath-0.04\java\security\spec\RSAKeyGenParameterSpec.java
+C:\classpath-0.04\java\security\spec\RSAPrivateCrtKeySpec.java
+C:\classpath-0.04\java\security\spec\RSAPrivateKeySpec.java
+C:\classpath-0.04\java\security\spec\RSAPublicKeySpec.java
+C:\classpath-0.04\java\security\spec\X509EncodedKeySpec.java
+C:\classpath-0.04\java\sql\Array.java
+C:\classpath-0.04\java\sql\BatchUpdateException.java
+C:\classpath-0.04\java\sql\Blob.java
+C:\classpath-0.04\java\sql\CallableStatement.java
+C:\classpath-0.04\java\sql\Clob.java
+C:\classpath-0.04\java\sql\Connection.java
+C:\classpath-0.04\java\sql\DatabaseMetaData.java
+C:\classpath-0.04\java\sql\DataTruncation.java
+C:\classpath-0.04\java\sql\Date.java
+C:\classpath-0.04\java\sql\Driver.java
+C:\classpath-0.04\java\sql\DriverManager.java
+C:\classpath-0.04\java\sql\DriverPropertyInfo.java
+C:\classpath-0.04\java\sql\PreparedStatement.java
+C:\classpath-0.04\java\sql\Ref.java
+C:\classpath-0.04\java\sql\ResultSet.java
+C:\classpath-0.04\java\sql\ResultSetMetaData.java
+C:\classpath-0.04\java\sql\SQLData.java
+C:\classpath-0.04\java\sql\SQLException.java
+C:\classpath-0.04\java\sql\SQLInput.java
+C:\classpath-0.04\java\sql\SQLOutput.java
+C:\classpath-0.04\java\sql\SQLWarning.java
+C:\classpath-0.04\java\sql\Statement.java
+C:\classpath-0.04\java\sql\Struct.java
+C:\classpath-0.04\java\sql\Time.java
+C:\classpath-0.04\java\sql\Timestamp.java
+C:\classpath-0.04\java\sql\Types.java
+C:\classpath-0.04\java\text\Annotation.java
+C:\classpath-0.04\java\text\AttributedCharacterIterator.java
+C:\classpath-0.04\java\text\AttributedString.java
+C:\classpath-0.04\java\text\AttributedStringIterator.java
+C:\classpath-0.04\java\text\BreakIterator.java
+C:\classpath-0.04\java\text\CharacterIterator.java
+C:\classpath-0.04\java\text\ChoiceFormat.java
+C:\classpath-0.04\java\text\CollationElementIterator.java
+C:\classpath-0.04\java\text\CollationKey.java
+C:\classpath-0.04\java\text\Collator.java
+C:\classpath-0.04\java\text\DateFormat.java
+C:\classpath-0.04\java\text\DateFormatSymbols.java
+C:\classpath-0.04\java\text\DecimalFormat.java
+C:\classpath-0.04\java\text\DecimalFormatSymbols.java
+C:\classpath-0.04\java\text\FieldPosition.java
+C:\classpath-0.04\java\text\Format.java
+C:\classpath-0.04\java\text\MessageFormat.java
+C:\classpath-0.04\java\text\NumberFormat.java
+C:\classpath-0.04\java\text\ParseException.java
+C:\classpath-0.04\java\text\ParsePosition.java
+C:\classpath-0.04\java\text\RuleBasedCollator.java
+C:\classpath-0.04\java\text\SimpleDateFormat.java
+C:\classpath-0.04\java\text\StringCharacterIterator.java
+C:\classpath-0.04\java\util\AbstractCollection.java
+C:\classpath-0.04\java\util\AbstractList.java
+C:\classpath-0.04\java\util\AbstractMap.java
+C:\classpath-0.04\java\util\AbstractSequentialList.java
+C:\classpath-0.04\java\util\AbstractSet.java
+C:\classpath-0.04\java\util\ArrayList.java
+C:\classpath-0.04\java\util\Arrays.java
+C:\classpath-0.04\java\util\BitSet.java
+C:\classpath-0.04\java\util\Calendar.java
+C:\classpath-0.04\java\util\Collection.java
+C:\classpath-0.04\java\util\Collections.java
+C:\classpath-0.04\java\util\Comparator.java
+C:\classpath-0.04\java\util\ConcurrentModificationException.java
+C:\classpath-0.04\java\util\Date.java
+C:\classpath-0.04\java\util\Dictionary.java
+C:\classpath-0.04\java\util\EmptyStackException.java
+C:\classpath-0.04\java\util\Enumeration.java
+C:\classpath-0.04\java\util\EventListener.java
+C:\classpath-0.04\java\util\EventListenerProxy.java
+C:\classpath-0.04\java\util\EventObject.java
+C:\classpath-0.04\java\util\GregorianCalendar.java
+C:\classpath-0.04\java\util\HashMap.java
+C:\classpath-0.04\java\util\HashSet.java
+C:\classpath-0.04\java\util\Hashtable.java
+C:\classpath-0.04\java\util\IdentityHashMap.java
+C:\classpath-0.04\java\util\Iterator.java
+C:\classpath-0.04\java\util\LinkedHashMap.java
+C:\classpath-0.04\java\util\LinkedHashSet.java
+C:\classpath-0.04\java\util\LinkedList.java
+C:\classpath-0.04\java\util\List.java
+C:\classpath-0.04\java\util\ListIterator.java
+C:\classpath-0.04\java\util\ListResourceBundle.java
+C:\classpath-0.04\java\util\Locale.java
+C:\classpath-0.04\java\util\Map.java
+C:\classpath-0.04\java\util\MissingResourceException.java
+C:\classpath-0.04\java\util\NoSuchElementException.java
+C:\classpath-0.04\java\util\Observable.java
+C:\classpath-0.04\java\util\Observer.java
+C:\classpath-0.04\java\util\Properties.java
+C:\classpath-0.04\java\util\PropertyPermission.java
+C:\classpath-0.04\java\util\PropertyPermissionCollection.java
+C:\classpath-0.04\java\util\PropertyResourceBundle.java
+C:\classpath-0.04\java\util\Random.java
+C:\classpath-0.04\java\util\RandomAccess.java
+C:\classpath-0.04\java\util\ResourceBundle.java
+C:\classpath-0.04\java\util\Set.java
+C:\classpath-0.04\java\util\SimpleTimeZone.java
+C:\classpath-0.04\java\util\SortedMap.java
+C:\classpath-0.04\java\util\SortedSet.java
+C:\classpath-0.04\java\util\Stack.java
+C:\classpath-0.04\java\util\StringTokenizer.java
+C:\classpath-0.04\java\util\Timer.java
+C:\classpath-0.04\java\util\TimerTask.java
+C:\classpath-0.04\java\util\TimeZone.java
+C:\classpath-0.04\java\util\TooManyListenersException.java
+C:\classpath-0.04\java\util\TreeMap.java
+C:\classpath-0.04\java\util\TreeSet.java
+C:\classpath-0.04\java\util\Vector.java
+C:\classpath-0.04\java\util\WeakHashMap.java
+C:\classpath-0.04\java\util\jar\Attributes.java
+C:\classpath-0.04\java\util\jar\JarEntry.java
+C:\classpath-0.04\java\util\jar\JarException.java
+C:\classpath-0.04\java\util\jar\JarFile.java
+C:\classpath-0.04\java\util\jar\JarInputStream.java
+C:\classpath-0.04\java\util\jar\JarOutputStream.java
+C:\classpath-0.04\java\util\jar\Manifest.java
+C:\classpath-0.04\java\util\logging\ConsoleHandler.java
+C:\classpath-0.04\java\util\logging\ErrorManager.java
+C:\classpath-0.04\java\util\logging\FileHandler.java
+C:\classpath-0.04\java\util\logging\Filter.java
+C:\classpath-0.04\java\util\logging\Formatter.java
+C:\classpath-0.04\java\util\logging\Handler.java
+C:\classpath-0.04\java\util\logging\Level.java
+C:\classpath-0.04\java\util\logging\Logger.java
+C:\classpath-0.04\java\util\logging\LoggingPermission.java
+C:\classpath-0.04\java\util\logging\LogManager.java
+C:\classpath-0.04\java\util\logging\LogRecord.java
+C:\classpath-0.04\java\util\logging\MemoryHandler.java
+C:\classpath-0.04\java\util\logging\SimpleFormatter.java
+C:\classpath-0.04\java\util\logging\SocketHandler.java
+C:\classpath-0.04\java\util\logging\StreamHandler.java
+C:\classpath-0.04\java\util\logging\XMLFormatter.java
+C:\classpath-0.04\java\util\prefs\AbstractPreferences.java
+C:\classpath-0.04\java\util\prefs\BackingStoreException.java
+C:\classpath-0.04\java\util\prefs\InvalidPreferencesFormatException.java
+C:\classpath-0.04\java\util\prefs\NodeChangeEvent.java
+C:\classpath-0.04\java\util\prefs\NodeChangeListener.java
+C:\classpath-0.04\java\util\prefs\PreferenceChangeEvent.java
+C:\classpath-0.04\java\util\prefs\PreferenceChangeListener.java
+C:\classpath-0.04\java\util\prefs\Preferences.java
+C:\classpath-0.04\java\util\prefs\PreferencesFactory.java
+C:\classpath-0.04\java\util\regex\Matcher.java
+C:\classpath-0.04\java\util\regex\Pattern.java
+C:\classpath-0.04\java\util\zip\Adler32.java
+C:\classpath-0.04\java\util\zip\CheckedInputStream.java
+C:\classpath-0.04\java\util\zip\CheckedOutputStream.java
+C:\classpath-0.04\java\util\zip\Checksum.java
+C:\classpath-0.04\java\util\zip\CRC32.java
+C:\classpath-0.04\java\util\zip\DataFormatException.java
+C:\classpath-0.04\java\util\zip\Deflater.java
+C:\classpath-0.04\java\util\zip\DeflaterConstants.java
+C:\classpath-0.04\java\util\zip\DeflaterEngine.java
+C:\classpath-0.04\java\util\zip\DeflaterHuffman.java
+C:\classpath-0.04\java\util\zip\DeflaterOutputStream.java
+C:\classpath-0.04\java\util\zip\DeflaterPending.java
+C:\classpath-0.04\java\util\zip\GZIPInputStream.java
+C:\classpath-0.04\java\util\zip\GZIPOutputStream.java
+C:\classpath-0.04\java\util\zip\Inflater.java
+C:\classpath-0.04\java\util\zip\InflaterDynHeader.java
+C:\classpath-0.04\java\util\zip\InflaterHuffmanTree.java
+C:\classpath-0.04\java\util\zip\InflaterInputStream.java
+C:\classpath-0.04\java\util\zip\OutputWindow.java
+C:\classpath-0.04\java\util\zip\PendingBuffer.java
+C:\classpath-0.04\java\util\zip\StreamManipulator.java
+C:\classpath-0.04\java\util\zip\ZipConstants.java
+C:\classpath-0.04\java\util\zip\ZipEntry.java
+C:\classpath-0.04\java\util\zip\ZipException.java
+C:\classpath-0.04\java\util\zip\ZipFile.java
+C:\classpath-0.04\java\util\zip\ZipInputStream.java
+C:\classpath-0.04\java\util\zip\ZipOutputStream.java
+C:\classpath-0.04\javax\accessibility\Accessible.java
+C:\classpath-0.04\javax\accessibility\AccessibleAction.java
+C:\classpath-0.04\javax\accessibility\AccessibleBundle.java
+C:\classpath-0.04\javax\accessibility\AccessibleComponent.java
+C:\classpath-0.04\javax\accessibility\AccessibleContext.java
+C:\classpath-0.04\javax\accessibility\AccessibleEditableText.java
+C:\classpath-0.04\javax\accessibility\AccessibleExtendedComponent.java
+C:\classpath-0.04\javax\accessibility\AccessibleExtendedTable.java
+C:\classpath-0.04\javax\accessibility\AccessibleHyperlink.java
+C:\classpath-0.04\javax\accessibility\AccessibleHypertext.java
+C:\classpath-0.04\javax\accessibility\AccessibleIcon.java
+C:\classpath-0.04\javax\accessibility\AccessibleKeyBinding.java
+C:\classpath-0.04\javax\accessibility\AccessibleRelation.java
+C:\classpath-0.04\javax\accessibility\AccessibleRelationSet.java
+C:\classpath-0.04\javax\accessibility\AccessibleResourceBundle.java
+C:\classpath-0.04\javax\accessibility\AccessibleRole.java
+C:\classpath-0.04\javax\accessibility\AccessibleSelection.java
+C:\classpath-0.04\javax\accessibility\AccessibleState.java
+C:\classpath-0.04\javax\accessibility\AccessibleStateSet.java
+C:\classpath-0.04\javax\accessibility\AccessibleTable.java
+C:\classpath-0.04\javax\accessibility\AccessibleTableModelChange.java
+C:\classpath-0.04\javax\accessibility\AccessibleText.java
+C:\classpath-0.04\javax\accessibility\AccessibleValue.java
+C:\classpath-0.04\javax\naming\BinaryRefAddr.java
+C:\classpath-0.04\javax\naming\InvalidNameException.java
+C:\classpath-0.04\javax\naming\Name.java
+C:\classpath-0.04\javax\naming\NamingException.java
+C:\classpath-0.04\javax\naming\RefAddr.java
+C:\classpath-0.04\javax\naming\StringRefAddr.java
+C:\classpath-0.04\javax\swing\AbstractAction.java
+C:\classpath-0.04\javax\swing\AbstractButton.java
+C:\classpath-0.04\javax\swing\AbstractListModel.java
+C:\classpath-0.04\javax\swing\AbstractSet.java
+C:\classpath-0.04\javax\swing\Action.java
+C:\classpath-0.04\javax\swing\BorderFactory.java
+C:\classpath-0.04\javax\swing\Box.java
+C:\classpath-0.04\javax\swing\BoxLayout.java
+C:\classpath-0.04\javax\swing\ButtonGroup.java
+C:\classpath-0.04\javax\swing\ButtonModel.java
+C:\classpath-0.04\javax\swing\CellEditor.java
+C:\classpath-0.04\javax\swing\ComponentInputMap.java
+C:\classpath-0.04\javax\swing\DefaultButtonModel.java
+C:\classpath-0.04\javax\swing\DefaultCellRenderer.java
+C:\classpath-0.04\javax\swing\DefaultListModel.java
+C:\classpath-0.04\javax\swing\DefaultListSelectionModel.java
+C:\classpath-0.04\javax\swing\GrayFilter.java
+C:\classpath-0.04\javax\swing\Icon.java
+C:\classpath-0.04\javax\swing\ImageIcon.java
+C:\classpath-0.04\javax\swing\InputMap.java
+C:\classpath-0.04\javax\swing\JApplet.java
+C:\classpath-0.04\javax\swing\JButton.java
+C:\classpath-0.04\javax\swing\JCheckBox.java
+C:\classpath-0.04\javax\swing\JComponent.java
+C:\classpath-0.04\javax\swing\JDialog.java
+C:\classpath-0.04\javax\swing\JEditorPane.java
+C:\classpath-0.04\javax\swing\JFrame.java
+C:\classpath-0.04\javax\swing\JInternalFrame.java
+C:\classpath-0.04\javax\swing\JLabel.java
+C:\classpath-0.04\javax\swing\JLayeredPane.java
+C:\classpath-0.04\javax\swing\JList.java
+C:\classpath-0.04\javax\swing\JMenuBar.java
+C:\classpath-0.04\javax\swing\JOptionPane.java
+C:\classpath-0.04\javax\swing\JPanel.java
+C:\classpath-0.04\javax\swing\JRadioButton.java
+C:\classpath-0.04\javax\swing\JRootPane.java
+C:\classpath-0.04\javax\swing\JScrollBar.java
+C:\classpath-0.04\javax\swing\JScrollPane.java
+C:\classpath-0.04\javax\swing\JTabbedPane.java
+C:\classpath-0.04\javax\swing\JTable.java
+C:\classpath-0.04\javax\swing\JTextField.java
+C:\classpath-0.04\javax\swing\JToggleButton.java
+C:\classpath-0.04\javax\swing\JToolTip.java
+C:\classpath-0.04\javax\swing\JTree.java
+C:\classpath-0.04\javax\swing\JViewport.java
+C:\classpath-0.04\javax\swing\JWindow.java
+C:\classpath-0.04\javax\swing\KeyStroke.java
+C:\classpath-0.04\javax\swing\ListCellRenderer.java
+C:\classpath-0.04\javax\swing\ListModel.java
+C:\classpath-0.04\javax\swing\ListSelectionModel.java
+C:\classpath-0.04\javax\swing\LookAndFeel.java
+C:\classpath-0.04\javax\swing\MenuElement.java
+C:\classpath-0.04\javax\swing\MenuSelectionManager.java
+C:\classpath-0.04\javax\swing\Scrollable.java
+C:\classpath-0.04\javax\swing\SwingConstants.java
+C:\classpath-0.04\javax\swing\SwingUtilities.java
+C:\classpath-0.04\javax\swing\Timer.java
+C:\classpath-0.04\javax\swing\ToggleButtonModel.java
+C:\classpath-0.04\javax\swing\UIDefaults.java
+C:\classpath-0.04\javax\swing\UIManager.java
+C:\classpath-0.04\javax\swing\UnsupportedLookAndFeelException.java
+C:\classpath-0.04\javax\swing\border\AbstractBorder.java
+C:\classpath-0.04\javax\swing\border\BevelBorder.java
+C:\classpath-0.04\javax\swing\border\Border.java
+C:\classpath-0.04\javax\swing\border\CompoundBorder.java
+C:\classpath-0.04\javax\swing\border\EmptyBorder.java
+C:\classpath-0.04\javax\swing\border\EtchedBorder.java
+C:\classpath-0.04\javax\swing\border\LineBorder.java
+C:\classpath-0.04\javax\swing\border\MatteBorder.java
+C:\classpath-0.04\javax\swing\border\TitledBorder.java
+C:\classpath-0.04\javax\swing\event\AncestorEvent.java
+C:\classpath-0.04\javax\swing\event\AncestorListener.java
+C:\classpath-0.04\javax\swing\event\CaretEvent.java
+C:\classpath-0.04\javax\swing\event\CaretListener.java
+C:\classpath-0.04\javax\swing\event\CellEditorListener.java
+C:\classpath-0.04\javax\swing\event\ChangeEvent.java
+C:\classpath-0.04\javax\swing\event\ChangeListener.java
+C:\classpath-0.04\javax\swing\event\DocumentEvent.java
+C:\classpath-0.04\javax\swing\event\DocumentListener.java
+C:\classpath-0.04\javax\swing\event\EventListenerList.java
+C:\classpath-0.04\javax\swing\event\HyperlinkEvent.java
+C:\classpath-0.04\javax\swing\event\HyperlinkListener.java
+C:\classpath-0.04\javax\swing\event\InternalFrameAdapter.java
+C:\classpath-0.04\javax\swing\event\InternalFrameEvent.java
+C:\classpath-0.04\javax\swing\event\InternalFrameListener.java
+C:\classpath-0.04\javax\swing\event\ListDataEvent.java
+C:\classpath-0.04\javax\swing\event\ListDataListener.java
+C:\classpath-0.04\javax\swing\event\ListSelectionEvent.java
+C:\classpath-0.04\javax\swing\event\ListSelectionListener.java
+C:\classpath-0.04\javax\swing\event\MenuDragMouseEvent.java
+C:\classpath-0.04\javax\swing\event\MenuDragMouseListener.java
+C:\classpath-0.04\javax\swing\event\MenuEvent.java
+C:\classpath-0.04\javax\swing\event\MenuKeyEvent.java
+C:\classpath-0.04\javax\swing\event\MenuKeyListener.java
+C:\classpath-0.04\javax\swing\event\MenuListener.java
+C:\classpath-0.04\javax\swing\event\MouseInputAdapter.java
+C:\classpath-0.04\javax\swing\event\MouseInputListener.java
+C:\classpath-0.04\javax\swing\event\PopupMenuEvent.java
+C:\classpath-0.04\javax\swing\event\PopupMenuListener.java
+C:\classpath-0.04\javax\swing\event\SwingPropertyChangeSupport.java
+C:\classpath-0.04\javax\swing\event\TableColumnModelEvent.java
+C:\classpath-0.04\javax\swing\event\TableColumnModelListener.java
+C:\classpath-0.04\javax\swing\event\TableModelEvent.java
+C:\classpath-0.04\javax\swing\event\TableModelListener.java
+C:\classpath-0.04\javax\swing\event\TreeExpansionEvent.java
+C:\classpath-0.04\javax\swing\event\TreeExpansionListener.java
+C:\classpath-0.04\javax\swing\event\TreeModelEvent.java
+C:\classpath-0.04\javax\swing\event\TreeModelListener.java
+C:\classpath-0.04\javax\swing\event\TreeSelectionEvent.java
+C:\classpath-0.04\javax\swing\event\TreeSelectionListener.java
+C:\classpath-0.04\javax\swing\event\TreeWillExpandListener.java
+C:\classpath-0.04\javax\swing\event\UndoableEditEvent.java
+C:\classpath-0.04\javax\swing\event\UndoableEditListener.java
+C:\classpath-0.04\javax\swing\plaf\BorderUIResource.java
+C:\classpath-0.04\javax\swing\plaf\ButtonUI.java
+C:\classpath-0.04\javax\swing\plaf\ColorUIResource.java
+C:\classpath-0.04\javax\swing\plaf\ComponentUI.java
+C:\classpath-0.04\javax\swing\plaf\DimensionUIResource.java
+C:\classpath-0.04\javax\swing\plaf\FontUIResource.java
+C:\classpath-0.04\javax\swing\plaf\IconUIResource.java
+C:\classpath-0.04\javax\swing\plaf\InsetsUIResource.java
+C:\classpath-0.04\javax\swing\plaf\LabelUI.java
+C:\classpath-0.04\javax\swing\plaf\ListUI.java
+C:\classpath-0.04\javax\swing\plaf\OptionPaneUI.java
+C:\classpath-0.04\javax\swing\plaf\PanelUI.java
+C:\classpath-0.04\javax\swing\plaf\ScrollPaneUI.java
+C:\classpath-0.04\javax\swing\plaf\TabbedPaneUI.java
+C:\classpath-0.04\javax\swing\plaf\TextUI.java
+C:\classpath-0.04\javax\swing\plaf\TreeUI.java
+C:\classpath-0.04\javax\swing\plaf\UIResource.java
+C:\classpath-0.04\javax\swing\plaf\ViewportUI.java
+C:\classpath-0.04\javax\swing\plaf\basic\BasicBorders.java
+C:\classpath-0.04\javax\swing\plaf\basic\BasicButtonUI.java
+C:\classpath-0.04\javax\swing\plaf\basic\BasicCheckBoxUI.java
+C:\classpath-0.04\javax\swing\plaf\basic\BasicDefaults.java
+C:\classpath-0.04\javax\swing\plaf\basic\BasicGraphicsUtils.java
+C:\classpath-0.04\javax\swing\plaf\basic\BasicIconFactory.java
+C:\classpath-0.04\javax\swing\plaf\basic\BasicLabelUI.java
+C:\classpath-0.04\javax\swing\plaf\basic\BasicListUI.java
+C:\classpath-0.04\javax\swing\plaf\basic\BasicLookAndFeel.java
+C:\classpath-0.04\javax\swing\plaf\basic\BasicOptionPaneUI.java
+C:\classpath-0.04\javax\swing\plaf\basic\BasicPanelUI.java
+C:\classpath-0.04\javax\swing\plaf\basic\BasicRadioButtonUI.java
+C:\classpath-0.04\javax\swing\plaf\basic\BasicScrollPaneUI.java
+C:\classpath-0.04\javax\swing\plaf\basic\BasicTabbedPaneUI.java
+C:\classpath-0.04\javax\swing\plaf\basic\BasicTextUI.java
+C:\classpath-0.04\javax\swing\plaf\basic\BasicToggleButtonUI.java
+C:\classpath-0.04\javax\swing\plaf\basic\BasicTreeUI.java
+C:\classpath-0.04\javax\swing\plaf\basic\BasicViewportUI.java
+C:\classpath-0.04\javax\swing\plaf\metal\MetalLookAndFeel.java
+C:\classpath-0.04\javax\swing\table\AbstractTableModel.java
+C:\classpath-0.04\javax\swing\table\DefaultTableCellRenderer.java
+C:\classpath-0.04\javax\swing\table\DefaultTableColumnModel.java
+C:\classpath-0.04\javax\swing\table\DefaultTableModel.java
+C:\classpath-0.04\javax\swing\table\TableCellEditor.java
+C:\classpath-0.04\javax\swing\table\TableCellRenderer.java
+C:\classpath-0.04\javax\swing\table\TableColumn.java
+C:\classpath-0.04\javax\swing\table\TableColumnModel.java
+C:\classpath-0.04\javax\swing\table\TableModel.java
+C:\classpath-0.04\javax\swing\text\AbstractDocument.java
+C:\classpath-0.04\javax\swing\text\AttributeSet.java
+C:\classpath-0.04\javax\swing\text\BadLocationException.java
+C:\classpath-0.04\javax\swing\text\Caret.java
+C:\classpath-0.04\javax\swing\text\CharacterIterator.java
+C:\classpath-0.04\javax\swing\text\ComponentView.java
+C:\classpath-0.04\javax\swing\text\DefaultCaret.java
+C:\classpath-0.04\javax\swing\text\DefaultEditorKit.java
+C:\classpath-0.04\javax\swing\text\Document.java
+C:\classpath-0.04\javax\swing\text\EditorKit.java
+C:\classpath-0.04\javax\swing\text\Element.java
+C:\classpath-0.04\javax\swing\text\GapContent.java
+C:\classpath-0.04\javax\swing\text\JTextComponent.java
+C:\classpath-0.04\javax\swing\text\Keymap.java
+C:\classpath-0.04\javax\swing\text\PlainDocument.java
+C:\classpath-0.04\javax\swing\text\PlainEditorKit.java
+C:\classpath-0.04\javax\swing\text\Position.java
+C:\classpath-0.04\javax\swing\text\Segment.java
+C:\classpath-0.04\javax\swing\text\Style.java
+C:\classpath-0.04\javax\swing\text\View.java
+C:\classpath-0.04\javax\swing\text\ViewFactory.java
+C:\classpath-0.04\javax\swing\tree\AbstractLayoutCache.java
+C:\classpath-0.04\javax\swing\tree\DefaultMutableTreeNode.java
+C:\classpath-0.04\javax\swing\tree\DefaultTreeCellEditor.java
+C:\classpath-0.04\javax\swing\tree\DefaultTreeCellRenderer.java
+C:\classpath-0.04\javax\swing\tree\DefaultTreeModel.java
+C:\classpath-0.04\javax\swing\tree\DefaultTreeSelectionModel.java
+C:\classpath-0.04\javax\swing\tree\ExpandVetoException.java
+C:\classpath-0.04\javax\swing\tree\FixedHeightLayoutCache.java
+C:\classpath-0.04\javax\swing\tree\MutableTreeNode.java
+C:\classpath-0.04\javax\swing\tree\RowMapper.java
+C:\classpath-0.04\javax\swing\tree\TreeCellEditor.java
+C:\classpath-0.04\javax\swing\tree\TreeCellRenderer.java
+C:\classpath-0.04\javax\swing\tree\TreeModel.java
+C:\classpath-0.04\javax\swing\tree\TreeNode.java
+C:\classpath-0.04\javax\swing\tree\TreePath.java
+C:\classpath-0.04\javax\swing\tree\TreeSelectionModel.java
+C:\classpath-0.04\javax\swing\tree\VariableHeightLayoutCache.java
+C:\classpath-0.04\javax\swing\undo\AbstractUndoableEdit.java
+C:\classpath-0.04\javax\swing\undo\CannotRedoException.java
+C:\classpath-0.04\javax\swing\undo\CannotUndoException.java
+C:\classpath-0.04\javax\swing\undo\CompoundEdit.java
+C:\classpath-0.04\javax\swing\undo\StateEdit.java
+C:\classpath-0.04\javax\swing\undo\StateEditable.java
+C:\classpath-0.04\javax\swing\undo\UndoableEdit.java
+C:\classpath-0.04\javax\swing\undo\UndoableEditSupport.java
+C:\classpath-0.04\javax\swing\undo\UndoManager.java
+C:\classpath-0.04\vm\reference\gnu\vm\stack\StackFrame.java
+C:\classpath-0.04\vm\reference\gnu\vm\stack\StackTrace.java
+C:\classpath-0.04\vm\reference\java\lang\Runtime.java
+C:\classpath-0.04\vm\reference\java\lang\Throwable.java
+C:\classpath-0.04\vm\reference\java\lang\VMObject.java
+C:\classpath-0.04\vm\reference\java\lang\VMSecurityManager.java
+C:\classpath-0.04\vm\reference\java\lang\VMSystem.java
diff --git a/classpath/classpath.build b/classpath/classpath.build
new file mode 100644
index 00000000..22d9318d
--- /dev/null
+++ b/classpath/classpath.build
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<project name="classpath.dll" default="classpath.dll">
+ <property name="Classpath.dir" value="/classpath-0.04" />
+
+ <target name="jars">
+ <!-- TODO
+ <exec program="${nant.project.basedir}/../bin/netexp.exe" commandline="" />
+ -->
+ </target>
+
+ <target name="classes" depends="jars" description="Classpath + IK.VM.NET specifica Java classes">
+ <delete>
+ <fileset basedir="${Classpath.dir}">
+ <includes name="**.class"/>
+ </fileset>
+ </delete>
+ <delete>
+ <fileset basedir=".">
+ <includes name="**.class"/>
+ </fileset>
+ </delete>
+ <property name="classpath" value=".;${Classpath.dir};${Classpath.dir}/vm/reference;mscorlib.jar;System.jar" />
+ <exec program="jikes.exe" commandline="-classpath ${classpath} @allsources.lst"/>
+ </target>
+
+ <target name="classpath.dll" depends="classes">
+ <exec program="${nant.project.basedir}/../bin/ikvmc.exe" commandline="-nojni -out:classpath.dll -target:library -recurse:./*.class -recurse:${Classpath.dir}/*.class mscorlib.jar System.jar System.Xml.jar" />
+ <copy file="classpath.dll" tofile="../bin/classpath.dll.new" />
+ <exec program="peverify" commandline="../bin/classpath.dll.new" />
+ <copy file="classpath.dll" todir="../bin" />
+ <delete file="../bin/classpath.dll.new" />
+ </target>
+</project>
diff --git a/classpath/gnu/classpath/Configuration.java b/classpath/gnu/classpath/Configuration.java
new file mode 100644
index 00000000..3e7b6558
--- /dev/null
+++ b/classpath/gnu/classpath/Configuration.java
@@ -0,0 +1,98 @@
+/* gnu.classpath.Configuration
+ Copyright (C) 1998, 2001 Free Software Foundation, Inc.
+
+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 gnu.classpath;
+
+/**
+ * This file defines compile-time constants that can be accessed by
+ * java code. It is pre-processed by configure.
+ */
+public interface Configuration
+{
+ // TODO
+ String CLASSPATH_HOME = "";
+ String CLASSPATH_VERSION = "";
+
+
+ /**
+ * The value of DEBUG is substituted according to whether the
+ * "--enable-debug" argument was passed to configure. Code
+ * which is made conditional based on the value of this flag - typically
+ * code that generates debugging output - will be removed by the optimizer
+ * in a non-debug build.
+ */
+ boolean DEBUG = false;
+
+ /**
+ * The value of LOAD_LIBRARY is substituted according to whether the
+ * "--enable-load-library" or "--disable-load-library" argument was passed
+ * to configure. By default, configure should define this is as true.
+ * If set to false, loadLibrary() calls to load native function
+ * implementations, typically found in static initializers of classes
+ * which contain native functions, will be omitted. This is useful for
+ * runtimes which pre-link their native function implementations and do
+ * not require additional shared libraries to be loaded.
+ */
+ boolean INIT_LOAD_LIBRARY = false;
+
+ /**
+ * Set to true if the VM provides a native method to implement
+ * Proxy.getProxyClass completely, including argument verification.
+ * If this is true, HAVE_NATIVE_GET_PROXY_DATA and
+ * HAVE_NATIVE_GENERATE_PROXY_CLASS should be false.
+ * @see java.lang.reflect.Proxy
+ */
+ boolean HAVE_NATIVE_GET_PROXY_CLASS = false;
+
+ /**
+ * Set to true if the VM provides a native method to implement
+ * the first part of Proxy.getProxyClass: generation of the array
+ * of methods to convert, and verification of the arguments.
+ * If this is true, HAVE_NATIVE_GET_PROXY_CLASS should be false.
+ * @see java.lang.reflect.Proxy
+ */
+ boolean HAVE_NATIVE_GET_PROXY_DATA = false;
+
+ /**
+ * Set to true if the VM provides a native method to implement
+ * the second part of Proxy.getProxyClass: conversion of an array of
+ * methods into an actual proxy class.
+ * If this is true, HAVE_NATIVE_GET_PROXY_CLASS should be false.
+ * @see java.lang.reflect.Proxy
+ */
+ boolean HAVE_NATIVE_GENERATE_PROXY_CLASS = false;
+}
diff --git a/classpath/gnu/java/net/protocol/ikvmres/Handler.java b/classpath/gnu/java/net/protocol/ikvmres/Handler.java
new file mode 100644
index 00000000..7d5c8061
--- /dev/null
+++ b/classpath/gnu/java/net/protocol/ikvmres/Handler.java
@@ -0,0 +1,103 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+
+package gnu.java.net.protocol.ikvmres;
+
+import system.io.*;
+import system.reflection.*;
+import java.net.*;
+import java.io.*;
+import java.io.IOException;
+
+class IkvmresURLConnection extends URLConnection
+{
+ private InputStream inputStream;
+
+ IkvmresURLConnection(URL url)
+ {
+ super(url);
+ doOutput = false;
+ }
+
+ public void connect() throws IOException
+ {
+ if(!connected)
+ {
+ String assembly = url.getHost();
+ String resource = url.getFile();
+ // TODO error handling
+ FieldInfo fi = Assembly.Load(assembly).GetLoadedModules()[0].GetField(resource);
+ byte[] b = new byte[system.runtime.interopservices.Marshal.SizeOf(fi.get_FieldType())];
+ InitArray(b, fi);
+ inputStream = new ByteArrayInputStream(b);
+ connected = true;
+ }
+ }
+ private static native void InitArray(byte[] buf, FieldInfo field);
+
+ public InputStream getInputStream() throws IOException
+ {
+ if(!connected)
+ {
+ connect();
+ }
+ return inputStream;
+ }
+
+ public OutputStream getOutputStream() throws IOException
+ {
+ throw new IOException("resource URLs are read only");
+ }
+
+ public long getLastModified()
+ {
+ return -1;
+ }
+
+ public int getContentLength()
+ {
+ return -1;
+ }
+}
+
+public class Handler extends URLStreamHandler
+{
+ protected URLConnection openConnection(URL url) throws IOException
+ {
+ return new IkvmresURLConnection(url);
+ }
+
+ protected void parseURL(URL url, String url_string, int start, int end)
+ {
+ int colon = url_string.indexOf(':', start);
+ String file = url_string.substring(start, colon);
+ String assembly = url_string.substring(colon + 1);
+ setURL(url, "ikvmres", assembly, 0, file, null);
+ }
+
+ protected String toExternalForm(URL url)
+ {
+ return "ikvmres:" + url.getFile() + ":" + url.getHost();
+ }
+}
diff --git a/classpath/ikvm/awt/NetToolkit.java b/classpath/ikvm/awt/NetToolkit.java
new file mode 100644
index 00000000..dde619c3
--- /dev/null
+++ b/classpath/ikvm/awt/NetToolkit.java
@@ -0,0 +1,316 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+
+package ikvm.awt;
+
+import java.awt.*;
+import java.awt.datatransfer.*;
+import java.awt.image.*;
+import java.awt.peer.*;
+import java.net.*;
+import java.util.*;
+import java.awt.List;
+
+public class NetToolkit extends Toolkit
+{
+ private static EventQueue eventQueue = new EventQueue();
+
+ // NOTE "native" is just an easy way to say I haven't implemented it yet
+
+ protected java.awt.peer.ButtonPeer createButton(Button target) throws HeadlessException
+ {
+ return new NetButtonPeer();
+ }
+
+ protected java.awt.peer.TextFieldPeer createTextField(TextField target) throws HeadlessException
+ {
+ return new NetTextFieldPeer();
+ }
+
+ protected native java.awt.peer.LabelPeer createLabel(Label target) throws HeadlessException;
+ protected native java.awt.peer.ListPeer createList(List target) throws HeadlessException;
+ protected native java.awt.peer.CheckboxPeer createCheckbox(Checkbox target)
+ throws HeadlessException;
+ protected native java.awt.peer.ScrollbarPeer createScrollbar(Scrollbar target)
+ throws HeadlessException;
+ protected native java.awt.peer.ScrollPanePeer createScrollPane(ScrollPane target)
+ throws HeadlessException;
+
+ protected java.awt.peer.TextAreaPeer createTextArea(TextArea target) throws HeadlessException
+ {
+ return new NetTextAreaPeer();
+ }
+
+ protected native java.awt.peer.ChoicePeer createChoice(Choice target)
+ throws HeadlessException;
+
+ protected java.awt.peer.FramePeer createFrame(Frame target) throws HeadlessException
+ {
+ return new NetFramePeer();
+ }
+
+ protected native java.awt.peer.CanvasPeer createCanvas(Canvas target);
+
+ protected java.awt.peer.PanelPeer createPanel(Panel target)
+ {
+ return new NetPanelPeer();
+ }
+
+ protected native java.awt.peer.WindowPeer createWindow(Window target)
+ throws HeadlessException;
+ protected native java.awt.peer.DialogPeer createDialog(Dialog target)
+ throws HeadlessException;
+ protected native java.awt.peer.MenuBarPeer createMenuBar(MenuBar target)
+ throws HeadlessException;
+ protected native java.awt.peer.MenuPeer createMenu(Menu target)
+ throws HeadlessException;
+ protected native java.awt.peer.PopupMenuPeer createPopupMenu(PopupMenu target)
+ throws HeadlessException;
+ protected native java.awt.peer.MenuItemPeer createMenuItem(MenuItem target)
+ throws HeadlessException;
+ protected native java.awt.peer.FileDialogPeer createFileDialog(FileDialog target)
+ throws HeadlessException;
+ protected native java.awt.peer.CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target)
+ throws HeadlessException;
+ protected native java.awt.peer.FontPeer getFontPeer(String name, int style);
+ public native Dimension getScreenSize() throws HeadlessException;
+ public native int getScreenResolution() throws HeadlessException;
+ public native ColorModel getColorModel()
+ throws HeadlessException;
+ public native String[] getFontList();
+ public native FontMetrics getFontMetrics(Font font);
+ public native void sync();
+ public native Image getImage(String filename);
+ public native Image getImage(URL url);
+ public native Image createImage(String filename);
+ public native Image createImage(URL url);
+ public native boolean prepareImage(Image image,
+ int width,
+ int height,
+ ImageObserver observer);
+ public native int checkImage(Image image,
+ int width,
+ int height,
+ ImageObserver observer);
+ public native Image createImage(ImageProducer producer);
+ public native Image createImage(byte[] imagedata,
+ int imageoffset,
+ int imagelength);
+ public native PrintJob getPrintJob(Frame frame,
+ String jobtitle,
+ Properties props);
+ public native void beep();
+ public native Clipboard getSystemClipboard()
+ throws HeadlessException;
+
+ protected EventQueue getSystemEventQueueImpl()
+ {
+ return eventQueue;
+ }
+
+// public native java.awt.dnd.peer.DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge)
+// throws InvalidDnDOperationException;
+// public native Map mapInputMethodHighlight(InputMethodHighlight highlight)
+// throws HeadlessException;
+}
+
+class NetComponentPeer implements ComponentPeer
+{
+ public native int checkImage(Image img, int width, int height, ImageObserver ob);
+ public native Image createImage(ImageProducer prod);
+ public native Image createImage(int width, int height);
+ public native void disable();
+ public native void dispose();
+ public native void enable();
+ public native ColorModel getColorModel();
+ public native FontMetrics getFontMetrics(Font f);
+ public native Graphics getGraphics();
+ public native Point getLocationOnScreen();
+ public native Dimension getMinimumSize();
+
+ public Dimension getPreferredSize()
+ {
+ System.out.println("NOTE: NetComponentPeer.getPreferredSize not implemented");
+ return new Dimension(0, 0);
+ }
+
+ public Toolkit getToolkit()
+ {
+ return Toolkit.getDefaultToolkit();
+ }
+
+ public native void handleEvent(AWTEvent e);
+ public native void hide();
+ public native boolean isFocusTraversable();
+ public native Dimension minimumSize();
+
+ public Dimension preferredSize()
+ {
+ System.out.println("NOTE: NetComponentPeer.preferredSize not implemented");
+ return new Dimension(0, 0);
+ }
+
+ public native void paint(Graphics graphics);
+ public native boolean prepareImage(Image img, int width, int height, ImageObserver ob);
+ public native void print(Graphics graphics);
+ public native void repaint(long tm, int x, int y, int width, int height);
+ public native void requestFocus();
+ public native void reshape(int x, int y, int width, int height);
+ public native void setBackground(Color color);
+ public native void setBounds(int x, int y, int width, int height);
+ public native void setCursor(Cursor cursor);
+
+ public void setEnabled(boolean enabled)
+ {
+ System.out.println("NOTE: NetComponentPeer.setEnabled not implemented");
+ }
+
+ public native void setFont(Font font);
+ public native void setForeground(Color color);
+
+ public void setVisible(boolean visible)
+ {
+ System.out.println("NOTE: NetComponentPeer.setVisible not implemented");
+ }
+
+ public native void show();
+ public native GraphicsConfiguration getGraphicsConfiguration();
+
+ public void setEventMask (long mask)
+ {
+ System.out.println("NOTE: NetComponentPeer.setEventMask not implemented");
+ }
+}
+
+class NetButtonPeer extends NetComponentPeer implements ButtonPeer
+{
+ public native void setLabel(String label);
+}
+
+class NetTextComponentPeer extends NetComponentPeer implements TextComponentPeer
+{
+ public native int getSelectionEnd();
+ public native int getSelectionStart();
+
+ public String getText()
+ {
+ System.out.println("NOTE: NetTextComponentPeer.getText not implemented");
+ return "";
+ }
+
+ public void setText(String text)
+ {
+ System.out.println("NOTE: NetTextComponentPeer.setText not implemented");
+ }
+
+ public native void select(int start_pos, int end_pos);
+ public native void setEditable(boolean editable);
+ public native int getCaretPosition();
+ public native void setCaretPosition(int pos);
+}
+
+class NetTextFieldPeer extends NetTextComponentPeer implements TextFieldPeer
+{
+ public native Dimension minimumSize(int len);
+ public native Dimension preferredSize(int len);
+ public native Dimension getMinimumSize(int len);
+
+ public Dimension getPreferredSize(int len)
+ {
+ System.out.println("NOTE: NetTextFieldPeer.getPreferredSize not implemented");
+ return new Dimension(0, 0);
+ }
+
+ public native void setEchoChar(char echo_char);
+ public native void setEchoCharacter(char echo_char);
+}
+
+class NetTextAreaPeer extends NetTextComponentPeer implements TextAreaPeer
+{
+ public void insert(String text, int pos)
+ {
+ System.out.println("NOTE: NetTextAreaPeer.insert not implemented");
+ }
+
+ public native void insertText(String text, int pos);
+ public native Dimension minimumSize(int rows, int cols);
+ public native Dimension getMinimumSize(int rows, int cols);
+ public native Dimension preferredSize(int rows, int cols);
+
+ public Dimension getPreferredSize(int rows, int cols)
+ {
+ System.out.println("NOTE: NetTextAreaPeer.getPreferredSize not implemented");
+ return new Dimension(0, 0);
+ }
+
+ public native void replaceRange(String text, int start_pos, int end_pos);
+ public native void replaceText(String text, int start_pos, int end_pos);
+}
+
+class NetContainerPeer extends NetComponentPeer implements ContainerPeer
+{
+ public native Insets insets();
+
+ public Insets getInsets()
+ {
+ System.out.println("NOTE: NetContainerPeer.getInsets not implemented");
+ return new Insets(0, 0, 0, 0);
+ }
+
+ public void beginValidate()
+ {
+ System.out.println("NOTE: NetContainerPeer.beginValidate not implemented");
+ }
+
+ public void endValidate()
+ {
+ System.out.println("NOTE: NetContainerPeer.endValidate not implemented");
+ }
+}
+
+class NetPanelPeer extends NetContainerPeer implements PanelPeer
+{
+}
+
+class NetWindowPeer extends NetContainerPeer implements WindowPeer
+{
+ public native void toBack();
+
+ public void toFront()
+ {
+ System.out.println("NOTE: NetWindowPeer.toFront not implemented");
+ }
+}
+
+class NetFramePeer extends NetWindowPeer implements FramePeer
+{
+ NetFramePeer()
+ {
+ }
+
+ public native void setIconImage(Image image);
+ public native void setMenuBar(MenuBar mb);
+ public native void setResizable(boolean resizable);
+ public native void setTitle(String title);
+}
diff --git a/classpath/java/io/FileDescriptor.java b/classpath/java/io/FileDescriptor.java
new file mode 100644
index 00000000..54ca461a
--- /dev/null
+++ b/classpath/java/io/FileDescriptor.java
@@ -0,0 +1,249 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+package java.io;
+
+import system.Console;
+import system.io.*;
+
+public final class FileDescriptor
+{
+ public static final FileDescriptor in = new FileDescriptor(Console.OpenStandardInput());
+ public static final FileDescriptor out = new FileDescriptor(Console.OpenStandardOutput());
+ public static final FileDescriptor err = new FileDescriptor(Console.OpenStandardError());
+ private Stream stream;
+
+ public FileDescriptor()
+ {
+ }
+
+ private FileDescriptor(Stream stream)
+ {
+ this.stream = stream;
+ }
+
+ public synchronized void sync() throws SyncFailedException
+ {
+ if(stream == null)
+ {
+ throw new SyncFailedException("The handle is invalid");
+ }
+ try
+ {
+ if(false) throw new system.io.IOException();
+ stream.Flush();
+ }
+ catch(system.io.IOException x)
+ {
+ throw new SyncFailedException(x.get_Message());
+ }
+ }
+
+ public synchronized boolean valid()
+ {
+ return stream != null;
+ }
+
+ synchronized void close() throws IOException
+ {
+ if(stream != null)
+ {
+ // HACK don't close stdin because that throws a NotSupportedException (bug in System.IO.__ConsoleStream)
+ if(stream != in.stream)
+ {
+ try
+ {
+ stream.Close();
+ if(false) throw new system.io.IOException();
+ }
+ catch(system.io.IOException x)
+ {
+ throw new IOException(x.get_Message());
+ }
+ }
+ stream = null;
+ }
+ }
+
+ private static String demanglePath(String path)
+ {
+ // HACK for some reason Java accepts: \c:\foo.txt
+ // I don't know what else, but for now lets just support this
+ if(path.length() > 3 && path.charAt(0) == '\\' && path.charAt(2) == ':')
+ {
+ path = path.substring(1);
+ }
+ return path;
+ }
+
+ static FileDescriptor open(String name, boolean append, boolean create, boolean read, boolean write) throws FileNotFoundException
+ {
+ try
+ {
+ if(false) throw new system.io.IOException();
+ if(false) throw new system.security.SecurityException();
+ FileStream fs = system.io.File.Open(demanglePath(name),
+ append ? FileMode.Append : (create ? FileMode.OpenOrCreate : FileMode.Open),
+ write ? (read ? FileAccess.ReadWrite : FileAccess.Write) : FileAccess.Read, FileShare.ReadWrite);
+ return new FileDescriptor(fs);
+ }
+ catch(system.security.SecurityException x1)
+ {
+ throw new SecurityException(x1.get_Message());
+ }
+ catch(system.io.IOException x2)
+ {
+ throw new FileNotFoundException(x2.get_Message());
+ }
+ // TODO map al the other exceptions as well...
+ }
+
+ synchronized long getFilePointer() throws IOException
+ {
+ if(stream == null)
+ {
+ throw new IOException();
+ }
+ try
+ {
+ if(false) throw new system.io.IOException();
+ return stream.get_Position();
+ }
+ catch(system.io.IOException x)
+ {
+ throw new IOException(x.get_Message());
+ }
+ // TODO map al the other exceptions as well...
+ }
+
+ synchronized long getLength() throws IOException
+ {
+ if(stream == null)
+ {
+ throw new IOException();
+ }
+ try
+ {
+ if(false) throw new system.io.IOException();
+ return stream.get_Length();
+ }
+ catch(system.io.IOException x)
+ {
+ throw new IOException(x.get_Message());
+ }
+ // TODO map al the other exceptions as well...
+ }
+
+ synchronized void setLength(long length) throws IOException
+ {
+ if(stream == null)
+ {
+ throw new IOException();
+ }
+ try
+ {
+ if(false) throw new system.io.IOException();
+ stream.SetLength(length);
+ }
+ catch(system.io.IOException x)
+ {
+ throw new IOException(x.get_Message());
+ }
+ // TODO map al the other exceptions as well...
+ }
+
+ synchronized void seek(long pos) throws IOException
+ {
+ if(stream == null)
+ {
+ throw new IOException();
+ }
+ try
+ {
+ if(false) throw new system.io.IOException();
+ stream.Seek(pos, SeekOrigin.Begin);
+ }
+ catch(system.io.IOException x)
+ {
+ throw new IOException(x.get_Message());
+ }
+ // TODO map al the other exceptions as well...
+ }
+
+ synchronized int read(byte[] buf, int offset, int length) throws IOException
+ {
+ if(stream == null)
+ {
+ throw new IOException();
+ }
+ try
+ {
+ if(false) throw new system.io.IOException();
+ return stream.Read(buf, offset, length);
+ }
+ catch(system.io.IOException x)
+ {
+ throw new IOException(x.get_Message());
+ }
+ // TODO map al the other exceptions as well...
+ }
+
+ synchronized void write(byte[] buf, int offset, int length) throws IOException
+ {
+ if(stream == null)
+ {
+ throw new IOException();
+ }
+ try
+ {
+ if(false) throw new system.io.IOException();
+ stream.Write(buf, offset, length);
+ }
+ catch(system.io.IOException x)
+ {
+ throw new IOException(x.get_Message());
+ }
+ // TODO map al the other exceptions as well...
+ }
+
+ synchronized long skip(long n) throws IOException
+ {
+ if(stream == null)
+ {
+ throw new IOException();
+ }
+ try
+ {
+ if(false) throw new system.io.IOException();
+ // TODO this is broken, because non-seekable streams should support skip as well...
+ // (and I don't think we should seek past EOF here)
+ stream.Seek(n, SeekOrigin.Current);
+ return n;
+ }
+ catch(system.io.IOException x)
+ {
+ throw new IOException(x.get_Message());
+ }
+ // TODO map al the other exceptions as well...
+ }
+}
diff --git a/classpath/java/io/FileInputStream.java b/classpath/java/io/FileInputStream.java
new file mode 100644
index 00000000..78e2f03e
--- /dev/null
+++ b/classpath/java/io/FileInputStream.java
@@ -0,0 +1,396 @@
+/* FileInputStream.java -- An input stream that reads from disk files.
+ Copyright (C) 1998 Free Software Foundation, Inc.
+
+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.io;
+
+import gnu.classpath.Configuration;
+import java.nio.channels.FileChannel;
+import gnu.java.nio.FileChannelImpl;
+
+/**
+ * This class is a stream that reads its bytes from a file.
+ *
+ * @version 0.0
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class FileInputStream extends InputStream
+{
+
+/*************************************************************************/
+
+/*
+ * Class Variables and Initializers
+ */
+
+ static
+ {
+ if (Configuration.INIT_LOAD_LIBRARY)
+ {
+ System.loadLibrary ("javaio");
+ }
+ }
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
+ */
+
+/**
+ * This is the native file handle for the file this stream is reading from
+ */
+private FileDescriptor fd;
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * This method initializes a <code>FileInputStream</code> to read from the
+ * specified named file. A security check is first made to determine
+ * whether or not access to this file is allowed. This is done by
+ * calling the <code>checkRead()</code> method of the <code>SecurityManager</code>
+ * (if one exists) with the name of this file. An exception is thrown
+ * if reading is not allowed. If the file does not exist, an exception
+ * is also thrown.
+ *
+ * @param name The name of the file this stream should read from
+ *
+ * @exception SecurityException If read access to the file is not allowed
+ * @exception FileNotFoundException If the file does not exist.
+ */
+public
+FileInputStream(String name) throws SecurityException, FileNotFoundException
+{
+ this(new File(name));
+}
+
+/*************************************************************************/
+
+/**
+ * This method initializes a <code>FileInputStream</code> to read from the
+ * specified <code>File</code> object. A security check is first made to determine
+ * whether or not access to this file is allowed. This is done by
+ * calling the <code>checkRead()</code> method of the <code>SecurityManager</code>
+ * (if one exists) with the name of this file. An exception is thrown
+ * if reading is not allowed. If the file does not exist, an exception
+ * is also thrown.
+ *
+ * @param file The <code>File</code> object this stream should read from
+ *
+ * @exception SecurityException If read access to the file is not allowed
+ * @exception FileNotFoundException If the file does not exist.
+ */
+public
+FileInputStream(File file) throws SecurityException, FileNotFoundException
+{
+ // Talk about the lazy man's way out. The File.exists() method does
+ // a security check so don't repeat it here.
+ if (!file.exists())
+ throw new FileNotFoundException(file.getName());
+
+ fd = FileDescriptor.open(file.getPath(), false, false, true, false);
+}
+
+/*************************************************************************/
+
+/**
+ * This method initializes a <code>FileInputStream</code> to read from the
+ * specified <code>FileDescriptor</code> object. A security check is first made to
+ * determine whether or not access to this file is allowed. This is done by
+ * calling the <code>checkRead()</code> method of the <code>SecurityManager</code>
+ * (if one exists) with the specified <code>FileDescriptor</code> An exception is
+ * thrown if reading is not allowed.
+ *
+ * @param fd The <code>FileDescriptor</code> object this stream should read from
+ *
+ * @exception SecurityException If read access to the file is not allowed
+ */
+public
+FileInputStream(FileDescriptor fd) throws SecurityException
+{
+ // Hmmm, no other exception but this one to throw, but if the descriptor
+ // isn't valid, we surely don't have "permission" to read from it.
+ if (!fd.valid())
+ throw new SecurityException("Invalid FileDescriptor");
+
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ sm.checkRead(fd);
+
+ this.fd = fd;
+}
+
+/*************************************************************************/
+
+/*
+ * Instance Methods
+ */
+
+/**
+ * This method returns a <code>FileDescriptor</code> object representing the
+ * underlying native file handle of the file this stream is reading
+ * from
+ *
+ * @return A <code>FileDescriptor</code> for this stream
+ *
+ * @exception IOException If an error occurs
+ */
+public final FileDescriptor
+getFD() throws IOException
+{
+ return fd;
+}
+
+/*************************************************************************/
+
+/**
+ * This method returns the number of bytes that can be read from this
+ * stream before a read can block. A return of 0 indicates that blocking
+ * might (or might not) occur on the very next read attempt.
+ * <p>
+ * This method returns the number of unread bytes remaining in the file if
+ * the descriptor being read from is an actual file. If this method is
+ * reading from a ''special'' file such a the standard input, this method
+ * will return the appropriate value for the stream being read.
+ * <p>
+ * Be aware that reads on plain files that do not reside locally might
+ * possibly block even if this method says they should not. For example,
+ * a remote server might crash, preventing an NFS mounted file from being
+ * read.
+ *
+ * @return The number of bytes that can be read before blocking could occur
+ *
+ * @exception IOException If an error occurs
+ */
+public int
+available() throws IOException
+{
+ int retval = (int)(fd.getLength() - fd.getFilePointer());
+
+ if (retval <= 0)
+ return(0);
+
+ return(retval);
+}
+
+/*************************************************************************/
+
+/**
+ * This method skips the specified number of bytes in the stream. It
+ * returns the actual number of bytes skipped, which may be less than the
+ * requested amount.
+ * <p>
+ * This method reads and discards bytes into a 256 byte array until the
+ * specified number of bytes were skipped or until either the end of stream
+ * is reached or a read attempt returns a short count. Subclasses can
+ * override this metho to provide a more efficient implementation where
+ * one exists.
+ *
+ * @param num_bytes The requested number of bytes to skip
+ *
+ * @return The actual number of bytes skipped.
+ *
+ * @exception IOException If an error occurs
+ */
+public long
+skip(long num_bytes) throws IOException
+{
+ if (num_bytes <= 0)
+ return(0);
+
+ if (num_bytes > available())
+ num_bytes = available();
+
+ long bytes_skipped = fd.skip(num_bytes);
+
+ return(bytes_skipped);
+}
+
+/*************************************************************************/
+
+/**
+ * This method reads an unsigned byte from the input stream and returns it
+ * as an int in the range of 0-255. This method also will return -1 if
+ * the end of the stream has been reached.
+ * <p>
+ * This method will block until the byte can be read.
+ *
+ * @return The byte read or -1 if end of stream
+ *
+ * @exception IOException If an error occurs
+ */
+public int
+read() throws IOException
+{
+ byte[] buf = new byte[1];
+
+ int bytes_read = fd.read(buf, 0, buf.length);
+ if (bytes_read == 0)
+ return(-1);
+ if (bytes_read == -1)
+ return(-1);
+
+ return((buf[0] & 0xFF));
+}
+
+/*************************************************************************/
+
+/**
+ * This method reads bytes from a stream and stores them into a caller
+ * supplied buffer. This method attempts to completely fill the buffer,
+ * but can return before doing so. The actual number of bytes read is
+ * returned as an int. A -1 is returned to indicate the end of the stream.
+ * <p>
+ * This method will block until some data can be read.
+ * <p>
+ * This method operates by calling an overloaded read method like so:
+ * <code>read(buf, 0, buf.length)</code>
+ *
+ * @param buf The buffer into which the bytes read will be stored.
+ *
+ * @return The number of bytes read or -1 if end of stream.
+ *
+ * @exception IOException If an error occurs.
+ */
+public int
+read(byte[] buf) throws IOException
+{
+ return(read(buf, 0, buf.length));
+}
+
+/*************************************************************************/
+
+/**
+ * This method read bytes from a stream and stores them into a caller
+ * supplied buffer. It starts storing the data at index <code>offset</code> into
+ * the buffer and attempts to read <code>len</code> bytes. This method can
+ * return before reading the number of bytes requested. The actual number
+ * of bytes read is returned as an int. A -1 is returned to indicate the
+ * end of the stream.
+ * <p>
+ * This method will block until some data can be read.
+ *
+ * @param buf The array into which the bytes read should be stored
+ * @param offset The offset into the array to start storing bytes
+ * @param len The requested number of bytes to read
+ *
+ * @return The actual number of bytes read, or -1 if end of stream.
+ *
+ * @exception IOException If an error occurs.
+ */
+public int
+read(byte[] buf, int offset, int len) throws IOException
+{
+ if (len == 0)
+ return(0);
+
+ int bytes_read = fd.read(buf, offset, len);
+ if (bytes_read == 0)
+ return(-1);
+ if (bytes_read == -1)
+ return(-1);
+
+ return(bytes_read);
+}
+
+/*************************************************************************/
+
+/**
+ * This method closes the stream. Any futher attempts to read from the
+ * stream will likely generate an IOException since the underlying file
+ * will be closed.
+ *
+ * @exception IOException If an error occurs.
+ */
+public void
+close() throws IOException
+{
+ fd.close();
+}
+
+/*************************************************************************/
+
+/**
+ * This method ensures that the underlying file is closed when this object
+ * is garbage collected. Since there is a system dependent limit on how
+ * many files a single process can have open, it is a good idea to close
+ * streams when they are no longer needed rather than waiting for garbage
+ * collectio to automatically close them.
+ *
+ * @exception IOException If an error occurs
+ */
+protected void
+finalize() throws IOException
+{
+ if(fd != null)
+ {
+ close();
+ }
+}
+
+
+/*************************************************************************/
+
+/**
+ * This method creates a java.nio.channels.FileChannel.
+ * Nio does not allow one to create a file channel directly.
+ * A file channel must be created by first creating an instance of
+ * Input/Output/RandomAccessFile and invoking the getChannel() method on it.
+ */
+
+private FileChannel ch; /* cached associated file-channel */
+
+public FileChannel
+getChannel()
+{
+ synchronized (this)
+ {
+// if (ch == null)
+// ch = new gnu.java.nio.FileChannelImpl(native_fd,
+// this);
+ }
+ return ch;
+}
+
+
+} // class FileInputStream
+
diff --git a/classpath/java/io/FileOutputStream.java b/classpath/java/io/FileOutputStream.java
new file mode 100644
index 00000000..bd7f5cb8
--- /dev/null
+++ b/classpath/java/io/FileOutputStream.java
@@ -0,0 +1,339 @@
+/* FileOutputStream.java -- Writes to a file on disk.
+ Copyright (C) 1998, 2001 Free Software Foundation, Inc.
+
+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.io;
+
+import gnu.classpath.Configuration;
+import java.nio.channels.FileChannel;
+import gnu.java.nio.FileChannelImpl;
+
+/**
+ * This classes allows a stream of data to be written to a disk file or
+ * any open <code>FileDescriptor</code>.
+ *
+ * @version 0.0
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class FileOutputStream extends OutputStream
+{
+
+/*************************************************************************/
+
+/*
+ * Class Variables and Initializers
+ */
+
+ static
+ {
+ if (Configuration.INIT_LOAD_LIBRARY)
+ {
+ System.loadLibrary ("javaio");
+ }
+ }
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
+ */
+
+/**
+ * This is the native file handle
+ */
+private FileDescriptor fd;
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * This method initializes a <code>FileOutputStream</code> object to write
+ * to the named file. The file is created if it does not exist, and
+ * the bytes written are written starting at the beginning of the file.
+ * <p>
+ * Before opening a file, a security check is performed by calling the
+ * <code>checkWrite</code> method of the <code>SecurityManager</code> (if
+ * one exists) with the name of the file to be opened. An exception is
+ * thrown if writing is not allowed.
+ *
+ * @param name The name of the file this stream should write to
+ *
+ * @exception SecurityException If write access to the file is not allowed
+ * @exception IOException If a non-security error occurs
+ */
+public
+FileOutputStream(String name) throws SecurityException, IOException
+{
+ this(name, false);
+}
+
+/*************************************************************************/
+
+/**
+ * This method initializes a <code>FileOutputStream</code> object to write
+ * to the specified <code>File</code> object. The file is created if it
+ * does not exist, and the bytes written are written starting at the
+ * beginning of the file.
+ * <p>
+ * Before opening a file, a security check is performed by calling the
+ * <code>checkWrite</code> method of the <code>SecurityManager</code> (if
+ * one exists) with the name of the file to be opened. An exception is
+ * thrown if writing is not allowed.
+ *
+ * @param file The <code>File</code> object this stream should write to
+ *
+ * @exception SecurityException If write access to the file is not allowed
+ * @exception IOException If a non-security error occurs
+ */
+public
+FileOutputStream(File file) throws SecurityException, IOException
+{
+ this(file.getPath(), false);
+}
+
+/*************************************************************************/
+
+/**
+ * This method initializes a <code>FileOutputStream</code> object to write
+ * to the named file. The file is created if it does not exist, and
+ * the bytes written are written starting at the beginning of the file if
+ * the <code>append</code> argument is <code>false</code> or at the end
+ * of the file if the <code>append</code> argument is true.
+ * <p>
+ * Before opening a file, a security check is performed by calling the
+ * <code>checkWrite</code> method of the <code>SecurityManager</code> (if
+ * one exists) with the name of the file to be opened. An exception is
+ * thrown if writing is not allowed.
+ *
+ * @param name The name of the file this stream should write to
+ * @param append <code>true</code> to append bytes to the end of the file, or <code>false</code> to write bytes to the beginning
+ *
+ * @exception SecurityException If write access to the file is not allowed
+ * @exception IOException If a non-security error occurs
+ */
+public
+FileOutputStream(String name, boolean append) throws SecurityException,
+ IOException
+{
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ {
+// try
+// {
+ sm.checkWrite(name);
+// }
+// catch(AccessControlException e)
+// {
+// throw new SecurityException(e.getMessage());
+// }
+ }
+
+ fd = FileDescriptor.open((new File(name)).getAbsolutePath(), append, true, false, true);
+}
+
+/*************************************************************************/
+
+/**
+ * This method initializes a <code>FileOutputStream</code> object to write
+ * to the file represented by the specified <code>FileDescriptor</code>
+ * object. This method does not create any underlying disk file or
+ * reposition the file pointer of the given descriptor. It assumes that
+ * this descriptor is ready for writing as is.
+ * <p>
+ * Before opening a file, a security check is performed by calling the
+ * <code>checkWrite</code> method of the <code>SecurityManager</code> (if
+ * one exists) with the specified <code>FileDescriptor</code> as an argument.
+ * An exception is thrown if writing is not allowed.
+ *
+ * @param file The <code>FileDescriptor</code> this stream should write to
+ *
+ * @exception SecurityException If write access to the file is not allowed
+ */
+public
+FileOutputStream(FileDescriptor fd) throws SecurityException
+{
+ // Hmm, no other exception but this one to throw, but if the descriptor
+ // isn't valid, we surely don't have "permission" to write to it.
+ if (!fd.valid())
+ throw new SecurityException("Invalid FileDescriptor");
+
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ {
+// try
+// {
+ // sm.checkWrite(fd);
+// }
+// catch(AccessControlException e)
+// {
+// throw new SecurityException(e.getMessage());
+// }
+ }
+
+ this.fd = fd;
+}
+
+/*************************************************************************/
+
+/**
+ * This method returns a <code>FileDescriptor</code> object representing
+ * the file that is currently being written to
+ *
+ * @return A <code>FileDescriptor</code> object for this stream
+ *
+ * @exception IOException If an error occurs
+ */
+public final FileDescriptor
+getFD() throws IOException
+{
+ return fd;
+}
+
+/*************************************************************************/
+
+/**
+ * This method writes a single byte of data to the file.
+ *
+ * @param b The byte of data to write, passed as an <code>int</code>
+ *
+ * @exception IOException If an error occurs
+ */
+public void
+write(int b) throws IOException
+{
+ byte[] buf = new byte[1];
+
+ buf[0] = (byte)(b & 0xFF);
+ fd.write(buf, 0, buf.length);
+}
+
+/*************************************************************************/
+
+/**
+ * This method writes all the bytes in the specified array to the
+ * file.
+ *
+ * @param buf The array of bytes to write to the file
+ *
+ * @exception IOException If an error occurs
+ */
+public void
+write(byte[] buf) throws IOException
+{
+ fd.write(buf, 0, buf.length);
+}
+
+/*************************************************************************/
+
+/**
+ * This method writes <code>len</code> bytes from the byte array
+ * <code>buf</code> to the file starting at index <code>offset</code>.
+ *
+ * @param buf The array of bytes to write to the file
+ * @param offset The offset into the array to start writing bytes from
+ * @param len The number of bytes to write to the file
+ *
+ * @exception IOException If an error occurs
+ */
+public void
+write(byte[] buf, int offset, int len) throws IOException
+{
+ fd.write(buf, offset, len);
+}
+
+/*************************************************************************/
+
+/**
+ * This method closes the underlying file. Any further attempts to
+ * write to this stream will likely generate an exception since the
+ * file is closed.
+ *
+ * @exception IOException If an error occurs
+ */
+public void
+close() throws IOException
+{
+ fd.close();
+}
+
+/*************************************************************************/
+
+/**
+ * This method closes the stream when this object is being garbage
+ * collected.
+ *
+ * @exception IOException If an error occurs (ignored by the Java runtime)
+ */
+protected void
+finalize() throws IOException
+{
+ if(fd != null)
+ {
+ close();
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * This method creates a java.nio.channels.FileChannel.
+ * Nio does not allow one to create a file channel directly.
+ * A file channel must be created by first creating an instance of
+ * Input/Output/RandomAccessFile and invoking the getChannel() method on it.
+ */
+
+private FileChannel ch; /* cached associated file-channel */
+
+public FileChannel
+getChannel()
+{
+ synchronized (this)
+ {
+// if (ch == null)
+// ch = new gnu.java.nio.FileChannelImpl(native_fd,
+// this);
+ }
+ return ch;
+}
+
+
+} // class FileOutputStream
+
diff --git a/classpath/java/io/RandomAccessFile.java b/classpath/java/io/RandomAccessFile.java
new file mode 100644
index 00000000..195622da
--- /dev/null
+++ b/classpath/java/io/RandomAccessFile.java
@@ -0,0 +1,1197 @@
+/* RandomAccessFile.java -- Class supporting random file I/O
+ Copyright (C) 1998 Free Software Foundation, Inc.
+
+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.io;
+
+import gnu.classpath.Configuration;
+import java.nio.channels.FileChannel;
+import gnu.java.nio.FileChannelImpl;
+
+/**
+ * This class allows reading and writing of files at random locations.
+ * Most Java I/O classes are either pure sequential input or output. This
+ * class fulfills the need to be able to read the bytes of a file in an
+ * arbitrary order. In addition, this class implements the
+ * <code>DataInput</code> and <code>DataOutput</code> interfaces to allow
+ * the reading and writing of Java primitives.
+ *
+ * @version 0.0
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+public class RandomAccessFile implements DataOutput, DataInput
+{
+
+ static
+ {
+ if (Configuration.INIT_LOAD_LIBRARY)
+ {
+ System.loadLibrary ("javaio");
+ }
+ }
+
+/*************************************************************************/
+
+/*
+ * Instance Variables
+ */
+
+/**
+ * The native file descriptor for this file
+ */
+private FileDescriptor fd;
+
+/**
+ * Whether or not this file is open in read only mode
+ */
+private boolean read_only;
+
+/*************************************************************************/
+
+/*
+ * Constructors
+ */
+
+/**
+ * This method initializes a new instance of <code>RandomAccessFile</code>
+ * to read from the specified file name with the specified access mode.
+ * The access mode is either "r" for read only access or "rw" for read
+ * write access.
+ * <p>
+ * Note that a <code>SecurityManager</code> check is made prior to
+ * opening the file to determine whether or not this file is allowed to
+ * be read or written.
+ *
+ * @param name The name of the file to read and/or write
+ * @param mode "r" for read only or "rw" for read-write access to the file
+ *
+ * @exception IllegalArgumentException If <code>mode</code> has an illegal value
+ * @exception SecurityException If the requested access to the file is not allowed
+ * @exception IOException If any other error occurs
+ */
+public
+RandomAccessFile(String name, String mode) throws IllegalArgumentException,
+ SecurityException,
+ IOException
+{
+ this(new File(name), mode);
+}
+
+/*************************************************************************/
+
+/**
+ * This method initializes a new instance of <code>RandomAccessFile</code>
+ * to read from the specified <code>File</code> object with the specified
+ * access mode. The access mode is either "r" for read only access or "rw"
+ * for read-write access.
+ * <p>
+ * Note that a <code>SecurityManager</code> check is made prior to
+ * opening the file to determine whether or not this file is allowed to
+ * be read or written.
+ *
+ * @param file The <code>File</code> object to read and/or write.
+ * @param mode "r" for read only or "rw" for read-write access to the file
+ *
+ * @exception IllegalArgumentException If <code>mode</code> has an illegal value
+ * @exception SecurityException If the requested access to the file is not allowed
+ * @exception IOException If any other error occurs
+ */
+public
+RandomAccessFile(File file, String mode) throws IllegalArgumentException,
+ SecurityException,
+ IOException
+{
+ // Check the mode
+ if (!mode.equals("r") && !mode.equals("rw"))
+ throw new IllegalArgumentException("Bad mode value: " + mode);
+
+ // The obligatory SecurityManager stuff
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ {
+ if (mode.equals("r"))
+ sm.checkRead(file.getPath());
+ else if (mode.equals("rw"))
+ sm.checkWrite(file.getPath());
+ }
+
+ if (mode.equals("r"))
+ read_only = true;
+
+ fd = FileDescriptor.open(file.getPath(), false, !read_only, true, !read_only);
+}
+
+/*************************************************************************/
+
+/*
+ * Instance Methods
+ */
+
+/**
+ * This method closes the file and frees up all file related system
+ * resources. Since most operating systems put a limit on how many files
+ * may be opened at any given time, it is a good idea to close all files
+ * when no longer needed to avoid hitting this limit
+ */
+public void
+close() throws IOException
+{
+ fd.close();
+}
+
+/*************************************************************************/
+
+/**
+ * This method returns a <code>FileDescriptor</code> object that
+ * represents the native file handle for this file.
+ *
+ * @return The <code>FileDescriptor</code> object for this file
+ *
+ * @exception IOException If an error occurs
+ */
+public final FileDescriptor
+getFD() throws IOException
+{
+ return fd;
+}
+
+/*************************************************************************/
+
+/**
+ * This method returns the current offset in the file at which the next
+ * read or write will occur
+ *
+ * @return The current file position
+ *
+ * @exception IOException If an error occurs
+ */
+public long
+getFilePointer() throws IOException
+{
+ return fd.getFilePointer();
+}
+
+/*************************************************************************/
+
+/**
+ * This method returns the length of the file in bytes
+ *
+ * @return The length of the file
+ *
+ * @exception IOException If an error occurs
+ */
+public long
+length() throws IOException
+{
+ return fd.getLength();
+}
+
+/*************************************************************************/
+
+/**
+ * This method sets the current file position to the specified offset
+ * from the beginning of the file. Note that some operating systems will
+ * allow the file pointer to be set past the current end of the file.
+ *
+ * @param pos The offset from the beginning of the file at which to set the file pointer
+ *
+ * @exception IOException If an error occurs
+ */
+public void
+seek(long pos) throws IOException
+{
+ fd.seek(pos);
+}
+
+/*************************************************************************/
+
+/**
+ * This method sets the length of the file to the specified length. If
+ * the currently length of the file is longer than the specified length,
+ * then the file is truncated to the specified length. If the current
+ * length of the file is shorter than the specified length, the file
+ * is extended with bytes of an undefined value.
+ * <p>
+ * The file must be open for write access for this operation to succeed.
+ *
+ * @param newlen The new length of the file
+ *
+ * @exception IOException If an error occurs
+ */
+public void
+setLength(long newlen) throws IOException
+{
+ if (read_only)
+ throw new IOException("File is open read only");
+
+ fd.setLength(newlen);
+}
+
+/*************************************************************************/
+
+/**
+ * This method reads a single byte of data from the file and returns it
+ * as an integer.
+ *
+ * @return The byte read as an int, or -1 if the end of the file was reached.
+ *
+ * @exception IOException If an error occurs
+ */
+public int
+read() throws IOException
+{
+ byte[] buf = new byte[1];
+
+ int rc = fd.read(buf, 0, buf.length);
+ if (rc == 0)
+ return(-1);
+
+ return(buf[0] & 0xFF);
+}
+
+/*************************************************************************/
+
+/**
+ * This method reads bytes from the file into the specified array. The
+ * bytes are stored starting at the beginning of the array and up to
+ * <code>buf.length</code> bytes can be read.
+ *
+ * @param buf The buffer to read bytes from the file into
+ *
+ * @return The actual number of bytes read or -1 if end of file
+ *
+ * @exception IOException If an error occurs
+ */
+public int
+read(byte[] buf) throws IOException
+{
+ int rc = fd.read(buf, 0, buf.length);
+ if (rc == 0)
+ return(-1);
+ else
+ return(rc);
+}
+
+/*************************************************************************/
+
+/**
+ * This methods reads up to <code>len</code> bytes from the file into the s
+ * pecified array starting at position <code>offset</code> into the array.
+ *
+ * @param buf The array to read the bytes into
+ * @param offset The index into the array to start storing bytes
+ * @param len The requested number of bytes to read
+ *
+ * @param len The actual number of bytes read, or -1 if end of file
+ *
+ * @exception IOException If an error occurs
+ */
+public int
+read(byte[] buf, int offset, int len) throws IOException
+{
+ int rc = fd.read(buf, offset, len);
+ if (rc == 0)
+ return(-1);
+ else
+ return(rc);
+}
+
+/*************************************************************************/
+
+/**
+ * This method reads a Java boolean value from an input stream. It does
+ * so by reading a single byte of data. If that byte is zero, then the
+ * value returned is <code>false</code> If the byte is non-zero, then
+ * the value returned is <code>true</code>
+ * <p>
+ * This method can read a <code>boolean</code> written by an object implementing the
+ * <code>writeBoolean()</code> method in the <code>DataOutput</code> interface.
+ *
+ * @return The <code>boolean</code> value read
+ *
+ * @exception EOFException If end of file is reached before reading the boolean
+ * @exception IOException If any other error occurs
+ */
+public final boolean
+readBoolean() throws EOFException, IOException
+{
+ int byte_read = read();
+
+ if (byte_read == -1)
+ throw new EOFException("Unexpected end of stream");
+
+ return(DataInputStream.convertToBoolean(byte_read));
+}
+
+/*************************************************************************/
+
+/**
+ * This method reads a Java byte value from an input stream. The value
+ * is in the range of -128 to 127.
+ * <p>
+ * This method can read a <code>byte</code> written by an object implementing the
+ * <code>writeByte()</code> method in the <code>DataOutput</code> interface.
+ *
+ * @return The <code>byte</code> value read
+ *
+ * @exception EOFException If end of file is reached before reading the byte
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput
+ */
+public final byte
+readByte() throws EOFException, IOException
+{
+ int byte_read = read();
+
+ if (byte_read == -1)
+ throw new EOFException("Unexpected end of stream");
+
+ return(DataInputStream.convertToByte(byte_read));
+}
+
+/*************************************************************************/
+
+/**
+ * This method reads 8 unsigned bits into a Java <code>int</code> value from the
+ * stream. The value returned is in the range of 0 to 255.
+ * <p>
+ * This method can read an unsigned byte written by an object implementing the
+ * <code>writeUnsignedByte()</code> method in the <code>DataOutput</code> interface.
+ *
+ * @return The unsigned bytes value read as a Java <code>int</code>
+ *
+ * @exception EOFException If end of file is reached before reading the value
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput
+ */
+public final int
+readUnsignedByte() throws EOFException, IOException
+{
+ int byte_read = read();
+
+ if (byte_read == -1)
+ throw new EOFException("Unexpected end of stream");
+
+ return(DataInputStream.convertToUnsignedByte(byte_read));
+}
+
+/*************************************************************************/
+
+/**
+ * This method reads a Java <code>char</code> value from an input stream.
+ * It operates by reading two bytes from the stream and converting them to
+ * a single 16-bit Java <code>char</code> The two bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> and code{byte2</code> represent the first
+ * and second byte read from the stream respectively, they will be
+ * transformed to a <code>char</code> in the following manner:
+ * <p>
+ * <code>(char)(((byte1 & 0xFF) << 8) | (byte2 & 0xFF)</code>
+ * <p>
+ * This method can read a <code>char</code> written by an object implementing the
+ * <code>writeChar()</code> method in the <code>DataOutput</code> interface.
+ *
+ * @return The <code>char</code> value read
+ *
+ * @exception EOFException If end of file is reached before reading the char
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput
+ */
+public final char
+readChar() throws EOFException, IOException
+{
+ byte[] buf = new byte[2];
+
+ readFully(buf);
+
+ return(DataInputStream.convertToChar(buf));
+}
+
+/*************************************************************************/
+
+/**
+ * This method reads a signed 16-bit value into a Java in from the stream.
+ * It operates by reading two bytes from the stream and converting them to
+ * a single 16-bit Java <code>short</code> The two bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> and code{byte2</code> represent the first
+ * and second byte read from the stream respectively, they will be
+ * transformed to a <code>short</code> in the following manner:
+ * <p>
+ * <code>(short)(((byte1 & 0xFF) << 8) | (byte2 & 0xFF)</code>
+ * <p>
+ * The value returned is in the range of -32768 to 32767.
+ * <p>
+ * This method can read a <code>short</code> written by an object implementing the
+ * <code>writeShort()</code> method in the <code>DataOutput</code> interface.
+ *
+ * @return The <code>short</code> value read
+ *
+ * @exception EOFException If end of file is reached before reading the value
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput
+ */
+public final short
+readShort() throws EOFException, IOException
+{
+ byte[] buf = new byte[2];
+
+ readFully(buf);
+
+ return(DataInputStream.convertToShort(buf));
+}
+
+/*************************************************************************/
+
+/**
+ * This method reads 16 unsigned bits into a Java int value from the stream.
+ * It operates by reading two bytes from the stream and converting them to
+ * a single Java <code>int</code> The two bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> and code{byte2</code> represent the first
+ * and second byte read from the stream respectively, they will be
+ * transformed to an <code>int</code> in the following manner:
+ * <p>
+ * <code>(int)(((byte1 & 0xFF) << 8) + (byte2 & 0xFF))</code>
+ * <p>
+ * The value returned is in the range of 0 to 65535.
+ * <p>
+ * This method can read an unsigned short written by an object implementing
+ * the <code>writeUnsignedShort()</code> method in the <code>DataOutput</code> interface.
+ *
+ * @return The unsigned short value read as a Java <code>int</code>
+ *
+ * @exception EOFException If end of file is reached before reading the value
+ * @exception IOException If any other error occurs
+ */
+public final int
+readUnsignedShort() throws EOFException, IOException
+{
+ byte[] buf = new byte[2];
+
+ readFully(buf);
+
+ return(DataInputStream.convertToUnsignedShort(buf));
+}
+
+/*************************************************************************/
+
+/**
+ * This method reads a Java <code>int</code> value from an input stream
+ * It operates by reading four bytes from the stream and converting them to
+ * a single Java <code>int</code> The bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> through <code>byte4</code> represent the first
+ * four bytes read from the stream, they will be
+ * transformed to an <code>int</code> in the following manner:
+ * <p>
+ * <code>(int)(((byte1 & 0xFF) << 24) + ((byte2 & 0xFF) << 16) +
+ * ((byte3 & 0xFF) << 8) + (byte4 & 0xFF)))</code>
+ * <p>
+ * The value returned is in the range of 0 to 65535.
+ * <p>
+ * This method can read an <code>int</code> written by an object implementing the
+ * <code>writeInt()</code> method in the <code>DataOutput</code> interface.
+ *
+ * @return The <code>int</code> value read
+ *
+ * @exception EOFException If end of file is reached before reading the int
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput
+ */
+public final int
+readInt() throws EOFException, IOException
+{
+ byte[] buf = new byte[4];
+
+ readFully(buf);
+
+ return(DataInputStream.convertToInt(buf));
+}
+
+/*************************************************************************/
+
+/**
+ * This method reads a Java long value from an input stream
+ * It operates by reading eight bytes from the stream and converting them to
+ * a single Java <code>long</code> The bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> through <code>byte8</code> represent the first
+ * eight bytes read from the stream, they will be
+ * transformed to an <code>long</code> in the following manner:
+ * <p>
+ * <code>(long)((((long)byte1 & 0xFF) << 56) + (((long)byte2 & 0xFF) << 48) +
+ * (((long)byte3 & 0xFF) << 40) + (((long)byte4 & 0xFF) << 32) +
+ * (((long)byte5 & 0xFF) << 24) + (((long)byte6 & 0xFF) << 16) +
+ * (((long)byte7 & 0xFF) << 8) + ((long)byte9 & 0xFF)))</code>
+ * <p>
+ * The value returned is in the range of 0 to 65535.
+ * <p>
+ * This method can read an <code>long</code> written by an object implementing the
+ * <code>writeLong()</code> method in the <code>DataOutput</code> interface.
+ *
+ * @return The <code>long</code> value read
+ *
+ * @exception EOFException If end of file is reached before reading the long
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput
+ */
+public final long
+readLong() throws EOFException, IOException
+{
+ byte[] buf = new byte[8];
+
+ readFully(buf);
+
+ return(DataInputStream.convertToLong(buf));
+}
+
+/*************************************************************************/
+
+/**
+ * This method reads a Java float value from an input stream. It operates
+ * by first reading an <code>int</code> value from the stream by calling the
+ * <code>readInt()</code> method in this interface, then converts that <code>int</code>
+ * to a <code>float</code> using the <code>intBitsToFloat</code> method in
+ * the class <code>java.lang.Float</code>
+ * <p>
+ * This method can read a <code>float</code> written by an object implementing the
+ * <code>writeFloat()</code> method in the <code>DataOutput</code> interface.
+ *
+ * @return The <code>float</code> value read
+ *
+ * @exception EOFException If end of file is reached before reading the float
+ * @exception IOException If any other error occurs
+ *
+ * @see java.lang.Float
+ * @see DataOutput
+ */
+public final float
+readFloat() throws EOFException, IOException
+{
+ int val = readInt();
+
+ return(Float.intBitsToFloat(val));
+}
+
+/*************************************************************************/
+
+/**
+ * This method reads a Java double value from an input stream. It operates
+ * by first reading a <code>logn</code> value from the stream by calling the
+ * <code>readLong()</code> method in this interface, then converts that <code>long</code>
+ * to a <code>double</code> using the <code>longBitsToDouble</code> method in
+ * the class <code>java.lang.Double</code>
+ * <p>
+ * This method can read a <code>double</code> written by an object implementing the
+ * <code>writeDouble()</code> method in the <code>DataOutput</code> interface.
+ *
+ * @return The <code>double</code> value read
+ *
+ * @exception EOFException If end of file is reached before reading the double
+ * @exception IOException If any other error occurs
+ *
+ * @see java.lang.Double
+ * @see DataOutput
+ */
+public final double
+readDouble() throws EOFException, IOException
+{
+ long val = readLong();
+
+ return(Double.longBitsToDouble(val));
+}
+
+/*************************************************************************/
+
+/**
+ * This method reads the next line of text data from an input stream.
+ * It operates by reading bytes and converting those bytes to <code>char</code>
+ * values by treating the byte read as the low eight bits of the <code>char</code>
+ * and using <code>0</code> as the high eight bits. Because of this, it does
+ * not support the full 16-bit Unicode character set.
+ * <p>
+ * The reading of bytes ends when either the end of file or a line terminator
+ * is encountered. The bytes read are then returned as a <code>String</code>
+ * A line terminator is a byte sequence consisting of either
+ * <code>\r</code> <code>\n</code> or <code>\r\n</code> These termination charaters are
+ * discarded and are not returned as part of the string.
+ * <p>
+ * This method can read data that was written by an object implementing the
+ * <code>writeLine()</code> method in <code>DataOutput</code>
+ *
+ * @return The line read as a <code>String</code>
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see DataOutput
+ *
+ * @deprecated
+ */
+public final String
+readLine() throws IOException
+{
+ StringBuffer sb = new StringBuffer("");
+
+ for (;;)
+ {
+ int byte_read = read();
+
+ if (byte_read == -1)
+ return(sb.toString());
+
+ char c = (char)byte_read;
+
+ if (c == '\r')
+ {
+ byte_read = read();
+ if (((char)byte_read) != '\n')
+ seek(getFilePointer() - 1);
+
+ return(sb.toString());
+ }
+
+ if (c == '\n')
+ return(sb.toString());
+
+ sb.append(c);
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * This method reads a <code>String</code> from an input stream that is encoded in
+ * a modified UTF-8 format. This format has a leading two byte sequence
+ * that contains the remaining number of bytes to read. This two byte
+ * sequence is read using the <code>readUnsignedShort()</code> method of this
+ * interface.
+ * <p>
+ * After the number of remaining bytes have been determined, these bytes
+ * are read an transformed into <code>char</code> values. These <code>char</code> values
+ * are encoded in the stream using either a one, two, or three byte format.
+ * The particular format in use can be determined by examining the first
+ * byte read.
+ * <p>
+ * If the first byte has a high order bit of 0 then
+ * that character consists on only one byte. This character value consists
+ * of seven bits that are at positions 0 through 6 of the byte. As an
+ * example, if <code>byte1</code> is the byte read from the stream, it would
+ * be converted to a <code>char</code> like so:
+ * <p>
+ * <code>(char)byte1</code>
+ * <p>
+ * If the first byte has <code>110</code> as its high order bits, then the
+ * character consists of two bytes. The bits that make up the character
+ * value are in positions 0 through 4 of the first byte and bit positions
+ * 0 through 5 of the second byte. (The second byte should have
+ * 10 as its high order bits). These values are in most significant
+ * byte first (i.e., "big endian") order.
+ * <p>
+ * As an example, if <code>byte1</code> and <code>byte2</code> are the first two bytes
+ * read respectively, and the high order bits of them match the patterns
+ * which indicate a two byte character encoding, then they would be
+ * converted to a Java <code>char</code> like so:
+ * <p>
+ * <code>(char)(((byte1 & 0x1F) << 6) | (byte2 & 0x3F))</code>
+ * <p>
+ * If the first byte has a <code>1110</code> as its high order bits, then the
+ * character consists of three bytes. The bits that make up the character
+ * value are in positions 0 through 3 of the first byte and bit positions
+ * 0 through 5 of the other two bytes. (The second and third bytes should
+ * have <code>10</code> as their high order bits). These values are in most
+ * significant byte first (i.e., "big endian") order.
+ * <p>
+ * As an example, if <code>byte1</code> <code>byte2</code> and <code>byte3</code> are the
+ * three bytes read, and the high order bits of them match the patterns
+ * which indicate a three byte character encoding, then they would be
+ * converted to a Java <code>char</code> like so:
+ * <p>
+ * <code>(char)(((byte1 & 0x0F) << 12) | ((byte2 & 0x3F) << 6) | (byte3 & 0x3F))</code>
+ * <p>
+ * Note that all characters are encoded in the method that requires the
+ * fewest number of bytes with the exception of the character with the
+ * value of <code>&#92;u0000</code> which is encoded as two bytes. This is a
+ * modification of the UTF standard used to prevent C language style
+ * <code>NUL</code> values from appearing in the byte stream.
+ * <p>
+ * This method can read data that was written by an object implementing the
+ * <code>writeUTF()</code> method in <code>DataOutput</code>
+ *
+ * @return The <code>String</code> read
+ *
+ * @exception EOFException If end of file is reached before reading the String
+ * @exception UTFDataFormatException If the data is not in UTF-8 format
+ * @exception IOException If any other error occurs
+ *
+ * @see DataOutput
+ */
+public final String
+readUTF() throws EOFException, UTFDataFormatException, IOException
+{
+ StringBuffer sb = new StringBuffer("");
+
+ int num_bytes = readUnsignedShort();
+ byte[] buf = new byte[num_bytes];
+ readFully(buf);
+
+ return(DataInputStream.convertFromUTF(buf));
+}
+
+/*************************************************************************/
+
+/**
+ * This method reads raw bytes into the passed array until the array is
+ * full. Note that this method blocks until the data is available and
+ * throws an exception if there is not enough data left in the stream to
+ * fill the buffer
+ *
+ * @param buf The buffer into which to read the data
+ *
+ * @exception EOFException If end of file is reached before filling the buffer
+ * @exception IOException If any other error occurs
+ */
+public final void
+readFully(byte[] buf) throws EOFException, IOException
+{
+ readFully(buf, 0, buf.length);
+}
+
+/*************************************************************************/
+
+/**
+ * This method reads raw bytes into the passed array <code>buf</code> starting
+ * <code>offset</code> bytes into the buffer. The number of bytes read will be
+ * exactly <code>len</code> Note that this method blocks until the data is
+ * available and * throws an exception if there is not enough data left in
+ * the stream to read <code>len</code> bytes.
+ *
+ * @param buf The buffer into which to read the data
+ * @param offset The offset into the buffer to start storing data
+ * @param len The number of bytes to read into the buffer
+ *
+ * @exception EOFException If end of file is reached before filling the buffer
+ * @exception IOException If any other error occurs
+ */
+public final void
+readFully(byte[] buf, int offset, int len) throws EOFException, IOException
+{
+ int total_read = 0;
+
+ while (total_read < len)
+ {
+ int bytes_read = read(buf, offset + total_read, len - total_read);
+ if (bytes_read == -1)
+ throw new EOFException("Unexpected end of stream");
+
+ total_read += bytes_read;
+ }
+}
+
+/*************************************************************************/
+
+/**
+ * This method attempts to skip and discard the specified number of bytes
+ * in the input stream. It may actually skip fewer bytes than requested.
+ * The actual number of bytes skipped is returned. This method will not
+ * skip any bytes if passed a negative number of bytes to skip.
+ *
+ * @param num_bytes The requested number of bytes to skip.
+ *
+ * @return The number of bytes actually skipped.
+ *
+ * @exception IOException If an error occurs.
+ */
+public int
+skipBytes(int n) throws EOFException, IOException
+{
+ if (n <= 0)
+ return(0);
+
+ long total_skipped = fd.skip(n);
+
+ return((int)n);
+}
+
+/*************************************************************************/
+
+/**
+ * This method writes a single byte of data to the file. The file must
+ * be open for read-write in order for this operation to succeed.
+ *
+ * @param The byte of data to write, passed as an int.
+ *
+ * @exception IOException If an error occurs
+ */
+public void
+write(int b) throws IOException
+{
+ if (read_only)
+ throw new IOException("File is open read only");
+
+ byte[] buf = new byte[1];
+ buf[0] = (byte)b;
+
+ fd.write(buf, 0, buf.length);
+}
+
+/*************************************************************************/
+
+/**
+ * This method writes all the bytes in the specified array to the file.
+ * The file must be open read-write in order for this operation to succeed.
+ *
+ * @param buf The array of bytes to write to the file
+ */
+public void
+write(byte[] buf) throws IOException
+{
+ if (read_only)
+ throw new IOException("File is open read only");
+
+ fd.write(buf, 0, buf.length);
+}
+
+/*************************************************************************/
+
+/**
+ * This method writes <code>len</code> bytes to the file from the specified
+ * array starting at index <code>offset</code> into the array.
+ *
+ * @param buf The array of bytes to write to the file
+ * @param offset The index into the array to start writing file
+ * @param len The number of bytes to write
+ *
+ * @exception IOException If an error occurs
+ */
+public void
+write(byte[] buf, int offset, int len) throws IOException
+{
+ if (read_only)
+ throw new IOException("File is open read only");
+
+ fd.write(buf, offset, len);
+}
+
+/*************************************************************************/
+
+/**
+ * This method writes a Java <code>boolean</code> to the underlying output
+ * stream. For a value of <code>true</code>, 1 is written to the stream.
+ * For a value of <code>false</code>, 0 is written.
+ *
+ * @param b The <code>boolean</code> value to write to the stream
+ *
+ * @exception IOException If an error occurs
+ */
+public final void
+writeBoolean(boolean b) throws IOException
+{
+ int bool = DataOutputStream.convertFromBoolean(b);
+ write(bool);
+}
+
+/*************************************************************************/
+
+/**
+ * This method writes a Java <code>byte</code> value to the underlying
+ * output stream.
+ *
+ * @param b The <code>byte</code> to write to the stream, passed as an <code>int</code>.
+ *
+ * @exception IOException If an error occurs
+ */
+public final void
+writeByte(int b) throws IOException
+{
+ write(b);
+}
+
+/*************************************************************************/
+
+/**
+ * This method writes all the bytes in a <code>String</code> out to the
+ * stream. One byte is written for each character in the <code>String</code>.
+ * The high eight bits of each character are discarded.
+ *
+ * @param s The <code>String</code> to write to the stream
+ *
+ * @exception IOException If an error occurs
+ */
+public final void
+writeBytes(String s) throws IOException
+{
+ if (s.length() == 0)
+ return;
+
+ byte[] buf = new byte[s.length()];
+
+ for (int i = 0; i < s.length(); i++)
+ buf[i] = (byte)(s.charAt(i) & 0xFF);
+
+ write(buf);
+}
+
+/*************************************************************************/
+
+/**
+ * This method writes a single <code>char</code> value to the stream,
+ * high byte first.
+ *
+ * @param c The <code>char</code> value to write, passed as an <code>int</code>.
+ *
+ * @exception IOException If an error occurs
+ */
+public final void
+writeChar(int c) throws IOException
+{
+ write(DataOutputStream.convertFromChar(c));
+}
+
+/*************************************************************************/
+
+/**
+ * This method writes all the characters in a <code>String</code> to the
+ * stream. There will be two bytes for each character value. The high
+ * byte of the character will be written first.
+ *
+ * @param s The <code>String</code> to write to the stream.
+ *
+ * @exception IOException If an error occurs
+ */
+public final void
+writeChars(String s) throws IOException
+{
+ if (s.length() == 0)
+ return;
+
+ byte[] buf = DataOutputStream.getConvertedStringChars(s);
+ write(buf);
+}
+
+/*************************************************************************/
+
+/**
+ * This method writes a Java <code>short</code> to the stream, high byte
+ * first. This method requires two bytes to encode the value.
+ *
+ * @param s The <code>short</code> value to write to the stream, passed as an <code>int</code>.
+ *
+ * @exception IOException If an error occurs
+ */
+public final void
+writeShort(int s) throws IOException
+{
+ write(DataOutputStream.convertFromShort(s));
+}
+
+/*************************************************************************/
+
+/**
+ * This method writes a Java <code>int</code> to the stream, high bytes
+ * first. This method requires four bytes to encode the value.
+ *
+ * @param i The <code>int</code> value to write to the stream.
+ *
+ * @exception IOException If an error occurs
+ */
+public final void
+writeInt(int i) throws IOException
+{
+ write(DataOutputStream.convertFromInt(i));
+}
+
+/*************************************************************************/
+
+/**
+ * This method writes a Java <code>long</code> to the stream, high bytes
+ * first. This method requires eight bytes to encode the value.
+ *
+ * @param l The <code>long</code> value to write to the stream.
+ *
+ * @exception IOException If an error occurs
+ */
+public final void
+writeLong(long l) throws IOException
+{
+ write(DataOutputStream.convertFromLong(l));
+}
+
+/*************************************************************************/
+
+/**
+ * This method writes a Java <code>float</code> value to the stream. This
+ * value is written by first calling the method <code>Float.floatToIntBits</code>
+ * to retrieve an <code>int</code> representing the floating point number,
+ * then writing this <code>int</code> value to the stream exactly the same
+ * as the <code>writeInt()</code> method does.
+ *
+ * @param f The floating point number to write to the stream.
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see writeInt
+ */
+public final void
+writeFloat(float f) throws IOException
+{
+ int i = Float.floatToIntBits(f);
+ writeInt(i);
+}
+
+/*************************************************************************/
+
+/**
+ * This method writes a Java <code>double</code> value to the stream. This
+ * value is written by first calling the method <code>Double.doubleToLongBits</code>
+ * to retrieve an <code>long</code> representing the floating point number,
+ * then writing this <code>long</code> value to the stream exactly the same
+ * as the <code>writeLong()</code> method does.
+ *
+ * @param d The double precision floating point number to write to the stream.
+ *
+ * @exception IOException If an error occurs
+ *
+ * @see writeLong
+ */
+public final void
+writeDouble(double d) throws IOException
+{
+ long l = Double.doubleToLongBits(d);
+ writeLong(l);
+}
+
+/*************************************************************************/
+
+/**
+ * This method writes a Java <code>String</code> to the stream in a modified
+ * UTF-8 format. First, two bytes are written to the stream indicating the
+ * number of bytes to follow. Note that this is the number of bytes in the
+ * encoded <code>String</code> not the <code>String</code> length. Next
+ * come the encoded characters. Each character in the <code>String</code>
+ * is encoded as either one, two or three bytes. For characters in the
+ * range of <code>&#92;u0001</code> to <code>&#92;u007F</code>, one byte is used. The character
+ * value goes into bits 0-7 and bit eight is 0. For characters in the range
+ * of <code>&#92;u0080</code> to <code>&#92;u007FF</code>, two bytes are used. Bits
+ * 6-10 of the character value are encoded bits 0-4 of the first byte, with
+ * the high bytes having a value of "110". Bits 0-5 of the character value
+ * are stored in bits 0-5 of the second byte, with the high bits set to
+ * "10". This type of encoding is also done for the null character
+ * <code>&#92;u0000</code>. This eliminates any C style NUL character values
+ * in the output. All remaining characters are stored as three bytes.
+ * Bits 12-15 of the character value are stored in bits 0-3 of the first
+ * byte. The high bits of the first bytes are set to "1110". Bits 6-11
+ * of the character value are stored in bits 0-5 of the second byte. The
+ * high bits of the second byte are set to "10". And bits 0-5 of the
+ * character value are stored in bits 0-5 of byte three, with the high bits
+ * of that byte set to "10".
+ *
+ * @param s The <code>String</code> to write to the output in UTF format
+ *
+ * @exception IOException If an error occurs
+ */
+public final void
+writeUTF(String s) throws IOException
+{
+ byte[] buf = DataOutputStream.convertToUTF(s);
+
+ writeShort(buf.length);
+ write(buf);
+}
+
+/*************************************************************************/
+
+/**
+ * This method creates a java.nio.channels.FileChannel.
+ * Nio does not allow one to create a file channel directly.
+ * A file channel must be created by first creating an instance of
+ * Input/Output/RandomAccessFile and invoking the getChannel() method on it.
+ */
+
+private FileChannel ch; /* cached associated file-channel */
+
+public FileChannel
+getChannel()
+{
+ synchronized (this)
+ {
+// if (ch == null)
+// ch = new gnu.java.nio.FileChannelImpl(native_fd,
+// this);
+ }
+ return ch;
+}
+
+/*************************************************************************/
+
+/**
+ * This method ensures that the underlying file is closed when this object
+ * is garbage collected. Since there is a system dependent limit on how
+ * many files a single process can have open, it is a good idea to close
+ * streams when they are no longer needed rather than waiting for garbage
+ * collectio to automatically close them.
+ *
+ * @exception IOException If an error occurs
+ */
+protected void finalize() throws IOException
+{
+ if(fd != null)
+ {
+ close();
+ }
+}
+
+
+} // class RandomAccessFile
+
diff --git a/classpath/java/lang/Thread.java b/classpath/java/lang/Thread.java
new file mode 100644
index 00000000..b52e7995
--- /dev/null
+++ b/classpath/java/lang/Thread.java
@@ -0,0 +1,1005 @@
+/* Thread -- an independent thread of executable code
+ Copyright (C) 1998, 2001, 2002 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;
+
+/**
+ * Thread represents a single thread of execution in the VM. When an
+ * application VM starts up, it creates a non-daemon Thread which calls the
+ * main() method of a particular class. There may be other Threads running,
+ * such as the garbage collection thread.
+ *
+ * <p>Threads have names to identify them. These names are not necessarily
+ * unique. Every Thread has a priority, as well, which tells the VM which
+ * Threads should get more running time. New threads inherit the priority
+ * and daemon status of the parent thread, by default.
+ *
+ * <p>There are two methods of creating a Thread: you may subclass Thread and
+ * implement the <code>run()</code> method, at which point you may start the
+ * Thread by calling its <code>start()</code> method, or you may implement
+ * <code>Runnable</code> in the class you want to use and then call new
+ * <code>Thread(your_obj).start()</code>.
+ *
+ * <p>The virtual machine runs until all non-daemon threads have died (either
+ * by returning from the run() method as invoked by start(), or by throwing
+ * an uncaught exception); or until <code>System.exit</code> is called with
+ * adequate permissions.
+ *
+ * <p>It is unclear at what point a Thread should be added to a ThreadGroup,
+ * and at what point it should be removed. Should it be inserted when it
+ * starts, or when it is created? Should it be removed when it is suspended
+ * or interrupted? The only thing that is clear is that the Thread should be
+ * removed when it is stopped.
+ *
+ * @author John Keiser
+ * @author Eric Blake <ebb9@email.byu.edu>
+ * @see Runnable
+ * @see Runtime#exit(int)
+ * @see #run()
+ * @see #start()
+ * @see ThreadLocal
+ * @since 1.0
+ * @status updated to 1.4
+ */
+public class Thread implements Runnable
+{
+ /** The minimum priority for a Thread. */
+ public static final int MIN_PRIORITY = 1;
+
+ /** The priority a Thread gets by default. */
+ public static final int NORM_PRIORITY = 5;
+
+ /** The maximum priority for a Thread. */
+ public static final int MAX_PRIORITY = 10;
+
+ // note that nativeThread is only set for threads that have actually been started!
+ private system.threading.Thread nativeThread;
+ private static system.LocalDataStoreSlot localDataStoreSlot;
+
+ /**
+ * The group this thread belongs to. This is set to null by
+ * ThreadGroup.removeThread when the thread dies.
+ */
+ ThreadGroup group;
+
+ /** The object to run(), null if this is the target. */
+ final Runnable toRun;
+
+ /** The thread name, non-null. */
+ String name;
+
+ /** Whether the thread is a daemon. */
+ boolean daemon;
+
+ /** The thread priority, 1 to 10. */
+ int priority;
+
+ /** The context classloader for this Thread. */
+ private ClassLoader contextClassLoader = ClassLoader.getSystemClassLoader();
+
+ /** The next thread number to use. */
+ private static int numAnonymousThreadsCreated = 0;
+
+ private Thread(ThreadGroup group, system.threading.Thread nativeThread)
+ {
+ this.group = group;
+ this.nativeThread = nativeThread;
+ this.toRun = null;
+ this.name = nativeThread.get_Name();
+ switch(nativeThread.get_Priority())
+ {
+ case system.threading.ThreadPriority.Lowest:
+ priority = MIN_PRIORITY;
+ break;
+ case system.threading.ThreadPriority.BelowNormal:
+ priority = 3;
+ break;
+ case system.threading.ThreadPriority.Normal:
+ priority = NORM_PRIORITY;
+ break;
+ case system.threading.ThreadPriority.AboveNormal:
+ priority = 7;
+ break;
+ case system.threading.ThreadPriority.Highest:
+ priority = MAX_PRIORITY;
+ break;
+ }
+ }
+
+ /**
+ * Allocate a new Thread object, as if by
+ * <code>Thread(null, null, <i>fake name</i>)</code>, where the fake name
+ * is "Thread-" + <i>unique integer</i>.
+ *
+ * @see #Thread(ThreadGroup, Runnable, String)
+ */
+ public Thread()
+ {
+ this(null, (Runnable) null);
+ }
+
+ /**
+ * Allocate a new Thread object, as if by
+ * <code>Thread(null, toRun, <i>fake name</i>)</code>, where the fake name
+ * is "Thread-" + <i>unique integer</i>.
+ *
+ * @param toRun the Runnable object to execute
+ * @see #Thread(ThreadGroup, Runnable, String)
+ */
+ public Thread(Runnable toRun)
+ {
+ this(null, toRun);
+ }
+
+ /**
+ * Allocate a new Thread object, as if by
+ * <code>Thread(group, toRun, <i>fake name</i>)</code>, where the fake name
+ * is "Thread-" + <i>unique integer</i>.
+ *
+ * @param group the group to put the Thread into
+ * @param target the Runnable object to execute
+ * @throws SecurityException if this thread cannot access <code>group</code>
+ * @throws IllegalThreadStateException if group is destroyed
+ * @see #Thread(ThreadGroup, Runnable, String)
+ */
+ public Thread(ThreadGroup group, Runnable toRun)
+ {
+ this(group, toRun, "Thread-" + ++numAnonymousThreadsCreated, 0);
+ }
+
+ /**
+ * Allocate a new Thread object, as if by
+ * <code>Thread(null, null, name)</code>.
+ *
+ * @param name the name for the Thread
+ * @throws NullPointerException if name is null
+ * @see #Thread(ThreadGroup, Runnable, String)
+ */
+ public Thread(String name)
+ {
+ this(null, null, name, 0);
+ }
+
+ /**
+ * Allocate a new Thread object, as if by
+ * <code>Thread(group, null, name)</code>.
+ *
+ * @param group the group to put the Thread into
+ * @param name the name for the Thread
+ * @throws NullPointerException if name is null
+ * @throws SecurityException if this thread cannot access <code>group</code>
+ * @throws IllegalThreadStateException if group is destroyed
+ * @see #Thread(ThreadGroup, Runnable, String)
+ */
+ public Thread(ThreadGroup group, String name)
+ {
+ this(group, null, name, 0);
+ }
+
+ /**
+ * Allocate a new Thread object, as if by
+ * <code>Thread(group, null, name)</code>.
+ *
+ * @param toRun the Runnable object to execute
+ * @param name the name for the Thread
+ * @throws NullPointerException if name is null
+ * @see #Thread(ThreadGroup, Runnable, String)
+ */
+ public Thread(Runnable toRun, String name)
+ {
+ this(null, toRun, name, 0);
+ }
+
+ /**
+ * Allocate a new Thread object, with the specified ThreadGroup and name, and
+ * using the specified Runnable object's <code>run()</code> method to
+ * execute. If the Runnable object is null, <code>this</code> (which is
+ * a Runnable) is used instead.
+ *
+ * <p>If the ThreadGroup is null, the security manager is checked. If a
+ * manager exists and returns a non-null object for
+ * <code>getThreadGroup</code>, that group is used; otherwise the group
+ * of the creating thread is used. Note that the security manager calls
+ * <code>checkAccess</code> if the ThreadGroup is not null.
+ *
+ * <p>The new Thread will inherit its creator's priority and daemon status.
+ * These can be changed with <code>setPriority</code> and
+ * <code>setDaemon</code>.
+ *
+ * @param group the group to put the Thread into
+ * @param target the Runnable object to execute
+ * @param name the name for the Thread
+ * @throws NullPointerException if name is null
+ * @throws SecurityException if this thread cannot access <code>group</code>
+ * @throws IllegalThreadStateException if group is destroyed
+ * @see Runnable#run()
+ * @see #run()
+ * @see #setDaemon(boolean)
+ * @see #setPriority(int)
+ * @see SecurityManager#checkAccess(ThreadGroup)
+ * @see ThreadGroup#checkAccess()
+ */
+ public Thread(ThreadGroup group, Runnable toRun, String name)
+ {
+ this(group, toRun, name, 0);
+ }
+
+ /**
+ * Allocate a new Thread object, as if by
+ * <code>Thread(group, null, name)</code>, and give it the specified stack
+ * size, in bytes. The stack size is <b>highly platform independent</b>,
+ * and the virtual machine is free to round up or down, or ignore it
+ * completely. A higher value might let you go longer before a
+ * <code>StackOverflowError</code>, while a lower value might let you go
+ * longer before an <code>OutOfMemoryError</code>. Or, it may do absolutely
+ * nothing! So be careful, and expect to need to tune this value if your
+ * virtual machine even supports it.
+ *
+ * @param group the group to put the Thread into
+ * @param target the Runnable object to execute
+ * @param name the name for the Thread
+ * @param size the stack size, in bytes; 0 to be ignored
+ * @throws NullPointerException if name is null
+ * @throws SecurityException if this thread cannot access <code>group</code>
+ * @throws IllegalThreadStateException if group is destroyed
+ * @since 1.4
+ */
+ public Thread(ThreadGroup group, Runnable toRun, String name, long size)
+ {
+ // Bypass System.getSecurityManager, for bootstrap efficiency.
+ SecurityManager sm = Runtime.securityManager;
+ if (group == null)
+ {
+ if (sm != null)
+ group = sm.getThreadGroup();
+ if (group == null)
+ group = currentThread().group;
+ }
+ else if (sm != null)
+ sm.checkAccess(group);
+ this.group = group;
+
+ // Use toString hack to detect null.
+ this.name = name.toString();
+ this.toRun = toRun;
+ Thread current = currentThread();
+ priority = current.priority;
+ daemon = current.daemon;
+
+ group.addThread(this);
+ InheritableThreadLocal.newChildThread(this);
+ }
+
+ /**
+ * Get the currently executing Thread.
+ *
+ * @return the currently executing Thread
+ */
+ public static Thread currentThread()
+ {
+ if(localDataStoreSlot == null)
+ {
+ localDataStoreSlot = system.threading.Thread.AllocateDataSlot();
+ }
+ system.threading.Thread thread = system.threading.Thread.get_CurrentThread();
+ Thread javaThread = (Thread)system.threading.Thread.GetData(localDataStoreSlot);
+ if(javaThread == null)
+ {
+ // threads created outside of Java always run in the root thread group
+ javaThread = new Thread(ThreadGroup.root, thread);
+ system.threading.Thread.SetData(localDataStoreSlot, javaThread);
+ }
+ return javaThread;
+ }
+
+ /**
+ * Yield to another thread. The Thread will not lose any locks it holds
+ * during this time. There are no guarantees which thread will be
+ * next to run, and it could even be this one, but most VMs will choose
+ * the highest priority threat that has been waiting longest.
+ */
+ public static void yield()
+ {
+ system.threading.Thread.Sleep(0);
+ }
+
+ /**
+ * Suspend the current Thread's execution for the specified amount of
+ * time. The Thread will not lose any locks it has during this time. There
+ * are no guarantees which thread will be next to run, but most VMs will
+ * choose the highest priority threat that has been waiting longest.
+ *
+ * @param ms the number of milliseconds to sleep, or 0 for forever
+ * @throws InterruptedException if the Thread is interrupted; it's
+ * <i>interrupted status</i> will be cleared
+ * @see #notify()
+ * @see #wait(long)
+ */
+ public static void sleep(long ms) throws InterruptedException
+ {
+ sleep(ms, 0);
+ }
+
+ /**
+ * Suspend the current Thread's execution for the specified amount of
+ * time. The Thread will not lose any locks it has during this time. There
+ * are no guarantees which thread will be next to run, but most VMs will
+ * choose the highest priority threat that has been waiting longest.
+ *
+ * <p>Note that 1,000,000 nanoseconds == 1 millisecond, but most VMs do
+ * not offer that fine a grain of timing resolution. Besides, there is
+ * no guarantee that this thread can start up immediately when time expires,
+ * because some other thread may be active. So don't expect real-time
+ * performance.
+ *
+ * @param ms the number of milliseconds to sleep, or 0 for forever
+ * @param ns the number of extra nanoseconds to sleep (0-999999)
+ * @throws InterruptedException if the Thread is interrupted; it's
+ * <i>interrupted status</i> will be cleared
+ * @throws IllegalArgumentException if ns is invalid
+ * @see #notify()
+ * @see #wait(long, int)
+ */
+ public static native void sleep(long ms, int ns) throws InterruptedException;
+
+ /**
+ * Start this Thread, calling the run() method of the Runnable this Thread
+ * was created with, or else the run() method of the Thread itself. This
+ * is the only way to start a new thread; calling run by yourself will just
+ * stay in the same thread. The virtual machine will remove the thread from
+ * its thread group when the run() method completes.
+ *
+ * @throws IllegalThreadStateException if the thread has already started
+ * @see #run()
+ */
+ public synchronized void start() throws IllegalThreadStateException
+ {
+ if(nativeThread != null)
+ {
+ throw new IllegalThreadStateException();
+ }
+ if(localDataStoreSlot == null)
+ {
+ localDataStoreSlot = system.threading.Thread.AllocateDataSlot();
+ }
+ system.threading.ThreadStart starter = new system.threading.ThreadStart(
+ new system.threading.ThreadStart.Method()
+ {
+ public void Invoke()
+ {
+ try
+ {
+ system.threading.Thread.SetData(localDataStoreSlot, Thread.this);
+ try
+ {
+ run();
+ }
+ catch(Throwable t)
+ {
+ if(group != null)
+ {
+ group.uncaughtException(Thread.this, t);
+ }
+ }
+ }
+ finally
+ {
+ if(group != null)
+ {
+ group.removeThread(Thread.this);
+ // NOTE shouldn't we set group to null here?
+ }
+ }
+ }
+ });
+ nativeThread = new system.threading.Thread(starter);
+ nativeThread.set_Name(name);
+ nativeThread.set_IsBackground(daemon);
+ setPriorityNative();
+ nativeThread.Start();
+ }
+
+ /**
+ * The method of Thread that will be run if there is no Runnable object
+ * associated with the Thread. Thread's implementation does nothing at all.
+ *
+ * @see #start()
+ * @see #Thread(ThreadGroup, Runnable, String)
+ */
+ public void run()
+ {
+ if (toRun != null)
+ toRun.run();
+ }
+
+ /**
+ * Cause this Thread to stop abnormally because of the throw of a ThreadDeath
+ * error. If you stop a Thread that has not yet started, it will stop
+ * immediately when it is actually started.
+ *
+ * <p>This is inherently unsafe, as it can interrupt synchronized blocks and
+ * leave data in bad states. Hence, there is a security check:
+ * <code>checkAccess(this)</code>, plus another one if the current thread
+ * is not this: <code>RuntimePermission("stopThread")</code>. If you must
+ * catch a ThreadDeath, be sure to rethrow it after you have cleaned up.
+ * ThreadDeath is the only exception which does not print a stack trace when
+ * the thread dies.
+ *
+ * @throws SecurityException if you cannot stop the Thread
+ * @see #interrupt()
+ * @see #checkAccess()
+ * @see #start()
+ * @see ThreadDeath
+ * @see ThreadGroup#uncaughtException(Thread, Throwable)
+ * @see SecurityManager#checkAccess(Thread)
+ * @see SecurityManager#checkPermission(Permission)
+ * @deprecated unsafe operation, try not to use
+ */
+ public final void stop()
+ {
+ stop(new ThreadDeath());
+ }
+
+ /**
+ * Cause this Thread to stop abnormally and throw the specified exception.
+ * If you stop a Thread that has not yet started, it will stop immediately
+ * when it is actually started. <b>WARNING</b>This bypasses Java security,
+ * and can throw a checked exception which the call stack is unprepared to
+ * handle. Do not abuse this power.
+ *
+ * <p>This is inherently unsafe, as it can interrupt synchronized blocks and
+ * leave data in bad states. Hence, there is a security check:
+ * <code>checkAccess(this)</code>, plus another one if the current thread
+ * is not this: <code>RuntimePermission("stopThread")</code>. If you must
+ * catch a ThreadDeath, be sure to rethrow it after you have cleaned up.
+ * ThreadDeath is the only exception which does not print a stack trace when
+ * the thread dies.
+ *
+ * @param t the Throwable to throw when the Thread dies
+ * @throws SecurityException if you cannot stop the Thread
+ * @throws NullPointerException in the calling thread, if t is null
+ * @see #interrupt()
+ * @see #checkAccess()
+ * @see #start()
+ * @see ThreadDeath
+ * @see ThreadGroup#uncaughtException(Thread, Throwable)
+ * @see SecurityManager#checkAccess(Thread)
+ * @see SecurityManager#checkPermission(Permission)
+ * @deprecated unsafe operation, try not to use
+ */
+ public final synchronized void stop(Throwable t)
+ {
+ if (t == null)
+ throw new NullPointerException();
+ // Bypass System.getSecurityManager, for bootstrap efficiency.
+ SecurityManager sm = Runtime.securityManager;
+ if (sm != null)
+ {
+ sm.checkAccess(this);
+ if (this != currentThread())
+ sm.checkPermission(new RuntimePermission("stopThread"));
+ }
+ group.removeThread(this);
+ // TODO what happens if the thread hasn't been started yet?
+ nativeThread.Abort(t);
+ }
+
+ /**
+ * Interrupt this Thread. First, there is a security check,
+ * <code>checkAccess</code>. Then, depending on the current state of the
+ * thread, various actions take place:
+ *
+ * <p>If the thread is waiting because of {@link #wait()},
+ * {@link #sleep(long)}, or {@link #join()}, its <i>interrupt status</i>
+ * will be cleared, and an InterruptedException will be thrown. Notice that
+ * this case is only possible if an external thread called interrupt().
+ *
+ * <p>If the thread is blocked in an interruptible I/O operation, in
+ * {@link java.nio.channels.InterruptibleChannel}, the <i>interrupt
+ * status</i> will be set, and ClosedByInterruptException will be thrown.
+ *
+ * <p>If the thread is blocked on a {@link java.nio.channels.Selector}, the
+ * <i>interrupt status</i> will be set, and the selection will return, with
+ * a possible non-zero value, as though by the wakeup() method.
+ *
+ * <p>Otherwise, the interrupt status will be set.
+ *
+ * @throws SecurityException if you cannot modify this Thread
+ */
+ public synchronized void interrupt()
+ {
+ checkAccess();
+ // TODO what happens if the thread hasn't been started yet?
+ // TODO figure out how interrupt really works
+ nativeThread.Interrupt();
+ }
+
+ /**
+ * Determine whether the current Thread has been interrupted, and clear
+ * the <i>interrupted status</i> in the process.
+ *
+ * @return whether the current Thread has been interrupted
+ * @see #isInterrupted()
+ */
+ public static boolean interrupted()
+ {
+ try
+ {
+ synchronized(currentThread())
+ {
+ if(false) throw new InterruptedException();
+ system.threading.Thread.Sleep(0);
+ }
+ return false;
+ }
+ catch(InterruptedException x)
+ {
+ return true;
+ }
+ }
+
+ /**
+ * Determine whether the given Thread has been interrupted, but leave
+ * the <i>interrupted status</i> alone in the process.
+ *
+ * @return whether the current Thread has been interrupted
+ * @see #interrupted()
+ */
+ public boolean isInterrupted()
+ {
+ // NOTE special case for current thread, because then we can use the .NET interrupted status
+ if(this == currentThread())
+ {
+ try
+ {
+ if(false) throw new InterruptedException();
+ system.threading.Thread.Sleep(0);
+ return false;
+ }
+ catch(InterruptedException x)
+ {
+ // because we "consumed" the interrupt, we need to interrupt ourself again
+ nativeThread.Interrupt();
+ return true;
+ }
+ }
+ // HACK since quering the interrupted state of another thread is inherently racy, I hope
+ // we can get away with always returning false, because I have no idea how to obtain this
+ // information from the .NET runtime
+ return false;
+ }
+
+ /**
+ * Originally intended to destroy this thread, this method was never
+ * implemented by Sun, and is hence a no-op.
+ */
+ public void destroy()
+ {
+ }
+
+ /**
+ * Determine whether this Thread is alive. A thread which is alive has
+ * started and not yet died.
+ *
+ * @return whether this Thread is alive
+ */
+ public final boolean isAlive()
+ {
+ system.threading.Thread t = nativeThread;
+ return t != null && t.get_IsAlive();
+ }
+
+ /**
+ * Suspend this Thread. It will not come back, ever, unless it is resumed.
+ *
+ * <p>This is inherently unsafe, as the suspended thread still holds locks,
+ * and can potentially deadlock your program. Hence, there is a security
+ * check: <code>checkAccess</code>.
+ *
+ * @throws SecurityException if you cannot suspend the Thread
+ * @see #checkAccess()
+ * @see #resume()
+ * @deprecated unsafe operation, try not to use
+ */
+ public final synchronized void suspend()
+ {
+ checkAccess();
+ // TODO what happens if the thread hasn't been started yet?
+ // TODO handle errors
+ nativeThread.Suspend();
+ }
+
+ /**
+ * Resume this Thread. If the thread is not suspended, this method does
+ * nothing. To mirror suspend(), there may be a security check:
+ * <code>checkAccess</code>.
+ *
+ * @throws SecurityException if you cannot resume the Thread
+ * @see #checkAccess()
+ * @see #suspend()
+ * @deprecated pointless, since suspend is deprecated
+ */
+ public final synchronized void resume()
+ {
+ checkAccess();
+ // TODO what happens if the thread hasn't been started yet?
+ // TODO handle errors
+ nativeThread.Resume();
+ }
+
+ /**
+ * Set this Thread's priority. There may be a security check,
+ * <code>checkAccess</code>, then the priority is set to the smaller of
+ * priority and the ThreadGroup maximum priority.
+ *
+ * @param priority the new priority for this Thread
+ * @throws IllegalArgumentException if priority exceeds MIN_PRIORITY or
+ * MAX_PRIORITY
+ * @throws SecurityException if you cannot modify this Thread
+ * @see #getPriority()
+ * @see #checkAccess()
+ * @see ThreadGroup#getMaxPriority()
+ * @see #MIN_PRIORITY
+ * @see #MAX_PRIORITY
+ */
+ public final void setPriority(int priority)
+ {
+ checkAccess();
+ if (priority < MIN_PRIORITY || priority > MAX_PRIORITY)
+ {
+ throw new IllegalArgumentException("Invalid thread priority value " + priority + ".");
+ }
+ this.priority = Math.min(priority, group.getMaxPriority());
+ if(nativeThread != null)
+ {
+ setPriorityNative();
+ }
+ }
+
+ private void setPriorityNative()
+ {
+ if(priority == MIN_PRIORITY)
+ {
+ nativeThread.set_Priority(system.threading.ThreadPriority.Lowest);
+ }
+ else if(priority > MIN_PRIORITY && priority < NORM_PRIORITY)
+ {
+ nativeThread.set_Priority(system.threading.ThreadPriority.BelowNormal);
+ }
+ else if(priority == NORM_PRIORITY)
+ {
+ nativeThread.set_Priority(system.threading.ThreadPriority.Normal);
+ }
+ else if(priority > NORM_PRIORITY && priority < MAX_PRIORITY)
+ {
+ nativeThread.set_Priority(system.threading.ThreadPriority.AboveNormal);
+ }
+ else if(priority == MAX_PRIORITY)
+ {
+ nativeThread.set_Priority(system.threading.ThreadPriority.Highest);
+ }
+ }
+
+ /**
+ * Get this Thread's priority.
+ *
+ * @return the Thread's priority
+ */
+ public final int getPriority()
+ {
+ return priority;
+ }
+
+ /**
+ * Set this Thread's name. There may be a security check,
+ * <code>checkAccess</code>.
+ *
+ * @param name the new name for this Thread
+ * @throws NullPointerException if name is null
+ * @throws SecurityException if you cannot modify this Thread
+ */
+ public final void setName(String name)
+ {
+ checkAccess();
+ // Use toString hack to detect null.
+ this.name = name.toString();
+ }
+
+ /**
+ * Get this Thread's name.
+ *
+ * @return this Thread's name
+ */
+ public final String getName()
+ {
+ return name;
+ }
+
+ /**
+ * Get the ThreadGroup this Thread belongs to. If the thread has died, this
+ * returns null.
+ *
+ * @return this Thread's ThreadGroup
+ */
+ public final ThreadGroup getThreadGroup()
+ {
+ return group;
+ }
+
+ /**
+ * Get the number of active threads in the current Thread's ThreadGroup.
+ * This implementation calls
+ * <code>currentThread().getThreadGroup().activeCount()</code>.
+ *
+ * @return the number of active threads in the current ThreadGroup
+ * @see ThreadGroup#activeCount()
+ */
+ public static int activeCount()
+ {
+ return currentThread().group.activeCount();
+ }
+
+ /**
+ * Copy every active thread in the current Thread's ThreadGroup into the
+ * array. Extra threads are silently ignored. This implementation calls
+ * <code>getThreadGroup().enumerate(array)</code>, which may have a
+ * security check, <code>checkAccess(group)</code>.
+ *
+ * @param array the array to place the Threads into
+ * @return the number of Threads placed into the array
+ * @throws NullPointerException if array is null
+ * @throws SecurityException if you cannot access the ThreadGroup
+ * @see ThreadGroup#enumerate(Thread[])
+ * @see #activeCount()
+ * @see SecurityManager#checkAccess(ThreadGroup)
+ */
+ public static int enumerate(Thread[] array)
+ {
+ return currentThread().group.enumerate(array);
+ }
+
+ /**
+ * Count the number of stack frames in this Thread. The Thread in question
+ * must be suspended when this occurs.
+ *
+ * @return the number of stack frames in this Thread
+ * @throws IllegalThreadStateException if this Thread is not suspended
+ * @deprecated pointless, since suspend is deprecated
+ */
+ public int countStackFrames()
+ {
+ // Sun's 1.4 JVM returns 0, so we can do the same
+ return 0;
+ }
+
+ /**
+ * Wait the specified amount of time for the Thread in question to die.
+ *
+ * @param ms the number of milliseconds to wait, or 0 for forever
+ * @throws InterruptedException if the Thread is interrupted; it's
+ * <i>interrupted status</i> will be cleared
+ */
+ public final void join(long ms) throws InterruptedException
+ {
+ join(ms, 0);
+ }
+
+ /**
+ * Wait the specified amount of time for the Thread in question to die.
+ *
+ * <p>Note that 1,000,000 nanoseconds == 1 millisecond, but most VMs do
+ * not offer that fine a grain of timing resolution. Besides, there is
+ * no guarantee that this thread can start up immediately when time expires,
+ * because some other thread may be active. So don't expect real-time
+ * performance.
+ *
+ * @param ms the number of milliseconds to wait, or 0 for forever
+ * @param ns the number of extra nanoseconds to sleep (0-999999)
+ * @throws InterruptedException if the Thread is interrupted; it's
+ * <i>interrupted status</i> will be cleared
+ * @throws IllegalArgumentException if ns is invalid
+ * @XXX A ThreadListener would be nice, to make this efficient.
+ */
+ public final void join(long ms, int ns) throws InterruptedException
+ {
+ joinInternal(nativeThread, ms, ns);
+ }
+ private static native void joinInternal(system.threading.Thread nativeThread, long ms, int ns) throws InterruptedException;
+
+ /**
+ * Wait forever for the Thread in question to die.
+ *
+ * @throws InterruptedException if the Thread is interrupted; it's
+ * <i>interrupted status</i> will be cleared
+ */
+ public final void join() throws InterruptedException
+ {
+ join(0, 0);
+ }
+
+ /**
+ * Print a stack trace of the current thread to stderr using the same
+ * format as Throwable's printStackTrace() method.
+ *
+ * @see Throwable#printStackTrace()
+ */
+ public static void dumpStack()
+ {
+ new Throwable().printStackTrace();
+ }
+
+ /**
+ * Set the daemon status of this Thread. If this is a daemon Thread, then
+ * the VM may exit even if it is still running. This may only be called
+ * before the Thread starts running. There may be a security check,
+ * <code>checkAccess</code>.
+ *
+ * @param daemon whether this should be a daemon thread or not
+ * @throws SecurityException if you cannot modify this Thread
+ * @throws IllegalThreadStateException if the Thread is active
+ * @see #isDaemon()
+ * @see #checkAccess()
+ */
+ public final synchronized void setDaemon(boolean daemon)
+ {
+ if (isAlive() || group == null)
+ throw new IllegalThreadStateException();
+ checkAccess();
+ this.daemon = daemon;
+ }
+
+ /**
+ * Tell whether this is a daemon Thread or not.
+ *
+ * @return whether this is a daemon Thread or not
+ * @see #setDaemon(boolean)
+ */
+ public final boolean isDaemon()
+ {
+ return daemon;
+ }
+
+ /**
+ * Check whether the current Thread is allowed to modify this Thread. This
+ * passes the check on to <code>SecurityManager.checkAccess(this)</code>.
+ *
+ * @throws SecurityException if the current Thread cannot modify this Thread
+ * @see SecurityManager#checkAccess(Thread)
+ */
+ public final void checkAccess()
+ {
+ // Bypass System.getSecurityManager, for bootstrap efficiency.
+ SecurityManager sm = Runtime.securityManager;
+ if (sm != null)
+ sm.checkAccess(this);
+ }
+
+ /**
+ * Return a human-readable String representing this Thread. The format of
+ * the string is:<br>
+ * <code>"Thread[" + getName() + ',' + getPriority() + ','
+ * + (getThreadGroup() == null ? "" : getThreadGroup().getName())
+ + ']'</code>.
+ *
+ * @return a human-readable String representing this Thread
+ */
+ public String toString()
+ {
+ return "Thread[" + name + ',' + priority + ','
+ + (group == null ? "" : group.name) + ']';
+ }
+
+ /**
+ * Returns the context classloader of this Thread. The context
+ * classloader can be used by code that want to load classes depending
+ * on the current thread. Normally classes are loaded depending on
+ * the classloader of the current class. There may be a security check
+ * for <code>RuntimePermission("getClassLoader")</code> if the caller's
+ * class loader is not null or an ancestor of this thread's context class
+ * loader.
+ *
+ * @return the context class loader
+ * @throws SecurityException when permission is denied
+ * @see setContextClassLoader(ClassLoader)
+ * @since 1.2
+ */
+ public ClassLoader getContextClassLoader()
+ {
+ // Bypass System.getSecurityManager, for bootstrap efficiency.
+ SecurityManager sm = Runtime.securityManager;
+ if (sm != null)
+ // XXX Don't check this if the caller's class loader is an ancestor.
+ sm.checkPermission(new RuntimePermission("getClassLoader"));
+ return contextClassLoader;
+ }
+
+ /**
+ * Sets the context classloader for this Thread. When not explicitly set,
+ * the context classloader for a thread is the same as the context
+ * classloader of the thread that created this thread. The first thread has
+ * as context classloader the system classloader. There may be a security
+ * check for <code>RuntimePermission("setContextClassLoader")</code>.
+ *
+ * @param classloader the new context class loader
+ * @throws SecurityException when permission is denied
+ * @see getContextClassLoader()
+ * @since 1.2
+ */
+ public void setContextClassLoader(ClassLoader classloader)
+ {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ sm.checkPermission(new RuntimePermission("setContextClassLoader"));
+ this.contextClassLoader = classloader;
+ }
+
+ /**
+ * Checks whether the current thread holds the monitor on a given object.
+ * This allows you to do <code>assert Thread.holdsLock(obj)</code>.
+ *
+ * @param obj the object to check
+ * @return true if the current thread is currently synchronized on obj
+ * @throws NullPointerException if obj is null
+ * @since 1.4
+ */
+ public static boolean holdsLock(Object obj)
+ {
+ if(obj == null)
+ {
+ throw new NullPointerException();
+ }
+ try
+ {
+ // HACK this is a lame way of doing this, but I can't see any other way
+ // NOTE Wait causes the lock to be released temporarily, which isn't what we want
+ if(false) throw new IllegalMonitorStateException();
+ if(false) throw new InterruptedException();
+ system.threading.Monitor.Wait(obj, 0);
+ return true;
+ }
+ catch(IllegalMonitorStateException x)
+ {
+ return false;
+ }
+ catch(InterruptedException x1)
+ {
+ // Since we "consumed" the interrupt, we have to interrupt ourself again
+ Thread.currentThread().nativeThread.Interrupt();
+ return true;
+ }
+ }
+} // class Thread
diff --git a/classpath/java/lang/VMClassLoader.java b/classpath/java/lang/VMClassLoader.java
new file mode 100644
index 00000000..6c4506db
--- /dev/null
+++ b/classpath/java/lang/VMClassLoader.java
@@ -0,0 +1,271 @@
+/* VMClassLoader.java -- Reference implementation of native interface
+ required by ClassLoader
+ Copyright (C) 1998, 2001, 2002 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.security.ProtectionDomain;
+import java.net.URL;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.HashMap;
+import system.*;
+import system.reflection.*;
+/**
+ * java.lang.VMClassLoader is a package-private helper for VMs to implement
+ * on behalf of java.lang.ClassLoader.
+ *
+ * @author John Keiser
+ * @author Mark Wielaard <mark@klomp.org>
+ * @author Eric Blake <ebb9@email.byu.edu>
+ */
+final class VMClassLoader
+{
+ /**
+ * Helper to define a class using a string of bytes. This assumes that
+ * the security checks have already been performed, if necessary.
+ * <strong>This method will be removed in a future version of GNU
+ * Classpath</strong>.
+ *
+ * @param name the name to give the class, or null if unknown
+ * @param data the data representing the classfile, in classfile format
+ * @param offset the offset into the data where the classfile starts
+ * @param len the length of the classfile data in the array
+ * @return the class that was defined
+ * @throws ClassFormatError if data is not in proper classfile format
+ * @deprecated Implement
+ * {@link #defineClass(ClassLoader, String, byte[], int, int, ProtectionDomain)}
+ * instead.
+ */
+ static final Class defineClass(ClassLoader cl, String name, byte[] data, int offset, int len) throws ClassFormatError
+ {
+ return defineClass(cl, name, data, offset, len, null);
+ }
+
+ /**
+ * Helper to define a class using a string of bytes. This assumes that
+ * the security checks have already been performed, if necessary.
+ *
+ * <strong>For backward compatibility, this just ignores the protection
+ * domain; that is the wrong behavior, and you should directly implement
+ * this method natively if you can.</strong>
+ *
+ * @param name the name to give the class, or null if unknown
+ * @param data the data representing the classfile, in classfile format
+ * @param offset the offset into the data where the classfile starts
+ * @param len the length of the classfile data in the array
+ * @param pd the protection domain
+ * @return the class that was defined
+ * @throws ClassFormatError if data is not in proper classfile format
+ */
+ static final native Class defineClass(ClassLoader cl, String name, byte[] data, int offset, int len, ProtectionDomain pd)
+ throws ClassFormatError;
+
+ /**
+ * Helper to resolve all references to other classes from this class.
+ *
+ * @param c the class to resolve
+ */
+ static final void resolveClass(Class c)
+ {
+ // TODO
+ }
+
+ /**
+ * Helper to load a class from the bootstrap class loader.
+ *
+ * @param name the class name to load
+ * @param resolve whether to resolve it
+ * @return the class, loaded by the bootstrap classloader
+ */
+ static Class loadClass(String name, boolean resolve) throws ClassNotFoundException
+ {
+ Class c = Class.loadBootstrapClass(name, false);
+ if(c == null)
+ {
+ throw new ClassNotFoundException(name);
+ }
+ return c;
+ }
+
+ /**
+ * Helper to load a resource from the bootstrap class loader.
+ *
+ * XXX - Not implemented yet; this requires native help.
+ *
+ * @param name the resource to find
+ * @return the URL to the resource
+ */
+ static URL getResource(String name)
+ {
+ try
+ {
+ Assembly assembly = findResourceAssembly(name);
+ if(assembly != null)
+ {
+ return new URL("ikvmres:" + name + ":" + assembly.get_FullName());
+ }
+ }
+ catch(java.net.MalformedURLException x)
+ {
+ }
+ return null;
+ }
+ private static native Assembly findResourceAssembly(String name);
+
+ /**
+ * Helper to get a list of resources from the bootstrap class loader.
+ *
+ * XXX - Not implemented yet; this requires native help.
+ *
+ * @param name the resource to find
+ * @return an enumeration of resources
+ * @throws IOException if one occurs
+ */
+ static Enumeration getResources(String name) throws IOException
+ {
+ System.out.println("*** VMClassLoader.getResources: " + name);
+ // TODO
+ return new java.util.Vector(0).elements();
+ //return ClassLoader.getSystemResources(name);
+ }
+
+ /**
+ * Helper to get a package from the bootstrap class loader. The default
+ * implementation of returning null may be adequate, or you may decide
+ * that this needs some native help.
+ *
+ * @param name the name to find
+ * @return the named package, if it exists
+ */
+ static Package getPackage(String name)
+ {
+ return null;
+ }
+
+ /**
+ * Helper to get all packages from the bootstrap class loader. The default
+ * implementation of returning an empty array may be adequate, or you may
+ * decide that this needs some native help.
+ *
+ * @return all named packages, if any exist
+ */
+ static Package[] getPackages()
+ {
+ return new Package[0];
+ }
+
+ /**
+ * Helper for java.lang.Integer, Byte, etc to get the TYPE class
+ * at initialization time. The type code is one of the chars that
+ * represents the primitive type as in JNI.
+ *
+ * <ul>
+ * <li>'Z' - boolean</li>
+ * <li>'B' - byte</li>
+ * <li>'C' - char</li>
+ * <li>'D' - double</li>
+ * <li>'F' - float</li>
+ * <li>'I' - int</li>
+ * <li>'J' - long</li>
+ * <li>'S' - short</li>
+ * <li>'V' - void</li>
+ * </ul>
+ *
+ * Note that this is currently a java version that converts the type code
+ * to a string and calls the native <code>getPrimitiveClass(String)</code>
+ * method for backwards compatibility with VMs that used old versions of
+ * GNU Classpath. Please replace this method with a native method
+ * <code>final static native Class getPrimitiveClass(char type);</code>
+ * if your VM supports it. <strong>The java version of this method and
+ * the String version of this method will disappear in a future version
+ * of GNU Classpath</strong>.
+ *
+ * @param type the primitive type
+ * @return a "bogus" class representing the primitive type
+ */
+ static final Class getPrimitiveClass(char type)
+ {
+ return Class.getClassFromType(getPrimitiveType(type));
+ }
+
+ private static native system.Type getPrimitiveType(char type);
+
+ /**
+ * The system default for assertion status. This is used for all system
+ * classes (those with a null ClassLoader), as well as the initial value for
+ * every ClassLoader's default assertion status.
+ *
+ * XXX - Not implemented yet; this requires native help.
+ *
+ * @return the system-wide default assertion status
+ */
+ static final boolean defaultAssertionStatus()
+ {
+ return true;
+ }
+
+ /**
+ * The system default for package assertion status. This is used for all
+ * ClassLoader's packageAssertionStatus defaults. It must be a map of
+ * package names to Boolean.TRUE or Boolean.FALSE, with the unnamed package
+ * represented as a null key.
+ *
+ * XXX - Not implemented yet; this requires native help.
+ *
+ * @return a (read-only) map for the default packageAssertionStatus
+ */
+ static final Map packageAssertionStatus()
+ {
+ return new HashMap();
+ }
+
+ /**
+ * The system default for class assertion status. This is used for all
+ * ClassLoader's classAssertionStatus defaults. It must be a map of
+ * class names to Boolean.TRUE or Boolean.FALSE
+ *
+ * XXX - Not implemented yet; this requires native help.
+ *
+ * @return a (read-only) map for the default classAssertionStatus
+ */
+ static final Map classAssertionStatus()
+ {
+ return new HashMap();
+ }
+}
diff --git a/classpath/java/lang/reflect/Constructor.java b/classpath/java/lang/reflect/Constructor.java
new file mode 100644
index 00000000..a52aedd7
--- /dev/null
+++ b/classpath/java/lang/reflect/Constructor.java
@@ -0,0 +1,282 @@
+/* java.lang.reflect.Constructor - reflection of Java constructors
+ Copyright (C) 1998, 2001 Free Software Foundation, Inc.
+
+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.reflect;
+
+import system.*;
+import system.reflection.*;
+
+/**
+ * The Constructor class represents a constructor of a class. It also allows
+ * dynamic creation of an object, via reflection. Invocation on Constructor
+ * objects knows how to do widening conversions, but throws
+ * {@link IllegalArgumentException} if a narrowing conversion would be
+ * necessary. You can query for information on this Constructor regardless
+ * of location, but construction access may be limited by Java language
+ * access controls. If you can't do it in the compiler, you can't normally
+ * do it here either.<p>
+ *
+ * <B>Note:</B> This class returns and accepts types as Classes, even
+ * primitive types; there are Class types defined that represent each
+ * different primitive type. They are <code>java.lang.Boolean.TYPE,
+ * java.lang.Byte.TYPE,</code>, also available as <code>boolean.class,
+ * byte.class</code>, etc. These are not to be confused with the
+ * classes <code>java.lang.Boolean, java.lang.Byte</code>, etc., which are
+ * real classes.<p>
+ *
+ * Also note that this is not a serializable class. It is entirely feasible
+ * to make it serializable using the Externalizable interface, but this is
+ * on Sun, not me.
+ *
+ * @author John Keiser
+ * @author Eric Blake <ebb9@email.byu.edu>
+ * @see Member
+ * @see Class
+ * @see java.lang.Class#getConstructor(Object[])
+ * @see java.lang.Class#getDeclaredConstructor(Object[])
+ * @see java.lang.Class#getConstructors()
+ * @see java.lang.Class#getDeclaredConstructors()
+ * @since 1.1
+ * @status updated to 1.4
+ */
+public final class Constructor
+ extends AccessibleObject implements Member
+{
+ private Class clazz;
+ private Object methodCookie;
+
+ /**
+ * This class is instantiated by java.lang.Class
+ */
+ // TODO this constructor shouldn't be public (but it needs to be accessible to java.lang.Class)
+ public Constructor(Class declaringClass, Object methodCookie)
+ {
+ this.clazz = declaringClass;
+ this.methodCookie = methodCookie;
+ }
+
+ /**
+ * Gets the class that declared this constructor.
+ * @return the class that declared this member
+ */
+ public Class getDeclaringClass()
+ {
+ return clazz;
+ }
+
+ /**
+ * Gets the name of this constructor (the non-qualified name of the class
+ * it was declared in).
+ * @return the name of this constructor
+ */
+ public String getName()
+ {
+ return Method.GetName(methodCookie);
+ }
+
+ /**
+ * Gets the modifiers this constructor uses. Use the <code>Modifier</code>
+ * class to interpret the values. A constructor can only have a subset of the
+ * following modifiers: public, private, protected.
+ *
+ * @return an integer representing the modifiers to this Member
+ * @see Modifier
+ */
+ public int getModifiers()
+ {
+ return Method.GetModifiers(methodCookie);
+ }
+
+ /**
+ * Get the parameter list for this constructor, in declaration order. If the
+ * constructor takes no parameters, returns a 0-length array (not null).
+ *
+ * @return a list of the types of the constructor's parameters
+ */
+ public Class[] getParameterTypes()
+ {
+ Object[] params = Method.GetParameterTypes(methodCookie);
+ Class[] paramsClass = new Class[params.length];
+ System.arraycopy(params, 0, paramsClass, 0, params.length);
+ return paramsClass;
+ }
+
+ /**
+ * Get the exception types this constructor says it throws, in no particular
+ * order. If the constructor has no throws clause, returns a 0-length array
+ * (not null).
+ *
+ * @return a list of the types in the constructor's throws clause
+ */
+ public Class[] getExceptionTypes()
+ {
+ Object[] ex = Method.GetExceptionTypes(methodCookie);
+ Class[] exc = new Class[ex.length];
+ System.arraycopy(ex, 0, exc, 0, ex.length);
+ return exc;
+ }
+
+ /**
+ * Compare two objects to see if they are semantically equivalent.
+ * Two Constructors are semantically equivalent if they have the same
+ * declaring class and the same parameter list. This ignores different
+ * exception clauses, but since you can't create a Method except through the
+ * VM, this is just the == relation.
+ *
+ * @param o the object to compare to
+ * @return <code>true</code> if they are equal; <code>false</code> if not.
+ */
+ public boolean equals(Object o)
+ {
+ if(o instanceof ConstructorInfo)
+ {
+ return methodCookie == ((Constructor)o).methodCookie;
+ }
+ return false;
+ }
+
+ /**
+ * Get the hash code for the Constructor. The Constructor hash code is the
+ * hash code of the declaring class's name.
+ *
+ * @return the hash code for the object
+ */
+ public int hashCode()
+ {
+ return getDeclaringClass().getName().hashCode();
+ }
+
+ /**
+ * Get a String representation of the Constructor. A Constructor's String
+ * representation is "&lt;modifier&gt; &lt;classname&gt;(&lt;paramtypes&gt;)
+ * throws &lt;exceptions&gt;", where everything after ')' is omitted if
+ * there are no exceptions.<br> Example:
+ * <code>public java.io.FileInputStream(java.lang.Runnable)
+ * throws java.io.FileNotFoundException</code>
+ *
+ * @return the String representation of the Constructor
+ */
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer();
+ Modifier.toString(getModifiers(), sb).append(' ');
+ sb.append(getDeclaringClass().getName()).append('(');
+ Class[] c = getParameterTypes();
+ if (c.length > 0)
+ {
+ sb.append(c[0].getName());
+ for (int i = 1; i < c.length; i++)
+ sb.append(',').append(c[i].getName());
+ }
+ sb.append(')');
+ c = getExceptionTypes();
+ if (c.length > 0)
+ {
+ sb.append(" throws ").append(c[0].getName());
+ for (int i = 1; i < c.length; i++)
+ sb.append(',').append(c[i].getName());
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Create a new instance by invoking the constructor. Arguments are
+ * automatically unwrapped and widened, if needed.<p>
+ *
+ * If this class is abstract, you will get an
+ * <code>InstantiationException</code>. If the constructor takes 0
+ * arguments, you may use null or a 0-length array for <code>args</code>.<p>
+ *
+ * If this Constructor enforces access control, your runtime context is
+ * evaluated, and you may have an <code>IllegalAccessException</code> if
+ * you could not create this object in similar compiled code. If the class
+ * is uninitialized, you trigger class initialization, which may end in a
+ * <code>ExceptionInInitializerError</code>.<p>
+ *
+ * Then, the constructor is invoked. If it completes normally, the return
+ * value will be the new object. If it completes abruptly, the exception is
+ * wrapped in an <code>InvocationTargetException</code>.
+ *
+ * @param args the arguments to the constructor
+ * @return the newly created object
+ * @throws IllegalAccessException if the constructor could not normally be
+ * called by the Java code (i.e. it is not public)
+ * @throws IllegalArgumentException if the number of arguments is incorrect;
+ * or if the arguments types are wrong even with a widening
+ * conversion
+ * @throws InstantiationException if the class is abstract
+ * @throws InvocationTargetException if the constructor throws an exception
+ * @throws ExceptionInInitializerError if construction triggered class
+ * initialization, which then failed
+ */
+ public Object newInstance(Object args[])
+ throws InstantiationException, IllegalAccessException,
+ InvocationTargetException
+ {
+ return Method.Invoke(methodCookie, null, args);
+ /*
+ try
+ {
+ if(false) throw new MemberAccessException();
+ if(false) throw new ArgumentException();
+ if(false) throw new TargetParameterCountException();
+ if(false) throw new TargetInvocationException(null);
+ // TODO wrappers need to be unwrapped (e.g. java.lang.Integer -> boxed System.Int32)
+ return ci.Invoke(args);
+ }
+ catch(MemberAccessException x1)
+ {
+ throw new IllegalAccessException(x1.get_Message());
+ }
+ catch(ArgumentException x2)
+ {
+ throw new IllegalArgumentException();
+ }
+ catch(TargetParameterCountException x3)
+ {
+ throw new IllegalArgumentException();
+ }
+ catch(TargetInvocationException x4)
+ {
+ InstantiationException ie = new InstantiationException();
+ ie.initCause(Method.mapException(x4.get_InnerException()));
+ throw ie;
+ }
+ */
+ }
+}
diff --git a/classpath/java/lang/reflect/Field.java b/classpath/java/lang/reflect/Field.java
new file mode 100644
index 00000000..fc603836
--- /dev/null
+++ b/classpath/java/lang/reflect/Field.java
@@ -0,0 +1,646 @@
+/* java.lang.reflect.Field - reflection of Java fields
+ Copyright (C) 1998, 2001 Free Software Foundation, Inc.
+
+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.reflect;
+
+/**
+ * The Field class represents a member variable of a class. It also allows
+ * dynamic access to a member, via reflection. This works for both
+ * static and instance fields. Operations on Field objects know how to
+ * do widening conversions, but throw {@link IllegalArgumentException} if
+ * a narrowing conversion would be necessary. You can query for information
+ * on this Field regardless of location, but get and set access may be limited
+ * by Java language access controls. If you can't do it in the compiler, you
+ * can't normally do it here either.<p>
+ *
+ * <B>Note:</B> This class returns and accepts types as Classes, even
+ * primitive types; there are Class types defined that represent each
+ * different primitive type. They are <code>java.lang.Boolean.TYPE,
+ * java.lang.Byte.TYPE,</code>, also available as <code>boolean.class,
+ * byte.class</code>, etc. These are not to be confused with the
+ * classes <code>java.lang.Boolean, java.lang.Byte</code>, etc., which are
+ * real classes.<p>
+ *
+ * Also note that this is not a serializable class. It is entirely feasible
+ * to make it serializable using the Externalizable interface, but this is
+ * on Sun, not me.
+ *
+ * @author John Keiser
+ * @author Eric Blake <ebb9@email.byu.edu>
+ * @see Member
+ * @see Class
+ * @see Class#getField(String)
+ * @see Class#getDeclaredField(String)
+ * @see Class#getFields()
+ * @see Class#getDeclaredFields()
+ * @since 1.1
+ * @status updated to 1.4
+ */
+public final class Field extends AccessibleObject implements Member
+{
+ private Class declaringClass;
+ private Object fieldCookie;
+
+ /**
+ * This class is uninstantiable except natively.
+ */
+ public Field(Class declaringClass, Object fieldCookie)
+ {
+ this.declaringClass = declaringClass;
+ this.fieldCookie = fieldCookie;
+ }
+
+ /**
+ * Gets the class that declared this field, or the class where this field
+ * is a non-inherited member.
+ * @return the class that declared this member
+ */
+ public Class getDeclaringClass()
+ {
+ return declaringClass;
+ }
+
+ /**
+ * Gets the name of this field.
+ * @return the name of this field
+ */
+ public String getName()
+ {
+ return GetName(fieldCookie);
+ }
+ private static native String GetName(Object fieldCookie);
+
+
+ /**
+ * Gets the modifiers this field uses. Use the <code>Modifier</code>
+ * class to interpret the values. A field can only have a subset of the
+ * following modifiers: public, private, protected, static, final,
+ * transient, and volatile.
+ *
+ * @return an integer representing the modifiers to this Member
+ * @see Modifier
+ */
+ public int getModifiers()
+ {
+ return GetModifiers(fieldCookie);
+ }
+ private static native int GetModifiers(Object fieldCookie);
+
+ /**
+ * Gets the type of this field.
+ * @return the type of this field
+ */
+ public Class getType()
+ {
+ return (Class)GetFieldType(fieldCookie);
+ }
+ private static native Object GetFieldType(Object fieldCookie);
+
+ /**
+ * Compare two objects to see if they are semantically equivalent.
+ * Two Fields are semantically equivalent if they have the same declaring
+ * class, name, and type. Since you can't creat a Field except through
+ * the VM, this is just the == relation.
+ *
+ * @param o the object to compare to
+ * @return <code>true</code> if they are equal; <code>false</code> if not
+ */
+ public boolean equals(Object o)
+ {
+ if(o instanceof Field)
+ {
+ return fieldCookie == ((Field)o).fieldCookie;
+ }
+ return false;
+ }
+
+ /**
+ * Get the hash code for the Field. The Field hash code is the hash code
+ * of its name XOR'd with the hash code of its class name.
+ *
+ * @return the hash code for the object.
+ */
+ public int hashCode()
+ {
+ return getDeclaringClass().getName().hashCode() ^ getName().hashCode();
+ }
+
+ /**
+ * Get a String representation of the Field. A Field's String
+ * representation is "&lt;modifiers&gt; &lt;type&gt;
+ * &lt;class&gt;.&lt;fieldname&gt;".<br> Example:
+ * <code>public transient boolean gnu.parse.Parser.parseComplete</code>
+ *
+ * @return the String representation of the Field
+ */
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer();
+ Modifier.toString(getModifiers(), sb).append(' ');
+ sb.append(getType().getName()).append(' ');
+ sb.append(getDeclaringClass().getName()).append('.');
+ sb.append(getName());
+ return sb.toString();
+ }
+
+ /**
+ * Get the value of this Field. If it is primitive, it will be wrapped
+ * in the appropriate wrapper type (boolean = java.lang.Boolean).<p>
+ *
+ * If the field is static, <code>o</code> will be ignored. Otherwise, if
+ * <code>o</code> is null, you get a <code>NullPointerException</code>,
+ * and if it is incompatible with the declaring class of the field, you
+ * get an <code>IllegalArgumentException</code>.<p>
+ *
+ * Next, if this Field enforces access control, your runtime context is
+ * evaluated, and you may have an <code>IllegalAccessException</code> if
+ * you could not access this field in similar compiled code. If the field
+ * is static, and its class is uninitialized, you trigger class
+ * initialization, which may end in a
+ * <code>ExceptionInInitializerError</code>.<p>
+ *
+ * Finally, the field is accessed, and primitives are wrapped (but not
+ * necessarily in new objects). This method accesses the field of the
+ * declaring class, even if the instance passed in belongs to a subclass
+ * which declares another field to hide this one.
+ *
+ * @param o the object to get the value of this Field from
+ * @return the value of the Field
+ * @throws IllegalAccessException if you could not normally access this field
+ * (i.e. it is not public)
+ * @throws IllegalArgumentException if <code>o</code> is not an instance of
+ * the class or interface declaring this field
+ * @throws NullPointerException if <code>o</code> is null and this field
+ * requires an instance
+ * @throws ExceptionInInitializerError if accessing a static field triggered
+ * class initialization, which then failed
+ * @see #getBoolean(Object)
+ * @see #getByte(Object)
+ * @see #getChar(Object)
+ * @see #getShort(Object)
+ * @see #getInt(Object)
+ * @see #getLong(Object)
+ * @see #getFloat(Object)
+ * @see #getDouble(Object)
+ */
+ public Object get(Object o)
+ throws IllegalAccessException
+ {
+ return GetValue(fieldCookie, o);
+ }
+ private static native Object GetValue(Object fieldCookie, Object o);
+
+ /**
+ * Get the value of this boolean Field. If the field is static,
+ * <code>o</code> will be ignored.
+ *
+ * @param o the object to get the value of this Field from
+ * @return the value of the Field
+ * @throws IllegalAccessException if you could not normally access this field
+ * (i.e. it is not public)
+ * @throws IllegalArgumentException if this is not a boolean field of
+ * <code>o</code>, or if <code>o</code> is not an instance of the
+ * declaring class of this field
+ * @throws NullPointerException if <code>o</code> is null and this field
+ * requires an instance
+ * @throws ExceptionInInitializerError if accessing a static field triggered
+ * class initialization, which then failed
+ * @see #get(Object)
+ */
+ public boolean getBoolean(Object o)
+ throws IllegalAccessException
+ {
+ return ((Boolean)get(o)).booleanValue();
+ }
+
+ /**
+ * Get the value of this byte Field. If the field is static,
+ * <code>o</code> will be ignored.
+ *
+ * @param o the object to get the value of this Field from
+ * @return the value of the Field
+ * @throws IllegalAccessException if you could not normally access this field
+ * (i.e. it is not public)
+ * @throws IllegalArgumentException if this is not a byte field of
+ * <code>o</code>, or if <code>o</code> is not an instance of the
+ * declaring class of this field
+ * @throws NullPointerException if <code>o</code> is null and this field
+ * requires an instance
+ * @throws ExceptionInInitializerError if accessing a static field triggered
+ * class initialization, which then failed
+ * @see #get(Object)
+ */
+ public byte getByte(Object o)
+ throws IllegalAccessException
+ {
+ return ((Byte)get(o)).byteValue();
+ }
+
+ /**
+ * Get the value of this Field as a char. If the field is static,
+ * <code>o</code> will be ignored.
+ *
+ * @throws IllegalAccessException if you could not normally access this field
+ * (i.e. it is not public)
+ * @throws IllegalArgumentException if this is not a char field of
+ * <code>o</code>, or if <code>o</code> is not an instance
+ * of the declaring class of this field
+ * @throws NullPointerException if <code>o</code> is null and this field
+ * requires an instance
+ * @throws ExceptionInInitializerError if accessing a static field triggered
+ * class initialization, which then failed
+ * @see #get(Object)
+ */
+ public char getChar(Object o)
+ throws IllegalAccessException
+ {
+ return ((Character)get(o)).charValue();
+ }
+
+ /**
+ * Get the value of this Field as a short. If the field is static,
+ * <code>o</code> will be ignored.
+ *
+ * @param o the object to get the value of this Field from
+ * @return the value of the Field
+ * @throws IllegalAccessException if you could not normally access this field
+ * (i.e. it is not public)
+ * @throws IllegalArgumentException if this is not a byte or short
+ * field of <code>o</code>, or if <code>o</code> is not an instance
+ * of the declaring class of this field
+ * @throws NullPointerException if <code>o</code> is null and this field
+ * requires an instance
+ * @throws ExceptionInInitializerError if accessing a static field triggered
+ * class initialization, which then failed
+ * @see #get(Object)
+ */
+ public short getShort(Object o)
+ throws IllegalAccessException
+ {
+ return ((Short)get(o)).shortValue();
+ }
+
+ /**
+ * Get the value of this Field as an int. If the field is static,
+ * <code>o</code> will be ignored.
+ *
+ * @param o the object to get the value of this Field from
+ * @return the value of the Field
+ * @throws IllegalAccessException if you could not normally access this field
+ * (i.e. it is not public)
+ * @throws IllegalArgumentException if this is not a byte, short, char, or
+ * int field of <code>o</code>, or if <code>o</code> is not an
+ * instance of the declaring class of this field
+ * @throws NullPointerException if <code>o</code> is null and this field
+ * requires an instance
+ * @throws ExceptionInInitializerError if accessing a static field triggered
+ * class initialization, which then failed
+ * @see #get(Object)
+ */
+ public int getInt(Object o)
+ throws IllegalAccessException
+ {
+ return ((Integer)get(o)).intValue();
+ }
+
+ /**
+ * Get the value of this Field as a long. If the field is static,
+ * <code>o</code> will be ignored.
+ *
+ * @param o the object to get the value of this Field from
+ * @return the value of the Field
+ * @throws IllegalAccessException if you could not normally access this field
+ * (i.e. it is not public)
+ * @throws IllegalArgumentException if this is not a byte, short, char, int,
+ * or long field of <code>o</code>, or if <code>o</code> is not an
+ * instance of the declaring class of this field
+ * @throws NullPointerException if <code>o</code> is null and this field
+ * requires an instance
+ * @throws ExceptionInInitializerError if accessing a static field triggered
+ * class initialization, which then failed
+ * @see #get(Object)
+ */
+ public long getLong(Object o)
+ throws IllegalAccessException
+ {
+ return ((Long)get(o)).longValue();
+ }
+
+ /**
+ * Get the value of this Field as a float. If the field is static,
+ * <code>o</code> will be ignored.
+ *
+ * @param o the object to get the value of this Field from
+ * @return the value of the Field
+ * @throws IllegalAccessException if you could not normally access this field
+ * (i.e. it is not public)
+ * @throws IllegalArgumentException if this is not a byte, short, char, int,
+ * long, or float field of <code>o</code>, or if <code>o</code> is
+ * not an instance of the declaring class of this field
+ * @throws NullPointerException if <code>o</code> is null and this field
+ * requires an instance
+ * @throws ExceptionInInitializerError if accessing a static field triggered
+ * class initialization, which then failed
+ * @see #get(Object)
+ */
+ public float getFloat(Object o)
+ throws IllegalAccessException
+ {
+ return ((Float)get(o)).floatValue();
+ }
+
+ /**
+ * Get the value of this Field as a double. If the field is static,
+ * <code>o</code> will be ignored.
+ *
+ * @param o the object to get the value of this Field from
+ * @return the value of the Field
+ * @throws IllegalAccessException if you could not normally access this field
+ * (i.e. it is not public)
+ * @throws IllegalArgumentException if this is not a byte, short, char, int,
+ * long, float, or double field of <code>o</code>, or if
+ * <code>o</code> is not an instance of the declaring class of this
+ * field
+ * @throws NullPointerException if <code>o</code> is null and this field
+ * requires an instance
+ * @throws ExceptionInInitializerError if accessing a static field triggered
+ * class initialization, which then failed
+ * @see #get(Object)
+ */
+ public double getDouble(Object o)
+ throws IllegalAccessException
+ {
+ return ((Double)get(o)).doubleValue();
+ }
+
+ /**
+ * Set the value of this Field. If it is a primitive field, the value
+ * will be unwrapped from the passed object (boolean = java.lang.Boolean).<p>
+ *
+ * If the field is static, <code>o</code> will be ignored. Otherwise, if
+ * <code>o</code> is null, you get a <code>NullPointerException</code>,
+ * and if it is incompatible with the declaring class of the field, you
+ * get an <code>IllegalArgumentException</code>.<p>
+ *
+ * Next, if this Field enforces access control, your runtime context is
+ * evaluated, and you may have an <code>IllegalAccessException</code> if
+ * you could not access this field in similar compiled code. This also
+ * occurs whether or not there is access control if the field is final.
+ * If the field is primitive, and unwrapping your argument fails, you will
+ * get an <code>IllegalArgumentException</code>; likewise, this error
+ * happens if <code>value</code> cannot be cast to the correct object type.
+ * If the field is static, and its class is uninitialized, you trigger class
+ * initialization, which may end in a
+ * <code>ExceptionInInitializerError</code>.<p>
+ *
+ * Finally, the field is set with the widened value. This method accesses
+ * the field of the declaring class, even if the instance passed in belongs
+ * to a subclass which declares another field to hide this one.
+ *
+ * @param o the object to set this Field on
+ * @param value the value to set this Field to
+ * @throws IllegalAccessException if you could not normally access this field
+ * (i.e. it is not public)
+ * @throws IllegalArgumentException if <code>value</code> cannot be
+ * converted by a widening conversion to the underlying type of
+ * the Field, or if <code>o</code> is not an instance of the class
+ * declaring this field
+ * @throws NullPointerException if <code>o</code> is null and this field
+ * requires an instance
+ * @throws ExceptionInInitializerError if accessing a static field triggered
+ * class initialization, which then failed
+ * @see #setBoolean(Object, boolean)
+ * @see #setByte(Object, byte)
+ * @see #setChar(Object, char)
+ * @see #setShort(Object, short)
+ * @see #setInt(Object, int)
+ * @see #setLong(Object, long)
+ * @see #setFloat(Object, float)
+ * @see #setDouble(Object, double)
+ */
+ public void set(Object o, Object value)
+ throws IllegalAccessException
+ {
+ SetValue(fieldCookie, o, value);
+ }
+ private static native void SetValue(Object fieldCookie, Object o, Object value);
+
+ /**
+ * Set this boolean Field. If the field is static, <code>o</code> will be
+ * ignored.
+ *
+ * @param o the object to set this Field on
+ * @param value the value to set this Field to
+ * @throws IllegalAccessException if you could not normally access this field
+ * (i.e. it is not public)
+ * @throws IllegalArgumentException if this is not a boolean field, or if
+ * <code>o</code> is not an instance of the class declaring this
+ * field
+ * @throws NullPointerException if <code>o</code> is null and this field
+ * requires an instance
+ * @throws ExceptionInInitializerError if accessing a static field triggered
+ * class initialization, which then failed
+ * @see #set(Object, Object)
+ */
+ public void setBoolean(Object o, boolean value)
+ throws IllegalAccessException
+ {
+ set(o, new Boolean(value));
+ }
+
+ /**
+ * Set this byte Field. If the field is static, <code>o</code> will be
+ * ignored.
+ *
+ * @param o the object to set this Field on
+ * @param value the value to set this Field to
+ * @throws IllegalAccessException if you could not normally access this field
+ * (i.e. it is not public)
+ * @throws IllegalArgumentException if this is not a byte, short, int, long,
+ * float, or double field, or if <code>o</code> is not an instance
+ * of the class declaring this field
+ * @throws NullPointerException if <code>o</code> is null and this field
+ * requires an instance
+ * @throws ExceptionInInitializerError if accessing a static field triggered
+ * class initialization, which then failed
+ * @see #set(Object, Object)
+ */
+ public void setByte(Object o, byte value)
+ throws IllegalAccessException
+ {
+ set(o, new Byte(value));
+ }
+
+ /**
+ * Set this char Field. If the field is static, <code>o</code> will be
+ * ignored.
+ *
+ * @param o the object to set this Field on
+ * @param value the value to set this Field to
+ * @throws IllegalAccessException if you could not normally access this field
+ * (i.e. it is not public)
+ * @throws IllegalArgumentException if this is not a char, int, long,
+ * float, or double field, or if <code>o</code> is not an instance
+ * of the class declaring this field
+ * @throws NullPointerException if <code>o</code> is null and this field
+ * requires an instance
+ * @throws ExceptionInInitializerError if accessing a static field triggered
+ * class initialization, which then failed
+ * @see #set(Object, Object)
+ */
+ public void setChar(Object o, char value)
+ throws IllegalAccessException
+ {
+ set(o, new Character(value));
+ }
+
+ /**
+ * Set this short Field. If the field is static, <code>o</code> will be
+ * ignored.
+ *
+ * @param o the object to set this Field on
+ * @param value the value to set this Field to
+ * @throws IllegalAccessException if you could not normally access this field
+ * (i.e. it is not public)
+ * @throws IllegalArgumentException if this is not a short, int, long,
+ * float, or double field, or if <code>o</code> is not an instance
+ * of the class declaring this field
+ * @throws NullPointerException if <code>o</code> is null and this field
+ * requires an instance
+ * @throws ExceptionInInitializerError if accessing a static field triggered
+ * class initialization, which then failed
+ * @see #set(Object, Object)
+ */
+ public void setShort(Object o, short value)
+ throws IllegalAccessException
+ {
+ set(o, new Short(value));
+ }
+
+ /**
+ * Set this int Field. If the field is static, <code>o</code> will be
+ * ignored.
+ *
+ * @param o the object to set this Field on
+ * @param value the value to set this Field to
+ * @throws IllegalAccessException if you could not normally access this field
+ * (i.e. it is not public)
+ * @throws IllegalArgumentException if this is not an int, long, float, or
+ * double field, or if <code>o</code> is not an instance of the
+ * class declaring this field
+ * @throws NullPointerException if <code>o</code> is null and this field
+ * requires an instance
+ * @throws ExceptionInInitializerError if accessing a static field triggered
+ * class initialization, which then failed
+ * @see #set(Object, Object)
+ */
+ public void setInt(Object o, int value)
+ throws IllegalAccessException
+ {
+ set(o, new Integer(value));
+ }
+
+ /**
+ * Set this long Field. If the field is static, <code>o</code> will be
+ * ignored.
+ *
+ * @param o the object to set this Field on
+ * @param value the value to set this Field to
+ * @throws IllegalAccessException if you could not normally access this field
+ * (i.e. it is not public)
+ * @throws IllegalArgumentException if this is not a long, float, or double
+ * field, or if <code>o</code> is not an instance of the class
+ * declaring this field
+ * @throws NullPointerException if <code>o</code> is null and this field
+ * requires an instance
+ * @throws ExceptionInInitializerError if accessing a static field triggered
+ * class initialization, which then failed
+ * @see #set(Object, Object)
+ */
+ public void setLong(Object o, long value)
+ throws IllegalAccessException
+ {
+ set(o, new Long(value));
+ }
+
+ /**
+ * Set this float Field. If the field is static, <code>o</code> will be
+ * ignored.
+ *
+ * @param o the object to set this Field on
+ * @param value the value to set this Field to
+ * @throws IllegalAccessException if you could not normally access this field
+ * (i.e. it is not public)
+ * @throws IllegalArgumentException if this is not a float or long field, or
+ * if <code>o</code> is not an instance of the class declaring this
+ * field
+ * @throws NullPointerException if <code>o</code> is null and this field
+ * requires an instance
+ * @throws ExceptionInInitializerError if accessing a static field triggered
+ * class initialization, which then failed
+ * @see #set(Object, Object)
+ */
+ public void setFloat(Object o, float value)
+ throws IllegalAccessException
+ {
+ set(o, new Float(value));
+ }
+
+ /**
+ * Set this double Field. If the field is static, <code>o</code> will be
+ * ignored.
+ *
+ * @param o the object to set this Field on
+ * @param value the value to set this Field to
+ * @throws IllegalAccessException if you could not normally access this field
+ * (i.e. it is not public)
+ * @throws IllegalArgumentException if this is not a double field, or if
+ * <code>o</code> is not an instance of the class declaring this
+ * field
+ * @throws NullPointerException if <code>o</code> is null and this field
+ * requires an instance
+ * @throws ExceptionInInitializerError if accessing a static field triggered
+ * class initialization, which then failed
+ * @see #set(Object, Object)
+ */
+ public void setDouble(Object o, double value)
+ throws IllegalAccessException
+ {
+ set(o, new Double(value));
+ }
+}
diff --git a/classpath/java/lang/reflect/Method.java b/classpath/java/lang/reflect/Method.java
new file mode 100644
index 00000000..4bf682a8
--- /dev/null
+++ b/classpath/java/lang/reflect/Method.java
@@ -0,0 +1,376 @@
+/* java.lang.reflect.Method - reflection of Java methods
+ Copyright (C) 1998, 2001, 2002 Free Software Foundation, Inc.
+
+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.reflect;
+
+import system.*;
+import system.reflection.*;
+
+/**
+ * The Method class represents a member method of a class. It also allows
+ * dynamic invocation, via reflection. This works for both static and
+ * instance methods. Invocation on Method objects knows how to do
+ * widening conversions, but throws {@link IllegalArgumentException} if
+ * a narrowing conversion would be necessary. You can query for information
+ * on this Method regardless of location, but invocation access may be limited
+ * by Java language access controls. If you can't do it in the compiler, you
+ * can't normally do it here either.<p>
+ *
+ * <B>Note:</B> This class returns and accepts types as Classes, even
+ * primitive types; there are Class types defined that represent each
+ * different primitive type. They are <code>java.lang.Boolean.TYPE,
+ * java.lang.Byte.TYPE,</code>, also available as <code>boolean.class,
+ * byte.class</code>, etc. These are not to be confused with the
+ * classes <code>java.lang.Boolean, java.lang.Byte</code>, etc., which are
+ * real classes.<p>
+ *
+ * Also note that this is not a serializable class. It is entirely feasible
+ * to make it serializable using the Externalizable interface, but this is
+ * on Sun, not me.
+ *
+ * @author John Keiser
+ * @author Eric Blake <ebb9@email.byu.edu>
+ * @see Member
+ * @see Class
+ * @see java.lang.Class#getMethod(String,Object[])
+ * @see java.lang.Class#getDeclaredMethod(String,Object[])
+ * @see java.lang.Class#getMethods()
+ * @see java.lang.Class#getDeclaredMethods()
+ * @since 1.1
+ * @status updated to 1.4
+ */
+public final class Method extends AccessibleObject implements Member
+{
+ private Class declaringClass;
+ private Object methodCookie;
+
+ /**
+ * This class is uninstantiable.
+ */
+ public Method(Class declaringClass, Object methodCookie)
+ {
+ this.declaringClass = declaringClass;
+ this.methodCookie = methodCookie;
+ }
+
+ /**
+ * Gets the class that declared this method, or the class where this method
+ * is a non-inherited member.
+ * @return the class that declared this member
+ */
+ public Class getDeclaringClass()
+ {
+ return declaringClass;
+ }
+
+ /**
+ * Gets the name of this method.
+ * @return the name of this method
+ */
+ public String getName()
+ {
+ return GetName(methodCookie);
+ }
+ static native String GetName(Object methodCookie);
+
+ /**
+ * Gets the modifiers this method uses. Use the <code>Modifier</code>
+ * class to interpret the values. A method can only have a subset of the
+ * following modifiers: public, private, protected, abstract, static,
+ * final, synchronized, native, and strictfp.
+ *
+ * @return an integer representing the modifiers to this Member
+ * @see Modifier
+ */
+ public int getModifiers()
+ {
+ return GetModifiers(methodCookie);
+ }
+ static native int GetModifiers(Object methodCookie);
+
+ /**
+ * Gets the return type of this method.
+ * @return the type of this method
+ */
+ public Class getReturnType()
+ {
+ return (Class)GetReturnType(methodCookie);
+ }
+ static native Object GetReturnType(Object methodCookie);
+
+ /**
+ * Get the parameter list for this method, in declaration order. If the
+ * method takes no parameters, returns a 0-length array (not null).
+ *
+ * @return a list of the types of the method's parameters
+ */
+ public Class[] getParameterTypes()
+ {
+ Object[] params = GetParameterTypes(methodCookie);
+ Class[] paramsClass = new Class[params.length];
+ System.arraycopy(params, 0, paramsClass, 0, params.length);
+ return paramsClass;
+ }
+ static native Object[] GetParameterTypes(Object methodCookie);
+
+ /**
+ * Get the exception types this method says it throws, in no particular
+ * order. If the method has no throws clause, returns a 0-length array
+ * (not null).
+ *
+ * @return a list of the types in the method's throws clause
+ */
+ public Class[] getExceptionTypes()
+ {
+ Object[] ex = GetExceptionTypes(methodCookie);
+ Class[] exc = new Class[ex.length];
+ System.arraycopy(ex, 0, exc, 0, ex.length);
+ return exc;
+ }
+ static native Object[] GetExceptionTypes(Object methodCookie);
+
+ /**
+ * Compare two objects to see if they are semantically equivalent.
+ * Two Methods are semantically equivalent if they have the same declaring
+ * class, name, and parameter list. This ignores different exception
+ * clauses or return types.
+ *
+ * @param o the object to compare to
+ * @return <code>true</code> if they are equal; <code>false</code> if not
+ */
+ public boolean equals(Object o)
+ {
+ // Implementation note:
+ // The following is a correct but possibly slow implementation.
+ //
+ // This class has a private field 'slot' that could be used by
+ // the VM implementation to "link" a particular method to a Class.
+ // In that case equals could be simply implemented as:
+ //
+ // if (o instanceof Method)
+ // {
+ // Method m = (Method)o;
+ // return m.declaringClass == this.declaringClass
+ // && m.slot == this.slot;
+ // }
+ // return false;
+ //
+ // If a VM uses the Method class as their native/internal representation
+ // then just using the following would be optimal:
+ //
+ // return return this == o;
+ //
+
+ if (!(o instanceof Method))
+ return false;
+
+ Method m = (Method)o;
+ if(!getName().equals(m.getName()))
+ return false;
+
+ if(declaringClass != m.declaringClass)
+ return false;
+
+ Class[] params1 = getParameterTypes();
+ Class[] params2 = m.getParameterTypes();
+ if(params1.length != params2.length)
+ return false;
+
+ for(int i = 0; i < params1.length; i++)
+ if(params1[i] != params2[i])
+ return false;
+
+ return true;
+ }
+
+ /**
+ * Get the hash code for the Method. The Method hash code is the hash code
+ * of its name XOR'd with the hash code of its class name.
+ *
+ * @return the hash code for the object
+ */
+ public int hashCode()
+ {
+ return getDeclaringClass().getName().hashCode() ^ getName().hashCode();
+ }
+
+ /**
+ * Get a String representation of the Method. A Method's String
+ * representation is "&lt;modifiers&gt; &lt;returntype&gt;
+ * &lt;methodname&gt;(&lt;paramtypes&gt;) throws &lt;exceptions&gt;", where
+ * everything after ')' is omitted if there are no exceptions.<br> Example:
+ * <code>public static int run(java.lang.Runnable,int)</code>
+ *
+ * @return the String representation of the Method
+ */
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer();
+ Modifier.toString(getModifiers(), sb).append(' ');
+ sb.append(getReturnType().getName()).append(' ');
+ sb.append(getDeclaringClass().getName()).append('.');
+ sb.append(getName()).append('(');
+ Class[] c = getParameterTypes();
+ if (c.length > 0)
+ {
+ sb.append(c[0].getName());
+ for (int i = 1; i < c.length; i++)
+ sb.append(',').append(c[i].getName());
+ }
+ sb.append(')');
+ c = getExceptionTypes();
+ if (c.length > 0)
+ {
+ sb.append(" throws ").append(c[0].getName());
+ for (int i = 1; i < c.length; i++)
+ sb.append(',').append(c[i].getName());
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Invoke the method. Arguments are automatically unwrapped and widened,
+ * and the result is automatically wrapped, if needed.<p>
+ *
+ * If the method is static, <code>o</code> will be ignored. Otherwise,
+ * the method uses dynamic lookup as described in JLS 15.12.4.4. You cannot
+ * mimic the behavior of nonvirtual lookup (as in super.foo()). This means
+ * you will get a <code>NullPointerException</code> if <code>o</code> is
+ * null, and an <code>IllegalArgumentException</code> if it is incompatible
+ * with the declaring class of the method. If the method takes 0 arguments,
+ * you may use null or a 0-length array for <code>args</code>.<p>
+ *
+ * Next, if this Method enforces access control, your runtime context is
+ * evaluated, and you may have an <code>IllegalAccessException</code> if
+ * you could not acces this method in similar compiled code. If the method
+ * is static, and its class is uninitialized, you trigger class
+ * initialization, which may end in a
+ * <code>ExceptionInInitializerError</code>.<p>
+ *
+ * Finally, the method is invoked. If it completes normally, the return value
+ * will be null for a void method, a wrapped object for a primitive return
+ * method, or the actual return of an Object method. If it completes
+ * abruptly, the exception is wrapped in an
+ * <code>InvocationTargetException</code>.
+ *
+ * @param o the object to invoke the method on
+ * @param args the arguments to the method
+ * @return the return value of the method, wrapped in the appropriate
+ * wrapper if it is primitive
+ * @throws IllegalAccessException if the method could not normally be called
+ * by the Java code (i.e. it is not public)
+ * @throws IllegalArgumentException if the number of arguments is incorrect;
+ * if the arguments types are wrong even with a widening conversion;
+ * or if <code>o</code> is not an instance of the class or interface
+ * declaring this method
+ * @throws InvocationTargetException if the method throws an exception
+ * @throws NullPointerException if <code>o</code> is null and this field
+ * requires an instance
+ * @throws ExceptionInInitializerError if accessing a static method triggered
+ * class initialization, which then failed
+ */
+ public Object invoke(Object o, Object[] args)
+ throws IllegalAccessException, InvocationTargetException
+ {
+ // TODO
+ return Invoke(methodCookie, o, args);
+ /*
+ try
+ {
+ if(false) throw new MemberAccessException();
+ if(false) throw new ArgumentException();
+ if(false) throw new TargetParameterCountException();
+ if(false) throw new TargetInvocationException(null);
+ ParameterInfo[] params = method.GetParameters();
+ for(int i = 0; i < params.length; i++)
+ {
+ Type type = params[i].get_ParameterType();
+ if(type.get_IsPrimitive())
+ {
+ if(type == BoxHelper.INT)
+ {
+ args[i] = BoxHelper.boxInteger(((Integer)args[i]).intValue());
+ }
+ else if(type == BoxHelper.BOOLEAN)
+ {
+ args[i] = BoxHelper.boxBoolean(((java.lang.Boolean)args[i]).booleanValue());
+ }
+ else
+ {
+ throw new InternalError("method invoke arg boxing not implemented for " + type.get_FullName());
+ }
+ }
+ }
+ // TODO wrappers need to be unwrapped (e.g. java.lang.Integer -> boxed System.Int32)
+ Object retval = method.Invoke(o, args);
+ Type rettype = method.get_ReturnType();
+ if(rettype.get_IsPrimitive())
+ {
+ if(rettype == BoxHelper.INT)
+ {
+ retval = new Integer(BoxHelper.unboxInteger(retval));
+ }
+ else
+ {
+ throw new InternalError("method invoke retval unboxing not implemented for " + rettype.get_FullName());
+ }
+ }
+ return retval;
+ }
+ catch(MemberAccessException x1)
+ {
+ throw new IllegalAccessException(x1.get_Message());
+ }
+ catch(ArgumentException x2)
+ {
+ throw new IllegalArgumentException();
+ }
+ catch(TargetParameterCountException x3)
+ {
+ throw new IllegalArgumentException();
+ }
+ catch(TargetInvocationException x4)
+ {
+ throw new InvocationTargetException(mapException(x4.get_InnerException()));
+ }
+ */
+ }
+ static native Object Invoke(Object methodCookie, Object o, Object[] args);
+
+ static native Throwable mapException(Throwable x);
+}
diff --git a/classpath/java/net/PlainDatagramSocketImpl.java b/classpath/java/net/PlainDatagramSocketImpl.java
new file mode 100644
index 00000000..1cad3cd7
--- /dev/null
+++ b/classpath/java/net/PlainDatagramSocketImpl.java
@@ -0,0 +1,312 @@
+/* PlainDatagramSocketImpl.java -- Default DatagramSocket implementation
+ Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc.
+
+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.net;
+
+import java.io.IOException;
+import system.net.*;
+import system.net.sockets.*;
+
+/**
+* This is the default socket implementation for datagram sockets.
+* It makes native calls to C routines that implement BSD style
+* SOCK_DGRAM sockets in the AF_INET family.
+*
+* @version 0.1
+*
+* @author Aaron M. Renn (arenn@urbanophile.com)
+*/
+public class PlainDatagramSocketImpl extends DatagramSocketImpl
+{
+ /*
+ * Static Variables
+ */
+
+ /**
+ * Option id for the IP_TTL (time to live) value.
+ */
+ private static final int IP_TTL = 0x1E61; // 7777
+
+
+ /*
+ * Instance Variables
+ */
+
+ /**
+ * This is the actual underlying socket
+ */
+ private UdpClient socket;
+
+ /*************************************************************************/
+
+ /*
+ * Constructors
+ */
+
+ /**
+ * Default do nothing constructor
+ */
+ public PlainDatagramSocketImpl()
+ {
+ }
+
+ /*************************************************************************/
+
+ /*
+ * Instance Methods
+ */
+
+ /**
+ * Creates a new datagram socket
+ *
+ * @exception SocketException If an error occurs
+ */
+ protected void create() throws SocketException
+ {
+ }
+
+ /*************************************************************************/
+
+ /**
+ * Closes the socket
+ */
+ protected void close()
+ {
+ socket.Close();
+ }
+
+ /*************************************************************************/
+
+ /**
+ * Binds this socket to a particular port and interface
+ *
+ * @param port The port to bind to
+ * @param addr The address to bind to
+ *
+ * @exception SocketException If an error occurs
+ */
+ protected void bind(int port, InetAddress addr) throws SocketException
+ {
+ // TODO error handling
+ socket = new UdpClient(new IPEndPoint(PlainSocketImpl.getAddressFromInetAddress(addr), port));
+ }
+
+ /*************************************************************************/
+
+ /**
+ * Sends a packet of data to a remote host
+ *
+ * @param packet The packet to send
+ *
+ * @exception IOException If an error occurs
+ */
+ protected void send(DatagramPacket packet) throws IOException
+ {
+ // TODO error handling
+ int len = packet.getLength();
+ if(socket.Send(packet.getData(), len, new IPEndPoint(PlainSocketImpl.getAddressFromInetAddress(packet.getAddress()), packet.getPort())) != len)
+ {
+ // TODO
+ throw new IOException();
+ }
+ }
+
+ /*************************************************************************/
+
+ /**
+ * What does this method really do?
+ */
+ protected int peek(InetAddress addr) throws IOException
+ {
+ throw new IOException("Not Implemented Yet");
+ }
+
+ /*************************************************************************/
+
+ /**
+ * Receives a UDP packet from the network
+ *
+ * @param packet The packet to fill in with the data received
+ *
+ * @exception IOException IOException If an error occurs
+ */
+ protected native void receive(DatagramPacket packet) throws IOException;
+
+ /*************************************************************************/
+
+ /**
+ * Joins a multicast group
+ *
+ * @param addr The group to join
+ *
+ * @exception IOException If an error occurs
+ */
+ protected void join(InetAddress addr) throws IOException
+ {
+ System.out.println("PlainDatagramSocketImpl.join not implemented");
+ throw new IOException("join not implemented");
+ }
+
+ /*************************************************************************/
+
+ /**
+ * Leaves a multicast group
+ *
+ * @param addr The group to leave
+ *
+ * @exception IOException If an error occurs
+ */
+ protected void leave(InetAddress addr) throws IOException
+ {
+ System.out.println("PlainDatagramSocketImpl.leave not implemented");
+ throw new IOException("leave not implemented");
+ }
+
+ /*************************************************************************/
+
+ /**
+ * Gets the Time to Live value for the socket
+ *
+ * @return The TTL value
+ *
+ * @exception IOException If an error occurs
+ */
+ protected byte getTTL() throws IOException
+ {
+ Object obj = getOption(IP_TTL);
+
+ if (!(obj instanceof Integer))
+ throw new IOException("Internal Error");
+
+ return(((Integer)obj).byteValue());
+ }
+
+ /*************************************************************************/
+
+ /**
+ * Sets the Time to Live value for the socket
+ *
+ * @param ttl The new TTL value
+ *
+ * @exception IOException If an error occurs
+ */
+ protected void setTTL(byte ttl) throws IOException
+ {
+ setOption(IP_TTL, new Integer(ttl));
+ }
+
+ /*************************************************************************/
+
+ /**
+ * Gets the Time to Live value for the socket
+ *
+ * @return The TTL value
+ *
+ * @exception IOException If an error occurs
+ */
+ protected int getTimeToLive() throws IOException
+ {
+ Object obj = getOption(IP_TTL);
+
+ if (!(obj instanceof Integer))
+ throw new IOException("Internal Error");
+
+ return(((Integer)obj).intValue());
+ }
+
+ /*************************************************************************/
+
+ /**
+ * Sets the Time to Live value for the socket
+ *
+ * @param ttl The new TTL value
+ *
+ * @exception IOException If an error occurs
+ */
+ protected void setTimeToLive(int ttl) throws IOException
+ {
+ setOption(IP_TTL, new Integer(ttl));
+ }
+
+ /*************************************************************************/
+
+ /**
+ * Retrieves the value of an option on the socket
+ *
+ * @param option_id The identifier of the option to retrieve
+ *
+ * @return The value of the option
+ *
+ * @exception SocketException If an error occurs
+ */
+ public Object getOption(int option_id) throws SocketException
+ {
+ // TODO
+ return null;
+ }
+
+ /*************************************************************************/
+
+ /**
+ * Sets the value of an option on the socket
+ *
+ * @param option_id The identifier of the option to set
+ * @param val The value of the option to set
+ *
+ * @exception SocketException If an error occurs
+ */
+ public void setOption(int option_id, Object val) throws SocketException
+ {
+ // TODO
+ }
+
+ public int peekData(DatagramPacket packet)
+ {
+ throw new InternalError ("PlainDatagramSocketImpl::peekData is not implemented");
+ }
+
+ public void joinGroup(SocketAddress address, NetworkInterface netIf)
+ {
+ throw new InternalError ("PlainDatagramSocketImpl::joinGroup is not implemented");
+ }
+
+ public void leaveGroup(SocketAddress address, NetworkInterface netIf)
+ {
+ throw new InternalError ("PlainDatagramSocketImpl::leaveGroup is not implemented");
+ }
+} // class PlainDatagramSocketImpl
diff --git a/classpath/java/net/PlainSocketImpl.java b/classpath/java/net/PlainSocketImpl.java
new file mode 100644
index 00000000..6262c63b
--- /dev/null
+++ b/classpath/java/net/PlainSocketImpl.java
@@ -0,0 +1,327 @@
+/* PlainSocketImpl.java -- Default socket implementation
+ Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+
+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.net;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+import system.net.*;
+import system.net.sockets.*;
+
+/**
+ * Unless the application installs its own SocketImplFactory, this is the
+ * default socket implemetation that will be used. It simply uses a
+ * combination of Java and native routines to implement standard BSD
+ * style sockets of family AF_INET and types SOCK_STREAM and SOCK_DGRAM
+ *
+ * @version 0.1
+ *
+ * @author Aaron M. Renn (arenn@urbanophile.com)
+ */
+class PlainSocketImpl extends SocketImpl
+{
+ /**
+ * This is the native file descriptor for this socket
+ */
+ private system.net.sockets.Socket socket;
+
+
+ /**
+ * Default do nothing constructor
+ */
+ public PlainSocketImpl()
+ {
+ }
+
+ /**
+ * Accepts a new connection on this socket and returns in in the
+ * passed in SocketImpl.
+ *
+ * @param impl The SocketImpl object to accept this connection.
+ */
+ protected void accept(SocketImpl impl) throws IOException
+ {
+ // TODO catch .NET exceptions
+ system.net.sockets.Socket accept = socket.Accept();
+ ((PlainSocketImpl)impl).socket = accept;
+ IPEndPoint remoteEndPoint = ((IPEndPoint)accept.get_RemoteEndPoint());
+ long remoteIP = remoteEndPoint.get_Address().get_Address();
+ String remote = (remoteIP & 0xff) + "." + ((remoteIP >> 8) & 0xff) + "." + ((remoteIP >> 16) & 0xff) + "." + ((remoteIP >> 24) & 0xff);
+ impl.address = InetAddress.getByName(remote);
+ impl.port = remoteEndPoint.get_Port();
+ impl.localport = ((IPEndPoint)accept.get_LocalEndPoint()).get_Port();
+ }
+
+ /**
+ * Returns the number of bytes that the caller can read from this socket
+ * without blocking.
+ *
+ * @return The number of readable bytes before blocking
+ *
+ * @exception IOException If an error occurs
+ */
+ protected int available() throws IOException
+ {
+ // TODO catch .NET exceptions
+ return socket.get_Available();
+ }
+
+ /**
+ * Binds to the specified port on the specified addr. Note that this addr
+ * must represent a local IP address. **** How bind to INADDR_ANY? ****
+ *
+ * @param addr The address to bind to
+ * @param port The port number to bind to
+ *
+ * @exception IOException If an error occurs
+ */
+ protected void bind(InetAddress addr, int port) throws IOException
+ {
+ // TODO catch .NET exceptions
+ socket.Bind(new IPEndPoint(getAddressFromInetAddress(addr), port));
+ }
+
+ static int getAddressFromInetAddress(InetAddress addr)
+ {
+ byte[] b = addr.getAddress();
+ return ((b[3] & 0xff) << 24) + ((b[2] & 0xff) << 16) + ((b[1] & 0xff) << 8) + (b[0] & 0xff);
+ }
+
+ /**
+ * Closes the socket. This will cause any InputStream or OutputStream
+ * objects for this Socket to be closed as well.
+ * <p>
+ * Note that if the SO_LINGER option is set on this socket, then the
+ * operation could block.
+ *
+ * @exception IOException If an error occurs
+ */
+ protected void close() throws IOException
+ {
+ // TODO catch .NET exceptions
+ socket.Close();
+ }
+
+ /**
+ * Connects to the remote address and port specified as arguments.
+ *
+ * @param addr The remote address to connect to
+ * @param port The remote port to connect to
+ *
+ * @exception IOException If an error occurs
+ */
+ protected void connect(InetAddress addr, int port) throws IOException
+ {
+ // TODO error handling
+ socket.Connect(new IPEndPoint(getAddressFromInetAddress(addr), port));
+ }
+
+ /**
+ * Connects to the remote hostname and port specified as arguments.
+ *
+ * @param hostname The remote hostname to connect to
+ * @param port The remote port to connect to
+ *
+ * @exception IOException If an error occurs
+ */
+ protected void connect(String hostname, int port) throws IOException
+ {
+ // TODO error handling
+ InetAddress addr = InetAddress.getByName(hostname);
+ connect(addr, port);
+ }
+
+ /**
+ * Creates a new socket that is not bound to any local address/port and
+ * is not connected to any remote address/port. This will be created as
+ * a stream socket if the stream parameter is true, or a datagram socket
+ * if the stream parameter is false.
+ *
+ * @param stream true for a stream socket, false for a datagram socket
+ */
+ protected void create(boolean stream) throws IOException
+ {
+ // TODO error handling
+ if(!stream)
+ {
+ // TODO
+ System.out.println("NOTE: PlainSocketImpl.create(false) not implemented");
+ throw new IOException("PlainSocketImpl.create(false) not implemented");
+ }
+ socket = new system.net.sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+ }
+
+ /**
+ * Starts listening for connections on a socket. The queuelen parameter
+ * is how many pending connections will queue up waiting to be serviced
+ * before being accept'ed. If the queue of pending requests exceeds this
+ * number, additional connections will be refused.
+ *
+ * @param queuelen The length of the pending connection queue
+ *
+ * @exception IOException If an error occurs
+ */
+ protected void listen(int queuelen) throws IOException
+ {
+ // TODO error handling
+ socket.Listen(queuelen);
+ localport = ((IPEndPoint)socket.get_LocalEndPoint()).get_Port();
+ }
+
+ /**
+ * Internal method used by SocketInputStream for reading data from
+ * the connection. Reads up to len bytes of data into the buffer
+ * buf starting at offset bytes into the buffer.
+ *
+ * @return The actual number of bytes read or -1 if end of stream.
+ *
+ * @exception IOException If an error occurs
+ */
+ protected int read(byte[] buf, int offset, int len) throws IOException
+ {
+ // TODO error handling
+ return socket.Receive(buf, offset, len, SocketFlags.None);
+ }
+
+ /**
+ * Internal method used by SocketOuputStream for writing data to
+ * the connection. Writes up to len bytes of data from the buffer
+ * buf starting at offset bytes into the buffer.
+ *
+ * @exception IOException If an error occurs
+ */
+ protected void write(byte[] buf, int offset, int len) throws IOException
+ {
+ // TODO error handling
+ socket.Send(buf, offset, len, SocketFlags.None);
+ }
+
+ /**
+ * Sets the specified option on a socket to the passed in object. For
+ * options that take an integer argument, the passed in object is an
+ * Integer. The option_id parameter is one of the defined constants in
+ * this interface.
+ *
+ * @param option_id The identifier of the option
+ * @param val The value to set the option to
+ *
+ * @exception SocketException If an error occurs
+ */
+ public void setOption(int option_id, Object val) throws SocketException
+ {
+ switch(option_id)
+ {
+ case 0x1006:
+ // TODO set the timeout
+ return;
+ }
+ // TODO
+ System.out.println("setOption: " + option_id);
+ }
+
+ /**
+ * Returns the current setting of the specified option. The Object returned
+ * will be an Integer for options that have integer values. The option_id
+ * is one of the defined constants in this interface.
+ *
+ * @param option_id The option identifier
+ *
+ * @return The current value of the option
+ *
+ * @exception SocketException If an error occurs
+ */
+ public Object getOption(int option_id) throws SocketException
+ {
+ switch(option_id)
+ {
+ case 0x1006:
+ // TODO get the timeout from somewhere
+ return new Integer(0);
+ }
+ // TODO
+ System.out.println("getOption: " + option_id);
+ return null;
+ }
+
+ /**
+ * Returns an InputStream object for reading from this socket. This will
+ * be an instance of SocketInputStream.
+ *
+ * @return An InputStream
+ *
+ * @exception IOException If an error occurs
+ */
+ protected InputStream getInputStream() throws IOException
+ {
+ return new SocketInputStream(this);
+ }
+
+ /**
+ * Returns an OutputStream object for writing to this socket. This will
+ * be an instance of SocketOutputStream.
+ *
+ * @return An OutputStream
+ *
+ * @exception IOException If an error occurs
+ */
+ protected OutputStream getOutputStream() throws IOException
+ {
+ return new SocketOutputStream(this);
+ }
+
+ public void connect(SocketAddress address, int timeout)
+ {
+ throw new InternalError ("PlainSocketImpl::connect not implemented");
+ }
+
+ public void sendUrgentData(int data)
+ {
+ throw new InternalError ("PlainSocketImpl::sendUrgentData not implemented");
+ }
+
+ public void shutdownInput()
+ {
+ throw new InternalError ("PlainSocketImpl::shutdownInput not implemented");
+ }
+
+ public void shutdownOutput()
+ {
+ throw new InternalError ("PlainSocketImpl::shutdownOutput not implemented");
+ }
+} // class PlainSocketImpl
diff --git a/classpath/mscorlib.jar b/classpath/mscorlib.jar
new file mode 100644
index 00000000..d72b2d0d
--- /dev/null
+++ b/classpath/mscorlib.jar
Binary files differ
diff --git a/classpath/sun/misc/Ref.java b/classpath/sun/misc/Ref.java
new file mode 100644
index 00000000..1f2eafeb
--- /dev/null
+++ b/classpath/sun/misc/Ref.java
@@ -0,0 +1,66 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+
+package sun.misc;
+
+import system.WeakReference;
+
+public abstract class Ref
+{
+ private WeakReference weakRef = new WeakReference(null);
+
+ public Object get()
+ {
+ Object p = weakRef.get_Target();
+ if(p == null)
+ {
+ synchronized(this)
+ {
+ if((p = weakRef.get_Target()) == null)
+ {
+ p = reconstitute();
+ weakRef.set_Target(p);
+ }
+ }
+ }
+ return p;
+ }
+
+ public abstract Object reconstitute();
+
+ public void flush()
+ {
+ weakRef.set_Target(null);
+ }
+
+ public void setThing(Object thing)
+ {
+ weakRef.set_Target(thing);
+ }
+
+ public Object check()
+ {
+ return weakRef.get_Target();
+ }
+}
diff --git a/ikvm.build b/ikvm.build
new file mode 100644
index 00000000..fe36fad7
--- /dev/null
+++ b/ikvm.build
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<project name="ikvm" default="all">
+ <!--
+ NOTE because of the circular dependencies, we don't use NAnt dependencies,
+ but some predefined order, that hopefully makes sense.
+ Please note that, because of the circular dependencies, the BIN directory
+ needs to contain the IK.VM.NET.dll and classpath.dll binaries, before the project
+ can be built.
+ -->
+ <target name="all">
+ <nant buildfile="ikvmc/ikvmc.build" />
+ <nant buildfile="netexp/netexp.build" />
+ <nant buildfile="ik.vm.jni/ik.vm.jni.build" />
+ <nant buildfile="ik.vm.net/ik.vm.net.build" />
+ <nant buildfile="classpath/classpath.build" />
+ <nant buildfile="ikvm/ikvm.build" />
+ <nant buildfile="awt/awt.build" />
+ </target>
+</project>
diff --git a/ikvm.sln b/ikvm.sln
new file mode 100644
index 00000000..d9fb8eec
--- /dev/null
+++ b/ikvm.sln
@@ -0,0 +1,51 @@
+Microsoft Visual Studio Solution File, Format Version 7.00
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IK.VM.NET", "IK.VM.NET\IK.VM.NET.csproj", "{F5C7B588-0403-4AF2-A4DE-5697DE21BC2C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IK.VM.JNI", "IK.VM.JNI\IK.VM.JNI.vcproj", "{4D400F9D-68A1-4066-95F6-85AF0E58B710}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ikvm", "ikvm\ikvm.csproj", "{4FBAFF23-1E48-4977-8C50-30F87E70A8B5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "netexp", "netexp\netexp.csproj", "{D2A9434D-59E4-43E9-8D9C-332AA138CEAD}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ikvmc", "ikvmc\ikvmc.csproj", "{4CA3F3DF-D2B7-4FA2-874C-BFC4B04286A2}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "awt", "awt\awt.csproj", "{E00A0FA2-1FD7-4DD9-8C06-7202CE366102}"
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ ConfigName.0 = Debug
+ ConfigName.1 = Release
+ EndGlobalSection
+ GlobalSection(ProjectDependencies) = postSolution
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {F5C7B588-0403-4AF2-A4DE-5697DE21BC2C}.Debug.ActiveCfg = Debug|.NET
+ {F5C7B588-0403-4AF2-A4DE-5697DE21BC2C}.Debug.Build.0 = Debug|.NET
+ {F5C7B588-0403-4AF2-A4DE-5697DE21BC2C}.Release.ActiveCfg = Release|.NET
+ {F5C7B588-0403-4AF2-A4DE-5697DE21BC2C}.Release.Build.0 = Release|.NET
+ {4D400F9D-68A1-4066-95F6-85AF0E58B710}.Debug.ActiveCfg = Debug|Win32
+ {4D400F9D-68A1-4066-95F6-85AF0E58B710}.Debug.Build.0 = Debug|Win32
+ {4D400F9D-68A1-4066-95F6-85AF0E58B710}.Release.ActiveCfg = Release|Win32
+ {4D400F9D-68A1-4066-95F6-85AF0E58B710}.Release.Build.0 = Release|Win32
+ {4FBAFF23-1E48-4977-8C50-30F87E70A8B5}.Debug.ActiveCfg = Debug|.NET
+ {4FBAFF23-1E48-4977-8C50-30F87E70A8B5}.Debug.Build.0 = Debug|.NET
+ {4FBAFF23-1E48-4977-8C50-30F87E70A8B5}.Release.ActiveCfg = Release|.NET
+ {4FBAFF23-1E48-4977-8C50-30F87E70A8B5}.Release.Build.0 = Release|.NET
+ {D2A9434D-59E4-43E9-8D9C-332AA138CEAD}.Debug.ActiveCfg = Debug|.NET
+ {D2A9434D-59E4-43E9-8D9C-332AA138CEAD}.Debug.Build.0 = Debug|.NET
+ {D2A9434D-59E4-43E9-8D9C-332AA138CEAD}.Release.ActiveCfg = Release|.NET
+ {D2A9434D-59E4-43E9-8D9C-332AA138CEAD}.Release.Build.0 = Release|.NET
+ {4CA3F3DF-D2B7-4FA2-874C-BFC4B04286A2}.Debug.ActiveCfg = Debug|.NET
+ {4CA3F3DF-D2B7-4FA2-874C-BFC4B04286A2}.Debug.Build.0 = Debug|.NET
+ {4CA3F3DF-D2B7-4FA2-874C-BFC4B04286A2}.Release.ActiveCfg = Release|.NET
+ {4CA3F3DF-D2B7-4FA2-874C-BFC4B04286A2}.Release.Build.0 = Release|.NET
+ {E00A0FA2-1FD7-4DD9-8C06-7202CE366102}.Debug.ActiveCfg = Debug|.NET
+ {E00A0FA2-1FD7-4DD9-8C06-7202CE366102}.Debug.Build.0 = Debug|.NET
+ {E00A0FA2-1FD7-4DD9-8C06-7202CE366102}.Release.ActiveCfg = Release|.NET
+ {E00A0FA2-1FD7-4DD9-8C06-7202CE366102}.Release.Build.0 = Release|.NET
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/ikvm/AssemblyInfo.cs b/ikvm/AssemblyInfo.cs
new file mode 100644
index 00000000..1fb1f8ef
--- /dev/null
+++ b/ikvm/AssemblyInfo.cs
@@ -0,0 +1,81 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+//
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//
+[assembly: AssemblyTitle("")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+//
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+
+[assembly: AssemblyVersion("1.0.*")]
+
+//
+// In order to sign your assembly you must specify a key to use. Refer to the
+// Microsoft .NET Framework documentation for more information on assembly signing.
+//
+// Use the attributes below to control which key is used for signing.
+//
+// Notes:
+// (*) If no key is specified, the assembly is not signed.
+// (*) KeyName refers to a key that has been installed in the Crypto Service
+// Provider (CSP) on your machine. KeyFile refers to a file which contains
+// a key.
+// (*) If the KeyFile and the KeyName values are both specified, the
+// following processing occurs:
+// (1) If the KeyName can be found in the CSP, that key is used.
+// (2) If the KeyName does not exist and the KeyFile does exist, the key
+// in the KeyFile is installed into the CSP and used.
+// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
+// When specifying the KeyFile, the location of the KeyFile should be
+// relative to the project output directory which is
+// %Project Directory%\obj\<configuration>. For example, if your KeyFile is
+// located in the project directory, you would specify the AssemblyKeyFile
+// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
+// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
+// documentation for more information on this.
+//
+[assembly: AssemblyDelaySign(false)]
+[assembly: AssemblyKeyFile("")]
+[assembly: AssemblyKeyName("")]
diff --git a/ikvm/bin/Debug/lib/security/classpath.security b/ikvm/bin/Debug/lib/security/classpath.security
new file mode 100644
index 00000000..cd1223be
--- /dev/null
+++ b/ikvm/bin/Debug/lib/security/classpath.security
@@ -0,0 +1,39 @@
+# classpath.security
+# Copyright (C) 2002 Free Software Foundation, Inc.
+#
+# 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.
+
+
+security.provider.1=gnu.java.security.provider.Gnu
diff --git a/ikvm/bin/Release/lib/security/classpath.security b/ikvm/bin/Release/lib/security/classpath.security
new file mode 100644
index 00000000..cd1223be
--- /dev/null
+++ b/ikvm/bin/Release/lib/security/classpath.security
@@ -0,0 +1,39 @@
+# classpath.security
+# Copyright (C) 2002 Free Software Foundation, Inc.
+#
+# 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.
+
+
+security.provider.1=gnu.java.security.provider.Gnu
diff --git a/ikvm/ikvm.build b/ikvm/ikvm.build
new file mode 100644
index 00000000..46cd4024
--- /dev/null
+++ b/ikvm/ikvm.build
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<project name="ikvm" default="ikvm">
+ <target name="ikvm">
+ <csc target="exe" output="../bin/ikvm.exe">
+ <sources>
+ <includes name="*.cs" />
+ </sources>
+ <references>
+ <includes name="../bin/classpath.dll" asis="true" />
+ <includes name="../bin/IK.VM.NET.dll" asis="true" />
+ </references>
+ </csc>
+ </target>
+</project>
diff --git a/ikvm/ikvm.csproj b/ikvm/ikvm.csproj
new file mode 100644
index 00000000..ffe9af6d
--- /dev/null
+++ b/ikvm/ikvm.csproj
@@ -0,0 +1,103 @@
+<VisualStudioProject>
+ <CSHARP
+ ProjectType = "Local"
+ ProductVersion = "7.0.9466"
+ SchemaVersion = "1.0"
+ ProjectGuid = "{4FBAFF23-1E48-4977-8C50-30F87E70A8B5}"
+ >
+ <Build>
+ <Settings
+ ApplicationIcon = ""
+ AssemblyKeyContainerName = ""
+ AssemblyName = "ikvm"
+ AssemblyOriginatorKeyFile = ""
+ DefaultClientScript = "JScript"
+ DefaultHTMLPageLayout = "Grid"
+ DefaultTargetSchema = "IE50"
+ DelaySign = "false"
+ OutputType = "Exe"
+ RootNamespace = "ikvm"
+ StartupObject = ""
+ >
+ <Config
+ Name = "Debug"
+ AllowUnsafeBlocks = "false"
+ BaseAddress = "285212672"
+ CheckForOverflowUnderflow = "false"
+ ConfigurationOverrideFile = ""
+ DefineConstants = "DEBUG;TRACE"
+ DocumentationFile = ""
+ DebugSymbols = "true"
+ FileAlignment = "4096"
+ IncrementalBuild = "true"
+ Optimize = "false"
+ OutputPath = "bin\Debug\"
+ RegisterForComInterop = "false"
+ RemoveIntegerChecks = "false"
+ TreatWarningsAsErrors = "false"
+ WarningLevel = "4"
+ />
+ <Config
+ Name = "Release"
+ AllowUnsafeBlocks = "false"
+ BaseAddress = "285212672"
+ CheckForOverflowUnderflow = "false"
+ ConfigurationOverrideFile = ""
+ DefineConstants = "TRACE"
+ DocumentationFile = ""
+ DebugSymbols = "true"
+ FileAlignment = "4096"
+ IncrementalBuild = "false"
+ Optimize = "true"
+ OutputPath = "bin\Release\"
+ RegisterForComInterop = "false"
+ RemoveIntegerChecks = "false"
+ TreatWarningsAsErrors = "false"
+ WarningLevel = "4"
+ />
+ </Settings>
+ <References>
+ <Reference
+ Name = "System"
+ AssemblyName = "System"
+ HintPath = "..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.dll"
+ />
+ <Reference
+ Name = "System.Data"
+ AssemblyName = "System.Data"
+ HintPath = "..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Data.dll"
+ />
+ <Reference
+ Name = "System.XML"
+ AssemblyName = "System.Xml"
+ HintPath = "..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.XML.dll"
+ />
+ <Reference
+ Name = "IK.VM.NET"
+ Project = "{F5C7B588-0403-4AF2-A4DE-5697DE21BC2C}"
+ Package = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"
+ />
+ <Reference
+ Name = "classpath"
+ AssemblyName = "classpath"
+ HintPath = "..\bin\classpath.dll"
+ />
+ </References>
+ </Build>
+ <Files>
+ <Include>
+ <File
+ RelPath = "AssemblyInfo.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "starter.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ </Include>
+ </Files>
+ </CSHARP>
+</VisualStudioProject>
+
diff --git a/ikvm/starter.cs b/ikvm/starter.cs
new file mode 100644
index 00000000..c7bdda45
--- /dev/null
+++ b/ikvm/starter.cs
@@ -0,0 +1,249 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+using System.IO;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Collections;
+
+using java.lang.reflect;
+using java.net;
+using java.util.jar;
+using java.io;
+
+public class Starter
+{
+ private class Timer
+ {
+ private static Timer t;
+ private DateTime now = DateTime.Now;
+
+ internal Timer()
+ {
+ t = this;
+ }
+
+ ~Timer()
+ {
+ Console.WriteLine(DateTime.Now - now);
+ }
+ }
+
+ private class ExtClassLoader : URLClassLoader
+ {
+ private static URL[] GetClassPath()
+ {
+ string classpath = java.lang.System.getProperty("java.ext.dirs", "");
+ string[] s = classpath.Split(';');
+ ArrayList jars = new ArrayList();
+ for(int i = 0; i < s.Length; i++)
+ {
+ try
+ {
+ string[] files = Directory.GetFiles(s[i]);
+ for(int j = 0; j < files.Length; j++)
+ {
+ jars.Add(new java.io.File(files[j]).toURL());
+ }
+ }
+ catch(ArgumentException)
+ {
+ // ignore any malformed components
+ }
+ }
+ return (URL[])jars.ToArray(typeof(URL));
+ }
+
+ internal ExtClassLoader(java.lang.ClassLoader parent)
+ : base(GetClassPath(), parent)
+ {
+ }
+ }
+
+ public class AppClassLoader : URLClassLoader
+ {
+ private static URL[] GetClassPath()
+ {
+ string classpath = java.lang.System.getProperty("java.class.path", ".");
+ string[] s = classpath.Split(';');
+ URL[] urls = new URL[s.Length];
+ for(int i = 0; i < urls.Length; i++)
+ {
+ // TODO non-existing file/dir is treated as current directory, this obviously isn't correct
+ urls[i] = new java.io.File(s[i]).toURL();
+ }
+ return urls;
+ }
+
+ public AppClassLoader(java.lang.ClassLoader parent)
+ : base(GetClassPath(), new ExtClassLoader(parent))
+ {
+ }
+ }
+
+ [StackTraceInfo(Hidden = true, EatFrames = 1)]
+ [STAThread] // NOTE this is here because otherwise SWT's RegisterDragDrop (a COM thing) doesn't work
+ static int Main(string[] args)
+ {
+ System.Threading.Thread.CurrentThread.Name = "main";
+ bool jar = false;
+ bool saveAssembly = false;
+ string mainClass = null;
+ string[] vmargs = null;
+ for(int i = 0; i < args.Length; i++)
+ {
+ if(args[i][0] == '-')
+ {
+ if(args[i] == "-help")
+ {
+ break;
+ }
+ else if(args[i] == "-save")
+ {
+ saveAssembly = true;
+ }
+ else if(args[i] == "-time")
+ {
+ new Timer();
+ }
+ else if(args[i] == "-jar")
+ {
+ jar = true;
+ }
+ else if(args[i].StartsWith("-D"))
+ {
+ string[] keyvalue = args[i].Substring(2).Split('=');
+ if(keyvalue.Length != 2)
+ {
+ keyvalue = new string[] { keyvalue[0], "" };
+ }
+ java.lang.System.setProperty(keyvalue[0], keyvalue[1]);
+ }
+ else if(args[i] == "-cp" || args[i] == "-classpath")
+ {
+ java.lang.System.setProperty("java.class.path", args[++i]);
+ }
+ else
+ {
+ Console.Error.WriteLine("{0}: illegal argument", args[i]);
+ break;
+ }
+ }
+ else
+ {
+ mainClass = args[i];
+ vmargs = new string[args.Length - (i + 1)];
+ System.Array.Copy(args, i + 1, vmargs, 0, vmargs.Length);
+ break;
+ }
+ }
+ if(mainClass == null)
+ {
+ Console.Error.WriteLine("usage: ikvm [-options] <class> [args...]");
+ Console.Error.WriteLine(" (to execute a class)");
+ Console.Error.WriteLine(" or ikvm -jar [-options] <jarfile> [args...]");
+ Console.Error.WriteLine(" (to execute a jar file)");
+ Console.Error.WriteLine();
+ Console.Error.WriteLine("where options include:");
+ Console.Error.WriteLine(" -help Display this message");
+ Console.Error.WriteLine(" -cp -classpath <directories and zip/jar files separated by ;>");
+ Console.Error.WriteLine(" set search path for application classes and resources");
+ Console.Error.WriteLine(" -save Save the generated assembly (for debugging)");
+ Console.Error.WriteLine(" -time Time the execution");
+ Console.Error.WriteLine(" -D<name>=<value> Set a system property");
+ return 1;
+ }
+ try
+ {
+ // HACK we take our own assembly location as the location of classpath (this is used by the Security infrastructure
+ // to find the classpath.security file)
+ java.lang.System.setProperty("gnu.classpath.home", new System.IO.FileInfo(Assembly.GetExecutingAssembly().Location).DirectoryName);
+ if(jar)
+ {
+ // TODO if there is no classpath, we're adding the current directory, but is this correct when running a jar?
+ java.lang.System.setProperty("java.class.path", mainClass + ";" + java.lang.System.getProperty("java.class.path"));
+ JarFile jf = new JarFile(mainClass);
+ try
+ {
+ // TODO use Attributes.Name.MAIN_CLASS (we don't support inner classes at the moment)
+ mainClass = jf.getManifest().getMainAttributes().getValue("Main-Class");
+ }
+ finally
+ {
+ jf.close();
+ }
+ if(mainClass == null)
+ {
+ Console.Error.WriteLine("Manifest doesn't contain a Main-Class.");
+ return 1;
+ }
+ }
+ // NOTE we should use the default systemclassloader (gnu.java.lang.SystemClassLoader),
+ // but at the moment it is broken (doesn't implement findClass())
+ java.lang.System.setProperty("java.system.class.loader", typeof(AppClassLoader).AssemblyQualifiedName);
+ java.lang.ClassLoader loader = java.lang.ClassLoader.getSystemClassLoader();
+ java.lang.Class clazz = loader.loadClass(mainClass);
+ Method method = clazz.getMethod("main", new java.lang.Class[] { java.lang.Class.getClassFromType(typeof(string[])) });
+ if(!Modifier.isPublic(method.getModifiers()))
+ {
+ Console.Error.WriteLine("Main method not public.");
+ return 1;
+ }
+ try
+ {
+ try
+ {
+ method.invoke(null, new object[] { vmargs });
+ }
+ finally
+ {
+ if(saveAssembly)
+ {
+ // TODO it would be nice to wait for other threads to exit
+ // TODO consider using a Shutdown hook!
+ JVM.SaveDebugImage(clazz);
+ saveAssembly = false;
+ }
+ }
+ }
+ catch(InvocationTargetException x)
+ {
+ throw x.getCause();
+ }
+ if(saveAssembly)
+ {
+ // TODO it would be nice to wait for other threads to exit
+ // TODO consider using a Shutdown hook!
+ JVM.SaveDebugImage(clazz);
+ }
+ return 0;
+ }
+ catch(System.Exception x)
+ {
+ java.lang.Thread thread = java.lang.Thread.currentThread();
+ thread.getThreadGroup().uncaughtException(thread, ExceptionHelper.MapExceptionFast(x));
+ return 1;
+ }
+ }
+}
diff --git a/ikvmc/AssemblyInfo.cs b/ikvmc/AssemblyInfo.cs
new file mode 100644
index 00000000..1fb1f8ef
--- /dev/null
+++ b/ikvmc/AssemblyInfo.cs
@@ -0,0 +1,81 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+//
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//
+[assembly: AssemblyTitle("")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+//
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+
+[assembly: AssemblyVersion("1.0.*")]
+
+//
+// In order to sign your assembly you must specify a key to use. Refer to the
+// Microsoft .NET Framework documentation for more information on assembly signing.
+//
+// Use the attributes below to control which key is used for signing.
+//
+// Notes:
+// (*) If no key is specified, the assembly is not signed.
+// (*) KeyName refers to a key that has been installed in the Crypto Service
+// Provider (CSP) on your machine. KeyFile refers to a file which contains
+// a key.
+// (*) If the KeyFile and the KeyName values are both specified, the
+// following processing occurs:
+// (1) If the KeyName can be found in the CSP, that key is used.
+// (2) If the KeyName does not exist and the KeyFile does exist, the key
+// in the KeyFile is installed into the CSP and used.
+// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
+// When specifying the KeyFile, the location of the KeyFile should be
+// relative to the project output directory which is
+// %Project Directory%\obj\<configuration>. For example, if your KeyFile is
+// located in the project directory, you would specify the AssemblyKeyFile
+// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
+// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
+// documentation for more information on this.
+//
+[assembly: AssemblyDelaySign(false)]
+[assembly: AssemblyKeyFile("")]
+[assembly: AssemblyKeyName("")]
diff --git a/ikvmc/Compiler.cs b/ikvmc/Compiler.cs
new file mode 100644
index 00000000..2d3575f2
--- /dev/null
+++ b/ikvmc/Compiler.cs
@@ -0,0 +1,244 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+using System.Collections;
+using System.IO;
+using System.Reflection;
+using java.io;
+using java.util.zip;
+
+class Compiler : MarshalByRefObject
+{
+ private static ArrayList GetArgs(string[] args)
+ {
+ ArrayList arglist = new ArrayList();
+ foreach(string s in args)
+ {
+ if(s.StartsWith("@"))
+ {
+ using(StreamReader sr = new StreamReader(s.Substring(1)))
+ {
+ string line;
+ while((line = sr.ReadLine()) != null)
+ {
+ arglist.Add(line);
+ }
+ }
+ }
+ else
+ {
+ arglist.Add(s);
+ }
+ }
+ return arglist;
+ }
+
+ static int Main(string[] args)
+ {
+ System.Reflection.Emit.PEFileKinds target = System.Reflection.Emit.PEFileKinds.ConsoleApplication;
+ string assemblyname = null;
+ string outputfile = null;
+ string main = null;
+ bool nojni = false;
+ ArrayList references = new ArrayList();
+ ArrayList arglist = GetArgs(args);
+ if(arglist.Count == 0)
+ {
+ Console.Error.WriteLine("usage: ikvmc [-options] <classOrJar1> ... <classOrJarN>");
+ Console.Error.WriteLine();
+ Console.Error.WriteLine("options:");
+ Console.Error.WriteLine(" -out:<outputfile> Required");
+ Console.Error.WriteLine(" -assembly:<outputfile> Optionally used to specify assembly name");
+ Console.Error.WriteLine(" -target:exe Build a console executable");
+ Console.Error.WriteLine(" -target:winexe Build a windows executable");
+ Console.Error.WriteLine(" -target:library Build a library");
+ Console.Error.WriteLine(" -main:<class> Required (for executables)");
+ Console.Error.WriteLine(" -reference:<path> Reference an assembly");
+ Console.Error.WriteLine(" -recurse:<filespec> Recurse directory and include matching files");
+ Console.Error.WriteLine(" -nojni Do not generate JNI stub for native methods");
+ return 1;
+ }
+ ArrayList classes = new ArrayList();
+ Hashtable resources = new Hashtable();
+ foreach(string s in arglist)
+ {
+ if(s[0] == '-')
+ {
+ if(s.StartsWith("-out:"))
+ {
+ outputfile = s.Substring(5);
+ }
+ else if(s.StartsWith("-assembly:"))
+ {
+ assemblyname = s.Substring(10);
+ }
+ else if(s.StartsWith("-target:"))
+ {
+ switch(s)
+ {
+ case "-target:exe":
+ target = System.Reflection.Emit.PEFileKinds.ConsoleApplication;
+ break;
+ case "-target:winexe":
+ target = System.Reflection.Emit.PEFileKinds.WindowApplication;
+ break;
+ case "-target:library":
+ target = System.Reflection.Emit.PEFileKinds.Dll;
+ break;
+ }
+ }
+ else if(s.StartsWith("-main:"))
+ {
+ main = s.Substring(6);
+ }
+ else if(s.StartsWith("-reference:"))
+ {
+ references.Add(s.Substring(11));
+ }
+ else if(s.StartsWith("-recurse:"))
+ {
+ string spec = s.Substring(9);
+ Recurse(classes, resources, new DirectoryInfo(Path.GetDirectoryName(spec)), Path.GetFileName(spec));
+ }
+ else if(s == "-nojni")
+ {
+ nojni = true;
+ }
+ else
+ {
+ Console.Error.WriteLine("Warning: Unrecognized option: {0}", s);
+ }
+ }
+ else
+ {
+ ProcessFile(classes, resources, s);
+ }
+ }
+ if(outputfile == null)
+ {
+ Console.Error.WriteLine("Error: -out:<outputfile> must be specified");
+ return 1;
+ }
+ if(assemblyname == null)
+ {
+ int idx = outputfile.LastIndexOf('.');
+ if(idx > 0)
+ {
+ assemblyname = outputfile.Substring(0, idx);
+ }
+ else
+ {
+ assemblyname = outputfile;
+ }
+ }
+ if(target != System.Reflection.Emit.PEFileKinds.Dll && main == null)
+ {
+ Console.Error.WriteLine("Error: -main:<class> must be specified when creating an executable");
+ return 1;
+ }
+ // HACK since we use Classpath's zip code, our VM is already running in this AppDomain, which means that
+ // it cannot be (ab)used to statically compile anymore, so we create a new AppDomain to run the compile in.
+ Compiler c = (Compiler)AppDomain.CreateDomain("Compiler").CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, "Compiler");
+ return c.Compile(outputfile, assemblyname, main, target, (byte[][])classes.ToArray(typeof(byte[])), (string[])references.ToArray(typeof(string)), nojni, resources);
+ }
+
+ private static void ProcessFile(ArrayList classes, Hashtable resources, string file)
+ {
+ if(file.ToLower().EndsWith(".class"))
+ {
+ using(FileStream fs = new FileStream(file, FileMode.Open))
+ {
+ byte[] b = new byte[fs.Length];
+ fs.Read(b, 0, b.Length);
+ classes.Add(b);
+ }
+ }
+ else if(file.ToLower().EndsWith(".jar") || file.ToLower().EndsWith(".zip"))
+ {
+ ZipFile zf = new ZipFile(file);
+ java.util.Enumeration e = zf.entries();
+ while(e.hasMoreElements())
+ {
+ ZipEntry ze = (ZipEntry)e.nextElement();
+ if(ze.getName().ToLower().EndsWith(".class"))
+ {
+ sbyte[] sbuf = new sbyte[ze.getSize()];
+ DataInputStream dis = new DataInputStream(zf.getInputStream(ze));
+ dis.readFully(sbuf);
+ dis.close();
+ byte[] buf = new byte[sbuf.Length];
+ for(int i = 0; i < buf.Length; i++)
+ {
+ buf[i] = (byte)sbuf[i];
+ }
+ classes.Add(buf);
+ }
+ else
+ {
+ // if it's not a class, we treat it as a resource
+ sbyte[] sbuf = new sbyte[ze.getSize()];
+ DataInputStream dis = new DataInputStream(zf.getInputStream(ze));
+ dis.readFully(sbuf);
+ dis.close();
+ byte[] buf = new byte[sbuf.Length];
+ for(int i = 0; i < buf.Length; i++)
+ {
+ buf[i] = (byte)sbuf[i];
+ }
+ resources.Add(ze.getName(), buf);
+ }
+ }
+ }
+ else
+ {
+ Console.Error.WriteLine("Warning: Unknown file type: {0}", file);
+ }
+ }
+
+ private static void Recurse(ArrayList classes, Hashtable resources, DirectoryInfo dir, string spec)
+ {
+ foreach(FileInfo file in dir.GetFiles(spec))
+ {
+ ProcessFile(classes, resources, file.FullName);
+ }
+ foreach(DirectoryInfo sub in dir.GetDirectories())
+ {
+ Recurse(classes, resources, sub, spec);
+ }
+ }
+
+ public int Compile(string fileName, string assemblyName, string mainClass, System.Reflection.Emit.PEFileKinds target, byte[][] classes, string[] references, bool nojni, Hashtable resources)
+ {
+ try
+ {
+ JVM.Compile(fileName, assemblyName, mainClass, target, classes, references, nojni, resources);
+ return 0;
+ }
+ catch(Exception x)
+ {
+ Console.Error.WriteLine(x);
+ return 1;
+ }
+ }
+}
diff --git a/ikvmc/bin/Release/native.txt b/ikvmc/bin/Release/native.txt
new file mode 100644
index 00000000..a71719cf
--- /dev/null
+++ b/ikvmc/bin/Release/native.txt
@@ -0,0 +1,4 @@
+Compiling class files (1)
+Constructing compiler
+Loading remapped types
+Parsing class files
diff --git a/ikvmc/ikvmc.build b/ikvmc/ikvmc.build
new file mode 100644
index 00000000..27a325ce
--- /dev/null
+++ b/ikvmc/ikvmc.build
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<project name="ikvmc" default="ikvmc">
+ <target name="ikvmc">
+ <csc target="exe" output="../bin/ikvmc.exe">
+ <sources>
+ <includes name="*.cs" />
+ </sources>
+ <references>
+ <includes name="../bin/classpath.dll" asis="true" />
+ <includes name="../bin/ik.vm.net.dll" asis="true" />
+ </references>
+ </csc>
+ </target>
+</project>
diff --git a/ikvmc/ikvmc.csproj b/ikvmc/ikvmc.csproj
new file mode 100644
index 00000000..06554c49
--- /dev/null
+++ b/ikvmc/ikvmc.csproj
@@ -0,0 +1,103 @@
+<VisualStudioProject>
+ <CSHARP
+ ProjectType = "Local"
+ ProductVersion = "7.0.9466"
+ SchemaVersion = "1.0"
+ ProjectGuid = "{4CA3F3DF-D2B7-4FA2-874C-BFC4B04286A2}"
+ >
+ <Build>
+ <Settings
+ ApplicationIcon = ""
+ AssemblyKeyContainerName = ""
+ AssemblyName = "ikvmc"
+ AssemblyOriginatorKeyFile = ""
+ DefaultClientScript = "JScript"
+ DefaultHTMLPageLayout = "Grid"
+ DefaultTargetSchema = "IE50"
+ DelaySign = "false"
+ OutputType = "Exe"
+ RootNamespace = "ikvmc"
+ StartupObject = ""
+ >
+ <Config
+ Name = "Debug"
+ AllowUnsafeBlocks = "false"
+ BaseAddress = "285212672"
+ CheckForOverflowUnderflow = "false"
+ ConfigurationOverrideFile = ""
+ DefineConstants = "DEBUG;TRACE"
+ DocumentationFile = ""
+ DebugSymbols = "true"
+ FileAlignment = "4096"
+ IncrementalBuild = "true"
+ Optimize = "false"
+ OutputPath = "bin\Debug\"
+ RegisterForComInterop = "false"
+ RemoveIntegerChecks = "false"
+ TreatWarningsAsErrors = "false"
+ WarningLevel = "4"
+ />
+ <Config
+ Name = "Release"
+ AllowUnsafeBlocks = "false"
+ BaseAddress = "285212672"
+ CheckForOverflowUnderflow = "false"
+ ConfigurationOverrideFile = ""
+ DefineConstants = "TRACE"
+ DocumentationFile = ""
+ DebugSymbols = "true"
+ FileAlignment = "4096"
+ IncrementalBuild = "false"
+ Optimize = "true"
+ OutputPath = "bin\Release\"
+ RegisterForComInterop = "false"
+ RemoveIntegerChecks = "false"
+ TreatWarningsAsErrors = "false"
+ WarningLevel = "4"
+ />
+ </Settings>
+ <References>
+ <Reference
+ Name = "System"
+ AssemblyName = "System"
+ HintPath = "..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.dll"
+ />
+ <Reference
+ Name = "System.Data"
+ AssemblyName = "System.Data"
+ HintPath = "..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Data.dll"
+ />
+ <Reference
+ Name = "System.XML"
+ AssemblyName = "System.Xml"
+ HintPath = "..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.XML.dll"
+ />
+ <Reference
+ Name = "IK.VM.NET"
+ Project = "{F5C7B588-0403-4AF2-A4DE-5697DE21BC2C}"
+ Package = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"
+ />
+ <Reference
+ Name = "classpath"
+ AssemblyName = "classpath"
+ HintPath = "..\classpath\classpath.dll"
+ />
+ </References>
+ </Build>
+ <Files>
+ <Include>
+ <File
+ RelPath = "AssemblyInfo.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "Compiler.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ </Include>
+ </Files>
+ </CSHARP>
+</VisualStudioProject>
+
diff --git a/netexp/AssemblyInfo.cs b/netexp/AssemblyInfo.cs
new file mode 100644
index 00000000..1fb1f8ef
--- /dev/null
+++ b/netexp/AssemblyInfo.cs
@@ -0,0 +1,81 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+//
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//
+[assembly: AssemblyTitle("")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+//
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+
+[assembly: AssemblyVersion("1.0.*")]
+
+//
+// In order to sign your assembly you must specify a key to use. Refer to the
+// Microsoft .NET Framework documentation for more information on assembly signing.
+//
+// Use the attributes below to control which key is used for signing.
+//
+// Notes:
+// (*) If no key is specified, the assembly is not signed.
+// (*) KeyName refers to a key that has been installed in the Crypto Service
+// Provider (CSP) on your machine. KeyFile refers to a file which contains
+// a key.
+// (*) If the KeyFile and the KeyName values are both specified, the
+// following processing occurs:
+// (1) If the KeyName can be found in the CSP, that key is used.
+// (2) If the KeyName does not exist and the KeyFile does exist, the key
+// in the KeyFile is installed into the CSP and used.
+// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
+// When specifying the KeyFile, the location of the KeyFile should be
+// relative to the project output directory which is
+// %Project Directory%\obj\<configuration>. For example, if your KeyFile is
+// located in the project directory, you would specify the AssemblyKeyFile
+// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
+// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
+// documentation for more information on this.
+//
+[assembly: AssemblyDelaySign(false)]
+[assembly: AssemblyKeyFile("")]
+[assembly: AssemblyKeyName("")]
diff --git a/netexp/ClassFileWriter.cs b/netexp/ClassFileWriter.cs
new file mode 100644
index 00000000..faa19915
--- /dev/null
+++ b/netexp/ClassFileWriter.cs
@@ -0,0 +1,632 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+using System.IO;
+using System.Collections;
+
+class BigEndianStream
+{
+ private Stream stream;
+
+ public BigEndianStream(Stream stream)
+ {
+ this.stream = stream;
+ }
+
+ public void WriteUInt16(ushort s)
+ {
+ stream.WriteByte((byte)(s >> 8));
+ stream.WriteByte((byte)s);
+ }
+
+ public void WriteUInt32(uint u)
+ {
+ stream.WriteByte((byte)(u >> 24));
+ stream.WriteByte((byte)(u >> 16));
+ stream.WriteByte((byte)(u >> 8));
+ stream.WriteByte((byte)u);
+ }
+
+ public void WriteInt64(long l)
+ {
+ WriteUInt32((uint)(l >> 32));
+ WriteUInt32((uint)l);
+ }
+
+ public void WriteFloat(float f)
+ {
+ WriteUInt32(BitConverter.ToUInt32(BitConverter.GetBytes(f), 0));
+ }
+
+ public void WriteDouble(double d)
+ {
+ WriteInt64(BitConverter.ToInt64(BitConverter.GetBytes(d), 0));
+ }
+
+ public void WriteByte(byte b)
+ {
+ stream.WriteByte(b);
+ }
+
+ public void WriteUtf8(string str)
+ {
+ byte[] buf = new byte[str.Length * 3 + 1];
+ int j = 0;
+ for(int i = 0, e = str.Length; i < e; i++)
+ {
+ char ch = str[i];
+ if ((ch != 0) && (ch <=0x7f))
+ {
+ buf[j++] = (byte)ch;
+ }
+ else if (ch <= 0x7FF)
+ {
+ /* 11 bits or less. */
+ byte high_five = (byte)(ch >> 6);
+ byte low_six = (byte)(ch & 0x3F);
+ buf[j++] = (byte)(high_five | 0xC0); /* 110xxxxx */
+ buf[j++] = (byte)(low_six | 0x80); /* 10xxxxxx */
+ }
+ else
+ {
+ /* possibly full 16 bits. */
+ byte high_four = (byte)(ch >> 12);
+ byte mid_six = (byte)((ch >> 6) & 0x3F);
+ byte low_six = (byte)(ch & 0x3f);
+ buf[j++] = (byte)(high_four | 0xE0); /* 1110xxxx */
+ buf[j++] = (byte)(mid_six | 0x80); /* 10xxxxxx */
+ buf[j++] = (byte)(low_six | 0x80); /* 10xxxxxx*/
+ }
+ }
+ WriteUInt16((ushort)j);
+ stream.Write(buf, 0, j);
+ }
+}
+
+enum Constant
+{
+ Utf8 = 1,
+ Integer = 3,
+ Float = 4,
+ Long = 5,
+ Double = 6,
+ Class = 7,
+ String = 8,
+ Fieldref = 9,
+ Methodref = 10,
+ InterfaceMethodref = 11,
+ NameAndType = 12
+}
+
+abstract class ConstantPoolItem
+{
+ public abstract void Write(BigEndianStream bes);
+}
+
+class ConstantPoolItemClass : ConstantPoolItem
+{
+ private ushort name_index;
+
+ public ConstantPoolItemClass(ushort name_index)
+ {
+ this.name_index = name_index;
+ }
+
+ public override int GetHashCode()
+ {
+ return name_index;
+ }
+
+ public override bool Equals(object o)
+ {
+ if(o != null && o.GetType() == typeof(ConstantPoolItemClass))
+ {
+ return ((ConstantPoolItemClass)o).name_index == name_index;
+ }
+ return false;
+ }
+
+ public override void Write(BigEndianStream bes)
+ {
+ bes.WriteByte((byte)Constant.Class);
+ bes.WriteUInt16(name_index);
+ }
+}
+
+class ConstantPoolItemUtf8 : ConstantPoolItem
+{
+ private string str;
+
+ public ConstantPoolItemUtf8(string str)
+ {
+ this.str = str;
+ }
+
+ public override int GetHashCode()
+ {
+ return str.GetHashCode();
+ }
+
+ public override bool Equals(object o)
+ {
+ if(o != null && o.GetType() == typeof(ConstantPoolItemUtf8))
+ {
+ return ((ConstantPoolItemUtf8)o).str == str;
+ }
+ return false;
+ }
+
+ public override void Write(BigEndianStream bes)
+ {
+ bes.WriteByte((byte)Constant.Utf8);
+ bes.WriteUtf8(str);
+ }
+}
+
+class ConstantPoolItemInt : ConstantPoolItem
+{
+ private int v;
+
+ public ConstantPoolItemInt(int v)
+ {
+ this.v = v;
+ }
+
+ public override int GetHashCode()
+ {
+ return v;
+ }
+
+ public override bool Equals(object o)
+ {
+ if(o != null && o.GetType() == typeof(ConstantPoolItemInt))
+ {
+ return ((ConstantPoolItemInt)o).v == v;
+ }
+ return false;
+ }
+
+ public override void Write(BigEndianStream bes)
+ {
+ bes.WriteByte((byte)Constant.Integer);
+ bes.WriteUInt32((uint)v);
+ }
+}
+
+class ConstantPoolItemLong : ConstantPoolItem
+{
+ private long v;
+
+ public ConstantPoolItemLong(long v)
+ {
+ this.v = v;
+ }
+
+ public override int GetHashCode()
+ {
+ return (int)v;
+ }
+
+ public override bool Equals(object o)
+ {
+ if(o != null && o.GetType() == typeof(ConstantPoolItemLong))
+ {
+ return ((ConstantPoolItemLong)o).v == v;
+ }
+ return false;
+ }
+
+ public override void Write(BigEndianStream bes)
+ {
+ bes.WriteByte((byte)Constant.Long);
+ bes.WriteInt64(v);
+ }
+}
+
+class ConstantPoolItemFloat : ConstantPoolItem
+{
+ private float v;
+
+ public ConstantPoolItemFloat(float v)
+ {
+ this.v = v;
+ }
+
+ public override int GetHashCode()
+ {
+ return BitConverter.ToInt32(BitConverter.GetBytes(v), 0);
+ }
+
+ public override bool Equals(object o)
+ {
+ if(o != null && o.GetType() == typeof(ConstantPoolItemFloat))
+ {
+ return ((ConstantPoolItemFloat)o).v == v;
+ }
+ return false;
+ }
+
+ public override void Write(BigEndianStream bes)
+ {
+ bes.WriteByte((byte)Constant.Float);
+ bes.WriteFloat(v);
+ }
+}
+
+class ConstantPoolItemDouble : ConstantPoolItem
+{
+ private double v;
+
+ public ConstantPoolItemDouble(double v)
+ {
+ this.v = v;
+ }
+
+ public override int GetHashCode()
+ {
+ long l = BitConverter.DoubleToInt64Bits(v);
+ return ((int)l) ^ ((int)(l >> 32));
+ }
+
+ public override bool Equals(object o)
+ {
+ if(o != null && o.GetType() == typeof(ConstantPoolItemDouble))
+ {
+ return ((ConstantPoolItemDouble)o).v == v;
+ }
+ return false;
+ }
+
+ public override void Write(BigEndianStream bes)
+ {
+ bes.WriteByte((byte)Constant.Double);
+ bes.WriteDouble(v);
+ }
+}
+
+class ConstantPoolItemString : ConstantPoolItem
+{
+ private ushort string_index;
+
+ public ConstantPoolItemString(ushort string_index)
+ {
+ this.string_index = string_index;
+ }
+
+ public override int GetHashCode()
+ {
+ return string_index;
+ }
+
+ public override bool Equals(object o)
+ {
+ if(o != null && o.GetType() == typeof(ConstantPoolItemString))
+ {
+ return ((ConstantPoolItemString)o).string_index == string_index;
+ }
+ return false;
+ }
+
+ public override void Write(BigEndianStream bes)
+ {
+ bes.WriteByte((byte)Constant.String);
+ bes.WriteUInt16(string_index);
+ }
+}
+
+class ClassFileAttribute
+{
+ private ushort name_index;
+
+ public ClassFileAttribute(ushort name_index)
+ {
+ this.name_index = name_index;
+ }
+
+ public virtual void Write(BigEndianStream bes)
+ {
+ bes.WriteUInt16(name_index);
+ }
+}
+
+class ConstantValueAttribute : ClassFileAttribute
+{
+ private ushort constant_index;
+
+ public ConstantValueAttribute(ushort name_index, ushort constant_index)
+ : base(name_index)
+ {
+ this.constant_index = constant_index;
+ }
+
+ public override void Write(BigEndianStream bes)
+ {
+ base.Write(bes);
+ bes.WriteUInt32(2);
+ bes.WriteUInt16(constant_index);
+ }
+}
+
+class StringAttribute : ClassFileAttribute
+{
+ private ushort string_index;
+
+ public StringAttribute(ushort name_index, ushort string_index)
+ : base(name_index)
+ {
+ this.string_index = string_index;
+ }
+
+ public override void Write(BigEndianStream bes)
+ {
+ base.Write(bes);
+ bes.WriteUInt32(2);
+ bes.WriteUInt16(string_index);
+ }
+}
+
+class InnerClassesAttribute : ClassFileAttribute
+{
+ private ClassFileWriter classFile;
+ private ArrayList classes = new ArrayList();
+
+ public InnerClassesAttribute(ClassFileWriter classFile)
+ : base(classFile.AddUtf8("InnerClasses"))
+ {
+ this.classFile = classFile;
+ }
+
+ public override void Write(BigEndianStream bes)
+ {
+ base.Write(bes);
+ bes.WriteUInt32((uint)(2 + 8 * classes.Count));
+ bes.WriteUInt16((ushort)classes.Count);
+ foreach(Item i in classes)
+ {
+ bes.WriteUInt16(i.inner_class_info_index);
+ bes.WriteUInt16(i.outer_class_info_index);
+ bes.WriteUInt16(i.inner_name_index);
+ bes.WriteUInt16(i.inner_class_access_flags);
+ }
+ }
+
+ private class Item
+ {
+ internal ushort inner_class_info_index;
+ internal ushort outer_class_info_index;
+ internal ushort inner_name_index;
+ internal ushort inner_class_access_flags;
+ }
+
+ public void Add(string inner, string outer, string name, ushort access)
+ {
+ Item i = new Item();
+ i.inner_class_info_index = classFile.AddClass(inner);
+ i.outer_class_info_index = classFile.AddClass(outer);
+ if(name != null)
+ {
+ i.inner_name_index = classFile.AddUtf8(name);
+ }
+ i.inner_class_access_flags = access;
+ classes.Add(i);
+ }
+}
+
+class FieldOrMethod
+{
+ private Modifiers access_flags;
+ private ushort name_index;
+ private ushort descriptor_index;
+ private ArrayList attribs = new ArrayList();
+
+ public FieldOrMethod(Modifiers access_flags, ushort name_index, ushort descriptor_index)
+ {
+ this.access_flags = access_flags;
+ this.name_index = name_index;
+ this.descriptor_index = descriptor_index;
+ }
+
+ public void AddAttribute(ClassFileAttribute attrib)
+ {
+ attribs.Add(attrib);
+ }
+
+ public void Write(BigEndianStream bes)
+ {
+ bes.WriteUInt16((ushort)access_flags);
+ bes.WriteUInt16(name_index);
+ bes.WriteUInt16(descriptor_index);
+ bes.WriteUInt16((ushort)attribs.Count);
+ for(int i = 0; i < attribs.Count; i++)
+ {
+ ((ClassFileAttribute)attribs[i]).Write(bes);
+ }
+ }
+}
+
+class ClassFileWriter
+{
+ private ArrayList cplist = new ArrayList();
+ private Hashtable cphashtable = new Hashtable();
+ private ArrayList fields = new ArrayList();
+ private ArrayList methods = new ArrayList();
+ private ArrayList attribs = new ArrayList();
+ private Modifiers access_flags;
+ private ushort this_class;
+ private ushort super_class;
+
+ public ClassFileWriter(Modifiers mods, string name, string super)
+ {
+ cplist.Add(null);
+ access_flags = mods;
+ this_class = AddClass(name);
+ if(super != null)
+ {
+ super_class = AddClass(super);
+ }
+ }
+
+ private ushort Add(ConstantPoolItem cpi)
+ {
+ object index = cphashtable[cpi];
+ if(index == null)
+ {
+ index = (ushort)cplist.Add(cpi);
+ if(cpi is ConstantPoolItemDouble || cpi is ConstantPoolItemLong)
+ {
+ cplist.Add(null);
+ }
+ cphashtable[cpi] = index;
+ }
+ return (ushort)index;
+ }
+
+ public ushort AddUtf8(string str)
+ {
+ return Add(new ConstantPoolItemUtf8(str));
+ }
+
+ public ushort AddClass(string classname)
+ {
+ return Add(new ConstantPoolItemClass(AddUtf8(classname)));
+ }
+
+ private ushort AddInt(int i)
+ {
+ return Add(new ConstantPoolItemInt(i));
+ }
+
+ private ushort AddLong(long l)
+ {
+ return Add(new ConstantPoolItemLong(l));
+ }
+
+ private ushort AddFloat(float f)
+ {
+ return Add(new ConstantPoolItemFloat(f));
+ }
+
+ private ushort AddDouble(double d)
+ {
+ return Add(new ConstantPoolItemDouble(d));
+ }
+
+ private ushort AddString(string s)
+ {
+ return Add(new ConstantPoolItemString(AddUtf8(s)));
+ }
+
+ public FieldOrMethod AddMethod(Modifiers access, string name, string signature)
+ {
+ FieldOrMethod method = new FieldOrMethod(access, AddUtf8(name), AddUtf8(signature));
+ methods.Add(method);
+ return method;
+ }
+
+ public FieldOrMethod AddField(Modifiers access, string name, string signature, object constantValue)
+ {
+ FieldOrMethod field = new FieldOrMethod(access, AddUtf8(name), AddUtf8(signature));
+ if(constantValue != null)
+ {
+ ushort constantValueIndex;
+ if(constantValue is int)
+ {
+ constantValueIndex = AddInt((int)constantValue);
+ }
+ else if(constantValue is long)
+ {
+ constantValueIndex = AddLong((long)constantValue);
+ }
+ else if(constantValue is float)
+ {
+ constantValueIndex = AddFloat((float)constantValue);
+ }
+ else if(constantValue is double)
+ {
+ constantValueIndex = AddDouble((double)constantValue);
+ }
+ else if(constantValue is string)
+ {
+ constantValueIndex = AddString((string)constantValue);
+ }
+ else
+ {
+ throw new InvalidOperationException();
+ }
+ field.AddAttribute(new ConstantValueAttribute(AddUtf8("ConstantValue"), constantValueIndex));
+ }
+ fields.Add(field);
+ return field;
+ }
+
+ public void AddStringAttribute(string name, string value)
+ {
+ attribs.Add(new StringAttribute(AddUtf8(name), AddUtf8(value)));
+ }
+
+ public void AddAttribute(ClassFileAttribute attrib)
+ {
+ attribs.Add(attrib);
+ }
+
+ public void Write(Stream stream)
+ {
+ BigEndianStream bes = new BigEndianStream(stream);
+ bes.WriteUInt32(0xCAFEBABE);
+ bes.WriteUInt16((ushort)3);
+ bes.WriteUInt16((ushort)45);
+ bes.WriteUInt16((ushort)cplist.Count);
+ for(int i = 1; i < cplist.Count; i++)
+ {
+ ConstantPoolItem cpi = (ConstantPoolItem)cplist[i];
+ if(cpi != null)
+ {
+ cpi.Write(bes);
+ }
+ }
+ bes.WriteUInt16((ushort)access_flags);
+ bes.WriteUInt16(this_class);
+ bes.WriteUInt16(super_class);
+ // interfaces count
+ bes.WriteUInt16(0);
+ // fields count
+ bes.WriteUInt16((ushort)fields.Count);
+ for(int i = 0; i < fields.Count; i++)
+ {
+ ((FieldOrMethod)fields[i]).Write(bes);
+ }
+ // methods count
+ bes.WriteUInt16((ushort)methods.Count);
+ for(int i = 0; i < methods.Count; i++)
+ {
+ ((FieldOrMethod)methods[i]).Write(bes);
+ }
+ // attributes count
+ bes.WriteUInt16((ushort)attribs.Count);
+ for(int i = 0; i < attribs.Count; i++)
+ {
+ ((ClassFileAttribute)attribs[i]).Write(bes);
+ }
+ }
+}
diff --git a/netexp/NetExp.cs b/netexp/NetExp.cs
new file mode 100644
index 00000000..f2007683
--- /dev/null
+++ b/netexp/NetExp.cs
@@ -0,0 +1,474 @@
+/*
+ Copyright (C) 2002 Jeroen Frijters
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jeroen Frijters
+ jeroen@frijters.net
+
+*/
+using System;
+using System.Reflection;
+using System.IO;
+using System.Text;
+using System.Collections;
+using java.util.zip;
+using java.io;
+
+public class NetExp
+{
+ private static ZipOutputStream zipFile;
+
+ public static void Main(string[] args)
+ {
+ Assembly assembly = null;
+ if(new FileInfo(args[0]).Exists)
+ {
+ assembly = Assembly.LoadFrom(args[0]);
+ }
+ if(assembly == null)
+ {
+ Console.Error.WriteLine("Error: Assembly \"{0}\" not found", args[0]);
+ }
+ else
+ {
+ zipFile = new ZipOutputStream(new FileOutputStream(assembly.GetName().Name + ".jar"));
+ ProcessAssembly(assembly);
+ zipFile.close();
+ }
+ }
+
+ private static void ProcessAssembly(Assembly assembly)
+ {
+ object[] attribs = assembly.GetCustomAttributes(typeof(CLSCompliantAttribute), false);
+ bool assemblyIsCLSCompliant = true;
+ if(attribs.Length != 1)
+ {
+ assemblyIsCLSCompliant = false;
+ Console.Error.WriteLine("Warning: assembly has no (or multiple) CLS compliance attribute");
+ }
+ else if(!((CLSCompliantAttribute)attribs[0]).IsCompliant)
+ {
+ assemblyIsCLSCompliant = false;
+ Console.Error.WriteLine("Warning: assembly is marked as non-CLS compliant");
+ }
+ foreach(Type t in assembly.GetTypes())
+ {
+ bool typeIsCLSCompliant = true;
+ if(assemblyIsCLSCompliant)
+ {
+ attribs = t.GetCustomAttributes(typeof(CLSCompliantAttribute), false);
+ if(attribs.Length == 1)
+ {
+ typeIsCLSCompliant = ((CLSCompliantAttribute)attribs[0]).IsCompliant;
+ }
+ }
+ if(t.IsPublic && typeIsCLSCompliant)
+ {
+ ProcessType(t);
+ }
+ }
+ }
+
+ private static object UnwrapEnum(object o)
+ {
+ // is there a way to generically convert a boxed enum to its boxed underlying value?
+ Type underlyingType = Enum.GetUnderlyingType(o.GetType());
+ if(underlyingType == typeof(int))
+ {
+ o = (int)o;
+ }
+ else if(underlyingType == typeof(short))
+ {
+ o = (short)o;
+ }
+ else
+ {
+ throw new NotImplementedException(o.GetType().Name);
+ }
+ return o;
+ }
+
+ private static string ClassName(Type t)
+ {
+ if(t == typeof(object))
+ {
+ return "java/lang/Object";
+ }
+ else if(t == typeof(string))
+ {
+ return "java/lang/String";
+ }
+ string name = t.FullName;
+ int lastDot = name.LastIndexOf('.');
+ if(lastDot > 0)
+ {
+ name = name.Substring(0, lastDot).ToLower() + name.Substring(lastDot);
+ }
+ return name.Replace('.', '/');
+ }
+
+ // returns the mapped type in signature format (e.g. Ljava/lang/String;)
+ private static string SigType(Type t)
+ {
+ if(t.IsEnum)
+ {
+ t = Enum.GetUnderlyingType(t);
+ }
+ if(t == typeof(void))
+ {
+ return "V";
+ }
+ else if(t == typeof(byte) || t == typeof(sbyte))
+ {
+ return "B";
+ }
+ else if(t == typeof(bool))
+ {
+ return "Z";
+ }
+ else if(t == typeof(short) || t == typeof(ushort))
+ {
+ return "S";
+ }
+ else if(t == typeof(char))
+ {
+ return "C";
+ }
+ else if(t == typeof(int) || t == typeof(uint))
+ {
+ return "I";
+ }
+ else if(t == typeof(long) || t == typeof(ulong))
+ {
+ return "J";
+ }
+ else if(t == typeof(float))
+ {
+ return "F";
+ }
+ else if(t == typeof(double))
+ {
+ return "D";
+ }
+ else if(t == typeof(IntPtr))
+ {
+ // HACK
+ return "I";
+ }
+ else if(t.IsArray)
+ {
+ StringBuilder sb = new StringBuilder();
+ while(t.IsArray)
+ {
+ sb.Append('[');
+ t = t.GetElementType();
+ }
+ sb.Append(SigType(t));
+ return sb.ToString();
+ }
+ else if(!t.IsPrimitive)
+ {
+ return "L" + ClassName(t) + ";";
+ }
+ else
+ {
+ throw new NotImplementedException(t.FullName);
+ }
+ }
+
+ private static void ProcessType(Type type)
+ {
+ if(type == typeof(object) || type == typeof(string))
+ {
+ // special case for System.Object & System.String, don't emit those
+ return;
+ }
+ string name = ClassName(type);
+ string super;
+ if(type.BaseType == null)
+ {
+ // in .NET interfaces don't have a baseType, but in Java they "extend" java/lang/Object
+ super = "java/lang/Object";
+ }
+ else
+ {
+ if(type == typeof(Exception))
+ {
+ super = "java/lang/Throwable";
+ }
+ else
+ {
+ super = ClassName(type.BaseType);
+ }
+ }
+ Modifiers mods = Modifiers.Public | Modifiers.Super;
+ if(type.IsInterface)
+ {
+ mods |= Modifiers.Interface;
+ }
+ if(type.IsSealed)
+ {
+ mods |= Modifiers.Final;
+ }
+ if(type.IsAbstract)
+ {
+ mods |= Modifiers.Abstract;
+ }
+ ClassFileWriter f = new ClassFileWriter(mods, name, super);
+ f.AddStringAttribute("IK.VM.NET.Type", type.AssemblyQualifiedName);
+ FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
+ Hashtable clashtable = new Hashtable();
+ for(int i = 0; i < fields.Length; i++)
+ {
+ if(fields[i].IsPublic || fields[i].IsFamily)
+ {
+ object[] attribs = fields[i].GetCustomAttributes(typeof(CLSCompliantAttribute), false);
+ if(attribs.Length == 1 && !((CLSCompliantAttribute)attribs[0]).IsCompliant)
+ {
+ // skip non-CLS compliant field
+ }
+ else
+ {
+ ProcessField(type, f, fields[i], clashtable);
+ }
+ }
+ }
+ clashtable.Clear();
+ ConstructorInfo[] constructors = type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
+ for(int i = 0; i < constructors.Length; i++)
+ {
+ if(constructors[i].IsPublic || constructors[i].IsFamily)
+ {
+ object[] attribs = constructors[i].GetCustomAttributes(typeof(CLSCompliantAttribute), false);
+ if(attribs.Length == 1 && !((CLSCompliantAttribute)attribs[0]).IsCompliant)
+ {
+ // skip non-CLS compliant field
+ }
+ else
+ {
+ ProcessMethod(type, f, constructors[i], clashtable);
+ }
+ }
+ }
+ MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly);
+ for(int i = 0; i < methods.Length; i++)
+ {
+ if(methods[i].IsPublic || methods[i].IsFamily)
+ {
+ object[] attribs = methods[i].GetCustomAttributes(typeof(CLSCompliantAttribute), false);
+ if(attribs.Length == 1 && !((CLSCompliantAttribute)attribs[0]).IsCompliant)
+ {
+ // skip non-CLS compliant field
+ }
+ else
+ {
+ ProcessMethod(type, f, methods[i], clashtable);
+ }
+ }
+ }
+ // for delegates we have to construct the inner interface
+ if(type.IsSubclassOf(typeof(MulticastDelegate)))
+ {
+ InnerClassesAttribute innerclasses = new InnerClassesAttribute(f);
+ string outer = ClassName(type);
+ innerclasses.Add(outer + "$Method", outer, "Method", 0x209);
+ f.AddAttribute(innerclasses);
+ // now we construct the inner interface type
+ ClassFileWriter iface = new ClassFileWriter(Modifiers.Interface | Modifiers.Public, outer + "$Method", "java/lang/Object");
+ MethodInfo invoke = type.GetMethod("Invoke");
+ StringBuilder sb = new StringBuilder();
+ sb.Append('(');
+ ParameterInfo[] parameters = invoke.GetParameters();
+ for(int i = 0; i < parameters.Length; i++)
+ {
+ sb.Append(SigType(parameters[i].ParameterType));
+ }
+ sb.Append(')');
+ sb.Append(SigType(invoke.ReturnType));
+ // TODO IK.VM.NET.Sig must be set here as well
+ iface.AddMethod(Modifiers.Public | Modifiers.Abstract, "Invoke", sb.ToString());
+ innerclasses = new InnerClassesAttribute(iface);
+ innerclasses.Add(outer + "$Method", outer, "Method", 0x209);
+ iface.AddAttribute(innerclasses);
+ WriteClass(outer + "$Method.class", iface);
+ }
+ WriteClass(name + ".class", f);
+ }
+
+ private static void WriteClass(string name, ClassFileWriter c)
+ {
+ zipFile.putNextEntry(new ZipEntry(name));
+ MemoryStream s = new MemoryStream();
+ c.Write(s);
+ byte[] buf = s.ToArray();
+ sbyte[] sbuf = new sbyte[buf.Length];
+ for(int i = 0; i < buf.Length; i++)
+ {
+ sbuf[i] = (sbyte)buf[i];
+ }
+ zipFile.write(sbuf, 0, sbuf.Length);
+ }
+
+ private static void ProcessField(Type type, ClassFileWriter f, FieldInfo fi, Hashtable clashtable)
+ {
+ Modifiers access;
+ if(fi.IsPublic)
+ {
+ access = Modifiers.Public;
+ }
+ else
+ {
+ access = Modifiers.Protected;
+ }
+ object v = null;
+ if(fi.IsLiteral)
+ {
+ v = fi.GetValue(null);
+ if(v is Enum)
+ {
+ v = UnwrapEnum(v);
+ }
+ if(v is byte)
+ {
+ v = (int)(byte)v;
+ }
+ else if(v is char)
+ {
+ v = (int)(char)v;
+ }
+ else if(v is short)
+ {
+ v = (int)(short)v;
+ }
+ else if(v is bool)
+ {
+ v = ((bool)v) ? 1 : 0;
+ }
+ else if(v is int || v is long || v is float || v is double || v is string)
+ {
+ }
+ else
+ {
+ throw new NotImplementedException(v.GetType().FullName);
+ }
+ access |= Modifiers.Static | Modifiers.Final;
+ }
+ else
+ {
+ if(fi.IsInitOnly)
+ {
+ access |= Modifiers.Final;
+ }
+ if(fi.IsStatic)
+ {
+ access |= Modifiers.Static;
+ }
+ if(type.IsEnum)
+ {
+ // we don't want the value__ field
+ return;
+ }
+ }
+ string sig = SigType(fi.FieldType);
+ string key = fi.Name + sig;
+ if(clashtable.ContainsKey(key))
+ {
+ // TODO instead of skipping, we should mangle the name
+ Console.Error.WriteLine("Skipping field " + type.FullName + "." + fi.Name + " (type " + sig + ") because it clashes");
+ }
+ else
+ {
+ clashtable.Add(key, key);
+ f.AddField(access, fi.Name, sig, v);
+ }
+ }
+
+ private static void ProcessMethod(Type type, ClassFileWriter f, MethodBase mb, Hashtable clashtable)
+ {
+ Modifiers access = 0;
+ if(!mb.IsAbstract)
+ {
+ access = Modifiers.Native;
+ }
+ if(mb.IsPublic)
+ {
+ access |= Modifiers.Public;
+ }
+ else
+ {
+ access |= Modifiers.Protected;
+ }
+ if(mb.IsFinal || !mb.IsVirtual)
+ {
+ access |= Modifiers.Final;
+ }
+ if(mb.IsStatic)
+ {
+ access |= Modifiers.Static;
+ }
+ if(mb.IsAbstract)
+ {
+ access |= Modifiers.Abstract;
+ }
+ // special case for delegate constructors!
+ if(mb.IsConstructor && type.IsSubclassOf(typeof(MulticastDelegate)))
+ {
+ access &= ~Modifiers.Final;
+ f.AddMethod(access, "<init>", "(L" + ClassName(type) + "$Method;)V");
+ return;
+ }
+ // HACK the native signature is really is very lame way of storing the signature
+ // TODO only store it when it doesn't match the Java sig and split it into parts (instead of one giant string)
+ StringBuilder nativesig = new StringBuilder();
+ StringBuilder sb = new StringBuilder();
+ sb.Append('(');
+ ParameterInfo[] parameters = mb.GetParameters();
+ string sep = "";
+ for(int i = 0; i < parameters.Length; i++)
+ {
+ sb.Append(SigType(parameters[i].ParameterType));
+ nativesig.Append(sep).Append(parameters[i].ParameterType.AssemblyQualifiedName);
+ sep = "|";
+ }
+ sb.Append(')');
+ if(mb.IsConstructor)
+ {
+ // HACK constructors may not be final in Java
+ access &= ~Modifiers.Final;
+ sb.Append('V');
+ }
+ else
+ {
+ sb.Append(SigType(((MethodInfo)mb).ReturnType));
+ }
+ string name = mb.IsConstructor ? "<init>" : mb.Name;
+ string sig = sb.ToString();
+ string key = name + sig;
+ if(clashtable.ContainsKey(key))
+ {
+ // TODO instead of skipping, we should mangle the name
+ Console.Error.WriteLine("Skipping method " + type.FullName + "." + name + sig + " because it clashes");
+ }
+ else
+ {
+ clashtable.Add(key, key);
+ f.AddMethod(access, name, sig)
+ .AddAttribute(new StringAttribute(f.AddUtf8("IK.VM.NET.Sig"), f.AddUtf8(nativesig.ToString())));
+ }
+ }
+}
diff --git a/netexp/netexp.build b/netexp/netexp.build
new file mode 100644
index 00000000..14bda8cb
--- /dev/null
+++ b/netexp/netexp.build
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<project name="netexp" default="netexp">
+ <target name="netexp">
+ <csc target="exe" output="../bin/netexp.exe">
+ <sources>
+ <includes name="*.cs" />
+ </sources>
+ <references>
+ <includes name="../bin/classpath.dll" asis="true" />
+ <includes name="../bin/IK.VM.NET.dll" asis="true" />
+ </references>
+ </csc>
+ </target>
+</project>
diff --git a/netexp/netexp.csproj b/netexp/netexp.csproj
new file mode 100644
index 00000000..52d354ce
--- /dev/null
+++ b/netexp/netexp.csproj
@@ -0,0 +1,108 @@
+<VisualStudioProject>
+ <CSHARP
+ ProjectType = "Local"
+ ProductVersion = "7.0.9466"
+ SchemaVersion = "1.0"
+ ProjectGuid = "{D2A9434D-59E4-43E9-8D9C-332AA138CEAD}"
+ >
+ <Build>
+ <Settings
+ ApplicationIcon = ""
+ AssemblyKeyContainerName = ""
+ AssemblyName = "netexp"
+ AssemblyOriginatorKeyFile = ""
+ DefaultClientScript = "JScript"
+ DefaultHTMLPageLayout = "Grid"
+ DefaultTargetSchema = "IE50"
+ DelaySign = "false"
+ OutputType = "Exe"
+ RootNamespace = "netexp"
+ StartupObject = ""
+ >
+ <Config
+ Name = "Debug"
+ AllowUnsafeBlocks = "false"
+ BaseAddress = "285212672"
+ CheckForOverflowUnderflow = "false"
+ ConfigurationOverrideFile = ""
+ DefineConstants = "DEBUG;TRACE"
+ DocumentationFile = ""
+ DebugSymbols = "true"
+ FileAlignment = "4096"
+ IncrementalBuild = "true"
+ Optimize = "false"
+ OutputPath = "bin\Debug\"
+ RegisterForComInterop = "false"
+ RemoveIntegerChecks = "false"
+ TreatWarningsAsErrors = "false"
+ WarningLevel = "4"
+ />
+ <Config
+ Name = "Release"
+ AllowUnsafeBlocks = "false"
+ BaseAddress = "285212672"
+ CheckForOverflowUnderflow = "false"
+ ConfigurationOverrideFile = ""
+ DefineConstants = "TRACE"
+ DocumentationFile = ""
+ DebugSymbols = "true"
+ FileAlignment = "4096"
+ IncrementalBuild = "false"
+ Optimize = "true"
+ OutputPath = "bin\Release\"
+ RegisterForComInterop = "false"
+ RemoveIntegerChecks = "false"
+ TreatWarningsAsErrors = "false"
+ WarningLevel = "4"
+ />
+ </Settings>
+ <References>
+ <Reference
+ Name = "System"
+ AssemblyName = "System"
+ HintPath = "..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.dll"
+ />
+ <Reference
+ Name = "System.Data"
+ AssemblyName = "System.Data"
+ HintPath = "..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.Data.dll"
+ />
+ <Reference
+ Name = "System.XML"
+ AssemblyName = "System.Xml"
+ HintPath = "..\..\..\..\..\..\WINDOWS\Microsoft.NET\Framework\v1.0.3705\System.XML.dll"
+ />
+ <Reference
+ Name = "classpath"
+ AssemblyName = "classpath"
+ HintPath = "..\classpath\classpath.dll"
+ />
+ <Reference
+ Name = "IK.VM.NET"
+ Project = "{F5C7B588-0403-4AF2-A4DE-5697DE21BC2C}"
+ Package = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"
+ />
+ </References>
+ </Build>
+ <Files>
+ <Include>
+ <File
+ RelPath = "AssemblyInfo.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "ClassFileWriter.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "NetExp.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ </Include>
+ </Files>
+ </CSHARP>
+</VisualStudioProject>
+