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 static void CreateMethod(CompilerClassLoader loader, TypeBuilder tb, ProxyMethod pm) { MethodBuilder mb = pm.mw.GetDefineMethodHelper().DefineMethod(loader.GetTypeWrapperFactory(), tb, pm.mw.Name, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final); List <string> exceptions = new List <string>(); foreach (TypeWrapper tw in pm.exceptions) { exceptions.Add(tw.Name); } AttributeHelper.SetThrowsAttribute(mb, exceptions.ToArray()); CodeEmitter ilgen = CodeEmitter.Create(mb); ilgen.BeginExceptionBlock(); ilgen.Emit(OpCodes.Ldarg_0); invocationHandlerField.EmitGet(ilgen); ilgen.Emit(OpCodes.Ldarg_0); ilgen.Emit(OpCodes.Ldsfld, pm.fb); TypeWrapper[] parameters = pm.mw.GetParameters(); if (parameters.Length == 0) { ilgen.Emit(OpCodes.Ldnull); } else { ilgen.EmitLdc_I4(parameters.Length); ilgen.Emit(OpCodes.Newarr, Types.Object); for (int i = 0; i < parameters.Length; i++) { ilgen.Emit(OpCodes.Dup); ilgen.EmitLdc_I4(i); ilgen.EmitLdarg(i); if (parameters[i].IsNonPrimitiveValueType) { parameters[i].EmitBox(ilgen); } else if (parameters[i].IsPrimitive) { Boxer.EmitBox(ilgen, parameters[i]); } ilgen.Emit(OpCodes.Stelem_Ref); } } invokeMethod.EmitCallvirt(ilgen); TypeWrapper returnType = pm.mw.ReturnType; CodeEmitterLocal returnValue = null; if (returnType != PrimitiveTypeWrapper.VOID) { returnValue = ilgen.DeclareLocal(returnType.TypeAsSignatureType); if (returnType.IsNonPrimitiveValueType) { returnType.EmitUnbox(ilgen); } else if (returnType.IsPrimitive) { Boxer.EmitUnbox(ilgen, returnType); } else if (returnType != CoreClasses.java.lang.Object.Wrapper) { ilgen.EmitCastclass(returnType.TypeAsSignatureType); } ilgen.Emit(OpCodes.Stloc, returnValue); } CodeEmitterLabel returnLabel = ilgen.DefineLabel(); ilgen.EmitLeave(returnLabel); // TODO consider using a filter here (but we would need to add filter support to CodeEmitter) ilgen.BeginCatchBlock(Types.Exception); ilgen.EmitLdc_I4(0); ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.mapException.MakeGenericMethod(Types.Exception)); CodeEmitterLocal exception = ilgen.DeclareLocal(Types.Exception); ilgen.Emit(OpCodes.Stloc, exception); CodeEmitterLabel rethrow = ilgen.DefineLabel(); ilgen.Emit(OpCodes.Ldloc, exception); errorClass.EmitInstanceOf(ilgen); ilgen.EmitBrtrue(rethrow); ilgen.Emit(OpCodes.Ldloc, exception); runtimeExceptionClass.EmitInstanceOf(ilgen); ilgen.EmitBrtrue(rethrow); foreach (TypeWrapper tw in pm.exceptions) { ilgen.Emit(OpCodes.Ldloc, exception); tw.EmitInstanceOf(ilgen); ilgen.EmitBrtrue(rethrow); } ilgen.Emit(OpCodes.Ldloc, exception); undeclaredThrowableExceptionConstructor.EmitNewobj(ilgen); ilgen.Emit(OpCodes.Throw); ilgen.MarkLabel(rethrow); ilgen.Emit(OpCodes.Rethrow); ilgen.EndExceptionBlock(); ilgen.MarkLabel(returnLabel); if (returnValue != null) { ilgen.Emit(OpCodes.Ldloc, returnValue); } ilgen.Emit(OpCodes.Ret); ilgen.DoEmit(); }
private static bool Unsafe_compareAndSwapObject(EmitIntrinsicContext eic) { TypeWrapper tw = eic.GetStackTypeWrapper(0, 3); if (IsSupportedArrayTypeForUnsafeOperation(tw) && eic.GetStackTypeWrapper(0, 0).IsAssignableTo(tw.ElementTypeWrapper) && eic.GetStackTypeWrapper(0, 1).IsAssignableTo(tw.ElementTypeWrapper)) { Type type = tw.TypeAsLocalOrStackType.GetElementType(); CodeEmitterLocal update = eic.Emitter.AllocTempLocal(type); CodeEmitterLocal expect = eic.Emitter.AllocTempLocal(type); CodeEmitterLocal index = eic.Emitter.AllocTempLocal(Types.Int32); CodeEmitterLocal obj = eic.Emitter.AllocTempLocal(tw.TypeAsLocalOrStackType); eic.Emitter.Emit(OpCodes.Stloc, update); eic.Emitter.Emit(OpCodes.Stloc, expect); 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.Emit(OpCodes.Ldelema, type); eic.Emitter.Emit(OpCodes.Ldloc, update); eic.Emitter.Emit(OpCodes.Ldloc, expect); eic.Emitter.Emit(OpCodes.Call, AtomicReferenceFieldUpdaterEmitter.MakeCompareExchange(type)); eic.Emitter.Emit(OpCodes.Ldloc, expect); eic.Emitter.Emit(OpCodes.Ceq); eic.Emitter.ReleaseTempLocal(obj); eic.Emitter.ReleaseTempLocal(index); eic.Emitter.ReleaseTempLocal(expect); eic.Emitter.ReleaseTempLocal(update); eic.NonLeaf = false; return(true); } if ((eic.Flags[eic.OpcodeIndex] & InstructionFlags.BranchTarget) != 0 || (eic.Flags[eic.OpcodeIndex - 1] & InstructionFlags.BranchTarget) != 0 || (eic.Flags[eic.OpcodeIndex - 2] & InstructionFlags.BranchTarget) != 0) { return(false); } if ((eic.Match(-1, NormalizedByteCode.__aload) || eic.Match(-1, NormalizedByteCode.__aconst_null)) && (eic.Match(-2, NormalizedByteCode.__aload) || eic.Match(-2, NormalizedByteCode.__aconst_null)) && eic.Match(-3, NormalizedByteCode.__getstatic)) { FieldWrapper fw = GetUnsafeField(eic, eic.GetFieldref(-3)); if (fw != null && fw.IsAccessibleFrom(fw.DeclaringType, eic.Caller.DeclaringType, fw.DeclaringType) && eic.GetStackTypeWrapper(0, 0).IsAssignableTo(fw.FieldTypeWrapper) && eic.GetStackTypeWrapper(0, 1).IsAssignableTo(fw.FieldTypeWrapper) && (fw.IsStatic || fw.DeclaringType == eic.GetStackTypeWrapper(0, 3))) { Type type = fw.FieldTypeWrapper.TypeAsLocalOrStackType; CodeEmitterLocal update = eic.Emitter.AllocTempLocal(type); CodeEmitterLocal expect = eic.Emitter.AllocTempLocal(type); eic.Emitter.Emit(OpCodes.Stloc, update); eic.Emitter.Emit(OpCodes.Stloc, expect); eic.Emitter.Emit(OpCodes.Pop); // discard index if (fw.IsStatic) { eic.Emitter.Emit(OpCodes.Pop); // discard obj EmitConsumeUnsafe(eic); eic.Emitter.Emit(OpCodes.Ldsflda, fw.GetField()); } else { CodeEmitterLocal obj = eic.Emitter.AllocTempLocal(eic.Caller.DeclaringType.TypeAsLocalOrStackType); eic.Emitter.Emit(OpCodes.Stloc, obj); EmitConsumeUnsafe(eic); eic.Emitter.Emit(OpCodes.Ldloc, obj); eic.Emitter.ReleaseTempLocal(obj); eic.Emitter.Emit(OpCodes.Ldflda, fw.GetField()); } eic.Emitter.Emit(OpCodes.Ldloc, update); eic.Emitter.Emit(OpCodes.Ldloc, expect); eic.Emitter.Emit(OpCodes.Call, AtomicReferenceFieldUpdaterEmitter.MakeCompareExchange(type)); eic.Emitter.Emit(OpCodes.Ldloc, expect); eic.Emitter.Emit(OpCodes.Ceq); eic.Emitter.ReleaseTempLocal(expect); eic.Emitter.ReleaseTempLocal(update); eic.NonLeaf = false; return(true); } } return(false); }
private static bool Unsafe_putObjectImpl(EmitIntrinsicContext eic, bool membarrier) { TypeWrapper tw = eic.GetStackTypeWrapper(0, 2); if (IsSupportedArrayTypeForUnsafeOperation(tw) && eic.GetStackTypeWrapper(0, 0).IsAssignableTo(tw.ElementTypeWrapper)) { CodeEmitterLocal value = eic.Emitter.AllocTempLocal(tw.ElementTypeWrapper.TypeAsLocalOrStackType); CodeEmitterLocal index = eic.Emitter.AllocTempLocal(Types.Int32); CodeEmitterLocal array = eic.Emitter.AllocTempLocal(tw.TypeAsLocalOrStackType); eic.Emitter.Emit(OpCodes.Stloc, value); eic.Emitter.Emit(OpCodes.Conv_Ovf_I4); eic.Emitter.Emit(OpCodes.Stloc, index); eic.Emitter.Emit(OpCodes.Stloc, array); EmitConsumeUnsafe(eic); eic.Emitter.Emit(OpCodes.Ldloc, array); eic.Emitter.Emit(OpCodes.Ldloc, index); eic.Emitter.Emit(OpCodes.Ldloc, value); eic.Emitter.ReleaseTempLocal(array); eic.Emitter.ReleaseTempLocal(index); eic.Emitter.ReleaseTempLocal(value); eic.Emitter.Emit(OpCodes.Stelem_Ref); if (membarrier) { eic.Emitter.EmitMemoryBarrier(); } eic.NonLeaf = false; return(true); } if ((eic.Flags[eic.OpcodeIndex] & InstructionFlags.BranchTarget) != 0 || (eic.Flags[eic.OpcodeIndex - 1] & InstructionFlags.BranchTarget) != 0) { return(false); } if ((eic.Match(-1, NormalizedByteCode.__aload) || eic.Match(-1, NormalizedByteCode.__aconst_null)) && eic.Match(-2, NormalizedByteCode.__getstatic)) { FieldWrapper fw = GetUnsafeField(eic, eic.GetFieldref(-2)); if (fw != null && (!fw.IsFinal || (!fw.IsStatic && eic.Caller.Name == "<init>") || (fw.IsStatic && eic.Caller.Name == "<clinit>")) && fw.IsAccessibleFrom(fw.DeclaringType, eic.Caller.DeclaringType, fw.DeclaringType) && eic.GetStackTypeWrapper(0, 0).IsAssignableTo(fw.FieldTypeWrapper) && (fw.IsStatic || fw.DeclaringType == eic.GetStackTypeWrapper(0, 2))) { CodeEmitterLocal value = eic.Emitter.AllocTempLocal(fw.FieldTypeWrapper.TypeAsLocalOrStackType); eic.Emitter.Emit(OpCodes.Stloc, value); eic.Emitter.Emit(OpCodes.Pop); // discard offset field if (fw.IsStatic) { eic.Emitter.Emit(OpCodes.Pop); // discard object EmitConsumeUnsafe(eic); } else { CodeEmitterLocal obj = eic.Emitter.AllocTempLocal(fw.DeclaringType.TypeAsLocalOrStackType); eic.Emitter.Emit(OpCodes.Stloc, obj); EmitConsumeUnsafe(eic); eic.Emitter.Emit(OpCodes.Ldloc, obj); eic.Emitter.ReleaseTempLocal(obj); } eic.Emitter.Emit(OpCodes.Ldloc, value); eic.Emitter.ReleaseTempLocal(value); // note that we assume the CLR memory model where all writes are ordered, // so we don't need a volatile store or a memory barrier and putOrderedObject // is typically used with a volatile field, so to avoid the memory barrier, // we don't use FieldWrapper.EmitSet(), but emit the store directly eic.Emitter.Emit(fw.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, fw.GetField()); if (membarrier) { eic.Emitter.EmitMemoryBarrier(); } eic.NonLeaf = false; return(true); } } return(false); }
/** * 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); }