internal sealed override void Generate(CodeGenContext context, CodeEmitter ilgen) { Debug.Assert(Name != null); if (Name == ".ctor") { Debug.Assert(Class == null && type != null); Type[] argTypes = context.ClassLoader.ArgTypeListFromSig(Sig); ConstructorInfo ci = StaticCompiler.GetType(context.ClassLoader, type).GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, CallingConventions.Standard, argTypes, null); if (ci == null) { throw new InvalidOperationException("Missing .ctor: " + type + "..ctor" + Sig); } ilgen.Emit(opcode, ci); } else { Debug.Assert(Class == null ^ type == null); if (Class != null) { Debug.Assert(Sig != null); MethodWrapper method = context.ClassLoader.LoadClassByDottedName(Class).GetMethodWrapper(Name, Sig, false); if (method == null) { throw new InvalidOperationException("method not found: " + Class + "." + Name + Sig); } method.Link(); // TODO this code is part of what Compiler.CastInterfaceArgs (in compiler.cs) does, // it would be nice if we could avoid this duplication... TypeWrapper[] argTypeWrappers = method.GetParameters(); for (int i = 0; i < argTypeWrappers.Length; i++) { if (argTypeWrappers[i].IsGhost) { LocalBuilder[] temps = new LocalBuilder[argTypeWrappers.Length + (method.IsStatic ? 0 : 1)]; for (int j = temps.Length - 1; j >= 0; j--) { TypeWrapper tw; if (method.IsStatic) { tw = argTypeWrappers[j]; } else { if (j == 0) { tw = method.DeclaringType; } else { tw = argTypeWrappers[j - 1]; } } if (tw.IsGhost) { tw.EmitConvStackTypeToSignatureType(ilgen, null); } temps[j] = ilgen.DeclareLocal(tw.TypeAsSignatureType); ilgen.Emit(OpCodes.Stloc, temps[j]); } for (int j = 0; j < temps.Length; j++) { ilgen.Emit(OpCodes.Ldloc, temps[j]); } break; } } if (opcode.Value == OpCodes.Call.Value) { method.EmitCall(ilgen); } else if (opcode.Value == OpCodes.Callvirt.Value) { method.EmitCallvirt(ilgen); } else if (opcode.Value == OpCodes.Newobj.Value) { method.EmitNewobj(ilgen); } else { throw new InvalidOperationException(); } } else { Type[] argTypes; if (Sig.StartsWith("(")) { argTypes = context.ClassLoader.ArgTypeListFromSig(Sig); } else { string[] types = Sig.Split(';'); argTypes = new Type[types.Length]; for (int i = 0; i < types.Length; i++) { argTypes[i] = StaticCompiler.GetType(context.ClassLoader, types[i]); } } MethodInfo mi = StaticCompiler.GetType(context.ClassLoader, type).GetMethod(Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static, null, argTypes, null); if (mi == null) { throw new InvalidOperationException("Missing method: " + type + "." + Name + Sig); } ilgen.Emit(opcode, mi); } } }
/** * Emit an invoke for the given name, using the MemberName directly. */ void emitStaticInvoke(MemberName member, Name name) { // push arguments emitPushArguments(name); // invocation if (member.isMethod()) { if (IsMethodHandleLinkTo(member)) { MethodType mt = member.getMethodType(); TypeWrapper[] args = new TypeWrapper[mt.parameterCount()]; for (int j = 0; j < args.Length; j++) { args[j] = TypeWrapper.FromClass(mt.parameterType(j)); args[j].Finish(); } TypeWrapper ret = TypeWrapper.FromClass(mt.returnType()); ret.Finish(); Compiler.MethodHandleMethodWrapper.EmitLinkToCall(ilgen, args, ret); ret.EmitConvSignatureTypeToStackType(ilgen); } else if (IsMethodHandleInvokeBasic(member)) { EmitInvokeBasic(member.getMethodType()); } else { switch (member.getReferenceKind()) { case MethodHandleNatives.Constants.REF_invokeInterface: case MethodHandleNatives.Constants.REF_invokeSpecial: case MethodHandleNatives.Constants.REF_invokeStatic: case MethodHandleNatives.Constants.REF_invokeVirtual: break; default: throw new BailoutException(Bailout.UnsupportedRefKind, member); } MethodWrapper mw = GetMethodWrapper(member); if (!IsStaticallyInvocable(mw)) { throw new BailoutException(Bailout.NotStaticallyInvocable, member); } mw.Link(); mw.DeclaringType.Finish(); mw.ResolveMethod(); if (mw.HasCallerID) { EmitConstant(DynamicCallerIDProvider.Instance); ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.DynamicCallerID); } if (mw.IsStatic || member.getReferenceKind() == MethodHandleNatives.Constants.REF_invokeSpecial) { mw.EmitCall(ilgen); } else { mw.EmitCallvirt(ilgen); } mw.ReturnType.EmitConvSignatureTypeToStackType(ilgen); } } else if (member.isField()) { FieldWrapper fw = GetFieldWrapper(member); if (!IsStaticallyInvocable(fw)) { throw new BailoutException(Bailout.NotStaticallyInvocable, member); } fw.Link(); fw.DeclaringType.Finish(); fw.ResolveField(); switch (member.getReferenceKind()) { case MethodHandleNatives.Constants.REF_getField: case MethodHandleNatives.Constants.REF_getStatic: fw.EmitGet(ilgen); fw.FieldTypeWrapper.EmitConvSignatureTypeToStackType(ilgen); break; case MethodHandleNatives.Constants.REF_putField: case MethodHandleNatives.Constants.REF_putStatic: fw.EmitSet(ilgen); break; default: throw new BailoutException(Bailout.UnsupportedRefKind, member); } } else { throw new BailoutException(Bailout.NotStaticallyInvocable, member); } }
internal void Callvirt(MethodWrapper mw) { mw.EmitCallvirt(ilgen); }
// 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); }