private static void EmitTest(Instruction instruction, string assembler) { var actual = new List <byte>(); Assert.Null(InstructionEmitter.Emit(instruction, actual)); var expected = TestHelpers.NasmBuildBinFromString($"bits 64\r\n{assembler}"); TestHelpers.AssertByteArrays(expected, actual, $"Assembling `{assembler}`:\r\n"); }
/// <summary> /// Compiles a method. /// </summary> /// <param name="methodDef">The method definition.</param> public void Compile(MethodDefinition methodDef) { string methodName = NameHelper.CreateMethodName(methodDef); ValueRef?function = mCompiler.Lookup.GetFunction(methodName); // It is possible we didn't create a declaration because we don't want to generate this method. // In that case, don't continue. if (!function.HasValue) { return; } // A method has internal linkage if one (or both) of the following is true: // 1) The method is a private method. // 2) The compiler got an option to set the linkage of instance methods to internal. if (!methodDef.IsStatic && (methodDef.IsPrivate || mCompiler.Options.InstanceMethodInternalLinkage)) { LLVM.SetLinkage(function.Value, Linkage.InternalLinkage); if (mCompiler.Options.InternalMethodsFastCC) { LLVM.SetFunctionCallConv(function.Value, 8); } } // Only generate if it has a body. if (!methodDef.HasBody || methodDef.Body.CodeSize == 0) { LLVM.SetLinkage(function.Value, Linkage.ExternalLinkage); return; } // Compile instructions. MethodContext ctx = new MethodContext(mCompiler, methodDef, function.Value); InstructionEmitter emitter = new InstructionEmitter(ctx); try { emitter.EmitInstructions(mCompiler.CodeGen); mCompiler.VerifyAndOptimizeFunction(function.Value); } catch (Exception e) { Logger.LogError("Exception inside method {0}: {1}", methodDef, e.Message); Logger.LogDetail("----------"); Logger.LogInfo(e.StackTrace); } }
public string Assemble(AstNode node) { switch (node) { case AssemblyListing listing: foreach (var directive in listing.Directives) { var err = Assemble(directive); if (err != null) { return(err); } } return(null); case ExternDeclaration externDeclaration: _symbolTable.Import(externDeclaration.Name); return(null); case GlobalDeclaration globalDeclaration: _symbolTable.Export(globalDeclaration.Name); return(null); case SectionDeclaration sectionDeclaration: foreach (var entry in sectionDeclaration.SectionEntries) { var error = Assemble(entry); if (error != null) { return(error); } } return(null); case Instruction instruction: return(InstructionEmitter.Emit(instruction, _data)); case Data data: case SectionLabel label: return(null); default: return($"unsupported AstNode: {node.GetType()}"); } }
/// <summary> /// Emits the MSIL that calls the logging method with the specified message and exception. /// </summary> /// <param name="emitter">IL emitter.</param> /// <param name="log">Field that stores reference to the logger.</param> /// <param name="method">Logging method to use. The method must return no value and must take 2 parameters of types <see cref="string"/> and <see cref="Exception"/>.</param> /// <param name="message">Message to log.</param> /// <param name="exception">Local variable where reference to the exception is stored.</param> /// <exception cref="ArgumentNullException"><paramref name="emitter"/>, <paramref name="log"/>, <paramref name="method"/>, <paramref name="message"/> or <paramref name="exception"/> is <see langword="null"/>.</exception> /// <remarks> /// <para>Code emitted by this method makes no assumptions on the state of the evaluation stack /// and it leaves the stack unmodified.</para> /// </remarks> private static void EmitLogStringException(InstructionEmitter emitter, FieldDefDeclaration log, IMethod method, string message, LocalVariableSymbol exception) { if (emitter == null) { throw new ArgumentNullException("emitter"); } if (log == null) { throw new ArgumentNullException("log"); } if (method == null) { throw new ArgumentNullException("method"); } if (message == null) { throw new ArgumentNullException("message"); } if (exception == null) { throw new ArgumentNullException("exception"); } emitter.EmitInstructionField(OpCodeNumber.Ldsfld, GenericHelper.GetFieldCanonicalGenericInstance(log)); emitter.EmitInstructionString(OpCodeNumber.Ldstr, message); emitter.EmitInstructionLocalVariable(OpCodeNumber.Ldloc_S, exception); emitter.EmitInstructionMethod(OpCodeNumber.Callvirt, method); }
/// <summary> /// Emits the MSIL that calls the logging method with the specified format provider, message and arguments. /// </summary> /// <param name="emitter">IL emitter.</param> /// <param name="log">Field that stores reference to the logger.</param> /// <param name="method">Logging method to use. The method must return no value and must take 3 arguments of types <see cref="IFormatProvider"/>, <see cref="string"/> and <see cref="Array"/> of <see cref="object"/>s.</param> /// <param name="formatProviderGetter">Getter of the property that returns the <see cref="IFormatProvider"/> instance.</param> /// <param name="formatString">Format string for the log.</param> /// <param name="args">Variable storing reference to array of arguments for placeholders used in the format string.</param> /// <exception cref="ArgumentNullException"><paramref name="emitter"/>, <paramref name="log"/>, <paramref name="formatProviderGetter"/>, <paramref name="formatString"/> or <paramref name="args"/> is <see langword="null"/>.</exception> /// <remarks> /// <para>Code emitted by this method makes no assumptions on the state of the evaluation stack /// and it leaves the stack unmodified.</para> /// </remarks> private static void EmitLogProviderStringArgs(InstructionEmitter emitter, FieldDefDeclaration log, IMethod method, IMethod formatProviderGetter, string formatString, LocalVariableSymbol args) { if (emitter == null) { throw new ArgumentNullException("emitter"); } if (log == null) { throw new ArgumentNullException("log"); } if (method == null) { throw new ArgumentNullException("method"); } if (formatProviderGetter == null) { throw new ArgumentNullException("formatProviderGetter"); } if (args == null) { throw new ArgumentNullException("args"); } emitter.EmitInstructionField(OpCodeNumber.Ldsfld, GenericHelper.GetFieldCanonicalGenericInstance(log)); emitter.EmitInstructionMethod(OpCodeNumber.Call, formatProviderGetter); emitter.EmitInstructionString(OpCodeNumber.Ldstr, formatString); emitter.EmitInstructionLocalVariable(OpCodeNumber.Ldloc, args); emitter.EmitInstructionMethod(OpCodeNumber.Callvirt, method); }
/// <summary> /// Emits the MSIL code that jumps to the specified label if logging is disabled. /// </summary> /// <param name="emitter">IL emitter.</param> /// <param name="logLevelSupportItem">Item for the logging level.</param> /// <param name="perTypeLoggingData">Data for the type being woven.</param> /// <param name="afterLoggingSequence">Sequence to jump to if logging is disabled.</param> /// <exception cref="ArgumentNullException"><paramref name="emitter"/>, <paramref name="logLevelSupportItem"/>, <paramref name="perTypeLoggingData"/> or <paramref name="afterLoggingSequence"/> is <see langword="null"/>.</exception> /// <remarks> /// <para>Code emitted by this method makes no assumptions on the state of the evaluation stack /// and it leaves the stack unmodified.</para> /// </remarks> private static void EmitLoggingEnabledCheck(InstructionEmitter emitter, LogLevelSupportItem logLevelSupportItem, PerTypeLoggingData perTypeLoggingData, InstructionSequence afterLoggingSequence) { if (emitter == null) { throw new ArgumentNullException("emitter"); } if (logLevelSupportItem == null) { throw new ArgumentNullException("logLevelSupportItem"); } if (perTypeLoggingData == null) { throw new ArgumentNullException("perTypeLoggingData"); } if (afterLoggingSequence == null) { throw new ArgumentNullException("afterLoggingSequence"); } emitter.EmitInstructionField(OpCodeNumber.Ldsfld, GenericHelper.GetFieldCanonicalGenericInstance(perTypeLoggingData.Log)); emitter.EmitInstructionMethod(OpCodeNumber.Callvirt, logLevelSupportItem.IsLoggingEnabledGetter); emitter.EmitInstruction(OpCodeNumber.Ldc_I4_0); emitter.EmitInstruction(OpCodeNumber.Ceq); emitter.EmitBranchingInstruction(OpCodeNumber.Brtrue_S, afterLoggingSequence); }