private static bool Unsafe_getObjectVolatile(EmitIntrinsicContext eic) { // the check here must be kept in sync with the hack in MethodAnalyzer.AnalyzeTypeFlow() TypeWrapper tw = eic.GetStackTypeWrapper(0, 1); if (IsSupportedArrayTypeForUnsafeOperation(tw)) { CodeEmitterLocal index = eic.Emitter.AllocTempLocal(Types.Int32); CodeEmitterLocal obj = eic.Emitter.AllocTempLocal(tw.TypeAsLocalOrStackType); eic.Emitter.Emit(OpCodes.Conv_Ovf_I4); eic.Emitter.Emit(OpCodes.Stloc, index); eic.Emitter.Emit(OpCodes.Stloc, obj); EmitConsumeUnsafe(eic); eic.Emitter.Emit(OpCodes.Ldloc, obj); eic.Emitter.Emit(OpCodes.Ldloc, index); eic.Emitter.ReleaseTempLocal(obj); eic.Emitter.ReleaseTempLocal(index); eic.Emitter.Emit(OpCodes.Ldelema, tw.TypeAsLocalOrStackType.GetElementType()); eic.Emitter.Emit(OpCodes.Volatile); eic.Emitter.Emit(OpCodes.Ldind_Ref); // remove the redundant checkcast that usually follows if (eic.Code[eic.OpcodeIndex + 1].NormalizedOpCode == NormalizedByteCode.__checkcast && tw.ElementTypeWrapper.IsAssignableTo(eic.ClassFile.GetConstantPoolClassType(eic.Code[eic.OpcodeIndex + 1].Arg1))) { eic.PatchOpCode(1, NormalizedByteCode.__nop); } eic.NonLeaf = false; return(true); } return(false); }
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); } } return(false); }
private static bool Reflection_getCallerClass(EmitIntrinsicContext eic) { if (eic.Caller.HasCallerID) { int arg = eic.Caller.GetParametersForDefineMethod().Length - 1; if (!eic.Caller.IsStatic) { arg++; } eic.Emitter.EmitLdarg(arg); MethodWrapper mw; if (MatchInvokeStatic(eic, 1, "java.lang.ClassLoader", "getClassLoader", "(Ljava.lang.Class;)Ljava.lang.ClassLoader;")) { eic.PatchOpCode(1, NormalizedByteCode.__nop); mw = [email protected]("getCallerClassLoader", "()Ljava.lang.ClassLoader;", false); } else { mw = [email protected]("getCallerClass", "()Ljava.lang.Class;", false); } mw.Link(); mw.EmitCallvirt(eic.Emitter); return(true); } else if (!DynamicTypeWrapper.RequiresDynamicReflectionCallerClass(eic.ClassFile.Name, eic.Caller.Name, eic.Caller.Signature)) { StaticCompiler.IssueMessage(Message.ReflectionCallerClassRequiresCallerID, eic.ClassFile.Name, eic.Caller.Name, eic.Caller.Signature); } return(false); }
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); }
private static bool Reflection_getCallerClass(EmitIntrinsicContext eic) { if (eic.Caller.HasCallerID) { int arg = eic.Caller.GetParametersForDefineMethod().Length - 1; if (!eic.Caller.IsStatic) { arg++; } eic.Emitter.EmitLdarg(arg); MethodWrapper mw; if (MatchInvokeStatic(eic, 1, "java.lang.ClassLoader", "getClassLoader", "(Ljava.lang.Class;)Ljava.lang.ClassLoader;")) { eic.PatchOpCode(1, NormalizedByteCode.__nop); mw = [email protected]("getCallerClassLoader", "()Ljava.lang.ClassLoader;", false); } else { mw = [email protected]("getCallerClass", "()Ljava.lang.Class;", false); } mw.Link(); mw.EmitCallvirt(eic.Emitter); return(true); } else if (DynamicTypeWrapper.RequiresDynamicReflectionCallerClass(eic.ClassFile.Name, eic.Caller.Name, eic.Caller.Signature)) { // since the non-intrinsic version of Reflection.getCallerClass() always throws an exception, we have to redirect to the dynamic version MethodWrapper getCallerClass = ClassLoaderWrapper.LoadClassCritical("sun.reflect.Reflection").GetMethodWrapper("getCallerClass", "(I)Ljava.lang.Class;", false); getCallerClass.Link(); eic.Emitter.EmitLdc_I4(2); getCallerClass.EmitCall(eic.Emitter); return(true); } else { StaticCompiler.IssueMessage(Message.ReflectionCallerClassRequiresCallerID, eic.ClassFile.Name, eic.Caller.Name, eic.Caller.Signature); } return(false); }
// this intrinsifies the unsafe.objectFieldOffset(XXX.class.getDeclaredField("xxx")) pattern // to avoid initializing the full reflection machinery at this point private static bool Class_getDeclaredField(EmitIntrinsicContext eic) { // validate that we're inside the XXX class and that xxx is an instance field of that class if (eic.MatchRange(-2, 4) && eic.Match(-2, NormalizedByteCode.__ldc) && eic.GetClassLiteral(-2) == eic.Caller.DeclaringType && eic.Match(-1, NormalizedByteCode.__ldc_nothrow) && eic.Match(1, NormalizedByteCode.__invokevirtual)) { FieldWrapper field = null; string fieldName = eic.GetStringLiteral(-1); foreach (FieldWrapper fw in eic.Caller.DeclaringType.GetFields()) { if (fw.Name == fieldName) { if (field != null) { return(false); } field = fw; } } if (field == null || field.IsStatic) { return(false); } ClassFile.ConstantPoolItemMI cpi = eic.GetMethodref(1); if (cpi.Class == "sun.misc.Unsafe" && cpi.Name == "objectFieldOffset" && cpi.Signature == "(Ljava.lang.reflect.Field;)J") { MethodWrapper mw = ClassLoaderWrapper.LoadClassCritical("sun.misc.Unsafe") .GetMethodWrapper("objectFieldOffset", "(Ljava.lang.Class;Ljava.lang.String;)J", false); mw.Link(); mw.EmitCallvirt(eic.Emitter); eic.PatchOpCode(1, NormalizedByteCode.__nop); return(true); } } return(false); }
// this intrinsifies the following two patterns: // unsafe.objectFieldOffset(XXX.class.getDeclaredField("xxx")); // and // Class k = XXX.class; // unsafe.objectFieldOffset(k.getDeclaredField("xxx")); // to avoid initializing the full reflection machinery at this point private static bool Class_getDeclaredField(EmitIntrinsicContext eic) { if (eic.Caller.DeclaringType.GetClassLoader() != CoreClasses.java.lang.Object.Wrapper.GetClassLoader()) { // we can only do this optimization when compiling the trusted core classes return(false); } TypeWrapper fieldClass; if (eic.MatchRange(-2, 4) && eic.Match(-2, NormalizedByteCode.__ldc) && eic.Match(-1, NormalizedByteCode.__ldc_nothrow) && eic.Match(1, NormalizedByteCode.__invokevirtual)) { // unsafe.objectFieldOffset(XXX.class.getDeclaredField("xxx")); fieldClass = eic.GetClassLiteral(-2); } else if (eic.MatchRange(-5, 7) && eic.Match(-5, NormalizedByteCode.__ldc) && eic.Match(-4, NormalizedByteCode.__astore) && eic.Match(-3, NormalizedByteCode.__getstatic) && eic.Match(-2, NormalizedByteCode.__aload, eic.Code[eic.OpcodeIndex - 4].NormalizedArg1) && eic.Match(-1, NormalizedByteCode.__ldc_nothrow) && eic.Match(1, NormalizedByteCode.__invokevirtual)) { // Class k = XXX.class; // unsafe.objectFieldOffset(k.getDeclaredField("xxx")); fieldClass = eic.GetClassLiteral(-5); } else { return(false); } FieldWrapper field = null; string fieldName = eic.GetStringLiteral(-1); foreach (FieldWrapper fw in fieldClass.GetFields()) { if (fw.Name == fieldName) { if (field != null) { return(false); } field = fw; } } if (field == null || field.IsStatic) { return(false); } ClassFile.ConstantPoolItemMI cpi = eic.GetMethodref(1); if (cpi.Class == "sun.misc.Unsafe" && cpi.Name == "objectFieldOffset" && cpi.Signature == "(Ljava.lang.reflect.Field;)J") { MethodWrapper mw = ClassLoaderWrapper.LoadClassCritical("sun.misc.Unsafe") .GetMethodWrapper("objectFieldOffset", "(Ljava.lang.Class;Ljava.lang.String;)J", false); mw.Link(); mw.EmitCallvirt(eic.Emitter); eic.PatchOpCode(1, NormalizedByteCode.__nop); return(true); } return(false); }