Repository: bytedance/sonic
Pull request #205 (2022-03-19 06:13:15)

feat: support Go1.18
### Modifications:
loader
- `_ModHeader`&`_FindFuncBucket` changes to one instance per module instead of global one;
- `_ModHeader.magic` changes to 0xfffffff0;
- `_ModHeader.textStart`&`_ModuleData.text`&`_ModuleData.etext` adds physical text address;
- `_FuncTab.entryoff` changes to relative offset (int32) to `_ModuleData.text`;
- `_Func.argsptr/localsptr` changes to relative offset (int32) to `_ModuleData.gofunc` which is the smaller of them;


Patch:
diff --git a/.github/workflows/push-check-go118.yml b/.github/workflows/push-check-go118.yml
new file mode 100644
index 0000000..8519ef4
--- /dev/null
+++ b/.github/workflows/push-check-go118.yml
@@ -0,0 +1,27 @@
+name: Push Check Go1.18
+
+on: push
+
+jobs:
+  build:
+    runs-on: self-hosted
+    steps:
+      - uses: actions/checkout@v2
+
+      - name: Set up Go
+        uses: actions/setup-go@v2
+        with:
+          go-version: 1.18
+
+      - uses: actions/cache@v2
+        with:
+          path: ~/go/pkg/mod
+          key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
+          restore-keys: |
+            ${{ runner.os }}-go-
+
+      - name: Unit Test
+        run: GOMAXPROCS=4 go test -v -gcflags=-d=checkptr=0 -race -covermode=atomic -coverprofile=coverage.out ./...
+      
+      - name: Generic Test
+        run: go test -v -gcflags=-d=checkptr=0 -race -covermode=atomic ./generic_test
diff --git a/decoder/assembler_amd64_go117.go b/decoder/assembler_amd64_go117.go
index c153e08..194eddb 100644
--- a/decoder/assembler_amd64_go117.go
+++ b/decoder/assembler_amd64_go117.go
@@ -1,4 +1,4 @@
-// +build go1.17,!go1.18
+// +build go1.17,!go1.19
 
 /*
  * Copyright 2021 ByteDance Inc.
diff --git a/decoder/generic_amd64_go117.go b/decoder/generic_amd64_go117.go
index 093800d..c1576c9 100644
--- a/decoder/generic_amd64_go117.go
+++ b/decoder/generic_amd64_go117.go
@@ -1,4 +1,4 @@
-// +build go1.17,!go1.18
+// +build go1.17,!go1.19
 
 /*
  * Copyright 2021 ByteDance Inc.
diff --git a/encoder/assembler_amd64_go117.go b/encoder/assembler_amd64_go117.go
index 7339d77..7d59be5 100644
--- a/encoder/assembler_amd64_go117.go
+++ b/encoder/assembler_amd64_go117.go
@@ -1,4 +1,4 @@
-// +build go1.17,!go1.18
+// +build go1.17,!go1.19
 
 /*
  * Copyright 2021 ByteDance Inc.
diff --git a/encoder/stubs_go117.go b/encoder/stubs_go117.go
index 0d47bfc..14bf613 100644
--- a/encoder/stubs_go117.go
+++ b/encoder/stubs_go117.go
@@ -1,4 +1,4 @@
-// +build go1.17,!go1.18
+// +build go1.17,!go1.19
 
 /*
  * Copyright 2021 ByteDance Inc.
diff --git a/go.work b/go.work
new file mode 100644
index 0000000..54cfc12
--- /dev/null
+++ b/go.work
@@ -0,0 +1,6 @@
+go 1.18
+
+use (
+	.
+	./generic_test
+)
diff --git a/internal/loader/funcdata_go115.go b/internal/loader/funcdata_go115.go
index 48e400a..bd334de 100644
--- a/internal/loader/funcdata_go115.go
+++ b/internal/loader/funcdata_go115.go
@@ -98,7 +98,7 @@ var findFuncTab = &_FindFuncBucket {
     idx: 1,
 }
 
-func registerFunction(name string, pc uintptr, fp int, args int, size uintptr, argptrs uintptr, localptrs uintptr) {
+func registerFunction(name string, pc uintptr, textSize uintptr, fp int, args int, size uintptr, argptrs uintptr, localptrs uintptr) {
     minpc := pc
     maxpc := pc + size
 
diff --git a/internal/loader/funcdata_go116.go b/internal/loader/funcdata_go116.go
index 9d4821e..1316b64 100644
--- a/internal/loader/funcdata_go116.go
+++ b/internal/loader/funcdata_go116.go
@@ -126,7 +126,7 @@ func makePCtab(fp int) []byte {
     return append([]byte{0}, encodeVariant((fp + 1) << 1)...)
 }
 
-func registerFunction(name string, pc uintptr, fp int, args int, size uintptr, argptrs uintptr, localptrs uintptr) {
+func registerFunction(name string, pc uintptr, textSize uintptr, fp int, args int, size uintptr, argptrs uintptr, localptrs uintptr) {
     minpc := pc
     maxpc := pc + size
 
diff --git a/internal/loader/funcdata_go118.go b/internal/loader/funcdata_go118.go
new file mode 100644
index 0000000..07312fa
--- /dev/null
+++ b/internal/loader/funcdata_go118.go
@@ -0,0 +1,195 @@
+// +build go1.18,!go1.19
+
+/*
+ * Copyright 2021 ByteDance Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package loader
+
+import (
+    `unsafe`
+
+    `github.com/bytedance/sonic/internal/rt`
+)
+
+// A FuncFlag holds bits about a function.
+// This list must match the list in cmd/internal/objabi/funcid.go.
+type funcFlag uint8
+
+
+type _Func struct {
+    entryOff    uint32 // start pc
+    nameoff     int32   // function name
+    args        int32   // in/out args size
+    deferreturn uint32  // offset of start of a deferreturn call instruction from entry, if any.
+    pcsp        uint32
+    pcfile      uint32
+    pcln        uint32
+    npcdata     uint32
+    cuOffset    uint32  // runtime.cutab offset of this function's CU
+    funcID      uint8   // set for certain special runtime functions
+    flag        funcFlag
+    _           [1]byte // pad
+    nfuncdata   uint8   // must be last
+    argptrs     uint32
+    localptrs   uint32
+}
+
+type _FuncTab struct {
+    entry   uint32
+    funcoff uint32
+}
+
+type _PCHeader struct {
+    magic          uint32  // 0xFFFFFFF0
+    pad1, pad2     uint8   // 0,0
+    minLC          uint8   // min instruction size
+    ptrSize        uint8   // size of a ptr in bytes
+    nfunc          int     // number of functions in the module
+    nfiles         uint    // number of entries in the file tab
+    textStart      uintptr // base for function entry PC offsets in this module, equal to moduledata.text
+    funcnameOffset uintptr // offset to the funcnametab variable from pcHeader
+    cuOffset       uintptr // offset to the cutab variable from pcHeader
+    filetabOffset  uintptr // offset to the filetab variable from pcHeader
+    pctabOffset    uintptr // offset to the pctab variable from pcHeader
+    pclnOffset     uintptr // offset to the pclntab variable from pcHeader
+}
+
+type _BitVector struct {
+    n        int32 // # of bits
+    bytedata *uint8
+}
+
+type _PtabEntry struct {
+    name int32
+    typ  int32
+}
+
+type _TextSection struct {
+    vaddr    uintptr // prelinked section vaddr
+    length   uintptr // section length
+    baseaddr uintptr // relocated section address
+}
+
+type _ModuleData struct {
+    pcHeader              *_PCHeader
+    funcnametab           []byte
+    cutab                 []uint32
+    filetab               []byte
+    pctab                 []byte
+    pclntable             []byte
+    ftab                  []_FuncTab
+    findfunctab           *_FindFuncBucket
+    minpc, maxpc          uintptr
+    text, etext           uintptr
+    noptrdata, enoptrdata uintptr
+    data, edata           uintptr
+    bss, ebss             uintptr
+    noptrbss, enoptrbss   uintptr
+    end, gcdata, gcbss    uintptr
+    types, etypes         uintptr
+    rodata                uintptr
+    gofunc                uintptr 
+    textsectmap           []_TextSection
+    typelinks             []int32
+    itablinks             []unsafe.Pointer
+    ptab                  []_PtabEntry
+    pluginpath            string
+    pkghashes             []struct{}
+    modulename            string
+    modulehashes          []struct{}
+    hasmain               uint8
+    gcdatamask, gcbssmask _BitVector
+    typemap               map[int32]unsafe.Pointer
+    bad                   bool
+    next                  *_ModuleData
+}
+
+
+type _FindFuncBucket struct {
+    idx        uint32
+    subbuckets [16]byte
+}
+
+
+
+func makePCtab(fp int) []byte {
+    return append([]byte{0}, encodeVariant((fp + 1) << 1)...)
+}
+
+func registerFunction(name string, pc uintptr, textSize uintptr, fp int, args int, size uintptr, argptrs uintptr, localptrs uintptr) {
+    minpc := pc
+    maxpc := pc + size
+
+    findFuncTab := make([]_FindFuncBucket, textSize/4096 + 1)
+
+    modHeader := &_PCHeader {
+        magic   : 0xfffffff0,
+        minLC   : 1,
+        nfunc   : 1,
+        ptrSize : 4 << (^uintptr(0) >> 63),
+        textStart: minpc,
+    }
+
+    base := argptrs
+    if argptrs > localptrs {
+        base = localptrs
+    }
+
+    /* function entry */
+    lnt := []_Func {{
+        entryOff  : 0,
+        nameoff   : 1,
+        args      : int32(args),
+        pcsp      : 1,
+        nfuncdata : 2,
+        argptrs: uint32(argptrs - base),
+        localptrs: uint32(localptrs - base),
+    }}
+    nlnt := len(lnt)*int(unsafe.Sizeof(_Func{}))
+    plnt := unsafe.Pointer(&lnt[0])
+
+    /* function table */
+    ftab := []_FuncTab {
+        {entry   : 0, funcoff : 16},    
+        {entry   : uint32(size)},
+    }
+    nftab := len(ftab)*int(unsafe.Sizeof(_FuncTab{}))
+    pftab := unsafe.Pointer(&ftab[0])
+
+    pclntab := make([]byte, 0, nftab + nlnt)
+    pclntab = append(pclntab, rt.BytesFrom(pftab, nftab, nftab)...)
+    pclntab = append(pclntab, rt.BytesFrom(plnt, nlnt, nlnt)...)
+
+    /* module data */
+    mod := &_ModuleData {
+        pcHeader    : modHeader,
+        funcnametab : append(append([]byte{0}, name...), 0),
+        pctab       : append(makePCtab(fp), encodeVariant(int(size))...),
+        pclntable   : pclntab,
+        ftab        : ftab,
+        text        : minpc,
+        etext       : pc + textSize,
+        findfunctab : &findFuncTab[0],
+        minpc       : minpc,
+        maxpc       : maxpc,
+        modulename  : name,
+        gofunc: base,
+    }
+
+    /* verify and register the new module */
+    moduledataverify1(mod)
+    registerModule(mod)
+}
\ No newline at end of file
diff --git a/internal/loader/funcdata_invalid.go b/internal/loader/funcdata_invalid.go
index 81dfd86..4079217 100644
--- a/internal/loader/funcdata_invalid.go
+++ b/internal/loader/funcdata_invalid.go
@@ -1,4 +1,4 @@
-// +build !go1.15 go1.18
+// +build !go1.15 go1.19
 
 /*
  * Copyright 2021 ByteDance Inc.
@@ -20,7 +20,7 @@ package loader
 
 // triggers a compilation error
 const (
-	_ = panic("Unsupported Go version. Supported versions are: 1.15, 1.16, 1.17")
+	_ = panic("Unsupported Go version. Supported versions are: 1.15, 1.16, 1.17, 1.18")
 )
 
 func registerFunction(_ string, _ uintptr, _ int, _ int, _ uintptr) {
diff --git a/internal/loader/loader.go b/internal/loader/loader.go
index 326fc28..e1ec862 100644
--- a/internal/loader/loader.go
+++ b/internal/loader/loader.go
@@ -41,7 +41,7 @@ func (self Loader) LoadWithFaker(fn string, fp int, args int, faker interface{})
     m := mmap(n)
     v := fmt.Sprintf("runtime.__%s_%x", fn, m)
     argsptr, localsptr := stackMap(faker)
-    registerFunction(v, m, fp, args, uintptr(len(self)), argsptr, localsptr)
+    registerFunction(v, m, uintptr(n), fp, args, uintptr(len(self)), argsptr, localsptr)
 
     /* reference as a slice */
     s := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader {


Test patch:
diff --git a/decoder/assembler_test.go b/decoder/assembler_test.go
index f6ea883..69c7577 100644
--- a/decoder/assembler_test.go
+++ b/decoder/assembler_test.go
@@ -1,18 +1,18 @@
 /*
- * Copyright 2021 ByteDance Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+* Copyright 2021 ByteDance Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
 
 package decoder
 
@@ -72,9 +72,9 @@ func (self *UjsonStruct) UnmarshalJSON(v []byte) error {
 }
 
 const (
-	_OP_dbg_get_sr _Op = 253
-	_OP_dbg_set_sr _Op = 254
-	_OP_dbg_break  _Op = 255
+    _OP_dbg_get_sr _Op = 253
+    _OP_dbg_set_sr _Op = 254
+    _OP_dbg_break  _Op = 255
 )
 
 func (self *_Assembler) _asm_OP_dbg_get_sr(_ *_Instr) {
@@ -739,4 +739,4 @@ func TestAssembler_DecodeByteSlice_List(t *testing.T) {
     require.NoError(t, err)
     assert.Equal(t, len(s), pos)
     assert.Equal(t, []byte("hello, world"), v)
-}
+}
\ No newline at end of file
diff --git a/decoder/generic_amd64_go117_test.s b/decoder/generic_amd64_go117_test.s
index 3bbe900..cf73bf6 100644
--- a/decoder/generic_amd64_go117_test.s
+++ b/decoder/generic_amd64_go117_test.s
@@ -1,4 +1,4 @@
-// +build go1.17,!go1.18
+// +build go1.17,!go1.19
 
 //
 // Copyright 2021 ByteDance Inc.
diff --git a/generic_test/go.mod b/generic_test/go.mod
new file mode 100644
index 0000000..c8e8f50
--- /dev/null
+++ b/generic_test/go.mod
@@ -0,0 +1,13 @@
+module github.com/bytedance/sonic/generic_test
+
+go 1.18
+
+require (
+	github.com/bytedance/sonic v1.0.0
+	github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06 // indirect
+	github.com/klauspost/cpuid/v2 v2.0.9 // indirect
+	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
+	golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
+)
+
+replace github.com/bytedance/sonic => ../.
diff --git a/generic_test/go.sum b/generic_test/go.sum
new file mode 100644
index 0000000..9085190
--- /dev/null
+++ b/generic_test/go.sum
@@ -0,0 +1,39 @@
+github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06 h1:1sDoSuDPWzhkdzNVxCxtIaKiAe96ESVPv8coGwc1gZ4=
+github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/goccy/go-json v0.9.4 h1:L8MLKG2mvVXiQu07qB6hmfqeSYQdOnqPot2GhsIwIaI=
+github.com/goccy/go-json v0.9.4/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
+github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
+github.com/tidwall/gjson v1.13.0 h1:3TFY9yxOQShrvmjdM76K+jc66zJeT6D3/VFFYCGQf7M=
+github.com/tidwall/gjson v1.13.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
+github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
+github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
+github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
+github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
+github.com/tidwall/sjson v1.2.4 h1:cuiLzLnaMeBhRmEv00Lpk3tkYrcxpmbU81tAY4Dw0tc=
+github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp19pSNM=
+github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
+github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
+golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU=
+golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
diff --git a/generic_test/sonic_test.go b/generic_test/sonic_test.go
new file mode 100644
index 0000000..3ba5284
--- /dev/null
+++ b/generic_test/sonic_test.go
@@ -0,0 +1,160 @@
+// +build go1.18
+
+/*
+ * Copyright 2021 ByteDance Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package generic_test
+
+import (
+	`testing`
+    `reflect`
+    
+    `github.com/bytedance/sonic`
+	`github.com/bytedance/sonic/option`
+    `github.com/bytedance/sonic/ast`
+)
+
+type Str interface {
+    string
+}
+
+type Bytes interface {
+    []byte
+}
+
+type Any interface {
+    any
+}
+
+type SliceAny interface {
+    []any
+}
+
+func unmarshalAny[S Str, B Bytes, T Any](data S, val T) error {
+    return sonic.Unmarshal(B(data), val)
+}
+
+func marshalAny[B Bytes, T Any](val T) (B, error) {
+    return sonic.Marshal(val)
+}
+
+func getAny[S Str, B Bytes, T SliceAny](src S, path T) (ast.Node, error) {
+    return sonic.Get(B(src), path...)
+}
+
+func pretouchAny[T Any](v T, opts ...option.CompileOption) error {
+	rt := reflect.TypeOf(v)
+	return sonic.Pretouch(rt, opts...)
+}
+
+type Basic interface {
+    ~*int|~*float64|~float64|~*string
+}
+
+func unmarshalBasic[S Str, B Bytes, T Basic](data S, val T) error {
+    return sonic.Unmarshal(B(data), val)
+}
+
+func marshalBasic[B Bytes, T Basic](val T) (B, error) {
+    return sonic.Marshal(val)
+}
+
+func pretouchBasic[T Basic](v T, opts ...option.CompileOption) error {
+	rt := reflect.TypeOf(v)
+	return sonic.Pretouch(rt, opts...)
+}
+
+type Float64 float64
+
+func TestGenericAPI(t *testing.T) {
+    var x interface{}
+    if err := unmarshalAny(`{"a":[true,0.5,"hello world"]}`, &x); err != nil {
+        t.Fatal(t)
+    }
+    out, err := marshalAny(x)
+    if err != nil {
+        t.Fatal(err)
+    }
+	t.Logf("%s", out)
+	
+	var x0 = struct{
+		A []Any `json:"a"`
+	}{}
+	if err := pretouchAny(x0); err != nil {
+		t.Fatal(err)
+	}
+	if err := unmarshalAny(`{"a":[true,0.5,"hello world"]}`, &x0); err != nil {
+        t.Fatal(t)
+    }
+    out0, err := marshalAny(x0)
+    if err != nil {
+        t.Fatal(err)
+    }
+	t.Logf("%s", out0)
+
+    var x1 int
+    if err := unmarshalBasic(`1`, &x1); err != nil {
+        t.Fatal(t)
+    }
+    out1, err := marshalBasic(&x1)
+    if err != nil {
+        t.Fatal(err)
+    }
+    t.Logf("%s", out1)
+
+	var x2 Float64 = 1
+	// if err := unmarshalBasic(`1`, &x2); err != nil {
+    //     t.Fatal(t)
+    // }
+    out2, err := marshalBasic(x2)
+    if err != nil {
+        t.Fatal(err)
+    }
+    t.Logf("%s", out2)
+
+    var x3 string
+    if err := unmarshalBasic(`"1"`, &x3); err != nil {
+        t.Fatal(t)
+    }
+    out3, err := marshalBasic(&x3)
+    if err != nil {
+        t.Fatal(err)
+    }
+	t.Logf("%s", out3)
+
+	var x4 Float64 = 1
+	if err := pretouchBasic(x4); err != nil {
+		t.Fatal(err)
+	}
+	// if err := unmarshalBasic(`0.5`, &x4); err != nil {
+    //     t.Fatal(t)
+    // }
+    out4, err := marshalBasic(x4)
+    if err != nil {
+        t.Fatal(err)
+    }
+	t.Logf("%s", out4)
+
+    root, err := getAny(`{"a":[true,1,"hello world"]}`, []interface{}{"a", 1})
+    if err != nil {
+        t.Fatal(err)
+    }
+    f, err := root.Float64()
+    if err != nil {
+        t.Fatal(err)
+    }
+    t.Log(f)
+}
\ No newline at end of file
diff --git a/internal/loader/loader_go117_test.go b/internal/loader/loader_go117_test.go
index ce2767f..3908254 100644
--- a/internal/loader/loader_go117_test.go
+++ b/internal/loader/loader_go117_test.go
@@ -1,4 +1,4 @@
-// +build go1.17,!go1.18
+// +build go1.17,!go1.19
 
 /*
  * Copyright 2021 ByteDance Inc.