diff --git a/CommonAssemblyInfo.cs.in b/CommonAssemblyInfo.cs.in index f50907fa0..01a509a03 100644 --- a/CommonAssemblyInfo.cs.in +++ b/CommonAssemblyInfo.cs.in @@ -29,7 +29,7 @@ using System.Reflection; [assembly: AssemblyCopyright("Copyright (C) 2019 Jessie Lesbian (based on work by Jeroen Frijters and Windward Studios)")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -[assembly: AssemblyVersion("8.5.2.0")] +[assembly: AssemblyVersion("8.6.1.0")] #if SIGNCODE #pragma warning disable 1699 diff --git a/ikvm/starter.cs b/ikvm/starter.cs index ef9037916..6a2a57676 100644 --- a/ikvm/starter.cs +++ b/ikvm/starter.cs @@ -28,6 +28,7 @@ Jeroen Frijters using IKVM.Internal; using ikvm.runtime; using java.lang.reflect; +using jessielesbian.IKVM; public static class Starter { @@ -288,11 +289,15 @@ static int Main(string[] args) } else if(arg.StartsWith("-Xoptimize:")){ try{ - jessielesbian.IKVM.Helper.optpasses = (int)Convert.ToUInt32(arg.Replace("-Xoptimize:", "")); + Helper.optpasses = (int)Convert.ToUInt32(arg.Replace("-Xoptimize:", "")); } catch{ Console.Error.WriteLine("SORRY, IKVM.NET experimental optimizations disabled, reason: negative or invalid number of optimization passes."); } } + else if(arg == "-Xpreoptimize") + { + Helper.enableJITPreOptimization = true; + } else { Console.Error.WriteLine("{0}: illegal argument", arg); @@ -440,6 +445,7 @@ private static void PrintXHelp() Console.Error.WriteLine(" -Xnoglobbing Disable argument globbing"); Console.Error.WriteLine(" -Xverify Enable strict class file verification"); Console.Error.WriteLine(" -Xoptimize:n Enable IKVM.NET experimental optimizations and use N passes of optimization"); + Console.Error.WriteLine(" -Xpreoptimize Enable precompilation optimizations"); Console.Error.WriteLine(); Console.Error.WriteLine("The -X options are non-standard and subject to change without notice."); Console.Error.WriteLine(); diff --git a/ikvmc/Compiler.cs b/ikvmc/Compiler.cs index 3cb98e33b..195ed27d7 100644 --- a/ikvmc/Compiler.cs +++ b/ikvmc/Compiler.cs @@ -30,6 +30,7 @@ Jeroen Frijters using IKVM.Internal; using IKVM.Reflection; using IKVM.Reflection.Emit; +using jessielesbian.IKVM; using Type = IKVM.Reflection.Type; sealed class FatalCompilerErrorException : Exception @@ -400,7 +401,14 @@ internal static byte[] ReadAllBytes(FileInfo path) { try { - return File.ReadAllBytes(path.FullName); + //ULTRA fast 2-step file reader by Jessie Lesbian + FileStream fileStream = path.OpenRead(); + MemoryStream memoryStream = new MemoryStream((int) fileStream.Length); + fileStream.CopyTo(memoryStream); + fileStream.Dispose(); + byte[] bytes = memoryStream.ToArray(); + memoryStream.Dispose(); + return bytes; } catch (Exception x) { @@ -481,6 +489,7 @@ private static void PrintHelp() Console.Error.WriteLine("-strictfinalfieldsemantics Don't allow final fields to be modified outside"); Console.Error.WriteLine(" of initializer methods"); Console.Error.WriteLine("-optimize:n Enable IKVM.NET experimental optimizations and use N passes of optimization"); + Console.Error.WriteLine("-preoptimize Enable precompilation optimizations"); Console.Error.WriteLine(); Console.Error.WriteLine(" - ERRORS AND WARNINGS -"); Console.Error.WriteLine("-nowarn: Suppress specified warnings"); @@ -1012,11 +1021,15 @@ void ContinueParseCommandLine(IEnumerator arglist, List else if(s.StartsWith("-optimize:")) { try{ - jessielesbian.IKVM.Helper.optpasses = (int)Convert.ToUInt32(s.Replace("-optimize:", "")); + Helper.optpasses = (int)Convert.ToUInt32(s.Replace("-optimize:", "")); } catch{ Console.Error.WriteLine("SORRY, IKVM.NET experimental optimizations disabled, reason: negative or invalid number of optimization passes."); } } + else if(s == "-preoptimize") + { + Helper.enableJITPreOptimization = true; + } else { throw new FatalCompilerErrorException(Message.UnrecognizedOption, s); diff --git a/ikvmc/CompilerClassLoader.cs b/ikvmc/CompilerClassLoader.cs index 1d6e66a3d..88ab076ce 100644 --- a/ikvmc/CompilerClassLoader.cs +++ b/ikvmc/CompilerClassLoader.cs @@ -4169,4 +4169,4 @@ internal object[][] ToArray() return list.ToArray(); } } -} +} \ No newline at end of file diff --git a/openjdk/commonAttributes.class b/openjdk/commonAttributes.class index 9fc5f6581..514ab1afa 100644 Binary files a/openjdk/commonAttributes.class and b/openjdk/commonAttributes.class differ diff --git a/openjdk/openjdk.build b/openjdk/openjdk.build index d9851e1da..49156399d 100644 --- a/openjdk/openjdk.build +++ b/openjdk/openjdk.build @@ -157,6 +157,7 @@ + diff --git a/runtime/compiler.cs b/runtime/compiler.cs index 08c2bc389..e2589b054 100644 --- a/runtime/compiler.cs +++ b/runtime/compiler.cs @@ -35,6 +35,7 @@ Jeroen Frijters using System.Diagnostics.SymbolStore; using IKVM.Attributes; using IKVM.Internal; +using jessielesbian.IKVM; using ExceptionTableEntry = IKVM.Internal.ClassFile.Method.ExceptionTableEntry; using LocalVariableTableEntry = IKVM.Internal.ClassFile.Method.LocalVariableTableEntry; @@ -288,7 +289,6 @@ sealed class Compiler private bool nonleaf; private readonly bool debug; private readonly bool keepAlive; - private readonly bool strictfp; private readonly bool emitLineNumbers; private int[] scopeBegin; private int[] scopeClose; @@ -336,7 +336,6 @@ private Compiler(DynamicTypeWrapper.FinishContext context, TypeWrapper host, Dyn this.m = m; this.ilGenerator = ilGenerator; this.debug = classLoader.EmitDebugInfo; - this.strictfp = m.IsStrictfp; if(mw.IsConstructor) { MethodWrapper finalize = clazz.GetMethodWrapper(StringConstants.FINALIZE, StringConstants.SIG_VOID, true); @@ -1064,6 +1063,10 @@ private void Compile(Block block, int startIndex) } } } + if(Helper.enableJITPreOptimization) + { + code = Helper.Optimize(code); + } for(int i = 0; i < code.Length; i++) { Instruction instr = code[i]; @@ -1357,11 +1360,7 @@ private void Compile(Block block, int startIndex) FieldWrapper field = cpi.GetField(); TypeWrapper tw = field.FieldTypeWrapper; tw.EmitConvStackTypeToSignatureType(ilGenerator, ma.GetStackTypeWrapper(i, 0)); - if(strictfp) - { - // no need to convert - } - else if(tw == PrimitiveTypeWrapper.DOUBLE) + if(tw == PrimitiveTypeWrapper.DOUBLE) { ilGenerator.Emit(OpCodes.Conv_R8); } @@ -1390,11 +1389,7 @@ private void Compile(Block block, int startIndex) ilGenerator.Emit(OpCodes.Ldloc, temp); } tw.EmitConvStackTypeToSignatureType(ilGenerator, ma.GetStackTypeWrapper(i, 0)); - if(strictfp) - { - // no need to convert - } - else if(tw == PrimitiveTypeWrapper.DOUBLE) + if(tw == PrimitiveTypeWrapper.DOUBLE) { ilGenerator.Emit(OpCodes.Conv_R8); } @@ -2262,10 +2257,7 @@ private void Compile(Block block, int startIndex) break; case NormalizedByteCode.__dadd: ilGenerator.Emit(OpCodes.Add); - if(strictfp) - { - ilGenerator.Emit(OpCodes.Conv_R8); - } + ilGenerator.Emit(OpCodes.Conv_R8); break; case NormalizedByteCode.__isub: case NormalizedByteCode.__lsub: @@ -2277,10 +2269,7 @@ private void Compile(Block block, int startIndex) break; case NormalizedByteCode.__dsub: ilGenerator.Emit(OpCodes.Sub); - if(strictfp) - { - ilGenerator.Emit(OpCodes.Conv_R8); - } + ilGenerator.Emit(OpCodes.Conv_R8); break; case NormalizedByteCode.__ixor: case NormalizedByteCode.__lxor: @@ -2304,10 +2293,7 @@ private void Compile(Block block, int startIndex) break; case NormalizedByteCode.__dmul: ilGenerator.Emit(OpCodes.Mul); - if(strictfp) - { - ilGenerator.Emit(OpCodes.Conv_R8); - } + ilGenerator.Emit(OpCodes.Conv_R8); break; case NormalizedByteCode.__idiv: ilGenerator.Emit_idiv(); @@ -2321,10 +2307,7 @@ private void Compile(Block block, int startIndex) break; case NormalizedByteCode.__ddiv: ilGenerator.Emit(OpCodes.Div); - if(strictfp) - { - ilGenerator.Emit(OpCodes.Conv_R8); - } + ilGenerator.Emit(OpCodes.Conv_R8); break; case NormalizedByteCode.__irem: case NormalizedByteCode.__lrem: @@ -2361,10 +2344,7 @@ private void Compile(Block block, int startIndex) break; case NormalizedByteCode.__drem: ilGenerator.Emit(OpCodes.Rem); - if(strictfp) - { - ilGenerator.Emit(OpCodes.Conv_R8); - } + ilGenerator.Emit(OpCodes.Conv_R8); break; case NormalizedByteCode.__ishl: ilGenerator.Emit_And_I4(31); @@ -2812,11 +2792,7 @@ private void Compile(Block block, int startIndex) private void EmitReturnTypeConversion(TypeWrapper returnType) { returnType.EmitConvSignatureTypeToStackType(ilGenerator); - if (!strictfp) - { - // no need to convert - } - else if (returnType == PrimitiveTypeWrapper.DOUBLE) + if (returnType == PrimitiveTypeWrapper.DOUBLE) { ilGenerator.Emit(OpCodes.Conv_R8); } @@ -3562,11 +3538,7 @@ private void DynamicGetPutField(Instruction instr, int i) if (kind == ClassFile.RefKind.putField || kind == ClassFile.RefKind.putStatic) { fieldType.EmitConvStackTypeToSignatureType(ilGenerator, ma.GetStackTypeWrapper(i, 0)); - if (strictfp) - { - // no need to convert - } - else if (fieldType == PrimitiveTypeWrapper.DOUBLE) + if (fieldType == PrimitiveTypeWrapper.DOUBLE) { ilGenerator.Emit(OpCodes.Conv_R8); } diff --git a/runtime/jessielesbian.cs b/runtime/jessielesbian.cs index 2afc6086e..1718e65d0 100644 --- a/runtime/jessielesbian.cs +++ b/runtime/jessielesbian.cs @@ -1,15 +1,249 @@ using System; +using System.Collections.Generic; +using Instruction = IKVM.Internal.ClassFile.Method.Instruction; + +//Do you believe in high-quality code by Female/LGBT programmers? Leave u/jessielesbian a PM on Reddit! + namespace jessielesbian.IKVM { public static class Helper { public static int optpasses = 0; - public static bool experimentalOptimizations + public static bool enableJITPreOptimization = false; + internal static bool experimentalOptimizations { get { return (optpasses > 0); } } + private static Instruction GetInstuction(NormalizedByteCode bc) + { + Instruction instruction = new Instruction(); + instruction.PatchOpCode(bc); + return instruction; + } + private static Instruction GetInstuction(NormalizedByteCode bc, int arg1) + { + Instruction instruction = new Instruction(); + instruction.PatchOpCode(bc, arg1); + return instruction; + } + private static Instruction GetInstuction(NormalizedByteCode bc, int arg1, short arg2) + { + Instruction instruction = new Instruction(); + instruction.PatchOpCode(bc, arg1, arg2); + return instruction; + } + internal static Instruction[] Optimize(Instruction[] instructions) + { + //Jessie Lesbian's IKVM.NET JIT Optimizer + //The lesbian had waviered all her rights over this algorigmth. + + instructions = (Instruction[])instructions.Clone(); + int optimizations = 1279738452; + List brtargets = new List(instructions.Length); + for (int i = 1; i < instructions.Length; i++) + { + switch (instructions[i].NormalizedOpCode) + { + case NormalizedByteCode.__goto: + case NormalizedByteCode.__goto_finally: + case NormalizedByteCode.__ifeq: + case NormalizedByteCode.__ifge: + case NormalizedByteCode.__ifgt: + case NormalizedByteCode.__ifle: + case NormalizedByteCode.__iflt: + case NormalizedByteCode.__ifne: + case NormalizedByteCode.__ifnonnull: + case NormalizedByteCode.__ifnull: + case NormalizedByteCode.__if_acmpeq: + case NormalizedByteCode.__if_acmpne: + case NormalizedByteCode.__if_icmpeq: + case NormalizedByteCode.__if_icmpge: + case NormalizedByteCode.__if_icmpgt: + case NormalizedByteCode.__if_icmple: + case NormalizedByteCode.__if_icmplt: + case NormalizedByteCode.__if_icmpne: + brtargets.Add(instructions[i].TargetIndex); + break; + default: + continue; + } + } + while (optimizations != 0) + { + optimizations = 0; + for (int i = 1; i < instructions.Length; i++) + { + Instruction current = instructions[i]; + Instruction prev = instructions[i - 1]; + if (brtargets.Contains(i)) + { + continue; + } + if (brtargets.Contains(i - 1)) + { + continue; + } + if (brtargets.Contains(i + 1)) + { + continue; + } + //peephole optimization: removal of unused arithmethc operations + if (current.NormalizedOpCode == NormalizedByteCode.__pop) + { + switch (prev.NormalizedOpCode) + { + case NormalizedByteCode.__iadd: + case NormalizedByteCode.__isub: + case NormalizedByteCode.__imul: + case NormalizedByteCode.__idiv: + case NormalizedByteCode.__irem: + case NormalizedByteCode.__ishl: + case NormalizedByteCode.__ishr: + case NormalizedByteCode.__iushr: + case NormalizedByteCode.__iand: + case NormalizedByteCode.__ior: + case NormalizedByteCode.__ixor: + case NormalizedByteCode.__fadd: + case NormalizedByteCode.__fsub: + case NormalizedByteCode.__fmul: + case NormalizedByteCode.__fdiv: + case NormalizedByteCode.__frem: + case NormalizedByteCode.__fcmpl: + case NormalizedByteCode.__fcmpg: + case NormalizedByteCode.__ladd: + case NormalizedByteCode.__lsub: + case NormalizedByteCode.__lmul: + case NormalizedByteCode.__ldiv: + case NormalizedByteCode.__lrem: + case NormalizedByteCode.__lshl: + case NormalizedByteCode.__lshr: + case NormalizedByteCode.__lushr: + case NormalizedByteCode.__land: + case NormalizedByteCode.__lor: + case NormalizedByteCode.__lxor: + case NormalizedByteCode.__lcmp: + case NormalizedByteCode.__dadd: + case NormalizedByteCode.__dsub: + case NormalizedByteCode.__dmul: + case NormalizedByteCode.__ddiv: + case NormalizedByteCode.__drem: + case NormalizedByteCode.__dcmpl: + case NormalizedByteCode.__dcmpg: + prev = GetInstuction(NormalizedByteCode.__pop); + optimizations = optimizations + 1; + break; + default: + break; + } + } + //peephole optimization: removal of self-cancelling operations + if (current.NormalizedOpCode == prev.NormalizedOpCode) + { + switch (instructions[i].NormalizedOpCode) + { + case NormalizedByteCode.__ineg: + case NormalizedByteCode.__lneg: + case NormalizedByteCode.__fneg: + case NormalizedByteCode.__dneg: + case NormalizedByteCode.__swap: + current = GetInstuction(NormalizedByteCode.__nop); + prev = GetInstuction(NormalizedByteCode.__nop); + optimizations = optimizations + 1; + break; + default: + break; + } + } + //peephole optimization: optimize addition and subtraction + if((prev.NormalizedOpCode == NormalizedByteCode.__ineg)) + { + if(current.NormalizedOpCode == NormalizedByteCode.__iadd) + { + current = GetInstuction(NormalizedByteCode.__isub); + prev = GetInstuction(NormalizedByteCode.__nop); + optimizations = optimizations + 1; + } + if (current.NormalizedOpCode == NormalizedByteCode.__isub) + { + current = GetInstuction(NormalizedByteCode.__iadd); + prev = GetInstuction(NormalizedByteCode.__nop); + optimizations = optimizations + 1; + } + } + if (prev.NormalizedOpCode == NormalizedByteCode.__lneg) + { + if (current.NormalizedOpCode == NormalizedByteCode.__ladd) + { + current = GetInstuction(NormalizedByteCode.__lsub); + prev = GetInstuction(NormalizedByteCode.__nop); + optimizations = optimizations + 1; + } + if (current.NormalizedOpCode == NormalizedByteCode.__lsub) + { + current = GetInstuction(NormalizedByteCode.__ladd); + prev = GetInstuction(NormalizedByteCode.__nop); + optimizations = optimizations + 1; + } + } + if (prev.NormalizedOpCode == NormalizedByteCode.__fneg) + { + if (current.NormalizedOpCode == NormalizedByteCode.__fadd) + { + current = GetInstuction(NormalizedByteCode.__fsub); + prev = GetInstuction(NormalizedByteCode.__nop); + optimizations = optimizations + 1; + } + if (current.NormalizedOpCode == NormalizedByteCode.__fsub) + { + current = GetInstuction(NormalizedByteCode.__fadd); + prev = GetInstuction(NormalizedByteCode.__nop); + optimizations = optimizations + 1; + } + } + if (prev.NormalizedOpCode == NormalizedByteCode.__dneg) + { + if (current.NormalizedOpCode == NormalizedByteCode.__dadd) + { + current = GetInstuction(NormalizedByteCode.__dsub); + prev = GetInstuction(NormalizedByteCode.__nop); + optimizations = optimizations + 1; + } + if (current.NormalizedOpCode == NormalizedByteCode.__dsub) + { + current = GetInstuction(NormalizedByteCode.__dadd); + prev = GetInstuction(NormalizedByteCode.__nop); + optimizations = optimizations + 1; + } + } + //peephole optimization: remove unnecessary swaps + if(prev.NormalizedOpCode == NormalizedByteCode.__swap) + { + switch (current.NormalizedOpCode) + { + case NormalizedByteCode.__iadd: + case NormalizedByteCode.__ladd: + case NormalizedByteCode.__fadd: + case NormalizedByteCode.__dadd: + case NormalizedByteCode.__imul: + case NormalizedByteCode.__lmul: + case NormalizedByteCode.__fmul: + case NormalizedByteCode.__dmul: + prev = GetInstuction(NormalizedByteCode.__nop); + optimizations = optimizations + 1; + break; + default: + break; + } + } + //sorry, I can't implement branch optimizations. + instructions[i] = current; + instructions[i - 1] = prev; + } + } + return instructions; + } } } \ No newline at end of file