mirror of https://github.com/goccy/go-json.git
Merge pull request #165 from goccy/feature/add-debug-mode
Add debug mode
This commit is contained in:
commit
ff31b04f58
|
@ -26,3 +26,6 @@ comment:
|
||||||
layout: "header,diff"
|
layout: "header,diff"
|
||||||
behavior: default
|
behavior: default
|
||||||
require_changes: no
|
require_changes: no
|
||||||
|
|
||||||
|
ignore:
|
||||||
|
- internal/encoder/vm_debug
|
||||||
|
|
|
@ -17,6 +17,7 @@ linters:
|
||||||
- exhaustive
|
- exhaustive
|
||||||
- exhaustivestruct
|
- exhaustivestruct
|
||||||
- errorlint
|
- errorlint
|
||||||
|
- forbidigo
|
||||||
- funlen
|
- funlen
|
||||||
- gci
|
- gci
|
||||||
- gochecknoglobals
|
- gochecknoglobals
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
ignore:
|
|
||||||
- encode_optype.go
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/goccy/go-json/internal/encoder"
|
"github.com/goccy/go-json/internal/encoder"
|
||||||
"github.com/goccy/go-json/internal/encoder/vm"
|
"github.com/goccy/go-json/internal/encoder/vm"
|
||||||
|
"github.com/goccy/go-json/internal/encoder/vm_debug"
|
||||||
"github.com/goccy/go-json/internal/encoder/vm_escaped"
|
"github.com/goccy/go-json/internal/encoder/vm_escaped"
|
||||||
"github.com/goccy/go-json/internal/encoder/vm_escaped_indent"
|
"github.com/goccy/go-json/internal/encoder/vm_escaped_indent"
|
||||||
"github.com/goccy/go-json/internal/encoder/vm_indent"
|
"github.com/goccy/go-json/internal/encoder/vm_indent"
|
||||||
|
@ -31,6 +32,7 @@ const (
|
||||||
EncodeOptionHTMLEscape EncodeOption = 1 << iota
|
EncodeOptionHTMLEscape EncodeOption = 1 << iota
|
||||||
EncodeOptionIndent
|
EncodeOptionIndent
|
||||||
EncodeOptionUnorderedMap
|
EncodeOptionUnorderedMap
|
||||||
|
EncodeOptionDebug
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -272,6 +274,9 @@ func encodeIndent(ctx *encoder.RuntimeContext, v interface{}, prefix, indent str
|
||||||
}
|
}
|
||||||
|
|
||||||
func encodeRunCode(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt EncodeOption) ([]byte, error) {
|
func encodeRunCode(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt EncodeOption) ([]byte, error) {
|
||||||
|
if (opt & EncodeOptionDebug) != 0 {
|
||||||
|
return vm_debug.Run(ctx, b, codeSet, encoder.Option(opt))
|
||||||
|
}
|
||||||
if (opt & EncodeOptionHTMLEscape) != 0 {
|
if (opt & EncodeOptionHTMLEscape) != 0 {
|
||||||
return vm_escaped.Run(ctx, b, codeSet, encoder.Option(opt))
|
return vm_escaped.Run(ctx, b, codeSet, encoder.Option(opt))
|
||||||
}
|
}
|
||||||
|
|
|
@ -410,6 +410,22 @@ func Test_Marshal(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type mustErrTypeForDebug struct{}
|
||||||
|
|
||||||
|
func (mustErrTypeForDebug) MarshalJSON() ([]byte, error) {
|
||||||
|
panic("panic")
|
||||||
|
return nil, fmt.Errorf("panic")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDebugMode(t *testing.T) {
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err == nil {
|
||||||
|
t.Fatal("expected error")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
json.MarshalWithOption(mustErrTypeForDebug{}, json.Debug())
|
||||||
|
}
|
||||||
|
|
||||||
func TestIssue116(t *testing.T) {
|
func TestIssue116(t *testing.T) {
|
||||||
t.Run("first", func(t *testing.T) {
|
t.Run("first", func(t *testing.T) {
|
||||||
type Boo struct{ B string }
|
type Boo struct{ B string }
|
||||||
|
|
|
@ -65,6 +65,7 @@ func compileToGetCodeSetSlowPath(typeptr uintptr) (*OpcodeSet, error) {
|
||||||
code = copyOpcode(code)
|
code = copyOpcode(code)
|
||||||
codeLength := code.TotalLength()
|
codeLength := code.TotalLength()
|
||||||
codeSet := &OpcodeSet{
|
codeSet := &OpcodeSet{
|
||||||
|
Type: copiedType,
|
||||||
Code: code,
|
Code: code,
|
||||||
CodeLength: codeLength,
|
CodeLength: codeLength,
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ func CompileToGetCodeSet(typeptr uintptr) (*OpcodeSet, error) {
|
||||||
code = copyOpcode(code)
|
code = copyOpcode(code)
|
||||||
codeLength := code.TotalLength()
|
codeLength := code.TotalLength()
|
||||||
codeSet := &OpcodeSet{
|
codeSet := &OpcodeSet{
|
||||||
|
Type: copiedType,
|
||||||
Code: code,
|
Code: code,
|
||||||
CodeLength: codeLength,
|
CodeLength: codeLength,
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ func CompileToGetCodeSet(typeptr uintptr) (*OpcodeSet, error) {
|
||||||
code = copyOpcode(code)
|
code = copyOpcode(code)
|
||||||
codeLength := code.TotalLength()
|
codeLength := code.TotalLength()
|
||||||
codeSet := &OpcodeSet{
|
codeSet := &OpcodeSet{
|
||||||
|
Type: copiedType,
|
||||||
Code: code,
|
Code: code,
|
||||||
CodeLength: codeLength,
|
CodeLength: codeLength,
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,6 +130,7 @@ func (t OpType) IsMultipleOpField() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
type OpcodeSet struct {
|
type OpcodeSet struct {
|
||||||
|
Type *runtime.Type
|
||||||
Code *Opcode
|
Code *Opcode
|
||||||
CodeLength int
|
CodeLength int
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,9 @@ import (
|
||||||
"github.com/goccy/go-json/internal/runtime"
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
|
||||||
// HACK: compile order
|
// HACK: compile order
|
||||||
// `vm`, `vm_escaped`, `vm_indent`, `vm_escaped_indent` packages uses a lot of memory to compile,
|
// `vm`, `vm_escaped`, `vm_indent`, `vm_escaped_indent`, `vm_debug` packages uses a lot of memory to compile,
|
||||||
// so forcibly make dependencies and avoid compiling in concurrent.
|
// so forcibly make dependencies and avoid compiling in concurrent.
|
||||||
// dependency order: vm => vm_escaped => vm_indent => vm_escaped_indent
|
// dependency order: vm => vm_escaped => vm_indent => vm_escaped_indent => vm_debug
|
||||||
_ "github.com/goccy/go-json/internal/encoder/vm_escaped"
|
_ "github.com/goccy/go-json/internal/encoder/vm_escaped"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
package vm_debug
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json/internal/encoder"
|
||||||
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
func load(base uintptr, idx uintptr) uintptr {
|
||||||
|
addr := base + idx
|
||||||
|
return **(**uintptr)(unsafe.Pointer(&addr))
|
||||||
|
}
|
||||||
|
|
||||||
|
func store(base uintptr, idx uintptr, p uintptr) {
|
||||||
|
addr := base + idx
|
||||||
|
**(**uintptr)(unsafe.Pointer(&addr)) = p
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadNPtr(base uintptr, idx uintptr, ptrNum int) uintptr {
|
||||||
|
addr := base + idx
|
||||||
|
p := **(**uintptr)(unsafe.Pointer(&addr))
|
||||||
|
for i := 0; i < ptrNum; i++ {
|
||||||
|
if p == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
p = ptrToPtr(p)
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func ptrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToBytes(p uintptr) []byte { return **(**[]byte)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToNumber(p uintptr) json.Number { return **(**json.Number)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToString(p uintptr) string { return **(**string)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToSlice(p uintptr) *runtime.SliceHeader { return *(**runtime.SliceHeader)(unsafe.Pointer(&p)) }
|
||||||
|
func ptrToPtr(p uintptr) uintptr {
|
||||||
|
return uintptr(**(**unsafe.Pointer)(unsafe.Pointer(&p)))
|
||||||
|
}
|
||||||
|
func ptrToNPtr(p uintptr, ptrNum int) uintptr {
|
||||||
|
for i := 0; i < ptrNum; i++ {
|
||||||
|
if p == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
p = ptrToPtr(p)
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func ptrToUnsafePtr(p uintptr) unsafe.Pointer {
|
||||||
|
return *(*unsafe.Pointer)(unsafe.Pointer(&p))
|
||||||
|
}
|
||||||
|
func ptrToInterface(code *encoder.Opcode, p uintptr) interface{} {
|
||||||
|
return *(*interface{})(unsafe.Pointer(&emptyInterface{
|
||||||
|
typ: code.Type,
|
||||||
|
ptr: *(*unsafe.Pointer)(unsafe.Pointer(&p)),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendBool(b []byte, v bool) []byte {
|
||||||
|
if v {
|
||||||
|
return append(b, "true"...)
|
||||||
|
}
|
||||||
|
return append(b, "false"...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendNull(b []byte) []byte {
|
||||||
|
return append(b, "null"...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendComma(b []byte) []byte {
|
||||||
|
return append(b, ',')
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendStructEnd(b []byte) []byte {
|
||||||
|
return append(b, '}', ',')
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -10,9 +10,9 @@ import (
|
||||||
"github.com/goccy/go-json/internal/runtime"
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
|
||||||
// HACK: compile order
|
// HACK: compile order
|
||||||
// `vm`, `vm_escaped`, `vm_indent`, `vm_escaped_indent` packages uses a lot of memory to compile,
|
// `vm`, `vm_escaped`, `vm_indent`, `vm_escaped_indent`, `vm_debug` packages uses a lot of memory to compile,
|
||||||
// so forcibly make dependencies and avoid compiling in concurrent.
|
// so forcibly make dependencies and avoid compiling in concurrent.
|
||||||
// dependency order: vm => vm_escaped => vm_indent => vm_escaped_indent
|
// dependency order: vm => vm_escaped => vm_indent => vm_escaped_indent => vm_debug
|
||||||
_ "github.com/goccy/go-json/internal/encoder/vm_indent"
|
_ "github.com/goccy/go-json/internal/encoder/vm_indent"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,12 @@ import (
|
||||||
|
|
||||||
"github.com/goccy/go-json/internal/encoder"
|
"github.com/goccy/go-json/internal/encoder"
|
||||||
"github.com/goccy/go-json/internal/runtime"
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
|
||||||
|
// HACK: compile order
|
||||||
|
// `vm`, `vm_escaped`, `vm_indent`, `vm_escaped_indent`, `vm_debug` packages uses a lot of memory to compile,
|
||||||
|
// so forcibly make dependencies and avoid compiling in concurrent.
|
||||||
|
// dependency order: vm => vm_escaped => vm_indent => vm_escaped_indent => vm_debug
|
||||||
|
_ "github.com/goccy/go-json/internal/encoder/vm_debug"
|
||||||
)
|
)
|
||||||
|
|
||||||
const uintptrSize = 4 << (^uintptr(0) >> 63)
|
const uintptrSize = 4 << (^uintptr(0) >> 63)
|
||||||
|
|
|
@ -11,9 +11,9 @@ import (
|
||||||
"github.com/goccy/go-json/internal/runtime"
|
"github.com/goccy/go-json/internal/runtime"
|
||||||
|
|
||||||
// HACK: compile order
|
// HACK: compile order
|
||||||
// `vm`, `vm_escaped`, `vm_indent`, `vm_escaped_indent` packages uses a lot of memory to compile,
|
// `vm`, `vm_escaped`, `vm_indent`, `vm_escaped_indent`, `vm_debug` packages uses a lot of memory to compile,
|
||||||
// so forcibly make dependencies and avoid compiling in concurrent.
|
// so forcibly make dependencies and avoid compiling in concurrent.
|
||||||
// dependency order: vm => vm_escaped => vm_indent => vm_escaped_indent
|
// dependency order: vm => vm_escaped => vm_indent => vm_escaped_indent => vm_debug
|
||||||
_ "github.com/goccy/go-json/internal/encoder/vm_escaped_indent"
|
_ "github.com/goccy/go-json/internal/encoder/vm_escaped_indent"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -7,3 +7,9 @@ func UnorderedMap() func(EncodeOption) EncodeOption {
|
||||||
return opt | EncodeOptionUnorderedMap
|
return opt | EncodeOptionUnorderedMap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Debug() func(EncodeOption) EncodeOption {
|
||||||
|
return func(opt EncodeOption) EncodeOption {
|
||||||
|
return opt | EncodeOptionDebug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue