Use the patch package to instrument the Go compiler
masterpatch package is designed for instrumenting the Go compiler (go tool compile). It provides the necessary tools to apply modifications or instrumentation to the compiler's behavior.repository·master·Indexed 19 days ago
https://github.com/xhd2015/xgoAn all-in-one test utility for Go that acts as a preprocessor for standard commands like go test and go build. It provides advanced capabilities including monkey patching (mocking), hierarchical stack trace visualization (tracing), and function execution recording.
patch package is designed for instrumenting the Go compiler (go tool compile). It provides the necessary tools to apply modifications or instrumentation to the compiler's behavior.The github.com/dop251/goja/ast package provides types that represent a JavaScript Abstract Syntax Tree (AST).
Warning: The parser and AST interfaces are currently works-in-progress, specifically regarding node types, and are subject to change in future versions.
import "github.com/dop251/goja/ast"github.com/dop251/goja/file package provides abstractions for managing source files and their positions, typically used by parsers and AST (Abstract Syntax Tree) implementations. It allows you to group multiple source files into a FileSet and resolve compact position indices (Idx) into human-readable Position objects.The github.com/dop251/goja/token package provides constants representing the lexical tokens of JavaScript (ECMA5). It is useful for writing parsers or tools that need to identify JavaScript syntax elements like keywords, operators, and delimiters.
import "github.com/dop251/goja/token"
// Example usage of token constants
var myToken = token.IDENTIFIERxgo is a wrapper around the standard go command designed to produce instrumented binaries.
It achieves this by leveraging the go -toolexec flag, which allows a custom program to intercept and invoke toolchain programs like vet and asm. When you run xgo build, the tool performs the following lifecycle:
GOROOT.GOROOT to ~/.xgo/go-instruments/GOROOT.go build -toolexec exec_tool <package>.exec_tool to forward compilation commands to the newly built instrumented compiler.xgo build ./my/exampleThe Patch DSL is a declarative, AST-aware language used to modify Go source files. It is primarily used by xgo to instrument the Go standard library for features like mocking, tracing, and interception.
Patch files must have the .xgo.patch extension and reside in a directory structure under patches/<go-version>/src/ that mirrors the GOROOT directory structure. For example, to patch src/runtime/runtime2.go, you would create patches/go1.25/src/runtime/runtime2.go.xgo.patch.
vscode-diff logic (from Microsoft's VS Code) into Go. It is designed to provide a consistent diff view between a backend and a frontend that uses monaco-editor (the web version of VS Code).Go 1.25+ forbids using the -overlay flag to replace files located under GOMODCACHE. Because xgo runtime packages (like runtime/trace) are often module dependencies in GOMODCACHE, xgo switches to a different mechanism for Go 1.25+:
.xgo/gen/modules/) outside GOMODCACHE.replace directive in a modified go.mod (via -modfile) to resolve the runtime from the local directory.import _ "runtime/trace") to ensure runtime packages are compiled.Note: This causes runtime/trace to be included in the test binary, which may affect tests asserting on exact functab contents.
Unlike traditional monkey patching, xgo provides concurrency-safe mocking. When you call trap.AddInterceptor outside of an init function, the interceptor is applied only to the current Goroutine. This allows you to run tests in parallel without side effects between different test cases, as the interceptor is automatically cleared when the Goroutine exits.
To manually clean up an interceptor registered after init, use the returned function:
func main() {
clear := trap.AddInterceptor(&trap.Interceptor{...})
defer clear()
// ...
}To avoid inserting code inside raw string literals or separating //go: directives (like //go:embed) from their target declarations, xgo uses a safe insertion logic via GenDeclSafeEnd.
The Logic:
//go: directive, it uses the position of the next declaration (nextDecl.Pos()) as the insertion point. This is more reliable than genDecl.End() when \r bytes are present.//go: directive, it falls back to the current declaration's end (genDecl.End()) to ensure the directive and its declaration remain together.Implementation Details:
\n separator rather than a semicolon ; to ensure compatibility with both insertion methods.GenDeclSafeEnd is located in instrument/patch/init.go.safeGenDeclEnd (a wrapper for variable traps) is located in instrument/instrument_var/trap_var.go.// GenDeclSafeEnd returns a safe insertion point after a GenDecl.
// When the next declaration has no go: directive, uses nextDecl.Pos()
// (computed by the scanner, always correct). Otherwise falls back to
// genDecl.End() to avoid separating directives from their declarations.
func GenDeclSafeEnd(file *ast.File, declIndex int) token.Pos {
if declIndex+1 < len(file.Decls) && !HasGoDirective(file.Decls[declIndex+1]) {
return file.Decls[declIndex+1].Pos()
}
return file.Decls[declIndex].End()
}A function symbol is essentially a pointer to the function's entry point in the code segment. In Go's runtime, a function symbol is treated as a byte representing the Program Counter (PC), which is a pointer to a read-only part of the binary.
Key observation: The entryPC (retrieved via runtime.GetcallerFuncPC()) is identical to the function symbol itself.
When choosing between a native Go Myers diff and the VSCode diff implementation, consider the latency trade-off. The VSCode implementation via Node.js IPC is significantly slower than native Go.
| Implementation | Latency |
|---|---|
| Myers (Native Go) | ~1585 ns/op |
| VSCode (Node.js IPC) | ~10.8 ms/op |
Recommendation: Use the VSCode implementation for consistency with Monaco/VS Code editors if the operation is performed in the background. Avoid using it for real-time, high-frequency scenarios due to the ~6842x performance penalty.