internal void LoadFirstArgAddress(TypeWrapper tw) { ilgen.EmitLdarg(0); if (tw.IsGhost) { tw.EmitConvStackTypeToSignatureType(ilgen, null); CodeEmitterLocal local = ilgen.DeclareLocal(tw.TypeAsSignatureType); ilgen.Emit(OpCodes.Stloc, local); ilgen.Emit(OpCodes.Ldloca, local); } else if (tw.IsNonPrimitiveValueType) { ilgen.Emit(OpCodes.Unbox, tw.TypeAsSignatureType); } else { throw new InvalidOperationException(); } }
internal override void Generate(CodeGenContext context, CodeEmitter ilgen) { CodeEmitterLocal lb = (CodeEmitterLocal)context[Name]; if (lb == null) { if (typeWrapper == null && typeType == null) { Debug.Assert(Class == null ^ type == null); if (type != null) { typeType = StaticCompiler.GetTypeForMapXml(context.ClassLoader, type); } else { typeWrapper = context.ClassLoader.LoadClassByDottedName(Class); } } lb = ilgen.DeclareLocal(typeType != null ? typeType : typeWrapper.TypeAsTBD); context[Name] = lb; } ilgen.Emit(OpCodes.Stloc, lb); }
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.GetTypeForMapXml(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) { CodeEmitterLocal[] temps = new CodeEmitterLocal[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 { // ldftn or ldvirtftn ilgen.Emit(opcode, (MethodInfo)method.GetMethod()); } } else { Type[] argTypes; if (Sig.StartsWith("(")) { argTypes = context.ClassLoader.ArgTypeListFromSig(Sig); } else if (Sig == "") { argTypes = Type.EmptyTypes; } else { string[] types = Sig.Split(';'); argTypes = new Type[types.Length]; for (int i = 0; i < types.Length; i++) { argTypes[i] = StaticCompiler.GetTypeForMapXml(context.ClassLoader, types[i]); } } MethodInfo mi = StaticCompiler.GetTypeForMapXml(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); } } }
internal FastFieldReflector(java.io.ObjectStreamField[] fields) { this.fields = fields; TypeWrapper tw = null; foreach (java.io.ObjectStreamField field in fields) { FieldWrapper fw = GetFieldWrapper(field); if (fw != null) { if (tw == null) { tw = fw.DeclaringType; } else if (tw != fw.DeclaringType) { // pre-condition is that all fields are from the same Type! throw new java.lang.InternalError(); } } } if (tw == null) { objFieldGetter = objFieldSetter = objDummy; primFieldGetter = primFieldSetter = primDummy; } else { try { tw.Finish(); } catch (RetargetableJavaException x) { throw x.ToJava(); } DynamicMethod dmObjGetter = DynamicMethodUtils.Create("__<ObjFieldGetter>", tw.TypeAsBaseType, true, null, new Type[] { typeof(object), typeof(object[]) }); DynamicMethod dmPrimGetter = DynamicMethodUtils.Create("__<PrimFieldGetter>", tw.TypeAsBaseType, true, null, new Type[] { typeof(object), typeof(byte[]) }); DynamicMethod dmObjSetter = DynamicMethodUtils.Create("__<ObjFieldSetter>", tw.TypeAsBaseType, true, null, new Type[] { typeof(object), typeof(object[]) }); DynamicMethod dmPrimSetter = DynamicMethodUtils.Create("__<PrimFieldSetter>", tw.TypeAsBaseType, true, null, new Type[] { typeof(object), typeof(byte[]) }); CodeEmitter ilgenObjGetter = CodeEmitter.Create(dmObjGetter); CodeEmitter ilgenPrimGetter = CodeEmitter.Create(dmPrimGetter); CodeEmitter ilgenObjSetter = CodeEmitter.Create(dmObjSetter); CodeEmitter ilgenPrimSetter = CodeEmitter.Create(dmPrimSetter); // we want the getters to be verifiable (because writeObject can be used from partial trust), // so we create a local to hold the properly typed object reference CodeEmitterLocal objGetterThis = ilgenObjGetter.DeclareLocal(tw.TypeAsBaseType); CodeEmitterLocal primGetterThis = ilgenPrimGetter.DeclareLocal(tw.TypeAsBaseType); ilgenObjGetter.Emit(OpCodes.Ldarg_0); ilgenObjGetter.Emit(OpCodes.Castclass, tw.TypeAsBaseType); ilgenObjGetter.Emit(OpCodes.Stloc, objGetterThis); ilgenPrimGetter.Emit(OpCodes.Ldarg_0); ilgenPrimGetter.Emit(OpCodes.Castclass, tw.TypeAsBaseType); ilgenPrimGetter.Emit(OpCodes.Stloc, primGetterThis); foreach (java.io.ObjectStreamField field in fields) { FieldWrapper fw = GetFieldWrapper(field); if (fw == null) { continue; } fw.ResolveField(); TypeWrapper fieldType = fw.FieldTypeWrapper; try { fieldType = fieldType.EnsureLoadable(tw.GetClassLoader()); fieldType.Finish(); } catch (RetargetableJavaException x) { throw x.ToJava(); } if (fieldType.IsPrimitive) { // Getter ilgenPrimGetter.Emit(OpCodes.Ldarg_1); ilgenPrimGetter.EmitLdc_I4(field.getOffset()); ilgenPrimGetter.Emit(OpCodes.Ldloc, primGetterThis); fw.EmitGet(ilgenPrimGetter); if (fieldType == PrimitiveTypeWrapper.BYTE) { ilgenPrimGetter.Emit(OpCodes.Call, WriteByteMethod); } else if (fieldType == PrimitiveTypeWrapper.BOOLEAN) { ilgenPrimGetter.Emit(OpCodes.Call, WriteBooleanMethod); } else if (fieldType == PrimitiveTypeWrapper.CHAR) { ilgenPrimGetter.Emit(OpCodes.Call, WriteCharMethod); } else if (fieldType == PrimitiveTypeWrapper.SHORT) { ilgenPrimGetter.Emit(OpCodes.Call, WriteShortMethod); } else if (fieldType == PrimitiveTypeWrapper.INT) { ilgenPrimGetter.Emit(OpCodes.Call, WriteIntMethod); } else if (fieldType == PrimitiveTypeWrapper.FLOAT) { ilgenPrimGetter.Emit(OpCodes.Call, WriteFloatMethod); } else if (fieldType == PrimitiveTypeWrapper.LONG) { ilgenPrimGetter.Emit(OpCodes.Call, WriteLongMethod); } else if (fieldType == PrimitiveTypeWrapper.DOUBLE) { ilgenPrimGetter.Emit(OpCodes.Call, WriteDoubleMethod); } else { throw new java.lang.InternalError(); } // Setter ilgenPrimSetter.Emit(OpCodes.Ldarg_0); ilgenPrimSetter.Emit(OpCodes.Castclass, tw.TypeAsBaseType); ilgenPrimSetter.Emit(OpCodes.Ldarg_1); ilgenPrimSetter.EmitLdc_I4(field.getOffset()); if (fieldType == PrimitiveTypeWrapper.BYTE) { ilgenPrimSetter.Emit(OpCodes.Call, ReadByteMethod); } else if (fieldType == PrimitiveTypeWrapper.BOOLEAN) { ilgenPrimSetter.Emit(OpCodes.Call, ReadBooleanMethod); } else if (fieldType == PrimitiveTypeWrapper.CHAR) { ilgenPrimSetter.Emit(OpCodes.Call, ReadCharMethod); } else if (fieldType == PrimitiveTypeWrapper.SHORT) { ilgenPrimSetter.Emit(OpCodes.Call, ReadShortMethod); } else if (fieldType == PrimitiveTypeWrapper.INT) { ilgenPrimSetter.Emit(OpCodes.Call, ReadIntMethod); } else if (fieldType == PrimitiveTypeWrapper.FLOAT) { ilgenPrimSetter.Emit(OpCodes.Call, ReadFloatMethod); } else if (fieldType == PrimitiveTypeWrapper.LONG) { ilgenPrimSetter.Emit(OpCodes.Call, ReadLongMethod); } else if (fieldType == PrimitiveTypeWrapper.DOUBLE) { ilgenPrimSetter.Emit(OpCodes.Call, ReadDoubleMethod); } else { throw new java.lang.InternalError(); } fw.EmitSet(ilgenPrimSetter); } else { // Getter ilgenObjGetter.Emit(OpCodes.Ldarg_1); ilgenObjGetter.EmitLdc_I4(field.getOffset()); ilgenObjGetter.Emit(OpCodes.Ldloc, objGetterThis); fw.EmitGet(ilgenObjGetter); fieldType.EmitConvSignatureTypeToStackType(ilgenObjGetter); ilgenObjGetter.Emit(OpCodes.Stelem_Ref); // Setter ilgenObjSetter.Emit(OpCodes.Ldarg_0); ilgenObjSetter.Emit(OpCodes.Ldarg_1); ilgenObjSetter.EmitLdc_I4(field.getOffset()); ilgenObjSetter.Emit(OpCodes.Ldelem_Ref); fieldType.EmitCheckcast(ilgenObjSetter); fieldType.EmitConvStackTypeToSignatureType(ilgenObjSetter, null); fw.EmitSet(ilgenObjSetter); } } ilgenObjGetter.Emit(OpCodes.Ret); ilgenPrimGetter.Emit(OpCodes.Ret); ilgenObjSetter.Emit(OpCodes.Ret); ilgenPrimSetter.Emit(OpCodes.Ret); ilgenObjGetter.DoEmit(); ilgenPrimGetter.DoEmit(); ilgenObjSetter.DoEmit(); ilgenPrimSetter.DoEmit(); objFieldGetter = (ObjFieldGetterSetter)dmObjGetter.CreateDelegate(typeof(ObjFieldGetterSetter)); primFieldGetter = (PrimFieldGetterSetter)dmPrimGetter.CreateDelegate(typeof(PrimFieldGetterSetter)); objFieldSetter = (ObjFieldGetterSetter)dmObjSetter.CreateDelegate(typeof(ObjFieldGetterSetter)); primFieldSetter = (PrimFieldGetterSetter)dmPrimSetter.CreateDelegate(typeof(PrimFieldGetterSetter)); } }
private NativeInvokerBytecodeGenerator(LambdaForm lambdaForm, MethodType invokerType) { if (invokerType != invokerType.basicType()) { throw new BailoutException(Bailout.NotBasicType, invokerType); } this.lambdaForm = lambdaForm; this.invokerType = invokerType; this.delegateType = MethodHandleUtil.GetMemberWrapperDelegateType(invokerType); MethodInfo mi = MethodHandleUtil.GetDelegateInvokeMethod(delegateType); Type[] paramTypes = MethodHandleUtil.GetParameterTypes(typeof(object[]), mi); // HACK the code we generate is not verifiable (known issue: locals aren't typed correctly), so we stick the DynamicMethod into mscorlib (a security critical assembly) this.dm = new DynamicMethod(lambdaForm.debugName, mi.ReturnType, paramTypes, typeof(object).Module, true); this.ilgen = CodeEmitter.Create(this.dm); if (invokerType.parameterCount() > MethodHandleUtil.MaxArity) { this.packedArgType = paramTypes[paramTypes.Length - 1]; this.packedArgPos = paramTypes.Length - 1; } else { this.packedArgPos = Int32.MaxValue; } locals = new CodeEmitterLocal[lambdaForm.names.Length]; for (int i = lambdaForm._arity(); i < lambdaForm.names.Length; i++) { Name name = lambdaForm.names[i]; if (name.index() != i) { throw new BailoutException(Bailout.PreconditionViolated, "name.index() != i"); } switch (name.typeChar()) { case 'L': locals[i] = ilgen.DeclareLocal(Types.Object); break; case 'I': locals[i] = ilgen.DeclareLocal(Types.Int32); break; case 'J': locals[i] = ilgen.DeclareLocal(Types.Int64); break; case 'F': locals[i] = ilgen.DeclareLocal(Types.Single); break; case 'D': locals[i] = ilgen.DeclareLocal(Types.Double); break; case 'V': break; default: throw new BailoutException(Bailout.PreconditionViolated, "Unsupported typeChar(): " + name.typeChar()); } } }
/** * Emit bytecode for the guardWithCatch idiom. * * The pattern looks like (Cf. MethodHandleImpl.makeGuardWithCatch): * <blockquote><pre>{@code * guardWithCatch=Lambda(a0:L,a1:L,a2:L,a3:L,a4:L,a5:L,a6:L,a7:L)=>{ * t8:L=MethodHandle.invokeBasic(a4:L,a6:L,a7:L); * t9:L=MethodHandleImpl.guardWithCatch(a1:L,a2:L,a3:L,t8:L); * t10:I=MethodHandle.invokeBasic(a5:L,t9:L);t10:I} * }</pre></blockquote> * * It is compiled into bytecode equivalent of the following code: * <blockquote><pre>{@code * try { * return a1.invokeBasic(a6, a7); * } catch (Throwable e) { * if (!a2.isInstance(e)) throw e; * return a3.invokeBasic(ex, a6, a7); * }}</pre></blockquote> */ private Name emitGuardWithCatch(int pos) { Name args = lambdaForm.names[pos]; Name invoker = lambdaForm.names[pos + 1]; Name result = lambdaForm.names[pos + 2]; CodeEmitterLabel L_handler = ilgen.DefineLabel(); CodeEmitterLabel L_done = ilgen.DefineLabel(); Class returnType = result.function._resolvedHandle().type().returnType(); MethodType type = args.function._resolvedHandle().type() .dropParameterTypes(0, 1) .changeReturnType(returnType); // Normal case ilgen.BeginExceptionBlock(); // load target emitPushArgument(invoker, 0); emitPushArguments(args, 1); // skip 1st argument: method handle EmitInvokeBasic(type.basicType()); CodeEmitterLocal returnValue = null; if (returnType != java.lang.Void.TYPE) { returnValue = ilgen.DeclareLocal(TypeWrapper.FromClass(returnType).TypeAsLocalOrStackType); ilgen.Emit(OpCodes.Stloc, returnValue); } ilgen.EmitLeave(L_done); // Exceptional case ilgen.BeginCatchBlock(typeof(Exception)); // [IKVM] map the exception and store it in a local and exit the handler ilgen.EmitLdc_I4(0); ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.mapException.MakeGenericMethod(typeof(Exception))); CodeEmitterLocal exception = ilgen.DeclareLocal(typeof(Exception)); ilgen.Emit(OpCodes.Stloc, exception); ilgen.EmitLeave(L_handler); ilgen.EndExceptionBlock(); // Check exception's type ilgen.MarkLabel(L_handler); // load exception class emitPushArgument(invoker, 1); ilgen.Emit(OpCodes.Ldloc, exception); CoreClasses.java.lang.Class.Wrapper.GetMethodWrapper("isInstance", "(Ljava.lang.Object;)Z", false).EmitCall(ilgen); CodeEmitterLabel L_rethrow = ilgen.DefineLabel(); ilgen.EmitBrfalse(L_rethrow); // Invoke catcher // load catcher emitPushArgument(invoker, 2); ilgen.Emit(OpCodes.Ldloc, exception); emitPushArguments(args, 1); // skip 1st argument: method handle MethodType catcherType = type.insertParameterTypes(0, CoreClasses.java.lang.Throwable.Wrapper.ClassObject); EmitInvokeBasic(catcherType.basicType()); if (returnValue != null) { ilgen.Emit(OpCodes.Stloc, returnValue); } ilgen.EmitBr(L_done); ilgen.MarkLabel(L_rethrow); ilgen.Emit(OpCodes.Ldloc, exception); ilgen.Emit(OpCodes.Call, Compiler.unmapExceptionMethod); ilgen.Emit(OpCodes.Throw); ilgen.MarkLabel(L_done); if (returnValue != null) { ilgen.Emit(OpCodes.Ldloc, returnValue); } return(result); }
private static void EmitConvert(CodeEmitter ilgen, java.lang.Class srcClass, java.lang.Class dstClass, int level) { if (srcClass != dstClass) { TypeWrapper src = TypeWrapper.FromClass(srcClass); TypeWrapper dst = TypeWrapper.FromClass(dstClass); src.Finish(); dst.Finish(); if (src.IsNonPrimitiveValueType) { src.EmitBox(ilgen); } if (dst == PrimitiveTypeWrapper.VOID) { ilgen.Emit(OpCodes.Pop); } else if (src.IsPrimitive) { if (dst.IsPrimitive) { if (src == PrimitiveTypeWrapper.BYTE) { ilgen.Emit(OpCodes.Conv_I1); } if (dst == PrimitiveTypeWrapper.FLOAT) { ilgen.Emit(OpCodes.Conv_R4); } else if (dst == PrimitiveTypeWrapper.DOUBLE) { ilgen.Emit(OpCodes.Conv_R8); } else if (dst == PrimitiveTypeWrapper.LONG) { if (src == PrimitiveTypeWrapper.FLOAT) { ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.f2l); } else if (src == PrimitiveTypeWrapper.DOUBLE) { ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.d2l); } else { ilgen.Emit(OpCodes.Conv_I8); } } else if (dst == PrimitiveTypeWrapper.BOOLEAN) { if (src == PrimitiveTypeWrapper.FLOAT) { ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.f2i); } else if (src == PrimitiveTypeWrapper.DOUBLE) { ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.d2i); } else { ilgen.Emit(OpCodes.Conv_I4); } ilgen.Emit(OpCodes.Ldc_I4_1); ilgen.Emit(OpCodes.And); } else if (src == PrimitiveTypeWrapper.LONG) { ilgen.Emit(OpCodes.Conv_I4); } else if (src == PrimitiveTypeWrapper.FLOAT) { ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.f2i); } else if (src == PrimitiveTypeWrapper.DOUBLE) { ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.d2i); } } else { BoxUtil.Box(ilgen, srcClass, dstClass, level); } } else if (src.IsGhost) { src.EmitConvSignatureTypeToStackType(ilgen); EmitConvert(ilgen, [email protected] <java.lang.Object> .Value, dstClass, level); } else if (srcClass == [email protected] <sun.invoke.empty.Empty> .Value) { ilgen.Emit(OpCodes.Pop); ilgen.Emit(OpCodes.Ldloc, ilgen.DeclareLocal(dst.TypeAsSignatureType)); } else if (dst.IsPrimitive) { BoxUtil.Unbox(ilgen, srcClass, dstClass, level); } else if (dst.IsGhost) { dst.EmitConvStackTypeToSignatureType(ilgen, null); } else if (dst.IsNonPrimitiveValueType) { dst.EmitUnbox(ilgen); } else { dst.EmitCheckcast(ilgen); } } }