Go Runtime Implementations: Select

Code Path: src/runtime/select.go IR stage IR will walk a select statement and generate the code accordingly: If there’s no case, replace the select statement with runtime.block, the current goroutine will be blocked forever. If there’s only one case, extract the send or receive operation from the case statement. Otherwise, convert case values to addresses. If there’s only one case with one default, replace it with non-block calls selectnbsend or selectnbrecv. Generate a select statement with the list of send and recv cases, and run selectgo on it. Run the case or default based on the returned index of selectgo. selectgo selectgo takes two major arguments: a list of scase and a list of the orders of recv/send. It returns the pos of case to execute. ...

November 4, 2022

Go Runtime Implementations: Slices

Code Path: src/runtime/slice.go makeslicecopy makeslicecopy is used for IR patterns like m = OMAKESLICE([]T, x); OCOPY(m, s), IR will rewrite this specific order of code path and replace it with OMAKESLICECOPY. If the elements has no pointer, SSA will generate code to do a mallocgc and memmove. Otherwise, the code will be expanded to makeslicecopy: Check the length of the slice to copy to. Do mallocgc Do memmove makeslice and `makeslice641 makeslice is used for make(slice, len, cap) statements, if cap is missing, by default it will be the same as len. ...

November 4, 2022

Go Runtime Implementations: Interfaces

Static Definition and Initialization Code Path: src/runtime/iface.go In proc.go, itabsinit will init the itabTable with the current activeModules information. The itabsinit function will read the itablinks from each module and add them to the global hash table. During the runtime, the getitab function will also build more items dynamically and fill the hash table accordingly. itablinks was produced for each module during the linking stage, and contains an array of itab. itab is generated by writeITab function (code path: cmd/compile/internal/reflectdata/reflect.go), used to store the type link between a concrete type (_type field) implementing an interface (inter field). If _type doesn’t implement inter, fun will be empty; else it will save the methods of _type implementing inter (not all methods of _type). ...

October 27, 2022

Go Runtime Implementations: Typing System

Compiling Code Path: src/cmd/compile/internal/ir/expr.go During the IR stage, each expression will get type info, it’s defined as miniExpr and can be assigned a types.Type value. Static Typing: types2 Code Path: src/cmd/compile/internal/types2 types and `types2 Conversion Code Path: src/cmd/compile/internal/noder/types.go Currently, both packages are in use, but much logic is being migrated to types2 package. types2 package was introduced as part of go generic features and has a better code structure than the old types package. ...

October 25, 2022

Go Runtime Implementations: Garbage Collection

Ref Garbage Collector Code Path: src/runtime/mgc.go gcinit gcinit runs after almost everything set up in schedinit. Set sweepDrainedMask Initialize gcController with GOGC (for GC percentage control) and GOMEMLIMIT (for memory limits). Initialize work semaphores. gcenable gcenable happens in the main goroutine, right after runtime_inittask. Start bgsweep Start bgscavenge GC GC runs a full garbage collection. Each run will finish the current GC cycle: sweep termination, mark, mark termination, and sweep. Then it will start a new GC cycle. Note that GC cycles can move forward to more than N+1. ...

October 18, 2022

Go Runtime Implementations: Stack and Memory Management

Stack Management Code Path: src/runtime/stack.go Stack pools are initialized before mheap_, because we don’t allocate any memory during this stage. Right after the stack pools initialized, the mheap_ will be initialized so later stack allocation is possible. stackpool stackpool is managed by the “order” (based on the ratio of stack size and _FixedStack) of the stack, each order of stack has its own stack pool. In stackinit, the stack pool will be initialized right after moduledataverify. ...

October 16, 2022

Go Runtime Implementations: Scheduling

