Merge pull request #165 from goccy/feature/add-debug-mode

Add debug mode
This commit is contained in:
Masaaki Goshima 2021-03-27 13:14:03 +09:00 committed by GitHub
commit ff31b04f58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 4625 additions and 8 deletions

View File

@ -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

View File

@ -17,6 +17,7 @@ linters:
- exhaustive - exhaustive
- exhaustivestruct - exhaustivestruct
- errorlint - errorlint
- forbidigo
- funlen - funlen
- gci - gci
- gochecknoglobals - gochecknoglobals

View File

@ -1,2 +0,0 @@
ignore:
- encode_optype.go

View File

@ -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))
} }

View File

@ -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 }

View File

@ -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,
} }

View File

@ -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,
} }

View File

@ -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,
} }

View File

@ -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
} }

View File

@ -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"
) )

View File

@ -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

View File

@ -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"
) )

View File

@ -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)

View File

@ -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"
) )

View File

@ -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
}
}