2
0
Fork 0
mirror of https://github.com/ii64/sonic.git synced 2026-06-20 16:45:22 +08:00

fix: relocate stack pointers (#156)

* fix: relocate stack pointer _VAR_sv to keep it alive

* fix: add stack pointer _VAR_vk to defend `encoding.TextUnmarshaler`

* fix: align faker func's stack with JIT func's

* fix: clear _Stack memory when err returned

* fix: clear stack pointer before return

* fix: relimit stack-overflow check at `_ValueDecoder`

Co-authored-by: duanyi.aster <duanyi.aster@bytedance.com>
This commit is contained in:
Yi Duan 2021-12-20 16:19:12 +08:00 committed by GitHub
parent e80837a84d
commit 22229eefc3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 242 additions and 149 deletions

View file

@ -20,10 +20,5 @@ jobs:
restore-keys: |
${{ runner.os }}-go-
- name: Check License Header
uses: apache/skywalking-eyes@main
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Unit Test
run: go test -v -race -covermode=atomic -coverprofile=coverage.out ./...

View file

@ -26,4 +26,4 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Unit Test
run: go test -v -covermode=atomic -coverprofile=coverage.out ./...
run: go test -v -race -covermode=atomic -coverprofile=coverage.out ./...

View file

@ -18,7 +18,6 @@ package ast
import (
`runtime`
`runtime/debug`
`sync`
`testing`
@ -57,7 +56,6 @@ func TestGC_Encode(t *testing.T) {
t.Fatal(err)
}
runtime.GC()
debug.FreeOSMemory()
}(wg)
}
wg.Wait()

View file

@ -20,6 +20,7 @@ import (
`os`
`encoding/json`
`testing`
`time`
`runtime`
`runtime/debug`
`sync`
@ -46,6 +47,7 @@ func TestMain(m *testing.M) {
}
println("stop GC looping!")
}()
time.Sleep(time.Millisecond)
m.Run()
}
@ -68,7 +70,6 @@ func TestGC_Parse(t *testing.T) {
t.Fatal(err)
}
runtime.GC()
debug.FreeOSMemory()
}(wg)
}
wg.Wait()

View file

@ -19,7 +19,6 @@ package ast
import (
`testing`
`runtime`
`runtime/debug`
`sync`
`fmt`
`math`
@ -53,7 +52,6 @@ func TestGC_Search(t *testing.T) {
t.Fatal(err)
}
runtime.GC()
debug.FreeOSMemory()
}(wg)
}
wg.Wait()

View file