Code Path: src/runtime/proc.go Start-Up Process of a Go program. Take src/runtime/asm_arm.s as an example: Take the address of g0 and m0. Set up m.g0 and g.m. Create istack. Do runtime check. Save argc and argv. Call runtime.osinit. Call runtime.schedinit. Call runtime.newproc for the main function. call runtime.mstart to start the M. runtime.osinit Take src/runtime/os_linux.go as an example: Get the number of processors. This is done by making a syscall SYS_sched_getaffinity. Get the huge page size. Run osArchInit. <- Seems not used. runtime.schedinit Initialize all the locks. Set up the g.racectx. Stop the world. moduledataverify. Defined in src/runtime/symtab.go, it will check moduledata’s binary info. stackinit. Defined in src/runtime/stack.go, it will setup the global stack pool, all stacks will be allocated by it. mallocinit. Defined in src/runtime/malloc.go, it will initialize the memory allocator used by Go. cpuinit. Set up the internal/cpu information. alginit. Defined in src/runtime/alg.go, set up the CPU instructions that will be used by some internal algorithms, depending on cpuinit. fastrandinit. Initialize the g0.m with mcommoninit. modulesinit. Defined in src/runtime/symtab.go, initialize the dynamic loaded modules. typelinksinit. Defined in src/runtime/type.go, initialized the dynamic-loaded module type informations. itabsinit. Defined in src/runtime/iface.go, update itabTable with the dynamic-loaded modules. stkobjinit. Defined in src/runtime/stkframe.go, this will set up methodValueCallFrameObjs, used by later GC module. Save the signal mask as initSigMask. Parse argv. Defined in src/runtime/runtime1.go. Parse environment variables. parsedebugvars. Defined in src/runtime/runtime1.go. gcinit. Set up the number of processors, and trim it accordingly with procresize: Grow allp as necessary. Initialize all the p’s of allp. Release old p’s. Track the idle and runnable p, and return the runnable p’s. There should be zero runnable p, since this is only a bootstrap process. Start the world. runtime.mstart mstart0 set up the stack info, then calls runtime.mstart1 to allocate the m: ...

October 14, 2022

Go Runtime Implementations: Goroutines

Preface Code path: src/runtime/proc.go Data structures are defined under src/runtime/runtime2.go. Concepts Copied from source code: // G - goroutine. // M - worker thread, or machine. // P - processor, a resource that is required to execute Go code. // M must have an associated P to execute Go code, however it can be // blocked or in a syscall w/o an associated P. main Set up stack size. Fork a new m and run the sysmon function, except the wasm platform. Lock the main m and g. Run the runtime initTask’s. Enable GC. Run the main initTask’s. Run main_main. runtime.sysmon sysmon is a global worker runs regularly to ensure the system state consistency. ...

October 12, 2022

Go Runtime Implementations: Channel

Path: src/runtime/chan.go Compilation When you make a chan with make function, the compiler will expand the expression to the makechan implementation. The actual expansion happens at cmd/compile/internal/walk/expr.go. The runtime will determine whether to use makechan or makechan64. Type Definitions type _type _type is used as the internal representation of a go type. The same structure is defined multiple times across the go runtime. _type stores the following fields: type chantype makechan only uses chantype.elem, the other fields are used by the type system. ...

September 29, 2022

Travesal Through The Go Compiler, Part 6

ssagen.Compile Build SSA for the ir.Func (buildssa) Check ssaDump and set the dump flag. Initialize ssagen.state. Push the line number or the parent’s line number (if it’s missing) to the stack. Set up ssagen.state flags from ir.Func information. Set up an empty ssagen.ssafn with ir.Func and ABI information. Allocate the starting block for the current ssa.Func. Check open-coded defers. <- What’s this? Do ABIAnalyze, get the abi.ABIParamResultInfo of function in/out parameters. Generate the addresses of the local variables saved in ir.Func.Dcl. Generate the AuxCall for the current function. Generate the addresses of the input parameters saved in ir.Func.Dcl. Generate the addresses of the closure variables saved in ir.Func.Dcl. Covert to SSA IR. I don’t have any experience with SSA, so it’s really difficult to understand this part of the code. Insert Phi values. <- What’s this? Call ssa.Compile. It defines an array of ssa.pass, and run each of them against the ssa.Func. Generate SSA (genssa) This step returns a objw.Progs to save the machine-level instructions of the function. objw saves platform-independent structures of the binary. ...

September 20, 2022