diff options
-rw-r--r-- | lib/compilers/dotnet.ts | 158 | ||||
-rw-r--r-- | lib/parsers/asm-parser-dotnet.ts | 1 |
2 files changed, 88 insertions, 71 deletions
diff --git a/lib/compilers/dotnet.ts b/lib/compilers/dotnet.ts index 5b767ceda..e21899a0b 100644 --- a/lib/compilers/dotnet.ts +++ b/lib/compilers/dotnet.ts @@ -49,10 +49,10 @@ class DotNetCompiler extends BaseCompiler { private readonly buildConfig: string; private readonly clrBuildDir: string; private readonly langVersion: string; - private readonly crossgen2Path: string; - private readonly sdkMajorVersion: number; + private readonly corerunPath: string; + private readonly disassemblyLoaderPath: string; - private crossgen2VersionString: string; + private versionString: string; constructor(compilerInfo: PreliminaryCompilerInfo, env) { super(compilerInfo, env); @@ -62,15 +62,15 @@ class DotNetCompiler extends BaseCompiler { const parts = this.sdkVersion.split('.'); this.targetFramework = `net${parts[0]}.${parts[1]}`; - this.sdkMajorVersion = Number(parts[0]); this.buildConfig = this.compilerProps<string>(`compiler.${this.compiler.id}.buildConfig`); this.clrBuildDir = this.compilerProps<string>(`compiler.${this.compiler.id}.clrDir`); this.langVersion = this.compilerProps<string>(`compiler.${this.compiler.id}.langVersion`); - this.crossgen2Path = path.join(this.clrBuildDir, 'crossgen2', 'crossgen2'); + this.corerunPath = path.join(this.clrBuildDir, 'corerun'); this.asm = new DotNetAsmParser(); - this.crossgen2VersionString = ''; + this.versionString = ''; + this.disassemblyLoaderPath = path.join(this.clrBuildDir, 'DisassemblyLoader', 'DisassemblyLoader.dll'); } get compilerOptions() { @@ -118,6 +118,7 @@ class DotNetCompiler extends BaseCompiler { </PropertyGroup> <ItemGroup> <Compile Include="${sourceFile}" /> + <Reference Include="DisassemblyLoader" HintPath="${this.disassemblyLoaderPath}" /> </ItemGroup> </Project> `; @@ -162,7 +163,7 @@ class DotNetCompiler extends BaseCompiler { const inputFilenameSafe = this.filename(inputFilename); const sourceFile = path.basename(inputFilenameSafe); await this.writeProjectfile(dirPath, true, sourceFile); - return await this.buildToDll(compiler, options, inputFilename, execOptions); + return await this.buildToDll(compiler, inputFilename, execOptions); } override async doCompilation(inputFilename, dirPath, key, options, filters, backendOptions, libraries, tools) { @@ -174,7 +175,6 @@ class DotNetCompiler extends BaseCompiler { async buildToDll( compiler: string, - options: string[], inputFilename: string, execOptions: ExecutionOptions & {env: Record<string, string>}, ): Promise<CompilationResult> { @@ -285,46 +285,69 @@ class DotNetCompiler extends BaseCompiler { inputFilename: string, execOptions: ExecutionOptions & {env: Record<string, string>}, ): Promise<CompilationResult> { - let toolOptions: string[] = []; - const toolSwitches: string[] = []; - const configurableOptions = this.configurableOptions; + const corerunArgs: string[] = []; + const ilcOptions: string[] = [ + '--codegenopt', + 'JitDisasm=*', + '--codegenopt', + 'JitDisasmDiffable=1', + '--parallelism', + '1', + ]; + const ilcSwitches: string[] = []; const programDir = path.dirname(inputFilename); const programOutputPath = path.join(programDir, 'bin', this.buildConfig, this.targetFramework); - const programDllPath = path.join(programOutputPath, `${AssemblyName}.dll`); - - for (const configurableOption of configurableOptions) { - const optionIndex = options.indexOf(configurableOption); - if (optionIndex === -1 || optionIndex === options.length - 1) { - continue; - } - toolOptions.push(options[optionIndex], options[optionIndex + 1]); - } - + const programDllPath = path.join(programOutputPath, 'CompilerExplorer.dll'); + const envVarFileContents = [ + 'DOTNET_EnableWriteXorExecute=0', + 'DOTNET_JitDisasm=*', + 'DOTNET_JitDisasmAssemblies=CompilerExplorer', + 'DOTNET_TieredCompilation=0', + ]; let isAot = false; - const configurableSwitches = this.configurableSwitches; - for (const configurableSwitch of configurableSwitches) { - const switchIndex = options.indexOf(configurableSwitch); - if (switchIndex === -1) { + + while (options.length > 0) { + const currentOption = options.shift(); + if (!currentOption) { continue; } - if (configurableSwitch === '--aot') { - isAot = true; - } else { - toolSwitches.push(options[switchIndex]); + if (currentOption === '-e' || currentOption === '--env') { + const envVar = options.shift(); + if (envVar) { + const [name] = envVar.split('='); + const normalizedName = name.trim().toUpperCase(); + if ( + normalizedName === 'DOTNET_JITDISASM' || + normalizedName === 'DOTNET_JITDUMP' || + normalizedName === 'DOTNET_JITDISASMASSEMBILES' + ) { + continue; + } + envVarFileContents.push(envVar); + } + } else if (currentOption === '-p' || currentOption === '--property') { + const property = options.shift(); + if (property) { + corerunArgs.push('-p', property); + } + } else if (this.configurableSwitches.indexOf(currentOption)) { + if (currentOption === '--aot') { + isAot = true; + } else { + ilcSwitches.push(currentOption); + } + } else if (this.configurableOptions.indexOf(currentOption)) { + const value = options.shift(); + if (value) { + ilcOptions.push(currentOption, value); + } } } this.setCompilerExecOptions(execOptions, programDir); - - // prettier-ignore - toolOptions = [ - '--codegenopt', this.sdkMajorVersion < 7 ? 'NgenDisasm=*' : 'JitDisasm=*', - '--codegenopt', this.sdkMajorVersion < 8 ? 'JitDiffableDasm=1' : 'JitDisasmDiffable=1', - '--parallelism', '1', - ].concat(toolOptions); - let compilerResult; + if (isAot) { if (!fs.existsSync(`${this.clrBuildDir}/aot`)) { return { @@ -336,24 +359,27 @@ class DotNetCompiler extends BaseCompiler { }; } - compilerResult = await this.publishAot(compiler, toolOptions, toolSwitches, inputFilename, execOptions); + compilerResult = await this.publishAot(compiler, ilcOptions, ilcSwitches, inputFilename, execOptions); } else { - compilerResult = await this.buildToDll(compiler, options, inputFilename, execOptions); + compilerResult = await this.buildToDll(compiler, inputFilename, execOptions); if (compilerResult.code !== 0) { return compilerResult; } - const crossgen2Result = await this.runCrossgen2( + const envVarFilePath = path.join(programDir, '.env'); + await fs.writeFile(envVarFilePath, envVarFileContents.join('\n')); + + const corerunResult = await this.runCorerunForDisasm( execOptions, this.clrBuildDir, + envVarFilePath, programDllPath, - toolOptions, - toolSwitches, + corerunArgs, this.getOutputFilename(programDir, this.outputFilebase), ); - if (crossgen2Result.code !== 0) { - return crossgen2Result; + if (corerunResult.code !== 0) { + return corerunResult; } } @@ -385,9 +411,8 @@ class DotNetCompiler extends BaseCompiler { execOptions.env.CORE_ROOT = this.clrBuildDir; execOptions.input = executeParameters.stdin; const execArgs = ['-p', 'System.Runtime.TieredCompilation=false', programDllPath, ...executeParameters.args]; - const corerun = path.join(this.clrBuildDir, 'corerun'); try { - const execResult: UnprocessedExecResult = await exec.sandbox(corerun, execArgs, execOptions); + const execResult: UnprocessedExecResult = await exec.sandbox(this.corerunPath, execArgs, execOptions); return this.processExecutionResult(execResult); } catch (err: UnprocessedExecResult | any) { if (err.code && err.stderr) { @@ -403,48 +428,41 @@ class DotNetCompiler extends BaseCompiler { } } - async ensureCrossgen2Version(execOptions: ExecutionOptions) { - if (!this.crossgen2VersionString) { - this.crossgen2VersionString = '// crossgen2 '; + async checkRuntimeVersion(execOptions: ExecutionOptions) { + if (!this.versionString) { + this.versionString = '// dotnet runtime '; const versionFilePath = `${this.clrBuildDir}/version.txt`; - const versionResult = await this.exec(this.crossgen2Path, ['--version'], execOptions); - if (versionResult.code === 0) { - this.crossgen2VersionString += versionResult.stdout; - } else if (fs.existsSync(versionFilePath)) { + if (fs.existsSync(versionFilePath)) { const versionString = await fs.readFile(versionFilePath); - this.crossgen2VersionString += versionString; + this.versionString += versionString; } else { - this.crossgen2VersionString += '<unknown version>'; + this.versionString += '<unknown version>'; } } } - async runCrossgen2( + async runCorerunForDisasm( execOptions: ExecutionOptions, - bclPath: string, + coreRoot: string, + envPath: string, dllPath: string, - toolOptions: string[], - toolSwitches: string[], + options: string[], outputPath: string, ) { - await this.ensureCrossgen2Version(execOptions); + await this.checkRuntimeVersion(execOptions); - // prettier-ignore - const crossgen2Options = [ - '-r', path.join(bclPath, '/'), + const corerunOptions = ['--clr-path', coreRoot, '--env', envPath].concat([ + ...options, + this.disassemblyLoaderPath, dllPath, - '-o', `${AssemblyName}.r2r.dll`, - '--inputbubble', - '--compilebubblegenerics', - ].concat(toolOptions).concat(toolSwitches); - - const compilerExecResult = await this.exec(this.crossgen2Path, crossgen2Options, execOptions); + ]); + const compilerExecResult = await this.exec(this.corerunPath, corerunOptions, execOptions); const result = this.transformToCompilationResult(compilerExecResult, dllPath); await fs.writeFile( outputPath, - `${this.crossgen2VersionString}\n\n${result.stdout.map(o => o.text).reduce((a, n) => `${a}\n${n}`, '')}`, + `${this.versionString}\n\n${result.stdout.map(o => o.text).reduce((a, n) => `${a}\n${n}`, '')}`, ); return result; diff --git a/lib/parsers/asm-parser-dotnet.ts b/lib/parsers/asm-parser-dotnet.ts index d6e8a4186..1fe7ca016 100644 --- a/lib/parsers/asm-parser-dotnet.ts +++ b/lib/parsers/asm-parser-dotnet.ts @@ -117,7 +117,6 @@ export class DotNetAsmParser implements IAsmParser { continue; } - if (line.startsWith('Emitting R2R PE file')) continue; cleanedAsm.push(line); } |