cloudflared-mirror/vendor/zombiezen.com/go/capnproto2/rawpointer.go

190 lines
5.8 KiB
Go

package capnp
// pointerOffset is an address offset in multiples of word size.
type pointerOffset int32
// resolve returns an absolute address relative to a base address.
// For near pointers, the base is the end of the near pointer.
// For far pointers, the base is zero (the beginning of the segment).
func (off pointerOffset) resolve(base Address) (_ Address, ok bool) {
if off == 0 {
return base, true
}
addr := base + Address(off*pointerOffset(wordSize))
return addr, (addr > base || off < 0) && (addr < base || off > 0)
}
// nearPointerOffset computes the offset for a pointer at paddr to point to addr.
func nearPointerOffset(paddr, addr Address) pointerOffset {
return pointerOffset(addr/Address(wordSize) - paddr/Address(wordSize) - 1)
}
// rawPointer is an encoded pointer.
type rawPointer uint64
// rawStructPointer returns a struct pointer. The offset is from the
// end of the pointer to the start of the struct.
func rawStructPointer(off pointerOffset, sz ObjectSize) rawPointer {
return rawPointer(structPointer) | rawPointer(uint32(off)<<2) | rawPointer(sz.dataWordCount())<<32 | rawPointer(sz.PointerCount)<<48
}
// rawListPointer returns a list pointer. The offset is the number of
// words relative to the end of the pointer that the list starts. If
// listType is compositeList, then length is the number of words
// that the list occupies, otherwise it is the number of elements in
// the list.
func rawListPointer(off pointerOffset, listType listType, length int32) rawPointer {
return rawPointer(listPointer) | rawPointer(uint32(off)<<2) | rawPointer(listType)<<32 | rawPointer(length)<<35
}
// rawInterfacePointer returns an interface pointer that references
// a capability number.
func rawInterfacePointer(capability CapabilityID) rawPointer {
return rawPointer(otherPointer) | rawPointer(capability)<<32
}
// rawFarPointer returns a pointer to a pointer in another segment.
func rawFarPointer(segID SegmentID, off Address) rawPointer {
return rawPointer(farPointer) | rawPointer(off&^7) | (rawPointer(segID) << 32)
}
// rawDoubleFarPointer returns a pointer to a pointer in another segment.
func rawDoubleFarPointer(segID SegmentID, off Address) rawPointer {
return rawPointer(doubleFarPointer) | rawPointer(off&^7) | (rawPointer(segID) << 32)
}
// landingPadNearPointer converts a double-far pointer landing pad into
// a near pointer in the destination segment. Its offset will be
// relative to the beginning of the segment. tag must be either a
// struct or a list pointer.
func landingPadNearPointer(far, tag rawPointer) rawPointer {
// Replace tag's offset with far's offset.
// far's offset (29-bit unsigned) just needs to be shifted down to
// make it into a signed 30-bit value.
return tag&^0xfffffffc | rawPointer(uint32(far&^3)>>1)
}
type pointerType int
// Raw pointer types.
const (
structPointer pointerType = 0
listPointer pointerType = 1
farPointer pointerType = 2
doubleFarPointer pointerType = 6
otherPointer pointerType = 3
)
func (p rawPointer) pointerType() pointerType {
t := pointerType(p & 3)
if t == farPointer {
return pointerType(p & 7)
}
return t
}
func (p rawPointer) structSize() ObjectSize {
c := uint16(p >> 32)
d := uint16(p >> 48)
return ObjectSize{
DataSize: Size(c) * wordSize,
PointerCount: d,
}
}
type listType int
// Raw list pointer types.
const (
voidList listType = 0
bit1List listType = 1
byte1List listType = 2
byte2List listType = 3
byte4List listType = 4
byte8List listType = 5
pointerList listType = 6
compositeList listType = 7
)
func (p rawPointer) listType() listType {
return listType((p >> 32) & 7)
}
func (p rawPointer) numListElements() int32 {
return int32(p >> 35)
}
// elementSize returns the size of an individual element in the list referenced by p.
func (p rawPointer) elementSize() ObjectSize {
switch p.listType() {
case voidList:
return ObjectSize{}
case bit1List:
// Size is ignored on bit lists.
return ObjectSize{}
case byte1List:
return ObjectSize{DataSize: 1}
case byte2List:
return ObjectSize{DataSize: 2}
case byte4List:
return ObjectSize{DataSize: 4}
case byte8List:
return ObjectSize{DataSize: 8}
case pointerList:
return ObjectSize{PointerCount: 1}
default:
panic("elementSize not supposed to be called on composite or unknown list type")
}
}
// totalListSize returns the total size of the list referenced by p.
func (p rawPointer) totalListSize() (sz Size, ok bool) {
n := p.numListElements()
switch p.listType() {
case voidList:
return 0, true
case bit1List:
return Size((n + 7) / 8), true
case compositeList:
// For a composite list, n represents the number of words (excluding the tag word).
return wordSize.times(n + 1)
default:
return p.elementSize().totalSize().times(n)
}
}
// offset returns a pointer's offset. Only valid for struct or list
// pointers.
func (p rawPointer) offset() pointerOffset {
return pointerOffset(int32(p) >> 2)
}
// withOffset replaces a pointer's offset. Only valid for struct or
// list pointers.
func (p rawPointer) withOffset(off pointerOffset) rawPointer {
return p&^0xfffffffc | rawPointer(uint32(off<<2))
}
// farAddress returns the address of the landing pad pointer.
func (p rawPointer) farAddress() Address {
// Far pointer offset is 29 bits, starting after the low 3 bits.
// It's an unsigned word offset, which would be equivalent to a
// logical left shift by 3.
return Address(p) &^ 7
}
// farSegment returns the segment ID that the far pointer references.
func (p rawPointer) farSegment() SegmentID {
return SegmentID(p >> 32)
}
// otherPointerType returns the type of "other pointer" from p.
func (p rawPointer) otherPointerType() uint32 {
return uint32(p) >> 2
}
// capabilityIndex returns the index of the capability in the message's capability table.
func (p rawPointer) capabilityIndex() CapabilityID {
return CapabilityID(p >> 32)
}