From aca7ac5acc561924afc851a9b3f196dcac1b085a Mon Sep 17 00:00:00 2001 From: "duanyi.aster" Date: Mon, 29 Jan 2024 21:23:36 +0800 Subject: [PATCH 01/17] feat:(encoder) implement encoding on Virtual Machine for AArch64 --- encoder/{encoder_amd64.go => encoder.go} | 2 - encoder/encoder_compat.go | 254 --- go.mod | 7 +- go.sum | 1 - internal/encoder/{ => alg}/mapiter.go | 89 +- internal/encoder/alg/opts.go | 30 + internal/encoder/alg/primitives.go | 95 ++ internal/encoder/{ => alg}/sort.go | 2 +- internal/encoder/{ => alg}/sort_test.go | 2 +- internal/encoder/alg/spec_amd64.go | 172 ++ internal/encoder/alg/spec_compat.go | 153 ++ internal/encoder/{ => alg}/utils.go | 31 +- internal/encoder/asm.s | 0 internal/encoder/asm_stubs_amd64_go116.go | 51 - internal/encoder/assembler_regabi_amd64.go | 1175 ------------- internal/encoder/assembler_stkabi_amd64.go | 1175 ------------- internal/encoder/assembler_test.go | 436 ----- internal/encoder/compiler.go | 1486 +++++++---------- internal/encoder/compiler_test.go | 4 +- internal/encoder/debug_go117.go | 205 --- internal/encoder/encoder.go | 143 +- internal/encoder/encoder_test.go | 117 +- internal/encoder/ir/op.go | 448 +++++ internal/encoder/pools.go | 193 --- internal/encoder/pools_amd64.go | 92 + internal/encoder/pools_compt.go | 23 + internal/encoder/primitives.go | 170 -- internal/encoder/stream.go | 19 +- internal/encoder/stubs_go116.go | 65 - internal/encoder/stubs_go117.go | 66 - internal/encoder/stubs_go120.go | 66 - internal/encoder/stubs_go121.go | 66 - internal/encoder/vars/cache.go | 48 + internal/encoder/vars/const.go | 42 + internal/encoder/{ => vars}/errors.go | 18 +- internal/encoder/vars/stack.go | 141 ++ internal/encoder/{ => vars}/types.go | 20 +- internal/encoder/vm/stbus.go | 48 + internal/encoder/vm/vm.go | 458 +++++ internal/encoder/vm/vm_test.go | 67 + .../{ => x86}/asm_stubs_amd64_go117.go | 20 +- .../{ => x86}/asm_stubs_amd64_go121.go | 20 +- .../encoder/x86/assembler_regabi_amd64.go | 1182 +++++++++++++ internal/encoder/x86/assembler_test.go | 361 ++++ internal/encoder/{ => x86}/debug_go116.go | 2 +- internal/encoder/x86/debug_go117.go | 201 +++ internal/encoder/x86/stbus.go | 52 + internal/rt/assertI2I.go | 27 + internal/rt/assertI2I_legacy.go | 27 + internal/rt/fastmem.go | 5 +- internal/rt/fastvalue.go | 227 +-- internal/rt/gcwb.go | 55 +- internal/rt/gcwb_legacy.go | 29 + internal/rt/growslice.go | 27 + internal/rt/growslice_legacy.go | 27 + internal/rt/stubs.go | 40 + .../testdata_test.go => testdata/twitter.go | 2 +- utf8/{utf8.go => utf8_amd64.go} | 0 utf8/utf8_compat.go | 48 + 59 files changed, 4838 insertions(+), 5194 deletions(-) rename encoder/{encoder_amd64.go => encoder.go} (99%) delete mode 100644 encoder/encoder_compat.go rename internal/encoder/{ => alg}/mapiter.go (52%) create mode 100644 internal/encoder/alg/opts.go create mode 100644 internal/encoder/alg/primitives.go rename internal/encoder/{ => alg}/sort.go (99%) rename internal/encoder/{ => alg}/sort_test.go (99%) create mode 100644 internal/encoder/alg/spec_amd64.go create mode 100644 internal/encoder/alg/spec_compat.go rename internal/encoder/{ => alg}/utils.go (54%) delete mode 100644 internal/encoder/asm.s delete mode 100644 internal/encoder/asm_stubs_amd64_go116.go delete mode 100644 internal/encoder/assembler_regabi_amd64.go delete mode 100644 internal/encoder/assembler_stkabi_amd64.go delete mode 100644 internal/encoder/assembler_test.go delete mode 100644 internal/encoder/debug_go117.go create mode 100644 internal/encoder/ir/op.go delete mode 100644 internal/encoder/pools.go create mode 100644 internal/encoder/pools_amd64.go create mode 100644 internal/encoder/pools_compt.go delete mode 100644 internal/encoder/primitives.go delete mode 100644 internal/encoder/stubs_go116.go delete mode 100644 internal/encoder/stubs_go117.go delete mode 100644 internal/encoder/stubs_go120.go delete mode 100644 internal/encoder/stubs_go121.go create mode 100644 internal/encoder/vars/cache.go create mode 100644 internal/encoder/vars/const.go rename internal/encoder/{ => vars}/errors.go (77%) create mode 100644 internal/encoder/vars/stack.go rename internal/encoder/{ => vars}/types.go (63%) create mode 100644 internal/encoder/vm/stbus.go create mode 100644 internal/encoder/vm/vm.go create mode 100644 internal/encoder/vm/vm_test.go rename internal/encoder/{ => x86}/asm_stubs_amd64_go117.go (74%) rename internal/encoder/{ => x86}/asm_stubs_amd64_go121.go (73%) create mode 100644 internal/encoder/x86/assembler_regabi_amd64.go create mode 100644 internal/encoder/x86/assembler_test.go rename internal/encoder/{ => x86}/debug_go116.go (99%) create mode 100644 internal/encoder/x86/debug_go117.go create mode 100644 internal/encoder/x86/stbus.go create mode 100644 internal/rt/assertI2I.go create mode 100644 internal/rt/assertI2I_legacy.go create mode 100644 internal/rt/gcwb_legacy.go create mode 100644 internal/rt/growslice.go create mode 100644 internal/rt/growslice_legacy.go create mode 100644 internal/rt/stubs.go rename internal/encoder/testdata_test.go => testdata/twitter.go (99%) rename utf8/{utf8.go => utf8_amd64.go} (100%) create mode 100644 utf8/utf8_compat.go diff --git a/encoder/encoder_amd64.go b/encoder/encoder.go similarity index 99% rename from encoder/encoder_amd64.go rename to encoder/encoder.go index 1cbef7b24..fedb79978 100644 --- a/encoder/encoder_amd64.go +++ b/encoder/encoder.go @@ -1,5 +1,3 @@ -// +build amd64,go1.16,!go1.22 - /* * Copyright 2023 ByteDance Inc. * diff --git a/encoder/encoder_compat.go b/encoder/encoder_compat.go deleted file mode 100644 index 2d3cb27a9..000000000 --- a/encoder/encoder_compat.go +++ /dev/null @@ -1,254 +0,0 @@ -// +build !amd64 !go1.16 go1.22 - -/* -* Copyright 2023 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 ( - `io` - `bytes` - `encoding/json` - `reflect` - - `github.com/bytedance/sonic/option` -) - -func init() { - println("WARNING: sonic only supports Go1.16~1.21 && CPU amd64, but your environment is not suitable") -} - -// Options is a set of encoding options. -type Options uint64 - -const ( - bitSortMapKeys = iota - bitEscapeHTML - bitCompactMarshaler - bitNoQuoteTextMarshaler - bitNoNullSliceOrMap - bitValidateString - bitNoValidateJSONMarshaler - bitNoEncoderNewline - - // used for recursive compile - bitPointerValue = 63 -) - -const ( - // SortMapKeys indicates that the keys of a map needs to be sorted - // before serializing into JSON. - // WARNING: This hurts performance A LOT, USE WITH CARE. - SortMapKeys Options = 1 << bitSortMapKeys - - // EscapeHTML indicates encoder to escape all HTML characters - // after serializing into JSON (see https://pkg.go.dev/encoding/json#HTMLEscape). - // WARNING: This hurts performance A LOT, USE WITH CARE. - EscapeHTML Options = 1 << bitEscapeHTML - - // CompactMarshaler indicates that the output JSON from json.Marshaler - // is always compact and needs no validation - CompactMarshaler Options = 1 << bitCompactMarshaler - - // NoQuoteTextMarshaler indicates that the output text from encoding.TextMarshaler - // is always escaped string and needs no quoting - NoQuoteTextMarshaler Options = 1 << bitNoQuoteTextMarshaler - - // NoNullSliceOrMap indicates all empty Array or Object are encoded as '[]' or '{}', - // instead of 'null' - NoNullSliceOrMap Options = 1 << bitNoNullSliceOrMap - - // ValidateString indicates that encoder should validate the input string - // before encoding it into JSON. - ValidateString Options = 1 << bitValidateString - - // NoValidateJSONMarshaler indicates that the encoder should not validate the output string - // after encoding the JSONMarshaler to JSON. - NoValidateJSONMarshaler Options = 1 << bitNoValidateJSONMarshaler - - // NoEncoderNewline indicates that the encoder should not add a newline after every message - NoEncoderNewline Options = 1 << bitNoEncoderNewline - - // CompatibleWithStd is used to be compatible with std encoder. - CompatibleWithStd Options = SortMapKeys | EscapeHTML | CompactMarshaler -) - -// Encoder represents a specific set of encoder configurations. -type Encoder struct { - Opts Options - prefix string - indent string -} - -// Encode returns the JSON encoding of v. -func (self *Encoder) Encode(v interface{}) ([]byte, error) { - if self.indent != "" || self.prefix != "" { - return EncodeIndented(v, self.prefix, self.indent, self.Opts) - } - return Encode(v, self.Opts) -} - -// SortKeys enables the SortMapKeys option. -func (self *Encoder) SortKeys() *Encoder { - self.Opts |= SortMapKeys - return self -} - -// SetEscapeHTML specifies if option EscapeHTML opens -func (self *Encoder) SetEscapeHTML(f bool) { - if f { - self.Opts |= EscapeHTML - } else { - self.Opts &= ^EscapeHTML - } -} - -// SetValidateString specifies if option ValidateString opens -func (self *Encoder) SetValidateString(f bool) { - if f { - self.Opts |= ValidateString - } else { - self.Opts &= ^ValidateString - } -} - -// SetNoValidateJSONMarshaler specifies if option NoValidateJSONMarshaler opens -func (self *Encoder) SetNoValidateJSONMarshaler(f bool) { - if f { - self.Opts |= NoValidateJSONMarshaler - } else { - self.Opts &= ^NoValidateJSONMarshaler - } -} - -// SetNoEncoderNewline specifies if option NoEncoderNewline opens -func (self *Encoder) SetNoEncoderNewline(f bool) { - if f { - self.Opts |= NoEncoderNewline - } else { - self.Opts &= ^NoEncoderNewline - } -} - -// SetCompactMarshaler specifies if option CompactMarshaler opens -func (self *Encoder) SetCompactMarshaler(f bool) { - if f { - self.Opts |= CompactMarshaler - } else { - self.Opts &= ^CompactMarshaler - } -} - -// SetNoQuoteTextMarshaler specifies if option NoQuoteTextMarshaler opens -func (self *Encoder) SetNoQuoteTextMarshaler(f bool) { - if f { - self.Opts |= NoQuoteTextMarshaler - } else { - self.Opts &= ^NoQuoteTextMarshaler - } -} - -// SetIndent instructs the encoder to format each subsequent encoded -// value as if indented by the package-level function EncodeIndent(). -// Calling SetIndent("", "") disables indentation. -func (enc *Encoder) SetIndent(prefix, indent string) { - enc.prefix = prefix - enc.indent = indent -} - -// Quote returns the JSON-quoted version of s. -func Quote(s string) string { - /* check for empty string */ - if s == "" { - return `""` - } - - out, _ := json.Marshal(s) - return string(out) -} - -// Encode returns the JSON encoding of val, encoded with opts. -func Encode(val interface{}, opts Options) ([]byte, error) { - return json.Marshal(val) -} - -// EncodeInto is like Encode but uses a user-supplied buffer instead of allocating -// a new one. -func EncodeInto(buf *[]byte, val interface{}, opts Options) error { - if buf == nil { - panic("user-supplied buffer buf is nil") - } - w := bytes.NewBuffer(*buf) - enc := json.NewEncoder(w) - enc.SetEscapeHTML((opts & EscapeHTML) != 0) - err := enc.Encode(val) - *buf = w.Bytes() - return err -} - -// HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029 -// characters inside string literals changed to \u003c, \u003e, \u0026, \u2028, \u2029 -// so that the JSON will be safe to embed inside HTML