public bool RestoreInstruction(VMModule module, int functionIndex, int address) { ModuleDebugData debugData; if (!_debugDataByModule.TryGetValue(module, out debugData)) { return(false); } Dictionary <int, Instruction> replacedInstructions; if (!debugData.ReplacedInstructionsByFunction.TryGetValue(functionIndex, out replacedInstructions)) { return(false); } Instruction originalInstruction; if (!replacedInstructions.TryGetValue(address, out originalInstruction)) { return(false); } replacedInstructions.Remove(address); module.ILModule.DefinedFunctions[functionIndex].Code[address] = originalInstruction; return(true); }
public VMModule?CompileAndLink( string source, string filename, InteropResolver resolver, List <ParseError> parseErrors, List <LinkError> linkErrors ) { Linker linker = new Linker(linkErrors); ParseModule parsedModule = CreateInputParseModuleFromInteropResolver(resolver); SetupLinkerWithInteropResolver(linker, resolver); ILModule?compiledModule = Compile(source, filename, parseErrors, parsedModule); if (compiledModule == null) { return(null); } linker.AddModule(compiledModule, export: true); VMModule linkedModule = linker.Link(); if (linkErrors.Count > 0) { return(null); } return(linkedModule); }
public void ReplaceInstruction(VMModule module, int functionIndex, int address) { ModuleDebugData debugData; if (!_debugDataByModule.TryGetValue(module, out debugData)) { return; } Dictionary <int, Instruction> replacedInstructions; if (!debugData.ReplacedInstructionsByFunction.TryGetValue(functionIndex, out replacedInstructions)) { replacedInstructions = new Dictionary <int, Instruction>(); debugData.ReplacedInstructionsByFunction[functionIndex] = replacedInstructions; } if (replacedInstructions.ContainsKey(address)) { // Instruction already replaced return; } ILFunction function = module.ILModule.DefinedFunctions[functionIndex]; Instruction ins = function.Code[address]; replacedInstructions.Add(address, ins); function.Code[address] = new Instruction(OpCode.BREAK); }
private void ReplaceInstructionForAllBreakpointsInModule(VMModule module) { foreach (Breakpoint breakpoint in _breakpoints) { ReplaceInstructionForBreakpointInModule(breakpoint, module); } }
public bool PrepareForExecution(VMModule module, IList <string> errors) { Dictionary <string, int> exporetedFunctions = module.ILModule.ExportedFunctions.ToDictionary(p => p.Key, p => p.Value); bool success = true; foreach (Type type in _linkableModules) { FieldInfo[] fields = type.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly); foreach (FieldInfo field in fields) { object[] attribs = field.GetCustomAttributes(typeof(ExternalFunctionAttribute), inherit: false); foreach (ExternalFunctionAttribute attrib in attribs) { int index; if (!exporetedFunctions.TryGetValue(attrib.Name, out index)) { errors.Add($"Cannot find exported method {attrib.Name}"); success = false; } field.SetValue(null, index); } } } return(success); }
private void ReplaceInstructionForBreakpointInModule(Breakpoint breakpoint, VMModule module) { int functionIndex, address; if (!LookupSymbol(module, breakpoint.SourcePath, breakpoint.LineNumber, out functionIndex, out address)) { return; } ReplaceInstruction(module, functionIndex, address); }
public void AddModule(VMModule module) { if (_debugDataByModule.ContainsKey(module)) { return; } ModuleDebugData data = new ModuleDebugData { ReplacedInstructionsByFunction = new Dictionary <int, Dictionary <int, Instruction> >() }; _debugDataByModule.Add(module, data); ReplaceInstructionForAllBreakpointsInModule(module); }
public IVMModuleArtifact GetVMModuleArtifact() { List <ILModule> modules = _input.GetModuleArtifacts().ConvertAll(m => (ILModule)m); List <LinkError> linkErrors = new List <LinkError>(); Linker linker = new Linker(linkErrors); foreach (ILModule module in modules) { linker.AddModule(module, export: true); } foreach (Binding binding in _job.InteropResolver.Bindings) { linker.AddFunctionBinding(binding.Prototype.Name, binding.Implementation, export: false); } VMModule vmModule = linker.Link(); foreach (LinkError error in linkErrors) { Diagnostics.Report(Diagnostics.Severity.Error, $"Link error: {error.Message}"); } Diagnostics.ThrowIfErrors(); List <string> loadErrors = new List <string>(); if (!_job.InteropResolver.PrepareForExecution(vmModule, loadErrors)) { foreach (string error in loadErrors) { Diagnostics.Report(Diagnostics.Severity.Error, $"Load error: {error}"); } Diagnostics.ThrowIfErrors(); } return(vmModule); }
public bool LookupSymbol(VMModule module, string sourcePath, int lineNumber, out int functionIndexResult, out int addressResult) { for (int functionIndex = 0, funcLen = module.ILModule.DefinedFunctions.Length; functionIndex < funcLen; ++functionIndex) { ILFunction function = module.ILModule.DefinedFunctions[functionIndex]; for (int i = 0, ilen = function.Code.Length; i < ilen; ++i) { Symbol symbol; if (!function.Symbols.TryGetValue(i, out symbol)) { continue; } if (symbol.SourceFile == null) { continue; } // TODO: More permissive path matching if (symbol.SourceFile != sourcePath) { // Assume that if the first symbol doesn't match the source path, none of them do. break; } if (lineNumber >= symbol.Start.Line && lineNumber <= symbol.End.Line) { functionIndexResult = functionIndex; addressResult = i; return(true); } } } functionIndexResult = 0; addressResult = 0; return(false); }
public VMModule?CompileAndLink( ParseModule parsedModule, InteropResolver resolver, List <LinkError> linkErrors ) { Linker linker = new Linker(linkErrors); SetupLinkerWithInteropResolver(linker, resolver); ILModule compiledModule = Compile(parsedModule); linker.AddModule(compiledModule, export: true); VMModule linkedModule = linker.Link(); if (linkErrors.Count > 0) { return(null); } return(linkedModule); }
public static void Main(string[] args) { bool isInteractive = false; bool showLex = false; bool showAst = false; bool showIl = false; bool withDebugger = false; bool forceCodegen = false; bool run = true; List <string> positionals = new List <string>(); List <int> argsToPass = new List <int>(); List <string> libraryNames = new List <string>(); List <string> librarySearchPaths = new List <string>(); for (int i = 0, ilen = args.Length; i < ilen; ++i) { string arg = args[i].Trim(); bool argFound = true; switch (arg) { case "-i": isInteractive = true; break; case "--showlex": showLex = true; break; case "--showast": showAst = true; break; case "--showil": showIl = true; break; case "-a": int argToPass; Int32.TryParse(args[++i], out argToPass); argsToPass.Add(argToPass); break; case "-l": libraryNames.Add(args[++i]); break; case "-L": librarySearchPaths.Add(args[++i]); break; case "--debugger": withDebugger = true; break; case "--force-codegen": // Indicate that the compiler should attempt to code gen IL, even if the parse stage failed. // This can be helpful to diagnose generated IL for code that doesn't compile outside of a // specific project due to undefined references. The parser tries its hardest to produce a // usable AST, even if there are semantic errors. Syntax errors? Not so much. forceCodegen = true; break; case "--skip-run": run = false; break; default: argFound = false; break; } if (!argFound) { if (!arg.Contains("-")) { positionals.Add(arg); } } } InteropResolver interopResolver = new InteropResolver(); const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static; foreach (string libraryName in libraryNames) { Assembly lib = LoadAssembly(libraryName, librarySearchPaths); interopResolver.ImportAssembly(lib, bindingFlags); } List <ParseModule> parseModules = new List <ParseModule>(positionals.Count); List <ParseError> errors = new List <ParseError>(); void ParseTokens(string?filename, List <Token> tokens) { Parser parser = new Parser(); ParseModule module = parser.Parse(filename, tokens, errors); parseModules.Add(module); } if (positionals.Count > 0) { // File mode - parse one or more files into ParseModules for (int i = 0, ilen = positionals.Count; i < ilen; ++i) { string filename = positionals[i]; Lexer lexer = new Lexer(); List <Token> tokens = new List <Token>(); string?input; filename = Path.GetFullPath(filename); using StreamReader reader = new StreamReader(filename); while ((input = reader.ReadLine()) != null) { LexLine(input, lexer, tokens, verbose: showLex); } lexer.FinishLex(tokens); ParseTokens(filename, tokens); } } else { // Interactive or StdIn mode - parse exactly one ParseModule Lexer lexer = new Lexer(); List <Token> tokens = new List <Token>(); string?input; if (isInteractive) { WritePrompt(); while ((input = Console.ReadLine()) != null) { LexLine(input, lexer, tokens, verbose: showLex); WritePrompt(); } } else { while ((input = Console.In.ReadLine()) != null) { LexLine(input, lexer, tokens, verbose: showLex); } } lexer.FinishLex(tokens); ParseTokens(null, tokens); } List <LinkError> linkErrors = new List <LinkError>(); Linker linker = new Linker(linkErrors); SemanticAnalyzer analyzer = new SemanticAnalyzer(errors); List <SemanticModule> semanticModules = new List <SemanticModule>(parseModules.Count); analyzer.Register(interopResolver.CreateHeaderModule()); foreach (ParseModule module in parseModules) { analyzer.Register(module); } foreach (ParseModule module in parseModules) { semanticModules.Add(analyzer.Process(module)); if (showAst) { PrintTreeVisitor treeVisitor = new PrintTreeVisitor(Console.Out); foreach (StructNode structNode in module.Structs) { structNode.AcceptTopLevelVisitor(treeVisitor); } foreach (FunctionDefinitionNode function in module.Functions) { function.AcceptTopLevelVisitor(treeVisitor); } } } for (int i = 0, ilen = errors.Count; i < ilen; ++i) { ParseError error = errors[i]; Console.Error.WriteLine($"{error.Start.Line + 1},{error.Start.Column + 1}: {error.Message}"); } if (errors.Count > 0 && !forceCodegen) { Environment.Exit(1); } foreach (SemanticModule module in semanticModules) { CodeGenerator generator = new CodeGenerator(module, analyzer.Context); ILModule ilmodule = generator.Generate(); if (showIl) { ilmodule.WriteListing(Console.Out); } linker.AddModule(ilmodule, export: true); } foreach (Binding binding in interopResolver.Bindings) { linker.AddFunctionBinding(binding.Prototype.Name, binding.Implementation, export: false); } VMModule vmModule = linker.Link(); if (linkErrors.Count > 0) { foreach (LinkError error in linkErrors) { Console.Error.WriteLine($"Link error: {error.Message}"); } Environment.Exit(1); } List <string> loadErrors = new List <string>(); if (!interopResolver.PrepareForExecution(vmModule, loadErrors)) { foreach (string error in loadErrors) { Console.Error.WriteLine($"Load error: {error}"); } Environment.Exit(1); } if (!run) { Environment.Exit(0); return; } using VirtualMachine vm = new VirtualMachine(); if (withDebugger) { Debugger debugger = new Debugger(); VMDebugger vmDebugger = new VMDebugger(debugger, vm); vmDebugger.Break += () => HandleBreak(vm, debugger, vmDebugger); vmDebugger.Pause(); } // TODO: Args to pass is broken if (!vm.Call(vmModule, "main", new byte[0], success => HandleExecutionFinished(vm, success))) { Console.Error.WriteLine("Failed to call main function."); Environment.Exit(-1); } }
void IVMDebugger.HandleModuleAdded(VMModule module) { _debugger.AddModule(module); }
/// <summary> /// 加载模块 /// </summary> /// <param name="binaryModule"></param> /// <param name="isDependency">是执行模块还是依赖模块</param> /// <returns></returns> public static VMModule AddModule(BinaryModule binaryModule, bool isDependency) { if (!isDependency) { LoadWatch.Start(); } VMModule module = new VMModule() { StringPoolLink = new List <uint>(), Classes = new Dictionary <uint, VMClass>(), ClassPool = binaryModule.ClassPool, ClassPoolLink = new List <VMClass>(), FieldPool = binaryModule.FieldPool, FieldPoolLink = new List <VMField>(), MethodPool = binaryModule.MethodPool, MethodPoolLink = new List <VMMethod>() }; HashSet <int> externalModuleNameIndexes = new HashSet <int>(); // 字符串常量 foreach (string stringConstant in binaryModule.StringPool) { // 建立映射 module.StringPoolLink.Add(MethodArea.Singleton.AddConstantString(stringConstant)); } Modules.Add(module.StringPoolLink[binaryModule.ModuleNameIndex - 1], module); // 类 foreach (ClassConstantInfo classInfo in module.ClassPool) { int moduleNameIndex = classInfo.Module; if (moduleNameIndex != binaryModule.ModuleNameIndex) { // 外部域 externalModuleNameIndexes.Add(moduleNameIndex); // 占位 module.ClassPoolLink.Add(null); } else { VMClass vmClass = new VMClass() { Parent = module, Methods = new Dictionary <uint, List <VMMethod> >(), StaticFields = new List <VMField>(), StaticFieldSize = HeapData.MiscDataSize, // 头部信息 Fields = new List <VMField>(), FieldSize = HeapData.MiscDataSize // 头部信息 }; module.Classes.Add(module.StringPoolLink[classInfo.Name - 1], vmClass); module.ClassPoolLink.Add(vmClass); } } // Field AccessFlag accessFlag = new AccessFlag(); foreach (FieldConstantInfo fieldInfo in module.FieldPool) { int moduleNameIndex = module.ClassPool[fieldInfo.Class - 1].Module; if (moduleNameIndex != binaryModule.ModuleNameIndex) { // 外部域 externalModuleNameIndexes.Add(moduleNameIndex); // 占位 module.FieldPoolLink.Add(null); } else { module.Classes.TryGetValue(module.StringPoolLink[module.ClassPool[fieldInfo.Class - 1].Name - 1], out VMClass vmClass); // 分配方法区空间并且链接地址 accessFlag.Flag = fieldInfo.Flag; VariableType fieldType = VariableType.GetType(binaryModule.StringPool[fieldInfo.Descriptor - 1]); VMField vmField; if (accessFlag.IsStatic) { vmField = new VMField(fieldInfo.Flag, fieldType, fieldInfo.Class, vmClass.StaticFieldSize); module.FieldPoolLink.Add(vmField); vmClass.StaticFields.Add(vmField); vmClass.StaticFieldSize += fieldType.Size; } else { vmField = new VMField(fieldInfo.Flag, fieldType, fieldInfo.Class, vmClass.FieldSize); module.FieldPoolLink.Add(vmField); vmClass.Fields.Add(vmField); vmClass.FieldSize += fieldType.Size; } } } // 完成静态空间分配 foreach (var vmClass in module.ClassPoolLink) { if (vmClass != null) { vmClass.StaticFieldAddress = StaticArea.Singleton.MallocClassStaticArea(vmClass); Classes.Add(vmClass.StaticFieldAddress, vmClass); } } // Method foreach ((MethodConstantInfo methodInfo, BinaryMethod binaryMethod) in module.MethodPool.Zip(binaryModule.Methods)) { int moduleNameIndex = module.ClassPool[methodInfo.Class - 1].Module; if (moduleNameIndex != binaryModule.ModuleNameIndex) { // 外部方法 externalModuleNameIndexes.Add(moduleNameIndex); // 占位 module.MethodPoolLink.Add(null); } else { module.Classes.TryGetValue(module.StringPoolLink[module.ClassPool[methodInfo.Class - 1].Name - 1], out VMClass vmClass); // 构造VMMethod VMMethod vmMethod = new VMMethod() { Parent = vmClass, Flag = new AccessFlag() { Flag = methodInfo.Flag }, DescriptorAddress = module.StringPoolLink[methodInfo.Descriptor - 1], LocalDescriptorAddress = binaryMethod.LocalDescriptorIndex.Select(i => module.StringPoolLink[i - 1]).ToList(), CodeBlock = MethodArea.Singleton.Malloc(binaryMethod.Instructions) }; Methods.Add(vmMethod.CodeAddress, vmMethod); // 将VMMethod添加到Class中 uint methodNameAddr = module.StringPoolLink[methodInfo.Name - 1]; if (vmClass.Methods.TryGetValue(methodNameAddr, out List <VMMethod> methodGroup)) { methodGroup.Add(vmMethod); } else { vmClass.Methods.Add(methodNameAddr, new List <VMMethod>() { vmMethod }); } // 建立Link module.MethodPoolLink.Add(vmMethod); } } if (!isDependency) { DependencyLoadWatch.Start(); } // 导入外部模块 foreach (int externalModuleNameIndex in externalModuleNameIndexes) { if (!Modules.ContainsKey(module.StringPoolLink[externalModuleNameIndex - 1])) { // 导入未导入的模块,图的广度优先遍历 AddModule(Program.LoadModule(binaryModule.StringPool[externalModuleNameIndex - 1]), true); } } if (!isDependency) { DependencyLoadWatch.Stop(); } // 链接外部符号 ExternalSymbolResolution(module); if (!isDependency) { LoadWatch.Stop(); } return(module); }
private static void ExternalSymbolResolution(VMModule module) { uint moduleNameAddress, nameAddress, classNameAddress; VMModule importedModule; VMClass outerClass; // 外部类 for (int i = 0; i < module.ClassPool.Length; ++i) { if (module.ClassPoolLink[i] != null) { continue; } ClassConstantInfo classInfo = module.ClassPool[i]; moduleNameAddress = module.StringPoolLink[classInfo.Module - 1]; Modules.TryGetValue(moduleNameAddress, out importedModule); nameAddress = module.StringPoolLink[classInfo.Name - 1]; if (!importedModule.Classes.TryGetValue(nameAddress, out outerClass)) { throw new XiVMError($"Outer class not found"); } module.ClassPoolLink[i] = outerClass; } // 外部域 for (int i = 0; i < module.FieldPool.Length; ++i) { if (module.FieldPoolLink[i] != null) { continue; } FieldConstantInfo fieldInfo = module.FieldPool[i]; moduleNameAddress = module.StringPoolLink[module.ClassPool[fieldInfo.Class - 1].Module - 1]; Modules.TryGetValue(moduleNameAddress, out importedModule); // TODO 可以将VMModule.Classes的结构化信息补全,这样直接在结构化信息中查找效率更高一些 // 外部函数符号也可以这样优化 classNameAddress = module.StringPoolLink[module.ClassPool[fieldInfo.Class - 1].Name - 1]; nameAddress = module.StringPoolLink[fieldInfo.Name - 1]; uint descriptorAddress = module.StringPoolLink[fieldInfo.Descriptor - 1]; foreach ((FieldConstantInfo candidateFieldInfo, VMField vmField) in importedModule.FieldPool.Zip(importedModule.FieldPoolLink)) { // 模块名类名函数名描述符匹配,未比较flag if (moduleNameAddress == importedModule.StringPoolLink[importedModule.ClassPool[candidateFieldInfo.Class - 1].Module - 1] && classNameAddress == importedModule.StringPoolLink[importedModule.ClassPool[candidateFieldInfo.Class - 1].Name - 1] && nameAddress == importedModule.StringPoolLink[candidateFieldInfo.Name - 1] && descriptorAddress == importedModule.StringPoolLink[candidateFieldInfo.Descriptor - 1]) { // 建立Link module.FieldPoolLink[i] = vmField; break; } } } // 外部函数符号 for (int i = 0; i < module.MethodPool.Length; ++i) { if (module.MethodPoolLink[i] != null) { // 已经填上了 continue; } MethodConstantInfo methodInfo = module.MethodPool[i]; moduleNameAddress = module.StringPoolLink[module.ClassPool[methodInfo.Class - 1].Module - 1]; Modules.TryGetValue(moduleNameAddress, out importedModule); classNameAddress = module.StringPoolLink[module.ClassPool[methodInfo.Class - 1].Name - 1]; nameAddress = module.StringPoolLink[methodInfo.Name - 1]; uint descriptorAddress = module.StringPoolLink[methodInfo.Descriptor - 1]; foreach ((MethodConstantInfo candidateMethodInfo, VMMethod vmMethod) in importedModule.MethodPool.Zip(importedModule.MethodPoolLink)) { // 模块名类名函数名描述符匹配,未比较flag if (moduleNameAddress == importedModule.StringPoolLink[importedModule.ClassPool[candidateMethodInfo.Class - 1].Module - 1] && classNameAddress == importedModule.StringPoolLink[importedModule.ClassPool[candidateMethodInfo.Class - 1].Name - 1] && nameAddress == importedModule.StringPoolLink[candidateMethodInfo.Name - 1] && descriptorAddress == importedModule.StringPoolLink[candidateMethodInfo.Descriptor - 1]) { // 建立Link module.MethodPoolLink[i] = vmMethod; break; } } } }