private static bool Object_getClass(EmitIntrinsicContext eic) { // this is the null-check idiom that javac uses (both in its own source and in the code it generates) if (eic.MatchRange(0, 2) && eic.Match(1, NormalizedByteCode.__pop)) { eic.Emitter.Emit(OpCodes.Dup); eic.Emitter.EmitNullCheck(); return(true); } // this optimizes obj1.getClass() ==/!= obj2.getClass() else if (eic.MatchRange(0, 4) && eic.Match(1, NormalizedByteCode.__aload) && eic.Match(2, NormalizedByteCode.__invokevirtual) && (eic.Match(3, NormalizedByteCode.__if_acmpeq) || eic.Match(3, NormalizedByteCode.__if_acmpne)) && (IsSafeForGetClassOptimization(eic.GetStackTypeWrapper(0, 0)) || IsSafeForGetClassOptimization(eic.GetStackTypeWrapper(2, 0)))) { ClassFile.ConstantPoolItemMI cpi = eic.GetMethodref(2); if (cpi.Class == "java.lang.Object" && cpi.Name == "getClass" && cpi.Signature == "()Ljava.lang.Class;") { // we can't patch the current opcode, so we have to emit the first call to GetTypeHandle here eic.Emitter.Emit(OpCodes.Callvirt, Compiler.getTypeMethod); eic.PatchOpCode(2, NormalizedByteCode.__intrinsic_gettype); return(true); } } // this optimizes obj.getClass() == Xxx.class else if (eic.MatchRange(0, 3) && eic.Match(1, NormalizedByteCode.__ldc) && eic.GetConstantType(1) == ClassFile.ConstantType.Class && (eic.Match(2, NormalizedByteCode.__if_acmpeq) || eic.Match(2, NormalizedByteCode.__if_acmpne))) { TypeWrapper tw = eic.GetClassLiteral(1); if (tw.IsGhost || tw.IsGhostArray || tw.IsUnloadable || (tw.IsRemapped && tw.IsFinal && tw is DotNetTypeWrapper)) { return(false); } eic.Emitter.Emit(OpCodes.Callvirt, Compiler.getTypeMethod); eic.Emitter.Emit(OpCodes.Ldtoken, (tw.IsRemapped && tw.IsFinal) ? tw.TypeAsTBD : tw.TypeAsBaseType); eic.Emitter.Emit(OpCodes.Call, Compiler.getTypeFromHandleMethod); eic.PatchOpCode(1, NormalizedByteCode.__nop); return(true); } return(false); }