diff --git a/src/internal/goexperiment/exp_stepopt2_off.go b/src/internal/goexperiment/exp_stepopt2_off.go new file mode 100644 index 0000000000000000000000000000000000000000..7a06da83f86008ef887f73bf0ff2ce4d98fa006f --- /dev/null +++ b/src/internal/goexperiment/exp_stepopt2_off.go @@ -0,0 +1,8 @@ +// Code generated by mkconsts.go. DO NOT EDIT. + +//go:build !goexperiment.stepopt2 + +package goexperiment + +const StepOpt2 = false +const StepOpt2Int = 0 diff --git a/src/internal/goexperiment/exp_stepopt2_on.go b/src/internal/goexperiment/exp_stepopt2_on.go new file mode 100644 index 0000000000000000000000000000000000000000..1cd2d7d609247ba582c18a3d6881c5230876c708 --- /dev/null +++ b/src/internal/goexperiment/exp_stepopt2_on.go @@ -0,0 +1,8 @@ +// Code generated by mkconsts.go. DO NOT EDIT. + +//go:build goexperiment.stepopt2 + +package goexperiment + +const StepOpt2 = true +const StepOpt2Int = 1 diff --git a/src/internal/goexperiment/flags.go b/src/internal/goexperiment/flags.go index 87ddd355ff18dcd092f6ccc57521f2b7162f09f1..f39a282fedc256dbd93fa9aa20b7dc6f62ada5ed 100644 --- a/src/internal/goexperiment/flags.go +++ b/src/internal/goexperiment/flags.go @@ -115,4 +115,7 @@ type Flags struct { //PageNum enables 128k span size PageNum bool + + // StepOpt2 enables optimization for func step in package runtime + StepOpt2 bool } diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go index b47f2d839099fa780fa53621d35b5ac05df18500..ef2163447b34bfe473bef54f0a1987280d24532f 100644 --- a/src/runtime/symtab.go +++ b/src/runtime/symtab.go @@ -7,6 +7,7 @@ package runtime import ( "internal/abi" "internal/goarch" + "internal/goexperiment" "runtime/internal/atomic" "runtime/internal/sys" "unsafe" @@ -1069,6 +1070,9 @@ func funcdata(f funcInfo, i uint8) unsafe.Pointer { // step advances to the next pc, value pair in the encoded table. func step(p []byte, pc *uintptr, val *int32, first bool) (newp []byte, ok bool) { + if goexperiment.StepOpt2 { + return step_exp2(p, pc, val, first) + } // For both uvdelta and pcdelta, the common case (~70%) // is that they are a single byte. If so, avoid calling readvarint. uvdelta := uint32(p[0]) @@ -1092,6 +1096,49 @@ func step(p []byte, pc *uintptr, val *int32, first bool) (newp []byte, ok bool) return p, true } +func step_exp2(p []byte, pc *uintptr, val *int32, first bool) (newp []byte, ok bool) { + // For both uvdelta and pcdelta, the common case (~70%) + // is that they are a single byte. If so, avoid calling readvarint. + var n uint32 + uvdelta := uint32(p[0]) + if uvdelta == 0 && !first { + return nil, false + } + if uvdelta&0x80 == 0 { + n = 1 + *val += int32(-(uvdelta & 1) ^ (uvdelta >> 1)) + p = p[n:] + } else { + a := uint32(p[1]) + if a&0x80 == 0 { + uvdelta = (uvdelta & 0x7f) | (a << 7) + n = 2 + } else { + n, uvdelta = readvarint(p) + } + *val += int32(-(uvdelta & 1) ^ (uvdelta >> 1)) + p = p[n:] + } + + pcdelta := uint32(p[0]) // load 2-byte once + if pcdelta&0x80 == 0 { + n = 1 + *pc += uintptr((pcdelta & 0xff) * sys.PCQuantum) + p = p[n:] + } else { + a := uint32(p[1]) + if a&0x80 == 0 { + pcdelta = (pcdelta & 0x7f) | (a << 7) + n = 2 + } else { + n, pcdelta = readvarint(p) + } + p = p[n:] + *pc += uintptr(pcdelta * sys.PCQuantum) + } + return p, true +} + // readvarint reads a varint from p. func readvarint(p []byte) (read uint32, val uint32) { var v, shift, n uint32