@ -2345,7 +2345,7 @@ func TestUnmarshalMaxDepth(t *testing.T) {
}{
{
name: "ArrayUnderMaxNestingDepth",
data: `{"a":` + strings.Repeat(`[`, 65535) + `0` + strings.Repeat(`]`, 65535) + `}`,
data: `{"a":` + strings.Repeat(`[`, 65534) + `0` + strings.Repeat(`]`, 65534) + `}`,
errMaxDepth: false,
},
{

View file

@ -52,7 +52,7 @@
/** Function Prototype & Stack Map
*
* func (s string, ic int, vp unsafe.Pointer, sb *_Stack, fv uint64) (rc int, err error)
* func (s string, ic int, vp unsafe.Pointer, sb *_Stack, fv uint64, sv string) (rc int, err error)
*
* s.buf : (FP)
* s.len : 8(FP)
@ -61,15 +61,16 @@
* sb : 32(FP)
* fv : 40(FP)
* rc : 48(FP)
* err.vt : 56(FP)
* err.vp : 64(FP)
* sv : 56(FP)
* err.vt : 72(FP)
* err.vp : 80(FP)
*/
const (
_FP_args = 72 // 72 bytes to pass arguments and return values for this function
_FP_args = 96 // 96 bytes to pass arguments and return values for this function
_FP_fargs = 80 // 80 bytes for passing arguments to other Go functions
_FP_saves = 40 // 40 bytes for saving the registers before CALL instructions
_FP_locals = 96 // 96 bytes for local variables
_FP_locals = 72 // 72 bytes for local variables
)
const (
@ -151,35 +152,36 @@
)
var (
_RET_rc = jit.Ptr(_SP, _FP_base + 48)
_RET_et = jit.Ptr(_SP, _FP_base + 56)
_RET_ep = jit.Ptr(_SP, _FP_base + 64)
_VAR_sv = _VAR_sv_p
_VAR_sv_p = jit.Ptr(_SP, _FP_base + 48)
_VAR_sv_n = jit.Ptr(_SP, _FP_base + 56)
_VAR_vk = jit.Ptr(_SP, _FP_base + 64)
)
var (
_VAR_sv = _VAR_sv_p
_RET_rc = jit.Ptr(_SP, _FP_base + 72)
_RET_et = jit.Ptr(_SP, _FP_base + 80)
_RET_ep = jit.Ptr(_SP, _FP_base + 88)
)
var (
_VAR_st = _VAR_st_Vt
_VAR_sr = jit.Ptr(_SP, _FP_fargs + _FP_saves)
)
var (
_VAR_sv_p = jit.Ptr(_SP, _FP_fargs + _FP_saves + 8)
_VAR_sv_n = jit.Ptr(_SP, _FP_fargs + _FP_saves + 16)
_VAR_st_Vt = jit.Ptr(_SP, _FP_fargs + _FP_saves + 0)
_VAR_st_Dv = jit.Ptr(_SP, _FP_fargs + _FP_saves + 8)
_VAR_st_Iv = jit.Ptr(_SP, _FP_fargs + _FP_saves + 16)
_VAR_st_Ep = jit.Ptr(_SP, _FP_fargs + _FP_saves + 24)
)
var (
_VAR_st_Vt = jit.Ptr(_SP, _FP_fargs + _FP_saves + 24)
_VAR_st_Dv = jit.Ptr(_SP, _FP_fargs + _FP_saves + 32)
_VAR_st_Iv = jit.Ptr(_SP, _FP_fargs + _FP_saves + 40)
_VAR_st_Ep = jit.Ptr(_SP, _FP_fargs + _FP_saves + 48)
)
var (
_VAR_ss_AX = jit.Ptr(_SP, _FP_fargs + _FP_saves + 56)
_VAR_ss_CX = jit.Ptr(_SP, _FP_fargs + _FP_saves + 64)
_VAR_ss_SI = jit.Ptr(_SP, _FP_fargs + _FP_saves + 72)
_VAR_ss_R8 = jit.Ptr(_SP, _FP_fargs + _FP_saves + 80)
_VAR_ss_R9 = jit.Ptr(_SP, _FP_fargs + _FP_saves + 88)
_VAR_ss_AX = jit.Ptr(_SP, _FP_fargs + _FP_saves + 32)
_VAR_ss_CX = jit.Ptr(_SP, _FP_fargs + _FP_saves + 40)
_VAR_ss_SI = jit.Ptr(_SP, _FP_fargs + _FP_saves + 48)
_VAR_ss_R8 = jit.Ptr(_SP, _FP_fargs + _FP_saves + 56)
_VAR_ss_R9 = jit.Ptr(_SP, _FP_fargs + _FP_saves + 64)
)
type _Assembler struct {
@ -816,6 +818,8 @@
/* allocate the key, and call the unmarshaler */
self.valloc(vk, _DI) // VALLOC ${vk}, DI
// must spill vk pointer since next call_go may invoke GC
self.Emit("MOVQ" , _DI, _VAR_vk)
self.Emit("MOVQ" , jit.Type(tk), _AX) // MOVQ ${tk}, AX
self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP)
self.Emit("MOVQ" , _DI, jit.Ptr(_SP, 8)) // MOVQ DI, 8(SP)
@ -826,6 +830,7 @@
self.Emit("MOVQ" , jit.Ptr(_SP, 40), _EP) // MOVQ 40(SP), EP
self.Emit("TESTQ", _ET, _ET) // TESTQ ET, ET
self.Sjmp("JNZ" , _LB_error) // JNZ _error
self.Emit("MOVQ" , _VAR_vk, _AX) // MOVQ VAR.vk, AX
self.Emit("MOVQ" , jit.Ptr(_SP, 8), _AX) // MOVQ 8(SP), AX
/* select the correct assignment function */
@ -1283,7 +1288,10 @@
self.parse_string() // PARSE STRING
self.unquote_once(_VAR_sv_p, _VAR_sv_n) // UNQUOTE once, sv.p, sv.n
if vt := p.vt(); !mapfast(vt) {
self.mapassign_std(vt, _VAR_sv_p) // MAPASSIGN string, DI, SI
self.valloc(vt.Key(), _DI)
self.Emit("MOVOU", _VAR_sv, _X0)
self.Emit("MOVOU", _X0, jit.Ptr(_DI, 0))
self.mapassign_std(vt, jit.Ptr(_DI, 0))
} else {
self.Emit("MOVQ", _VAR_sv_p, _DI) // MOVQ sv.p, DI
self.Emit("MOVQ", _VAR_sv_n, _SI) // MOVQ sv.n, SI
@ -1518,8 +1526,8 @@
func (self *_Assembler) _asm_OP_save(_ *_Instr) {
self.Emit("MOVQ", jit.Ptr(_ST, 0), _AX) // MOVQ (ST), AX
self.Emit("CMPQ", _AX, jit.Imm(_MaxStack)) // CMPQ AX, ${_MaxStack}
self.Sjmp("JA" , _LB_stack_error) // JA _stack_error
self.Emit("CMPQ", _AX, jit.Imm(_MaxStackBytes)) // CMPQ AX, ${_MaxStackBytes}
self.Sjmp("JAE" , _LB_stack_error) // JA _stack_error
self.Emit("MOVQ", _VP, jit.Sib(_ST, _AX, 1, 8)) // MOVQ VP, 8(ST)(AX)
self.Emit("ADDQ", jit.Imm(8), _AX) // ADDQ $8, AX
self.Emit("MOVQ", _AX, jit.Ptr(_ST, 0)) // MOVQ AX, (ST)

View file

@ -54,7 +54,7 @@ import (
/** Function Prototype & Stack Map
*
* func (s string, ic int, vp unsafe.Pointer, sb *_Stack, fv uint64) (rc int, err error)
* func (s string, ic int, vp unsafe.Pointer, sb *_Stack, fv uint64, sv string) (rc int, err error)
*
* s.buf : (FP)
* s.len : 8(FP)
@ -62,16 +62,16 @@ import (
* vp : 24(FP)
* sb : 32(FP)
* fv : 40(FP)
* rc : 48(FP)
* err.vt : 56(FP)
* err.vp : 64(FP)
* sv : 56(FP)
* err.vt : 72(FP)
* err.vp : 80(FP)
*/
const (
_FP_args = 72 // 72 bytes to pass arguments and return values for this function
_FP_args = 96 // 96 bytes to pass arguments and return values for this function
_FP_fargs = 80 // 80 bytes for passing arguments to other Go functions
_FP_saves = 40 // 40 bytes for saving the registers before CALL instructions
_FP_locals = 96 // 96 bytes for local variables
_FP_locals = 72 // 72 bytes for local variables
)
const (
@ -154,35 +154,37 @@ var (
)
var (
_RET_rc = jit.Ptr(_SP, _FP_base + 48)
_RET_et = jit.Ptr(_SP, _FP_base + 56)
_RET_ep = jit.Ptr(_SP, _FP_base + 64)
_VAR_sv = _VAR_sv_p
_VAR_sv_p = jit.Ptr(_SP, _FP_base + 48)
_VAR_sv_n = jit.Ptr(_SP, _FP_base + 56)
_VAR_vk = jit.Ptr(_SP, _FP_base + 64)
)
var (
_RET_rc = jit.Ptr(_SP, _FP_base + 72)
_RET_et = jit.Ptr(_SP, _FP_base + 80)
_RET_ep = jit.Ptr(_SP, _FP_base + 88)
)
var (
_VAR_sv = _VAR_sv_p
_VAR_st = _VAR_st_Vt
_VAR_sr = jit.Ptr(_SP, _FP_fargs + _FP_saves)
)
var (
_VAR_sv_p = jit.Ptr(_SP, _FP_fargs + _FP_saves + 8)
_VAR_sv_n = jit.Ptr(_SP, _FP_fargs + _FP_saves + 16)
_VAR_st_Vt = jit.Ptr(_SP, _FP_fargs + _FP_saves + 0)
_VAR_st_Dv = jit.Ptr(_SP, _FP_fargs + _FP_saves + 8)
_VAR_st_Iv = jit.Ptr(_SP, _FP_fargs + _FP_saves + 16)
_VAR_st_Ep = jit.Ptr(_SP, _FP_fargs + _FP_saves + 24)
)
var (
_VAR_st_Vt = jit.Ptr(_SP, _FP_fargs + _FP_saves + 24)
_VAR_st_Dv = jit.Ptr(_SP, _FP_fargs + _FP_saves + 32)
_VAR_st_Iv = jit.Ptr(_SP, _FP_fargs + _FP_saves + 40)
_VAR_st_Ep = jit.Ptr(_SP, _FP_fargs + _FP_saves + 48)
)
var (
_VAR_ss_AX = jit.Ptr(_SP, _FP_fargs + _FP_saves + 56)
_VAR_ss_CX = jit.Ptr(_SP, _FP_fargs + _FP_saves + 64)
_VAR_ss_SI = jit.Ptr(_SP, _FP_fargs + _FP_saves + 72)
_VAR_ss_R8 = jit.Ptr(_SP, _FP_fargs + _FP_saves + 80)
_VAR_ss_R9 = jit.Ptr(_SP, _FP_fargs + _FP_saves + 88)
_VAR_ss_AX = jit.Ptr(_SP, _FP_fargs + _FP_saves + 32)
_VAR_ss_CX = jit.Ptr(_SP, _FP_fargs + _FP_saves + 40)
_VAR_ss_SI = jit.Ptr(_SP, _FP_fargs + _FP_saves + 48)
_VAR_ss_R8 = jit.Ptr(_SP, _FP_fargs + _FP_saves + 56)
_VAR_ss_R9 = jit.Ptr(_SP, _FP_fargs + _FP_saves + 64)
)
type _Assembler struct {
@ -661,7 +663,7 @@ func (self *_Assembler) slice_from_r(p obj.Addr, d int64) {
self.Emit("LEAQ", jit.Sib(_IC, p, 1, d), _SI) // LEAQ d(IC)(${p}), SI
}
func (self *_Assembler) unquote_once(p obj.Addr, n obj.Addr) {
func (self *_Assembler) unquote_once(p obj.Addr, n obj.Addr, stack bool) {
self.slice_from(_VAR_st_Iv, -1) // SLICE st.Iv, $-1
self.Emit("MOVQ" , _DI, p) // MOVQ DI, ${p}
self.Emit("MOVQ" , _SI, n) // MOVQ SI, ${n}
@ -670,7 +672,12 @@ func (self *_Assembler) unquote_once(p obj.Addr, n obj.Addr) {
self.malloc(_SI, _DX) // MALLOC SI, DX
self.Emit("MOVQ" , p, _DI) // MOVQ ${p}, DI
self.Emit("MOVQ" , n, _SI) // MOVQ ${n}, SI
self.WriteRecNotAX(2, _DX, p, true, true) // MOVQ DX, ${p}
if stack {
// no need for writeBarrier
self.Emit("MOVQ", _DX, p) // MOVQ DX, ${p}
} else {
self.WriteRecNotAX(2, _DX, p, true, true) // MOVQ DX, ${p}
}
self.Emit("LEAQ" , _VAR_sr, _CX) // LEAQ sr, CX
self.Emit("XORL" , _R8, _R8) // XORL R8, R8
self.Emit("BTQ" , jit.Imm(_F_disable_urc), _ARG_fv) // BTQ ${_F_disable_urc}, fv
@ -685,7 +692,7 @@ func (self *_Assembler) unquote_once(p obj.Addr, n obj.Addr) {
self.Link("_noescape_{n}") // _noescape_{n}:
}
func (self *_Assembler) unquote_twice(p obj.Addr, n obj.Addr) {
func (self *_Assembler) unquote_twice(p obj.Addr, n obj.Addr, stack bool) {
self.Emit("CMPQ" , _VAR_st_Ep, jit.Imm(-1)) // CMPQ st.Ep, $-1
self.Sjmp("JE" , _LB_eof_error) // JE _eof_error
self.Emit("CMPB" , jit.Sib(_IP, _IC, 1, -3), jit.Imm('\\')) // CMPB -3(IP)(IC), $'\\'
@ -702,7 +709,12 @@ func (self *_Assembler) unquote_twice(p obj.Addr, n obj.Addr) {
self.malloc(_SI, _DX) // MALLOC SI, DX
self.Emit("MOVQ" , p, _DI) // MOVQ ${p}, DI
self.Emit("MOVQ" , n, _SI) // MOVQ ${n}, SI
self.WriteRecNotAX(6, _DX, p, true, true) // MOVQ DX, ${p}
if stack {
// no need for writeBarrier
self.Emit("MOVQ", _DX, p) // MOVQ DX, ${p}
} else {
self.WriteRecNotAX(2, _DX, p, true, true) // MOVQ DX, ${p}
}
self.Emit("LEAQ" , _VAR_sr, _CX) // LEAQ sr, CX
self.Emit("MOVL" , jit.Imm(types.F_DOUBLE_UNQUOTE), _R8) // MOVL ${types.F_DOUBLE_UNQUOTE}, R8
self.Emit("BTQ" , jit.Imm(_F_disable_urc), _ARG_fv) // BTQ ${_F_disable_urc}, AX
@ -819,6 +831,8 @@ func (self *_Assembler) mapassign_utext(t reflect.Type, addressable bool) {
/* allocate the key, and call the unmarshaler */
self.valloc(vk, _DI) // VALLOC ${vk}, DI
// must spill vk pointer since next call_go may invoke GC
self.Emit("MOVQ" , _DI, _VAR_vk)
self.Emit("MOVQ" , jit.Type(tk), _AX) // MOVQ ${tk}, AX
self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP)
self.Emit("MOVQ" , _DI, jit.Ptr(_SP, 8)) // MOVQ DI, 8(SP)
@ -829,7 +843,7 @@ func (self *_Assembler) mapassign_utext(t reflect.Type, addressable bool) {
self.Emit("MOVQ" , jit.Ptr(_SP, 40), _EP) // MOVQ 40(SP), EP
self.Emit("TESTQ", _ET, _ET) // TESTQ ET, ET
self.Sjmp("JNZ" , _LB_error) // JNZ _error
self.Emit("MOVQ" , jit.Ptr(_SP, 8), _AX) // MOVQ 8(SP), AX
self.Emit("MOVQ" , _VAR_vk, _AX)
/* select the correct assignment function */
if !pv {
@ -857,7 +871,7 @@ func (self *_Assembler) unmarshal_json(t reflect.Type, deref bool) {
func (self *_Assembler) unmarshal_text(t reflect.Type, deref bool) {
self.parse_string() // PARSE STRING
self.unquote_once(_VAR_sv_p, _VAR_sv_n) // UNQUOTE once, sv.p, sv.n
self.unquote_once(_VAR_sv_p, _VAR_sv_n, true) // UNQUOTE once, sv.p, sv.n
self.unmarshal_func(t, _F_decodeTextUnmarshaler, deref) // UNMARSHAL text, ${t}, ${deref}
}
@ -1012,7 +1026,7 @@ func (self *_Assembler) _asm_OP_dyn(p *_Instr) {
func (self *_Assembler) _asm_OP_str(_ *_Instr) {
self.parse_string() // PARSE STRING
self.unquote_once(jit.Ptr(_VP, 0), jit.Ptr(_VP, 8)) // UNQUOTE once, (VP), 8(VP)
self.unquote_once(jit.Ptr(_VP, 0), jit.Ptr(_VP, 8), false) // UNQUOTE once, (VP), 8(VP)
}
func (self *_Assembler) _asm_OP_bin(_ *_Instr) {
@ -1148,7 +1162,7 @@ func (self *_Assembler) _asm_OP_unquote(_ *_Instr) {
self.Sjmp("JNE" , _LB_char_1_error) // JNE _char_1_error
self.Emit("ADDQ", jit.Imm(2), _IC) // ADDQ $2, IC
self.parse_string() // PARSE STRING
self.unquote_twice(jit.Ptr(_VP, 0), jit.Ptr(_VP, 8)) // UNQUOTE twice, (VP), 8(VP)
self.unquote_twice(jit.Ptr(_VP, 0), jit.Ptr(_VP, 8), false) // UNQUOTE twice, (VP), 8(VP)
}
func (self *_Assembler) _asm_OP_nil_1(_ *_Instr) {
@ -1288,9 +1302,12 @@ func (self *_Assembler) _asm_OP_map_key_f64(p *_Instr) {
func (self *_Assembler) _asm_OP_map_key_str(p *_Instr) {
self.parse_string() // PARSE STRING
self.unquote_once(_VAR_sv_p, _VAR_sv_n) // UNQUOTE once, sv.p, sv.n
self.unquote_once(_VAR_sv_p, _VAR_sv_n, true) // UNQUOTE once, sv.p, sv.n
if vt := p.vt(); !mapfast(vt) {
self.mapassign_std(vt, _VAR_sv_p) // MAPASSIGN string, DI, SI
self.valloc(vt.Key(), _DI)
self.Emit("MOVOU", _VAR_sv, _X0)
self.Emit("MOVOU", _X0, jit.Ptr(_DI, 0))
self.mapassign_std(vt, jit.Ptr(_DI, 0))
} else {
self.Emit("MOVQ", _VAR_sv_p, _DI) // MOVQ sv.p, DI
self.Emit("MOVQ", _VAR_sv_n, _SI) // MOVQ sv.n, SI
@ -1300,13 +1317,13 @@ func (self *_Assembler) _asm_OP_map_key_str(p *_Instr) {
func (self *_Assembler) _asm_OP_map_key_utext(p *_Instr) {
self.parse_string() // PARSE STRING
self.unquote_once(_VAR_sv_p, _VAR_sv_n) // UNQUOTE once, sv.p, sv.n
self.unquote_once(_VAR_sv_p, _VAR_sv_n, true) // UNQUOTE once, sv.p, sv.n
self.mapassign_utext(p.vt(), false) // MAPASSIGN utext, ${p.vt()}, false
}
func (self *_Assembler) _asm_OP_map_key_utext_p(p *_Instr) {
self.parse_string() // PARSE STRING
self.unquote_once(_VAR_sv_p, _VAR_sv_n) // UNQUOTE once, sv.p, sv.n
self.unquote_once(_VAR_sv_p, _VAR_sv_n, true) // UNQUOTE once, sv.p, sv.n
self.mapassign_utext(p.vt(), true) // MAPASSIGN utext, ${p.vt()}, true
}
@ -1388,7 +1405,7 @@ func (self *_Assembler) _asm_OP_struct_field(p *_Instr) {
self.Emit("MOVQ" , jit.Imm(-1), _AX) // MOVQ $-1, AX
self.Emit("MOVQ" , _AX, _VAR_sr) // MOVQ AX, sr
self.parse_string() // PARSE STRING
self.unquote_once(_VAR_sv_p, _VAR_sv_n) // UNQUOTE once, sv.p, sv.n
self.unquote_once(_VAR_sv_p, _VAR_sv_n, true) // UNQUOTE once, sv.p, sv.n
self.Emit("LEAQ" , _VAR_sv, _AX) // LEAQ sv, AX
self.Emit("XORL" , _CX, _CX) // XORL CX, CX
self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP)
@ -1525,8 +1542,8 @@ func (self *_Assembler) _asm_OP_load(_ *_Instr) {
func (self *_Assembler) _asm_OP_save(_ *_Instr) {
self.Emit("MOVQ", jit.Ptr(_ST, 0), _CX) // MOVQ (ST), CX
self.Emit("CMPQ", _CX, jit.Imm(_MaxStack)) // CMPQ CX, ${_MaxStack}
self.Sjmp("JA" , _LB_stack_error) // JA _stack_error
self.Emit("CMPQ", _CX, jit.Imm(_MaxStackBytes)) // CMPQ CX, ${_MaxStackBytes}
self.Sjmp("JAE" , _LB_stack_error) // JA _stack_error
self.WriteRecNotAX(0 , _VP, jit.Sib(_ST, _CX, 1, 8), false, false) // MOVQ VP, 8(ST)(CX)
self.Emit("ADDQ", jit.Imm(8), _CX) // ADDQ $8, CX
self.Emit("MOVQ", _CX, jit.Ptr(_ST, 0)) // MOVQ CX, (ST)

View file

@ -54,7 +54,7 @@ import (
/** Function Prototype & Stack Map
*
* func (s string, ic int, vp unsafe.Pointer, sb *_Stack, fv uint64) (rc int, err error)
* func (s string, ic int, vp unsafe.Pointer, sb *_Stack, fv uint64, sv string) (rc int, err error)
*
* s.buf : (FP)
* s.len : 8(FP)
@ -62,16 +62,16 @@ import (
* vp : 24(FP)
* sb : 32(FP)
* fv : 40(FP)
* rc : 48(FP)
* err.vt : 56(FP)
* err.vp : 64(FP)
* sv : 56(FP)
* err.vt : 72(FP)
* err.vp : 80(FP)
*/
const (
_FP_args = 72 // 72 bytes to pass arguments and return values for this function
_FP_args = 72 // 72 bytes to pass and spill register arguements
_FP_fargs = 80 // 80 bytes for passing arguments to other Go functions
_FP_saves = 48 // 48 bytes for saving the registers before CALL instructions
_FP_locals = 96 // 96 bytes for local variables
_FP_locals = 72 // 72 bytes for local variables
)
const (
@ -143,9 +143,11 @@ var (
_EP = jit.Reg("BX")
)
var (
_ARG_s = _ARG_sp
_ARG_sp = jit.Ptr(_SP, _FP_base)
_ARG_sp = jit.Ptr(_SP, _FP_base + 0)
_ARG_sl = jit.Ptr(_SP, _FP_base + 8)
_ARG_ic = jit.Ptr(_SP, _FP_base + 16)
_ARG_vp = jit.Ptr(_SP, _FP_base + 24)
@ -154,35 +156,30 @@ var (
)
var (
_RET_rc = jit.Ptr(_SP, _FP_base + 48)
_RET_et = jit.Ptr(_SP, _FP_base + 56)
_RET_ep = jit.Ptr(_SP, _FP_base + 64)
_VAR_sv = _VAR_sv_p
_VAR_sv_p = jit.Ptr(_SP, _FP_base + 48)
_VAR_sv_n = jit.Ptr(_SP, _FP_base + 56)
_VAR_vk = jit.Ptr(_SP, _FP_base + 64)
)
var (
_VAR_sv = _VAR_sv_p
_VAR_st = _VAR_st_Vt
_VAR_sr = jit.Ptr(_SP, _FP_fargs + _FP_saves)
)
var (
_VAR_sv_p = jit.Ptr(_SP, _FP_fargs + _FP_saves + 8)
_VAR_sv_n = jit.Ptr(_SP, _FP_fargs + _FP_saves + 16)
_VAR_st_Vt = jit.Ptr(_SP, _FP_fargs + _FP_saves + 0)
_VAR_st_Dv = jit.Ptr(_SP, _FP_fargs + _FP_saves + 8)
_VAR_st_Iv = jit.Ptr(_SP, _FP_fargs + _FP_saves + 16)
_VAR_st_Ep = jit.Ptr(_SP, _FP_fargs + _FP_saves + 24)
)
var (
_VAR_st_Vt = jit.Ptr(_SP, _FP_fargs + _FP_saves + 24)
_VAR_st_Dv = jit.Ptr(_SP, _FP_fargs + _FP_saves + 32)
_VAR_st_Iv = jit.Ptr(_SP, _FP_fargs + _FP_saves + 40)
_VAR_st_Ep = jit.Ptr(_SP, _FP_fargs + _FP_saves + 48)
)
var (
_VAR_ss_AX = jit.Ptr(_SP, _FP_fargs + _FP_saves + 56)
_VAR_ss_CX = jit.Ptr(_SP, _FP_fargs + _FP_saves + 64)
_VAR_ss_SI = jit.Ptr(_SP, _FP_fargs + _FP_saves + 72)
_VAR_ss_R8 = jit.Ptr(_SP, _FP_fargs + _FP_saves + 80)
_VAR_ss_R9 = jit.Ptr(_SP, _FP_fargs + _FP_saves + 88)
_VAR_ss_AX = jit.Ptr(_SP, _FP_fargs + _FP_saves + 32)
_VAR_ss_CX = jit.Ptr(_SP, _FP_fargs + _FP_saves + 40)
_VAR_ss_SI = jit.Ptr(_SP, _FP_fargs + _FP_saves + 48)
_VAR_ss_R8 = jit.Ptr(_SP, _FP_fargs + _FP_saves + 56)
_VAR_ss_R9 = jit.Ptr(_SP, _FP_fargs + _FP_saves + 64)
)
type _Assembler struct {
@ -307,6 +304,10 @@ func (self *_Assembler) epilogue() {
self.Emit("MOVQ", _EP, _CX) // MOVQ BX, CX
self.Emit("MOVQ", _ET, _BX) // MOVQ AX, BX
self.Emit("MOVQ", _IC, _AX) // MOVQ IC, AX
self.Emit("MOVQ", jit.Imm(0), _ARG_sp) // MOVQ $0, sv.p<>+48(FP)
self.Emit("MOVQ", jit.Imm(0), _ARG_vp) // MOVQ $0, sv.p<>+48(FP)
self.Emit("MOVQ", jit.Imm(0), _VAR_sv_p) // MOVQ $0, sv.p<>+48(FP)
self.Emit("MOVQ", jit.Imm(0), _VAR_vk) // MOVQ $0, vk<>+64(FP)
self.Emit("MOVQ", jit.Ptr(_SP, _FP_offs), _BP) // MOVQ _FP_offs(SP), BP
self.Emit("ADDQ", jit.Imm(_FP_size), _SP) // ADDQ $_FP_size, SP
self.Emit("RET") // RET
@ -327,6 +328,9 @@ func (self *_Assembler) prologue() {
self.Emit("MOVQ", _SI, _ARG_sb) // MOVQ SI, sb<>+32(FP)
self.Emit("MOVQ", _SI, _ST) // MOVQ SI, ST
self.Emit("MOVQ", _R8, _ARG_fv) // MOVQ R8, fv<>+40(FP)
self.Emit("MOVQ", jit.Imm(0), _VAR_sv_p) // MOVQ $0, sv.p<>+48(FP)
self.Emit("MOVQ", jit.Imm(0), _VAR_sv_n) // MOVQ $0, sv.n<>+56(FP)
self.Emit("MOVQ", jit.Imm(0), _VAR_vk) // MOVQ $0, vk<>+64(FP)
}
/** Function Calling Helpers **/
@ -669,7 +673,7 @@ func (self *_Assembler) slice_from_r(p obj.Addr, d int64) {
self.Emit("LEAQ", jit.Sib(_IC, p, 1, d), _SI) // LEAQ d(IC)(${p}), SI
}
func (self *_Assembler) unquote_once(p obj.Addr, n obj.Addr) {
func (self *_Assembler) unquote_once(p obj.Addr, n obj.Addr, stack bool) {
self.slice_from(_VAR_st_Iv, -1) // SLICE st.Iv, $-1
self.Emit("MOVQ" , _DI, p) // MOVQ DI, ${p}
self.Emit("MOVQ" , _SI, n) // MOVQ SI, ${n}
@ -678,7 +682,12 @@ func (self *_Assembler) unquote_once(p obj.Addr, n obj.Addr) {
self.malloc(_SI, _DX) // MALLOC SI, DX
self.Emit("MOVQ" , p, _DI) // MOVQ ${p}, DI
self.Emit("MOVQ" , n, _SI) // MOVQ ${n}, SI
self.WriteRecNotAX(2, _DX, p, true, true) // MOVQ DX, ${p}
if stack {
// no need for writeBarrier
self.Emit("MOVQ", _DX, p) // MOVQ DX, ${p}
} else {
self.WriteRecNotAX(2, _DX, p, true, true) // MOVQ DX, ${p}
}
self.Emit("LEAQ" , _VAR_sr, _CX) // LEAQ sr, CX
self.Emit("XORL" , _R8, _R8) // XORL R8, R8
self.Emit("BTQ" , jit.Imm(_F_disable_urc), _ARG_fv) // BTQ ${_F_disable_urc}, fv
@ -693,7 +702,7 @@ func (self *_Assembler) unquote_once(p obj.Addr, n obj.Addr) {
self.Link("_noescape_{n}") // _noescape_{n}:
}
func (self *_Assembler) unquote_twice(p obj.Addr, n obj.Addr) {
func (self *_Assembler) unquote_twice(p obj.Addr, n obj.Addr, stack bool) {
self.Emit("CMPQ" , _VAR_st_Ep, jit.Imm(-1)) // CMPQ st.Ep, $-1
self.Sjmp("JE" , _LB_eof_error) // JE _eof_error
self.Emit("CMPB" , jit.Sib(_IP, _IC, 1, -3), jit.Imm('\\')) // CMPB -3(IP)(IC), $'\\'
@ -710,7 +719,12 @@ func (self *_Assembler) unquote_twice(p obj.Addr, n obj.Addr) {
self.malloc(_SI, _DX) // MALLOC SI, DX
self.Emit("MOVQ" , p, _DI) // MOVQ ${p}, DI
self.Emit("MOVQ" , n, _SI) // MOVQ ${n}, SI
self.WriteRecNotAX(6, _DX, p, true, true) // MOVQ DX, ${p}
if stack {
// no need for writeBarrier
self.Emit("MOVQ", _DX, p) // MOVQ DX, ${p}
} else {
self.WriteRecNotAX(2, _DX, p, true, true) // MOVQ DX, ${p}
}
self.Emit("LEAQ" , _VAR_sr, _CX) // LEAQ sr, CX
self.Emit("MOVL" , jit.Imm(types.F_DOUBLE_UNQUOTE), _R8) // MOVL ${types.F_DOUBLE_UNQUOTE}, R8
self.Emit("BTQ" , jit.Imm(_F_disable_urc), _ARG_fv) // BTQ ${_F_disable_urc}, AX
@ -824,14 +838,16 @@ func (self *_Assembler) mapassign_utext(t reflect.Type, addressable bool) {
/* allocate the key, and call the unmarshaler */
self.valloc(vk, _BX) // VALLOC ${vk}, BX
self.Emit("MOVQ" , _BX, jit.Ptr(_SP, 8)) // MOVQ BX, 8(SP)
// must spill vk pointer since next call_go may invoke GC
self.Emit("MOVQ" , _BX, _VAR_vk)
self.Emit("MOVQ" , jit.Type(tk), _AX) // MOVQ ${tk}, AX
self.Emit("MOVQ" , _VAR_sv_p, _CX) // MOVQ sv.p, CX
self.Emit("MOVQ" , _VAR_sv_n, _DI) // MOVQ sv.n, DI
self.call_go(_F_decodeTextUnmarshaler) // CALL_GO decodeTextUnmarshaler
self.Emit("TESTQ", _ET, _ET) // TESTQ ET, ET
self.Sjmp("JNZ" , _LB_error) // JNZ _error
self.Emit("MOVQ" , jit.Ptr(_SP, 8), _AX) // MOVQ 8(SP), AX
self.Emit("MOVQ" , _VAR_vk, _AX) // MOVQ VAR.vk, AX
self.Emit("MOVQ", jit.Imm(0), _VAR_vk)
/* select the correct assignment function */
if !pv {
@ -859,7 +875,7 @@ func (self *_Assembler) unmarshal_json(t reflect.Type, deref bool) {
func (self *_Assembler) unmarshal_text(t reflect.Type, deref bool) {
self.parse_string() // PARSE STRING
self.unquote_once(_VAR_sv_p, _VAR_sv_n) // UNQUOTE once, sv.p, sv.n
self.unquote_once(_VAR_sv_p, _VAR_sv_n, true) // UNQUOTE once, sv.p, sv.n
self.unmarshal_func(t, _F_decodeTextUnmarshaler, deref) // UNMARSHAL text, ${t}, ${deref}
}
@ -987,6 +1003,7 @@ func (self *_Assembler) _asm_OP_any(_ *_Instr) {
self.Emit("MOVQ" , _ARG_fv, _DF) // MOVQ fv, DF
self.Emit("MOVQ" , _ST, jit.Ptr(_SP, 0)) // MOVQ _ST, (SP)
self.call(_F_decodeValue) // CALL decodeValue
self.Emit("MOVQ" , jit.Imm(0), jit.Ptr(_SP, 0)) // MOVQ _ST, (SP)
self.Emit("TESTQ" , _EP, _EP) // TESTQ EP, EP
self.Sjmp("JNZ" , _LB_parsing_error) // JNZ _parsing_error
self.Link("_decode_end_{n}") // _decode_end_{n}:
@ -1009,7 +1026,7 @@ func (self *_Assembler) _asm_OP_dyn(p *_Instr) {
func (self *_Assembler) _asm_OP_str(_ *_Instr) {
self.parse_string() // PARSE STRING
self.unquote_once(jit.Ptr(_VP, 0), jit.Ptr(_VP, 8)) // UNQUOTE once, (VP), 8(VP)
self.unquote_once(jit.Ptr(_VP, 0), jit.Ptr(_VP, 8), false) // UNQUOTE once, (VP), 8(VP)
}
func (self *_Assembler) _asm_OP_bin(_ *_Instr) {
@ -1145,7 +1162,7 @@ func (self *_Assembler) _asm_OP_unquote(_ *_Instr) {
self.Sjmp("JNE" , _LB_char_1_error) // JNE _char_1_error
self.Emit("ADDQ", jit.Imm(2), _IC) // ADDQ $2, IC
self.parse_string() // PARSE STRING
self.unquote_twice(jit.Ptr(_VP, 0), jit.Ptr(_VP, 8)) // UNQUOTE twice, (VP), 8(VP)
self.unquote_twice(jit.Ptr(_VP, 0), jit.Ptr(_VP, 8), false) // UNQUOTE twice, (VP), 8(VP)
}
func (self *_Assembler) _asm_OP_nil_1(_ *_Instr) {
@ -1286,9 +1303,12 @@ func (self *_Assembler) _asm_OP_map_key_f64(p *_Instr) {
func (self *_Assembler) _asm_OP_map_key_str(p *_Instr) {
self.parse_string() // PARSE STRING
self.unquote_once(_VAR_sv_p, _VAR_sv_n) // UNQUOTE once, sv.p, sv.n
self.unquote_once(_VAR_sv_p, _VAR_sv_n, true) // UNQUOTE once, sv.p, sv.n
if vt := p.vt(); !mapfast(vt) {
self.mapassign_std(vt, _VAR_sv_p) // MAPASSIGN string, DI, SI
self.valloc(vt.Key(), _DI)
self.Emit("MOVOU", _VAR_sv, _X0)
self.Emit("MOVOU", _X0, jit.Ptr(_DI, 0))
self.mapassign_std(vt, jit.Ptr(_DI, 0)) // MAPASSIGN string, DI, SI
} else {
self.mapassign_str_fast(vt, _VAR_sv_p, _VAR_sv_n) // MAPASSIGN string, DI, SI
}
@ -1296,13 +1316,13 @@ func (self *_Assembler) _asm_OP_map_key_str(p *_Instr) {
func (self *_Assembler) _asm_OP_map_key_utext(p *_Instr) {
self.parse_string() // PARSE STRING
self.unquote_once(_VAR_sv_p, _VAR_sv_n) // UNQUOTE once, sv.p, sv.n
self.unquote_once(_VAR_sv_p, _VAR_sv_n, true) // UNQUOTE once, sv.p, sv.n
self.mapassign_utext(p.vt(), false) // MAPASSIGN utext, ${p.vt()}, false
}
func (self *_Assembler) _asm_OP_map_key_utext_p(p *_Instr) {
self.parse_string() // PARSE STRING
self.unquote_once(_VAR_sv_p, _VAR_sv_n) // UNQUOTE once, sv.p, sv.n
self.unquote_once(_VAR_sv_p, _VAR_sv_n, true) // UNQUOTE once, sv.p, sv.n
self.mapassign_utext(p.vt(), true) // MAPASSIGN utext, ${p.vt()}, true
}
@ -1376,7 +1396,7 @@ func (self *_Assembler) _asm_OP_struct_field(p *_Instr) {
self.Emit("MOVQ" , jit.Imm(-1), _AX) // MOVQ $-1, AX
self.Emit("MOVQ" , _AX, _VAR_sr) // MOVQ AX, sr
self.parse_string() // PARSE STRING
self.unquote_once(_VAR_sv_p, _VAR_sv_n) // UNQUOTE once, sv.p, sv.n
self.unquote_once(_VAR_sv_p, _VAR_sv_n, true) // UNQUOTE once, sv.p, sv.n
self.Emit("LEAQ" , _VAR_sv, _AX) // LEAQ sv, AX
self.Emit("XORL" , _BX, _BX) // XORL BX, BX
self.call_go(_F_strhash) // CALL_GO strhash
@ -1507,8 +1527,8 @@ func (self *_Assembler) _asm_OP_load(_ *_Instr) {
func (self *_Assembler) _asm_OP_save(_ *_Instr) {
self.Emit("MOVQ", jit.Ptr(_ST, 0), _CX) // MOVQ (ST), CX
self.Emit("CMPQ", _CX, jit.Imm(_MaxStack)) // CMPQ CX, ${_MaxStack}
self.Sjmp("JA" , _LB_stack_error) // JA _stack_error
self.Emit("CMPQ", _CX, jit.Imm(_MaxStackBytes)) // CMPQ CX, ${_MaxStackBytes}
self.Sjmp("JAE" , _LB_stack_error) // JA _stack_error
self.WriteRecNotAX(0 , _VP, jit.Sib(_ST, _CX, 1, 8), false, false) // MOVQ VP, 8(ST)(CX)
self.Emit("ADDQ", jit.Imm(8), _CX) // ADDQ $8, CX
self.Emit("MOVQ", _CX, jit.Ptr(_ST, 0)) // MOVQ CX, (ST)

View file

@ -33,7 +33,7 @@ import (
func TestAssembler_PrologueAndEpilogue(t *testing.T) {
a := newAssembler(nil)
_, e := a.Load()("", 0, nil, nil, 0)
_, e := a.Load()("", 0, nil, nil, 0, "", nil)
assert.Nil(t, e)
}
@ -117,7 +117,7 @@ func testOpCode(t *testing.T, ops *testOps) {
k := new(_Stack)
a := newAssembler(p)
f := a.Load()
i, e := f(ops.src, ops.pos, rt.UnpackEface(ops.val).Value, k, ops.opt)
i, e := f(ops.src, ops.pos, rt.UnpackEface(ops.val).Value, k, ops.opt, "", nil)
if ops.err != nil {
assert.EqualError(t, e, ops.err.Error())
} else {
@ -684,7 +684,7 @@ func TestAssembler_DecodeStruct(t *testing.T) {
k := new(_Stack)
a := newAssembler(p)
f := a.Load()
pos, err := f(s, 0, unsafe.Pointer(&v), k, 0)
pos, err := f(s, 0, unsafe.Pointer(&v), k, 0, "", nil)
require.NoError(t, err)
assert.Equal(t, len(s), pos)
assert.Equal(t, JsonStruct{
@ -707,7 +707,7 @@ func TestAssembler_DecodeStruct_SinglePrivateField(t *testing.T) {
k := new(_Stack)
a := newAssembler(p)
f := a.Load()
pos, err := f(s, 0, unsafe.Pointer(&v), k, 0)
pos, err := f(s, 0, unsafe.Pointer(&v), k, 0, "", nil)
require.NoError(t, err)
assert.Equal(t, len(s), pos)
assert.Equal(t, Tx{}, v)
@ -721,7 +721,7 @@ func TestAssembler_DecodeByteSlice_Bin(t *testing.T) {
k := new(_Stack)
a := newAssembler(p)
f := a.Load()
pos, err := f(s, 0, unsafe.Pointer(&v), k, 0)
pos, err := f(s, 0, unsafe.Pointer(&v), k, 0, "", nil)
require.NoError(t, err)
assert.Equal(t, len(s), pos)
assert.Equal(t, []byte("hello, world"), v)
@ -735,7 +735,7 @@ func TestAssembler_DecodeByteSlice_List(t *testing.T) {
k := new(_Stack)
a := newAssembler(p)
f := a.Load()
pos, err := f(s, 0, unsafe.Pointer(&v), k, 0)
pos, err := f(s, 0, unsafe.Pointer(&v), k, 0, "", nil)
require.NoError(t, err)
assert.Equal(t, len(s), pos)
assert.Equal(t, []byte("hello, world"), v)

View file

@ -70,6 +70,9 @@ func (self *Decoder) Decode(val interface{}) error {
nb, err := decodeTypedPointer(self.s, self.i, etp, vp, sb, self.f)
/* return the stack back */
if err != nil {
resetStack(sb)
}
self.i = nb
freeStack(sb)

View file

@ -19,6 +19,7 @@ package decoder
import (
`encoding/json`
`testing`
`time`
`runtime`
`runtime/debug`
`sync`
@ -42,6 +43,7 @@ func TestMain(m *testing.M) {
}
println("stop GC looping!")
}()
time.Sleep(time.Millisecond)
m.Run()
}
@ -72,7 +74,6 @@ func TestGC(t *testing.T) {
t.Fatal(out)
}
runtime.GC()
debug.FreeOSMemory()
}(wg)
}
wg.Wait()

View file

@ -329,7 +329,7 @@
/* add a new slot for the first element */
self.Emit("ADDQ", jit.Imm(1), _CX) // ADDQ $1, CX
self.Emit("CMPQ", _CX, jit.Imm(types.MAX_RECURSE)) // CMPQ CX, ${types.MAX_RECURSE}
self.Sjmp("JA" , "_stack_overflow") // JA _stack_overflow
self.Sjmp("JAE" , "_stack_overflow") // JA _stack_overflow
self.Emit("MOVQ", jit.Ptr(_R8, 0), _AX) // MOVQ (R8), AX
self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp
self.Emit("MOVQ", _AX, jit.Sib(_ST, _CX, 8, _ST_Vp)) // MOVQ AX, ST.Vp[CX]
@ -398,7 +398,7 @@
/* add a new delimiter */
self.Emit("ADDQ", jit.Imm(1), _CX) // ADDQ $1, CX
self.Emit("CMPQ", _CX, jit.Imm(types.MAX_RECURSE)) // CMPQ CX, ${types.MAX_RECURSE}
self.Sjmp("JA" , "_stack_overflow") // JA _stack_overflow
self.Sjmp("JAE" , "_stack_overflow") // JA _stack_overflow
self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp
self.Emit("MOVQ", jit.Imm(_S_obj_delim), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_obj_delim, ST.Vt[CX]
@ -533,6 +533,8 @@
self.Emit("ADDQ", jit.Imm(1), jit.Ptr(_SI, 8)) // ADDQ $1, 8(SI)
self.Emit("MOVQ", jit.Ptr(_SI, 0), _SI) // MOVQ (SI), SI
self.Emit("ADDQ", jit.Imm(1), _CX) // ADDQ $1, CX
self.Emit("CMPQ", _CX, jit.Imm(types.MAX_RECURSE)) // CMPQ CX, ${types.MAX_RECURSE}
self.Sjmp("JAE" , "_stack_overflow")
self.Emit("SHLQ", jit.Imm(1), _DX) // SHLQ $1, DX
self.Emit("LEAQ", jit.Sib(_SI, _DX, 8, 0), _SI) // LEAQ (SI)(DX*8), SI
self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp

View file

@ -332,7 +332,7 @@ func (self *_ValueDecoder) compile() {
/* add a new slot for the first element */
self.Emit("ADDQ", jit.Imm(1), _CX) // ADDQ $1, CX
self.Emit("CMPQ", _CX, jit.Imm(types.MAX_RECURSE)) // CMPQ CX, ${types.MAX_RECURSE}
self.Sjmp("JA" , "_stack_overflow") // JA _stack_overflow
self.Sjmp("JAE" , "_stack_overflow") // JA _stack_overflow
self.Emit("MOVQ", jit.Ptr(_R8, 0), _AX) // MOVQ (R8), AX
self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp
self.WritePtrAX(3, jit.Sib(_ST, _CX, 8, _ST_Vp), false) // MOVQ AX, ST.Vp[CX]
@ -401,7 +401,7 @@ func (self *_ValueDecoder) compile() {
/* add a new delimiter */
self.Emit("ADDQ", jit.Imm(1), _CX) // ADDQ $1, CX
self.Emit("CMPQ", _CX, jit.Imm(types.MAX_RECURSE)) // CMPQ CX, ${types.MAX_RECURSE}
self.Sjmp("JA" , "_stack_overflow") // JA _stack_overflow
self.Sjmp("JAE" , "_stack_overflow") // JA _stack_overflow
self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp
self.Emit("MOVQ", jit.Imm(_S_obj_delim), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_obj_delim, ST.Vt[CX]
@ -537,6 +537,8 @@ func (self *_ValueDecoder) compile() {
self.Emit("ADDQ", jit.Imm(1), jit.Ptr(_SI, 8)) // ADDQ $1, 8(SI)
self.Emit("MOVQ", jit.Ptr(_SI, 0), _SI) // MOVQ (SI), SI
self.Emit("ADDQ", jit.Imm(1), _CX) // ADDQ $1, CX
self.Emit("CMPQ", _CX, jit.Imm(types.MAX_RECURSE)) // CMPQ CX, ${types.MAX_RECURSE}
self.Sjmp("JAE" , "_stack_overflow")
self.Emit("SHLQ", jit.Imm(1), _DX) // SHLQ $1, DX
self.Emit("LEAQ", jit.Sib(_SI, _DX, 8, 0), _SI) // LEAQ (SI)(DX*8), SI
self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp

View file

@ -344,7 +344,7 @@ func (self *_ValueDecoder) compile() {
/* add a new slot for the first element */
self.Emit("ADDQ", jit.Imm(1), _CX) // ADDQ $1, CX
self.Emit("CMPQ", _CX, jit.Imm(types.MAX_RECURSE)) // CMPQ CX, ${types.MAX_RECURSE}
self.Sjmp("JA" , "_stack_overflow") // JA _stack_overflow
self.Sjmp("JAE" , "_stack_overflow") // JA _stack_overflow
self.Emit("MOVQ", jit.Ptr(_R8, 0), _AX) // MOVQ (R8), AX
self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp
self.WritePtrAX(3, jit.Sib(_ST, _CX, 8, _ST_Vp), false) // MOVQ AX, ST.Vp[CX]
@ -412,7 +412,7 @@ func (self *_ValueDecoder) compile() {
/* add a new delimiter */
self.Emit("ADDQ", jit.Imm(1), _CX) // ADDQ $1, CX
self.Emit("CMPQ", _CX, jit.Imm(types.MAX_RECURSE)) // CMPQ CX, ${types.MAX_RECURSE}
self.Sjmp("JA" , "_stack_overflow") // JA _stack_overflow
self.Sjmp("JAE" , "_stack_overflow") // JA _stack_overflow
self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp
self.Emit("MOVQ", jit.Imm(_S_obj_delim), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_obj_delim, ST.Vt[CX]
@ -542,6 +542,8 @@ func (self *_ValueDecoder) compile() {
self.Emit("ADDQ", jit.Imm(1), jit.Ptr(_SI, 8)) // ADDQ $1, 8(SI)
self.Emit("MOVQ", jit.Ptr(_SI, 0), _SI) // MOVQ (SI), SI
self.Emit("ADDQ", jit.Imm(1), _CX) // ADDQ $1, CX
self.Emit("CMPQ", _CX, jit.Imm(types.MAX_RECURSE)) // CMPQ CX, ${types.MAX_RECURSE}
self.Sjmp("JAE" , "_stack_overflow") // JA _stack_overflow
self.Emit("SHLQ", jit.Imm(1), _DX) // SHLQ $1, DX
self.Emit("LEAQ", jit.Sib(_SI, _DX, 8, 0), _SI) // LEAQ (SI)(DX*8), SI
self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp

View file

@ -18,7 +18,6 @@ package decoder
import (
`errors`
`runtime`
`sync`
`unsafe`
@ -30,11 +29,13 @@ import (
const (
_MinSlice = 16
_MaxStack = 65536 // 64k slots
_MaxStackBytes = _MaxStack * _PtrBytes
)
const (
_PtrBytes = _PTR_SIZE / 8
_FsmOffset = (_MaxStack + 1) * _PtrBytes
_StackSize = unsafe.Sizeof(_Stack{})
)
var (
@ -58,6 +59,8 @@ type _Decoder func(
vp unsafe.Pointer,
sb *_Stack,
fv uint64,
sv string, // DO NOT pass value to this arguement, since it is only used for local _VAR_sv
vk unsafe.Pointer, // DO NOT pass value to this arguement, since it is only used for local _VAR_vk
) (int, error)
var _KeepAlive struct {
@ -66,16 +69,21 @@ var _KeepAlive struct {
vp unsafe.Pointer
sb *_Stack
fv uint64
sv string
vk unsafe.Pointer
ret int
err error
frame [_FP_offs]byte
frame_decoder [_FP_offs]byte
frame_generic [_VD_offs]byte
}
var errCallShadow = errors.New("DON'T CALL THIS!")
//go:nosplit
// Faker func of _Decoder, used to export its stackmap as _Decoder's
func _Decoder_Shadow(s string, i int, vp unsafe.Pointer, sb *_Stack, fv uint64) (ret int, err error) {
func _Decoder_Shadow(s string, i int, vp unsafe.Pointer, sb *_Stack, fv uint64, sv string, vk unsafe.Pointer) (ret int, err error) {
// align to assembler_amd64.go: _FP_offs
var frame [_FP_offs]byte
@ -87,8 +95,10 @@ func _Decoder_Shadow(s string, i int, vp unsafe.Pointer, sb *_Stack, fv uint64)
_KeepAlive.fv = fv
_KeepAlive.ret = ret
_KeepAlive.err = err
_KeepAlive.frame = frame
_KeepAlive.sv = sv
_KeepAlive.vk = vk
_KeepAlive.frame_decoder = frame
return 0, errCallShadow
}
@ -96,11 +106,11 @@ func _Decoder_Shadow(s string, i int, vp unsafe.Pointer, sb *_Stack, fv uint64)
// Faker func of _Decoder_Generic, used to export its stackmap
func _Decoder_Generic_Shadow(sb *_Stack) {
// align to generic_amd64.go: _VD_offs
var stacks [_VD_offs]byte
runtime.KeepAlive(stacks)
var frame [_VD_offs]byte
// must keep sb noticeable to GC
runtime.KeepAlive(sb)
_KeepAlive.sb = sb
_KeepAlive.frame_generic = frame
}
func newStack() *_Stack {
@ -111,6 +121,10 @@ func newStack() *_Stack {
}
}
func resetStack(p *_Stack) {
memclrNoHeapPointers(unsafe.Pointer(p), _StackSize)
}
func freeStack(p *_Stack) {
p.sp = 0
stackPool.Put(p)

View file

@ -28,7 +28,7 @@ func decodeTypedPointer(s string, i int, vt *rt.GoType, vp unsafe.Pointer, sb *_
if fn, err := findOrCompile(vt); err != nil {
return 0, err
} else {
return fn(s, i, vp, sb, fv)
return fn(s, i, vp, sb, fv, "", nil)
}
}

View file

@ -30,6 +30,7 @@ import (
`runtime/debug`
`strconv`
`testing`
`time`
`unsafe`
`github.com/bytedance/sonic/encoder`
@ -49,7 +50,8 @@ func TestMain(m *testing.M) {
debug.FreeOSMemory()
}
println("stop GC looping!")
}()
}()
time.Sleep(time.Millisecond)
m.Run()
}

View file

@ -411,7 +411,7 @@
self.Emit("MOVQ", jit.Ptr(_ST, 0), _AX) // MOVQ (ST), AX
self.Emit("LEAQ", jit.Ptr(_AX, _StateSize), _R8) // LEAQ _StateSize(AX), R8
self.Emit("CMPQ", _R8, jit.Imm(_StackLimit)) // CMPQ R8, $_StackLimit
self.Sjmp("JA" , _LB_error_too_deep) // JA _error_too_deep
self.Sjmp("JAE" , _LB_error_too_deep) // JA _error_too_deep
self.Emit("MOVQ", _SP_x, jit.Sib(_ST, _AX, 1, 8)) // MOVQ SP.x, 8(ST)(AX)
self.Emit("MOVQ", _SP_f, jit.Sib(_ST, _AX, 1, 16)) // MOVQ SP.f, 16(ST)(AX)
self.Emit("MOVQ", _SP_p, jit.Sib(_ST, _AX, 1, 24)) // MOVQ SP.p, 24(ST)(AX)

View file

@ -412,7 +412,7 @@ func (self *_Assembler) save_state() {
self.Emit("MOVQ", jit.Ptr(_ST, 0), _CX) // MOVQ (ST), CX
self.Emit("LEAQ", jit.Ptr(_CX, _StateSize), _R8) // LEAQ _StateSize(CX), R8
self.Emit("CMPQ", _R8, jit.Imm(_StackLimit)) // CMPQ R8, $_StackLimit
self.Sjmp("JA" , _LB_error_too_deep) // JA _error_too_deep
self.Sjmp("JAE" , _LB_error_too_deep) // JA _error_too_deep
self.Emit("MOVQ", _SP_x, jit.Sib(_ST, _CX, 1, 8)) // MOVQ SP.x, 8(ST)(CX)
self.Emit("MOVQ", _SP_f, jit.Sib(_ST, _CX, 1, 16)) // MOVQ SP.f, 16(ST)(CX)
self.WriteRecNotAX(0, _SP_p, jit.Sib(_ST, _CX, 1, 24)) // MOVQ SP.p, 24(ST)(CX)

View file

@ -71,7 +71,7 @@ const (
)
const (
_FP_args = 48 // 48 bytes for passing arguments to this function
_FP_args = 32 // 32 bytes for spill registers of arguments
_FP_fargs = 40 // 40 bytes for passing arguments to other Go functions
_FP_saves = 64 // 64 bytes for saving the registers before CALL instructions
_FP_locals = 24 // 24 bytes for local variables
@ -169,7 +169,7 @@ var (
_REG_ffi = []obj.Addr{ _RP, _RL, _RC}
_REG_b64 = []obj.Addr{_SP_p, _SP_q}
_REG_go = []obj.Addr{_ST, _SP_x, _SP_f, _SP_p, _SP_q, _RP, _RL, _RC}
_REG_all = []obj.Addr{_ST, _SP_x, _SP_f, _SP_p, _SP_q, _RP, _RL, _RC}
_REG_ms = []obj.Addr{_ST, _SP_x, _SP_f, _SP_p, _SP_q, _LR}
_REG_enc = []obj.Addr{_ST, _SP_x, _SP_f, _SP_p, _SP_q}
)
@ -286,6 +286,9 @@ func (self *_Assembler) epilogue() {
self.Link(_LB_error)
self.Emit("MOVQ", _ARG_rb, _CX) // MOVQ rb<>+0(FP), CX
self.Emit("MOVQ", _RL, jit.Ptr(_CX, 8)) // MOVQ RL, 8(CX)
self.Emit("MOVQ", jit.Imm(0), _ARG_rb) // MOVQ AX, rb<>+0(FP)
self.Emit("MOVQ", jit.Imm(0), _ARG_vp) // MOVQ BX, vp<>+8(FP)
self.Emit("MOVQ", jit.Imm(0), _ARG_sb) // MOVQ CX, sb<>+16(FP)
self.Emit("MOVQ", jit.Ptr(_SP, _FP_offs), _BP) // MOVQ _FP_offs(SP), BP
self.Emit("ADDQ", jit.Imm(_FP_size), _SP) // ADDQ $_FP_size, SP
self.Emit("RET") // RET
@ -420,7 +423,7 @@ func (self *_Assembler) save_state() {
self.Emit("MOVQ", jit.Ptr(_ST, 0), _CX) // MOVQ (ST), CX
self.Emit("LEAQ", jit.Ptr(_CX, _StateSize), _R9) // LEAQ _StateSize(CX), R9
self.Emit("CMPQ", _R9, jit.Imm(_StackLimit)) // CMPQ R9, $_StackLimit
self.Sjmp("JA" , _LB_error_too_deep) // JA _error_too_deep
self.Sjmp("JAE" , _LB_error_too_deep) // JA _error_too_deep
self.Emit("MOVQ", _SP_x, jit.Sib(_ST, _CX, 1, 8)) // MOVQ SP.x, 8(ST)(CX)
self.Emit("MOVQ", _SP_f, jit.Sib(_ST, _CX, 1, 16)) // MOVQ SP.f, 16(ST)(CX)
self.WriteRecNotAX(0, _SP_p, jit.Sib(_ST, _CX, 1, 24)) // MOVQ SP.p, 24(ST)(CX)
@ -506,9 +509,9 @@ func (self *_Assembler) call_c(pc obj.Addr) {
}
func (self *_Assembler) call_go(pc obj.Addr) {
self.xsave(_REG_go...) // SAVE $REG_all
self.xsave(_REG_all...) // SAVE $REG_all
self.call(pc) // CALL $pc
self.xload(_REG_go...) // LOAD $REG_all
self.xload(_REG_all...) // LOAD $REG_all
}
func (self *_Assembler) call_more_space(pc obj.Addr) {

View file

@ -103,6 +103,9 @@ func EncodeInto(buf *[]byte, val interface{}, opts Options) error {
err := encodeTypedPointer(buf, efv.Type, &efv.Value, stk, uint64(opts))
/* return the stack into pool */
if err != nil {
resetStack(stk)
}
freeStack(stk)
/* avoid GC ahead */

View file

@ -23,6 +23,7 @@ import (
`strconv`
`sync`
`testing`
`time`
gojson `github.com/goccy/go-json`
`github.com/json-iterator/go`
@ -41,6 +42,7 @@ func TestMain(m *testing.M) {
}
println("stop GC looping!")
}()
time.Sleep(time.Millisecond)
m.Run()
}
@ -67,7 +69,6 @@ func TestGC(t *testing.T) {
t.Fatal(len(out), size)
}
runtime.GC()
debug.FreeOSMemory()
}(wg, n)
}
wg.Wait()

View file

@ -29,6 +29,8 @@ import (
const (
_MaxStack = 65536 // 64k states
_MaxBuffer = 1048576 // 1MB buffer size
_StackSize = unsafe.Sizeof(_Stack{})
)
var (
@ -101,6 +103,10 @@ func newStack() *_Stack {
}
}
func resetStack(p *_Stack) {
memclrNoHeapPointers(unsafe.Pointer(p), _StackSize)
}
func newBuffer() *bytes.Buffer {
if ret := bufferPool.Get(); ret != nil {
return ret.(*bytes.Buffer)

View file

@ -56,6 +56,11 @@ func mapiterinit(t *rt.GoMapType, m *rt.GoMap, it *rt.GoMapIterator)
//goland:noinspection GoUnusedParameter
func isValidNumber(s string) bool
//go:noescape
//go:linkname memclrNoHeapPointers runtime.memclrNoHeapPointers
//goland:noinspection GoUnusedParameter
func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)
func asText(v unsafe.Pointer) (string, error) {
text := assertI2I(_T_encoding_TextMarshaler, *(*rt.GoIface)(v))
r, e := (*(*encoding.TextMarshaler)(unsafe.Pointer(&text))).MarshalText()

View file

@ -56,6 +56,11 @@ func mapiterinit(t *rt.GoMapType, m *rt.GoMap, it *rt.GoMapIterator)
//goland:noinspection GoUnusedParameter
func isValidNumber(s string) bool
//go:noescape
//go:linkname memclrNoHeapPointers runtime.memclrNoHeapPointers
//goland:noinspection GoUnusedParameter
func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)
func asText(v unsafe.Pointer) (string, error) {
text := assertI2I(_T_encoding_TextMarshaler, *(*rt.GoIface)(v))
r, e := (*(*encoding.TextMarshaler)(unsafe.Pointer(&text))).MarshalText()

View file

@ -57,6 +57,11 @@ func mapiterinit(t *rt.GoMapType, m *rt.GoMap, it *rt.GoMapIterator)
//goland:noinspection GoUnusedParameter
func isValidNumber(s string) bool
//go:noescape
//go:linkname memclrNoHeapPointers runtime.memclrNoHeapPointers
//goland:noinspection GoUnusedParameter
func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)
var (
_F_assertI2I = jit.Func(assertI2I2)
)

View file

@ -21,6 +21,7 @@ import (
`runtime`
`runtime/debug`
`testing`
`time`
)
var debugAsyncGC = os.Getenv("SONIC_NO_ASYNC_GC") == ""
@ -36,5 +37,6 @@ func TestMain(m *testing.M) {
debug.FreeOSMemory()
}
}()
time.Sleep(time.Millisecond)
m.Run()
}