Skip to content

starlark-go-x Overview

starlark-go-x is our enhanced fork of Google’s official starlark-go interpreter. It adds instrumentation hooks that enable coverage collection, profiling, and debugging without modifying user code.

The official starlark-go interpreter doesn’t expose hooks for:

  • Tracking which lines of code execute
  • Monitoring branch decisions (if/else outcomes)
  • Observing function entry/exit
  • Counting loop iterations

These hooks are essential for building coverage tools like skycov and skytest --coverage.

OnExec

Line coverage - fires before each bytecode instruction

OnBranch

Branch coverage - fires after each conditional jump

OnFunctionEnter/Exit

Function coverage - fires on function entry and return

OnIteration

Loop coverage - fires on each for-loop iteration decision

Add to your go.mod:

// Replace upstream starlark-go with our fork
replace go.starlark.net => github.com/albertocavalcante/starlark-go-x v0.0.0-trunk

Or use a local path during development:

replace go.starlark.net => ../starlark-go-x/trunk
import "go.starlark.net/starlark"
thread := &starlark.Thread{
Name: "my-thread",
// Line coverage
OnExec: func(fn *starlark.Function, pc uint32) {
pos := fn.PositionAt(pc)
fmt.Printf("Executing %s:%d\n", pos.Filename(), pos.Line)
},
// Branch coverage
OnBranch: func(fn *starlark.Function, pc uint32, taken bool) {
pos := fn.PositionAt(pc)
fmt.Printf("Branch at %s:%d -> %v\n", pos.Filename(), pos.Line, taken)
},
}
// Execute Starlark code with instrumentation
starlark.ExecFile(thread, "example.star", src, nil)
BranchPurposeStatus
mainTracks upstream google/starlark-goRead-only
trunkAll features combinedUse this
coverage-hooksOnExec hook onlyMerged to trunk
branch-coverage+OnBranchMerged to trunk
function-coverage+OnFunctionEnter/ExitMerged to trunk
loop-coverage+OnIterationMerged to trunk
type-hintsType annotation parsingMerged to trunk
MetricHookDescription
Line CoverageOnExecTracks which source lines execute
Branch CoverageOnBranchTracks if/else and short-circuit outcomes
Function CoverageOnFunctionEnterTracks which functions are called
Loop CoverageOnIterationTracks for-loop iteration counts
ConstructBytecodeHook
if/elif/elseCJMPOnBranch
for x in itemsITERJMPOnIteration
a and bCJMPOnBranch
a or bCJMPOnBranch
x if cond else yCJMPOnBranch
[x for x in items]ITERJMPOnIteration
def f(): ... callsCALLOnFunctionEnter/Exit

We intend to propose these changes to google/starlark-go:

  1. Phase 1: OnExec hook (most impactful, enables line coverage)
  2. Phase 2: OnBranch hook (branch coverage)
  3. Phase 3: OnFunctionEnter/Exit hooks (function coverage, profiling)
  4. Phase 4: OnIteration hook (loop coverage)

Each hook is designed to have zero overhead when not used (nil check at call site).