blob: d6859802d2e075b4056222376c5ae29030fb2b2b [file] [log] [blame]
// 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
}