aboutsummaryrefslogtreecommitdiff
path: root/src/runtime
diff options
context:
space:
mode:
authorKeith Randall <khr@golang.org>2025-06-18 14:50:23 -0700
committerKeith Randall <khr@golang.org>2025-07-24 16:05:59 -0700
commit3024785b929cd8a740da87e1c24aef2c9b30e019 (patch)
tree4268d684d7707ce8b17a5781b8e8c82d1812c714 /src/runtime
parent741a19ab4197fb528f8d7f7d8a73d3db3ef99355 (diff)
downloadgo-3024785b929cd8a740da87e1c24aef2c9b30e019.tar.xz
cmd/compile,runtime: remember idx+len for bounds check failure with less code
Currently we must put the index and length into specific registers so we can call into the runtime to report a bounds check failure. So a typical bounds check call is something like: MOVD R3, R0 MOVD R7, R1 CALL runtime.panicIndex or, if for instance the index is constant, MOVD $7, R0 MOVD R9, R1 CALL runtime.panicIndex Sometimes the MOVD can be avoided, if the value happens to be in the right register already. But that's not terribly common, and doesn't work at all for constants. Let's get rid of those MOVD instructions. They pollute the instruction cache and are almost never executed. Instead, we'll encode in a PCDATA table where the runtime should find the index and length. The table encodes, for each index and length, whether it is a constant or in a register, and which register or constant it is. That way, we can avoid all those useless MOVDs. Instead, we can figure out the index and length at runtime. This makes the bounds panic path slower, but that's a good tradeoff. We can encode registers 0-15 and constants 0-31. Anything outside that range still needs to use an explicit instruction. This CL is the foundation, followon CLs will move each architecture to the new strategy. Change-Id: I705c511e546e6aac59fed922a8eaed4585e96820 Reviewed-on: https://go-review.googlesource.com/c/go/+/682396 Reviewed-by: Michael Knyszek <mknyszek@google.com> Reviewed-by: David Chase <drchase@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Diffstat (limited to 'src/runtime')
-rw-r--r--src/runtime/panic.go93
1 files changed, 93 insertions, 0 deletions
diff --git a/src/runtime/panic.go b/src/runtime/panic.go
index 0837b620e2..70e22836f2 100644
--- a/src/runtime/panic.go
+++ b/src/runtime/panic.go
@@ -225,6 +225,99 @@ func panicSlice3C(x int, y int)
func panicSlice3CU(x uint, y int)
func panicSliceConvert(x int, y int)
+func panicBounds() // in asm_GOARCH.s files, called from generated code
+func panicExtend() // in asm_GOARCH.s files, called from generated code (on 32-bit archs)
+func panicBounds64(pc uintptr, regs *[16]int64) { // called from panicBounds on 64-bit archs
+ f := findfunc(pc)
+ v := pcdatavalue(f, abi.PCDATA_PanicBounds, pc-1)
+
+ code, signed, xIsReg, yIsReg, xVal, yVal := abi.BoundsDecode(int(v))
+
+ if code == abi.BoundsIndex {
+ panicCheck1(pc, "index out of range")
+ } else {
+ panicCheck1(pc, "slice bounds out of range")
+ }
+
+ var e boundsError
+ e.code = code
+ e.signed = signed
+ if xIsReg {
+ e.x = regs[xVal]
+ } else {
+ e.x = int64(xVal)
+ }
+ if yIsReg {
+ e.y = int(regs[yVal])
+ } else {
+ e.y = yVal
+ }
+ panic(e)
+}
+
+func panicBounds32(pc uintptr, regs *[16]int32) { // called from panicBounds on 32-bit archs
+ f := findfunc(pc)
+ v := pcdatavalue(f, abi.PCDATA_PanicBounds, pc-1)
+
+ code, signed, xIsReg, yIsReg, xVal, yVal := abi.BoundsDecode(int(v))
+
+ if code == abi.BoundsIndex {
+ panicCheck1(pc, "index out of range")
+ } else {
+ panicCheck1(pc, "slice bounds out of range")
+ }
+
+ var e boundsError
+ e.code = code
+ e.signed = signed
+ if xIsReg {
+ if signed {
+ e.x = int64(regs[xVal])
+ } else {
+ e.x = int64(uint32(regs[xVal]))
+ }
+ } else {
+ e.x = int64(xVal)
+ }
+ if yIsReg {
+ e.y = int(regs[yVal])
+ } else {
+ e.y = yVal
+ }
+ panic(e)
+}
+
+func panicBounds32X(pc uintptr, regs *[16]int32) { // called from panicExtend on 32-bit archs
+ f := findfunc(pc)
+ v := pcdatavalue(f, abi.PCDATA_PanicBounds, pc-1)
+
+ code, signed, xIsReg, yIsReg, xVal, yVal := abi.BoundsDecode(int(v))
+
+ if code == abi.BoundsIndex {
+ panicCheck1(pc, "index out of range")
+ } else {
+ panicCheck1(pc, "slice bounds out of range")
+ }
+
+ var e boundsError
+ e.code = code
+ e.signed = signed
+ if xIsReg {
+ // Our 4-bit register numbers are actually 2 2-bit register numbers.
+ lo := xVal & 3
+ hi := xVal >> 2
+ e.x = int64(regs[hi])<<32 + int64(uint32(regs[lo]))
+ } else {
+ e.x = int64(xVal)
+ }
+ if yIsReg {
+ e.y = int(regs[yVal])
+ } else {
+ e.y = yVal
+ }
+ panic(e)
+}
+
var shiftError = error(errorString("negative shift amount"))
//go:yeswritebarrierrec