public void Emit(ILOpcode opcode, ILCodeLabel label) { Debug.Assert(opcode == ILOpcode.br || opcode == ILOpcode.brfalse || opcode == ILOpcode.brtrue || opcode == ILOpcode.beq || opcode == ILOpcode.bge || opcode == ILOpcode.bgt || opcode == ILOpcode.ble || opcode == ILOpcode.blt || opcode == ILOpcode.bne_un || opcode == ILOpcode.bge_un || opcode == ILOpcode.bgt_un || opcode == ILOpcode.ble_un || opcode == ILOpcode.blt_un || opcode == ILOpcode.leave); Emit(opcode); _offsetsNeedingPatching.Add(new LabelAndOffset(label, _length)); EmitUInt32(4); }
public LabelAndOffset(ILCodeLabel label, int offset) { Label = label; Offset = offset; }
public override MethodIL EmitIL() { const DelegateThunkKind maxThunkKind = DelegateThunkKind.ObjectArrayThunk; ILEmitter emitter = new ILEmitter(); var codeStream = emitter.NewCodeStream(); ILCodeLabel returnNullLabel = emitter.NewCodeLabel(); ILCodeLabel[] labels = new ILCodeLabel[(int)maxThunkKind]; for (DelegateThunkKind i = 0; i < maxThunkKind; i++) { MethodDesc thunk = _delegateInfo.Thunks[i]; if (thunk != null) labels[(int)i] = emitter.NewCodeLabel(); else labels[(int)i] = returnNullLabel; } codeStream.EmitLdArg(1); codeStream.EmitSwitch(labels); codeStream.Emit(ILOpcode.br, returnNullLabel); for (DelegateThunkKind i = 0; i < maxThunkKind; i++) { MethodDesc thunk = _delegateInfo.Thunks[i]; if (thunk != null) { codeStream.EmitLabel(labels[(int)i]); codeStream.Emit(ILOpcode.ldftn, emitter.NewToken(thunk.InstantiateAsOpen())); codeStream.Emit(ILOpcode.ret); } } codeStream.EmitLabel(returnNullLabel); codeStream.EmitLdc(0); codeStream.Emit(ILOpcode.conv_i); codeStream.Emit(ILOpcode.ret); return emitter.Link(this); }
public void EmitLabel(ILCodeLabel label) { label.Place(this, _length); }
public ILCodeLabel NewCodeLabel() { var newLabel = new ILCodeLabel(); return(newLabel); }
public override MethodIL EmitIL() { ILEmitter emitter = new ILEmitter(); ILCodeStream argSetupStream = emitter.NewCodeStream(); ILCodeStream thisCallSiteSetupStream = emitter.NewCodeStream(); ILCodeStream staticCallSiteSetupStream = emitter.NewCodeStream(); // This function will look like // // !For each parameter to the method // !if (parameter is In Parameter) // localX is TypeOfParameterX& // ldtoken TypeOfParameterX // call DynamicInvokeParamHelperIn(RuntimeTypeHandle) // stloc localX // !else // localX is TypeOfParameter // ldtoken TypeOfParameterX // call DynamicInvokeParamHelperRef(RuntimeTypeHandle) // stloc localX // ldarg.2 // call DynamicInvokeArgSetupComplete(ref ArgSetupState) // *** Thiscall instruction stream starts here *** // ldarg.3 // Load targetIsThisCall // brfalse Not_this_call // ldarg.0 // Load this pointer // !For each parameter // !if (parameter is In Parameter) // ldloc localX // ldobj TypeOfParameterX // !else // ldloc localX // ldarg.1 // calli ReturnType thiscall(TypeOfParameter1, ...) // !if ((ReturnType == void) // ldnull // !else // box ReturnType // ret // *** Static call instruction stream starts here *** // Not_this_call: // !For each parameter // !if (parameter is In Parameter) // ldloc localX // ldobj TypeOfParameterX // !else // ldloc localX // ldarg.1 // calli ReturnType (TypeOfParameter1, ...) // !if ((ReturnType == void) // ldnull // !else // box ReturnType // ret ILCodeLabel lStaticCall = emitter.NewCodeLabel(); thisCallSiteSetupStream.EmitLdArg(3); // targetIsThisCall thisCallSiteSetupStream.Emit(ILOpcode.brfalse, lStaticCall); staticCallSiteSetupStream.EmitLabel(lStaticCall); thisCallSiteSetupStream.EmitLdArg(0); // thisPtr ILToken tokDynamicInvokeParamHelperRef = emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeParamHelperRef", null)); ILToken tokDynamicInvokeParamHelperIn = emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeParamHelperIn", null)); TypeDesc[] targetMethodSignature = new TypeDesc[_targetSignature.Length]; for (int paramIndex = 0; paramIndex < _targetSignature.Length; paramIndex++) { TypeDesc paramType = Context.GetSignatureVariable(paramIndex, true); ILToken tokParamType = emitter.NewToken(paramType); ILLocalVariable local = emitter.NewLocal(paramType.MakeByRefType()); thisCallSiteSetupStream.EmitLdLoc(local); staticCallSiteSetupStream.EmitLdLoc(local); argSetupStream.Emit(ILOpcode.ldtoken, tokParamType); if (_targetSignature[paramIndex] == DynamicInvokeMethodParameterKind.Reference) { argSetupStream.Emit(ILOpcode.call, tokDynamicInvokeParamHelperRef); targetMethodSignature[paramIndex] = paramType.MakeByRefType(); } else { argSetupStream.Emit(ILOpcode.call, tokDynamicInvokeParamHelperIn); thisCallSiteSetupStream.Emit(ILOpcode.ldobj, tokParamType); staticCallSiteSetupStream.Emit(ILOpcode.ldobj, tokParamType); targetMethodSignature[paramIndex] = paramType; } argSetupStream.EmitStLoc(local); } argSetupStream.EmitLdArg(2); // argSetupState argSetupStream.Emit(ILOpcode.call, emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeArgSetupComplete", null))); thisCallSiteSetupStream.EmitLdArg(1); // methodToCall staticCallSiteSetupStream.EmitLdArg(1); // methodToCall TypeDesc returnType = _targetSignature.HasReturnValue ? Context.GetSignatureVariable(_targetSignature.Length, true) : Context.GetWellKnownType(WellKnownType.Void); MethodSignature thisCallMethodSig = new MethodSignature(0, 0, returnType, targetMethodSignature); CalliIntrinsic.EmitTransformedCalli(emitter, thisCallSiteSetupStream, thisCallMethodSig); //thisCallSiteSetupStream.Emit(ILOpcode.calli, emitter.NewToken(thisCallMethodSig)); MethodSignature staticCallMethodSig = new MethodSignature(MethodSignatureFlags.Static, 0, returnType, targetMethodSignature); CalliIntrinsic.EmitTransformedCalli(emitter, staticCallSiteSetupStream, staticCallMethodSig); //staticCallSiteSetupStream.Emit(ILOpcode.calli, emitter.NewToken(staticCallMethodSig)); if (_targetSignature.HasReturnValue) { ILToken tokReturnType = emitter.NewToken(returnType); thisCallSiteSetupStream.Emit(ILOpcode.box, tokReturnType); staticCallSiteSetupStream.Emit(ILOpcode.box, tokReturnType); } else { thisCallSiteSetupStream.Emit(ILOpcode.ldnull); staticCallSiteSetupStream.Emit(ILOpcode.ldnull); } thisCallSiteSetupStream.Emit(ILOpcode.ret); staticCallSiteSetupStream.Emit(ILOpcode.ret); return(emitter.Link(this)); }
public override MethodIL EmitIL() { ILEmitter emitter = new ILEmitter(); var codeStream = emitter.NewCodeStream(); ILCodeLabel returnNullLabel = emitter.NewCodeLabel(); bool hasDynamicInvokeThunk = (_delegateInfo.SupportedFeatures & DelegateFeature.DynamicInvoke) != 0 && DynamicInvokeMethodThunk.SupportsSignature(_delegateInfo.Signature); ILCodeLabel[] labels = new ILCodeLabel[(int)DelegateThunkCollection.MaxThunkKind]; for (DelegateThunkKind i = 0; i < DelegateThunkCollection.MaxThunkKind; i++) { MethodDesc thunk = _delegateInfo.Thunks[i]; if (thunk != null || (i == DelegateThunkKind.DelegateInvokeThunk && hasDynamicInvokeThunk)) { labels[(int)i] = emitter.NewCodeLabel(); } else { labels[(int)i] = returnNullLabel; } } codeStream.EmitLdArg(1); codeStream.EmitSwitch(labels); codeStream.Emit(ILOpcode.br, returnNullLabel); for (DelegateThunkKind i = 0; i < DelegateThunkCollection.MaxThunkKind; i++) { MethodDesc targetMethod = null; // Dynamic invoke thunk is special since we're calling into a shared helper if (i == DelegateThunkKind.DelegateInvokeThunk && hasDynamicInvokeThunk) { Debug.Assert(_delegateInfo.Thunks[i] == null); var sig = new DynamicInvokeMethodSignature(_delegateInfo.Signature); MethodDesc thunk = Context.GetDynamicInvokeThunk(sig); if (thunk.HasInstantiation) { TypeDesc[] inst = DynamicInvokeMethodThunk.GetThunkInstantiationForMethod(_delegateInfo.Type.InstantiateAsOpen().GetMethod("Invoke", null)); targetMethod = Context.GetInstantiatedMethod(thunk, new Instantiation(inst)); } else { targetMethod = thunk; } } else { MethodDesc thunk = _delegateInfo.Thunks[i]; if (thunk != null) { targetMethod = thunk.InstantiateAsOpen(); } } if (targetMethod != null) { codeStream.EmitLabel(labels[(int)i]); codeStream.Emit(ILOpcode.ldftn, emitter.NewToken(targetMethod)); codeStream.Emit(ILOpcode.ret); } } codeStream.EmitLabel(returnNullLabel); codeStream.EmitLdc(0); codeStream.Emit(ILOpcode.conv_i); codeStream.Emit(ILOpcode.ret); return(emitter.Link(this)); }
/// <summary> /// Marshals a string. Expects the string reference on the stack. Pushes a pointer /// to the stack that is safe to pass out to native code. /// </summary> /// <returns>The type the string was marshalled into.</returns> private TypeDesc EmitStringMarshalling() { PInvokeAttributes charset = _importMetadata.Attributes & PInvokeAttributes.CharSetMask; TypeSystemContext context = _targetMethod.Context; if (charset == 0) { // ECMA-335 II.10.1.5 - Default value is Ansi. charset = PInvokeAttributes.CharSetAnsi; } if (charset == PInvokeAttributes.CharSetAuto) { charset = PInvokeAttributes.CharSetUnicode; } TypeDesc stringType = context.GetWellKnownType(WellKnownType.String); if (charset == PInvokeAttributes.CharSetUnicode) { // // Unicode marshalling. Pin the string and push a pointer to the first character on the stack. // ILLocalVariable vPinnedString = _emitter.NewLocal(stringType, true); ILCodeLabel lNullString = _emitter.NewCodeLabel(); _marshallingCodeStream.EmitStLoc(vPinnedString); _marshallingCodeStream.EmitLdLoc(vPinnedString); _marshallingCodeStream.Emit(ILOpcode.conv_i); _marshallingCodeStream.Emit(ILOpcode.dup); // Marshalling a null string? _marshallingCodeStream.Emit(ILOpcode.brfalse, lNullString); // TODO: find a safe, non-awkward way to get to OffsetToStringData _marshallingCodeStream.EmitLdc(context.Target.PointerSize + 4); _marshallingCodeStream.Emit(ILOpcode.add); _marshallingCodeStream.EmitLabel(lNullString); } else { // // ANSI marshalling. Allocate a byte array, copy characters, pin first element. // TypeDesc byteType = context.GetWellKnownType(WellKnownType.Byte); TypeDesc byteArrayType = byteType.MakeArrayType(); MethodDesc getLengthMethod = stringType.GetMethod("get_Length", null); MethodDesc getCharsMethod = stringType.GetMethod("get_Chars", null); ILCodeLabel lStart = _emitter.NewCodeLabel(); ILCodeLabel lNext = _emitter.NewCodeLabel(); ILCodeLabel lNullString = _emitter.NewCodeLabel(); ILCodeLabel lDone = _emitter.NewCodeLabel(); // Check for the simple case: string is null ILLocalVariable vStringToMarshal = _emitter.NewLocal(stringType); _marshallingCodeStream.EmitStLoc(vStringToMarshal); _marshallingCodeStream.EmitLdLoc(vStringToMarshal); _marshallingCodeStream.Emit(ILOpcode.brfalse, lNullString); // TODO: figure out how to reference a helper from here and call the helper instead... // byte[] byteArray = new byte[stringToMarshal.Length + 1]; _marshallingCodeStream.EmitLdLoc(vStringToMarshal); _marshallingCodeStream.Emit(ILOpcode.call, _emitter.NewToken(getLengthMethod)); _marshallingCodeStream.EmitLdc(1); _marshallingCodeStream.Emit(ILOpcode.add); _marshallingCodeStream.Emit(ILOpcode.newarr, _emitter.NewToken(byteType)); ILLocalVariable vByteArray = _emitter.NewLocal(byteArrayType); _marshallingCodeStream.EmitStLoc(vByteArray); // for (int i = 0; i < byteArray.Length - 1; i++) // byteArray[i] = (byte)stringToMarshal[i]; ILLocalVariable vIterator = _emitter.NewLocal(context.GetWellKnownType(WellKnownType.Int32)); _marshallingCodeStream.Emit(ILOpcode.ldc_i4_0); _marshallingCodeStream.EmitStLoc(vIterator); _marshallingCodeStream.Emit(ILOpcode.br, lStart); _marshallingCodeStream.EmitLabel(lNext); _marshallingCodeStream.EmitLdLoc(vByteArray); _marshallingCodeStream.EmitLdLoc(vIterator); _marshallingCodeStream.EmitLdLoc(vStringToMarshal); _marshallingCodeStream.EmitLdLoc(vIterator); _marshallingCodeStream.Emit(ILOpcode.call, _emitter.NewToken(getCharsMethod)); _marshallingCodeStream.Emit(ILOpcode.conv_u1); _marshallingCodeStream.Emit(ILOpcode.stelem_i1); _marshallingCodeStream.EmitLdLoc(vIterator); _marshallingCodeStream.EmitLdc(1); _marshallingCodeStream.Emit(ILOpcode.add); _marshallingCodeStream.EmitStLoc(vIterator); _marshallingCodeStream.EmitLabel(lStart); _marshallingCodeStream.EmitLdLoc(vIterator); _marshallingCodeStream.EmitLdLoc(vByteArray); _marshallingCodeStream.Emit(ILOpcode.ldlen); _marshallingCodeStream.Emit(ILOpcode.conv_i4); _marshallingCodeStream.EmitLdc(1); _marshallingCodeStream.Emit(ILOpcode.sub); _marshallingCodeStream.Emit(ILOpcode.blt, lNext); _marshallingCodeStream.EmitLdLoc(vByteArray); // Pin first element and load the byref on the stack. _marshallingCodeStream.EmitLdc(0); _marshallingCodeStream.Emit(ILOpcode.ldelema, _emitter.NewToken(byteType)); ILLocalVariable vPinnedFirstElement = _emitter.NewLocal(byteArrayType.MakeByRefType(), true); _marshallingCodeStream.EmitStLoc(vPinnedFirstElement); _marshallingCodeStream.EmitLdLoc(vPinnedFirstElement); _marshallingCodeStream.Emit(ILOpcode.conv_i); _marshallingCodeStream.Emit(ILOpcode.br, lDone); _marshallingCodeStream.EmitLabel(lNullString); _marshallingCodeStream.Emit(ILOpcode.ldnull); _marshallingCodeStream.Emit(ILOpcode.conv_i); _marshallingCodeStream.EmitLabel(lDone); } return(_targetMethod.Context.GetWellKnownType(WellKnownType.IntPtr)); }
private MethodIL EmitIL() { if (_targetMethod.HasCustomAttribute("System.Runtime.InteropServices", "LCIDConversionAttribute")) { throw new NotSupportedException(); } PInvokeILCodeStreams pInvokeILCodeStreams = new PInvokeILCodeStreams(); ILEmitter emitter = pInvokeILCodeStreams.Emitter; ILCodeStream marshallingCodestream = pInvokeILCodeStreams.MarshallingCodeStream; ILCodeStream unmarshallingCodestream = pInvokeILCodeStreams.UnmarshallingCodestream; ILCodeStream cleanupCodestream = pInvokeILCodeStreams.CleanupCodeStream; // Marshalling is wrapped in a finally block to guarantee cleanup ILExceptionRegionBuilder tryFinally = emitter.NewFinallyRegion(); marshallingCodestream.BeginTry(tryFinally); cleanupCodestream.BeginHandler(tryFinally); // Marshal the arguments bool isHRSwappedRetVal = !_flags.PreserveSig && !_targetMethod.Signature.ReturnType.IsVoid; for (int i = isHRSwappedRetVal ? 1 : 0; i < _marshallers.Length; i++) { _marshallers[i].EmitMarshallingIL(pInvokeILCodeStreams); } if (isHRSwappedRetVal) { _marshallers[0].EmitMarshallingIL(pInvokeILCodeStreams); } // make the call switch (_targetMethod) { case DelegateMarshallingMethodThunk delegateMethod: EmitDelegateCall(delegateMethod, pInvokeILCodeStreams); break; case CalliMarshallingMethodThunk calliMethod: EmitCalli(pInvokeILCodeStreams, calliMethod); break; default: EmitPInvokeCall(pInvokeILCodeStreams); break; } ILCodeLabel lReturn = emitter.NewCodeLabel(); unmarshallingCodestream.Emit(ILOpcode.leave, lReturn); unmarshallingCodestream.EndTry(tryFinally); cleanupCodestream.Emit(ILOpcode.endfinally); cleanupCodestream.EndHandler(tryFinally); cleanupCodestream.EmitLabel(lReturn); _marshallers[0].LoadReturnValue(cleanupCodestream); cleanupCodestream.Emit(ILOpcode.ret); return(new PInvokeILStubMethodIL((ILStubMethodIL)emitter.Link(_targetMethod), IsStubRequired())); }
public override MethodIL EmitIL() { // We will generate the following code: // // object ret; // object[] args = new object[parameterCount]; // args[0] = param0; // args[1] = param1; // ... // try { // ret = ((Func<object[], object>)dlg.m_helperObject)(args); // } finally { // param0 = (T0)args[0]; // only generated for each byref argument // } // return (TRet)ret; ILEmitter emitter = new ILEmitter(); ILCodeStream codeStream = emitter.NewCodeStream(); TypeDesc objectType = Context.GetWellKnownType(WellKnownType.Object); TypeDesc objectArrayType = objectType.MakeArrayType(); ILLocalVariable argsLocal = emitter.NewLocal(objectArrayType); bool hasReturnValue = !Signature.ReturnType.IsVoid; bool hasRefArgs = false; if (Signature.Length > 0) { codeStream.EmitLdc(Signature.Length); codeStream.Emit(ILOpcode.newarr, emitter.NewToken(objectType)); codeStream.EmitStLoc(argsLocal); for (int i = 0; i < Signature.Length; i++) { TypeDesc paramType = Signature[i]; bool paramIsByRef = false; if (paramType.IsByRef) { hasRefArgs |= paramType.IsByRef; paramIsByRef = true; paramType = ((ByRefType)paramType).ParameterType; } hasRefArgs |= paramType.IsByRef; codeStream.EmitLdLoc(argsLocal); codeStream.EmitLdc(i); codeStream.EmitLdArg(i + 1); ILToken paramToken = emitter.NewToken(paramType); if (paramIsByRef) { codeStream.Emit(ILOpcode.ldobj, paramToken); } codeStream.Emit(ILOpcode.box, paramToken); codeStream.Emit(ILOpcode.stelem_ref); } } else { MethodDesc emptyObjectArrayMethod = Context.GetHelperEntryPoint("DelegateHelpers", "GetEmptyObjectArray"); codeStream.Emit(ILOpcode.call, emitter.NewToken(emptyObjectArrayMethod)); codeStream.EmitStLoc(argsLocal); } ILExceptionRegionBuilder tryFinallyRegion = null; if (hasRefArgs) { // we emit a try/finally to update the args array even if an exception is thrown tryFinallyRegion = emitter.NewFinallyRegion(); codeStream.BeginTry(tryFinallyRegion); } codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(HelperObjectField)); MetadataType funcType = Context.SystemModule.GetKnownType("System", "Func`2"); TypeDesc instantiatedFunc = funcType.MakeInstantiatedType(objectArrayType, objectType); codeStream.Emit(ILOpcode.castclass, emitter.NewToken(instantiatedFunc)); codeStream.EmitLdLoc(argsLocal); MethodDesc invokeMethod = instantiatedFunc.GetKnownMethod("Invoke", null); codeStream.Emit(ILOpcode.callvirt, emitter.NewToken(invokeMethod)); ILLocalVariable retLocal = (ILLocalVariable)(-1); if (hasReturnValue) { retLocal = emitter.NewLocal(objectType); codeStream.EmitStLoc(retLocal); } else { codeStream.Emit(ILOpcode.pop); } if (hasRefArgs) { ILCodeLabel returnLabel = emitter.NewCodeLabel(); codeStream.Emit(ILOpcode.leave, returnLabel); codeStream.EndTry(tryFinallyRegion); // copy back ref/out args codeStream.BeginHandler(tryFinallyRegion); for (int i = 0; i < Signature.Length; i++) { TypeDesc paramType = Signature[i]; if (paramType.IsByRef) { paramType = ((ByRefType)paramType).ParameterType; ILToken paramToken = emitter.NewToken(paramType); // Update parameter codeStream.EmitLdArg(i + 1); codeStream.EmitLdLoc(argsLocal); codeStream.EmitLdc(i); codeStream.Emit(ILOpcode.ldelem_ref); codeStream.Emit(ILOpcode.unbox_any, paramToken); codeStream.Emit(ILOpcode.stobj, paramToken); } } codeStream.Emit(ILOpcode.endfinally); codeStream.EndHandler(tryFinallyRegion); codeStream.EmitLabel(returnLabel); } if (hasReturnValue) { codeStream.EmitLdLoc(retLocal); codeStream.Emit(ILOpcode.unbox_any, emitter.NewToken(Signature.ReturnType)); } codeStream.Emit(ILOpcode.ret); return(emitter.Link(this)); }
public override MethodIL EmitIL() { TypeDesc owningType = _owningType.InstantiateAsOpen(); ILEmitter emitter = new ILEmitter(); TypeDesc eeTypePtrType = Context.SystemModule.GetKnownType("System", "EETypePtr"); MethodDesc eeTypePtrOfMethod = eeTypePtrType.GetKnownMethod("EETypePtrOf", null); ILToken eeTypePtrToken = emitter.NewToken(eeTypePtrType); var switchStream = emitter.NewCodeStream(); var getFieldStream = emitter.NewCodeStream(); ArrayBuilder <ILCodeLabel> fieldGetters = new ArrayBuilder <ILCodeLabel>(); foreach (FieldDesc field in owningType.GetFields()) { if (field.IsStatic) { continue; } ILCodeLabel label = emitter.NewCodeLabel(); fieldGetters.Add(label); getFieldStream.EmitLabel(label); getFieldStream.EmitLdArg(2); // We need something we can instantiate EETypePtrOf over. Also, the classlib // code doesn't handle pointers. TypeDesc boxableFieldType = field.FieldType; if (boxableFieldType.IsPointer || boxableFieldType.IsFunctionPointer) { boxableFieldType = Context.GetWellKnownType(WellKnownType.IntPtr); } MethodDesc ptrOfField = eeTypePtrOfMethod.MakeInstantiatedMethod(boxableFieldType); getFieldStream.Emit(ILOpcode.call, emitter.NewToken(ptrOfField)); getFieldStream.Emit(ILOpcode.stobj, eeTypePtrToken); getFieldStream.EmitLdArg(0); getFieldStream.Emit(ILOpcode.ldflda, emitter.NewToken(field)); getFieldStream.EmitLdArg(0); getFieldStream.Emit(ILOpcode.sub); getFieldStream.Emit(ILOpcode.ret); } if (fieldGetters.Count > 0) { switchStream.EmitLdArg(1); switchStream.EmitSwitch(fieldGetters.ToArray()); } switchStream.EmitLdc(fieldGetters.Count); switchStream.Emit(ILOpcode.ret); return(emitter.Link(this)); }
private void EmitILForAccessor() { Debug.Assert(_method.OwningType.IsMdArray); var codeStream = _emitter.NewCodeStream(); var context = _method.Context; var int32Type = context.GetWellKnownType(WellKnownType.Int32); var totalLocalNum = _emitter.NewLocal(int32Type); var lengthLocalNum = _emitter.NewLocal(int32Type); int pointerSize = context.Target.PointerSize; int argStartOffset = _method.Kind == ArrayMethodKind.AddressWithHiddenArg ? 2 : 1; var rangeExceptionLabel = _emitter.NewCodeLabel(); ILCodeLabel typeMismatchExceptionLabel = null; if (_elementType.IsGCPointer) { // Type check if (_method.Kind == ArrayMethodKind.Set) { MethodDesc checkArrayStore = context.SystemModule.GetKnownType("System.Runtime", "RuntimeImports").GetKnownMethod("RhCheckArrayStore", null); codeStream.EmitLdArg(0); codeStream.EmitLdArg(_rank + argStartOffset); codeStream.Emit(ILOpcode.call, _emitter.NewToken(checkArrayStore)); } else if (_method.Kind == ArrayMethodKind.AddressWithHiddenArg) { TypeDesc objectType = context.GetWellKnownType(WellKnownType.Object); TypeDesc eetypePtrType = context.SystemModule.GetKnownType("System", "EETypePtr"); typeMismatchExceptionLabel = _emitter.NewCodeLabel(); ILLocalVariable thisEEType = _emitter.NewLocal(eetypePtrType); ILCodeLabel typeCheckPassedLabel = _emitter.NewCodeLabel(); // Codegen will pass a null hidden argument if this is a `constrained.` call to the Address method. // As per ECMA-335 III.2.3, the prefix suppresses the type check. // if (hiddenArg.IsNull) // goto TypeCheckPassed; codeStream.EmitLdArga(1); codeStream.Emit(ILOpcode.call, _emitter.NewToken(eetypePtrType.GetKnownMethod("get_IsNull", null))); codeStream.Emit(ILOpcode.brtrue, typeCheckPassedLabel); // EETypePtr actualElementType = this.EETypePtr.ArrayElementType; codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.call, _emitter.NewToken(objectType.GetKnownMethod("get_EETypePtr", null))); codeStream.EmitStLoc(thisEEType); codeStream.EmitLdLoca(thisEEType); codeStream.Emit(ILOpcode.call, _emitter.NewToken(eetypePtrType.GetKnownMethod("get_ArrayElementType", null))); // EETypePtr expectedElementType = hiddenArg.ArrayElementType; codeStream.EmitLdArga(1); codeStream.Emit(ILOpcode.call, _emitter.NewToken(eetypePtrType.GetKnownMethod("get_ArrayElementType", null))); // if (expectedElementType != actualElementType) // ThrowHelpers.ThrowArrayTypeMismatchException(); codeStream.Emit(ILOpcode.call, _emitter.NewToken(eetypePtrType.GetKnownMethod("op_Equality", null))); codeStream.Emit(ILOpcode.brfalse, typeMismatchExceptionLabel); codeStream.EmitLabel(typeCheckPassedLabel); } } // Methods on Rank 1 MdArray need to be able to handle `this` that is an SzArray // because SzArray is castable to Rank 1 MdArray (but not the other way around). ILCodeLabel rangeCheckDoneLabel = null; if (_rank == 1) { TypeDesc objectType = context.GetWellKnownType(WellKnownType.Object); TypeDesc eetypePtrType = context.SystemModule.GetKnownType("System", "EETypePtr"); ILLocalVariable thisEEType = _emitter.NewLocal(eetypePtrType); codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.call, _emitter.NewToken(objectType.GetKnownMethod("get_EETypePtr", null))); codeStream.EmitStLoc(thisEEType); codeStream.EmitLdLoca(thisEEType); codeStream.Emit(ILOpcode.call, _emitter.NewToken(eetypePtrType.GetKnownMethod("get_IsSzArray", null))); ILCodeLabel notSzArrayLabel = _emitter.NewCodeLabel(); codeStream.Emit(ILOpcode.brfalse, notSzArrayLabel); // We have an SzArray - do the bounds check differently EmitLoadInteriorAddress(codeStream, pointerSize); codeStream.Emit(ILOpcode.dup); codeStream.Emit(ILOpcode.ldind_i4); codeStream.EmitLdArg(argStartOffset); codeStream.EmitStLoc(totalLocalNum); codeStream.EmitLdLoc(totalLocalNum); codeStream.Emit(ILOpcode.ble_un, rangeExceptionLabel); codeStream.EmitLdc(pointerSize); codeStream.Emit(ILOpcode.add); rangeCheckDoneLabel = _emitter.NewCodeLabel(); codeStream.Emit(ILOpcode.br, rangeCheckDoneLabel); codeStream.EmitLabel(notSzArrayLabel); } for (int i = 0; i < _rank; i++) { // The first two fields are EEType pointer and total length. Lengths for each dimension follows. int lengthOffset = (2 * pointerSize + i * sizeof(int)); EmitLoadInteriorAddress(codeStream, lengthOffset); codeStream.Emit(ILOpcode.ldind_i4); codeStream.EmitStLoc(lengthLocalNum); codeStream.EmitLdArg(i + argStartOffset); // Compare with length codeStream.Emit(ILOpcode.dup); codeStream.EmitLdLoc(lengthLocalNum); codeStream.Emit(ILOpcode.bge_un, rangeExceptionLabel); // Add to the running total if we have one already if (i > 0) { codeStream.EmitLdLoc(totalLocalNum); codeStream.EmitLdLoc(lengthLocalNum); codeStream.Emit(ILOpcode.mul); codeStream.Emit(ILOpcode.add); } codeStream.EmitStLoc(totalLocalNum); } // Compute element offset // TODO: This leaves unused space for lower bounds to match CoreCLR... int firstElementOffset = (2 * pointerSize + 2 * _rank * sizeof(int)); EmitLoadInteriorAddress(codeStream, firstElementOffset); if (rangeCheckDoneLabel != null) { codeStream.EmitLabel(rangeCheckDoneLabel); } codeStream.EmitLdLoc(totalLocalNum); codeStream.Emit(ILOpcode.conv_u); int elementSize = _elementType.GetElementSize().AsInt; if (elementSize != 1) { codeStream.EmitLdc(elementSize); codeStream.Emit(ILOpcode.mul); } codeStream.Emit(ILOpcode.add); switch (_method.Kind) { case ArrayMethodKind.Get: codeStream.Emit(ILOpcode.ldobj, _emitter.NewToken(_elementType)); break; case ArrayMethodKind.Set: codeStream.EmitLdArg(_rank + argStartOffset); codeStream.Emit(ILOpcode.stobj, _emitter.NewToken(_elementType)); break; case ArrayMethodKind.AddressWithHiddenArg: break; } codeStream.Emit(ILOpcode.ret); codeStream.EmitLdc(0); codeStream.EmitLabel(rangeExceptionLabel); // Assumes that there is one "int" pushed on the stack codeStream.Emit(ILOpcode.pop); MethodDesc throwHelper = context.GetHelperEntryPoint("ThrowHelpers", "ThrowIndexOutOfRangeException"); codeStream.EmitCallThrowHelper(_emitter, throwHelper); if (typeMismatchExceptionLabel != null) { codeStream.EmitLabel(typeMismatchExceptionLabel); codeStream.EmitCallThrowHelper(_emitter, context.GetHelperEntryPoint("ThrowHelpers", "ThrowArrayTypeMismatchException")); } }
public override MethodIL EmitIL() { ILEmitter emitter = new ILEmitter(); ILCodeStream argSetupStream = emitter.NewCodeStream(); ILCodeStream thisCallSiteSetupStream = emitter.NewCodeStream(); ILCodeStream staticCallSiteSetupStream = emitter.NewCodeStream(); ILCodeStream returnCodeStream = emitter.NewCodeStream(); // This function will look like // // !For each parameter to the method // !if (parameter is In Parameter) // localX is TypeOfParameterX& // ldarg.2 // ldtoken TypeOfParameterX // call DynamicInvokeParamHelperIn(ref ArgSetupState, RuntimeTypeHandle) // stloc localX // !else // localX is TypeOfParameter // ldarg.2 // ldtoken TypeOfParameterX // call DynamicInvokeParamHelperRef(ref ArgSetupState, RuntimeTypeHandle) // stloc localX // ldarg.2 // call DynamicInvokeArgSetupComplete(ref ArgSetupState) // *** Thiscall instruction stream starts here *** // ldarg.3 // Load targetIsThisCall // brfalse Not_this_call // ldarg.0 // Load this pointer // !For each parameter // !if (parameter is In Parameter) // ldloc localX // ldobj TypeOfParameterX // !else // ldloc localX // ldarg.1 // calli ReturnType thiscall(TypeOfParameter1, ...) // br Process_return // *** Static call instruction stream starts here *** // Not_this_call: // !For each parameter // !if (parameter is In Parameter) // ldloc localX // ldobj TypeOfParameterX // !else // ldloc localX // ldarg.1 // calli ReturnType (TypeOfParameter1, ...) // *** Return code stream starts here *** // Process_return: // !if (ReturnType is Byref) // dup // brfalse ByRefNull // ldobj ReturnType // !if ((ReturnType == void) // ldnull // !elif (ReturnType is pointer) // System.Reflection.Pointer.Box(ReturnType) // !else // box ReturnType // ret // // !if (ReturnType is ByRef) // ByRefNull: // pop // call InvokeUtils.get_NullByRefValueSentinel // ret ILCodeLabel lStaticCall = emitter.NewCodeLabel(); ILCodeLabel lProcessReturn = emitter.NewCodeLabel(); thisCallSiteSetupStream.EmitLdArg(3); // targetIsThisCall thisCallSiteSetupStream.Emit(ILOpcode.brfalse, lStaticCall); staticCallSiteSetupStream.EmitLabel(lStaticCall); thisCallSiteSetupStream.EmitLdArg(0); // thisPtr ILToken tokDynamicInvokeParamHelperRef = emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeParamHelperRef", null)); ILToken tokDynamicInvokeParamHelperIn = emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeParamHelperIn", null)); TypeDesc[] targetMethodSignature = new TypeDesc[_targetSignature.Length]; for (int paramIndex = 0; paramIndex < _targetSignature.Length; paramIndex++) { TypeDesc paramType = Context.GetSignatureVariable(paramIndex, true); DynamicInvokeMethodParameterKind paramKind = _targetSignature[paramIndex]; for (int i = 0; i < _targetSignature.GetNumberOfParameterPointerIndirections(paramIndex); i++) { paramType = paramType.MakePointerType(); } ILToken tokParamType = emitter.NewToken(paramType); ILLocalVariable local = emitter.NewLocal(paramType.MakeByRefType()); thisCallSiteSetupStream.EmitLdLoc(local); staticCallSiteSetupStream.EmitLdLoc(local); argSetupStream.EmitLdArg(2); // argSetupState argSetupStream.Emit(ILOpcode.ldtoken, tokParamType); if (paramKind == DynamicInvokeMethodParameterKind.Reference) { argSetupStream.Emit(ILOpcode.call, tokDynamicInvokeParamHelperRef); targetMethodSignature[paramIndex] = paramType.MakeByRefType(); } else { argSetupStream.Emit(ILOpcode.call, tokDynamicInvokeParamHelperIn); thisCallSiteSetupStream.EmitLdInd(paramType); staticCallSiteSetupStream.EmitLdInd(paramType); targetMethodSignature[paramIndex] = paramType; } argSetupStream.EmitStLoc(local); } argSetupStream.EmitLdArg(2); // argSetupState argSetupStream.Emit(ILOpcode.call, emitter.NewToken(InvokeUtilsType.GetKnownMethod("DynamicInvokeArgSetupComplete", null))); thisCallSiteSetupStream.EmitLdArg(1); // methodToCall staticCallSiteSetupStream.EmitLdArg(1); // methodToCall DynamicInvokeMethodParameterKind returnKind = _targetSignature.ReturnType; TypeDesc returnType = returnKind != DynamicInvokeMethodParameterKind.None ? Context.GetSignatureVariable(_targetSignature.Length, true) : Context.GetWellKnownType(WellKnownType.Void); for (int i = 0; i < _targetSignature.GetNumerOfReturnTypePointerIndirections(); i++) { returnType = returnType.MakePointerType(); } if (returnKind == DynamicInvokeMethodParameterKind.Reference) { returnType = returnType.MakeByRefType(); } MethodSignature thisCallMethodSig = new MethodSignature(0, 0, returnType, targetMethodSignature); thisCallSiteSetupStream.Emit(ILOpcode.calli, emitter.NewToken(thisCallMethodSig)); thisCallSiteSetupStream.Emit(ILOpcode.br, lProcessReturn); MethodSignature staticCallMethodSig = new MethodSignature(MethodSignatureFlags.Static, 0, returnType, targetMethodSignature); staticCallSiteSetupStream.Emit(ILOpcode.calli, emitter.NewToken(staticCallMethodSig)); returnCodeStream.EmitLabel(lProcessReturn); ILCodeLabel lByRefReturnNull = null; if (returnKind == DynamicInvokeMethodParameterKind.None) { returnCodeStream.Emit(ILOpcode.ldnull); } else { TypeDesc returnTypeForBoxing = returnType; if (returnType.IsByRef) { // If this is a byref return, we need to dereference first returnTypeForBoxing = ((ByRefType)returnType).ParameterType; lByRefReturnNull = emitter.NewCodeLabel(); returnCodeStream.Emit(ILOpcode.dup); returnCodeStream.Emit(ILOpcode.brfalse, lByRefReturnNull); returnCodeStream.EmitLdInd(returnTypeForBoxing); } if (returnTypeForBoxing.IsPointer) { // Pointers box differently returnCodeStream.Emit(ILOpcode.ldtoken, emitter.NewToken(returnTypeForBoxing)); MethodDesc getTypeFromHandleMethod = Context.SystemModule.GetKnownType("System", "Type").GetKnownMethod("GetTypeFromHandle", null); returnCodeStream.Emit(ILOpcode.call, emitter.NewToken(getTypeFromHandleMethod)); MethodDesc pointerBoxMethod = Context.SystemModule.GetKnownType("System.Reflection", "Pointer").GetKnownMethod("Box", null); returnCodeStream.Emit(ILOpcode.call, emitter.NewToken(pointerBoxMethod)); } else { ILToken tokReturnType = emitter.NewToken(returnTypeForBoxing); returnCodeStream.Emit(ILOpcode.box, tokReturnType); } } returnCodeStream.Emit(ILOpcode.ret); if (lByRefReturnNull != null) { returnCodeStream.EmitLabel(lByRefReturnNull); returnCodeStream.Emit(ILOpcode.pop); returnCodeStream.Emit(ILOpcode.call, emitter.NewToken(InvokeUtilsType.GetKnownMethod("get_NullByRefValueSentinel", null))); returnCodeStream.Emit(ILOpcode.ret); } return(emitter.Link(this)); }
public void EmitSwitch(ILCodeLabel[] labels) { Emit(ILOpcode.switch_); EmitUInt32(labels.Length); int remainingBytes = labels.Length * 4; foreach (var label in labels) { _offsetsNeedingPatching.Add(new LabelAndOffset(label, _length)); EmitUInt32(remainingBytes); remainingBytes -= 4; } }
public override MethodIL EmitIL() { ILEmitter emitter = new ILEmitter(); ILCodeStream codeStream = emitter.NewCodeStream(); ArrayType invocationListArrayType = SystemDelegateType.MakeArrayType(); ILLocalVariable delegateArrayLocal = emitter.NewLocal(invocationListArrayType); ILLocalVariable invocationCountLocal = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); ILLocalVariable iteratorLocal = emitter.NewLocal(Context.GetWellKnownType(WellKnownType.Int32)); ILLocalVariable delegateToCallLocal = emitter.NewLocal(SystemDelegateType); ILLocalVariable returnValueLocal = 0; if (Signature.ReturnType.IsSignatureVariable || !Signature.ReturnType.IsVoid) { returnValueLocal = emitter.NewLocal(Signature.ReturnType); } // Fill in delegateArrayLocal // Delegate[] delegateArrayLocal = (Delegate[])this.m_helperObject // ldarg.0 (this pointer) // ldfld Delegate.HelperObjectField // castclass Delegate[] // stloc delegateArrayLocal codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(HelperObjectField)); codeStream.Emit(ILOpcode.castclass, emitter.NewToken(invocationListArrayType)); codeStream.EmitStLoc(delegateArrayLocal); // Fill in invocationCountLocal // int invocationCountLocal = this.m_extraFunctionPointerOrData // ldarg.0 (this pointer) // ldfld Delegate.m_extraFunctionPointerOrData // stloc invocationCountLocal codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(ExtraFunctionPointerOrDataField)); codeStream.EmitStLoc(invocationCountLocal); // Fill in iteratorLocal // int iteratorLocal = 0; // ldc.0 // stloc iteratorLocal codeStream.EmitLdc(0); codeStream.EmitStLoc(iteratorLocal); // Loop across every element of the array. ILCodeLabel startOfLoopLabel = emitter.NewCodeLabel(); codeStream.EmitLabel(startOfLoopLabel); // Implement as do/while loop. We only have this stub in play if we're in the multicast situation // Find the delegate to call // Delegate = delegateToCallLocal = delegateArrayLocal[iteratorLocal]; // ldloc delegateArrayLocal // ldloc iteratorLocal // ldelem System.Delegate // stloc delegateToCallLocal codeStream.EmitLdLoc(delegateArrayLocal); codeStream.EmitLdLoc(iteratorLocal); codeStream.Emit(ILOpcode.ldelem, emitter.NewToken(SystemDelegateType)); codeStream.EmitStLoc(delegateToCallLocal); // Call the delegate // returnValueLocal = delegateToCallLocal(...); // ldloc delegateToCallLocal // ldfld System.Delegate.m_firstParameter // ldarg 1, n // ldloc delegateToCallLocal // ldfld System.Delegate.m_functionPointer // calli returnValueType thiscall (all the params) // IF there is a return value // stloc returnValueLocal codeStream.EmitLdLoc(delegateToCallLocal); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(FirstParameterField)); for (int i = 0; i < Signature.Length; i++) { codeStream.EmitLdArg(i + 1); } codeStream.EmitLdLoc(delegateToCallLocal); codeStream.Emit(ILOpcode.ldfld, emitter.NewToken(FunctionPointerField)); codeStream.Emit(ILOpcode.calli, emitter.NewToken(Signature)); if (returnValueLocal != 0) { codeStream.EmitStLoc(returnValueLocal); } // Increment iteratorLocal // ++iteratorLocal; // ldloc iteratorLocal // ldc.i4.1 // add // stloc iteratorLocal codeStream.EmitLdLoc(iteratorLocal); codeStream.EmitLdc(1); codeStream.Emit(ILOpcode.add); codeStream.EmitStLoc(iteratorLocal); // Check to see if the loop is done codeStream.EmitLdLoc(invocationCountLocal); codeStream.EmitLdLoc(iteratorLocal); codeStream.Emit(ILOpcode.bne_un, startOfLoopLabel); // Return to caller. If the delegate has a return value, be certain to return that. // return returnValueLocal; // ldloc returnValueLocal // ret if (returnValueLocal != 0) { codeStream.EmitLdLoc(returnValueLocal); } codeStream.Emit(ILOpcode.ret); return(emitter.Link(this)); }
private void EmitILForAccessor() { Debug.Assert(!_method.OwningType.IsSzArray); var codeStream = _emitter.NewCodeStream(); var context = _method.Context; var int32Type = context.GetWellKnownType(WellKnownType.Int32); var totalLocalNum = _emitter.NewLocal(int32Type); var lengthLocalNum = _emitter.NewLocal(int32Type); int pointerSize = context.Target.PointerSize; var rangeExceptionLabel = _emitter.NewCodeLabel(); ILCodeLabel typeMismatchExceptionLabel = null; if (!_elementType.IsValueType) { // Type check if (_method.Kind == ArrayMethodKind.Set) { MethodDesc checkArrayStore = context.SystemModule.GetKnownType("System.Runtime", "RuntimeImports").GetKnownMethod("RhCheckArrayStore", null); codeStream.EmitLdArg(0); codeStream.EmitLdArg(_rank + 1); codeStream.Emit(ILOpcode.call, _emitter.NewToken(checkArrayStore)); } else if (_method.Kind == ArrayMethodKind.Address) { TypeDesc objectType = context.GetWellKnownType(WellKnownType.Object); TypeDesc eetypePtrType = context.SystemModule.GetKnownType("System", "EETypePtr"); MethodDesc eetypePtrOfMethod = eetypePtrType.GetKnownMethod("EETypePtrOf", null) .MakeInstantiatedMethod(new Instantiation(new[] { _elementType })); typeMismatchExceptionLabel = _emitter.NewCodeLabel(); ILLocalVariable thisEEType = _emitter.NewLocal(eetypePtrType); // EETypePtr actualElementType = this.EETypePtr.ArrayElementType; codeStream.EmitLdArg(0); codeStream.Emit(ILOpcode.call, _emitter.NewToken(objectType.GetKnownMethod("get_EETypePtr", null))); codeStream.EmitStLoc(thisEEType); codeStream.EmitLdLoca(thisEEType); codeStream.Emit(ILOpcode.call, _emitter.NewToken(eetypePtrType.GetKnownMethod("get_ArrayElementType", null))); // EETypePtr expectedElementType = EETypePtr.EETypePtrOf<_elementType>(); codeStream.Emit(ILOpcode.call, _emitter.NewToken(eetypePtrOfMethod)); // if (expectedElementType != actualElementType) // ThrowHelpers.ThrowArrayTypeMismatchException(); codeStream.Emit(ILOpcode.call, _emitter.NewToken(eetypePtrType.GetKnownMethod("op_Equality", null))); codeStream.Emit(ILOpcode.brfalse, typeMismatchExceptionLabel); } } for (int i = 0; i < _rank; i++) { // The first two fields are EEType pointer and total length. Lengths for each dimension follows. int lengthOffset = (2 * pointerSize + i * int32Type.GetElementSize()); EmitLoadInteriorAddress(codeStream, lengthOffset); codeStream.Emit(ILOpcode.ldind_i4); codeStream.EmitStLoc(lengthLocalNum); codeStream.EmitLdArg(i + 1); // Compare with length codeStream.Emit(ILOpcode.dup); codeStream.EmitLdLoc(lengthLocalNum); codeStream.Emit(ILOpcode.bge_un, rangeExceptionLabel); // Add to the running total if we have one already if (i > 0) { codeStream.EmitLdLoc(totalLocalNum); codeStream.EmitLdLoc(lengthLocalNum); codeStream.Emit(ILOpcode.mul); codeStream.Emit(ILOpcode.add); } codeStream.EmitStLoc(totalLocalNum); } // Compute element offset // TODO: This leaves unused space for lower bounds to match CoreCLR... int firstElementOffset = (2 * pointerSize + 2 * _rank * int32Type.GetElementSize()); EmitLoadInteriorAddress(codeStream, firstElementOffset); codeStream.EmitLdLoc(totalLocalNum); int elementSize = _elementType.GetElementSize(); if (elementSize != 1) { codeStream.EmitLdc(elementSize); codeStream.Emit(ILOpcode.mul); } codeStream.Emit(ILOpcode.add); switch (_method.Kind) { case ArrayMethodKind.Get: codeStream.Emit(ILOpcode.ldobj, _emitter.NewToken(_elementType)); break; case ArrayMethodKind.Set: codeStream.EmitLdArg(_rank + 1); codeStream.Emit(ILOpcode.stobj, _emitter.NewToken(_elementType)); break; case ArrayMethodKind.Address: break; } codeStream.Emit(ILOpcode.ret); codeStream.EmitLdc(0); codeStream.EmitLabel(rangeExceptionLabel); // Assumes that there is one "int" pushed on the stack codeStream.Emit(ILOpcode.pop); MethodDesc throwHelper = context.GetHelperEntryPoint("ThrowHelpers", "ThrowIndexOutOfRangeException"); codeStream.EmitCallThrowHelper(_emitter, throwHelper); if (typeMismatchExceptionLabel != null) { codeStream.EmitLabel(typeMismatchExceptionLabel); codeStream.EmitCallThrowHelper(_emitter, context.GetHelperEntryPoint("ThrowHelpers", "ThrowArrayTypeMismatchException")); } }
public ILCodeLabel NewCodeLabel() { var newLabel = new ILCodeLabel(); return newLabel; }
public override MethodIL EmitIL() { TypeDesc owningType = _owningType.InstantiateAsOpen(); ILEmitter emitter = new ILEmitter(); TypeDesc eeTypePtrType = Context.SystemModule.GetKnownType("System", "EETypePtr"); MethodDesc eeTypePtrOfMethod = eeTypePtrType.GetKnownMethod("EETypePtrOf", null); ILToken eeTypePtrToken = emitter.NewToken(eeTypePtrType); var switchStream = emitter.NewCodeStream(); var getFieldStream = emitter.NewCodeStream(); ArrayBuilder <ILCodeLabel> fieldGetters = new ArrayBuilder <ILCodeLabel>(); foreach (FieldDesc field in owningType.GetFields()) { if (field.IsStatic) { continue; } ILCodeLabel label = emitter.NewCodeLabel(); fieldGetters.Add(label); getFieldStream.EmitLabel(label); getFieldStream.EmitLdArg(2); // We need something we can instantiate EETypePtrOf over. Also, the classlib // code doesn't handle pointers. TypeDesc boxableFieldType = field.FieldType; if (boxableFieldType.IsPointer || boxableFieldType.IsFunctionPointer) { boxableFieldType = Context.GetWellKnownType(WellKnownType.IntPtr); } // The fact that the type is a reference type is sufficient for the callers. // Don't unnecessarily create an MethodTable for the field type. if (!boxableFieldType.IsSignatureVariable && !boxableFieldType.IsValueType) { boxableFieldType = Context.GetWellKnownType(WellKnownType.Object); } // If this is an enum, it's okay to Equals/GetHashCode the underlying type. // Don't unnecessarily create an MethodTable for the enum. boxableFieldType = boxableFieldType.UnderlyingType; MethodDesc ptrOfField = eeTypePtrOfMethod.MakeInstantiatedMethod(boxableFieldType); getFieldStream.Emit(ILOpcode.call, emitter.NewToken(ptrOfField)); getFieldStream.Emit(ILOpcode.stobj, eeTypePtrToken); getFieldStream.EmitLdArg(0); getFieldStream.Emit(ILOpcode.ldflda, emitter.NewToken(field)); getFieldStream.EmitLdArg(0); getFieldStream.Emit(ILOpcode.sub); getFieldStream.Emit(ILOpcode.ret); } if (fieldGetters.Count > 0) { switchStream.EmitLdArg(1); switchStream.EmitSwitch(fieldGetters.ToArray()); } switchStream.EmitLdc(fieldGetters.Count); switchStream.Emit(ILOpcode.ret); return(emitter.Link(this)); }