Beispiel #1
0
        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);
        }
Beispiel #2
0
        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);
        }
Beispiel #3
0
        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);
        }
Beispiel #4
0
 private void ReplaceInstructionForAllBreakpointsInModule(VMModule module)
 {
     foreach (Breakpoint breakpoint in _breakpoints)
     {
         ReplaceInstructionForBreakpointInModule(breakpoint, module);
     }
 }
Beispiel #5
0
        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);
        }
Beispiel #6
0
        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);
        }
Beispiel #7
0
        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);
        }
Beispiel #8
0
        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);
        }
Beispiel #9
0
        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);
        }
Beispiel #10
0
        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);
        }
Beispiel #11
0
        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);
            }
        }
Beispiel #12
0
 void IVMDebugger.HandleModuleAdded(VMModule module)
 {
     _debugger.AddModule(module);
 }
Beispiel #13
0
        /// <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);
        }
Beispiel #14
0
        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;
                    }
                }
            }
        }