private void CompileSingleMethod(CorInfoImpl corInfo, MethodCodeNode methodCodeNodeNeedingCode) { MethodDesc method = methodCodeNodeNeedingCode.Method; try { corInfo.CompileMethod(methodCodeNodeNeedingCode); } catch (TypeSystemException ex) { // TODO: fail compilation if a switch was passed // Try to compile the method again, but with a throwing method body this time. MethodIL throwingIL = TypeSystemThrowingILEmitter.EmitIL(method, ex); corInfo.CompileMethod(methodCodeNodeNeedingCode, throwingIL); // TODO: Log as a warning. For now, just log to the logger; but this needs to // have an error code, be supressible, the method name/sig needs to be properly formatted, etc. // https://github.com/dotnet/corert/issues/72 Logger.Writer.WriteLine($"Warning: Method `{method}` will always throw because: {ex.Message}"); } finally { if (_compilationCountdown != null) { _compilationCountdown.Signal(); } } }
/// <summary> /// Compiles the provided method code node while swapping it's body with a throwing stub. /// </summary> private bool TryCompileWithThrowingBody(MethodCodeNode methodNode, TypeSystemException exception) { MethodDesc helper; Type exceptionType = exception.GetType(); if (exceptionType == typeof(TypeSystemException.TypeLoadException)) { helper = _typeSystemContext.GetHelperEntryPoint("ThrowHelpers", "ThrowTypeLoadException"); } else if (exceptionType == typeof(TypeSystemException.MissingFieldException)) { helper = _typeSystemContext.GetHelperEntryPoint("ThrowHelpers", "ThrowMissingFieldException"); } else if (exceptionType == typeof(TypeSystemException.MissingMethodException)) { helper = _typeSystemContext.GetHelperEntryPoint("ThrowHelpers", "ThrowMissingMethodException"); } else if (exceptionType == typeof(TypeSystemException.FileNotFoundException)) { helper = _typeSystemContext.GetHelperEntryPoint("ThrowHelpers", "ThrowFileNotFoundException"); } else if (exceptionType == typeof(TypeSystemException.InvalidProgramException)) { helper = _typeSystemContext.GetHelperEntryPoint("ThrowHelpers", "ThrowInvalidProgramException"); } else { return(false); } Debug.Assert(helper.Signature.Length == exception.Arguments.Count + 1); var emitter = new Internal.IL.Stubs.ILEmitter(); var codeStream = emitter.NewCodeStream(); var infinityLabel = emitter.NewCodeLabel(); codeStream.EmitLabel(infinityLabel); codeStream.EmitLdc((int)exception.StringID); foreach (var arg in exception.Arguments) { codeStream.Emit(ILOpcode.ldstr, emitter.NewToken(arg)); } codeStream.Emit(ILOpcode.call, emitter.NewToken(helper)); // The call will never return, but we still need to emit something. Emit a jump so that // we don't have to bother balancing the stack if the method returns something. codeStream.Emit(ILOpcode.br, infinityLabel); _corInfo.CompileMethod(methodNode, emitter.Link(methodNode.Method)); return(true); }
private void CompileSingleMethod(CorInfoImpl corInfo, MethodCodeNode methodCodeNodeNeedingCode) { MethodDesc method = methodCodeNodeNeedingCode.Method; TypeSystemException exception = _methodImportationErrorProvider.GetCompilationError(method); // If we previously failed to import the method, do not try to import it again and go // directly to the error path. if (exception == null) { try { corInfo.CompileMethod(methodCodeNodeNeedingCode); } catch (TypeSystemException ex) { exception = ex; } } if (exception != null) { // Try to compile the method again, but with a throwing method body this time. MethodIL throwingIL = TypeSystemThrowingILEmitter.EmitIL(method, exception); corInfo.CompileMethod(methodCodeNodeNeedingCode, throwingIL); if (exception is TypeSystemException.InvalidProgramException && method.OwningType is MetadataType mdOwningType && mdOwningType.HasCustomAttribute("System.Runtime.InteropServices", "ClassInterfaceAttribute")) { Logger.LogWarning(method, DiagnosticId.COMInteropNotSupportedInFullAOT); } if ((_compilationOptions & RyuJitCompilationOptions.UseResilience) != 0) { Logger.LogMessage($"Method '{method}' will always throw because: {exception.Message}"); } else { Logger.LogError($"Method will always throw because: {exception.Message}", 1005, method, MessageSubCategory.AotAnalysis); } } }
private void CompileSingleMethod(CorInfoImpl corInfo, MethodCodeNode methodCodeNodeNeedingCode) { try { MethodDesc method = methodCodeNodeNeedingCode.Method; TypeSystemException exception = _methodImportationErrorProvider.GetCompilationError(method); // If we previously failed to import the method, do not try to import it again and go // directly to the error path. if (exception == null) { try { corInfo.CompileMethod(methodCodeNodeNeedingCode); } catch (TypeSystemException ex) { exception = ex; } } if (exception != null) { // TODO: fail compilation if a switch was passed // Try to compile the method again, but with a throwing method body this time. MethodIL throwingIL = TypeSystemThrowingILEmitter.EmitIL(method, exception); corInfo.CompileMethod(methodCodeNodeNeedingCode, throwingIL); if (exception is TypeSystemException.InvalidProgramException && method.OwningType is MetadataType mdOwningType && mdOwningType.HasCustomAttribute("System.Runtime.InteropServices", "ClassInterfaceAttribute")) { Logger.LogWarning("COM interop is not supported with full ahead of time compilation", 3052, method, MessageSubCategory.AotAnalysis); } else { Logger.LogWarning($"Method will always throw because: {exception.Message}", 1005, method, MessageSubCategory.AotAnalysis); } } }
private void CompileSingleMethod(MethodCodeNode methodCodeNodeNeedingCode) { CorInfoImpl corInfo = _corinfos.GetValue(Thread.CurrentThread, thread => new CorInfoImpl(this)); CompileSingleMethod(corInfo, methodCodeNodeNeedingCode); }