This is an automated email from the ASF dual-hosted git repository.
chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fory.git
The following commit(s) were added to refs/heads/main by this push:
new ed586af22 perf(go): remove //go:inline directives and mark cold paths
as //go:noinline (#3456)
ed586af22 is described below
commit ed586af222327bb2c3e7220832c991f211920005
Author: Ayush Kumar <[email protected]>
AuthorDate: Mon Mar 9 07:59:04 2026 +0530
perf(go): remove //go:inline directives and mark cold paths as
//go:noinline (#3456)
## Why?
//go:inline directives were introduced in the go runtime, expecting the
gc compiler would inline that specific function. But //go:inline isn't a
directive that is recognized by the gc compiler. gc compiler
automatically inlines a function which costs less than 80.
## What does this PR do?
1. Removes all occurrences of //go:inline.
2. Mark cold paths as //go:noinline.
## Related issues
Closes #3446
## Does this PR introduce any user-facing change?
- [ ] Does this PR introduce any public API change?
- [ ] Does this PR introduce any binary protocol compatibility change?
## Benchmark
main branch -
<img width="1114" height="811" alt="image"
src="https://github.com/user-attachments/assets/75f1dbea-7110-484b-8233-ac5599137cf6"
/>
this branch -
<img width="1114" height="811" alt="image"
src="https://github.com/user-attachments/assets/50d8b9cd-f4e9-48a0-a81d-36e47ac32947"
/>
---
go/fory/buffer.go | 128 ---------------------------------------------
go/fory/errors.go | 33 ++++++++++++
go/fory/fory.go | 23 ++++++++
go/fory/slice_primitive.go | 56 --------------------
4 files changed, 56 insertions(+), 184 deletions(-)
diff --git a/go/fory/buffer.go b/go/fory/buffer.go
index 70d2fc535..c51071fd1 100644
--- a/go/fory/buffer.go
+++ b/go/fory/buffer.go
@@ -110,8 +110,6 @@ func (b *ByteBuffer) fill(n int, errOut *Error) bool {
}
// grow ensures there's space for n more bytes. Hot path is inlined.
-//
-//go:inline
func (b *ByteBuffer) grow(n int) {
if b.writerIndex+n <= len(b.data) {
return // Fast path - single comparison, easily inlined
@@ -134,7 +132,6 @@ func (b *ByteBuffer) growSlow(n int) {
}
}
-//go:inline
func (b *ByteBuffer) WriteBool(value bool) {
b.grow(1)
// Branchless: directly convert bool to byte via unsafe
@@ -142,7 +139,6 @@ func (b *ByteBuffer) WriteBool(value bool) {
b.writerIndex++
}
-//go:inline
func (b *ByteBuffer) WriteByte(value byte) error {
b.grow(1)
b.data[b.writerIndex] = value
@@ -150,49 +146,42 @@ func (b *ByteBuffer) WriteByte(value byte) error {
return nil
}
-//go:inline
func (b *ByteBuffer) WriteByte_(value byte) {
b.grow(1)
b.data[b.writerIndex] = value
b.writerIndex++
}
-//go:inline
func (b *ByteBuffer) WriteInt8(value int8) {
b.grow(1)
b.data[b.writerIndex] = byte(value)
b.writerIndex++
}
-//go:inline
func (b *ByteBuffer) WriteUint8(value uint8) {
b.grow(1)
b.data[b.writerIndex] = value
b.writerIndex++
}
-//go:inline
func (b *ByteBuffer) WriteUint16(value uint16) {
b.grow(2)
binary.LittleEndian.PutUint16(b.data[b.writerIndex:], value)
b.writerIndex += 2
}
-//go:inline
func (b *ByteBuffer) WriteInt16(value int16) {
b.grow(2)
binary.LittleEndian.PutUint16(b.data[b.writerIndex:], uint16(value))
b.writerIndex += 2
}
-//go:inline
func (b *ByteBuffer) WriteUint32(value uint32) {
b.grow(4)
binary.LittleEndian.PutUint32(b.data[b.writerIndex:], value)
b.writerIndex += 4
}
-//go:inline
func (b *ByteBuffer) WriteInt32(value int32) {
b.grow(4)
binary.LittleEndian.PutUint32(b.data[b.writerIndex:], uint32(value))
@@ -211,28 +200,24 @@ func (b *ByteBuffer) ReadLength(err *Error) int {
return int(b.ReadVarUint32(err))
}
-//go:inline
func (b *ByteBuffer) WriteUint64(value uint64) {
b.grow(8)
binary.LittleEndian.PutUint64(b.data[b.writerIndex:], value)
b.writerIndex += 8
}
-//go:inline
func (b *ByteBuffer) WriteInt64(value int64) {
b.grow(8)
binary.LittleEndian.PutUint64(b.data[b.writerIndex:], uint64(value))
b.writerIndex += 8
}
-//go:inline
func (b *ByteBuffer) WriteFloat32(value float32) {
b.grow(4)
binary.LittleEndian.PutUint32(b.data[b.writerIndex:],
Float32bits(value))
b.writerIndex += 4
}
-//go:inline
func (b *ByteBuffer) WriteFloat64(value float64) {
b.grow(8)
binary.LittleEndian.PutUint64(b.data[b.writerIndex:],
Float64bits(value))
@@ -256,8 +241,6 @@ func (b *ByteBuffer) WriteBinary(p []byte) {
}
// ReadBool reads a bool and sets error on bounds violation
-//
-//go:inline
func (b *ByteBuffer) ReadBool(err *Error) bool {
if b.readerIndex+1 > len(b.data) {
if !b.fill(1, err) {
@@ -270,8 +253,6 @@ func (b *ByteBuffer) ReadBool(err *Error) bool {
}
// ReadByte reads a byte and sets error on bounds violation
-//
-//go:inline
func (b *ByteBuffer) ReadByte(err *Error) byte {
if b.readerIndex+1 > len(b.data) {
if !b.fill(1, err) {
@@ -284,8 +265,6 @@ func (b *ByteBuffer) ReadByte(err *Error) byte {
}
// ReadInt8 reads an int8 and sets error on bounds violation
-//
-//go:inline
func (b *ByteBuffer) ReadInt8(err *Error) int8 {
if b.readerIndex+1 > len(b.data) {
if !b.fill(1, err) {
@@ -298,8 +277,6 @@ func (b *ByteBuffer) ReadInt8(err *Error) int8 {
}
// ReadInt16 reads an int16 and sets error on bounds violation
-//
-//go:inline
func (b *ByteBuffer) ReadInt16(err *Error) int16 {
if b.readerIndex+2 > len(b.data) {
if !b.fill(2, err) {
@@ -312,8 +289,6 @@ func (b *ByteBuffer) ReadInt16(err *Error) int16 {
}
// ReadUint16 reads a uint16 and sets error on bounds violation
-//
-//go:inline
func (b *ByteBuffer) ReadUint16(err *Error) uint16 {
if b.readerIndex+2 > len(b.data) {
if !b.fill(2, err) {
@@ -326,8 +301,6 @@ func (b *ByteBuffer) ReadUint16(err *Error) uint16 {
}
// ReadUint32 reads a uint32 and sets error on bounds violation
-//
-//go:inline
func (b *ByteBuffer) ReadUint32(err *Error) uint32 {
if b.readerIndex+4 > len(b.data) {
if !b.fill(4, err) {
@@ -340,8 +313,6 @@ func (b *ByteBuffer) ReadUint32(err *Error) uint32 {
}
// ReadUint64 reads a uint64 and sets error on bounds violation
-//
-//go:inline
func (b *ByteBuffer) ReadUint64(err *Error) uint64 {
if b.readerIndex+8 > len(b.data) {
if !b.fill(8, err) {
@@ -354,29 +325,21 @@ func (b *ByteBuffer) ReadUint64(err *Error) uint64 {
}
// ReadInt32 reads an int32 and sets error on bounds violation
-//
-//go:inline
func (b *ByteBuffer) ReadInt32(err *Error) int32 {
return int32(b.ReadUint32(err))
}
// ReadInt64 reads an int64 and sets error on bounds violation
-//
-//go:inline
func (b *ByteBuffer) ReadInt64(err *Error) int64 {
return int64(b.ReadUint64(err))
}
// ReadFloat32 reads a float32 and sets error on bounds violation
-//
-//go:inline
func (b *ByteBuffer) ReadFloat32(err *Error) float32 {
return Float32frombits(b.ReadUint32(err))
}
// ReadFloat64 reads a float64 and sets error on bounds violation
-//
-//go:inline
func (b *ByteBuffer) ReadFloat64(err *Error) float64 {
return Float64frombits(b.ReadUint64(err))
}
@@ -427,12 +390,10 @@ func (b *ByteBuffer) ReadBinary(length int, err *Error)
[]byte {
return v
}
-//go:inline
func (b *ByteBuffer) GetData() []byte {
return b.data
}
-//go:inline
func (b *ByteBuffer) GetByteSlice(start, end int) []byte {
return b.data[start:end]
}
@@ -441,29 +402,23 @@ func (b *ByteBuffer) Slice(start, length int) *ByteBuffer
{
return NewByteBuffer(b.data[start : start+length])
}
-//go:inline
func (b *ByteBuffer) WriterIndex() int {
return b.writerIndex
}
// Bytes returns all written bytes from the buffer (from 0 to writerIndex).
-//
-//go:inline
func (b *ByteBuffer) Bytes() []byte {
return b.GetByteSlice(0, b.writerIndex)
}
-//go:inline
func (b *ByteBuffer) SetWriterIndex(index int) {
b.writerIndex = index
}
-//go:inline
func (b *ByteBuffer) ReaderIndex() int {
return b.readerIndex
}
-//go:inline
func (b *ByteBuffer) SetReaderIndex(index int) {
b.readerIndex = index
}
@@ -514,8 +469,6 @@ func (b *ByteBuffer) Reserve(n int) {
// UnsafeWriteVarint32 writes a varint32 without grow check.
// Caller must have called Reserve(5) beforehand.
-//
-//go:inline
func (b *ByteBuffer) UnsafeWriteVarint32(value int32) int8 {
u := uint32((value << 1) ^ (value >> 31))
return b.UnsafeWriteVarUint32(u)
@@ -586,16 +539,12 @@ func (b *ByteBuffer) UnsafeWriteVarUint32(value uint32)
int8 {
}
// UnsafeWriteByte writes a single byte without grow check.
-//
-//go:inline
func (b *ByteBuffer) UnsafeWriteByte(v byte) {
b.data[b.writerIndex] = v
b.writerIndex++
}
// UnsafeWriteInt16 writes an int16 without grow check.
-//
-//go:inline
func (b *ByteBuffer) UnsafeWriteInt16(v int16) {
if isLittleEndian {
*(*int16)(unsafe.Pointer(&b.data[b.writerIndex])) = v
@@ -606,8 +555,6 @@ func (b *ByteBuffer) UnsafeWriteInt16(v int16) {
}
// UnsafeWriteInt32 writes an int32 without grow check.
-//
-//go:inline
func (b *ByteBuffer) UnsafeWriteInt32(v int32) {
if isLittleEndian {
*(*int32)(unsafe.Pointer(&b.data[b.writerIndex])) = v
@@ -618,8 +565,6 @@ func (b *ByteBuffer) UnsafeWriteInt32(v int32) {
}
// UnsafeWriteInt64 writes an int64 without grow check.
-//
-//go:inline
func (b *ByteBuffer) UnsafeWriteInt64(v int64) {
if isLittleEndian {
*(*int64)(unsafe.Pointer(&b.data[b.writerIndex])) = v
@@ -630,8 +575,6 @@ func (b *ByteBuffer) UnsafeWriteInt64(v int64) {
}
// UnsafeReadInt32 reads an int32 without bounds check.
-//
-//go:inline
func (b *ByteBuffer) UnsafeReadInt32() int32 {
var v int32
if isLittleEndian {
@@ -644,8 +587,6 @@ func (b *ByteBuffer) UnsafeReadInt32() int32 {
}
// UnsafeReadInt64 reads an int64 without bounds check.
-//
-//go:inline
func (b *ByteBuffer) UnsafeReadInt64() int64 {
var v int64
if isLittleEndian {
@@ -658,8 +599,6 @@ func (b *ByteBuffer) UnsafeReadInt64() int64 {
}
// UnsafeReadUint32 reads a uint32 without bounds check.
-//
-//go:inline
func (b *ByteBuffer) UnsafeReadUint32() uint32 {
var v uint32
if isLittleEndian {
@@ -672,8 +611,6 @@ func (b *ByteBuffer) UnsafeReadUint32() uint32 {
}
// UnsafeReadUint64 reads a uint64 without bounds check.
-//
-//go:inline
func (b *ByteBuffer) UnsafeReadUint64() uint64 {
var v uint64
if isLittleEndian {
@@ -686,8 +623,6 @@ func (b *ByteBuffer) UnsafeReadUint64() uint64 {
}
// UnsafeWriteFloat32 writes a float32 without grow check.
-//
-//go:inline
func (b *ByteBuffer) UnsafeWriteFloat32(v float32) {
if isLittleEndian {
*(*float32)(unsafe.Pointer(&b.data[b.writerIndex])) = v
@@ -698,8 +633,6 @@ func (b *ByteBuffer) UnsafeWriteFloat32(v float32) {
}
// UnsafeWriteFloat64 writes a float64 without grow check.
-//
-//go:inline
func (b *ByteBuffer) UnsafeWriteFloat64(v float64) {
if isLittleEndian {
*(*float64)(unsafe.Pointer(&b.data[b.writerIndex])) = v
@@ -710,8 +643,6 @@ func (b *ByteBuffer) UnsafeWriteFloat64(v float64) {
}
// UnsafeWriteBool writes a bool without grow check.
-//
-//go:inline
func (b *ByteBuffer) UnsafeWriteBool(v bool) {
// Branchless: directly convert bool to byte via unsafe
b.data[b.writerIndex] = *(*byte)(unsafe.Pointer(&v))
@@ -721,8 +652,6 @@ func (b *ByteBuffer) UnsafeWriteBool(v bool) {
// UnsafePutVarInt32 writes a zigzag-encoded varint32 at the given offset
without advancing writerIndex.
// Caller must have called Reserve() to ensure capacity.
// Returns the number of bytes written (1-5).
-//
-//go:inline
func (b *ByteBuffer) UnsafePutVarInt32(offset int, value int32) int {
u := uint32((value << 1) ^ (value >> 31))
return b.UnsafePutVarUint32(offset, u)
@@ -787,8 +716,6 @@ func (b *ByteBuffer) UnsafePutVarUint32(offset int, value
uint32) int {
// UnsafePutVarInt64 writes a zigzag-encoded varint64 at the given offset
without advancing writerIndex.
// Caller must have called Reserve() to ensure capacity.
// Returns the number of bytes written (1-9).
-//
-//go:inline
func (b *ByteBuffer) UnsafePutVarInt64(offset int, value int64) int {
u := uint64((value << 1) ^ (value >> 63))
return b.UnsafePutVarUint64(offset, u)
@@ -914,7 +841,6 @@ func (b *ByteBuffer) UnsafePutVarUint64(offset int, value
uint64) int {
return 9
}
-//go:inline
func (b *ByteBuffer) PutInt32(index int, value int32) {
b.grow(4)
binary.LittleEndian.PutUint32(b.data[index:], uint32(value))
@@ -922,8 +848,6 @@ func (b *ByteBuffer) PutInt32(index int, value int32) {
// WriteVarUint32 writes a 1-5 byte positive int (no zigzag encoding), returns
the number of bytes written.
// Use this for lengths, type IDs, and other non-negative values.
-//
-//go:inline
func (b *ByteBuffer) WriteVarUint32(value uint32) int8 {
b.grow(8) // 8 bytes for bulk uint64 write in worst case
return b.UnsafeWriteVarUint32(value)
@@ -936,8 +860,6 @@ type BufferObject interface {
}
// WriteVarint64 writes the zig-zag encoded varint (compatible with Java's
writeVarint64).
-//
-//go:inline
func (b *ByteBuffer) WriteVarint64(value int64) {
u := uint64((value << 1) ^ (value >> 63))
b.WriteVarUint64(u)
@@ -999,8 +921,6 @@ func (b *ByteBuffer) WriteVaruint36Small(value uint64) {
// ReadVaruint36Small reads a varint optimized for small values (up to 36 bits)
// Used for string headers: (length << 2) | encoding
-//
-//go:inline
func (b *ByteBuffer) ReadVaruint36Small(err *Error) uint64 {
if b.remaining() >= 8 {
return b.readVaruint36SmallFast()
@@ -1008,7 +928,6 @@ func (b *ByteBuffer) ReadVaruint36Small(err *Error) uint64
{
return b.readVaruint36SmallSlow(err)
}
-//go:inline
func (b *ByteBuffer) readVaruint36SmallFast() uint64 {
// Single instruction load using unsafe pointer cast (little-endian
only)
// On big-endian systems, use binary.LittleEndian which the compiler
optimizes
@@ -1067,8 +986,6 @@ func (b *ByteBuffer) readVaruint36SmallSlow(err *Error)
uint64 {
}
// ReadVarint64 reads the varint encoded with zig-zag (compatible with Java's
readVarint64).
-//
-//go:inline
func (b *ByteBuffer) ReadVarint64(err *Error) int64 {
u := b.ReadVarUint64(err)
v := int64(u >> 1)
@@ -1186,8 +1103,6 @@ func (b *ByteBuffer) ReadTaggedUint64(err *Error) uint64 {
}
// ReadVarUint64 reads unsigned varint
-//
-//go:inline
func (b *ByteBuffer) ReadVarUint64(err *Error) uint64 {
if b.remaining() >= 9 {
return b.readVarUint64Fast()
@@ -1196,8 +1111,6 @@ func (b *ByteBuffer) ReadVarUint64(err *Error) uint64 {
}
// Fast path (when the remaining bytes are sufficient)
-//
-//go:inline
func (b *ByteBuffer) readVarUint64Fast() uint64 {
// Single instruction load using unsafe pointer cast (little-endian
only)
var bulk uint64
@@ -1277,15 +1190,11 @@ func (b *ByteBuffer) readVarUint64Slow(err *Error)
uint64 {
}
// Auxiliary function
-//
-//go:inline
func (b *ByteBuffer) remaining() int {
return len(b.data) - b.readerIndex
}
// ReadUint8 reads a uint8 and sets error on bounds violation
-//
-//go:inline
func (b *ByteBuffer) ReadUint8(err *Error) uint8 {
if b.readerIndex >= len(b.data) {
if !b.fill(1, err) {
@@ -1298,16 +1207,12 @@ func (b *ByteBuffer) ReadUint8(err *Error) uint8 {
}
// WriteVarint32 writes a signed int32 using zigzag encoding (compatible with
Java's writeVarint32).
-//
-//go:inline
func (b *ByteBuffer) WriteVarint32(value int32) int8 {
u := uint32((value << 1) ^ (value >> 31))
return b.WriteVarUint32(u)
}
// ReadVarint32 reads a signed int32 using zigzag decoding (compatible with
Java's readVarint32).
-//
-//go:inline
func (b *ByteBuffer) ReadVarint32(err *Error) int32 {
u := b.ReadVarUint32(err)
v := int32(u >> 1)
@@ -1319,8 +1224,6 @@ func (b *ByteBuffer) ReadVarint32(err *Error) int32 {
// UnsafeReadVarint32 reads a varint32 without bounds checking.
// Caller must ensure remaining() >= 5 before calling.
-//
-//go:inline
func (b *ByteBuffer) UnsafeReadVarint32() int32 {
u := b.readVarUint32Fast()
v := int32(u >> 1)
@@ -1332,8 +1235,6 @@ func (b *ByteBuffer) UnsafeReadVarint32() int32 {
// UnsafeReadVarint64 reads a varint64 without bounds checking.
// Caller must ensure remaining() >= 10 before calling.
-//
-//go:inline
func (b *ByteBuffer) UnsafeReadVarint64() int64 {
u := b.readVarUint64Fast()
v := int64(u >> 1)
@@ -1345,23 +1246,17 @@ func (b *ByteBuffer) UnsafeReadVarint64() int64 {
// UnsafeReadVarUint32 reads a VarUint32 without bounds checking.
// Caller must ensure remaining() >= 5 before calling.
-//
-//go:inline
func (b *ByteBuffer) UnsafeReadVarUint32() uint32 {
return b.readVarUint32Fast()
}
// UnsafeReadVarUint64 reads a VarUint64 without bounds checking.
// Caller must ensure remaining() >= 10 before calling.
-//
-//go:inline
func (b *ByteBuffer) UnsafeReadVarUint64() uint64 {
return b.readVarUint64Fast()
}
// ReadVarUint32 reads a VarUint32 and sets error on bounds violation
-//
-//go:inline
func (b *ByteBuffer) ReadVarUint32(err *Error) uint32 {
if b.remaining() >= 8 { // Need 8 bytes for bulk uint64 read in fast
path
return b.readVarUint32Fast()
@@ -1370,8 +1265,6 @@ func (b *ByteBuffer) ReadVarUint32(err *Error) uint32 {
}
// Fast path reading (when the remaining bytes are sufficient)
-//
-//go:inline
func (b *ByteBuffer) readVarUint32Fast() uint32 {
// Single instruction load using unsafe pointer cast (little-endian
only)
// On big-endian systems, use binary.LittleEndian which the compiler
optimizes
@@ -1430,7 +1323,6 @@ func (b *ByteBuffer) readVarUint32Slow(err *Error) uint32
{
return result
}
-//go:inline
func (b *ByteBuffer) PutUint8(writerIndex int, value uint8) {
b.data[writerIndex] = byte(value)
}
@@ -1479,12 +1371,10 @@ func (b *ByteBuffer) continuePutVarint36(index int,
encoded, value uint64) int {
return 5
}
-//go:inline
func (b *ByteBuffer) unsafePutInt32(index int, v int32) {
binary.LittleEndian.PutUint32(b.data[index:], uint32(v))
}
-//go:inline
func (b *ByteBuffer) unsafePutInt64(index int, v uint64) {
binary.LittleEndian.PutUint64(b.data[index:], v)
}
@@ -1492,8 +1382,6 @@ func (b *ByteBuffer) unsafePutInt64(index int, v uint64) {
// UnsafePutUint32 writes a uint32 at the given offset without advancing
writerIndex.
// Caller must have called Reserve() to ensure capacity.
// Returns the number of bytes written (4).
-//
-//go:inline
func (b *ByteBuffer) UnsafePutUint32(offset int, value uint32) int {
binary.LittleEndian.PutUint32(b.data[offset:], value)
return 4
@@ -1502,8 +1390,6 @@ func (b *ByteBuffer) UnsafePutUint32(offset int, value
uint32) int {
// UnsafePutUint64 writes a uint64 at the given offset without advancing
writerIndex.
// Caller must have called Reserve() to ensure capacity.
// Returns the number of bytes written (8).
-//
-//go:inline
func (b *ByteBuffer) UnsafePutUint64(offset int, value uint64) int {
binary.LittleEndian.PutUint64(b.data[offset:], value)
return 8
@@ -1512,8 +1398,6 @@ func (b *ByteBuffer) UnsafePutUint64(offset int, value
uint64) int {
// UnsafePutInt8 writes 1 byte at the given offset without bound checking.
// Caller must have ensured capacity.
// Returns the number of bytes written (1).
-//
-//go:inline
func (b *ByteBuffer) UnsafePutInt8(offset int, value int8) int {
b.data[offset] = byte(value)
return 1
@@ -1522,8 +1406,6 @@ func (b *ByteBuffer) UnsafePutInt8(offset int, value
int8) int {
// UnsafePutInt64 writes an int64 in little-endian format at the given offset
without bound checking.
// Caller must have ensured capacity.
// Returns the number of bytes written (8).
-//
-//go:inline
func (b *ByteBuffer) UnsafePutInt64(offset int, value int64) int {
binary.LittleEndian.PutUint64(b.data[offset:], uint64(value))
return 8
@@ -1532,8 +1414,6 @@ func (b *ByteBuffer) UnsafePutInt64(offset int, value
int64) int {
// UnsafePutTaggedInt64 writes int64 using tagged encoding at the given offset.
// Caller must have ensured capacity (9 bytes max).
// Returns the number of bytes written (4 or 9).
-//
-//go:inline
func (b *ByteBuffer) UnsafePutTaggedInt64(offset int, value int64) int {
const halfMinIntValue int64 = -1073741824 // INT32_MIN / 2
const halfMaxIntValue int64 = 1073741823 // INT32_MAX / 2
@@ -1553,8 +1433,6 @@ func (b *ByteBuffer) UnsafePutTaggedInt64(offset int,
value int64) int {
// UnsafePutTaggedUint64 writes uint64 using tagged encoding at the given
offset.
// Caller must have ensured capacity (9 bytes max).
// Returns the number of bytes written (4 or 9).
-//
-//go:inline
func (b *ByteBuffer) UnsafePutTaggedUint64(offset int, value uint64) int {
const maxSmallValue uint64 = 0x7fffffff // INT32_MAX as u64
if value <= maxSmallValue {
@@ -1647,15 +1525,11 @@ func (b *ByteBuffer) readVaruint36Slow(err *Error)
uint64 {
}
// unsafeGetInt32 reads little-endian int32 at index
-//
-//go:inline
func (b *ByteBuffer) unsafeGetInt32(idx int) int {
return int(int32(binary.LittleEndian.Uint32(b.data[idx:])))
}
// IncreaseReaderIndex advances readerIndex
-//
-//go:inline
func (b *ByteBuffer) IncreaseReaderIndex(n int) {
b.readerIndex += n
}
@@ -1693,8 +1567,6 @@ func (b *ByteBuffer) Skip(length int, err *Error) {
// CheckReadable ensures that at least n bytes are available to read.
// In stream mode, it will attempt to fill the buffer if necessary.
-//
-//go:inline
func (b *ByteBuffer) CheckReadable(n int, err *Error) bool {
if b.readerIndex+n > len(b.data) {
return b.fill(n, err)
diff --git a/go/fory/errors.go b/go/fory/errors.go
index 2e4f19e9a..25f7dd087 100644
--- a/go/fory/errors.go
+++ b/go/fory/errors.go
@@ -87,6 +87,7 @@ func parsePanicOnError() bool {
}
}
+//go:noinline
func panicIfEnabled(err Error) Error {
if panicOnError && err.kind != ErrKindOK {
panic(err.Error())
@@ -150,6 +151,8 @@ func (e Error) Error() string {
}
// BufferOutOfBoundError creates a buffer out of bound error
+//
+//go:noinline
func BufferOutOfBoundError(offset, need, size int) Error {
return panicIfEnabled(Error{
kind: ErrKindBufferOutOfBound,
@@ -160,6 +163,8 @@ func BufferOutOfBoundError(offset, need, size int) Error {
}
// TypeMismatchError creates a type mismatch error
+//
+//go:noinline
func TypeMismatchError(actual, expected TypeId) Error {
return panicIfEnabled(Error{
kind: ErrKindTypeMismatch,
@@ -169,6 +174,8 @@ func TypeMismatchError(actual, expected TypeId) Error {
}
// UnknownTypeError creates an unknown type error
+//
+//go:noinline
func UnknownTypeError(typeId TypeId) Error {
return panicIfEnabled(Error{
kind: ErrKindUnknownType,
@@ -178,6 +185,8 @@ func UnknownTypeError(typeId TypeId) Error {
}
// HashMismatchError creates a struct hash mismatch error
+//
+//go:noinline
func HashMismatchError(actual, expected int32, typeName string) Error {
return panicIfEnabled(Error{
kind: ErrKindHashMismatch,
@@ -188,6 +197,8 @@ func HashMismatchError(actual, expected int32, typeName
string) Error {
}
// SerializationError creates a general serialization error
+//
+//go:noinline
func SerializationError(msg string) Error {
return panicIfEnabled(Error{
kind: ErrKindSerializationFailed,
@@ -196,6 +207,8 @@ func SerializationError(msg string) Error {
}
// SerializationErrorf creates a formatted serialization error
+//
+//go:noinline
func SerializationErrorf(format string, args ...any) Error {
return panicIfEnabled(Error{
kind: ErrKindSerializationFailed,
@@ -204,6 +217,8 @@ func SerializationErrorf(format string, args ...any) Error {
}
// DeserializationError creates a general deserialization error
+//
+//go:noinline
func DeserializationError(msg string) Error {
return panicIfEnabled(Error{
kind: ErrKindDeserializationFailed,
@@ -212,6 +227,8 @@ func DeserializationError(msg string) Error {
}
// DeserializationErrorf creates a formatted deserialization error
+//
+//go:noinline
func DeserializationErrorf(format string, args ...any) Error {
return panicIfEnabled(Error{
kind: ErrKindDeserializationFailed,
@@ -220,6 +237,8 @@ func DeserializationErrorf(format string, args ...any)
Error {
}
// MaxDepthExceededError creates a max depth exceeded error
+//
+//go:noinline
func MaxDepthExceededError(depth int) Error {
return panicIfEnabled(Error{
kind: ErrKindMaxDepthExceeded,
@@ -228,6 +247,8 @@ func MaxDepthExceededError(depth int) Error {
}
// NilPointerError creates a nil pointer error
+//
+//go:noinline
func NilPointerError(msg string) Error {
return panicIfEnabled(Error{
kind: ErrKindNilPointer,
@@ -236,6 +257,8 @@ func NilPointerError(msg string) Error {
}
// InvalidRefIdError creates an invalid reference ID error
+//
+//go:noinline
func InvalidRefIdError(refId int32) Error {
return panicIfEnabled(Error{
kind: ErrKindInvalidRefId,
@@ -244,6 +267,8 @@ func InvalidRefIdError(refId int32) Error {
}
// InvalidTagError creates an invalid fory struct tag error
+//
+//go:noinline
func InvalidTagError(msg string) Error {
return panicIfEnabled(Error{
kind: ErrKindInvalidTag,
@@ -252,6 +277,8 @@ func InvalidTagError(msg string) Error {
}
// InvalidTagErrorf creates a formatted invalid fory struct tag error
+//
+//go:noinline
func InvalidTagErrorf(format string, args ...any) Error {
return panicIfEnabled(Error{
kind: ErrKindInvalidTag,
@@ -260,6 +287,8 @@ func InvalidTagErrorf(format string, args ...any) Error {
}
// InvalidUTF16StringError creates an invalid UTF-16 string error
+//
+//go:noinline
func InvalidUTF16StringError(byteCount int) Error {
return panicIfEnabled(Error{
kind: ErrKindInvalidUTF16String,
@@ -268,6 +297,8 @@ func InvalidUTF16StringError(byteCount int) Error {
}
// WrapError wraps a standard error into a fory Error
+//
+//go:noinline
func WrapError(err error, kind ErrorKind) Error {
if err == nil {
return Error{kind: ErrKindOK}
@@ -281,6 +312,8 @@ func WrapError(err error, kind ErrorKind) Error {
// FromError converts a standard error to a fory Error
// If err is already a fory Error, it returns it as-is
// Otherwise wraps it as a deserialization error
+//
+//go:noinline
func FromError(err error) Error {
if err == nil {
return Error{kind: ErrKindOK}
diff --git a/go/fory/fory.go b/go/fory/fory.go
index 09a0e3c6d..342b0acc3 100644
--- a/go/fory/fory.go
+++ b/go/fory/fory.go
@@ -180,6 +180,7 @@ func NewFory(opts ...Option) *Fory {
return New(opts...)
}
+//go:noinline
func validateUserTypeID(typeID uint32) error {
if typeID > maxUserTypeID {
return fmt.Errorf("typeID must be in range [0, 0xfffffffe], got
%d", typeID)
@@ -192,6 +193,8 @@ func validateUserTypeID(typeID uint32) error {
// type_ can be either a reflect.Type or an instance of the type
// typeID should be the user type ID in the range 0-0xfffffffe (0xffffffff is
reserved for "unset").
// Note: For enum types, use RegisterEnum instead.
+//
+//go:noinline
func (f *Fory) RegisterStruct(type_ any, typeID uint32) error {
if err := validateUserTypeID(typeID); err != nil {
return err
@@ -223,6 +226,8 @@ func (f *Fory) RegisterStruct(type_ any, typeID uint32)
error {
// type_ can be either a reflect.Type or an instance of the union type.
// typeID should be the user type ID in the range 0-0xfffffffe (0xffffffff is
reserved for "unset").
// serializer must implement union payload encoding/decoding.
+//
+//go:noinline
func (f *Fory) RegisterUnion(type_ any, typeID uint32, serializer Serializer)
error {
if serializer == nil {
return fmt.Errorf("RegisterUnion requires a non-nil serializer")
@@ -248,6 +253,8 @@ func (f *Fory) RegisterUnion(type_ any, typeID uint32,
serializer Serializer) er
// RegisterNamedUnion registers a union type with a namespace + type name for
cross-language serialization.
// type_ can be either a reflect.Type or an instance of the union type.
// serializer must implement union payload encoding/decoding.
+//
+//go:noinline
func (f *Fory) RegisterNamedUnion(type_ any, typeName string, serializer
Serializer) error {
if serializer == nil {
return fmt.Errorf("RegisterNamedUnion requires a non-nil
serializer")
@@ -277,6 +284,8 @@ func (f *Fory) RegisterNamedUnion(type_ any, typeName
string, serializer Seriali
// type_ can be either a reflect.Type or an instance of the type
// typeName can include a namespace prefix separated by "." (e.g.,
"example.Foo")
// Note: For enum types, use RegisterNamedEnum instead.
+//
+//go:noinline
func (f *Fory) RegisterNamedStruct(type_ any, typeName string) error {
var t reflect.Type
if rt, ok := type_.(reflect.Type); ok {
@@ -305,6 +314,8 @@ func (f *Fory) RegisterNamedStruct(type_ any, typeName
string) error {
// This method creates an enum serializer that writes/reads the enum value as
VarUint32Small7.
// type_ can be either a reflect.Type or an instance of the enum type
// typeID should be the user type ID in the range 0-0xfffffffe (0xffffffff is
reserved for "unset").
+//
+//go:noinline
func (f *Fory) RegisterEnum(type_ any, typeID uint32) error {
if err := validateUserTypeID(typeID); err != nil {
return err
@@ -335,6 +346,8 @@ func (f *Fory) RegisterEnum(type_ any, typeID uint32) error
{
// In Go, enums are typically defined as int-based types (e.g., type Color
int32).
// type_ can be either a reflect.Type or an instance of the enum type
// typeName can include a namespace prefix separated by "." (e.g.,
"example.Color")
+//
+//go:noinline
func (f *Fory) RegisterNamedEnum(type_ any, typeName string) error {
var t reflect.Type
if rt, ok := type_.(reflect.Type); ok {
@@ -368,6 +381,8 @@ func (f *Fory) RegisterNamedEnum(type_ any, typeName
string) error {
// RegisterExtension registers a type as an extension type with a numeric ID.
// Extension types use a custom serializer provided by the user.
// typeID should be the user type ID in the range 0-0xfffffffe (0xffffffff is
reserved for "unset").
+//
+//go:noinline
func (f *Fory) RegisterExtension(type_ any, typeID uint32, serializer
ExtensionSerializer) error {
if err := validateUserTypeID(typeID); err != nil {
return err
@@ -405,6 +420,8 @@ func (f *Fory) RegisterExtension(type_ any, typeID uint32,
serializer ExtensionS
//
// // Register with custom serializer
// f.RegisterNamedExtension(MyExt{}, "my_ext", &MyExtSerializer{})
+//
+//go:noinline
func (f *Fory) RegisterNamedExtension(type_ any, typeName string, serializer
ExtensionSerializer) error {
var t reflect.Type
if rt, ok := type_.(reflect.Type); ok {
@@ -724,6 +741,8 @@ func (f *Fory) DeserializeWithCallbackBuffers(buffer
*ByteBuffer, v any, buffers
// serializeReflectValue serializes a reflect.Value directly, avoiding boxing
overhead.
// This is used by Serialize[T] fallback path to avoid struct copy.
// For structs, the value must be a pointer to struct, not struct value.
+//
+//go:noinline
func (f *Fory) serializeReflectValue(value reflect.Value) ([]byte, error) {
// Check that structs are passed as pointers
if value.Kind() == reflect.Struct {
@@ -757,6 +776,8 @@ func writeHeader(ctx *WriteContext, config Config) {
// isNilValue checks if a value is nil, including nil pointers wrapped in any
// In Go, `*int32(nil)` wrapped in `any` is NOT equal to `nil`, but we need to
treat it as null.
+//
+//go:noinline
func isNilValue(value any) bool {
if value == nil {
return true
@@ -771,6 +792,8 @@ func isNilValue(value any) bool {
// writeNullHeader writes a null object header (1 byte: bitmap with isNilFlag)
// This is compatible with Java's null serialization format
+//
+//go:noinline
func writeNullHeader(ctx *WriteContext) {
ctx.buffer.WriteByte_(IsNilFlag) // bitmap with only isNilFlag set
}
diff --git a/go/fory/slice_primitive.go b/go/fory/slice_primitive.go
index e4daf990b..c89390898 100644
--- a/go/fory/slice_primitive.go
+++ b/go/fory/slice_primitive.go
@@ -682,8 +682,6 @@ func (s stringSliceSerializer) ReadData(ctx *ReadContext,
value reflect.Value) {
// ============================================================================
// WriteByteSlice writes []byte to buffer using ARRAY protocol
-//
-//go:inline
func WriteByteSlice(buf *ByteBuffer, value []byte) {
buf.WriteLength(len(value))
if len(value) > 0 {
@@ -692,8 +690,6 @@ func WriteByteSlice(buf *ByteBuffer, value []byte) {
}
// ReadByteSlice reads []byte from buffer using ARRAY protocol
-//
-//go:inline
func ReadByteSlice(buf *ByteBuffer, err *Error) []byte {
size := buf.ReadLength(err)
if size == 0 {
@@ -706,8 +702,6 @@ func ReadByteSlice(buf *ByteBuffer, err *Error) []byte {
}
// WriteBoolSlice writes []bool to buffer using ARRAY protocol
-//
-//go:inline
func WriteBoolSlice(buf *ByteBuffer, value []bool) {
size := len(value)
buf.WriteLength(size)
@@ -717,8 +711,6 @@ func WriteBoolSlice(buf *ByteBuffer, value []bool) {
}
// ReadBoolSlice reads []bool from buffer using ARRAY protocol
-//
-//go:inline
func ReadBoolSlice(buf *ByteBuffer, err *Error) []bool {
size := buf.ReadLength(err)
if size == 0 {
@@ -731,8 +723,6 @@ func ReadBoolSlice(buf *ByteBuffer, err *Error) []bool {
}
// WriteInt8Slice writes []int8 to buffer using ARRAY protocol
-//
-//go:inline
func WriteInt8Slice(buf *ByteBuffer, value []int8) {
size := len(value)
buf.WriteLength(size)
@@ -742,8 +732,6 @@ func WriteInt8Slice(buf *ByteBuffer, value []int8) {
}
// ReadInt8Slice reads []int8 from buffer using ARRAY protocol
-//
-//go:inline
func ReadInt8Slice(buf *ByteBuffer, err *Error) []int8 {
size := buf.ReadLength(err)
if size == 0 {
@@ -756,8 +744,6 @@ func ReadInt8Slice(buf *ByteBuffer, err *Error) []int8 {
}
// WriteInt16Slice writes []int16 to buffer using ARRAY protocol
-//
-//go:inline
func WriteInt16Slice(buf *ByteBuffer, value []int16) {
size := len(value) * 2
buf.WriteLength(size)
@@ -773,8 +759,6 @@ func WriteInt16Slice(buf *ByteBuffer, value []int16) {
}
// ReadInt16Slice reads []int16 from buffer using ARRAY protocol
-//
-//go:inline
func ReadInt16Slice(buf *ByteBuffer, err *Error) []int16 {
size := buf.ReadLength(err)
length := size / 2
@@ -794,8 +778,6 @@ func ReadInt16Slice(buf *ByteBuffer, err *Error) []int16 {
}
// WriteInt32Slice writes []int32 to buffer using ARRAY protocol
-//
-//go:inline
func WriteInt32Slice(buf *ByteBuffer, value []int32) {
size := len(value) * 4
buf.WriteLength(size)
@@ -811,8 +793,6 @@ func WriteInt32Slice(buf *ByteBuffer, value []int32) {
}
// ReadInt32Slice reads []int32 from buffer using ARRAY protocol
-//
-//go:inline
func ReadInt32Slice(buf *ByteBuffer, err *Error) []int32 {
size := buf.ReadLength(err)
length := size / 4
@@ -832,8 +812,6 @@ func ReadInt32Slice(buf *ByteBuffer, err *Error) []int32 {
}
// WriteInt64Slice writes []int64 to buffer using ARRAY protocol
-//
-//go:inline
func WriteInt64Slice(buf *ByteBuffer, value []int64) {
size := len(value) * 8
buf.WriteLength(size)
@@ -849,8 +827,6 @@ func WriteInt64Slice(buf *ByteBuffer, value []int64) {
}
// ReadInt64Slice reads []int64 from buffer using ARRAY protocol
-//
-//go:inline
func ReadInt64Slice(buf *ByteBuffer, err *Error) []int64 {
size := buf.ReadLength(err)
length := size / 8
@@ -870,8 +846,6 @@ func ReadInt64Slice(buf *ByteBuffer, err *Error) []int64 {
}
// WriteUint16Slice writes []uint16 to buffer using ARRAY protocol
-//
-//go:inline
func WriteUint16Slice(buf *ByteBuffer, value []uint16) {
size := len(value) * 2
buf.WriteLength(size)
@@ -887,8 +861,6 @@ func WriteUint16Slice(buf *ByteBuffer, value []uint16) {
}
// ReadUint16Slice reads []uint16 from buffer using ARRAY protocol
-//
-//go:inline
func ReadUint16Slice(buf *ByteBuffer, err *Error) []uint16 {
size := buf.ReadLength(err)
length := size / 2
@@ -908,8 +880,6 @@ func ReadUint16Slice(buf *ByteBuffer, err *Error) []uint16 {
}
// WriteUint32Slice writes []uint32 to buffer using ARRAY protocol
-//
-//go:inline
func WriteUint32Slice(buf *ByteBuffer, value []uint32) {
size := len(value) * 4
buf.WriteLength(size)
@@ -925,8 +895,6 @@ func WriteUint32Slice(buf *ByteBuffer, value []uint32) {
}
// ReadUint32Slice reads []uint32 from buffer using ARRAY protocol
-//
-//go:inline
func ReadUint32Slice(buf *ByteBuffer, err *Error) []uint32 {
size := buf.ReadLength(err)
length := size / 4
@@ -946,8 +914,6 @@ func ReadUint32Slice(buf *ByteBuffer, err *Error) []uint32 {
}
// WriteUint64Slice writes []uint64 to buffer using ARRAY protocol
-//
-//go:inline
func WriteUint64Slice(buf *ByteBuffer, value []uint64) {
size := len(value) * 8
buf.WriteLength(size)
@@ -963,8 +929,6 @@ func WriteUint64Slice(buf *ByteBuffer, value []uint64) {
}
// ReadUint64Slice reads []uint64 from buffer using ARRAY protocol
-//
-//go:inline
func ReadUint64Slice(buf *ByteBuffer, err *Error) []uint64 {
size := buf.ReadLength(err)
length := size / 8
@@ -984,8 +948,6 @@ func ReadUint64Slice(buf *ByteBuffer, err *Error) []uint64 {
}
// WriteFloat32Slice writes []float32 to buffer using ARRAY protocol
-//
-//go:inline
func WriteFloat32Slice(buf *ByteBuffer, value []float32) {
size := len(value) * 4
buf.WriteLength(size)
@@ -1001,8 +963,6 @@ func WriteFloat32Slice(buf *ByteBuffer, value []float32) {
}
// ReadFloat32Slice reads []float32 from buffer using ARRAY protocol
-//
-//go:inline
func ReadFloat32Slice(buf *ByteBuffer, err *Error) []float32 {
size := buf.ReadLength(err)
length := size / 4
@@ -1022,8 +982,6 @@ func ReadFloat32Slice(buf *ByteBuffer, err *Error)
[]float32 {
}
// WriteFloat64Slice writes []float64 to buffer using ARRAY protocol
-//
-//go:inline
func WriteFloat64Slice(buf *ByteBuffer, value []float64) {
size := len(value) * 8
buf.WriteLength(size)
@@ -1039,8 +997,6 @@ func WriteFloat64Slice(buf *ByteBuffer, value []float64) {
}
// ReadFloat64Slice reads []float64 from buffer using ARRAY protocol
-//
-//go:inline
func ReadFloat64Slice(buf *ByteBuffer, err *Error) []float64 {
size := buf.ReadLength(err)
length := size / 8
@@ -1145,8 +1101,6 @@ func (s float16SliceSerializer) ReadData(ctx
*ReadContext, value reflect.Value)
}
// WriteIntSlice writes []int to buffer using ARRAY protocol
-//
-//go:inline
func WriteIntSlice(buf *ByteBuffer, value []int) {
if strconv.IntSize == 64 {
size := len(value) * 8
@@ -1176,8 +1130,6 @@ func WriteIntSlice(buf *ByteBuffer, value []int) {
}
// ReadIntSlice reads []int from buffer using ARRAY protocol
-//
-//go:inline
func ReadIntSlice(buf *ByteBuffer, err *Error) []int {
size := buf.ReadLength(err)
if strconv.IntSize == 64 {
@@ -1214,8 +1166,6 @@ func ReadIntSlice(buf *ByteBuffer, err *Error) []int {
}
// WriteUintSlice writes []uint to buffer using ARRAY protocol
-//
-//go:inline
func WriteUintSlice(buf *ByteBuffer, value []uint) {
if strconv.IntSize == 64 {
size := len(value) * 8
@@ -1245,8 +1195,6 @@ func WriteUintSlice(buf *ByteBuffer, value []uint) {
}
// ReadUintSlice reads []uint from buffer using ARRAY protocol
-//
-//go:inline
func ReadUintSlice(buf *ByteBuffer, err *Error) []uint {
size := buf.ReadLength(err)
if strconv.IntSize == 64 {
@@ -1285,8 +1233,6 @@ func ReadUintSlice(buf *ByteBuffer, err *Error) []uint {
// WriteStringSlice writes []string to buffer using LIST protocol.
// When hasGenerics is true (element type known from TypeDef/generics), uses
IS_DECL_ELEMENT_TYPE
// and doesn't write element type ID. When false, writes element type ID.
-//
-//go:inline
func WriteStringSlice(buf *ByteBuffer, value []string, hasGenerics bool) {
length := len(value)
buf.WriteVarUint32(uint32(length))
@@ -1306,8 +1252,6 @@ func WriteStringSlice(buf *ByteBuffer, value []string,
hasGenerics bool) {
}
// ReadStringSlice reads []string from buffer using LIST protocol
-//
-//go:inline
func ReadStringSlice(buf *ByteBuffer, err *Error) []string {
length := int(buf.ReadVarUint32(err))
if length == 0 {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]