From b3e93b704076820f2ca6c778f8725da7c587cfdf Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Sat, 6 Feb 2021 01:09:24 +0900 Subject: [PATCH] Enable Boundary Check Elimination by pointer arithmetic --- decode_context.go | 6 ++++++ decode_int.go | 7 ++++--- decode_string.go | 5 +++-- decode_struct.go | 30 ++++++++++++++++-------------- 4 files changed, 29 insertions(+), 19 deletions(-) diff --git a/decode_context.go b/decode_context.go index 23e0d3f..de02a37 100644 --- a/decode_context.go +++ b/decode_context.go @@ -1,5 +1,7 @@ package json +import "unsafe" + var ( isWhiteSpace = [256]bool{} ) @@ -11,6 +13,10 @@ func init() { isWhiteSpace['\r'] = true } +func char(ptr unsafe.Pointer, offset int64) byte { + return *(*byte)(unsafe.Pointer(uintptr(ptr) + uintptr(offset))) +} + func skipWhiteSpace(buf []byte, cursor int64) int64 { LOOP: if isWhiteSpace[buf[cursor]] { diff --git a/decode_int.go b/decode_int.go index fb0d3c7..b091812 100644 --- a/decode_int.go +++ b/decode_int.go @@ -130,8 +130,9 @@ ERROR: } func (d *intDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) { + b := (*sliceHeader)(unsafe.Pointer(&buf)).data for { - switch buf[cursor] { + switch char(b, cursor) { case ' ', '\n', '\t', '\r': cursor++ continue @@ -139,14 +140,14 @@ func (d *intDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, error) start := cursor cursor++ LOOP: - if numTable[buf[cursor]] { + if numTable[char(b, cursor)] { cursor++ goto LOOP } num := buf[start:cursor] return num, cursor, nil default: - return nil, 0, d.typeError([]byte{buf[cursor]}, cursor) + return nil, 0, d.typeError([]byte{char(b, cursor)}, cursor) } } } diff --git a/decode_string.go b/decode_string.go index a90f911..66412c9 100644 --- a/decode_string.go +++ b/decode_string.go @@ -249,11 +249,12 @@ func (d *stringDecoder) decodeByte(buf []byte, cursor int64) ([]byte, int64, err case '"': cursor++ start := cursor + b := (*sliceHeader)(unsafe.Pointer(&buf)).data for { - switch buf[cursor] { + switch char(b, cursor) { case '\\': cursor++ - switch buf[cursor] { + switch char(b, cursor) { case '"': buf[cursor] = '"' buf = append(buf[:cursor-1], buf[cursor:]...) diff --git a/decode_struct.go b/decode_struct.go index 5b12aec..414c673 100644 --- a/decode_struct.go +++ b/decode_struct.go @@ -120,13 +120,14 @@ func decodeKeyByBitmapInt8(d *structDecoder, buf []byte, cursor int64) (int64, * field *structFieldSet curBit int8 = math.MaxInt8 ) + b := (*sliceHeader)(unsafe.Pointer(&buf)).data for { - switch buf[cursor] { + switch char(b, cursor) { case ' ', '\n', '\t', '\r': cursor++ case '"': cursor++ - c := buf[cursor] + c := char(b, cursor) switch c { case '"': cursor++ @@ -138,7 +139,7 @@ func decodeKeyByBitmapInt8(d *structDecoder, buf []byte, cursor int64) (int64, * bitmap := d.keyBitmapInt8 keyBitmapLen := len(bitmap) for { - c := buf[cursor] + c := char(b, cursor) switch c { case '"': x := uint64(curBit & -curBit) @@ -152,13 +153,13 @@ func decodeKeyByBitmapInt8(d *structDecoder, buf []byte, cursor int64) (int64, * if keyIdx >= keyBitmapLen { for { cursor++ - switch buf[cursor] { + switch char(b, cursor) { case '"': cursor++ return cursor, field, nil case '\\': cursor++ - if buf[cursor] == nul { + if char(b, cursor) == nul { return 0, nil, errUnexpectedEndOfJSON("string", cursor) } case nul: @@ -170,13 +171,13 @@ func decodeKeyByBitmapInt8(d *structDecoder, buf []byte, cursor int64) (int64, * if curBit == 0 { for { cursor++ - switch buf[cursor] { + switch char(b, cursor) { case '"': cursor++ return cursor, field, nil case '\\': cursor++ - if buf[cursor] == nul { + if char(b, cursor) == nul { return 0, nil, errUnexpectedEndOfJSON("string", cursor) } case nul: @@ -199,13 +200,14 @@ func decodeKeyByBitmapInt16(d *structDecoder, buf []byte, cursor int64) (int64, field *structFieldSet curBit int16 = math.MaxInt16 ) + b := (*sliceHeader)(unsafe.Pointer(&buf)).data for { - switch buf[cursor] { + switch char(b, cursor) { case ' ', '\n', '\t', '\r': cursor++ case '"': cursor++ - c := buf[cursor] + c := char(b, cursor) switch c { case '"': cursor++ @@ -217,7 +219,7 @@ func decodeKeyByBitmapInt16(d *structDecoder, buf []byte, cursor int64) (int64, bitmap := d.keyBitmapInt16 keyBitmapLen := len(bitmap) for { - c := buf[cursor] + c := char(b, cursor) switch c { case '"': x := uint64(curBit & -curBit) @@ -231,13 +233,13 @@ func decodeKeyByBitmapInt16(d *structDecoder, buf []byte, cursor int64) (int64, if keyIdx >= keyBitmapLen { for { cursor++ - switch buf[cursor] { + switch char(b, cursor) { case '"': cursor++ return cursor, field, nil case '\\': cursor++ - if buf[cursor] == nul { + if char(b, cursor) == nul { return 0, nil, errUnexpectedEndOfJSON("string", cursor) } case nul: @@ -249,13 +251,13 @@ func decodeKeyByBitmapInt16(d *structDecoder, buf []byte, cursor int64) (int64, if curBit == 0 { for { cursor++ - switch buf[cursor] { + switch char(b, cursor) { case '"': cursor++ return cursor, field, nil case '\\': cursor++ - if buf[cursor] == nul { + if char(b, cursor) == nul { return 0, nil, errUnexpectedEndOfJSON("string", cursor) } case nul: