未验证 提交 f49851ca 编写于 作者: J Jan Kotas 提交者: GitHub

Delete NGen flavor of JIT configs (#73383)

* Delete NGen flavor of JIT configs

We do not need them anymore since the JIT configs are specified on AOT tool command line now.

* Update docs
上级 4f835ae4
......@@ -1465,7 +1465,7 @@ Use `#ifdef DEBUG` for debug-only code. Do not use `#ifdef _DEBUG` (with a leadi
Use the `INDEBUG(x)` macro (and related macros) judiciously, for code that only runs in DEBUG, to avoid `#ifdef`s.
Use the `JITDUMP(x)` macro for printing things to the JIT dump output. Note that these things will only get printed when the `verbose` variable is set, which is when `COMPlus_JitDump=*` or when `COMPlus_JitDump=XXX` and we are JITting function XXX; or when `COMPlus_NgenDump=*` or `COMPlus_NgenDump=XXX` and we are NGENing function XXX. Do not use `JITDUMP` for all output in a debug-only function that might be useful to call from the debugger. In that case, define a function that uses `printf` (which is a JIT-specific implementation of this function), which can be called from the debugger, and invoke that function like this:
Use the `JITDUMP(x)` macro for printing things to the JIT dump output. Note that these things will only get printed when the `verbose` variable is set, which is when `COMPlus_JitDump=*` or when `COMPlus_JitDump=XXX` and we are JITting function XXX. Do not use `JITDUMP` for all output in a debug-only function that might be useful to call from the debugger. In that case, define a function that uses `printf` (which is a JIT-specific implementation of this function), which can be called from the debugger, and invoke that function like this:
```c++
DBEXEC(verbose, MyDumpFunction());
......
......@@ -47,9 +47,9 @@ At the time of writing the current supported sets of valid arguments are:
|`--targetos osx --targetarch x64` |
|`--targetos osx --targetarch arm64` |
- Passing special jit behavior flags to the compiler is done via the `--codegenopt` switch. As an example to turn on tailcall loop optimizations and dump all code compiled use a pair of them like `--codegenopt NgenDump=* --codegenopt TailCallLoopOpt=1`.
- Passing special jit behavior flags to the compiler is done via the `--codegenopt` switch. As an example to turn on tailcall loop optimizations and dump all code compiled use a pair of them like `--codegenopt JitDump=* --codegenopt TailCallLoopOpt=1`.
- When using the NgenDump feature of the JIT, disable parallelism as described above or specify a single method to be compiled. Otherwise, output from multiple functions will be interleaved and inscrutable.
- When using the JitDump feature of the JIT, disable parallelism as described above or specify a single method to be compiled. Otherwise, output from multiple functions will be interleaved and inscrutable.
- Since there are 2 jits in the process, when debugging in the JIT, if the source files match up, there is a decent chance that a native debugger will stop at unfortunate and unexpected locations. This is extremely annoying, and to combat this, we generally recommend making a point of using a runtime which doesn't exactly match that of the compiler in use. However, if that isn't feasible, it is also possible to disable symbol loading in most native debuggers. For instance, in Visual Studio, one would use the "Specify excluded modules" feature.
......@@ -137,9 +137,9 @@ Single method repro args:--singlemethodtypename "Complex_Array_Test,Complex1" --
Emitting R2R PE file: c:\git2\runtime\artifacts\tests\coreclr\windows.x64.Debug\jit\Directed\Arrays\Complex1\\Complex1.dll
```
I then wanted to see some more detail from the jit. To keep the size of this example small, I'm just using the `NgenOrder=1`switch, but jit developers would more likely use `NgenDump=*` switch.
I then wanted to see some more detail from the jit. To keep the size of this example small, I'm just using the `JitOrder=1`switch, but jit developers would more likely use `JitDump=*` switch.
```
C:\git2\runtime>"dotnet" "c:\git2\runtime\artifacts\tests\coreclr\windows.x64.Debug\Tests\Core_Root\crossgen2\crossgen2.dll" @"c:\git2\runtime\artifacts\tests\coreclr\windows.x64.Debug\jit\Directed\Arrays\Complex1\\Complex1.dll.rsp" -r:c:\git2\runtime\artifacts\tests\coreclr\windows.x64.Debug\jit\Directed\Arrays\Complex1\IL-CG2\*.dll --print-repro-instructions --singlemethodtypename "Complex_Array_Test,Complex1" --singlemethodname Main --singlemethodindex 1 --codegenopt NgenOrder=1
C:\git2\runtime>"dotnet" "c:\git2\runtime\artifacts\tests\coreclr\windows.x64.Debug\Tests\Core_Root\crossgen2\crossgen2.dll" @"c:\git2\runtime\artifacts\tests\coreclr\windows.x64.Debug\jit\Directed\Arrays\Complex1\\Complex1.dll.rsp" -r:c:\git2\runtime\artifacts\tests\coreclr\windows.x64.Debug\jit\Directed\Arrays\Complex1\IL-CG2\*.dll --print-repro-instructions --singlemethodtypename "Complex_Array_Test,Complex1" --singlemethodname Main --singlemethodindex 1 --codegenopt JitOrder=1
C:\git2\runtime\.dotnet
Single method repro args:--singlemethodtypename "Complex_Array_Test,Complex1" --singlemethodname Main --singlemethodindex 1
| Profiled | Method | Method has | calls | Num |LclV |AProp| CSE | Perf |bytes | x64 codesize|
......@@ -152,7 +152,7 @@ Emitting R2R PE file: c:\git2\runtime\artifacts\tests\coreclr\windows.x64.Debug\
And finally, as the last `--targetarch` and `--targetos` switch is the meaningful one, it is simple to target a different architecture for ad hoc exploration...
```
C:\git2\runtime>"dotnet" "c:\git2\runtime\artifacts\tests\coreclr\windows.x64.Debug\Tests\Core_Root\crossgen2\crossgen2.dll" @"c:\git2\runtime\artifacts\tests\coreclr\windows.x64.Debug\jit\Directed\Arrays\Complex1\\Complex1.dll.rsp" -r:c:\git2\runtime\artifacts\tests\coreclr\windows.x64.Debug\jit\Directed\Arrays\Complex1\IL-CG2\*.dll --print-repro-instructions --singlemethodtypename "Complex_Array_Test,Complex1" --singlemethodname Main --singlemethodindex 1 --codegenopt NgenOrder=1 --targetarch arm64
C:\git2\runtime>"dotnet" "c:\git2\runtime\artifacts\tests\coreclr\windows.x64.Debug\Tests\Core_Root\crossgen2\crossgen2.dll" @"c:\git2\runtime\artifacts\tests\coreclr\windows.x64.Debug\jit\Directed\Arrays\Complex1\\Complex1.dll.rsp" -r:c:\git2\runtime\artifacts\tests\coreclr\windows.x64.Debug\jit\Directed\Arrays\Complex1\IL-CG2\*.dll --print-repro-instructions --singlemethodtypename "Complex_Array_Test,Complex1" --singlemethodname Main --singlemethodindex 1 --codegenopt JitOrder=1 --targetarch arm64
C:\git2\runtime\.dotnet
Single method repro args:--singlemethodtypename "Complex_Array_Test,Complex1" --singlemethodname Main --singlemethodindex 1
| Profiled | Method | Method has | calls | Num |LclV |AProp| CSE | Perf |bytes | arm64 codesize|
......@@ -168,7 +168,7 @@ Finally, attaching a debugger to crossgen2.
Since this example uses `dotnet` as the `__TestDotNetCmd` you will need to debug the `c:\git2\runtime\.dotnet\dotnet.exe` process.
```
devenv /debugexe C:\git2\runtime\.dotnet\dotnet.exe "c:\git2\runtime\artifacts\tests\coreclr\windows.x64.Debug\Tests\Core_Root\crossgen2\crossgen2.dll" @"c:\git2\runtime\artifacts\tests\coreclr\windows.x64.Debug\jit\Directed\Arrays\Complex1\\Complex1.dll.rsp" -r:c:\git2\runtime\artifacts\tests\coreclr\windows.x64.Debug\jit\Directed\Arrays\Complex1\IL-CG2\*.dll --print-repro-instructions --singlemethodtypename "Complex_Array_Test,Complex1" --singlemethodname Main --singlemethodindex 1 --codegenopt NgenOrder=1 --targetarch arm64
devenv /debugexe C:\git2\runtime\.dotnet\dotnet.exe "c:\git2\runtime\artifacts\tests\coreclr\windows.x64.Debug\Tests\Core_Root\crossgen2\crossgen2.dll" @"c:\git2\runtime\artifacts\tests\coreclr\windows.x64.Debug\jit\Directed\Arrays\Complex1\\Complex1.dll.rsp" -r:c:\git2\runtime\artifacts\tests\coreclr\windows.x64.Debug\jit\Directed\Arrays\Complex1\IL-CG2\*.dll --print-repro-instructions --singlemethodtypename "Complex_Array_Test,Complex1" --singlemethodname Main --singlemethodindex 1 --codegenopt JitOrder=1 --targetarch arm64
```
This will launch the Visual Studio debugger, with a solution setup for debugging the dotnet.exe process. By default this solution will debug the native code of the process only. To debug the managed components, edit the properties on the solution and set the `Debugger Type` to `Managed (.NET Core, .NET 5+)` or `Mixed (.NET Core, .NET 5+)`.
......
......@@ -2633,29 +2633,14 @@ void Compiler::compInitOptions(JitFlags* jitFlags)
//
if (!compIsForInlining())
{
if (jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
if (JitConfig.JitDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
{
if (JitConfig.NgenDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
{
verboseDump = true;
}
unsigned ngenHashDumpVal = (unsigned)JitConfig.NgenHashDump();
if ((ngenHashDumpVal != (DWORD)-1) && (ngenHashDumpVal == info.compMethodHash()))
{
verboseDump = true;
}
verboseDump = true;
}
else
unsigned jitHashDumpVal = (unsigned)JitConfig.JitHashDump();
if ((jitHashDumpVal != (DWORD)-1) && (jitHashDumpVal == info.compMethodHash()))
{
if (JitConfig.JitDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
{
verboseDump = true;
}
unsigned jitHashDumpVal = (unsigned)JitConfig.JitHashDump();
if ((jitHashDumpVal != (DWORD)-1) && (jitHashDumpVal == info.compMethodHash()))
{
verboseDump = true;
}
verboseDump = true;
}
}
}
......@@ -2849,109 +2834,67 @@ void Compiler::compInitOptions(JitFlags* jitFlags)
//
if (!altJitConfig || opts.altJit)
{
if (jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
bool disEnabled = true;
// Setup assembly name list for disassembly, if not already set up.
if (!s_pJitDisasmIncludeAssembliesListInitialized)
{
if ((JitConfig.NgenOrder() & 1) == 1)
const WCHAR* assemblyNameList = JitConfig.JitDisasmAssemblies();
if (assemblyNameList != nullptr)
{
opts.dspOrder = true;
s_pJitDisasmIncludeAssembliesList = new (HostAllocator::getHostAllocator())
AssemblyNamesList2(assemblyNameList, HostAllocator::getHostAllocator());
}
s_pJitDisasmIncludeAssembliesListInitialized = true;
}
if (JitConfig.NgenGCDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
{
opts.dspGCtbls = true;
}
// If we have an assembly name list for disassembly, also check this method's assembly.
if (s_pJitDisasmIncludeAssembliesList != nullptr && !s_pJitDisasmIncludeAssembliesList->IsEmpty())
{
const char* assemblyName = info.compCompHnd->getAssemblyName(
info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));
if (JitConfig.NgenDisasm().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
if (!s_pJitDisasmIncludeAssembliesList->IsInList(assemblyName))
{
opts.disAsm = true;
disEnabled = false;
}
if (JitConfig.NgenDisasm().contains("SPILLED", nullptr, nullptr))
}
if (disEnabled)
{
if ((JitConfig.JitOrder() & 1) == 1)
{
opts.disAsmSpilled = true;
opts.dspOrder = true;
}
if (JitConfig.NgenUnwindDump().contains(info.compMethodName, info.compClassName,
&info.compMethodInfo->args))
if (JitConfig.JitGCDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
{
opts.dspUnwind = true;
opts.dspGCtbls = true;
}
if (JitConfig.NgenEHDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
if (JitConfig.JitDisasm().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
{
opts.dspEHTable = true;
opts.disAsm = true;
}
if (JitConfig.NgenDebugDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
if (JitConfig.JitDisasm().contains("SPILLED", nullptr, nullptr))
{
opts.dspDebugInfo = true;
opts.disAsmSpilled = true;
}
}
else
{
bool disEnabled = true;
// Setup assembly name list for disassembly, if not already set up.
if (!s_pJitDisasmIncludeAssembliesListInitialized)
if (JitConfig.JitUnwindDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
{
const WCHAR* assemblyNameList = JitConfig.JitDisasmAssemblies();
if (assemblyNameList != nullptr)
{
s_pJitDisasmIncludeAssembliesList = new (HostAllocator::getHostAllocator())
AssemblyNamesList2(assemblyNameList, HostAllocator::getHostAllocator());
}
s_pJitDisasmIncludeAssembliesListInitialized = true;
opts.dspUnwind = true;
}
// If we have an assembly name list for disassembly, also check this method's assembly.
if (s_pJitDisasmIncludeAssembliesList != nullptr && !s_pJitDisasmIncludeAssembliesList->IsEmpty())
if (JitConfig.JitEHDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
{
const char* assemblyName = info.compCompHnd->getAssemblyName(
info.compCompHnd->getModuleAssembly(info.compCompHnd->getClassModule(info.compClassHnd)));
if (!s_pJitDisasmIncludeAssembliesList->IsInList(assemblyName))
{
disEnabled = false;
}
opts.dspEHTable = true;
}
if (disEnabled)
if (JitConfig.JitDebugDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
{
if ((JitConfig.JitOrder() & 1) == 1)
{
opts.dspOrder = true;
}
if (JitConfig.JitGCDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
{
opts.dspGCtbls = true;
}
if (JitConfig.JitDisasm().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
{
opts.disAsm = true;
}
if (JitConfig.JitDisasm().contains("SPILLED", nullptr, nullptr))
{
opts.disAsmSpilled = true;
}
if (JitConfig.JitUnwindDump().contains(info.compMethodName, info.compClassName,
&info.compMethodInfo->args))
{
opts.dspUnwind = true;
}
if (JitConfig.JitEHDump().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args))
{
opts.dspEHTable = true;
}
if (JitConfig.JitDebugDump().contains(info.compMethodName, info.compClassName,
&info.compMethodInfo->args))
{
opts.dspDebugInfo = true;
}
opts.dspDebugInfo = true;
}
}
if (opts.disAsm && JitConfig.JitDisasmWithGC())
......
......@@ -467,20 +467,9 @@ FILE* Compiler::fgOpenFlowGraphFile(bool* wbDontClose, Phases phase, PhasePositi
}
#ifdef DEBUG
if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT))
{
dumpFunction =
JitConfig.NgenDumpFg().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args);
filename = JitConfig.NgenDumpFgFile();
pathname = JitConfig.NgenDumpFgDir();
}
else
{
dumpFunction =
JitConfig.JitDumpFg().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args);
filename = JitConfig.JitDumpFgFile();
pathname = JitConfig.JitDumpFgDir();
}
dumpFunction = JitConfig.JitDumpFg().contains(info.compMethodName, info.compClassName, &info.compMethodInfo->args);
filename = JitConfig.JitDumpFgFile();
pathname = JitConfig.JitDumpFgDir();
prePhasePattern = JitConfig.JitDumpFgPrePhase();
postPhasePattern = JitConfig.JitDumpFgPhase();
......@@ -728,9 +717,6 @@ FILE* Compiler::fgOpenFlowGraphFile(bool* wbDontClose, Phases phase, PhasePositi
// COMPlus_JitDumpFgDir A path to a directory into which the flowgraphs will be dumped.
// COMPlus_JitDumpFgFile The filename to use. The default is "default.[xml|dot]".
// Note that the new graphs will be appended to this file if it already exists.
// COMPlus_NgenDumpFg Same as COMPlus_JitDumpFg, but for ngen compiles.
// COMPlus_NgenDumpFgDir Same as COMPlus_JitDumpFgDir, but for ngen compiles.
// COMPlus_NgenDumpFgFile Same as COMPlus_JitDumpFgFile, but for ngen compiles.
// COMPlus_JitDumpFgPhase Phase(s) after which to dump the flowgraph.
// Set to the short name of a phase to see the flowgraph after that phase.
// Leave unset to dump after COLD-BLK (determine first cold block) or set to *
......
......@@ -137,7 +137,7 @@ CONFIG_INTEGER(JitReportFastTailCallDecisions, W("JitReportFastTailCallDecisions
CONFIG_INTEGER(JitPInvokeCheckEnabled, W("JITPInvokeCheckEnabled"), 0)
CONFIG_INTEGER(JitPInvokeEnabled, W("JITPInvokeEnabled"), 1)
// Controls verbosity for JitPrintInlinedMethods. Ignored for JitDump/NgenDump where
// Controls verbosity for JitPrintInlinedMethods. Ignored for JitDump where
// it's always set.
CONFIG_INTEGER(JitPrintInlinedMethodsVerbose, W("JitPrintInlinedMethodsVerboseLevel"), 0)
// Prints a tree of inlinees for a specific method (use '*' for all methods)
......@@ -174,8 +174,6 @@ CONFIG_STRING(JitStressRegsRange, W("JitStressRegsRange")) // Only apply JitStre
CONFIG_INTEGER(JitVNMapSelLimit, W("JitVNMapSelLimit"), 0) // If non-zero, assert if # of VNF_MapSelect applications
// considered reaches this
CONFIG_INTEGER(NgenHashDump, W("NgenHashDump"), -1) // same as JitHashDump, but for ngen
CONFIG_INTEGER(NgenOrder, W("NgenOrder"), 0)
CONFIG_INTEGER(RunAltJitCode, W("RunAltJitCode"), 1) // If non-zero, and the compilation succeeds for an AltJit, then
// use the code. If zero, then we always throw away the generated
// code and fall back to the default compiler.
......@@ -215,18 +213,7 @@ CONFIG_METHODSET(JitNoProcedureSplittingEH, W("JitNoProcedureSplittingEH")) // D
// exception handling
CONFIG_METHODSET(JitStressOnly, W("JitStressOnly")) // Internal Jit stress mode: stress only the specified method(s)
CONFIG_METHODSET(JitUnwindDump, W("JitUnwindDump")) // Dump the unwind codes for the method
///
/// NGEN
///
CONFIG_METHODSET(NgenDisasm, W("NgenDisasm")) // Same as JitDisasm, but for ngen
CONFIG_METHODSET(NgenDump, W("NgenDump")) // Same as JitDump, but for ngen
CONFIG_METHODSET(NgenEHDump, W("NgenEHDump")) // Dump the EH table for the method, as reported to the VM
CONFIG_METHODSET(NgenGCDump, W("NgenGCDump"))
CONFIG_METHODSET(NgenDebugDump, W("NgenDebugDump"))
CONFIG_METHODSET(NgenUnwindDump, W("NgenUnwindDump")) // Dump the unwind codes for the method
///
/// JIT
///
CONFIG_METHODSET(JitDumpFg, W("JitDumpFg")) // Dumps Xml/Dot Flowgraph for specified method
CONFIG_STRING(JitDumpFgDir, W("JitDumpFgDir")) // Directory for Xml/Dot flowgraph dump(s)
CONFIG_STRING(JitDumpFgFile, W("JitDumpFgFile")) // Filename for Xml/Dot flowgraph dump(s) (default: "default")
......@@ -259,12 +246,6 @@ CONFIG_STRING(JitStressModeNamesNot, W("JitStressModeNamesNot")) // Internal Jit
// STRESS_TAILCALL
CONFIG_STRING(JitStressRange, W("JitStressRange")) // Internal Jit stress mode
///
/// NGEN
///
CONFIG_METHODSET(NgenDumpFg, W("NgenDumpFg")) // Ngen Xml/Dot flowgraph dump support
CONFIG_STRING(NgenDumpFgDir, W("NgenDumpFgDir")) // Ngen Xml/Dot flowgraph dump support
CONFIG_STRING(NgenDumpFgFile, W("NgenDumpFgFile")) // Ngen Xml/Dot flowgraph dump support
///
/// JIT Hardware Intrinsics
///
CONFIG_INTEGER(EnableIncompleteISAClass, W("EnableIncompleteISAClass"), 0) // Enable testing not-yet-implemented
......
......@@ -336,8 +336,8 @@ base_diff_parser.add_argument("-diff_jit_option", action="append", help="Option
# subparser for asmdiffs
asm_diff_parser = subparsers.add_parser("asmdiffs", description=asm_diff_description, parents=[core_root_parser, target_parser, superpmi_common_parser, replay_common_parser, base_diff_parser])
asm_diff_parser.add_argument("--diff_jit_dump", action="store_true", help="Generate JitDump output for diffs. Default: only generate asm, not JitDump.")
asm_diff_parser.add_argument("--gcinfo", action="store_true", help="Include GC info in disassembly (sets COMPlus_JitGCDump/COMPlus_NgenGCDump; requires instructions to be prefixed by offsets).")
asm_diff_parser.add_argument("--debuginfo", action="store_true", help="Include debug info after disassembly (sets COMPlus_JitDebugDump/COMPlus_NgenDebugDump).")
asm_diff_parser.add_argument("--gcinfo", action="store_true", help="Include GC info in disassembly (sets COMPlus_JitGCDump; requires instructions to be prefixed by offsets).")
asm_diff_parser.add_argument("--debuginfo", action="store_true", help="Include debug info after disassembly (sets COMPlus_JitDebugDump).")
asm_diff_parser.add_argument("-tag", help="Specify a word to add to the directory name where the asm diffs will be placed")
asm_diff_parser.add_argument("-metrics", action="append", help="Metrics option to pass to jit-analyze. Can be specified multiple times, or pass comma-separated values.")
asm_diff_parser.add_argument("-retainOnlyTopFiles", action="store_true", help="Retain only top .dasm files with largest improvements or regressions and delete remaining files.")
......@@ -1426,9 +1426,6 @@ class SuperPMIReplayAsmDiffs:
"COMPlus_JitDisasm": "*",
"COMPlus_JitUnwindDump": "*",
"COMPlus_JitEHDump": "*",
"COMPlus_NgenDisasm": "*",
"COMPlus_NgenUnwindDump": "*",
"COMPlus_NgenEHDump": "*",
"COMPlus_JitDiffableDasm": "1",
"COMPlus_JitEnableNoWayAssert": "1",
"COMPlus_JitNoForceFallback": "1",
......@@ -1436,19 +1433,16 @@ class SuperPMIReplayAsmDiffs:
if self.coreclr_args.gcinfo:
asm_complus_vars.update({
"COMPlus_JitGCDump": "*",
"COMPlus_NgenGCDump": "*" })
"COMPlus_JitGCDump": "*" })
if self.coreclr_args.debuginfo:
asm_complus_vars.update({
"COMPlus_JitDebugDump": "*",
"COMPlus_NgenDebugDump": "*",
"COMPlus_JitDisasmWithDebugInfo": "1" })
jit_dump_complus_vars = asm_complus_vars.copy()
jit_dump_complus_vars.update({
"COMPlus_JitDump": "*",
"COMPlus_NgenDump": "*" })
"COMPlus_JitDump": "*" })
asm_complus_vars_full_env = os.environ.copy()
asm_complus_vars_full_env.update(asm_complus_vars)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册