mirror of
https://github.com/ii64/sonic.git
synced 2026-06-20 16:45:22 +08:00
fix: use stackmap of shadow func as jit func's (#127)
* fix: use stackmap of shadow func as jit func's * fix: use LoadWithFaker in decoder * fix: LoadWithFaker support go115 * add 'runtime.' prefix on jit funcname to prevent preempt * add parallel GC tests * remove no_stack_pointer() Co-authored-by: duanyi.aster <duanyi.aster@bytedance.com> Co-authored-by: liuqiang <liuqiang.06@bytedance.com>
This commit is contained in:
parent
3a25fcac4f
commit
442ce696fb
26 changed files with 7204 additions and 5553 deletions
|
|
@ -19,5 +19,6 @@ header:
|
|||
- 'internal/native/avx2/native_subr_amd64.go' # auto-generated by asm2asm
|
||||
- 'internal/resolver/asm.s' # empty file
|
||||
- 'internal/rt/asm.s' # empty file
|
||||
- 'internal/loader/asm.s' # empty file
|
||||
|
||||
comment: on-failure
|
||||
|
|
@ -17,12 +17,47 @@
|
|||
package ast
|
||||
|
||||
import (
|
||||
`encoding/json`
|
||||
`testing`
|
||||
`encoding/json`
|
||||
`testing`
|
||||
`runtime`
|
||||
`runtime/debug`
|
||||
`sync`
|
||||
|
||||
`github.com/bytedance/sonic/internal/native/types`
|
||||
`github.com/bytedance/sonic/internal/native/types`
|
||||
)
|
||||
|
||||
func TestGC_Encode(t *testing.T) {
|
||||
root, err := NewSearcher(_TwitterJson).GetByPath()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
root.LoadAll()
|
||||
_, err = root.MarshalJSON()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
wg := &sync.WaitGroup{}
|
||||
N := 10000
|
||||
for i:=0; i<N; i++ {
|
||||
wg.Add(1)
|
||||
go func (wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
root, err := NewSearcher(_TwitterJson).GetByPath()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
root.Load()
|
||||
_, err = root.MarshalJSON()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime.GC()
|
||||
debug.FreeOSMemory()
|
||||
}(wg)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestEncodeValue(t *testing.T) {
|
||||
type Case struct {
|
||||
node Node
|
||||
|
|
|
|||
|
|
@ -19,12 +19,49 @@ package ast
|
|||
import (
|
||||
`encoding/json`
|
||||
`testing`
|
||||
`runtime`
|
||||
`runtime/debug`
|
||||
`sync`
|
||||
|
||||
jsoniter `github.com/json-iterator/go`
|
||||
`github.com/stretchr/testify/assert`
|
||||
`github.com/tidwall/gjson`
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
go func () {
|
||||
println("Begin GC looping...")
|
||||
for {
|
||||
runtime.GC()
|
||||
debug.FreeOSMemory()
|
||||
}
|
||||
println("stop GC looping!")
|
||||
}()
|
||||
m.Run()
|
||||
}
|
||||
|
||||
func TestGC_Parse(t *testing.T) {
|
||||
_, _, err := Loads(_TwitterJson)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
wg := &sync.WaitGroup{}
|
||||
N := 1000
|
||||
for i:=0; i<N; i++ {
|
||||
wg.Add(1)
|
||||
go func (wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
_, _, err := Loads(_TwitterJson)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime.GC()
|
||||
debug.FreeOSMemory()
|
||||
}(wg)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func runDecoderTest(t *testing.T, src string, expect interface{}) {
|
||||
vv, err := NewParser(src).Parse()
|
||||
if err != 0 { panic(err) }
|
||||
|
|
|
|||
|
|
@ -18,12 +18,38 @@ package ast
|
|||
|
||||
import (
|
||||
`testing`
|
||||
`runtime`
|
||||
`runtime/debug`
|
||||
`sync`
|
||||
|
||||
jsoniter `github.com/json-iterator/go`
|
||||
`github.com/stretchr/testify/assert`
|
||||
`github.com/tidwall/gjson`
|
||||
)
|
||||
|
||||
|
||||
func TestGC_Search(t *testing.T) {
|
||||
_, err := NewSearcher(_TwitterJson).GetByPath("statuses", 0, "id")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
wg := &sync.WaitGroup{}
|
||||
N := 10000
|
||||
for i:=0; i<N; i++ {
|
||||
wg.Add(1)
|
||||
go func (wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
_, err := NewSearcher(_TwitterJson).GetByPath("statuses", 0, "id")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runtime.GC()
|
||||
debug.FreeOSMemory()
|
||||
}(wg)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestExportError(t *testing.T) {
|
||||
data := `{"a":]`
|
||||
p := NewSearcher(data)
|
||||
|
|
|
|||
|
|
@ -192,7 +192,7 @@ func newAssembler(p _Program) *_Assembler {
|
|||
/** Assembler Interface **/
|
||||
|
||||
func (self *_Assembler) Load() _Decoder {
|
||||
return ptodec(self.BaseAssembler.Load("json_decoder", _FP_size, _FP_args))
|
||||
return ptodec(self.BaseAssembler.LoadWithFaker("json_decoder", _FP_size, _FP_args, _Decoder_Shadow))
|
||||
}
|
||||
|
||||
func (self *_Assembler) Init(p _Program) *_Assembler {
|
||||
|
|
@ -289,6 +289,7 @@ func (self *_Assembler) instrs() {
|
|||
for i, v := range self.p {
|
||||
self.Mark(i)
|
||||
self.instr(&v)
|
||||
self.debug_instr(i, &v)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
68
decoder/debug.go
Normal file
68
decoder/debug.go
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
import (
|
||||
`strings`
|
||||
`runtime`
|
||||
`runtime/debug`
|
||||
|
||||
`github.com/bytedance/sonic/internal/jit`
|
||||
)
|
||||
|
||||
//WARN: MUST set false after release
|
||||
var debugGC = false
|
||||
|
||||
var (
|
||||
_Instr_End _Instr = newInsOp(_OP_nil_1)
|
||||
|
||||
_F_gc = jit.Func(runtime.GC)
|
||||
_F_force_gc = jit.Func(debug.FreeOSMemory)
|
||||
_F_println = jit.Func(println_wrapper)
|
||||
)
|
||||
|
||||
func println_wrapper(i int, op1 int, op2 int){
|
||||
println(i, " Intrs ", op1, _OpNames[op1], "next: ", op2, _OpNames[op2])
|
||||
}
|
||||
|
||||
func (self *_Assembler) print_gc(i int, p1 *_Instr, p2 *_Instr) {
|
||||
self.Emit("MOVQ", jit.Imm(int64(p2.op())), jit.Ptr(_SP, 16))// MOVQ $(p2.op()), 16(SP)
|
||||
self.Emit("MOVQ", jit.Imm(int64(p1.op())), jit.Ptr(_SP, 8)) // MOVQ $(p1.op()), 8(SP)
|
||||
self.Emit("MOVQ", jit.Imm(int64(i)), jit.Ptr(_SP, 0)) // MOVQ $(i), (SP)
|
||||
self.call_go(_F_println)
|
||||
}
|
||||
|
||||
func (self *_Assembler) force_gc() {
|
||||
self.call_go(_F_gc)
|
||||
self.call_go(_F_force_gc)
|
||||
}
|
||||
|
||||
func (self *_Assembler) debug_instr(i int, v *_Instr) {
|
||||
if debugGC {
|
||||
if (i+1 == len(self.p)) {
|
||||
self.print_gc(i, v, &_Instr_End)
|
||||
} else {
|
||||
next := &(self.p[i+1])
|
||||
self.print_gc(i, v, next)
|
||||
name := _OpNames[next.op()]
|
||||
if strings.Contains(name, "save") {
|
||||
return
|
||||
}
|
||||
}
|
||||
self.force_gc()
|
||||
}
|
||||
}
|
||||
|
|
@ -19,6 +19,9 @@ package decoder
|
|||
import (
|
||||
`encoding/json`
|
||||
`testing`
|
||||
`runtime`
|
||||
`runtime/debug`
|
||||
`sync`
|
||||
|
||||
`github.com/davecgh/go-spew/spew`
|
||||
gojson `github.com/goccy/go-json`
|
||||
|
|
@ -27,6 +30,48 @@ import (
|
|||
`github.com/stretchr/testify/require`
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
go func () {
|
||||
println("Begin GC looping...")
|
||||
for {
|
||||
runtime.GC()
|
||||
debug.FreeOSMemory()
|
||||
}
|
||||
println("stop GC looping!")
|
||||
}()
|
||||
m.Run()
|
||||
}
|
||||
|
||||
func TestGC(t *testing.T) {
|
||||
var w interface{}
|
||||
out, err := decode(TwitterJson, &w)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if out != len(TwitterJson) {
|
||||
t.Fatal(out)
|
||||
}
|
||||
wg := &sync.WaitGroup{}
|
||||
N := 10000
|
||||
for i:=0; i<N; i++ {
|
||||
wg.Add(1)
|
||||
go func (wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
var w interface{}
|
||||
out, err := decode(TwitterJson, &w)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if out != len(TwitterJson) {
|
||||
t.Fatal(out)
|
||||
}
|
||||
runtime.GC()
|
||||
debug.FreeOSMemory()
|
||||
}(wg)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
var _BindingValue TwitterStruct
|
||||
|
||||
func init() {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
package decoder
|
||||
|
||||
import (
|
||||
`errors`
|
||||
`runtime`
|
||||
`sync`
|
||||
`unsafe`
|
||||
|
||||
|
|
@ -58,6 +60,23 @@ type _Decoder func(
|
|||
fv uint64,
|
||||
) (int, error)
|
||||
|
||||
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(rb *[]byte, vp unsafe.Pointer, sb *_Stack, fv uint64) error {
|
||||
// align to assembler_amd64.go: _FP_offs
|
||||
var stacks [_FP_offs]byte
|
||||
runtime.KeepAlive(stacks)
|
||||
|
||||
// must keep rb, vp and sb noticeable to GC
|
||||
runtime.KeepAlive(sb)
|
||||
runtime.KeepAlive(rb)
|
||||
runtime.KeepAlive(vp)
|
||||
|
||||
return errCallShadow
|
||||
}
|
||||
|
||||
func newStack() *_Stack {
|
||||
if ret := stackPool.Get(); ret == nil {
|
||||
return new(_Stack)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ import (
|
|||
`math`
|
||||
`reflect`
|
||||
`regexp`
|
||||
`runtime`
|
||||
`runtime/debug`
|
||||
`strconv`
|
||||
`testing`
|
||||
`unsafe`
|
||||
|
|
@ -32,6 +34,18 @@ import (
|
|||
`github.com/bytedance/sonic/encoder`
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
go func () {
|
||||
println("Begin GC looping...")
|
||||
for {
|
||||
runtime.GC()
|
||||
debug.FreeOSMemory()
|
||||
}
|
||||
println("stop GC looping!")
|
||||
}()
|
||||
m.Run()
|
||||
}
|
||||
|
||||
type Optionals struct {
|
||||
Sr string `json:"sr"`
|
||||
So string `json:"so,omitempty"`
|
||||
|
|
|
|||
|
|
@ -123,16 +123,16 @@ var (
|
|||
)
|
||||
|
||||
var (
|
||||
_ST = jit.Reg("BX")
|
||||
_RP = jit.Reg("DI")
|
||||
_RL = jit.Reg("SI")
|
||||
_RC = jit.Reg("DX")
|
||||
_ST = jit.Reg("BX")
|
||||
_RP = jit.Reg("DI")
|
||||
_RL = jit.Reg("SI")
|
||||
_RC = jit.Reg("DX")
|
||||
)
|
||||
|
||||
var (
|
||||
_LR = jit.Reg("R9")
|
||||
_ET = jit.Reg("R10")
|
||||
_EP = jit.Reg("R11")
|
||||
_ET = jit.Reg("R10")
|
||||
_EP = jit.Reg("R11")
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -179,7 +179,7 @@ func newAssembler(p _Program) *_Assembler {
|
|||
/** Assembler Interface **/
|
||||
|
||||
func (self *_Assembler) Load() _Encoder {
|
||||
return ptoenc(self.BaseAssembler.Load("json_encoder", _FP_size, _FP_args))
|
||||
return ptoenc(self.BaseAssembler.LoadWithFaker("json_encoder", _FP_size, _FP_args, _Encoder_Shadow))
|
||||
}
|
||||
|
||||
func (self *_Assembler) Init(p _Program) *_Assembler {
|
||||
|
|
@ -260,6 +260,7 @@ func (self *_Assembler) instrs() {
|
|||
for i, v := range self.p {
|
||||
self.Mark(i)
|
||||
self.instr(&v)
|
||||
self.debug_instr(i, &v)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
68
encoder/debug.go
Normal file
68
encoder/debug.go
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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 encoder
|
||||
|
||||
import (
|
||||
`strings`
|
||||
`runtime`
|
||||
`runtime/debug`
|
||||
|
||||
`github.com/bytedance/sonic/internal/jit`
|
||||
)
|
||||
|
||||
//WARN: MUST set false after release
|
||||
var debugGC = false
|
||||
|
||||
var (
|
||||
_Instr_End _Instr = newInsOp(_OP_null)
|
||||
|
||||
_F_gc = jit.Func(runtime.GC)
|
||||
_F_force_gc = jit.Func(debug.FreeOSMemory)
|
||||
_F_println = jit.Func(println_wrapper)
|
||||
)
|
||||
|
||||
func println_wrapper(i int, op1 int, op2 int){
|
||||
println(i, " Intrs ", op1, _OpNames[op1], "next: ", op2, _OpNames[op2])
|
||||
}
|
||||
|
||||
func (self *_Assembler) print_gc(i int, p1 *_Instr, p2 *_Instr) {
|
||||
self.Emit("MOVQ", jit.Imm(int64(p2.op())), jit.Ptr(_SP, 16))// MOVQ $(p2.op()), 16(SP)
|
||||
self.Emit("MOVQ", jit.Imm(int64(p1.op())), jit.Ptr(_SP, 8)) // MOVQ $(p1.op()), 8(SP)
|
||||
self.Emit("MOVQ", jit.Imm(int64(i)), jit.Ptr(_SP, 0)) // MOVQ $(i), (SP)
|
||||
self.call_go(_F_println)
|
||||
}
|
||||
|
||||
func (self *_Assembler) force_gc() {
|
||||
self.call_go(_F_gc)
|
||||
self.call_go(_F_force_gc)
|
||||
}
|
||||
|
||||
func (self *_Assembler) debug_instr(i int, v *_Instr) {
|
||||
if debugGC {
|
||||
if (i+1 == len(self.p)) {
|
||||
self.print_gc(i, v, &_Instr_End)
|
||||
} else {
|
||||
next := &(self.p[i+1])
|
||||
self.print_gc(i, v, next)
|
||||
name := _OpNames[next.op()]
|
||||
if strings.Contains(name, "save") {
|
||||
return
|
||||
}
|
||||
}
|
||||
self.force_gc()
|
||||
}
|
||||
}
|
||||
|
|
@ -18,7 +18,10 @@ package encoder
|
|||
|
||||
import (
|
||||
`encoding/json`
|
||||
`runtime`
|
||||
`runtime/debug`
|
||||
`strconv`
|
||||
`sync`
|
||||
`testing`
|
||||
|
||||
gojson `github.com/goccy/go-json`
|
||||
|
|
@ -26,6 +29,44 @@ import (
|
|||
`github.com/stretchr/testify/require`
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
go func () {
|
||||
println("Begin GC looping...")
|
||||
for {
|
||||
runtime.GC()
|
||||
debug.FreeOSMemory()
|
||||
}
|
||||
println("stop GC looping!")
|
||||
}()
|
||||
m.Run()
|
||||
}
|
||||
|
||||
func TestGC(t *testing.T) {
|
||||
out, err := Encode(_GenericValue, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
n := len(out)
|
||||
wg := &sync.WaitGroup{}
|
||||
N := 10000
|
||||
for i:=0; i<N; i++ {
|
||||
wg.Add(1)
|
||||
go func (wg *sync.WaitGroup, size int) {
|
||||
defer wg.Done()
|
||||
out, err := Encode(_GenericValue, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(out) != size {
|
||||
t.Fatal(len(out), size)
|
||||
}
|
||||
runtime.GC()
|
||||
debug.FreeOSMemory()
|
||||
}(wg, n)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func runEncoderTest(t *testing.T, fn func(string)string, exp string, arg string) {
|
||||
require.Equal(t, exp, fn(arg))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ package encoder
|
|||
|
||||
import (
|
||||
`bytes`
|
||||
`errors`
|
||||
`runtime`
|
||||
`sync`
|
||||
`unsafe`
|
||||
|
||||
|
|
@ -56,6 +58,24 @@ type _Encoder func(
|
|||
fv uint64,
|
||||
) error
|
||||
|
||||
var errCallShadow = errors.New("DON'T CALL THIS!")
|
||||
|
||||
// Faker func of _Encoder, used to export its stackmap as _Encoder's
|
||||
//go:nosplit
|
||||
func _Encoder_Shadow(rb *[]byte, vp unsafe.Pointer, sb *_Stack, fv uint64) error {
|
||||
// align to assembler_amd64.go: _FP_offs
|
||||
var frames [_FP_offs]byte
|
||||
runtime.KeepAlive(frames)
|
||||
|
||||
// must keep sb noticeable to GC
|
||||
runtime.KeepAlive(sb)
|
||||
runtime.KeepAlive(rb)
|
||||
runtime.KeepAlive(vp)
|
||||
|
||||
return errCallShadow
|
||||
}
|
||||
|
||||
|
||||
func newBytes() []byte {
|
||||
if ret := bytesPool.Get(); ret != nil {
|
||||
return ret.([]byte)
|
||||
|
|
|
|||
|
|
@ -207,6 +207,11 @@ func (self *BaseAssembler) Load(fn string, fp int, args int) loader.Function {
|
|||
return loader.Loader(self.c).Load(fn, fp, args)
|
||||
}
|
||||
|
||||
func (self *BaseAssembler) LoadWithFaker(fn string, fp int, args int, faker interface{}) loader.Function {
|
||||
self.build()
|
||||
return loader.Loader(self.c).LoadWithFaker(fn, fp, args, faker)
|
||||
}
|
||||
|
||||
/** Assembler Stages **/
|
||||
|
||||
func (self *BaseAssembler) init() {
|
||||
|
|
|
|||
0
internal/loader/asm.s
Normal file
0
internal/loader/asm.s
Normal file
|
|
@ -18,7 +18,8 @@ package loader
|
|||
|
||||
import (
|
||||
`sync`
|
||||
_ `unsafe`
|
||||
`unsafe`
|
||||
`reflect`
|
||||
)
|
||||
|
||||
//go:linkname lastmoduledatap runtime.lastmoduledatap
|
||||
|
|
@ -28,8 +29,24 @@ var lastmoduledatap *_ModuleData
|
|||
//go:linkname moduledataverify1 runtime.moduledataverify1
|
||||
func moduledataverify1(_ *_ModuleData)
|
||||
|
||||
//go:nosplit
|
||||
func no_pointers_stackmap() uintptr
|
||||
// PCDATA and FUNCDATA table indexes.
|
||||
//
|
||||
// See funcdata.h and $GROOT/src/cmd/internal/objabi/funcdata.go.
|
||||
const (
|
||||
_FUNCDATA_ArgsPointerMaps = 0
|
||||
_FUNCDATA_LocalsPointerMaps = 1
|
||||
)
|
||||
|
||||
type funcInfo struct {
|
||||
*_Func
|
||||
datap *_ModuleData
|
||||
}
|
||||
|
||||
//go:linkname findfunc runtime.findfunc
|
||||
func findfunc(pc uintptr) funcInfo
|
||||
|
||||
//go:linkname funcdata runtime.funcdata
|
||||
func funcdata(f funcInfo, i uint8) unsafe.Pointer
|
||||
|
||||
var (
|
||||
modLock sync.Mutex
|
||||
|
|
@ -64,3 +81,12 @@ func registerModule(mod *_ModuleData) {
|
|||
lastmoduledatap = mod
|
||||
modLock.Unlock()
|
||||
}
|
||||
|
||||
func stackMap(f interface{}) (args uintptr, locals uintptr) {
|
||||
fv := reflect.ValueOf(f)
|
||||
if fv.Kind() != reflect.Func {
|
||||
panic("f must be reflect.Func kind!")
|
||||
}
|
||||
fi := findfunc(fv.Pointer())
|
||||
return uintptr(funcdata(fi, uint8(_FUNCDATA_ArgsPointerMaps))), uintptr(funcdata(fi, uint8(_FUNCDATA_LocalsPointerMaps)))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ var findFuncTab = &_FindFuncBucket {
|
|||
idx: 1,
|
||||
}
|
||||
|
||||
func registerFunction(name string, pc uintptr, fp int, args int, size uintptr) {
|
||||
func registerFunction(name string, pc uintptr, fp int, args int, size uintptr, argptrs uintptr, localptrs uintptr) {
|
||||
minpc := pc
|
||||
maxpc := pc + size
|
||||
|
||||
|
|
@ -127,8 +127,8 @@ func registerFunction(name string, pc uintptr, fp int, args int, size uintptr) {
|
|||
args : int32(args),
|
||||
pcsp : int32(pcsp),
|
||||
nfuncdata : 2,
|
||||
argptrs : no_pointers_stackmap(),
|
||||
localptrs : no_pointers_stackmap(),
|
||||
argptrs : argptrs,
|
||||
localptrs : localptrs,
|
||||
}
|
||||
|
||||
/* align the func to 8 bytes */
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
func registerFunction(name string, pc uintptr, fp int, args int, size uintptr, argptrs uintptr, localptrs uintptr) {
|
||||
minpc := pc
|
||||
maxpc := pc + size
|
||||
|
||||
|
|
@ -137,8 +137,8 @@ func registerFunction(name string, pc uintptr, fp int, args int, size uintptr) {
|
|||
args : int32(args),
|
||||
pcsp : 1,
|
||||
nfuncdata : 2,
|
||||
argptrs : no_pointers_stackmap(),
|
||||
localptrs : no_pointers_stackmap(),
|
||||
argptrs : argptrs,
|
||||
localptrs : localptrs,
|
||||
}}
|
||||
|
||||
/* function table */
|
||||
|
|
|
|||
|
|
@ -33,14 +33,15 @@ const (
|
|||
type Loader []byte
|
||||
type Function unsafe.Pointer
|
||||
|
||||
func (self Loader) Load(fn string, fp int, args int) (f Function) {
|
||||
func (self Loader) LoadWithFaker(fn string, fp int, args int, faker interface{}) (f Function) {
|
||||
p := os.Getpagesize()
|
||||
n := (((len(self) - 1) / p) + 1) * p
|
||||
|
||||
/* register the function */
|
||||
m := mmap(n)
|
||||
v := fmt.Sprintf("__%s_%x", fn, m)
|
||||
registerFunction(v, m, fp, args, uintptr(len(self)))
|
||||
v := fmt.Sprintf("runtime.__%s_%x", fn, m)
|
||||
argsptr, localsptr := stackMap(faker)
|
||||
registerFunction(v, m, fp, args, uintptr(len(self)), argsptr, localsptr)
|
||||
|
||||
/* reference as a slice */
|
||||
s := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader {
|
||||
|
|
@ -55,6 +56,10 @@ func (self Loader) Load(fn string, fp int, args int) (f Function) {
|
|||
return Function(&m)
|
||||
}
|
||||
|
||||
func (self Loader) Load(fn string, fp int, args int) (f Function) {
|
||||
return self.LoadWithFaker(fn, fp, args, func(){})
|
||||
}
|
||||
|
||||
func mmap(nb int) uintptr {
|
||||
if m, _, e := syscall.RawSyscall6(syscall.SYS_MMAP, 0, uintptr(nb), _RW, _AP, 0, 0); e != 0 {
|
||||
panic(e)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,11 @@
|
|||
package loader
|
||||
|
||||
import (
|
||||
`errors`
|
||||
`fmt`
|
||||
`reflect`
|
||||
`runtime`
|
||||
`runtime/debug`
|
||||
`testing`
|
||||
`unsafe`
|
||||
|
||||
|
|
@ -36,3 +40,73 @@ func TestLoader_Load(t *testing.T) {
|
|||
assert.Equal(t, 1234, v0)
|
||||
println(runtime.FuncForPC(*(*uintptr)(fn)).Name())
|
||||
}
|
||||
|
||||
func faker1(in string) error {
|
||||
runtime.KeepAlive(in)
|
||||
return errors.New("1")
|
||||
}
|
||||
|
||||
func faker2(in string) error {
|
||||
runtime.KeepAlive(in)
|
||||
return errors.New("2")
|
||||
}
|
||||
|
||||
func faker4(in string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestStackMap(t *testing.T) {
|
||||
args1, locals1 := stackMap(faker1)
|
||||
fi1 := findfunc(reflect.ValueOf(faker1).Pointer())
|
||||
fmt.Printf("func1: %#v, args: %x, locals: %x\n", fi1, args1, locals1)
|
||||
|
||||
args2, locals2 := stackMap(faker2)
|
||||
fi2 := findfunc(reflect.ValueOf(faker2).Pointer())
|
||||
fmt.Printf("func2: %#v, args: %x, locals: %x\n", fi2, args2, locals2)
|
||||
|
||||
args4, locals4 := stackMap(faker4)
|
||||
fi4 := findfunc(reflect.ValueOf(faker4).Pointer())
|
||||
fmt.Printf("func4: %#v, args: %x, locals: %x\n", fi4, args4, locals4)
|
||||
|
||||
if reflect.DeepEqual(fi1, fi2) || reflect.DeepEqual(fi1, fi2) {
|
||||
t.Fatal()
|
||||
}
|
||||
if args1 != args2 || locals1 != locals2 {
|
||||
t.Fatal()
|
||||
}
|
||||
if args1 == args4 || locals1 == locals4 || args2 == args4 || locals2 == locals4 {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
|
||||
func funcWrap(f func(i *int)) int {
|
||||
var ret int
|
||||
var x int = 0
|
||||
runtime.SetFinalizer(&x, func(xp *int){
|
||||
fmt.Printf("x got dropped: %x\n", unsafe.Pointer(xp))
|
||||
})
|
||||
f(&x)
|
||||
ret = x
|
||||
return ret
|
||||
}
|
||||
|
||||
func TestLoadWithStackMap(t *testing.T) {
|
||||
var f = func(i *int) {
|
||||
*i = 1234
|
||||
}
|
||||
v1 := funcWrap(f)
|
||||
|
||||
bc := []byte {
|
||||
0x48, 0x8b, 0x44, 0x24, 0x08, // MOVQ 8(%rsp), %rax
|
||||
0x48, 0xc7, 0x00, 0xd2, 0x04, 0x00, 0x00, // MOVQ $1234, (%rax)
|
||||
0xc3, // RET
|
||||
}
|
||||
fn := Loader(bc).LoadWithFaker("test", 0, 8, f)
|
||||
f2 := (*(*func(*int))(unsafe.Pointer(&fn)))
|
||||
v2 := funcWrap(f2)
|
||||
|
||||
runtime.GC()
|
||||
debug.FreeOSMemory()
|
||||
println(v1, v2)
|
||||
assert.Equal(t, v1, v2)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#include "go_asm.h"
|
||||
#include "funcdata.h"
|
||||
#include "textflag.h"
|
||||
|
||||
TEXT ·no_pointers_stackmap(SB), NOSPLIT, $0 - 8
|
||||
NO_LOCAL_POINTERS
|
||||
LEAQ runtime·no_pointers_stackmap(SB), AX
|
||||
MOVQ AX, ret+0(FP)
|
||||
RET
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -3,32 +3,27 @@
|
|||
|
||||
package avx
|
||||
|
||||
import (
|
||||
`unsafe`
|
||||
)
|
||||
|
||||
//go:nosplit
|
||||
//go:noescape
|
||||
//goland:noinspection ALL
|
||||
func ___asm2asm_compiled_code__DO_NOT_CALL_THIS_SYMBOL___()
|
||||
func __native_entry__() uintptr
|
||||
|
||||
var (
|
||||
_func__base = ___asm2asm_compiled_code__DO_NOT_CALL_THIS_SYMBOL___
|
||||
_subr__f64toa = **(**uintptr)(unsafe.Pointer(&_func__base)) + 542
|
||||
_subr__i64toa = **(**uintptr)(unsafe.Pointer(&_func__base)) + 3551
|
||||
_subr__lspace = **(**uintptr)(unsafe.Pointer(&_func__base)) + 238
|
||||
_subr__lzero = **(**uintptr)(unsafe.Pointer(&_func__base)) + 0
|
||||
_subr__quote = **(**uintptr)(unsafe.Pointer(&_func__base)) + 4864
|
||||
_subr__skip_array = **(**uintptr)(unsafe.Pointer(&_func__base)) + 16010
|
||||
_subr__skip_object = **(**uintptr)(unsafe.Pointer(&_func__base)) + 16045
|
||||
_subr__skip_one = **(**uintptr)(unsafe.Pointer(&_func__base)) + 14217
|
||||
_subr__u64toa = **(**uintptr)(unsafe.Pointer(&_func__base)) + 3644
|
||||
_subr__unquote = **(**uintptr)(unsafe.Pointer(&_func__base)) + 5885
|
||||
_subr__value = **(**uintptr)(unsafe.Pointer(&_func__base)) + 9700
|
||||
_subr__vnumber = **(**uintptr)(unsafe.Pointer(&_func__base)) + 12411
|
||||
_subr__vsigned = **(**uintptr)(unsafe.Pointer(&_func__base)) + 13667
|
||||
_subr__vstring = **(**uintptr)(unsafe.Pointer(&_func__base)) + 11458
|
||||
_subr__vunsigned = **(**uintptr)(unsafe.Pointer(&_func__base)) + 13944
|
||||
_subr__f64toa = __native_entry__() + 630
|
||||
_subr__i64toa = __native_entry__() + 3642
|
||||
_subr__lspace = __native_entry__() + 301
|
||||
_subr__lzero = __native_entry__() + 13
|
||||
_subr__quote = __native_entry__() + 4955
|
||||
_subr__skip_array = __native_entry__() + 17298
|
||||
_subr__skip_object = __native_entry__() + 17333
|
||||
_subr__skip_one = __native_entry__() + 15505
|
||||
_subr__u64toa = __native_entry__() + 3735
|
||||
_subr__unquote = __native_entry__() + 5888
|
||||
_subr__value = __native_entry__() + 10928
|
||||
_subr__vnumber = __native_entry__() + 13704
|
||||
_subr__vsigned = __native_entry__() + 14977
|
||||
_subr__vstring = __native_entry__() + 12691
|
||||
_subr__vunsigned = __native_entry__() + 15236
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -3,32 +3,27 @@
|
|||
|
||||
package avx2
|
||||
|
||||
import (
|
||||
`unsafe`
|
||||
)
|
||||
|
||||
//go:nosplit
|
||||
//go:noescape
|
||||
//goland:noinspection ALL
|
||||
func ___asm2asm_compiled_code__DO_NOT_CALL_THIS_SYMBOL___()
|
||||
func __native_entry__() uintptr
|
||||
|
||||
var (
|
||||
_func__base = ___asm2asm_compiled_code__DO_NOT_CALL_THIS_SYMBOL___
|
||||
_subr__f64toa = **(**uintptr)(unsafe.Pointer(&_func__base)) + 790
|
||||
_subr__i64toa = **(**uintptr)(unsafe.Pointer(&_func__base)) + 3799
|
||||
_subr__lspace = **(**uintptr)(unsafe.Pointer(&_func__base)) + 366
|
||||
_subr__lzero = **(**uintptr)(unsafe.Pointer(&_func__base)) + 0
|
||||
_subr__quote = **(**uintptr)(unsafe.Pointer(&_func__base)) + 5212
|
||||
_subr__skip_array = **(**uintptr)(unsafe.Pointer(&_func__base)) + 17881
|
||||
_subr__skip_object = **(**uintptr)(unsafe.Pointer(&_func__base)) + 17916
|
||||
_subr__skip_one = **(**uintptr)(unsafe.Pointer(&_func__base)) + 16135
|
||||
_subr__u64toa = **(**uintptr)(unsafe.Pointer(&_func__base)) + 3892
|
||||
_subr__unquote = **(**uintptr)(unsafe.Pointer(&_func__base)) + 7049
|
||||
_subr__value = **(**uintptr)(unsafe.Pointer(&_func__base)) + 11489
|
||||
_subr__vnumber = **(**uintptr)(unsafe.Pointer(&_func__base)) + 14329
|
||||
_subr__vsigned = **(**uintptr)(unsafe.Pointer(&_func__base)) + 15585
|
||||
_subr__vstring = **(**uintptr)(unsafe.Pointer(&_func__base)) + 13492
|
||||
_subr__vunsigned = **(**uintptr)(unsafe.Pointer(&_func__base)) + 15862
|
||||
_subr__f64toa = __native_entry__() + 903
|
||||
_subr__i64toa = __native_entry__() + 3915
|
||||
_subr__lspace = __native_entry__() + 429
|
||||
_subr__lzero = __native_entry__() + 13
|
||||
_subr__quote = __native_entry__() + 5328
|
||||
_subr__skip_array = __native_entry__() + 20361
|
||||
_subr__skip_object = __native_entry__() + 20396
|
||||
_subr__skip_one = __native_entry__() + 17472
|
||||
_subr__u64toa = __native_entry__() + 4008
|
||||
_subr__unquote = __native_entry__() + 7125
|
||||
_subr__value = __native_entry__() + 13020
|
||||
_subr__vnumber = __native_entry__() + 15671
|
||||
_subr__vsigned = __native_entry__() + 16944
|
||||
_subr__vstring = __native_entry__() + 14794
|
||||
_subr__vunsigned = __native_entry__() + 17203
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit daab6520b48bc30586f7468676c990b5c1f781bd
|
||||
Subproject commit a9988b2b8191ac9b8bc879ff8db18c650753a067
|
||||
Loading…
Reference in a new issue