public static MibcConfig ParseMibcConfig(TypeSystemContext tsc, PEReader pEReader) { EcmaModule mibcModule = EcmaModule.Create(tsc, pEReader, null); EcmaMethod mibcConfigMth = (EcmaMethod)mibcModule.GetGlobalModuleType().GetMethod(nameof(MibcConfig), null); if (mibcConfigMth == null) { return(null); } var ilBody = EcmaMethodIL.Create(mibcConfigMth); var ilReader = new ILReader(ilBody.GetILBytes()); // Parse: // // ldstr "key1" // ldstr "value1" // pop // pop // ldstr "key2" // ldstr "value2" // pop // pop // ... // ret string fieldName = null; Dictionary <string, string> keyValue = new(); while (ilReader.HasNext) { ILOpcode opcode = ilReader.ReadILOpcode(); switch (opcode) { case ILOpcode.ldstr: var ldStrValue = (string)ilBody.GetObject(ilReader.ReadILToken()); if (fieldName != null) { keyValue[fieldName] = ldStrValue; } else { fieldName = ldStrValue; } break; case ILOpcode.ret: case ILOpcode.pop: fieldName = null; break; default: throw new InvalidOperationException($"Unexpected opcode: {opcode}"); } } return(MibcConfig.FromKeyValueMap(keyValue)); }
private void ImportBranch(ILOpcode opcode, BasicBlock target, BasicBlock fallthrough) { ImportFallthrough(target); if (fallthrough != null) { ImportFallthrough(fallthrough); } }
private static bool ScanMethodBodyForFieldAccess(MethodIL body, bool write, out FieldDesc?found) { // Tries to find the backing field for a property getter/setter. // Returns true if this is a method body that we can unambiguously analyze. // The found field could still be null if there's no backing store. found = null; ILReader ilReader = new ILReader(body.GetILBytes()); while (ilReader.HasNext) { ILOpcode opcode = ilReader.ReadILOpcode(); switch (opcode) { case ILOpcode.ldsfld when !write: case ILOpcode.ldfld when !write: case ILOpcode.stsfld when write: case ILOpcode.stfld when write: { // This writes/reads multiple fields - can't guess which one is the backing store. // Return failure. if (found != null) { found = null; return(false); } found = (FieldDesc)body.GetObject(ilReader.ReadILToken()); } break; default: ilReader.Skip(opcode); break; } } if (found == null) { // Doesn't access any fields. Could be e.g. "Type Foo => typeof(Bar);" // Return success. return(true); } if (found.OwningType != body.OwningMethod.OwningType || found.IsStatic != body.OwningMethod.Signature.IsStatic || !found.HasCustomAttribute("System.Runtime.CompilerServices", "CompilerGeneratedAttribute")) { // A couple heuristics to make sure we got the right field. // Return failure. found = null; return(false); } return(true); }
public ILOpcode ReadILOpcode() { ILOpcode opcode = (ILOpcode)ReadILByte(); if (opcode == ILOpcode.prefix1) { opcode = (ILOpcode)(0x100 + ReadILByte()); } return(opcode); }
public bool TryReadRet() { ILOpcode opcode = PeekILOpcode(); if (opcode == ILOpcode.ret) { ReadILOpcode(); return(true); } return(false); }
public bool TryReadPop() { ILOpcode opcode = PeekILOpcode(); if (opcode == ILOpcode.pop) { ReadILOpcode(); return(true); } return(false); }
public ILOpcode PeekILOpcode() { ILOpcode opcode = (ILOpcode)_ilBytes[_currentOffset]; if (opcode == ILOpcode.prefix1) { opcode = (ILOpcode)(0x100 + _ilBytes[_currentOffset + 1]); } return(opcode); }
private void ImportCasting(ILOpcode opcode, int token) { TypeDesc type = (TypeDesc)_methodIL.GetObject(token); if (type.IsRuntimeDeterminedSubtype) { _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.TypeHandleForCasting, type), "IsInst/CastClass"); } else { _dependencies.Add(_compilation.ComputeConstantLookup(ReadyToRunHelperId.TypeHandleForCasting, type), "IsInst/CastClass"); } }
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); }
private void ImportBinaryOperation(ILOpcode opcode) { switch (opcode) { case ILOpcode.add_ovf: case ILOpcode.add_ovf_un: case ILOpcode.mul_ovf: case ILOpcode.mul_ovf_un: case ILOpcode.sub_ovf: case ILOpcode.sub_ovf_un: _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.Overflow), "_ovf"); break; } }
public int ReadBranchDestination(ILOpcode currentOpcode) { if ((currentOpcode >= ILOpcode.br_s && currentOpcode <= ILOpcode.blt_un_s) || currentOpcode == ILOpcode.leave_s) { return((sbyte)ReadILByte() + Offset); } else { Debug.Assert((currentOpcode >= ILOpcode.br && currentOpcode <= ILOpcode.blt_un) || currentOpcode == ILOpcode.leave); return((int)ReadILUInt32() + Offset); } }
public static void Scan(ref DependencyList list, NodeFactory factory, MethodIL methodIL) { ILReader reader = new ILReader(methodIL.GetILBytes()); Tracker tracker = new Tracker(methodIL); // The algorithm here is really primitive: we scan the IL forward in a single pass, remembering // the last type/string/token we saw. // // We then intrinsically recognize a couple methods that consume this information. // // This has obvious problems since we don't have exact knowledge of the parameters passed // (something being in front of a call doesn't mean it's a parameter to the call). But since // this is a heuristic, it's okay. We want this to be as fast as possible. // // The main purposes of this scanner is to make following patterns work: // // * Enum.GetValues(typeof(Foo)) - this is very common and we need to make sure Foo[] is compiled. // * Type.GetType("Foo, Bar").GetMethod("Blah") - framework uses this to work around layering problems. // * typeof(Foo<>).MakeGenericType(arg).GetMethod("Blah") - used in e.g. LINQ expressions implementation // * Marshal.SizeOf(typeof(Foo)) - very common and we need to make sure interop data is generated while (reader.HasNext) { ILOpcode opcode = reader.ReadILOpcode(); switch (opcode) { case ILOpcode.ldstr: tracker.TrackStringToken(reader.ReadILToken()); break; case ILOpcode.ldtoken: tracker.TrackLdTokenToken(reader.ReadILToken()); break; case ILOpcode.call: case ILOpcode.callvirt: var method = methodIL.GetObject(reader.ReadILToken()) as MethodDesc; if (method != null) { HandleCall(ref list, factory, methodIL, method, ref tracker); } break; default: reader.Skip(opcode); break; } } }
/// <summary> /// Parse MIbcGroup method and return enumerable of MethodProfileData /// /// Like the AssemblyDictionary method, data is encoded via IL instructions. The format is /// /// ldtoken methodInProfileData /// Any series of instructions that does not include pop /// pop /// {Repeat N times for N methods described} /// /// This format is designed to be extensible to hold more data as we add new per method profile data without breaking existing parsers. /// </summary> static IEnumerable <MethodProfileData> ReadMIbcGroup(TypeSystemContext tsc, EcmaMethod method) { EcmaMethodIL ilBody = EcmaMethodIL.Create(method); byte[] ilBytes = ilBody.GetILBytes(); int currentOffset = 0; object metadataObject = null; object methodNotResolvable = new object(); while (currentOffset < ilBytes.Length) { ILOpcode opcode = (ILOpcode)ilBytes[currentOffset]; if (opcode == ILOpcode.prefix1) { opcode = 0x100 + (ILOpcode)ilBytes[currentOffset + 1]; } switch (opcode) { case ILOpcode.ldtoken: if (metadataObject == null) { uint token = (uint)(ilBytes[currentOffset + 1] + (ilBytes[currentOffset + 2] << 8) + (ilBytes[currentOffset + 3] << 16) + (ilBytes[currentOffset + 4] << 24)); try { metadataObject = ilBody.GetObject((int)token); } catch (TypeSystemException) { // The method being referred to may be missing. In that situation, // use the methodNotResolvable sentinel to indicate that this record should be ignored metadataObject = methodNotResolvable; } } break; case ILOpcode.pop: if (metadataObject != methodNotResolvable) { MethodProfileData mibcData = new MethodProfileData((MethodDesc)metadataObject, MethodProfilingDataFlags.ReadMethodCode, 0xFFFFFFFF); yield return(mibcData); } metadataObject = null; break; } // This isn't correct if there is a switch opcode, but since we won't do that, its ok currentOffset += opcode.GetSize(); } }
private void ImportLdFtn(int token, ILOpcode opCode) { // Is this a verifiable delegate creation? If so, we will handle it when we reach the newobj if (_ilBytes[_currentOffset] == (byte)ILOpcode.newobj) { int delegateToken = ReadILTokenAt(_currentOffset + 1); var delegateType = ((MethodDesc)_methodIL.GetObject(delegateToken)).OwningType; if (delegateType.IsDelegate) { return; } } ImportCall(opCode, token); }
public ILOpcode PeekILOpcode() { ILOpcode opcode = (ILOpcode)_ilBytes[_currentOffset]; if (opcode == ILOpcode.prefix1) { if (_currentOffset + 2 > _ilBytes.Length) { ThrowHelper.ThrowInvalidProgramException(); } opcode = (ILOpcode)(0x100 + _ilBytes[_currentOffset + 1]); } return(opcode); }
private void ImportCompareOperation(ILOpcode opcode) { var op1 = _stack.Pop(); var op2 = _stack.Pop(); // StackValueKind is carefully ordered to make this work (assuming the IL is valid) StackValueKind kind; if (op1.Kind > op2.Kind) { kind = op1.Kind; } else { kind = op2.Kind; } LLVMValueRef result; switch (opcode) { case ILOpcode.ceq: result = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntEQ, op2.LLVMValue, op1.LLVMValue, "ceq"); break; case ILOpcode.cgt: result = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntSGT, op2.LLVMValue, op1.LLVMValue, "cgt"); break; case ILOpcode.clt: result = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntSLT, op2.LLVMValue, op1.LLVMValue, "clt"); break; case ILOpcode.cgt_un: result = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntUGT, op2.LLVMValue, op1.LLVMValue, "cgt_un"); break; case ILOpcode.clt_un: result = LLVM.BuildICmp(_builder, LLVMIntPredicate.LLVMIntULT, op2.LLVMValue, op1.LLVMValue, "clt_un"); break; default: throw new NotSupportedException(); // unreachable } PushExpression(kind, "", result, GetWellKnownType(WellKnownType.SByte)); }
private void ImportCall(ILOpcode opcode, int token) { MethodDesc callee = (MethodDesc)_methodIL.GetObject(token); if (callee.IsPInvoke) { ImportRawPInvoke(callee); return; } // we don't really have virtual call support, but we'll treat it as direct for now if (opcode != ILOpcode.call && opcode != ILOpcode.callvirt) { throw new NotImplementedException(); } HandleCall(callee); }
/// <summary> /// Skips over a "foo == typeof(Bar)" or "typeof(Foo) == typeof(Bar)" sequence. /// </summary> private static bool IsTypeEqualityTest(MethodIL methodIL, ILReader reader, out ILReader afterTest) { afterTest = default; if (reader.ReadILOpcode() != ILOpcode.call) { return(false); } MethodDesc method = methodIL.GetObject(reader.ReadILToken()) as MethodDesc; if (method == null || method.Name != "GetTypeFromHandle" && !method.OwningType.IsSystemType()) { return(false); } ILOpcode opcode = reader.ReadILOpcode(); if (opcode == ILOpcode.ldtoken) { reader.ReadILToken(); opcode = reader.ReadILOpcode(); if (opcode != ILOpcode.call) { return(false); } method = methodIL.GetObject(reader.ReadILToken()) as MethodDesc; if (method == null || method.Name != "GetTypeFromHandle" && !method.OwningType.IsSystemType()) { return(false); } opcode = reader.ReadILOpcode(); } if (opcode != ILOpcode.call) { return(false); } method = methodIL.GetObject(reader.ReadILToken()) as MethodDesc; if (method == null || method.Name != "op_Equality" && !method.OwningType.IsSystemType()) { return(false); } afterTest = reader; return(true); }
public void Skip(ILOpcode opcode) { if (!opcode.IsValid()) { ThrowHelper.ThrowInvalidProgramException(); } if (opcode != ILOpcode.switch_) { int opcodeSize = (byte)opcode != (int)opcode ? 2 : 1; _currentOffset += opcode.GetSize() - opcodeSize; } else { // "switch" opcode is special uint count = ReadILUInt32(); _currentOffset += checked ((int)(count * 4)); } }
public int MoveNext(int offset) { if (_foundEndOfPrevBlock || _methodBranchTargets.Contains(offset)) { _currentBlockIndex++; _foundEndOfPrevBlock = false; } var reader = new ILReader(_methodBody.GetILBytes()); reader.Seek(offset); ILOpcode opcode = reader.ReadILOpcode(); if (opcode.IsControlFlowInstruction()) { _foundEndOfPrevBlock = true; } return(CurrentBlockIndex); }
public static bool IsControlFlowInstruction(this ILOpcode opcode) { switch (opcode) { case ILOpcode.br_s: case ILOpcode.br: case ILOpcode.brfalse_s: case ILOpcode.brtrue_s: case ILOpcode.beq_s: case ILOpcode.bge_s: case ILOpcode.bgt_s: case ILOpcode.ble_s: case ILOpcode.blt_s: case ILOpcode.bne_un_s: case ILOpcode.bge_un_s: case ILOpcode.bgt_un_s: case ILOpcode.ble_un_s: case ILOpcode.blt_un_s: case ILOpcode.brfalse: case ILOpcode.brtrue: case ILOpcode.beq: case ILOpcode.bge: case ILOpcode.bgt: case ILOpcode.ble: case ILOpcode.blt: case ILOpcode.bne_un: case ILOpcode.bge_un: case ILOpcode.bgt_un: case ILOpcode.ble_un: case ILOpcode.blt_un: case ILOpcode.switch_: case ILOpcode.leave: case ILOpcode.leave_s: case ILOpcode.endfilter: case ILOpcode.endfinally: case ILOpcode.throw_: case ILOpcode.rethrow: return(true); } return(false); }
private static bool ILOpcodeHasToken(ILOpcode opcode) { switch (opcode) { case ILOpcode.jmp: case ILOpcode.call: case ILOpcode.calli: case ILOpcode.callvirt: case ILOpcode.cpobj: case ILOpcode.ldobj: case ILOpcode.ldstr: case ILOpcode.newobj: case ILOpcode.castclass: case ILOpcode.isinst: case ILOpcode.unbox: case ILOpcode.ldfld: case ILOpcode.ldflda: case ILOpcode.stfld: case ILOpcode.ldsfld: case ILOpcode.ldsflda: case ILOpcode.stsfld: case ILOpcode.stobj: case ILOpcode.box: case ILOpcode.newarr: case ILOpcode.ldelema: case ILOpcode.ldelem: case ILOpcode.stelem: case ILOpcode.unbox_any: case ILOpcode.refanyval: case ILOpcode.mkrefany: case ILOpcode.ldtoken: case ILOpcode.ldftn: case ILOpcode.ldvirtftn: case ILOpcode.initobj: case ILOpcode.constrained: case ILOpcode.sizeof_: return(true); } return(false); }
private void ImportUnbox(int token, ILOpcode opCode) { TypeDesc type = (TypeDesc)_methodIL.GetObject(token); if (!type.IsValueType) { if (opCode == ILOpcode.unbox_any) { // When applied to a reference type, unbox_any has the same effect as castclass. ImportCasting(ILOpcode.castclass, token); } return; } if (type.IsRuntimeDeterminedSubtype) { _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.TypeHandle, type), "Unbox"); } else { _dependencies.Add(_factory.NecessaryTypeSymbol(type), "Unbox"); } ReadyToRunHelper helper; if (opCode == ILOpcode.unbox) { helper = ReadyToRunHelper.Unbox; } else { Debug.Assert(opCode == ILOpcode.unbox_any); helper = ReadyToRunHelper.Unbox_Nullable; } _dependencies.Add(GetHelperEntrypoint(helper), "Unbox"); }
static IEnumerable <MIbcData> ReadMIbcData(TraceTypeSystemContext tsc, FileInfo outputFileName, byte[] moduleBytes) { var peReader = new System.Reflection.PortableExecutable.PEReader(System.Collections.Immutable.ImmutableArray.Create <byte>(moduleBytes)); var module = EcmaModule.Create(tsc, peReader, null, null, new CustomCanonResolver(tsc)); var loadedMethod = (EcmaMethod)module.GetGlobalModuleType().GetMethod("AssemblyDictionary", null); EcmaMethodIL ilBody = EcmaMethodIL.Create(loadedMethod); byte[] ilBytes = ilBody.GetILBytes(); int currentOffset = 0; while (currentOffset < ilBytes.Length) { ILOpcode opcode = (ILOpcode)ilBytes[currentOffset]; if (opcode == ILOpcode.prefix1) { opcode = 0x100 + (ILOpcode)ilBytes[currentOffset + 1]; } switch (opcode) { case ILOpcode.ldtoken: UInt32 token = (UInt32)(ilBytes[currentOffset + 1] + (ilBytes[currentOffset + 2] << 8) + (ilBytes[currentOffset + 3] << 16) + (ilBytes[currentOffset + 4] << 24)); foreach (var data in ReadMIbcGroup(tsc, (EcmaMethod)ilBody.GetObject((int)token))) { yield return(data); } break; case ILOpcode.pop: break; } // This isn't correct if there is a switch opcode, but since we won't do that, its ok currentOffset += opcode.GetSize(); } GC.KeepAlive(peReader); }
public static HashSet <int> ComputeBranchTargets(this MethodIL methodBody) { HashSet <int> branchTargets = new HashSet <int>(); var reader = new ILReader(methodBody.GetILBytes()); while (reader.HasNext) { ILOpcode opcode = reader.ReadILOpcode(); if (opcode >= ILOpcode.br_s && opcode <= ILOpcode.blt_un) { branchTargets.Add(reader.ReadBranchDestination(opcode)); } else if (opcode == ILOpcode.switch_) { uint count = reader.ReadILUInt32(); int jmpBase = reader.Offset + (int)(4 * count); for (uint i = 0; i < count; i++) { branchTargets.Add((int)reader.ReadILUInt32() + jmpBase); } } else { reader.Skip(opcode); } } foreach (ILExceptionRegion einfo in methodBody.GetExceptionRegions()) { if (einfo.Kind == ILExceptionRegionKind.Filter) { branchTargets.Add(einfo.FilterOffset); } branchTargets.Add(einfo.HandlerOffset); } return(branchTargets); }
public static bool IsBranch(this ILOpcode opcode) { if (opcode >= ILOpcode.br && opcode <= ILOpcode.blt_un) { return(true); } if (opcode >= ILOpcode.br_s && opcode <= ILOpcode.blt_un_s) { return(true); } if (opcode == ILOpcode.leave_s) { return(true); } if (opcode == ILOpcode.leave) { return(true); } return(false); }
private void ImportCall(ILOpcode opcode, int token) { bool callViaSlot = false; bool delegateInvoke = false; bool callViaInterfaceDispatch = false; DelegateCreationInfo delegateInfo = null; MethodDesc method = (MethodDesc)_methodIL.GetObject(token); if (method.IsIntrinsic) { if (ImportIntrinsicCall(method)) return; } TypeDesc constrained = null; if (opcode != ILOpcode.newobj) { if ((_pendingPrefix & Prefix.Constrained) != 0 && opcode == ILOpcode.callvirt) { _pendingPrefix &= ~Prefix.Constrained; constrained = _constrained; bool forceUseRuntimeLookup; MethodDesc directMethod = constrained.GetClosestDefType().TryResolveConstraintMethodApprox(method.OwningType, method, out forceUseRuntimeLookup); if (forceUseRuntimeLookup) throw new NotImplementedException(); if (directMethod != null) { method = directMethod; opcode = ILOpcode.call; } else { // Dereference "this" int thisPosition = _stack.Top - (method.Signature.Length + 1); string tempName = NewTempName(); Append(GetStackValueKindCPPTypeName(StackValueKind.ObjRef)); Append(" "); Append(tempName); Append(" = *("); Append(GetStackValueKindCPPTypeName(StackValueKind.ObjRef)); Append("*)"); Append(_stack[thisPosition]); AppendSemicolon(); _stack[thisPosition] = new ExpressionEntry(StackValueKind.ObjRef, tempName); } } } TypeDesc owningType = method.OwningType; TypeDesc retType = null; { if (opcode == ILOpcode.newobj) { retType = owningType; if (owningType.IsString) { // String constructors actually look like regular method calls method = method.GetStringInitializer(); opcode = ILOpcode.call; } else if (owningType.IsArray) { ImportNewObjArray(owningType, method); return; } else if (owningType.IsDelegate) { delegateInfo = _compilation.GetDelegateCtor(owningType, ((LdTokenEntry<MethodDesc>)_stack.Peek()).LdToken); method = delegateInfo.Constructor.Method; } } else if (owningType.IsDelegate) { if (method.Name == "Invoke") { opcode = ILOpcode.call; delegateInvoke = true; } } } if (opcode == ILOpcode.callvirt) { // TODO: Null checks if (method.IsVirtual) { // TODO: Full resolution of virtual methods if (!method.IsNewSlot) throw new NotImplementedException(); if (method.OwningType.IsInterface) callViaInterfaceDispatch = true; else callViaSlot = true; _dependencies.Add(_nodeFactory.VirtualMethodUse(method)); } } if (!callViaSlot && !delegateInvoke && !callViaInterfaceDispatch) AddMethodReference(method); if (opcode == ILOpcode.newobj) AddTypeReference(retType, true); var methodSignature = method.Signature; if (retType == null) retType = methodSignature.ReturnType; string temp = null; StackValueKind retKind = StackValueKind.Unknown; var needNewLine = false; if (callViaInterfaceDispatch) { _dependencies.Add(_nodeFactory.ReadyToRunHelper(ReadyToRunHelperId.VirtualCall, method)); ExpressionEntry v = (ExpressionEntry)_stack[_stack.Top - (methodSignature.Length + 1)]; string typeDefName = _writer.GetCppMethodName(method); _writer.AppendSignatureTypeDef(_builder, typeDefName, method.Signature, method.OwningType); string functionPtr = NewTempName(); AppendEmptyLine(); Append("void*"); Append(functionPtr); Append(" = (void*) (("); Append(typeDefName); // Call method to find implementation address Append(") System_Private_CoreLib::System::Runtime::DispatchResolve::FindInterfaceMethodImplementationTarget("); // Get EEType of current object (interface implementation) Append("::System_Private_CoreLib::System::Object::get_EEType((::System_Private_CoreLib::System::Object*)"); Append(v.Name); Append(")"); Append(", "); // Get EEType of interface Append("((::System_Private_CoreLib::Internal::Runtime::EEType *)("); Append(_writer.GetCppTypeName(method.OwningType)); Append("::__getMethodTable()))"); Append(", "); // Get slot of implementation Append("(uint16_t)"); Append("("); Append(_writer.GetCppTypeName(method.OwningType)); Append("::"); Append("__getslot__"); Append(_writer.GetCppMethodName(method)); Append("("); Append(v.Name); Append("))"); Append("));"); PushExpression(StackValueKind.ByRef, functionPtr); } if (!retType.IsVoid) { retKind = GetStackValueKind(retType); temp = NewTempName(); AppendLine(); Append(GetStackValueKindCPPTypeName(retKind, retType)); Append(" "); Append(temp); if (retType.IsValueType && opcode == ILOpcode.newobj) { Append(";"); needNewLine = true; } else { Append(" = "); if (retType.IsPointer) { Append("(intptr_t)"); } } } else { needNewLine = true; } AddTypeReference(method.OwningType, true); if (opcode == ILOpcode.newobj) { if (!retType.IsValueType) { // We do not reset needNewLine since we still need for the next statement. if (needNewLine) AppendLine(); Append("__allocate_object("); Append(_writer.GetCppTypeName(retType)); Append("::__getMethodTable())"); AppendSemicolon(); needNewLine = true; if (delegateInfo != null && delegateInfo.Thunk != null) { MethodDesc thunkMethod = delegateInfo.Thunk.Method; AddMethodReference(thunkMethod); // Update stack with new name. ((ExpressionEntry)_stack[_stack.Top - 2]).Name = temp; var sb = new CppGenerationBuffer(); AppendLine(); sb.Append("(intptr_t)&"); sb.Append(_writer.GetCppTypeName(thunkMethod.OwningType)); sb.Append("::"); sb.Append(_writer.GetCppMethodName(thunkMethod)); PushExpression(StackValueKind.NativeInt, sb.ToString()); } } } if (needNewLine) AppendLine(); if (callViaSlot || delegateInvoke) { ExpressionEntry v = (ExpressionEntry)_stack[_stack.Top - (methodSignature.Length + 1)]; Append("(*"); Append(_writer.GetCppTypeName(method.OwningType)); Append("::"); Append(delegateInvoke ? "__invoke__" : "__getslot__"); Append(_writer.GetCppMethodName(method)); Append("("); Append(v); Append("))"); if (delegateInvoke) { v.Name = "((" + _writer.GetCppSignatureTypeName(GetWellKnownType(WellKnownType.MulticastDelegate)) + ")" + v.Name + ")->m_firstParameter"; } } else if (callViaInterfaceDispatch) { Append("(("); Append(_writer.GetCppMethodName(method)); Append(")"); ExpressionEntry v = (ExpressionEntry)_stack.Pop(); Append(v); Append(")"); } else { Append(_writer.GetCppTypeName(method.OwningType)); Append("::"); Append(_writer.GetCppMethodName(method)); } TypeDesc thisArgument = null; Append("("); if (opcode == ILOpcode.newobj) { Append("("); if (retType.IsValueType) { Append(_writer.GetCppSignatureTypeName(retType.MakeByRefType())); Append(")"); Append("&" + temp); } else { Append(_writer.GetCppSignatureTypeName(retType)); Append(")"); Append(temp); } if (methodSignature.Length > 0) Append(", "); } else { if (!methodSignature.IsStatic) { thisArgument = owningType; if (thisArgument.IsValueType) thisArgument = thisArgument.MakeByRefType(); } } PassCallArguments(methodSignature, thisArgument); Append(")"); if (temp != null) { Debug.Assert(retKind != StackValueKind.Unknown, "Valid return type"); PushExpression(retKind, temp, retType); } AppendSemicolon(); }
private void ImportCall(ILOpcode opcode, int token) { bool callViaSlot = false; bool delegateInvoke = false; DelegateInfo delegateInfo = null; bool mdArrayCreate = false; MethodDesc method = (MethodDesc)_methodIL.GetObject(token); if (method.IsIntrinsic) { if (ImportIntrinsicCall(method)) return; } TypeDesc constrained = null; if (opcode != ILOpcode.newobj) { if ((_pendingPrefix & Prefix.Constrained) != 0 && opcode == ILOpcode.callvirt) { _pendingPrefix &= ~Prefix.Constrained; constrained = _constrained; // TODO: throw new NotImplementedException(); } } TypeDesc owningType = method.OwningType; TypeDesc retType = null; { if (opcode == ILOpcode.newobj) retType = owningType; if (opcode == ILOpcode.newobj) { if (owningType.IsString) { // String constructors actually look like regular method calls method = method.GetStringInitializer(); opcode = ILOpcode.call; // WORKAROUND: the static method expects an extra arg // Annoyingly, it needs to be before all the others if (_stackTop >= _stack.Length) Array.Resize(ref _stack, 2 * _stackTop + 3); for (int i = _stackTop - 1; i > _stackTop - method.Signature.Length; i--) _stack[i + 1] = _stack[i]; _stackTop++; _stack[_stackTop - method.Signature.Length] = new StackValue { Kind = StackValueKind.ObjRef, Value = new Value("0") }; } else if (owningType.IsArray) { mdArrayCreate = true; } else if (owningType.IsDelegate) { delegateInfo = _compilation.GetDelegateCtor((MethodDesc)_stack[_stackTop - 1].Value.Aux); method = delegateInfo.Ctor; } } else if (owningType.IsDelegate) { if (method.Name == "Invoke") { opcode = ILOpcode.call; delegateInvoke = true; } } } if (opcode == ILOpcode.callvirt) { // TODO: Null checks if (method.IsVirtual) { // TODO: Full resolution of virtual methods if (!method.IsNewSlot) throw new NotImplementedException(); // TODO: Interface calls if (method.OwningType.IsInterface) throw new NotImplementedException(); _dependencies.Add(_nodeFactory.VirtualMethodUse(method)); callViaSlot = true; } } if (!callViaSlot && !delegateInvoke && !mdArrayCreate) AddMethodReference(method); if (opcode == ILOpcode.newobj) AddTypeReference(retType, true); var methodSignature = method.Signature; if (retType == null) retType = methodSignature.ReturnType; string temp = null; StackValueKind retKind = StackValueKind.Unknown; if (!retType.IsVoid) { retKind = GetStackValueKind(retType); temp = NewTempName(); Append(GetStackValueKindCPPTypeName(retKind, retType)); Append(" "); Append(temp); if (retType.IsValueType && opcode == ILOpcode.newobj) { Append(";"); } else { Append("="); if (retType.IsPointer) { Append("(intptr_t)"); } } } if (opcode == ILOpcode.newobj && !mdArrayCreate) { if (!retType.IsValueType) { Append("__allocate_object("); Append(_writer.GetCppTypeName(retType)); Append("::__getMethodTable())"); Finish(); if (delegateInfo != null && delegateInfo.ShuffleThunk != null) { AddMethodReference(delegateInfo.ShuffleThunk); _stack[_stackTop - 2].Value.Name = temp; StringBuilder sb = new StringBuilder(); sb.Append("(intptr_t)&"); sb.Append(_writer.GetCppTypeName(delegateInfo.ShuffleThunk.OwningType)); sb.Append("::"); sb.Append(_writer.GetCppMethodName(delegateInfo.ShuffleThunk)); Push(StackValueKind.NativeInt, new Value(sb.ToString()), null); } } } if (callViaSlot || delegateInvoke) { Append("(*"); Append(_writer.GetCppTypeName(method.OwningType)); Append("::"); Append(delegateInvoke ? "__invoke__" : "__getslot__"); Append(_writer.GetCppMethodName(method)); Append("("); Append(_stack[_stackTop - (methodSignature.Length + 1)].Value.Name); Append("))"); if (delegateInvoke) { _stack[_stackTop - (methodSignature.Length + 1)].Value.Name = "((" + _writer.GetCppSignatureTypeName(GetWellKnownType(WellKnownType.MulticastDelegate)) + ")" + _stack[_stackTop - (methodSignature.Length + 1)].Value.Name + ")->m_firstParameter"; } } else if (mdArrayCreate) { Append("RhNewMDArray"); } else { Append(_writer.GetCppTypeName(method.OwningType)); Append("::"); Append(_writer.GetCppMethodName(method)); } TypeDesc thisArgument = null; Append("("); if (mdArrayCreate) { Append(_writer.GetCppTypeName(method.OwningType)); Append("::__getMethodTable(), "); Append(IntToString(((ArrayType)method.OwningType).Rank)); Append(", "); } else if (opcode == ILOpcode.newobj) { Append("("); if (retType.IsValueType) { Append(_writer.GetCppSignatureTypeName(retType.MakeByRefType())); Append(")"); Append("&" + temp); } else { Append(_writer.GetCppSignatureTypeName(retType)); Append(")"); Append(temp); } if (methodSignature.Length > 0) Append(", "); } else { if (!methodSignature.IsStatic) { thisArgument = owningType; if (thisArgument.IsValueType) thisArgument = thisArgument.MakeByRefType(); } } PassCallArguments(methodSignature, thisArgument); Append(")"); if (temp != null) Push(retKind, new Value(temp), retType); Finish(); }
private void ImportCall(ILOpcode opcode, int token) { bool callViaSlot = false; bool delegateInvoke = false; DelegateCreationInfo delegateInfo = null; bool mdArrayCreate = false; MethodDesc method = (MethodDesc)_methodIL.GetObject(token); if (method.IsIntrinsic) { if (ImportIntrinsicCall(method)) return; } TypeDesc constrained = null; if (opcode != ILOpcode.newobj) { if ((_pendingPrefix & Prefix.Constrained) != 0 && opcode == ILOpcode.callvirt) { _pendingPrefix &= ~Prefix.Constrained; constrained = _constrained; bool forceUseRuntimeLookup; MethodDesc directMethod = constrained.GetClosestMetadataType().TryResolveConstraintMethodApprox(method.OwningType, method, out forceUseRuntimeLookup); if (directMethod == null || forceUseRuntimeLookup) throw new NotImplementedException(); method = directMethod; opcode = ILOpcode.call; } } TypeDesc owningType = method.OwningType; TypeDesc retType = null; { if (opcode == ILOpcode.newobj) retType = owningType; if (opcode == ILOpcode.newobj) { if (owningType.IsString) { // String constructors actually look like regular method calls method = method.GetStringInitializer(); opcode = ILOpcode.call; // WORKAROUND: the static method expects an extra arg // Annoyingly, it needs to be before all the others _stack.InsertAt(new ExpressionEntry(StackValueKind.ObjRef, "0"), _stack.Top - method.Signature.Length + 1); } else if (owningType.IsArray) { mdArrayCreate = true; } else if (owningType.IsDelegate) { delegateInfo = _compilation.GetDelegateCtor(owningType, ((LdTokenEntry<MethodDesc>)_stack.Peek()).LdToken); method = delegateInfo.Constructor.Method; } } else if (owningType.IsDelegate) { if (method.Name == "Invoke") { opcode = ILOpcode.call; delegateInvoke = true; } } } if (opcode == ILOpcode.callvirt) { // TODO: Null checks if (method.IsVirtual) { // TODO: Full resolution of virtual methods if (!method.IsNewSlot) throw new NotImplementedException(); // TODO: Interface calls if (method.OwningType.IsInterface) throw new NotImplementedException(); _dependencies.Add(_nodeFactory.VirtualMethodUse(method)); callViaSlot = true; } } if (!callViaSlot && !delegateInvoke && !mdArrayCreate) AddMethodReference(method); if (opcode == ILOpcode.newobj) AddTypeReference(retType, true); var methodSignature = method.Signature; if (retType == null) retType = methodSignature.ReturnType; string temp = null; StackValueKind retKind = StackValueKind.Unknown; var needNewLine = false; if (!retType.IsVoid) { retKind = GetStackValueKind(retType); temp = NewTempName(); AppendLine(); Append(GetStackValueKindCPPTypeName(retKind, retType)); Append(" "); Append(temp); if (retType.IsValueType && opcode == ILOpcode.newobj) { Append(";"); needNewLine = true; } else { Append(" = "); if (retType.IsPointer) { Append("(intptr_t)"); } } } else { needNewLine = true; } if (opcode == ILOpcode.newobj && !mdArrayCreate) { if (!retType.IsValueType) { // We do not reset needNewLine since we still need for the next statement. if (needNewLine) AppendLine(); Append("__allocate_object("); Append(_writer.GetCppTypeName(retType)); Append("::__getMethodTable())"); AppendSemicolon(); needNewLine = true; if (delegateInfo != null && delegateInfo.Thunk != null) { MethodDesc thunkMethod = delegateInfo.Thunk.Method; AddMethodReference(thunkMethod); // Update stack with new name. ((ExpressionEntry) _stack[_stack.Top - 2]).Name = temp; var sb = new CppGenerationBuffer(); AppendLine(); sb.Append("(intptr_t)&"); sb.Append(_writer.GetCppTypeName(thunkMethod.OwningType)); sb.Append("::"); sb.Append(_writer.GetCppMethodName(thunkMethod)); PushExpression(StackValueKind.NativeInt, sb.ToString()); } } } if (needNewLine) AppendLine(); if (callViaSlot || delegateInvoke) { // While waiting for C# return by ref, get this reference and insert it back // if it is a delegate invoke. ExpressionEntry v = (ExpressionEntry) _stack[_stack.Top - (methodSignature.Length + 1)]; Append("(*"); Append(_writer.GetCppTypeName(method.OwningType)); Append("::"); Append(delegateInvoke ? "__invoke__" : "__getslot__"); Append(_writer.GetCppMethodName(method)); Append("("); Append(v); Append("))"); if (delegateInvoke) { v.Name = "((" + _writer.GetCppSignatureTypeName(GetWellKnownType(WellKnownType.MulticastDelegate)) + ")" + v.Name + ")->m_firstParameter"; } } else if (mdArrayCreate) { Append("RhNewMDArray"); } else { Append(_writer.GetCppTypeName(method.OwningType)); Append("::"); Append(_writer.GetCppMethodName(method)); } TypeDesc thisArgument = null; Append("("); if (mdArrayCreate) { Append(_writer.GetCppTypeName(method.OwningType)); Append("::__getMethodTable(), "); Append(((ArrayType)method.OwningType).Rank.ToStringInvariant()); Append(", "); } else if (opcode == ILOpcode.newobj) { Append("("); if (retType.IsValueType) { Append(_writer.GetCppSignatureTypeName(retType.MakeByRefType())); Append(")"); Append("&" + temp); } else { Append(_writer.GetCppSignatureTypeName(retType)); Append(")"); Append(temp); } if (methodSignature.Length > 0) Append(", "); } else { if (!methodSignature.IsStatic) { thisArgument = owningType; if (thisArgument.IsValueType) thisArgument = thisArgument.MakeByRefType(); } } PassCallArguments(methodSignature, thisArgument); Append(")"); if (temp != null) { Debug.Assert(retKind != StackValueKind.Unknown, "Valid return type"); PushExpression(retKind, temp, retType); } AppendSemicolon(); }
private void ImportCasting(ILOpcode opcode, int token) { TypeDesc type = (TypeDesc)_methodIL.GetObject(token); var value = _stack.Pop(); PushTemp(StackValueKind.ObjRef, type); AddTypeReference(type, false); Append(opcode == ILOpcode.isinst ? "__isinst" : "__castclass"); Append("("); Append(value); Append(", "); Append(_writer.GetCppTypeName(type)); Append("::__getMethodTable())"); AppendSemicolon(); }
private void ImportUnbox(int token, ILOpcode opCode) { var type = ResolveTypeToken(token); var obj = _stack.Pop(); if (opCode == ILOpcode.unbox) { PushTemp(StackValueKind.ByRef, type.MakeByRefType()); } else { PushTemp(GetStackValueKind(type), type); } if (type.IsValueType) { // TODO: Unbox of nullable types if (type.IsNullable) throw new NotImplementedException(); if (opCode == ILOpcode.unbox_any) { string typeName = GetStackValueKindCPPTypeName(GetStackValueKind(type), type); Append("*("); Append(typeName); Append("*)"); } Append("("); Append(_writer.GetCppSignatureTypeName(type)); Append("*)"); Append("((void **)"); Append(obj); Append("+1)"); } else { // TODO: Cast Append(obj); } AppendSemicolon(); }
private void ImportCasting(ILOpcode opcode, int token) { TypeDesc type = (TypeDesc)_methodIL.GetObject(token); if (type.IsInterface || type.IsArray) throw new NotImplementedException(); var value = Pop(); PushTemp(StackValueKind.ObjRef, type); Append(opcode == ILOpcode.isinst ? "__isinst_class" : "__castclass_class"); Append("("); Append(value.Value.Name); Append(", "); Append(_writer.GetCppTypeName(type)); Append("::__getMethodTable())"); Finish(); }
private void ImportCompareOperation(ILOpcode opcode) { var op1 = _stack.Pop(); var op2 = _stack.Pop(); // StackValueKind is carefully ordered to make this work (assuming the IL is valid) StackValueKind kind; if (op1.Kind > op2.Kind) { kind = op1.Kind; } else { kind = op2.Kind; } PushTemp(StackValueKind.Int32); string op = null; bool unsigned = false; bool inverted = false; switch (opcode) { case ILOpcode.ceq: op = "=="; break; case ILOpcode.cgt: op = ">"; break; case ILOpcode.clt: op = "<"; break; case ILOpcode.cgt_un: if (kind == StackValueKind.Float) { op = "<="; inverted = true; } else { op = ">"; if (kind == StackValueKind.Int32 || kind == StackValueKind.Int64) unsigned = true; } break; case ILOpcode.clt_un: if (kind == StackValueKind.Float) { op = ">="; inverted = true; } else { op = "<"; if (kind == StackValueKind.Int32 || kind == StackValueKind.Int64) unsigned = true; } break; } if (kind == StackValueKind.ByRef) unsigned = false; if (inverted) { Append("!("); } if (unsigned) { Append("(u"); Append(GetStackValueKindCPPTypeName(kind)); Append(")"); } Append(op2); Append(" "); Append(op); Append(" "); if (unsigned) { Append("(u"); Append(GetStackValueKindCPPTypeName(kind)); Append(")"); } Append(op1); if (inverted) { Append(")"); } AppendSemicolon(); }
private void ImportBasicBlock(BasicBlock basicBlock) { _currentBasicBlock = basicBlock; _currentOffset = basicBlock.StartOffset; for (;;) { StartImportingInstruction(); ILOpcode opCode = (ILOpcode)ReadILByte(); again: switch (opCode) { case ILOpcode.nop: ImportNop(); break; case ILOpcode.break_: ImportBreak(); break; case ILOpcode.ldarg_0: case ILOpcode.ldarg_1: case ILOpcode.ldarg_2: case ILOpcode.ldarg_3: ImportLoadVar(opCode - ILOpcode.ldarg_0, true); break; case ILOpcode.ldloc_0: case ILOpcode.ldloc_1: case ILOpcode.ldloc_2: case ILOpcode.ldloc_3: ImportLoadVar(opCode - ILOpcode.ldloc_0, false); break; case ILOpcode.stloc_0: case ILOpcode.stloc_1: case ILOpcode.stloc_2: case ILOpcode.stloc_3: ImportStoreVar(opCode - ILOpcode.stloc_0, false); break; case ILOpcode.ldarg_s: ImportLoadVar(ReadILByte(), true); break; case ILOpcode.ldarga_s: ImportAddressOfVar(ReadILByte(), true); break; case ILOpcode.starg_s: ImportStoreVar(ReadILByte(), true); break; case ILOpcode.ldloc_s: ImportLoadVar(ReadILByte(), false); break; case ILOpcode.ldloca_s: ImportAddressOfVar(ReadILByte(), false); break; case ILOpcode.stloc_s: ImportStoreVar(ReadILByte(), false); break; case ILOpcode.ldnull: ImportLoadNull(); break; case ILOpcode.ldc_i4_m1: ImportLoadInt(-1, StackValueKind.Int32); break; case ILOpcode.ldc_i4_0: case ILOpcode.ldc_i4_1: case ILOpcode.ldc_i4_2: case ILOpcode.ldc_i4_3: case ILOpcode.ldc_i4_4: case ILOpcode.ldc_i4_5: case ILOpcode.ldc_i4_6: case ILOpcode.ldc_i4_7: case ILOpcode.ldc_i4_8: ImportLoadInt(opCode - ILOpcode.ldc_i4_0, StackValueKind.Int32); break; case ILOpcode.ldc_i4_s: ImportLoadInt((sbyte)ReadILByte(), StackValueKind.Int32); break; case ILOpcode.ldc_i4: ImportLoadInt((int)ReadILUInt32(), StackValueKind.Int32); break; case ILOpcode.ldc_i8: ImportLoadInt((long)ReadILUInt64(), StackValueKind.Int64); break; case ILOpcode.ldc_r4: ImportLoadFloat(ReadILFloat()); break; case ILOpcode.ldc_r8: ImportLoadFloat(ReadILDouble()); break; case ILOpcode.dup: ImportDup(); break; case ILOpcode.pop: ImportPop(); break; case ILOpcode.jmp: ImportJmp(ReadILToken()); EndImportingInstruction(); return; case ILOpcode.call: ImportCall(opCode, ReadILToken()); break; case ILOpcode.calli: ImportCalli(ReadILToken()); break; case ILOpcode.ret: ImportReturn(); EndImportingInstruction(); return; case ILOpcode.br_s: case ILOpcode.brfalse_s: case ILOpcode.brtrue_s: case ILOpcode.beq_s: case ILOpcode.bge_s: case ILOpcode.bgt_s: case ILOpcode.ble_s: case ILOpcode.blt_s: case ILOpcode.bne_un_s: case ILOpcode.bge_un_s: case ILOpcode.bgt_un_s: case ILOpcode.ble_un_s: case ILOpcode.blt_un_s: { int delta = (sbyte)ReadILByte(); ImportBranch(opCode + (ILOpcode.br - ILOpcode.br_s), _basicBlocks[_currentOffset + delta], (opCode != ILOpcode.br_s) ? _basicBlocks[_currentOffset] : null); } EndImportingInstruction(); return; case ILOpcode.br: case ILOpcode.brfalse: case ILOpcode.brtrue: case ILOpcode.beq: case ILOpcode.bge: case ILOpcode.bgt: case ILOpcode.ble: case ILOpcode.blt: case ILOpcode.bne_un: case ILOpcode.bge_un: case ILOpcode.bgt_un: case ILOpcode.ble_un: case ILOpcode.blt_un: { int delta = (int)ReadILUInt32(); ImportBranch(opCode, _basicBlocks[_currentOffset + delta], (opCode != ILOpcode.br) ? _basicBlocks[_currentOffset] : null); } EndImportingInstruction(); return; case ILOpcode.switch_: { uint count = ReadILUInt32(); int jmpBase = _currentOffset + (int)(4 * count); int[] jmpDelta = new int[count]; for (uint i = 0; i < count; i++) { jmpDelta[i] = (int)ReadILUInt32(); } ImportSwitchJump(jmpBase, jmpDelta, _basicBlocks[_currentOffset]); } EndImportingInstruction(); return; case ILOpcode.ldind_i1: ImportLoadIndirect(WellKnownType.SByte); break; case ILOpcode.ldind_u1: ImportLoadIndirect(WellKnownType.Byte); break; case ILOpcode.ldind_i2: ImportLoadIndirect(WellKnownType.Int16); break; case ILOpcode.ldind_u2: ImportLoadIndirect(WellKnownType.UInt16); break; case ILOpcode.ldind_i4: ImportLoadIndirect(WellKnownType.Int32); break; case ILOpcode.ldind_u4: ImportLoadIndirect(WellKnownType.UInt32); break; case ILOpcode.ldind_i8: ImportLoadIndirect(WellKnownType.Int64); break; case ILOpcode.ldind_i: ImportLoadIndirect(WellKnownType.IntPtr); break; case ILOpcode.ldind_r4: ImportLoadIndirect(WellKnownType.Single); break; case ILOpcode.ldind_r8: ImportLoadIndirect(WellKnownType.Double); break; case ILOpcode.ldind_ref: ImportLoadIndirect(null); break; case ILOpcode.stind_ref: ImportStoreIndirect(null); break; case ILOpcode.stind_i1: ImportStoreIndirect(WellKnownType.SByte); break; case ILOpcode.stind_i2: ImportStoreIndirect(WellKnownType.Int16); break; case ILOpcode.stind_i4: ImportStoreIndirect(WellKnownType.Int32); break; case ILOpcode.stind_i8: ImportStoreIndirect(WellKnownType.Int64); break; case ILOpcode.stind_r4: ImportStoreIndirect(WellKnownType.Single); break; case ILOpcode.stind_r8: ImportStoreIndirect(WellKnownType.Double); break; case ILOpcode.add: case ILOpcode.sub: case ILOpcode.mul: case ILOpcode.div: case ILOpcode.div_un: case ILOpcode.rem: case ILOpcode.rem_un: case ILOpcode.and: case ILOpcode.or: case ILOpcode.xor: ImportBinaryOperation(opCode); break; case ILOpcode.shl: case ILOpcode.shr: case ILOpcode.shr_un: ImportShiftOperation(opCode); break; case ILOpcode.neg: case ILOpcode.not: ImportUnaryOperation(opCode); break; case ILOpcode.conv_i1: ImportConvert(WellKnownType.SByte, false, false); break; case ILOpcode.conv_i2: ImportConvert(WellKnownType.Int16, false, false); break; case ILOpcode.conv_i4: ImportConvert(WellKnownType.Int32, false, false); break; case ILOpcode.conv_i8: ImportConvert(WellKnownType.Int64, false, false); break; case ILOpcode.conv_r4: ImportConvert(WellKnownType.Single, false, false); break; case ILOpcode.conv_r8: ImportConvert(WellKnownType.Double, false, false); break; case ILOpcode.conv_u4: ImportConvert(WellKnownType.UInt32, false, false); break; case ILOpcode.conv_u8: ImportConvert(WellKnownType.UInt64, false, true); break; case ILOpcode.callvirt: ImportCall(opCode, ReadILToken()); break; case ILOpcode.cpobj: ImportCpOpj(ReadILToken()); break; case ILOpcode.ldobj: ImportLoadIndirect(ReadILToken()); break; case ILOpcode.ldstr: ImportLoadString(ReadILToken()); break; case ILOpcode.newobj: ImportCall(opCode, ReadILToken()); break; case ILOpcode.castclass: case ILOpcode.isinst: ImportCasting(opCode, ReadILToken()); break; case ILOpcode.conv_r_un: ImportConvert(WellKnownType.Double, false, true); break; case ILOpcode.unbox: ImportUnbox(ReadILToken(), opCode); break; case ILOpcode.throw_: ImportThrow(); EndImportingInstruction(); return; case ILOpcode.ldfld: ImportLoadField(ReadILToken(), false); break; case ILOpcode.ldflda: ImportAddressOfField(ReadILToken(), false); break; case ILOpcode.stfld: ImportStoreField(ReadILToken(), false); break; case ILOpcode.ldsfld: ImportLoadField(ReadILToken(), true); break; case ILOpcode.ldsflda: ImportAddressOfField(ReadILToken(), true); break; case ILOpcode.stsfld: ImportStoreField(ReadILToken(), true); break; case ILOpcode.stobj: ImportStoreIndirect(ReadILToken()); break; case ILOpcode.conv_ovf_i1_un: ImportConvert(WellKnownType.SByte, true, true); break; case ILOpcode.conv_ovf_i2_un: ImportConvert(WellKnownType.Int16, true, true); break; case ILOpcode.conv_ovf_i4_un: ImportConvert(WellKnownType.Int32, true, true); break; case ILOpcode.conv_ovf_i8_un: ImportConvert(WellKnownType.Int64, true, true); break; case ILOpcode.conv_ovf_u1_un: ImportConvert(WellKnownType.Byte, true, true); break; case ILOpcode.conv_ovf_u2_un: ImportConvert(WellKnownType.UInt16, true, true); break; case ILOpcode.conv_ovf_u4_un: ImportConvert(WellKnownType.UInt32, true, true); break; case ILOpcode.conv_ovf_u8_un: ImportConvert(WellKnownType.UInt64, true, true); break; case ILOpcode.conv_ovf_i_un: ImportConvert(WellKnownType.IntPtr, true, true); break; case ILOpcode.conv_ovf_u_un: ImportConvert(WellKnownType.UIntPtr, true, true); break; case ILOpcode.box: ImportBox(ReadILToken()); break; case ILOpcode.newarr: ImportNewArray(ReadILToken()); break; case ILOpcode.ldlen: ImportLoadLength(); break; case ILOpcode.ldelema: ImportAddressOfElement(ReadILToken()); break; case ILOpcode.ldelem_i1: ImportLoadElement(WellKnownType.SByte); break; case ILOpcode.ldelem_u1: ImportLoadElement(WellKnownType.Byte); break; case ILOpcode.ldelem_i2: ImportLoadElement(WellKnownType.Int16); break; case ILOpcode.ldelem_u2: ImportLoadElement(WellKnownType.UInt16); break; case ILOpcode.ldelem_i4: ImportLoadElement(WellKnownType.Int32); break; case ILOpcode.ldelem_u4: ImportLoadElement(WellKnownType.UInt32); break; case ILOpcode.ldelem_i8: ImportLoadElement(WellKnownType.Int64); break; case ILOpcode.ldelem_i: ImportLoadElement(WellKnownType.IntPtr); break; case ILOpcode.ldelem_r4: ImportLoadElement(WellKnownType.Single); break; case ILOpcode.ldelem_r8: ImportLoadElement(WellKnownType.Double); break; case ILOpcode.ldelem_ref: ImportLoadElement(null); break; case ILOpcode.stelem_i: ImportStoreElement(WellKnownType.IntPtr); break; case ILOpcode.stelem_i1: ImportStoreElement(WellKnownType.SByte); break; case ILOpcode.stelem_i2: ImportStoreElement(WellKnownType.Int16); break; case ILOpcode.stelem_i4: ImportStoreElement(WellKnownType.Int32); break; case ILOpcode.stelem_i8: ImportStoreElement(WellKnownType.Int64); break; case ILOpcode.stelem_r4: ImportStoreElement(WellKnownType.Single); break; case ILOpcode.stelem_r8: ImportStoreElement(WellKnownType.Double); break; case ILOpcode.stelem_ref: ImportStoreElement(null); break; case ILOpcode.ldelem: ImportLoadElement(ReadILToken()); break; case ILOpcode.stelem: ImportStoreElement(ReadILToken()); break; case ILOpcode.unbox_any: ImportUnbox(ReadILToken(), opCode); break; case ILOpcode.conv_ovf_i1: ImportConvert(WellKnownType.SByte, true, false); break; case ILOpcode.conv_ovf_u1: ImportConvert(WellKnownType.Byte, true, false); break; case ILOpcode.conv_ovf_i2: ImportConvert(WellKnownType.Int16, true, false); break; case ILOpcode.conv_ovf_u2: ImportConvert(WellKnownType.UInt16, true, false); break; case ILOpcode.conv_ovf_i4: ImportConvert(WellKnownType.Int32, true, false); break; case ILOpcode.conv_ovf_u4: ImportConvert(WellKnownType.UInt32, true, false); break; case ILOpcode.conv_ovf_i8: ImportConvert(WellKnownType.Int64, true, false); break; case ILOpcode.conv_ovf_u8: ImportConvert(WellKnownType.UInt64, true, false); break; case ILOpcode.refanyval: ImportRefAnyVal(ReadILToken()); break; case ILOpcode.ckfinite: ImportCkFinite(); break; case ILOpcode.mkrefany: ImportMkRefAny(ReadILToken()); break; case ILOpcode.ldtoken: ImportLdToken(ReadILToken()); break; case ILOpcode.conv_u2: ImportConvert(WellKnownType.UInt16, false, false); break; case ILOpcode.conv_u1: ImportConvert(WellKnownType.Byte, false, false); break; case ILOpcode.conv_i: ImportConvert(WellKnownType.IntPtr, false, false); break; case ILOpcode.conv_ovf_i: ImportConvert(WellKnownType.IntPtr, true, false); break; case ILOpcode.conv_ovf_u: ImportConvert(WellKnownType.UIntPtr, true, false); break; case ILOpcode.add_ovf: case ILOpcode.add_ovf_un: case ILOpcode.mul_ovf: case ILOpcode.mul_ovf_un: case ILOpcode.sub_ovf: case ILOpcode.sub_ovf_un: ImportBinaryOperation(opCode); break; case ILOpcode.endfinally: //both endfinally and endfault ImportEndFinally(); EndImportingInstruction(); return; case ILOpcode.leave: { int delta = (int)ReadILUInt32(); ImportLeave(_basicBlocks[_currentOffset + delta]); } EndImportingInstruction(); return; case ILOpcode.leave_s: { int delta = (sbyte)ReadILByte(); ImportLeave(_basicBlocks[_currentOffset + delta]); } EndImportingInstruction(); return; case ILOpcode.stind_i: ImportStoreIndirect(WellKnownType.IntPtr); break; case ILOpcode.conv_u: ImportConvert(WellKnownType.UIntPtr, false, false); break; case ILOpcode.prefix1: opCode = (ILOpcode)(0x100 + ReadILByte()); goto again; case ILOpcode.arglist: ImportArgList(); break; case ILOpcode.ceq: case ILOpcode.cgt: case ILOpcode.cgt_un: case ILOpcode.clt: case ILOpcode.clt_un: ImportCompareOperation(opCode); break; case ILOpcode.ldftn: case ILOpcode.ldvirtftn: ImportLdFtn(ReadILToken(), opCode); break; case ILOpcode.ldarg: ImportLoadVar(ReadILUInt16(), true); break; case ILOpcode.ldarga: ImportAddressOfVar(ReadILUInt16(), true); break; case ILOpcode.starg: ImportStoreVar(ReadILUInt16(), true); break; case ILOpcode.ldloc: ImportLoadVar(ReadILUInt16(), false); break; case ILOpcode.ldloca: ImportAddressOfVar(ReadILUInt16(), false); break; case ILOpcode.stloc: ImportStoreVar(ReadILUInt16(), false); break; case ILOpcode.localloc: ImportLocalAlloc(); break; case ILOpcode.endfilter: ImportEndFilter(); EndImportingInstruction(); return; case ILOpcode.unaligned: ImportUnalignedPrefix(ReadILByte()); continue; case ILOpcode.volatile_: ImportVolatilePrefix(); continue; case ILOpcode.tail: ImportTailPrefix(); continue; case ILOpcode.initobj: ImportInitObj(ReadILToken()); break; case ILOpcode.constrained: ImportConstrainedPrefix(ReadILToken()); continue; case ILOpcode.cpblk: ImportCpBlk(); break; case ILOpcode.initblk: ImportInitBlk(); break; case ILOpcode.no: ImportNoPrefix(ReadILByte()); continue; case ILOpcode.rethrow: ImportRethrow(); EndImportingInstruction(); return; case ILOpcode.sizeof_: ImportSizeOf(ReadILToken()); break; case ILOpcode.refanytype: ImportRefAnyType(); break; case ILOpcode.readonly_: ImportReadOnlyPrefix(); continue; default: ReportInvalidInstruction(opCode); EndImportingInstruction(); return; } EndImportingInstruction(); // Check if control falls through the end of method. if (_currentOffset == _basicBlocks.Length) { ReportFallthroughAtEndOfMethod(); return; } BasicBlock nextBasicBlock = _basicBlocks[_currentOffset]; if (nextBasicBlock != null) { ImportFallthrough(nextBasicBlock); return; } } }
/// <summary> /// Parse MIbcGroup method and return enumerable of MethodProfileData /// /// Like the AssemblyDictionary method, data is encoded via IL instructions. The format is /// /// ldtoken methodInProfileData /// Any series of instructions that does not include pop. Expansion data is encoded via ldstr "id" /// followed by a expansion specific sequence of il opcodes. /// pop /// {Repeat N times for N methods described} /// /// Extensions supported with current parser: /// /// ldstr "ExclusiveWeight" /// Any ldc.i4 or ldc.r4 or ldc.r8 instruction to indicate the exclusive weight /// /// ldstr "WeightedCallData" /// ldc.i4 <Count of methods called> /// Repeat <Count of methods called times> /// ldtoken <Method called from this method> /// ldc.i4 <Weight associated with calling the <Method called from this method>> /// /// This format is designed to be extensible to hold more data as we add new per method profile data without breaking existing parsers. /// </summary> static IEnumerable <MethodProfileData> ReadMIbcGroup(TypeSystemContext tsc, EcmaMethod method) { EcmaMethodIL ilBody = EcmaMethodIL.Create(method); MetadataLoaderForPgoData metadataLoader = new MetadataLoaderForPgoData(ilBody); byte[] ilBytes = ilBody.GetILBytes(); int currentOffset = 0; object methodInProgress = null; object metadataNotResolvable = new object(); object metadataObject = null; MibcGroupParseState state = MibcGroupParseState.LookingForNextMethod; int intValue = 0; int weightedCallGraphSize = 0; int profileEntryFound = 0; double exclusiveWeight = 0; Dictionary <MethodDesc, int> weights = null; bool processIntValue = false; List <long> instrumentationDataLongs = null; PgoSchemaElem[] pgoSchemaData = null; while (currentOffset < ilBytes.Length) { ILOpcode opcode = (ILOpcode)ilBytes[currentOffset]; if (opcode == ILOpcode.prefix1) { opcode = 0x100 + (ILOpcode)ilBytes[currentOffset + 1]; } processIntValue = false; switch (opcode) { case ILOpcode.ldtoken: { uint token = BitConverter.ToUInt32(ilBytes.AsSpan(currentOffset + 1, 4)); if (state == MibcGroupParseState.ProcessingInstrumentationData) { instrumentationDataLongs.Add(token); } else { metadataObject = null; try { metadataObject = ilBody.GetObject((int)token); } catch (TypeSystemException) { // The method being referred to may be missing. In that situation, // use the metadataNotResolvable sentinel to indicate that this record should be ignored metadataObject = metadataNotResolvable; } switch (state) { case MibcGroupParseState.ProcessingCallgraphToken: state = MibcGroupParseState.ProcessingCallgraphWeight; break; case MibcGroupParseState.LookingForNextMethod: methodInProgress = metadataObject; state = MibcGroupParseState.LookingForOptionalData; break; default: state = MibcGroupParseState.LookingForOptionalData; break; } } } break; case ILOpcode.ldc_r4: { float fltValue = BitConverter.ToSingle(ilBytes.AsSpan(currentOffset + 1, 4)); switch (state) { case MibcGroupParseState.ProcessingExclusiveWeight: exclusiveWeight = fltValue; state = MibcGroupParseState.LookingForOptionalData; break; default: state = MibcGroupParseState.LookingForOptionalData; break; } break; } case ILOpcode.ldc_r8: { double dblValue = BitConverter.ToDouble(ilBytes.AsSpan(currentOffset + 1, 8)); switch (state) { case MibcGroupParseState.ProcessingExclusiveWeight: exclusiveWeight = dblValue; state = MibcGroupParseState.LookingForOptionalData; break; default: state = MibcGroupParseState.LookingForOptionalData; break; } break; } case ILOpcode.ldc_i4_0: intValue = 0; processIntValue = true; break; case ILOpcode.ldc_i4_1: intValue = 1; processIntValue = true; break; case ILOpcode.ldc_i4_2: intValue = 2; processIntValue = true; break; case ILOpcode.ldc_i4_3: intValue = 3; processIntValue = true; break; case ILOpcode.ldc_i4_4: intValue = 4; processIntValue = true; break; case ILOpcode.ldc_i4_5: intValue = 5; processIntValue = true; break; case ILOpcode.ldc_i4_6: intValue = 6; processIntValue = true; break; case ILOpcode.ldc_i4_7: intValue = 7; processIntValue = true; break; case ILOpcode.ldc_i4_8: intValue = 8; processIntValue = true; break; case ILOpcode.ldc_i4_m1: intValue = -1; processIntValue = true; break; case ILOpcode.ldc_i4_s: intValue = (sbyte)ilBytes[currentOffset + 1]; processIntValue = true; break; case ILOpcode.ldc_i4: intValue = BitConverter.ToInt32(ilBytes.AsSpan(currentOffset + 1, 4)); processIntValue = true; break; case ILOpcode.ldc_i8: if (state == MibcGroupParseState.ProcessingInstrumentationData) { instrumentationDataLongs.Add(BitConverter.ToInt64(ilBytes.AsSpan(currentOffset + 1, 8))); } break; case ILOpcode.ldstr: { UInt32 userStringToken = BitConverter.ToUInt32(ilBytes.AsSpan(currentOffset + 1, 4)); string optionalDataName = (string)ilBody.GetObject((int)userStringToken); switch (optionalDataName) { case "ExclusiveWeight": state = MibcGroupParseState.ProcessingExclusiveWeight; break; case "WeightedCallData": state = MibcGroupParseState.ProcessingCallgraphCount; break; case "InstrumentationDataStart": state = MibcGroupParseState.ProcessingInstrumentationData; instrumentationDataLongs = new List <long>(); break; case "InstrumentationDataEnd": if (instrumentationDataLongs != null) { instrumentationDataLongs.Add(2); // MarshalMask 2 (Type) instrumentationDataLongs.Add(0); // PgoInstrumentationKind.Done (0) pgoSchemaData = PgoProcessor.ParsePgoData <TypeSystemEntityOrUnknown>(metadataLoader, instrumentationDataLongs, false).ToArray(); } state = MibcGroupParseState.LookingForOptionalData; break; default: state = MibcGroupParseState.LookingForOptionalData; break; } } break; case ILOpcode.pop: if (methodInProgress != metadataNotResolvable) { profileEntryFound++; if (exclusiveWeight == 0) { // If no exclusive weight is found assign a non zero value that assumes the order in the pgo file is significant. exclusiveWeight = Math.Min(1000000.0 - profileEntryFound, 0.0) / 1000000.0; } MethodProfileData mibcData = new MethodProfileData((MethodDesc)methodInProgress, MethodProfilingDataFlags.ReadMethodCode, exclusiveWeight, weights, 0xFFFFFFFF, pgoSchemaData); state = MibcGroupParseState.LookingForNextMethod; exclusiveWeight = 0; weights = null; instrumentationDataLongs = null; pgoSchemaData = null; yield return(mibcData); } methodInProgress = null; break; default: state = MibcGroupParseState.LookingForOptionalData; break; } if (processIntValue) { switch (state) { case MibcGroupParseState.ProcessingExclusiveWeight: exclusiveWeight = intValue; state = MibcGroupParseState.LookingForOptionalData; break; case MibcGroupParseState.ProcessingCallgraphCount: weightedCallGraphSize = intValue; weights = new Dictionary <MethodDesc, int>(); if (weightedCallGraphSize > 0) { state = MibcGroupParseState.ProcessingCallgraphToken; } else { state = MibcGroupParseState.LookingForOptionalData; } break; case MibcGroupParseState.ProcessingCallgraphWeight: if (metadataObject != metadataNotResolvable) { weights.Add((MethodDesc)metadataObject, intValue); } weightedCallGraphSize--; if (weightedCallGraphSize > 0) { state = MibcGroupParseState.ProcessingCallgraphToken; } else { state = MibcGroupParseState.LookingForOptionalData; } break; case MibcGroupParseState.ProcessingInstrumentationData: instrumentationDataLongs.Add(intValue); break; default: state = MibcGroupParseState.LookingForOptionalData; instrumentationDataLongs = null; break; } } // This isn't correct if there is a switch opcode, but since we won't do that, its ok currentOffset += opcode.GetSize(); } }
private void ImportLdFtn(int token, ILOpcode opCode) { MethodDesc method = (MethodDesc)_methodIL.GetObject(token); if (opCode == ILOpcode.ldvirtftn) { if (method.IsVirtual) throw new NotImplementedException(); } AddMethodReference(method); var entry = new LdTokenEntry<MethodDesc>(StackValueKind.NativeInt, NewTempName(), method); PushTemp(entry); Append("(intptr_t)&"); Append(_writer.GetCppTypeName(method.OwningType)); Append("::"); Append(_writer.GetCppMethodName(method)); AppendSemicolon(); }
private void ImportLdFtn(int token, ILOpcode opCode) { MethodDesc method = (MethodDesc)_methodIL.GetObject(token); if (opCode == ILOpcode.ldvirtftn) { if (method.IsVirtual) throw new NotImplementedException(); } _compilation.AddMethod(method); PushTemp(StackValueKind.NativeInt); Append("(intptr_t)&"); Append(_writer.GetCppTypeName(method.OwningType)); Append("::"); Append(_writer.GetCppMethodName(method)); _stack[_stackTop - 1].Value.Aux = method; Finish(); }
private void ImportCall(ILOpcode opcode, int token) { bool callViaSlot = false; bool delegateInvoke = false; DelegateInfo delegateInfo = null; bool mdArrayCreate = false; MethodDesc method = (MethodDesc)_methodIL.GetObject(token); var intrinsicClassification = IntrinsicMethods.GetIntrinsicMethodClassification(method); if (intrinsicClassification != IntrinsicMethodKind.None) { ImportIntrinsicCall(intrinsicClassification); return; } if (opcode == ILOpcode.calli) throw new NotImplementedException(); TypeDesc constrained = null; if (opcode != ILOpcode.newobj) { if ((_pendingPrefix & Prefix.Constrained) != 0 && opcode == ILOpcode.callvirt) { _pendingPrefix &= ~Prefix.Constrained; constrained = _constrained; // TODO: throw new NotImplementedException(); } } TypeDesc retType = null; { TypeDesc owningType = method.OwningType; if (opcode == ILOpcode.newobj) retType = owningType; if (opcode == ILOpcode.newobj) { if (owningType.IsString) { // String constructors actually look like regular method calls method = IntrinsicMethods.GetStringInitializer(method); opcode = ILOpcode.call; // WORKAROUND: the static method expects an extra arg // Annoyingly, it needs to be before all the others if (_stackTop >= _stack.Length) Array.Resize(ref _stack, 2 * _stackTop + 3); for (int i = _stackTop - 1; i > _stackTop - method.Signature.Length; i--) _stack[i + 1] = _stack[i]; _stackTop++; _stack[_stackTop - method.Signature.Length] = new StackValue { Kind = StackValueKind.ObjRef, Value = new Value("0") }; } else if (owningType.IsArray) { mdArrayCreate = true; } else if (owningType.IsDelegate) { delegateInfo = _compilation.GetDelegateCtor((MethodDesc)_stack[_stackTop - 1].Value.Aux); method = delegateInfo.Ctor; } } else if (owningType.IsDelegate) { if (method.Name == "Invoke") { opcode = ILOpcode.call; delegateInvoke = true; } } } if (opcode == ILOpcode.callvirt) { // TODO: Null checks if (method.IsVirtual) { // TODO: Full resolution of virtual methods if (!method.IsNewSlot) throw new NotImplementedException(); // TODO: Interface calls if (method.OwningType.IsInterface) throw new NotImplementedException(); _compilation.AddVirtualSlot(method); callViaSlot = true; } } if (!callViaSlot && !delegateInvoke && !mdArrayCreate) _compilation.AddMethod(method); if (opcode == ILOpcode.newobj) _compilation.MarkAsConstructed(retType); var methodSignature = method.Signature; if (retType == null) retType = methodSignature.ReturnType; string temp = null; StackValueKind retKind = StackValueKind.Unknown; if (!retType.IsVoid) { retKind = GetStackValueKind(retType); temp = NewTempName(); Append(GetStackValueKindCPPTypeName(retKind, retType)); Append(" "); Append(temp); if (retType.IsValueType && opcode == ILOpcode.newobj) { Append(";"); } else { Append("="); if (retType.IsPointer) { Append("(intptr_t)"); } } } if (opcode == ILOpcode.newobj && !mdArrayCreate) { if (!retType.IsValueType) { _compilation.AddType(retType); Append("__allocate_object("); Append(_writer.GetCppTypeName(retType)); Append("::__getMethodTable())"); Finish(); if (delegateInfo != null && delegateInfo.ShuffleThunk != null) { _stack[_stackTop - 2].Value.Name = temp; StringBuilder sb = new StringBuilder(); sb.Append("(intptr_t)&"); sb.Append(_writer.GetCppTypeName(delegateInfo.ShuffleThunk.OwningType)); sb.Append("::"); sb.Append(_writer.GetCppMethodName(delegateInfo.ShuffleThunk)); Push(StackValueKind.NativeInt, new Value(sb.ToString()), null); } } } if (callViaSlot || delegateInvoke) { Append("(*"); Append(_writer.GetCppTypeName(method.OwningType)); Append("::"); Append(delegateInvoke ? "__invoke__" : "__getslot__"); Append(_writer.GetCppMethodName(method)); Append("("); Append(_stack[_stackTop - (methodSignature.Length + 1)].Value.Name); Append("))"); if (delegateInvoke) { _stack[_stackTop - (methodSignature.Length + 1)].Value.Name = "((" + _writer.GetCppSignatureTypeName(GetWellKnownType(WellKnownType.MulticastDelegate)) + ")" + _stack[_stackTop - (methodSignature.Length + 1)].Value.Name + ")->m_firstParameter"; } } else if (mdArrayCreate) { _compilation.AddType(method.OwningType); Append("RhNewMDArray"); } else { Append(_writer.GetCppTypeName(method.OwningType)); Append("::"); Append(_writer.GetCppMethodName(method)); } Append("("); int count = methodSignature.Length; bool hasThis = !methodSignature.IsStatic; if (hasThis) count++; if (mdArrayCreate) { Append(_writer.GetCppTypeName(method.OwningType)); Append("::__getMethodTable(), "); Append(((ArrayType)method.OwningType).Rank.ToString()); Append(", "); count--; } else if (opcode == ILOpcode.newobj) { Append("("); if (retType.IsValueType) { Append(_writer.GetCppSignatureTypeName(retType.MakeByRefType())); Append(")"); Append("&" + temp); } else { Append(_writer.GetCppSignatureTypeName(retType)); Append(")"); Append(temp); } count--; if (count > 0) Append(", "); } for (int i = 0; i < count; i++) { var op = _stack[_stackTop - count + i]; int argIndex = methodSignature.Length - (count - i); TypeDesc argType; if (argIndex == -1) { argType = method.OwningType; if (argType.IsValueType) argType = argType.MakeByRefType(); } else { argType = methodSignature[argIndex]; } AppendCastIfNecessary(argType, op.Kind); Append(op.Value.Name); if (i != count - 1) Append(", "); } _stackTop -= count; Append(")"); if (temp != null) Push(retKind, new Value(temp), retType); Finish(); }
private void ImportUnaryOperation(ILOpcode opCode) { var argument = _stack.Pop(); PushTemp(argument.Kind, argument.Type); Debug.Assert((opCode == ILOpcode.neg) || (opCode == ILOpcode.not)); Append((opCode == ILOpcode.neg) ? "-" : "~"); Append(argument); AppendSemicolon(); }
private void ImportUnaryOperation(ILOpcode opCode) { var argument = _stack.Pop(); if (argument.Kind == StackValueKind.Float) throw new NotImplementedException(); PushTemp(argument.Kind, argument.Type); Append((opCode == ILOpcode.neg) ? "~" : "!"); Append(argument); AppendSemicolon(); }
private void ImportBranch(ILOpcode opcode, BasicBlock target, BasicBlock fallthrough) { AppendLine(); if (opcode != ILOpcode.br) { Append("if ("); if (opcode == ILOpcode.brfalse || opcode == ILOpcode.brtrue) { var op = _stack.Pop(); Append(op); Append((opcode == ILOpcode.brtrue) ? " != 0" : " == 0"); } else { var op1 = _stack.Pop(); var op2 = _stack.Pop(); // StackValueKind is carefully ordered to make this work (assuming the IL is valid) StackValueKind kind; if (op1.Kind > op2.Kind) { kind = op1.Kind; } else { kind = op2.Kind; } string op = null; bool unsigned = false; bool inverted = false; switch (opcode) { case ILOpcode.beq: op = "=="; break; case ILOpcode.bge: op = ">="; break; case ILOpcode.bgt: op = ">"; break; case ILOpcode.ble: op = "<="; break; case ILOpcode.blt: op = "<"; break; case ILOpcode.bne_un: op = "!="; break; case ILOpcode.bge_un: if (kind == StackValueKind.Float) { op = "<"; inverted = true; } else { op = ">="; } if (kind == StackValueKind.Int32 || kind == StackValueKind.Int64) unsigned = true; break; case ILOpcode.bgt_un: if (kind == StackValueKind.Float) { op = "<="; inverted = true; } else { op = ">"; } if (kind == StackValueKind.Int32 || kind == StackValueKind.Int64) unsigned = true; break; case ILOpcode.ble_un: if (kind == StackValueKind.Float) { op = ">"; inverted = true; } else { op = "<="; } if (kind == StackValueKind.Int32 || kind == StackValueKind.Int64) unsigned = true; break; case ILOpcode.blt_un: if (kind == StackValueKind.Float) { op = ">="; inverted = true; } else { op = "<"; } if (kind == StackValueKind.Int32 || kind == StackValueKind.Int64) unsigned = true; break; } if (kind == StackValueKind.ByRef) unsigned = false; if (inverted) { Append("!("); } if (unsigned) { Append("(u"); Append(GetStackValueKindCPPTypeName(kind)); Append(")"); } Append(op2); Append(" "); Append(op); Append(" "); if (unsigned) { Append("(u"); Append(GetStackValueKindCPPTypeName(kind)); Append(")"); } Append(op1); if (inverted) { Append(")"); } } Append(") "); } Append("{"); Indent(); ImportFallthrough(target); AppendLine(); Append("goto _bb"); Append(target.StartOffset.ToStringInvariant()); AppendSemicolon(); Exdent(); AppendLine(); Append("}"); if (fallthrough != null) ImportFallthrough(fallthrough); }
void ImportShiftOperation(ILOpcode opcode) { var shiftAmount = Pop(); var op = Pop(); PushTemp(op.Kind, op.Type); if (opcode == ILOpcode.shr_un) { Append("(u"); Append(GetStackValueKindCPPTypeName(op.Kind)); Append(")"); } Append(op.Value.Name); Append((opcode == ILOpcode.shl) ? "<<" : ">>"); Append(shiftAmount.Value.Name); Finish(); }
public void Emit(ILOpcode opcode, int token) { Emit(opcode); EmitUInt32(token); }
private void ImportBinaryOperation(ILOpcode opcode) { var op1 = _stack.Pop(); var op2 = _stack.Pop(); // StackValueKind is carefully ordered to make this work (assuming the IL is valid) StackValueKind kind; TypeDesc type; if (op1.Kind > op2.Kind) { kind = op1.Kind; type = op1.Type; } else { kind = op2.Kind; type = op2.Type; } // The one exception from the above rule if ((kind == StackValueKind.ByRef) && (opcode == ILOpcode.sub || opcode == ILOpcode.sub_ovf || opcode == ILOpcode.sub_ovf_un)) { kind = StackValueKind.NativeInt; type = null; } PushTemp(kind, type); string op = null; bool unsigned = false; switch (opcode) { case ILOpcode.add: op = "+"; break; case ILOpcode.sub: op = "-"; break; case ILOpcode.mul: op = "*"; break; case ILOpcode.div: op = "/"; break; case ILOpcode.div_un: op = "/"; unsigned = true; break; case ILOpcode.rem: op = "%"; break; case ILOpcode.rem_un: op = "%"; unsigned = true; break; case ILOpcode.and: op = "&"; break; case ILOpcode.or: op = "|"; break; case ILOpcode.xor: op = "^"; break; // TODO: Overflow checks case ILOpcode.add_ovf: op = "+"; break; case ILOpcode.add_ovf_un: op = "+"; unsigned = true; break; case ILOpcode.sub_ovf: op = "-"; break; case ILOpcode.sub_ovf_un: op = "-"; unsigned = true; break; case ILOpcode.mul_ovf: op = "*"; break; case ILOpcode.mul_ovf_un: op = "*"; unsigned = true; break; default: Debug.Assert(false, "Unexpected opcode"); break; } if (unsigned) { Append("(u"); Append(GetStackValueKindCPPTypeName(kind)); Append(")"); } Append(op2); Append(" "); Append(op); Append(" "); if (unsigned) { Append("(u"); Append(GetStackValueKindCPPTypeName(kind)); Append(")"); } Append(op1); AppendSemicolon(); }
public void Emit(ILOpcode opcode) { if ((int)opcode > 0x100) EmitByte((byte)ILOpcode.prefix1); EmitByte((byte)opcode); }
private void ImportShiftOperation(ILOpcode opcode) { var shiftAmount = _stack.Pop(); var op = _stack.Pop(); PushTemp(op.Kind, op.Type); if (opcode == ILOpcode.shr_un) { Append("(u"); Append(GetStackValueKindCPPTypeName(op.Kind)); Append(")"); } Append(op); Append((opcode == ILOpcode.shl) ? " << " : " >> "); Append(shiftAmount); AppendSemicolon(); }
private void FindJumpTargets() { _currentOffset = 0; while (_currentOffset < _ilBytes.Length) { MarkInstructionBoundary(); ILOpcode opCode = (ILOpcode)ReadILByte(); again: switch (opCode) { case ILOpcode.ldarg_s: case ILOpcode.ldarga_s: case ILOpcode.starg_s: case ILOpcode.ldloc_s: case ILOpcode.ldloca_s: case ILOpcode.stloc_s: case ILOpcode.ldc_i4_s: case ILOpcode.unaligned: case ILOpcode.no: SkipIL(1); break; case ILOpcode.ldarg: case ILOpcode.ldarga: case ILOpcode.starg: case ILOpcode.ldloc: case ILOpcode.ldloca: case ILOpcode.stloc: SkipIL(2); break; case ILOpcode.ldc_i4: case ILOpcode.ldc_r4: SkipIL(4); break; case ILOpcode.ldc_i8: case ILOpcode.ldc_r8: SkipIL(8); break; case ILOpcode.jmp: case ILOpcode.call: case ILOpcode.calli: case ILOpcode.callvirt: case ILOpcode.cpobj: case ILOpcode.ldobj: case ILOpcode.ldstr: case ILOpcode.newobj: case ILOpcode.castclass: case ILOpcode.isinst: case ILOpcode.unbox: case ILOpcode.ldfld: case ILOpcode.ldflda: case ILOpcode.stfld: case ILOpcode.ldsfld: case ILOpcode.ldsflda: case ILOpcode.stsfld: case ILOpcode.stobj: case ILOpcode.box: case ILOpcode.newarr: case ILOpcode.ldelema: case ILOpcode.ldelem: case ILOpcode.stelem: case ILOpcode.unbox_any: case ILOpcode.refanyval: case ILOpcode.mkrefany: case ILOpcode.ldtoken: case ILOpcode.ldftn: case ILOpcode.ldvirtftn: case ILOpcode.initobj: case ILOpcode.constrained: case ILOpcode.sizeof_: SkipIL(4); break; case ILOpcode.prefix1: opCode = (ILOpcode)(0x100 + ReadILByte()); goto again; case ILOpcode.br_s: case ILOpcode.leave_s: { int delta = (sbyte)ReadILByte(); int target = _currentOffset + delta; if ((uint)target < (uint)_basicBlocks.Length) { CreateBasicBlock(target); } else { ReportInvalidBranchTarget(target); } } break; case ILOpcode.brfalse_s: case ILOpcode.brtrue_s: case ILOpcode.beq_s: case ILOpcode.bge_s: case ILOpcode.bgt_s: case ILOpcode.ble_s: case ILOpcode.blt_s: case ILOpcode.bne_un_s: case ILOpcode.bge_un_s: case ILOpcode.bgt_un_s: case ILOpcode.ble_un_s: case ILOpcode.blt_un_s: { int delta = (sbyte)ReadILByte(); int target = _currentOffset + delta; if ((uint)target < (uint)_basicBlocks.Length) { CreateBasicBlock(target); } else { ReportInvalidBranchTarget(target); } CreateBasicBlock(_currentOffset); } break; case ILOpcode.br: case ILOpcode.leave: { int delta = (int)ReadILUInt32(); int target = _currentOffset + delta; if ((uint)target < (uint)_basicBlocks.Length) { CreateBasicBlock(target); } else { ReportInvalidBranchTarget(target); } } break; case ILOpcode.brfalse: case ILOpcode.brtrue: case ILOpcode.beq: case ILOpcode.bge: case ILOpcode.bgt: case ILOpcode.ble: case ILOpcode.blt: case ILOpcode.bne_un: case ILOpcode.bge_un: case ILOpcode.bgt_un: case ILOpcode.ble_un: case ILOpcode.blt_un: { int delta = (int)ReadILUInt32(); int target = _currentOffset + delta; if ((uint)target < (uint)_basicBlocks.Length) { CreateBasicBlock(target); } else { ReportInvalidBranchTarget(target); } CreateBasicBlock(_currentOffset); } break; case ILOpcode.switch_: { uint count = ReadILUInt32(); int jmpBase = _currentOffset + (int)(4 * count); for (uint i = 0; i < count; i++) { int delta = (int)ReadILUInt32(); int target = jmpBase + delta; if ((uint)target < (uint)_basicBlocks.Length) { CreateBasicBlock(target); } else { ReportInvalidBranchTarget(target); } } CreateBasicBlock(_currentOffset); } break; default: continue; } } }
public void Emit(ILOpcode opcode, ILToken token) { Emit(opcode); EmitUInt32((int)token); }
bool IsBinaryComparable(StackValue src, StackValue dst, ILOpcode op) { if (src.Kind == dst.Kind && src.Type == dst.Type) { return(true); } switch (src.Kind) { case StackValueKind.ObjRef: switch (dst.Kind) { case StackValueKind.ObjRef: // ECMA-335 III.1.5 Operand type table, P. 303: // __cgt.un__ is allowed and verifiable on ObjectRefs (O). This is commonly used when // comparing an ObjectRef with null(there is no "compare - not - equal" instruction, which // would otherwise be a more obvious solution) return(op == ILOpcode.beq || op == ILOpcode.beq_s || op == ILOpcode.bne_un || op == ILOpcode.bne_un_s || op == ILOpcode.ceq || op == ILOpcode.cgt_un); default: return(false); } case StackValueKind.ValueType: return(false); case StackValueKind.ByRef: switch (dst.Kind) { case StackValueKind.ByRef: return(true); case StackValueKind.NativeInt: return(op == ILOpcode.beq || op == ILOpcode.beq_s || op == ILOpcode.bne_un || op == ILOpcode.bne_un_s || op == ILOpcode.ceq); default: return(false); } case StackValueKind.Int32: return(dst.Kind == StackValueKind.Int64 || dst.Kind == StackValueKind.NativeInt); case StackValueKind.Int64: return(dst.Kind == StackValueKind.Int64); case StackValueKind.NativeInt: switch (dst.Kind) { case StackValueKind.Int32: case StackValueKind.NativeInt: return(true); case StackValueKind.ByRef: return(op == ILOpcode.beq || op == ILOpcode.beq_s || op == ILOpcode.bne_un || op == ILOpcode.bne_un_s || op == ILOpcode.ceq); default: return(false); } case StackValueKind.Float: return(dst.Kind == StackValueKind.Float); default: throw new NotImplementedException(); } }
private void ImportUnaryOperation(ILOpcode opCode) { var argument = Pop(); PushTemp(argument.Kind, argument.Type); Append((opCode == ILOpcode.neg) ? "~" : "!"); Append(argument.Value.Name); Finish(); }