// Copyright 2025 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package abi // This type and constants are for encoding different // kinds of bounds check failures. type BoundsErrorCode uint8 const ( BoundsIndex BoundsErrorCode = iota // s[x], 0 <= x < len(s) failed BoundsSliceAlen // s[?:x], 0 <= x <= len(s) failed BoundsSliceAcap // s[?:x], 0 <= x <= cap(s) failed BoundsSliceB // s[x:y], 0 <= x <= y failed (but boundsSliceA didn't happen) BoundsSlice3Alen // s[?:?:x], 0 <= x <= len(s) failed BoundsSlice3Acap // s[?:?:x], 0 <= x <= cap(s) failed BoundsSlice3B // s[?:x:y], 0 <= x <= y failed (but boundsSlice3A didn't happen) BoundsSlice3C // s[x:y:?], 0 <= x <= y failed (but boundsSlice3A/B didn't happen) BoundsConvert // (*[x]T)(s), 0 <= x <= len(s) failed numBoundsCodes ) const ( BoundsMaxReg = 15 BoundsMaxConst = 31 ) // Here's how we encode PCDATA_PanicBounds entries: // We allow 16 registers (0-15) and 32 constants (0-31). // Encode the following constant c: // bits use // ----------------------------- // 0 x is in a register // 1 y is in a register // // if x is in a register // 2 x is signed // [3:6] x's register number // else // [2:6] x's constant value // // if y is in a register // [7:10] y's register number // else // [7:11] y's constant value // // The final integer is c * numBoundsCode + code // TODO: 32-bit // Encode bounds failure information into an integer for PCDATA_PanicBounds. // Register numbers must be in 0-15. Constants must be in 0-31. func BoundsEncode(code BoundsErrorCode, signed, xIsReg, yIsReg bool, xVal, yVal int) int { c := int(0) if xIsReg { c |= 1 << 0 if signed { c |= 1 << 2 } if xVal < 0 || xVal > BoundsMaxReg { panic("bad xReg") } c |= xVal << 3 } else { if xVal < 0 || xVal > BoundsMaxConst { panic("bad xConst") } c |= xVal << 2 } if yIsReg { c |= 1 << 1 if yVal < 0 || yVal > BoundsMaxReg { panic("bad yReg") } c |= yVal << 7 } else { if yVal < 0 || yVal > BoundsMaxConst { panic("bad yConst") } c |= yVal << 7 } return c*int(numBoundsCodes) + int(code) } func BoundsDecode(v int) (code BoundsErrorCode, signed, xIsReg, yIsReg bool, xVal, yVal int) { code = BoundsErrorCode(v % int(numBoundsCodes)) c := v / int(numBoundsCodes) xIsReg = c&1 != 0 c >>= 1 yIsReg = c&1 != 0 c >>= 1 if xIsReg { signed = c&1 != 0 c >>= 1 xVal = c & 0xf c >>= 4 } else { xVal = c & 0x1f c >>= 5 } if yIsReg { yVal = c & 0xf c >>= 4 } else { yVal = c & 0x1f c >>= 5 } if c != 0 { panic("BoundsDecode decoding error") } return }