diff --git a/src/internal/goexperiment/exp_stepopt_off.go b/src/internal/goexperiment/exp_stepopt_off.go new file mode 100644 index 0000000000000000000000000000000000000000..bca12c06e2d4ab403b1e44b7e19227bec35a95e8 --- /dev/null +++ b/src/internal/goexperiment/exp_stepopt_off.go @@ -0,0 +1,8 @@ +// Code generated by mkconsts.go. DO NOT EDIT. + +//go:build !goexperiment.stepopt + +package goexperiment + +const StepOpt = false +const StepOptInt = 0 diff --git a/src/internal/goexperiment/exp_stepopt_on.go b/src/internal/goexperiment/exp_stepopt_on.go new file mode 100644 index 0000000000000000000000000000000000000000..957d2daac2ca2ec2abec9312603b3f9d35215e7c --- /dev/null +++ b/src/internal/goexperiment/exp_stepopt_on.go @@ -0,0 +1,8 @@ +// Code generated by mkconsts.go. DO NOT EDIT. + +//go:build goexperiment.stepopt + +package goexperiment + +const StepOpt = true +const StepOptInt = 1 diff --git a/src/internal/goexperiment/flags.go b/src/internal/goexperiment/flags.go index ac85fc800092a40a2090e8f719e5c012b54a682f..4b3b0f8ab3c8c1a926fa81ea926478ef5a70a6fb 100644 --- a/src/internal/goexperiment/flags.go +++ b/src/internal/goexperiment/flags.go @@ -131,4 +131,7 @@ type Flags struct { // Kunpeng malloc prefetch optimization. PrefetchMalloc bool + + // StepOpt enables optimization for func step in package runtime + StepOpt bool } diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go index 8c6ef2b4fc60816c2e3d428cde3541e04512dd94..608ec524a2702667c9e91c6935cf7a8e41848a7a 100644 --- a/src/runtime/symtab.go +++ b/src/runtime/symtab.go @@ -7,6 +7,7 @@ package runtime import ( "internal/abi" "internal/goarch" + "internal/goexperiment" "internal/runtime/atomic" "internal/runtime/sys" "unsafe" @@ -1246,6 +1247,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.StepOpt { + return stepOpt(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]) @@ -1269,6 +1273,49 @@ func step(p []byte, pc *uintptr, val *int32, first bool) (newp []byte, ok bool) return p, true } +func stepOpt(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