From 7884f41f49ac7cc52c051d8f541b00135e70bdaf Mon Sep 17 00:00:00 2001 From: Moses Narrow Date: Sat, 19 Oct 2024 12:02:37 -0500 Subject: [PATCH 1/4] update all code deps --- go.mod | 70 +- go.sum | 189 +- .../VictoriaMetrics/metrics/README.md | 5 +- .../VictoriaMetrics/metrics/counter.go | 9 + .../VictoriaMetrics/metrics/floatcounter.go | 4 + .../VictoriaMetrics/metrics/gauge.go | 67 +- .../VictoriaMetrics/metrics/go_metrics.go | 186 +- .../VictoriaMetrics/metrics/histogram.go | 42 +- .../VictoriaMetrics/metrics/metrics.go | 142 +- .../metrics/process_metrics_linux.go | 49 +- .../metrics/process_metrics_windows.go | 25 +- .../VictoriaMetrics/metrics/push.go | 441 +- .../github.com/VictoriaMetrics/metrics/set.go | 47 +- .../VictoriaMetrics/metrics/summary.go | 8 + vendor/github.com/bitfield/script/README.md | 50 +- vendor/github.com/bitfield/script/script.go | 112 +- vendor/github.com/bytedance/sonic/.gitignore | 5 +- vendor/github.com/bytedance/sonic/.gitmodules | 7 +- vendor/github.com/bytedance/sonic/Makefile | 111 - vendor/github.com/bytedance/sonic/README.md | 112 +- .../bytedance/sonic/README_ZH_CN.md | 91 +- vendor/github.com/bytedance/sonic/api.go | 76 +- .../sonic/ast/{api_amd64.go => api.go} | 52 +- .../bytedance/sonic/ast/api_compat.go | 82 +- .../github.com/bytedance/sonic/ast/buffer.go | 223 +- .../github.com/bytedance/sonic/ast/decode.go | 44 +- .../github.com/bytedance/sonic/ast/encode.go | 87 +- .../github.com/bytedance/sonic/ast/error.go | 6 +- .../bytedance/sonic/ast/iterator.go | 35 +- vendor/github.com/bytedance/sonic/ast/node.go | 677 +- .../github.com/bytedance/sonic/ast/parser.go | 151 +- .../github.com/bytedance/sonic/ast/search.go | 127 + .../github.com/bytedance/sonic/ast/stubs.go | 142 + .../bytedance/sonic/ast/stubs_go115.go | 55 - .../bytedance/sonic/ast/stubs_go120.go | 55 - .../github.com/bytedance/sonic/ast/visitor.go | 47 +- vendor/github.com/bytedance/sonic/compat.go | 4 +- .../bytedance/sonic/decoder/decoder_compat.go | 10 +- .../{decoder_amd64.go => decoder_native.go} | 37 +- .../bytedance/sonic/encoder/encoder_compat.go | 56 +- .../{encoder_amd64.go => encoder_native.go} | 14 +- vendor/github.com/bytedance/sonic/go.work | 5 +- vendor/github.com/bytedance/sonic/go.work.sum | 1 + .../sonic/internal/base64/b64_amd64.go | 46 + .../sonic/internal/base64/b64_compat.go | 44 + .../bytedance/sonic/internal/cpu/features.go | 4 +- .../internal/decoder/{ => api}/decoder.go | 136 +- .../internal/decoder/api/decoder_amd64.go | 38 + .../internal/decoder/api/decoder_arm64.go | 38 + .../internal/decoder/{ => api}/stream.go | 198 +- .../internal/decoder/asm_stubs_amd64_go116.go | 130 - .../decoder/assembler_stkabi_amd64.go | 1949 -- .../sonic/internal/decoder/consts/option.go | 36 + .../internal/decoder/{ => errors}/errors.go | 16 +- .../internal/decoder/generic_stkabi_amd64.go | 733 - .../sonic/internal/decoder/{ => jitdec}/asm.s | 0 .../{ => jitdec}/asm_stubs_amd64_go117.go | 2 +- .../{ => jitdec}/asm_stubs_amd64_go121.go | 5 +- .../{ => jitdec}/assembler_regabi_amd64.go | 111 +- .../internal/decoder/{ => jitdec}/compiler.go | 144 +- .../internal/decoder/{ => jitdec}/debug.go | 2 +- .../sonic/internal/decoder/jitdec/decoder.go | 140 + .../{ => jitdec}/generic_regabi_amd64.go | 8 +- .../{ => jitdec}/generic_regabi_amd64_test.s | 2 +- .../internal/decoder/{ => jitdec}/pools.go | 4 +- .../decoder/{ => jitdec}/primitives.go | 11 +- .../decoder/{ => jitdec}/stubs_go116.go | 13 +- .../decoder/{ => jitdec}/stubs_go120.go | 11 +- .../internal/decoder/{ => jitdec}/types.go | 2 +- .../internal/decoder/{ => jitdec}/utils.go | 2 +- .../internal/decoder/optdec/compile_struct.go | 174 + .../sonic/internal/decoder/optdec/compiler.go | 449 + .../sonic/internal/decoder/optdec/const.go | 60 + .../sonic/internal/decoder/optdec/context.go | 3 + .../sonic/internal/decoder/optdec/decoder.go | 160 + .../sonic/internal/decoder/optdec/errors.go | 73 + .../sonic/internal/decoder/optdec/functor.go | 281 + .../sonic/internal/decoder/optdec/helper.go | 101 + .../internal/decoder/optdec/interface.go | 169 + .../sonic/internal/decoder/optdec/map.go | 430 + .../sonic/internal/decoder/optdec/native.go | 269 + .../sonic/internal/decoder/optdec/node.go | 1279 ++ .../sonic/internal/decoder/optdec/slice.go | 224 + .../internal/decoder/optdec/stringopts.go | 360 + .../sonic/internal/decoder/optdec/structs.go | 61 + .../sonic/internal/decoder/optdec/types.go | 60 + .../internal/encoder/{ => alg}/mapiter.go | 89 +- .../sonic/internal/encoder/alg/opts.go | 31 + .../sonic/internal/encoder/alg/primitives.go | 95 + .../sonic/internal/encoder/{ => alg}/sort.go | 2 +- .../sonic/internal/encoder/alg/spec.go | 198 + .../sonic/internal/encoder/alg/spec_compat.go | 148 + .../internal/encoder/asm_stubs_amd64_go116.go | 51 - .../encoder/assembler_regabi_amd64.go | 1177 -- .../encoder/assembler_stkabi_amd64.go | 1175 -- .../sonic/internal/encoder/compiler.go | 1517 +- .../sonic/internal/encoder/debug_go117.go | 205 - .../sonic/internal/encoder/encode_norace.go | 24 + .../sonic/internal/encoder/encode_race.go | 54 + .../sonic/internal/encoder/encoder.go | 191 +- .../bytedance/sonic/internal/encoder/ir/op.go | 473 + .../bytedance/sonic/internal/encoder/pools.go | 193 - .../sonic/internal/encoder/pools_amd64.go | 97 + .../sonic/internal/encoder/pools_compt.go | 24 + .../sonic/internal/encoder/primitives.go | 168 - .../sonic/internal/encoder/stream.go | 35 +- .../sonic/internal/encoder/stubs_go116.go | 65 - .../sonic/internal/encoder/stubs_go117.go | 66 - .../sonic/internal/encoder/stubs_go120.go | 66 - .../sonic/internal/encoder/stubs_go121.go | 66 - .../sonic/internal/encoder/vars/cache.go | 48 + .../sonic/internal/encoder/vars/const.go | 42 + .../internal/encoder/{ => vars}/errors.go | 20 +- .../sonic/internal/encoder/vars/stack.go | 146 + .../internal/encoder/{ => vars}/types.go | 20 +- .../sonic/internal/encoder/vm/stbus.go | 45 + .../bytedance/sonic/internal/encoder/vm/vm.go | 374 + .../{ => x86}/asm_stubs_amd64_go117.go | 20 +- .../{ => x86}/asm_stubs_amd64_go121.go | 22 +- .../encoder/x86/assembler_regabi_amd64.go | 1194 ++ .../internal/encoder/{ => x86}/debug_go116.go | 4 +- .../sonic/internal/encoder/x86/debug_go117.go | 201 + .../sonic/internal/encoder/x86/stbus.go | 54 + .../bytedance/sonic/internal/envs/decode.go | 24 + .../sonic/internal/jit/assembler_amd64.go | 12 - .../bytedance/sonic/internal/jit/runtime.go | 7 +- .../sonic/internal/native/avx/native_amd64.go | 191 - .../internal/native/avx/native_subr_amd64.go | 603 - .../internal/native/avx/native_text_amd64.go | 14075 -------------- .../sonic/internal/native/avx2/f32toa.go | 35 + .../sonic/internal/native/avx2/f32toa_subr.go | 46 + .../internal/native/avx2/f32toa_text_amd64.go | 1063 ++ .../sonic/internal/native/avx2/f64toa.go | 35 + .../sonic/internal/native/avx2/f64toa_subr.go | 46 + .../internal/native/avx2/f64toa_text_amd64.go | 2497 +++ .../sonic/internal/native/avx2/get_by_path.go | 35 + .../internal/native/avx2/get_by_path_subr.go | 46 + .../native/avx2/get_by_path_text_amd64.go | 6241 +++++++ .../sonic/internal/native/avx2/html_escape.go | 34 + .../internal/native/avx2/html_escape_subr.go | 45 + .../native/avx2/html_escape_text_amd64.go | 833 + .../sonic/internal/native/avx2/i64toa.go | 35 + .../sonic/internal/native/avx2/i64toa_subr.go | 47 + .../internal/native/avx2/i64toa_text_amd64.go | 631 + .../internal/native/avx2/lookup_small_key.go | 37 + .../native/avx2/lookup_small_key_subr.go | 45 + .../avx2/lookup_small_key_text_amd64.go | 216 + .../sonic/internal/native/avx2/lspace.go | 35 + .../sonic/internal/native/avx2/lspace_subr.go | 38 + .../internal/native/avx2/lspace_text_amd64.go | 113 + .../internal/native/avx2/native_amd64.go | 191 - .../internal/native/avx2/native_export.go | 51 + .../internal/native/avx2/native_subr_amd64.go | 610 - .../internal/native/avx2/native_text_amd64.go | 14800 --------------- .../native/avx2/parse_with_padding.go | 36 + .../native/avx2/parse_with_padding_subr.go | 46 + .../avx2/parse_with_padding_text_amd64.go | 15284 ++++++++++++++++ .../sonic/internal/native/avx2/quote.go | 33 + .../sonic/internal/native/avx2/quote_subr.go | 46 + .../internal/native/avx2/quote_text_amd64.go | 1349 ++ .../sonic/internal/native/avx2/skip_array.go | 35 + .../internal/native/avx2/skip_array_subr.go | 46 + .../native/avx2/skip_array_text_amd64.go | 4348 +++++ .../sonic/internal/native/avx2/skip_number.go | 34 + .../internal/native/avx2/skip_number_subr.go | 46 + .../native/avx2/skip_number_text_amd64.go | 494 + .../sonic/internal/native/avx2/skip_object.go | 35 + .../internal/native/avx2/skip_object_subr.go | 46 + .../native/avx2/skip_object_text_amd64.go | 4348 +++++ .../sonic/internal/native/avx2/skip_one.go | 35 + .../internal/native/avx2/skip_one_fast.go | 35 + .../native/avx2/skip_one_fast_subr.go | 46 + .../native/avx2/skip_one_fast_text_amd64.go | 957 + .../internal/native/avx2/skip_one_subr.go | 46 + .../native/avx2/skip_one_text_amd64.go | 3719 ++++ .../sonic/internal/native/avx2/u64toa.go | 34 + .../sonic/internal/native/avx2/u64toa_subr.go | 39 + .../internal/native/avx2/u64toa_text_amd64.go | 364 + .../sonic/internal/native/avx2/unquote.go | 34 + .../internal/native/avx2/unquote_subr.go | 46 + .../native/avx2/unquote_text_amd64.go | 594 + .../internal/native/avx2/validate_one.go | 35 + .../internal/native/avx2/validate_one_subr.go | 46 + .../native/avx2/validate_one_text_amd64.go | 4348 +++++ .../internal/native/avx2/validate_utf8.go | 37 + .../native/avx2/validate_utf8_fast.go | 34 + .../native/avx2/validate_utf8_fast_subr.go | 42 + .../avx2/validate_utf8_fast_text_amd64.go | 752 + .../native/avx2/validate_utf8_subr.go | 44 + .../native/avx2/validate_utf8_text_amd64.go | 193 + .../sonic/internal/native/avx2/value.go | 33 + .../sonic/internal/native/avx2/value_subr.go | 46 + .../internal/native/avx2/value_text_amd64.go | 5660 ++++++ .../sonic/internal/native/avx2/vnumber.go | 33 + .../internal/native/avx2/vnumber_subr.go | 46 + .../native/avx2/vnumber_text_amd64.go | 4283 +++++ .../sonic/internal/native/avx2/vsigned.go | 33 + .../internal/native/avx2/vsigned_subr.go | 50 + .../native/avx2/vsigned_text_amd64.go | 120 + .../sonic/internal/native/avx2/vstring.go | 33 + .../internal/native/avx2/vstring_subr.go | 46 + .../native/avx2/vstring_text_amd64.go | 505 + .../sonic/internal/native/avx2/vunsigned.go | 33 + .../internal/native/avx2/vunsigned_subr.go | 57 + .../native/avx2/vunsigned_text_amd64.go | 127 + .../sonic/internal/native/dispatch_amd64.go | 171 +- .../sonic/internal/native/dispatch_arm64.go | 169 + .../sonic/internal/native/f32toa.tmpl | 35 + .../sonic/internal/native/f64toa.tmpl | 35 + ...at_amd64_test.tmpl => fastfloat_test.tmpl} | 3 + ...tint_amd64_test.tmpl => fastint_test.tmpl} | 3 + .../sonic/internal/native/get_by_path.tmpl | 35 + .../sonic/internal/native/html_escape.tmpl | 34 + .../sonic/internal/native/i64toa.tmpl | 35 + .../internal/native/lookup_small_key.tmpl | 37 + .../sonic/internal/native/lspace.tmpl | 35 + .../sonic/internal/native/native_amd64.tmpl | 189 - .../sonic/internal/native/native_export.tmpl | 51 + ...ative_amd64_test.tmpl => native_test.tmpl} | 13 +- .../internal/native/neon/f32toa_arm64.go | 29 + .../sonic/internal/native/neon/f32toa_arm64.s | 1019 ++ .../internal/native/neon/f32toa_subr_arm64.go | 25 + .../internal/native/neon/f64toa_arm64.go | 29 + .../sonic/internal/native/neon/f64toa_arm64.s | 2492 +++ .../internal/native/neon/f64toa_subr_arm64.go | 25 + .../internal/native/neon/get_by_path_arm64.go | 33 + .../internal/native/neon/get_by_path_arm64.s | 5627 ++++++ .../native/neon/get_by_path_subr_arm64.go | 25 + .../neon/html_escape_arm64.go} | 35 +- .../internal/native/neon/html_escape_arm64.s | 1406 ++ .../native/neon/html_escape_subr_arm64.go | 25 + .../internal/native/neon/i64toa_arm64.go | 29 + .../sonic/internal/native/neon/i64toa_arm64.s | 985 + .../internal/native/neon/i64toa_subr_arm64.go | 25 + .../native/neon/lookup_small_key_arm64.go | 31 + .../native/neon/lookup_small_key_arm64.s | 354 + .../neon/lookup_small_key_subr_arm64.go | 25 + .../internal/native/neon/lspace_arm64.go | 35 + .../sonic/internal/native/neon/lspace_arm64.s | 68 + .../internal/native/neon/lspace_subr_arm64.go | 25 + .../native/neon/native_export_arm64.go | 51 + .../native/neon/parse_with_padding_arm64.go | 30 + .../native/neon/parse_with_padding_arm64.s | 14122 ++++++++++++++ .../neon/parse_with_padding_subr_arm64.go | 25 + .../sonic/internal/native/neon/quote_arm64.go | 35 + .../sonic/internal/native/neon/quote_arm64.s | 2563 +++ .../internal/native/neon/quote_subr_arm64.go | 25 + .../internal/native/neon/skip_array_arm64.go | 35 + .../internal/native/neon/skip_array_arm64.s | 3481 ++++ .../native/neon/skip_array_subr_arm64.go | 25 + .../internal/native/neon/skip_number_arm64.go | 29 + .../internal/native/neon/skip_number_arm64.s | 373 + .../native/neon/skip_number_subr_arm64.go | 25 + .../internal/native/neon/skip_object_arm64.go | 35 + .../internal/native/neon/skip_object_arm64.s | 3481 ++++ .../native/neon/skip_object_subr_arm64.go | 25 + .../internal/native/neon/skip_one_arm64.go | 35 + .../internal/native/neon/skip_one_arm64.s | 3294 ++++ .../native/neon/skip_one_fast_arm64.go | 29 + .../native/neon/skip_one_fast_arm64.s | 998 + .../native/neon/skip_one_fast_subr_arm64.go | 25 + .../native/neon/skip_one_subr_arm64.go | 25 + .../internal/native/neon/u64toa_arm64.go | 29 + .../sonic/internal/native/neon/u64toa_arm64.s | 598 + .../internal/native/neon/u64toa_subr_arm64.go | 25 + .../internal/native/neon/unquote_arm64.go | 35 + .../internal/native/neon/unquote_arm64.s | 615 + .../native/neon/unquote_subr_arm64.go | 25 + .../native/neon/validate_one_arm64.go | 35 + .../internal/native/neon/validate_one_arm64.s | 3480 ++++ .../native/neon/validate_one_subr_arm64.go | 25 + .../native/neon/validate_utf8_arm64.go | 36 + .../native/neon/validate_utf8_arm64.s | 222 + .../native/neon/validate_utf8_fast_arm64.go | 29 + .../native/neon/validate_utf8_fast_arm64.s | 182 + .../neon/validate_utf8_fast_subr_arm64.go | 25 + .../native/neon/validate_utf8_subr_arm64.go | 25 + .../sonic/internal/native/neon/value_arm64.go | 34 + .../sonic/internal/native/neon/value_arm64.s | 5968 ++++++ .../internal/native/neon/value_subr_arm64.go | 25 + .../internal/native/neon/vnumber_arm64.go | 34 + .../internal/native/neon/vnumber_arm64.s | 4690 +++++ .../native/neon/vnumber_subr_arm64.go | 25 + .../internal/native/neon/vsigned_arm64.go | 32 + .../internal/native/neon/vsigned_arm64.s | 156 + .../native/neon/vsigned_subr_arm64.go | 25 + .../internal/native/neon/vstring_arm64.go | 32 + .../internal/native/neon/vstring_arm64.s | 628 + .../native/neon/vstring_subr_arm64.go | 25 + .../internal/native/neon/vunsigned_arm64.go | 32 + .../internal/native/neon/vunsigned_arm64.s | 150 + .../native/neon/vunsigned_subr_arm64.go | 25 + .../internal/native/parse_with_padding.tmpl | 36 + .../sonic/internal/native/quote.tmpl | 33 + .../internal/native/recover_amd64_test.tmpl | 697 - .../sonic/internal/native/recover_test.tmpl | 722 + .../sonic/internal/native/skip_array.tmpl | 35 + .../sonic/internal/native/skip_number.tmpl | 34 + .../sonic/internal/native/skip_object.tmpl | 35 + .../sonic/internal/native/skip_one.tmpl | 35 + .../sonic/internal/native/skip_one_fast.tmpl | 35 + .../sonic/internal/native/sse/f32toa.go | 35 + .../sonic/internal/native/sse/f32toa_subr.go | 46 + .../internal/native/sse/f32toa_text_amd64.go | 1052 ++ .../sonic/internal/native/sse/f64toa.go | 35 + .../sonic/internal/native/sse/f64toa_subr.go | 46 + .../internal/native/sse/f64toa_text_amd64.go | 2486 +++ .../sonic/internal/native/sse/get_by_path.go | 35 + .../internal/native/sse/get_by_path_subr.go | 46 + .../native/sse/get_by_path_text_amd64.go | 6154 +++++++ .../sonic/internal/native/sse/html_escape.go | 34 + .../internal/native/sse/html_escape_subr.go | 45 + .../native/sse/html_escape_text_amd64.go | 635 + .../sonic/internal/native/sse/i64toa.go | 35 + .../sonic/internal/native/sse/i64toa_subr.go | 47 + .../internal/native/sse/i64toa_text_amd64.go | 658 + .../internal/native/sse/lookup_small_key.go | 37 + .../native/sse/lookup_small_key_subr.go | 45 + .../native/sse/lookup_small_key_text_amd64.go | 239 + .../sonic/internal/native/sse/lspace.go | 35 + .../sonic/internal/native/sse/lspace_subr.go | 33 + .../internal/native/sse/lspace_text_amd64.go | 37 + .../sonic/internal/native/sse/native_amd64.go | 191 - .../internal/native/sse/native_export.go | 51 + .../internal/native/sse/native_subr_amd64.go | 604 - .../internal/native/sse/native_text_amd64.go | 14266 --------------- .../internal/native/sse/parse_with_padding.go | 36 + .../native/sse/parse_with_padding_subr.go | 46 + .../sse/parse_with_padding_text_amd64.go | 15013 +++++++++++++++ .../sonic/internal/native/sse/quote.go | 33 + .../sonic/internal/native/sse/quote_subr.go | 46 + .../internal/native/sse/quote_text_amd64.go | 1100 ++ .../sonic/internal/native/sse/skip_array.go | 35 + .../internal/native/sse/skip_array_subr.go | 46 + .../native/sse/skip_array_text_amd64.go | 4017 ++++ .../sonic/internal/native/sse/skip_number.go | 34 + .../internal/native/sse/skip_number_subr.go | 46 + .../native/sse/skip_number_text_amd64.go | 351 + .../sonic/internal/native/sse/skip_object.go | 35 + .../internal/native/sse/skip_object_subr.go | 46 + .../native/sse/skip_object_text_amd64.go | 4017 ++++ .../sonic/internal/native/sse/skip_one.go | 35 + .../internal/native/sse/skip_one_fast.go | 35 + .../internal/native/sse/skip_one_fast_subr.go | 46 + .../native/sse/skip_one_fast_text_amd64.go | 1037 ++ .../internal/native/sse/skip_one_subr.go | 46 + .../native/sse/skip_one_text_amd64.go | 3844 ++++ .../sonic/internal/native/sse/u64toa.go | 34 + .../sonic/internal/native/sse/u64toa_subr.go | 39 + .../internal/native/sse/u64toa_text_amd64.go | 384 + .../sonic/internal/native/sse/unquote.go | 34 + .../sonic/internal/native/sse/unquote_subr.go | 46 + .../internal/native/sse/unquote_text_amd64.go | 538 + .../sonic/internal/native/sse/validate_one.go | 35 + .../internal/native/sse/validate_one_subr.go | 46 + .../native/sse/validate_one_text_amd64.go | 4017 ++++ .../internal/native/sse/validate_utf8.go | 37 + .../internal/native/sse/validate_utf8_fast.go | 34 + .../native/sse/validate_utf8_fast_subr.go | 41 + .../sse/validate_utf8_fast_text_amd64.go | 158 + .../internal/native/sse/validate_utf8_subr.go | 44 + .../native/sse/validate_utf8_text_amd64.go | 193 + .../sonic/internal/native/sse/value.go | 33 + .../sonic/internal/native/sse/value_subr.go | 46 + .../internal/native/sse/value_text_amd64.go | 5439 ++++++ .../sonic/internal/native/sse/vnumber.go | 33 + .../sonic/internal/native/sse/vnumber_subr.go | 46 + .../internal/native/sse/vnumber_text_amd64.go | 4161 +++++ .../sonic/internal/native/sse/vsigned.go | 33 + .../sonic/internal/native/sse/vsigned_subr.go | 50 + .../internal/native/sse/vsigned_text_amd64.go | 120 + .../sonic/internal/native/sse/vstring.go | 33 + .../sonic/internal/native/sse/vstring_subr.go | 46 + .../internal/native/sse/vstring_text_amd64.go | 653 + .../sonic/internal/native/sse/vunsigned.go | 33 + .../internal/native/sse/vunsigned_subr.go | 57 + .../native/sse/vunsigned_text_amd64.go | 127 + .../internal/native/traceback_test.mock_tmpl | 379 + .../sonic/internal/native/types/types.go | 9 +- .../sonic/internal/native/u64toa.tmpl | 34 + .../sonic/internal/native/unquote.tmpl | 34 + .../sonic/internal/native/validate_one.tmpl | 35 + .../sonic/internal/native/validate_utf8.tmpl | 37 + .../internal/native/validate_utf8_fast.tmpl | 34 + .../sonic/internal/native/value.tmpl | 33 + .../sonic/internal/native/vnumber.tmpl | 33 + .../sonic/internal/native/vsigned.tmpl | 33 + .../sonic/internal/native/vstring.tmpl | 33 + .../sonic/internal/native/vunsigned.tmpl | 33 + .../internal/{encoder => optcaching}/asm.s | 0 .../sonic/internal/optcaching/fcache.go | 362 + .../bytedance/sonic/internal/rt/asm_amd64.s | 40 - .../bytedance/sonic/internal/rt/assertI2I.go | 42 + .../sonic/internal/rt/base64_amd64.go | 20 + .../sonic/internal/rt/base64_compat.go | 20 + .../bytedance/sonic/internal/rt/fastconv.go | 175 + .../bytedance/sonic/internal/rt/fastmem.go | 39 +- .../bytedance/sonic/internal/rt/fastvalue.go | 244 +- .../bytedance/sonic/internal/rt/gcwb.go | 55 +- .../sonic/internal/rt/gcwb_legacy.go | 29 + .../bytedance/sonic/internal/rt/growslice.go | 36 + .../sonic/internal/rt/growslice_legacy.go | 27 + .../bytedance/sonic/internal/rt/int48.go | 6 +- .../bytedance/sonic/internal/rt/pool.go | 31 + .../bytedance/sonic/internal/rt/stackmap.go | 2 +- .../bytedance/sonic/internal/rt/stubs.go | 165 + .../bytedance/sonic/internal/rt/table.go | 118 + .../bytedance/sonic/internal/rt/types.go | 45 + .../sonic/loader}/LICENSE | 0 .../bytedance/sonic/loader/funcdata_compat.go | 6 +- .../bytedance/sonic/loader/funcdata_go116.go | 6 +- .../bytedance/sonic/loader/funcdata_go118.go | 2 +- .../bytedance/sonic/loader/funcdata_go120.go | 2 +- .../bytedance/sonic/loader/funcdata_go121.go | 6 +- .../bytedance/sonic/loader/funcdata_go123.go | 118 + .../bytedance/sonic/loader/funcdata_latest.go | 6 +- .../sonic/{ => loader}/internal/abi/abi.go | 2 +- .../{ => loader}/internal/abi/abi_amd64.go | 2 +- .../internal/abi/abi_legacy_amd64.go | 2 +- .../internal/abi/abi_regabi_amd64.go | 2 +- .../sonic/{ => loader}/internal/abi/stubs.go | 2 +- .../sonic/loader/internal/rt/fastmem.go | 62 + .../sonic/loader/internal/rt/fastvalue.go | 183 + .../sonic/loader/internal/rt/stackmap.go | 181 + .../bytedance/sonic/loader/loader_latest.go | 5 +- .../bytedance/sonic/loader/mmap_unix.go | 4 +- .../bytedance/sonic/loader/stubs.go | 34 +- .../bytedance/sonic/loader/wrapper.go | 4 +- .../bytedance/sonic/option/option.go | 12 +- vendor/github.com/bytedance/sonic/sonic.go | 55 +- .../bytedance/sonic/unquote/unquote.go | 31 +- .../github.com/bytedance/sonic/utf8/utf8.go | 12 +- vendor/github.com/cespare/xxhash/v2/README.md | 33 +- .../github.com/cespare/xxhash/v2/testall.sh | 10 + vendor/github.com/cespare/xxhash/v2/xxhash.go | 70 +- .../cespare/xxhash/v2/xxhash_amd64.s | 336 +- .../cespare/xxhash/v2/xxhash_arm64.s | 183 + .../v2/{xxhash_amd64.go => xxhash_asm.go} | 4 +- .../cespare/xxhash/v2/xxhash_other.go | 24 +- .../cespare/xxhash/v2/xxhash_safe.go | 3 +- .../cespare/xxhash/v2/xxhash_unsafe.go | 5 +- .../github.com/chenzhuoyu/base64x/.gitignore | 43 - .../github.com/chenzhuoyu/base64x/.gitmodules | 3 - vendor/github.com/chenzhuoyu/base64x/cpuid.go | 17 - .../github.com/chenzhuoyu/iasm/expr/pools.go | 26 - .../github.com/chenzhuoyu/iasm/expr/term.go | 7 - .../github.com/chenzhuoyu/iasm/x86_64/asm.s | 0 .../chenzhuoyu/iasm/x86_64/operands.go | 510 - .../chenzhuoyu/iasm/x86_64/pools.go | 117 - .../chenzhuoyu/iasm/x86_64/program.go | 542 - .../github.com/cloudwego/base64x/.gitignore | 30 + .../cloudwego/base64x/.golangci.yaml | 37 + .../cloudwego/base64x/.licenserc.yaml | 14 + .../cloudwego/base64x/CODE_OF_CONDUCT.md | 128 + .../cloudwego/base64x/CONTRIBUTING.md | 55 + .../iasm => cloudwego/base64x}/LICENSE | 0 .../base64x/LICENSE-APACHE} | 127 - .../base64x/Makefile | 0 .../base64x/README.md | 0 .../github.com/cloudwego/base64x/_typos.toml | 4 + .../base64x/base64x.go | 16 + .../cloudwego/base64x/check_branch_name.sh | 10 + vendor/github.com/cloudwego/base64x/cpuid.go | 33 + .../base64x/faststr.go | 16 + .../base64x/native_amd64.go | 16 + .../base64x/native_subr_amd64.go | 0 .../base64x/native_text_amd64.go | 0 .../github.com/cloudwego/iasm/LICENSE-APACHE | 177 + .../iasm/expr/ast.go | 16 + .../iasm/expr/errors.go | 16 + .../iasm/expr/ops.go | 16 + .../iasm/expr/parser.go | 16 + .../iasm/expr/pools.go} | 47 +- vendor/github.com/cloudwego/iasm/expr/term.go | 23 + .../iasm/expr/utils.go | 16 + .../iasm/x86_64/arch.go | 16 + vendor/github.com/cloudwego/iasm/x86_64/asm.s | 16 + .../iasm/x86_64/assembler.go | 18 +- .../iasm/x86_64/assembler_alias.go | 16 + .../iasm/x86_64/eface.go | 16 + .../iasm/x86_64/encodings.go | 16 + .../iasm/x86_64/instructions.go | 16 + .../iasm/x86_64/instructions_table.go | 16 + .../cloudwego/iasm/x86_64/operands.go | 665 + .../github.com/cloudwego/iasm/x86_64/pools.go | 54 + .../cloudwego/iasm/x86_64/program.go | 584 + .../iasm/x86_64/registers.go | 16 + .../iasm/x86_64/utils.go | 16 + vendor/github.com/creack/pty/.editorconfig | 54 + vendor/github.com/creack/pty/.golangci.yml | 324 + .../github.com/creack/pty/Dockerfile.golang | 2 +- vendor/github.com/creack/pty/Dockerfile.riscv | 23 - vendor/github.com/creack/pty/README.md | 2 +- vendor/github.com/creack/pty/ioctl.go | 31 +- vendor/github.com/creack/pty/ioctl_inner.go | 20 + vendor/github.com/creack/pty/ioctl_legacy.go | 10 + vendor/github.com/creack/pty/ioctl_solaris.go | 2 +- .../creack/pty/ioctl_unsupported.go | 2 +- vendor/github.com/creack/pty/pty_darwin.go | 6 +- vendor/github.com/creack/pty/pty_dragonfly.go | 10 +- vendor/github.com/creack/pty/pty_freebsd.go | 8 +- vendor/github.com/creack/pty/pty_linux.go | 6 +- vendor/github.com/creack/pty/pty_netbsd.go | 4 +- vendor/github.com/creack/pty/pty_openbsd.go | 17 +- vendor/github.com/creack/pty/pty_solaris.go | 41 +- .../creack/pty/test_crosscompile.sh | 8 +- vendor/github.com/creack/pty/winsize.go | 5 +- vendor/github.com/creack/pty/winsize_unix.go | 12 +- .../creack/pty/ztypes_freebsd_riscv64.go | 13 + .../creack/pty/ztypes_openbsd_32bit_int.go | 3 +- vendor/github.com/creack/pty/ztypes_ppc.go | 9 + vendor/github.com/creack/pty/ztypes_sparcx.go | 12 + vendor/github.com/fatih/color/color.go | 61 +- .../gabriel-vasile/mimetype/LICENSE | 2 +- .../gabriel-vasile/mimetype/README.md | 8 +- .../mimetype/internal/json/json.go | 27 +- .../mimetype/internal/magic/archive.go | 104 +- .../mimetype/internal/magic/binary.go | 40 +- .../mimetype/internal/magic/ftyp.go | 43 +- .../mimetype/internal/magic/magic.go | 16 +- .../mimetype/internal/magic/ms_office.go | 45 +- .../mimetype/internal/magic/text.go | 46 +- .../mimetype/internal/magic/text_csv.go | 60 +- .../mimetype/internal/magic/zip.go | 90 +- .../gabriel-vasile/mimetype/mimetype.gif | Bin 1343793 -> 0 bytes .../gabriel-vasile/mimetype/mimetype.go | 11 +- .../mimetype/supported_mimes.md | 29 +- .../gabriel-vasile/mimetype/tree.go | 46 +- vendor/github.com/gin-gonic/gin/.gitignore | 4 + vendor/github.com/gin-gonic/gin/.golangci.yml | 1 - .../github.com/gin-gonic/gin/.goreleaser.yaml | 29 +- vendor/github.com/gin-gonic/gin/Makefile | 1 + vendor/github.com/gin-gonic/gin/auth.go | 25 + .../gin-gonic/gin/binding/binding.go | 27 +- .../gin/binding/binding_nomsgpack.go | 3 +- .../gin/binding/default_validator.go | 5 +- .../gin-gonic/gin/binding/form_mapping.go | 28 + vendor/github.com/gin-gonic/gin/codecov.yml | 13 + vendor/github.com/gin-gonic/gin/context.go | 52 +- vendor/github.com/gin-gonic/gin/debug.go | 20 +- vendor/github.com/gin-gonic/gin/deprecated.go | 2 + vendor/github.com/gin-gonic/gin/gin.go | 37 +- vendor/github.com/gin-gonic/gin/logger.go | 53 +- .../github.com/gin-gonic/gin/render/render.go | 32 +- .../github.com/gin-gonic/gin/render/yaml.go | 2 +- vendor/github.com/gin-gonic/gin/tree.go | 43 +- vendor/github.com/gin-gonic/gin/version.go | 2 +- vendor/github.com/go-chi/chi/v5/CHANGELOG.md | 5 + .../github.com/go-chi/chi/v5/CONTRIBUTING.md | 12 +- vendor/github.com/go-chi/chi/v5/README.md | 2 + vendor/github.com/go-chi/chi/v5/context.go | 3 +- .../go-chi/chi/v5/middleware/maybe.go | 2 +- .../go-chi/chi/v5/middleware/realip.go | 2 +- .../go-chi/chi/v5/middleware/wrap_writer.go | 35 +- vendor/github.com/go-chi/chi/v5/mux.go | 16 + vendor/github.com/go-chi/chi/v5/path_value.go | 20 + .../go-chi/chi/v5/path_value_fallback.go | 19 + .../go-playground/validator/v10/Makefile | 6 +- .../go-playground/validator/v10/README.md | 139 +- .../go-playground/validator/v10/baked_in.go | 284 +- .../go-playground/validator/v10/cache.go | 30 +- .../validator/v10/country_codes.go | 2305 +-- .../validator/v10/currency_codes.go | 148 +- .../go-playground/validator/v10/doc.go | 38 +- .../go-playground/validator/v10/errors.go | 8 +- .../go-playground/validator/v10/options.go | 26 + .../validator/v10/postcode_regexes.go | 12 +- .../go-playground/validator/v10/regexes.go | 158 +- .../go-playground/validator/v10/util.go | 22 +- .../go-playground/validator/v10/validator.go | 169 +- .../validator/v10/validator_instance.go | 42 +- vendor/github.com/goccy/go-json/.golangci.yml | 3 + vendor/github.com/goccy/go-json/Makefile | 2 +- vendor/github.com/goccy/go-json/encode.go | 4 +- .../goccy/go-json/internal/decoder/ptr.go | 1 + .../internal/decoder/unmarshal_text.go | 2 +- .../goccy/go-json/internal/encoder/compact.go | 2 +- .../go-json/internal/encoder/compiler.go | 2 +- .../goccy/go-json/internal/encoder/int.go | 24 + .../goccy/go-json/internal/encoder/string.go | 24 + .../goccy/go-json/internal/runtime/rtype.go | 1 - vendor/github.com/goccy/go-json/json.go | 35 +- vendor/github.com/hashicorp/yamux/LICENSE | 2 + vendor/github.com/hashicorp/yamux/mux.go | 8 +- vendor/github.com/hashicorp/yamux/session.go | 21 +- vendor/github.com/hashicorp/yamux/spec.md | 2 +- vendor/github.com/hashicorp/yamux/stream.go | 34 +- vendor/github.com/hashicorp/yamux/util.go | 7 + vendor/github.com/itchyny/gojq/.dockerignore | 1 - vendor/github.com/itchyny/gojq/.gitattributes | 3 +- vendor/github.com/itchyny/gojq/.gitignore | 1 - vendor/github.com/itchyny/gojq/CHANGELOG.md | 37 + vendor/github.com/itchyny/gojq/Dockerfile | 4 +- vendor/github.com/itchyny/gojq/LICENSE | 2 +- vendor/github.com/itchyny/gojq/README.md | 22 +- vendor/github.com/itchyny/gojq/_gojq | 8 +- vendor/github.com/itchyny/gojq/builtin.go | 120 +- vendor/github.com/itchyny/gojq/builtin.jq | 9 +- vendor/github.com/itchyny/gojq/compare.go | 10 +- vendor/github.com/itchyny/gojq/compiler.go | 98 +- vendor/github.com/itchyny/gojq/debug.go | 17 +- vendor/github.com/itchyny/gojq/error.go | 37 +- vendor/github.com/itchyny/gojq/execute.go | 26 +- vendor/github.com/itchyny/gojq/func.go | 114 +- vendor/github.com/itchyny/gojq/go.dev.mod | 6 +- vendor/github.com/itchyny/gojq/go.dev.sum | 8 +- vendor/github.com/itchyny/gojq/lexer.go | 63 +- .../github.com/itchyny/gojq/module_loader.go | 106 +- vendor/github.com/itchyny/gojq/operator.go | 32 +- vendor/github.com/itchyny/gojq/parser.go | 1196 +- vendor/github.com/itchyny/gojq/parser.go.y | 286 +- vendor/github.com/itchyny/gojq/query.go | 71 +- vendor/github.com/itchyny/gojq/release.go | 10 +- .../itchyny/timefmt-go/CHANGELOG.md | 5 + .../github.com/itchyny/timefmt-go/README.md | 6 +- .../github.com/itchyny/timefmt-go/format.go | 42 +- vendor/github.com/itchyny/timefmt-go/parse.go | 260 +- .../klauspost/compress/flate/deflate.go | 988 - .../klauspost/compress/flate/dict_decoder.go | 184 - .../klauspost/compress/flate/fast_encoder.go | 216 - .../compress/flate/huffman_bit_writer.go | 1182 -- .../klauspost/compress/flate/huffman_code.go | 417 - .../compress/flate/huffman_sortByFreq.go | 159 - .../compress/flate/huffman_sortByLiteral.go | 201 - .../klauspost/compress/flate/inflate.go | 793 - .../klauspost/compress/flate/inflate_gen.go | 1283 -- .../klauspost/compress/flate/level1.go | 241 - .../klauspost/compress/flate/level2.go | 214 - .../klauspost/compress/flate/level3.go | 241 - .../klauspost/compress/flate/level4.go | 221 - .../klauspost/compress/flate/level5.go | 310 - .../klauspost/compress/flate/level6.go | 325 - .../klauspost/compress/flate/regmask_amd64.go | 37 - .../klauspost/compress/flate/regmask_other.go | 40 - .../klauspost/compress/flate/stateless.go | 318 - .../klauspost/compress/flate/token.go | 379 - .../github.com/klauspost/cpuid/v2/README.md | 15 +- vendor/github.com/klauspost/cpuid/v2/cpuid.go | 459 +- .../klauspost/cpuid/v2/detect_x86.go | 2 + .../klauspost/cpuid/v2/featureid_string.go | 413 +- vendor/github.com/leodido/go-urn/.gitignore | 3 +- vendor/github.com/leodido/go-urn/README.md | 126 +- vendor/github.com/leodido/go-urn/kind.go | 10 + vendor/github.com/leodido/go-urn/machine.go | 6178 +++++-- .../github.com/leodido/go-urn/machine.go.rl | 283 +- vendor/github.com/leodido/go-urn/makefile | 20 +- vendor/github.com/leodido/go-urn/options.go | 9 + .../github.com/leodido/go-urn/parsing_mode.go | 12 + vendor/github.com/leodido/go-urn/scim.go | 48 + .../leodido/go-urn/scim/schema/type.go | 36 + vendor/github.com/leodido/go-urn/urn.go | 75 +- vendor/github.com/leodido/go-urn/urn8141.go | 30 + .../github.com/mattn/go-isatty/isatty_bsd.go | 3 +- .../mattn/go-isatty/isatty_others.go | 5 +- .../mattn/go-isatty/isatty_tcgets.go | 3 +- .../pelletier/go-toml/v2/.gitignore | 3 +- .../pelletier/go-toml/v2/.goreleaser.yaml | 4 + .../pelletier/go-toml/v2/CONTRIBUTING.md | 31 +- .../github.com/pelletier/go-toml/v2/LICENSE | 3 +- .../github.com/pelletier/go-toml/v2/README.md | 161 +- .../pelletier/go-toml/v2/SECURITY.md | 3 - vendor/github.com/pelletier/go-toml/v2/ci.sh | 22 +- .../github.com/pelletier/go-toml/v2/decode.go | 2 +- .../go-toml/v2/internal/tracker/seen.go | 74 +- .../pelletier/go-toml/v2/marshaler.go | 97 +- .../pelletier/go-toml/v2/unmarshaler.go | 114 +- .../pelletier/go-toml/v2/unstable/parser.go | 6 + .../go-toml/v2/unstable/unmarshaler.go | 7 + .../github.com/pires/go-proxyproto/header.go | 6 +- .../github.com/pires/go-proxyproto/policy.go | 57 + .../pires/go-proxyproto/protocol.go | 150 +- vendor/github.com/pires/go-proxyproto/v1.go | 24 +- vendor/github.com/spf13/cobra/.golangci.yml | 29 +- vendor/github.com/spf13/cobra/README.md | 8 +- vendor/github.com/spf13/cobra/active_help.go | 13 +- vendor/github.com/spf13/cobra/active_help.md | 157 - vendor/github.com/spf13/cobra/args.go | 4 +- .../spf13/cobra/bash_completions.go | 27 +- .../spf13/cobra/bash_completions.md | 93 - .../spf13/cobra/bash_completionsV2.go | 2 +- vendor/github.com/spf13/cobra/cobra.go | 15 +- vendor/github.com/spf13/cobra/command.go | 118 +- vendor/github.com/spf13/cobra/completions.go | 91 +- .../spf13/cobra/fish_completions.go | 2 +- .../spf13/cobra/fish_completions.md | 4 - vendor/github.com/spf13/cobra/flag_groups.go | 86 +- .../spf13/cobra/powershell_completions.go | 10 +- .../spf13/cobra/powershell_completions.md | 3 - .../spf13/cobra/projects_using_cobra.md | 64 - .../spf13/cobra/shell_completions.md | 576 - vendor/github.com/spf13/cobra/user_guide.md | 726 - .../github.com/spf13/cobra/zsh_completions.md | 48 - vendor/github.com/ugorji/go/codec/cbor.go | 23 +- vendor/github.com/ugorji/go/codec/decode.go | 13 +- vendor/github.com/ugorji/go/codec/encode.go | 11 +- vendor/github.com/ugorji/go/codec/gen.go | 16 +- vendor/github.com/ugorji/go/codec/helper.go | 31 +- vendor/github.com/ugorji/go/codec/json.go | 3 + vendor/github.com/ugorji/go/codec/msgpack.go | 2 +- vendor/github.com/ugorji/go/codec/reader.go | 4 +- vendor/golang.org/x/arch/LICENSE | 4 +- vendor/golang.org/x/arch/x86/x86asm/gnu.go | 2 +- vendor/golang.org/x/arch/x86/x86asm/inst.go | 2 +- vendor/golang.org/x/crypto/LICENSE | 4 +- .../x/crypto/blake2b/blake2bAVX2_amd64.s | 5167 +++++- .../x/crypto/blake2b/blake2b_amd64.s | 1681 +- vendor/golang.org/x/crypto/blake2s/blake2s.go | 10 +- .../x/crypto/blake2s/blake2s_amd64.s | 2571 ++- .../golang.org/x/crypto/blake2s/register.go | 21 - .../x/crypto/chacha20/chacha_ppc64le.s | 110 +- .../chacha20poly1305/chacha20poly1305.go | 2 +- .../chacha20poly1305/chacha20poly1305_amd64.s | 11503 +++++++++--- .../x/crypto/curve25519/curve25519.go | 39 +- .../x/crypto/curve25519/curve25519_compat.go | 105 - .../x/crypto/curve25519/curve25519_go120.go | 46 - .../x/crypto/curve25519/internal/field/README | 7 - .../x/crypto/curve25519/internal/field/fe.go | 416 - .../curve25519/internal/field/fe_amd64.go | 15 - .../curve25519/internal/field/fe_amd64.s | 378 - .../internal/field/fe_amd64_noasm.go | 11 - .../curve25519/internal/field/fe_arm64.go | 15 - .../curve25519/internal/field/fe_arm64.s | 42 - .../internal/field/fe_arm64_noasm.go | 11 - .../curve25519/internal/field/fe_generic.go | 264 - .../curve25519/internal/field/sync.checkpoint | 1 - .../crypto/curve25519/internal/field/sync.sh | 19 - .../x/crypto/internal/poly1305/sum_amd64.s | 133 +- vendor/golang.org/x/crypto/sha3/doc.go | 2 +- vendor/golang.org/x/crypto/sha3/hashes.go | 42 +- .../x/crypto/sha3/hashes_generic.go | 27 - .../golang.org/x/crypto/sha3/hashes_noasm.go | 23 + .../golang.org/x/crypto/sha3/keccakf_amd64.s | 5787 +++++- vendor/golang.org/x/crypto/sha3/register.go | 18 - vendor/golang.org/x/crypto/sha3/sha3.go | 62 +- vendor/golang.org/x/crypto/sha3/sha3_s390x.go | 67 +- vendor/golang.org/x/crypto/sha3/shake.go | 20 +- .../golang.org/x/crypto/sha3/shake_generic.go | 19 - .../golang.org/x/crypto/sha3/shake_noasm.go | 15 + vendor/golang.org/x/crypto/sha3/xor.go | 45 +- .../golang.org/x/crypto/sha3/xor_generic.go | 28 - .../golang.org/x/crypto/sha3/xor_unaligned.go | 66 - vendor/golang.org/x/net/LICENSE | 4 +- vendor/golang.org/x/net/html/doc.go | 2 +- .../golang.org/x/net/http/httpguts/httplex.go | 13 +- vendor/golang.org/x/net/http2/config.go | 122 + vendor/golang.org/x/net/http2/config_go124.go | 61 + .../x/net/http2/config_pre_go124.go | 16 + vendor/golang.org/x/net/http2/frame.go | 40 +- vendor/golang.org/x/net/http2/http2.go | 72 +- vendor/golang.org/x/net/http2/pipe.go | 11 +- vendor/golang.org/x/net/http2/server.go | 271 +- vendor/golang.org/x/net/http2/timer.go | 20 + vendor/golang.org/x/net/http2/transport.go | 373 +- vendor/golang.org/x/net/http2/write.go | 10 + .../x/net/http2/writesched_priority.go | 4 +- vendor/golang.org/x/net/nettest/conntest.go | 5 +- vendor/golang.org/x/net/nettest/nettest.go | 3 +- vendor/golang.org/x/net/proxy/per_host.go | 8 +- vendor/golang.org/x/sys/LICENSE | 4 +- vendor/golang.org/x/sys/cpu/cpu.go | 21 + vendor/golang.org/x/sys/cpu/cpu_arm64.go | 12 + .../golang.org/x/sys/cpu/cpu_linux_arm64.go | 5 + .../golang.org/x/sys/cpu/cpu_linux_noinit.go | 2 +- .../golang.org/x/sys/cpu/cpu_linux_riscv64.go | 137 + vendor/golang.org/x/sys/cpu/cpu_riscv64.go | 11 +- vendor/golang.org/x/sys/unix/README.md | 2 +- vendor/golang.org/x/sys/unix/mkerrors.sh | 8 +- vendor/golang.org/x/sys/unix/mremap.go | 5 + vendor/golang.org/x/sys/unix/syscall_aix.go | 2 +- .../golang.org/x/sys/unix/syscall_darwin.go | 61 + vendor/golang.org/x/sys/unix/syscall_hurd.go | 1 + vendor/golang.org/x/sys/unix/syscall_linux.go | 64 +- .../x/sys/unix/syscall_linux_arm64.go | 2 + .../x/sys/unix/syscall_linux_loong64.go | 2 + .../x/sys/unix/syscall_linux_riscv64.go | 2 + .../golang.org/x/sys/unix/syscall_openbsd.go | 1 + vendor/golang.org/x/sys/unix/syscall_unix.go | 9 + .../golang.org/x/sys/unix/vgetrandom_linux.go | 13 + .../x/sys/unix/vgetrandom_unsupported.go | 11 + .../x/sys/unix/zerrors_darwin_amd64.go | 12 + .../x/sys/unix/zerrors_darwin_arm64.go | 12 + vendor/golang.org/x/sys/unix/zerrors_linux.go | 69 +- .../x/sys/unix/zerrors_linux_386.go | 8 + .../x/sys/unix/zerrors_linux_amd64.go | 8 + .../x/sys/unix/zerrors_linux_arm.go | 7 + .../x/sys/unix/zerrors_linux_arm64.go | 8 + .../x/sys/unix/zerrors_linux_loong64.go | 7 + .../x/sys/unix/zerrors_linux_mips.go | 7 + .../x/sys/unix/zerrors_linux_mips64.go | 7 + .../x/sys/unix/zerrors_linux_mips64le.go | 7 + .../x/sys/unix/zerrors_linux_mipsle.go | 7 + .../x/sys/unix/zerrors_linux_ppc.go | 7 + .../x/sys/unix/zerrors_linux_ppc64.go | 7 + .../x/sys/unix/zerrors_linux_ppc64le.go | 7 + .../x/sys/unix/zerrors_linux_riscv64.go | 7 + .../x/sys/unix/zerrors_linux_s390x.go | 7 + .../x/sys/unix/zerrors_linux_sparc64.go | 7 + .../x/sys/unix/zerrors_zos_s390x.go | 2 + .../x/sys/unix/zsyscall_darwin_amd64.go | 101 + .../x/sys/unix/zsyscall_darwin_amd64.s | 25 + .../x/sys/unix/zsyscall_darwin_arm64.go | 101 + .../x/sys/unix/zsyscall_darwin_arm64.s | 25 + .../golang.org/x/sys/unix/zsyscall_linux.go | 33 +- .../x/sys/unix/zsyscall_openbsd_386.go | 24 + .../x/sys/unix/zsyscall_openbsd_386.s | 5 + .../x/sys/unix/zsyscall_openbsd_amd64.go | 24 + .../x/sys/unix/zsyscall_openbsd_amd64.s | 5 + .../x/sys/unix/zsyscall_openbsd_arm.go | 24 + .../x/sys/unix/zsyscall_openbsd_arm.s | 5 + .../x/sys/unix/zsyscall_openbsd_arm64.go | 24 + .../x/sys/unix/zsyscall_openbsd_arm64.s | 5 + .../x/sys/unix/zsyscall_openbsd_mips64.go | 24 + .../x/sys/unix/zsyscall_openbsd_mips64.s | 5 + .../x/sys/unix/zsyscall_openbsd_ppc64.go | 24 + .../x/sys/unix/zsyscall_openbsd_ppc64.s | 6 + .../x/sys/unix/zsyscall_openbsd_riscv64.go | 24 + .../x/sys/unix/zsyscall_openbsd_riscv64.s | 5 + .../x/sys/unix/zsysnum_linux_386.go | 1 + .../x/sys/unix/zsysnum_linux_amd64.go | 2 + .../x/sys/unix/zsysnum_linux_arm.go | 1 + .../x/sys/unix/zsysnum_linux_arm64.go | 3 +- .../x/sys/unix/zsysnum_linux_loong64.go | 3 + .../x/sys/unix/zsysnum_linux_mips.go | 1 + .../x/sys/unix/zsysnum_linux_mips64.go | 1 + .../x/sys/unix/zsysnum_linux_mips64le.go | 1 + .../x/sys/unix/zsysnum_linux_mipsle.go | 1 + .../x/sys/unix/zsysnum_linux_ppc.go | 1 + .../x/sys/unix/zsysnum_linux_ppc64.go | 1 + .../x/sys/unix/zsysnum_linux_ppc64le.go | 1 + .../x/sys/unix/zsysnum_linux_riscv64.go | 3 +- .../x/sys/unix/zsysnum_linux_s390x.go | 1 + .../x/sys/unix/zsysnum_linux_sparc64.go | 1 + .../x/sys/unix/ztypes_darwin_amd64.go | 13 + .../x/sys/unix/ztypes_darwin_arm64.go | 13 + .../x/sys/unix/ztypes_freebsd_386.go | 1 + .../x/sys/unix/ztypes_freebsd_amd64.go | 1 + .../x/sys/unix/ztypes_freebsd_arm.go | 1 + .../x/sys/unix/ztypes_freebsd_arm64.go | 1 + .../x/sys/unix/ztypes_freebsd_riscv64.go | 1 + vendor/golang.org/x/sys/unix/ztypes_linux.go | 129 +- .../x/sys/unix/ztypes_linux_riscv64.go | 33 + .../golang.org/x/sys/windows/dll_windows.go | 2 +- .../x/sys/windows/security_windows.go | 25 +- .../x/sys/windows/syscall_windows.go | 16 +- .../golang.org/x/sys/windows/types_windows.go | 72 +- .../x/sys/windows/zsyscall_windows.go | 89 + vendor/golang.org/x/term/LICENSE | 4 +- vendor/golang.org/x/term/term_windows.go | 1 + vendor/golang.org/x/text/LICENSE | 4 +- .../protobuf/encoding/protowire/wire.go | 28 +- .../protobuf/internal/errors/errors.go | 21 +- .../protobuf/internal/genid/descriptor_gen.go | 401 +- .../protobuf/internal/genid/doc.go | 2 +- .../internal/genid/go_features_gen.go | 36 + .../protobuf/internal/genid/map_entry.go | 2 +- .../protobuf/internal/genid/struct_gen.go | 5 + .../protobuf/internal/genid/type_gen.go | 38 + .../protobuf/internal/genid/wrappers.go | 2 +- .../protobuf/internal/order/range.go | 4 +- .../protobuf/internal/strs/strings.go | 2 +- .../protobuf/internal/strs/strings_pure.go | 28 - ...ings_unsafe.go => strings_unsafe_go120.go} | 3 +- .../internal/strs/strings_unsafe_go121.go | 73 + .../protobuf/proto/decode.go | 4 +- .../google.golang.org/protobuf/proto/doc.go | 58 +- .../protobuf/proto/encode.go | 46 +- .../google.golang.org/protobuf/proto/equal.go | 9 + .../protobuf/proto/extension.go | 90 +- .../google.golang.org/protobuf/proto/merge.go | 2 +- .../protobuf/proto/messageset.go | 7 +- .../google.golang.org/protobuf/proto/proto.go | 18 +- .../google.golang.org/protobuf/proto/size.go | 2 + .../protobuf/reflect/protoreflect/methods.go | 10 + .../protobuf/reflect/protoreflect/proto.go | 87 +- .../reflect/protoreflect/source_gen.go | 85 +- .../protobuf/reflect/protoreflect/type.go | 56 +- .../protobuf/reflect/protoreflect/value.go | 24 +- .../reflect/protoreflect/value_equal.go | 8 +- .../reflect/protoreflect/value_pure.go | 60 - .../reflect/protoreflect/value_union.go | 58 +- ...{value_unsafe.go => value_unsafe_go120.go} | 9 +- .../protoreflect/value_unsafe_go121.go | 86 + .../reflect/protoregistry/registry.go | 38 +- .../protobuf/runtime/protoiface/methods.go | 18 + vendor/modules.txt | 129 +- vendor/mvdan.cc/sh/v3/expand/arith.go | 34 +- vendor/mvdan.cc/sh/v3/expand/braces.go | 21 +- vendor/mvdan.cc/sh/v3/expand/environ.go | 34 +- vendor/mvdan.cc/sh/v3/expand/expand.go | 127 +- vendor/mvdan.cc/sh/v3/expand/param.go | 11 +- vendor/mvdan.cc/sh/v3/fileutil/file.go | 4 +- vendor/mvdan.cc/sh/v3/pattern/pattern.go | 6 +- vendor/mvdan.cc/sh/v3/syntax/braces.go | 3 +- vendor/mvdan.cc/sh/v3/syntax/lexer.go | 44 +- vendor/mvdan.cc/sh/v3/syntax/nodes.go | 10 +- vendor/mvdan.cc/sh/v3/syntax/parser.go | 122 +- vendor/mvdan.cc/sh/v3/syntax/parser_arithm.go | 6 +- vendor/mvdan.cc/sh/v3/syntax/printer.go | 372 +- vendor/mvdan.cc/sh/v3/syntax/simplify.go | 62 +- vendor/mvdan.cc/sh/v3/syntax/tokens.go | 1 + vendor/mvdan.cc/sh/v3/syntax/walk.go | 197 +- vendor/nhooyr.io/websocket/.gitignore | 1 - vendor/nhooyr.io/websocket/LICENSE.txt | 34 +- vendor/nhooyr.io/websocket/README.md | 133 +- vendor/nhooyr.io/websocket/accept.go | 116 +- vendor/nhooyr.io/websocket/accept_js.go | 20 - vendor/nhooyr.io/websocket/close.go | 283 + vendor/nhooyr.io/websocket/close_notjs.go | 211 - vendor/nhooyr.io/websocket/compress.go | 246 +- vendor/nhooyr.io/websocket/compress_notjs.go | 181 - vendor/nhooyr.io/websocket/conn.go | 290 + vendor/nhooyr.io/websocket/conn_notjs.go | 265 - vendor/nhooyr.io/websocket/dial.go | 94 +- vendor/nhooyr.io/websocket/doc.go | 16 +- vendor/nhooyr.io/websocket/frame.go | 125 +- .../nhooyr.io/websocket/internal/util/util.go | 15 + .../websocket/internal/wsjs/wsjs_js.go | 3 +- .../nhooyr.io/websocket/internal/xsync/go.go | 3 +- vendor/nhooyr.io/websocket/make.sh | 12 + vendor/nhooyr.io/websocket/mask.go | 128 + vendor/nhooyr.io/websocket/mask_amd64.s | 127 + vendor/nhooyr.io/websocket/mask_arm64.s | 72 + vendor/nhooyr.io/websocket/mask_asm.go | 26 + vendor/nhooyr.io/websocket/mask_go.go | 7 + vendor/nhooyr.io/websocket/netconn.go | 181 +- vendor/nhooyr.io/websocket/netconn_js.go | 11 + vendor/nhooyr.io/websocket/netconn_notjs.go | 20 + vendor/nhooyr.io/websocket/read.go | 126 +- vendor/nhooyr.io/websocket/stringer.go | 2 + vendor/nhooyr.io/websocket/write.go | 149 +- vendor/nhooyr.io/websocket/ws_js.go | 255 +- 931 files changed, 236232 insertions(+), 80328 deletions(-) delete mode 100644 vendor/github.com/bytedance/sonic/Makefile rename vendor/github.com/bytedance/sonic/ast/{api_amd64.go => api.go} (71%) create mode 100644 vendor/github.com/bytedance/sonic/ast/stubs.go delete mode 100644 vendor/github.com/bytedance/sonic/ast/stubs_go115.go delete mode 100644 vendor/github.com/bytedance/sonic/ast/stubs_go120.go rename vendor/github.com/bytedance/sonic/decoder/{decoder_amd64.go => decoder_native.go} (64%) rename vendor/github.com/bytedance/sonic/encoder/{encoder_amd64.go => encoder_native.go} (86%) create mode 100644 vendor/github.com/bytedance/sonic/go.work.sum create mode 100644 vendor/github.com/bytedance/sonic/internal/base64/b64_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/base64/b64_compat.go rename vendor/github.com/bytedance/sonic/internal/decoder/{ => api}/decoder.go (57%) create mode 100644 vendor/github.com/bytedance/sonic/internal/decoder/api/decoder_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/decoder/api/decoder_arm64.go rename vendor/github.com/bytedance/sonic/internal/decoder/{ => api}/stream.go (60%) delete mode 100644 vendor/github.com/bytedance/sonic/internal/decoder/asm_stubs_amd64_go116.go delete mode 100644 vendor/github.com/bytedance/sonic/internal/decoder/assembler_stkabi_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/decoder/consts/option.go rename vendor/github.com/bytedance/sonic/internal/decoder/{ => errors}/errors.go (90%) delete mode 100644 vendor/github.com/bytedance/sonic/internal/decoder/generic_stkabi_amd64.go rename vendor/github.com/bytedance/sonic/internal/decoder/{ => jitdec}/asm.s (100%) rename vendor/github.com/bytedance/sonic/internal/decoder/{ => jitdec}/asm_stubs_amd64_go117.go (99%) rename vendor/github.com/bytedance/sonic/internal/decoder/{ => jitdec}/asm_stubs_amd64_go121.go (98%) rename vendor/github.com/bytedance/sonic/internal/decoder/{ => jitdec}/assembler_regabi_amd64.go (96%) rename vendor/github.com/bytedance/sonic/internal/decoder/{ => jitdec}/compiler.go (93%) rename vendor/github.com/bytedance/sonic/internal/decoder/{ => jitdec}/debug.go (99%) create mode 100644 vendor/github.com/bytedance/sonic/internal/decoder/jitdec/decoder.go rename vendor/github.com/bytedance/sonic/internal/decoder/{ => jitdec}/generic_regabi_amd64.go (99%) rename vendor/github.com/bytedance/sonic/internal/decoder/{ => jitdec}/generic_regabi_amd64_test.s (97%) rename vendor/github.com/bytedance/sonic/internal/decoder/{ => jitdec}/pools.go (97%) rename vendor/github.com/bytedance/sonic/internal/decoder/{ => jitdec}/primitives.go (84%) rename vendor/github.com/bytedance/sonic/internal/decoder/{ => jitdec}/stubs_go116.go (91%) rename vendor/github.com/bytedance/sonic/internal/decoder/{ => jitdec}/stubs_go120.go (91%) rename vendor/github.com/bytedance/sonic/internal/decoder/{ => jitdec}/types.go (99%) rename vendor/github.com/bytedance/sonic/internal/decoder/{ => jitdec}/utils.go (98%) create mode 100644 vendor/github.com/bytedance/sonic/internal/decoder/optdec/compile_struct.go create mode 100644 vendor/github.com/bytedance/sonic/internal/decoder/optdec/compiler.go create mode 100644 vendor/github.com/bytedance/sonic/internal/decoder/optdec/const.go create mode 100644 vendor/github.com/bytedance/sonic/internal/decoder/optdec/context.go create mode 100644 vendor/github.com/bytedance/sonic/internal/decoder/optdec/decoder.go create mode 100644 vendor/github.com/bytedance/sonic/internal/decoder/optdec/errors.go create mode 100644 vendor/github.com/bytedance/sonic/internal/decoder/optdec/functor.go create mode 100644 vendor/github.com/bytedance/sonic/internal/decoder/optdec/helper.go create mode 100644 vendor/github.com/bytedance/sonic/internal/decoder/optdec/interface.go create mode 100644 vendor/github.com/bytedance/sonic/internal/decoder/optdec/map.go create mode 100644 vendor/github.com/bytedance/sonic/internal/decoder/optdec/native.go create mode 100644 vendor/github.com/bytedance/sonic/internal/decoder/optdec/node.go create mode 100644 vendor/github.com/bytedance/sonic/internal/decoder/optdec/slice.go create mode 100644 vendor/github.com/bytedance/sonic/internal/decoder/optdec/stringopts.go create mode 100644 vendor/github.com/bytedance/sonic/internal/decoder/optdec/structs.go create mode 100644 vendor/github.com/bytedance/sonic/internal/decoder/optdec/types.go rename vendor/github.com/bytedance/sonic/internal/encoder/{ => alg}/mapiter.go (52%) create mode 100644 vendor/github.com/bytedance/sonic/internal/encoder/alg/opts.go create mode 100644 vendor/github.com/bytedance/sonic/internal/encoder/alg/primitives.go rename vendor/github.com/bytedance/sonic/internal/encoder/{ => alg}/sort.go (99%) create mode 100644 vendor/github.com/bytedance/sonic/internal/encoder/alg/spec.go create mode 100644 vendor/github.com/bytedance/sonic/internal/encoder/alg/spec_compat.go delete mode 100644 vendor/github.com/bytedance/sonic/internal/encoder/asm_stubs_amd64_go116.go delete mode 100644 vendor/github.com/bytedance/sonic/internal/encoder/assembler_regabi_amd64.go delete mode 100644 vendor/github.com/bytedance/sonic/internal/encoder/assembler_stkabi_amd64.go delete mode 100644 vendor/github.com/bytedance/sonic/internal/encoder/debug_go117.go create mode 100644 vendor/github.com/bytedance/sonic/internal/encoder/encode_norace.go create mode 100644 vendor/github.com/bytedance/sonic/internal/encoder/encode_race.go create mode 100644 vendor/github.com/bytedance/sonic/internal/encoder/ir/op.go delete mode 100644 vendor/github.com/bytedance/sonic/internal/encoder/pools.go create mode 100644 vendor/github.com/bytedance/sonic/internal/encoder/pools_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/encoder/pools_compt.go delete mode 100644 vendor/github.com/bytedance/sonic/internal/encoder/primitives.go delete mode 100644 vendor/github.com/bytedance/sonic/internal/encoder/stubs_go116.go delete mode 100644 vendor/github.com/bytedance/sonic/internal/encoder/stubs_go117.go delete mode 100644 vendor/github.com/bytedance/sonic/internal/encoder/stubs_go120.go delete mode 100644 vendor/github.com/bytedance/sonic/internal/encoder/stubs_go121.go create mode 100644 vendor/github.com/bytedance/sonic/internal/encoder/vars/cache.go create mode 100644 vendor/github.com/bytedance/sonic/internal/encoder/vars/const.go rename vendor/github.com/bytedance/sonic/internal/encoder/{ => vars}/errors.go (68%) create mode 100644 vendor/github.com/bytedance/sonic/internal/encoder/vars/stack.go rename vendor/github.com/bytedance/sonic/internal/encoder/{ => vars}/types.go (63%) create mode 100644 vendor/github.com/bytedance/sonic/internal/encoder/vm/stbus.go create mode 100644 vendor/github.com/bytedance/sonic/internal/encoder/vm/vm.go rename vendor/github.com/bytedance/sonic/internal/encoder/{ => x86}/asm_stubs_amd64_go117.go (74%) rename vendor/github.com/bytedance/sonic/internal/encoder/{ => x86}/asm_stubs_amd64_go121.go (72%) create mode 100644 vendor/github.com/bytedance/sonic/internal/encoder/x86/assembler_regabi_amd64.go rename vendor/github.com/bytedance/sonic/internal/encoder/{ => x86}/debug_go116.go (97%) create mode 100644 vendor/github.com/bytedance/sonic/internal/encoder/x86/debug_go117.go create mode 100644 vendor/github.com/bytedance/sonic/internal/encoder/x86/stbus.go create mode 100644 vendor/github.com/bytedance/sonic/internal/envs/decode.go delete mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx/native_amd64.go delete mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx/native_subr_amd64.go delete mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx/native_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/f32toa.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/f32toa_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/f32toa_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/f64toa.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/f64toa_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/f64toa_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/get_by_path.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/get_by_path_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/get_by_path_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/html_escape.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/html_escape_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/html_escape_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/i64toa.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/i64toa_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/i64toa_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/lookup_small_key.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/lookup_small_key_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/lookup_small_key_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/lspace.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/lspace_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/lspace_text_amd64.go delete mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/native_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/native_export.go delete mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/native_subr_amd64.go delete mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/native_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/parse_with_padding.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/parse_with_padding_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/parse_with_padding_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/quote.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/quote_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/quote_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/skip_array.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/skip_array_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/skip_array_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/skip_number.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/skip_number_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/skip_number_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/skip_object.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/skip_object_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/skip_object_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/skip_one.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/skip_one_fast.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/skip_one_fast_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/skip_one_fast_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/skip_one_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/skip_one_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/u64toa.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/u64toa_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/u64toa_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/unquote.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/unquote_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/unquote_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/validate_one.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/validate_one_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/validate_one_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/validate_utf8.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/validate_utf8_fast.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/validate_utf8_fast_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/validate_utf8_fast_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/validate_utf8_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/validate_utf8_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/value.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/value_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/value_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/vnumber.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/vnumber_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/vnumber_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/vsigned.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/vsigned_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/vsigned_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/vstring.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/vstring_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/vstring_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/vunsigned.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/vunsigned_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/avx2/vunsigned_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/dispatch_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/f32toa.tmpl create mode 100644 vendor/github.com/bytedance/sonic/internal/native/f64toa.tmpl rename vendor/github.com/bytedance/sonic/internal/native/{fastfloat_amd64_test.tmpl => fastfloat_test.tmpl} (99%) rename vendor/github.com/bytedance/sonic/internal/native/{fastint_amd64_test.tmpl => fastint_test.tmpl} (99%) create mode 100644 vendor/github.com/bytedance/sonic/internal/native/get_by_path.tmpl create mode 100644 vendor/github.com/bytedance/sonic/internal/native/html_escape.tmpl create mode 100644 vendor/github.com/bytedance/sonic/internal/native/i64toa.tmpl create mode 100644 vendor/github.com/bytedance/sonic/internal/native/lookup_small_key.tmpl create mode 100644 vendor/github.com/bytedance/sonic/internal/native/lspace.tmpl delete mode 100644 vendor/github.com/bytedance/sonic/internal/native/native_amd64.tmpl create mode 100644 vendor/github.com/bytedance/sonic/internal/native/native_export.tmpl rename vendor/github.com/bytedance/sonic/internal/native/{native_amd64_test.tmpl => native_test.tmpl} (98%) create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/f32toa_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/f32toa_arm64.s create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/f32toa_subr_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/f64toa_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/f64toa_arm64.s create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/f64toa_subr_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/get_by_path_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/get_by_path_arm64.s create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/get_by_path_subr_arm64.go rename vendor/github.com/bytedance/sonic/internal/{encoder/utils.go => native/neon/html_escape_arm64.go} (52%) create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/html_escape_arm64.s create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/html_escape_subr_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/i64toa_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/i64toa_arm64.s create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/i64toa_subr_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/lookup_small_key_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/lookup_small_key_arm64.s create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/lookup_small_key_subr_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/lspace_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/lspace_arm64.s create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/lspace_subr_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/native_export_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/parse_with_padding_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/parse_with_padding_arm64.s create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/parse_with_padding_subr_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/quote_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/quote_arm64.s create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/quote_subr_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/skip_array_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/skip_array_arm64.s create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/skip_array_subr_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/skip_number_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/skip_number_arm64.s create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/skip_number_subr_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/skip_object_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/skip_object_arm64.s create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/skip_object_subr_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/skip_one_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/skip_one_arm64.s create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/skip_one_fast_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/skip_one_fast_arm64.s create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/skip_one_fast_subr_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/skip_one_subr_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/u64toa_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/u64toa_arm64.s create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/u64toa_subr_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/unquote_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/unquote_arm64.s create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/unquote_subr_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/validate_one_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/validate_one_arm64.s create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/validate_one_subr_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/validate_utf8_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/validate_utf8_arm64.s create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/validate_utf8_fast_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/validate_utf8_fast_arm64.s create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/validate_utf8_fast_subr_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/validate_utf8_subr_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/value_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/value_arm64.s create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/value_subr_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/vnumber_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/vnumber_arm64.s create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/vnumber_subr_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/vsigned_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/vsigned_arm64.s create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/vsigned_subr_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/vstring_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/vstring_arm64.s create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/vstring_subr_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/vunsigned_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/vunsigned_arm64.s create mode 100644 vendor/github.com/bytedance/sonic/internal/native/neon/vunsigned_subr_arm64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/parse_with_padding.tmpl create mode 100644 vendor/github.com/bytedance/sonic/internal/native/quote.tmpl delete mode 100644 vendor/github.com/bytedance/sonic/internal/native/recover_amd64_test.tmpl create mode 100644 vendor/github.com/bytedance/sonic/internal/native/recover_test.tmpl create mode 100644 vendor/github.com/bytedance/sonic/internal/native/skip_array.tmpl create mode 100644 vendor/github.com/bytedance/sonic/internal/native/skip_number.tmpl create mode 100644 vendor/github.com/bytedance/sonic/internal/native/skip_object.tmpl create mode 100644 vendor/github.com/bytedance/sonic/internal/native/skip_one.tmpl create mode 100644 vendor/github.com/bytedance/sonic/internal/native/skip_one_fast.tmpl create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/f32toa.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/f32toa_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/f32toa_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/f64toa.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/f64toa_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/f64toa_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/get_by_path.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/get_by_path_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/get_by_path_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/html_escape.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/html_escape_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/html_escape_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/i64toa.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/i64toa_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/i64toa_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/lookup_small_key.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/lookup_small_key_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/lookup_small_key_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/lspace.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/lspace_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/lspace_text_amd64.go delete mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/native_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/native_export.go delete mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/native_subr_amd64.go delete mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/native_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/parse_with_padding.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/parse_with_padding_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/parse_with_padding_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/quote.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/quote_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/quote_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/skip_array.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/skip_array_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/skip_array_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/skip_number.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/skip_number_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/skip_number_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/skip_object.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/skip_object_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/skip_object_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/skip_one.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/skip_one_fast.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/skip_one_fast_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/skip_one_fast_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/skip_one_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/skip_one_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/u64toa.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/u64toa_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/u64toa_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/unquote.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/unquote_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/unquote_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/validate_one.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/validate_one_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/validate_one_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/validate_utf8.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/validate_utf8_fast.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/validate_utf8_fast_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/validate_utf8_fast_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/validate_utf8_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/validate_utf8_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/value.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/value_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/value_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/vnumber.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/vnumber_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/vnumber_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/vsigned.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/vsigned_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/vsigned_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/vstring.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/vstring_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/vstring_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/vunsigned.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/vunsigned_subr.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/sse/vunsigned_text_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/native/traceback_test.mock_tmpl create mode 100644 vendor/github.com/bytedance/sonic/internal/native/u64toa.tmpl create mode 100644 vendor/github.com/bytedance/sonic/internal/native/unquote.tmpl create mode 100644 vendor/github.com/bytedance/sonic/internal/native/validate_one.tmpl create mode 100644 vendor/github.com/bytedance/sonic/internal/native/validate_utf8.tmpl create mode 100644 vendor/github.com/bytedance/sonic/internal/native/validate_utf8_fast.tmpl create mode 100644 vendor/github.com/bytedance/sonic/internal/native/value.tmpl create mode 100644 vendor/github.com/bytedance/sonic/internal/native/vnumber.tmpl create mode 100644 vendor/github.com/bytedance/sonic/internal/native/vsigned.tmpl create mode 100644 vendor/github.com/bytedance/sonic/internal/native/vstring.tmpl create mode 100644 vendor/github.com/bytedance/sonic/internal/native/vunsigned.tmpl rename vendor/github.com/bytedance/sonic/internal/{encoder => optcaching}/asm.s (100%) create mode 100644 vendor/github.com/bytedance/sonic/internal/optcaching/fcache.go create mode 100644 vendor/github.com/bytedance/sonic/internal/rt/assertI2I.go create mode 100644 vendor/github.com/bytedance/sonic/internal/rt/base64_amd64.go create mode 100644 vendor/github.com/bytedance/sonic/internal/rt/base64_compat.go create mode 100644 vendor/github.com/bytedance/sonic/internal/rt/fastconv.go create mode 100644 vendor/github.com/bytedance/sonic/internal/rt/gcwb_legacy.go create mode 100644 vendor/github.com/bytedance/sonic/internal/rt/growslice.go create mode 100644 vendor/github.com/bytedance/sonic/internal/rt/growslice_legacy.go create mode 100644 vendor/github.com/bytedance/sonic/internal/rt/pool.go create mode 100644 vendor/github.com/bytedance/sonic/internal/rt/stubs.go create mode 100644 vendor/github.com/bytedance/sonic/internal/rt/table.go create mode 100644 vendor/github.com/bytedance/sonic/internal/rt/types.go rename vendor/github.com/{chenzhuoyu/base64x => bytedance/sonic/loader}/LICENSE (100%) create mode 100644 vendor/github.com/bytedance/sonic/loader/funcdata_go123.go rename vendor/github.com/bytedance/sonic/{ => loader}/internal/abi/abi.go (98%) rename vendor/github.com/bytedance/sonic/{ => loader}/internal/abi/abi_amd64.go (99%) rename vendor/github.com/bytedance/sonic/{ => loader}/internal/abi/abi_legacy_amd64.go (99%) rename vendor/github.com/bytedance/sonic/{ => loader}/internal/abi/abi_regabi_amd64.go (99%) rename vendor/github.com/bytedance/sonic/{ => loader}/internal/abi/stubs.go (94%) create mode 100644 vendor/github.com/bytedance/sonic/loader/internal/rt/fastmem.go create mode 100644 vendor/github.com/bytedance/sonic/loader/internal/rt/fastvalue.go create mode 100644 vendor/github.com/bytedance/sonic/loader/internal/rt/stackmap.go create mode 100644 vendor/github.com/cespare/xxhash/v2/testall.sh create mode 100644 vendor/github.com/cespare/xxhash/v2/xxhash_arm64.s rename vendor/github.com/cespare/xxhash/v2/{xxhash_amd64.go => xxhash_asm.go} (53%) delete mode 100644 vendor/github.com/chenzhuoyu/base64x/.gitignore delete mode 100644 vendor/github.com/chenzhuoyu/base64x/.gitmodules delete mode 100644 vendor/github.com/chenzhuoyu/base64x/cpuid.go delete mode 100644 vendor/github.com/chenzhuoyu/iasm/expr/pools.go delete mode 100644 vendor/github.com/chenzhuoyu/iasm/expr/term.go delete mode 100644 vendor/github.com/chenzhuoyu/iasm/x86_64/asm.s delete mode 100644 vendor/github.com/chenzhuoyu/iasm/x86_64/operands.go delete mode 100644 vendor/github.com/chenzhuoyu/iasm/x86_64/pools.go delete mode 100644 vendor/github.com/chenzhuoyu/iasm/x86_64/program.go create mode 100644 vendor/github.com/cloudwego/base64x/.gitignore create mode 100644 vendor/github.com/cloudwego/base64x/.golangci.yaml create mode 100644 vendor/github.com/cloudwego/base64x/.licenserc.yaml create mode 100644 vendor/github.com/cloudwego/base64x/CODE_OF_CONDUCT.md create mode 100644 vendor/github.com/cloudwego/base64x/CONTRIBUTING.md rename vendor/github.com/{chenzhuoyu/iasm => cloudwego/base64x}/LICENSE (100%) rename vendor/github.com/{klauspost/compress/LICENSE => cloudwego/base64x/LICENSE-APACHE} (60%) rename vendor/github.com/{chenzhuoyu => cloudwego}/base64x/Makefile (100%) rename vendor/github.com/{chenzhuoyu => cloudwego}/base64x/README.md (100%) create mode 100644 vendor/github.com/cloudwego/base64x/_typos.toml rename vendor/github.com/{chenzhuoyu => cloudwego}/base64x/base64x.go (88%) create mode 100644 vendor/github.com/cloudwego/base64x/check_branch_name.sh create mode 100644 vendor/github.com/cloudwego/base64x/cpuid.go rename vendor/github.com/{chenzhuoyu => cloudwego}/base64x/faststr.go (65%) rename vendor/github.com/{chenzhuoyu => cloudwego}/base64x/native_amd64.go (62%) rename vendor/github.com/{chenzhuoyu => cloudwego}/base64x/native_subr_amd64.go (100%) rename vendor/github.com/{chenzhuoyu => cloudwego}/base64x/native_text_amd64.go (100%) create mode 100644 vendor/github.com/cloudwego/iasm/LICENSE-APACHE rename vendor/github.com/{chenzhuoyu => cloudwego}/iasm/expr/ast.go (91%) rename vendor/github.com/{chenzhuoyu => cloudwego}/iasm/expr/errors.go (54%) rename vendor/github.com/{chenzhuoyu => cloudwego}/iasm/expr/ops.go (62%) rename vendor/github.com/{chenzhuoyu => cloudwego}/iasm/expr/parser.go (92%) rename vendor/github.com/{bytedance/sonic/internal/decoder/generic_stkabi_amd64_test.s => cloudwego/iasm/expr/pools.go} (53%) create mode 100644 vendor/github.com/cloudwego/iasm/expr/term.go rename vendor/github.com/{chenzhuoyu => cloudwego}/iasm/expr/utils.go (64%) rename vendor/github.com/{chenzhuoyu => cloudwego}/iasm/x86_64/arch.go (91%) create mode 100644 vendor/github.com/cloudwego/iasm/x86_64/asm.s rename vendor/github.com/{chenzhuoyu => cloudwego}/iasm/x86_64/assembler.go (98%) rename vendor/github.com/{chenzhuoyu => cloudwego}/iasm/x86_64/assembler_alias.go (60%) rename vendor/github.com/{chenzhuoyu => cloudwego}/iasm/x86_64/eface.go (64%) rename vendor/github.com/{chenzhuoyu => cloudwego}/iasm/x86_64/encodings.go (97%) rename vendor/github.com/{chenzhuoyu => cloudwego}/iasm/x86_64/instructions.go (99%) rename vendor/github.com/{chenzhuoyu => cloudwego}/iasm/x86_64/instructions_table.go (99%) create mode 100644 vendor/github.com/cloudwego/iasm/x86_64/operands.go create mode 100644 vendor/github.com/cloudwego/iasm/x86_64/pools.go create mode 100644 vendor/github.com/cloudwego/iasm/x86_64/program.go rename vendor/github.com/{chenzhuoyu => cloudwego}/iasm/x86_64/registers.go (95%) rename vendor/github.com/{chenzhuoyu => cloudwego}/iasm/x86_64/utils.go (82%) create mode 100644 vendor/github.com/creack/pty/.editorconfig create mode 100644 vendor/github.com/creack/pty/.golangci.yml delete mode 100644 vendor/github.com/creack/pty/Dockerfile.riscv create mode 100644 vendor/github.com/creack/pty/ioctl_inner.go create mode 100644 vendor/github.com/creack/pty/ioctl_legacy.go create mode 100644 vendor/github.com/creack/pty/ztypes_freebsd_riscv64.go create mode 100644 vendor/github.com/creack/pty/ztypes_ppc.go create mode 100644 vendor/github.com/creack/pty/ztypes_sparcx.go delete mode 100644 vendor/github.com/gabriel-vasile/mimetype/mimetype.gif create mode 100644 vendor/github.com/gin-gonic/gin/codecov.yml create mode 100644 vendor/github.com/go-chi/chi/v5/path_value.go create mode 100644 vendor/github.com/go-chi/chi/v5/path_value_fallback.go create mode 100644 vendor/github.com/go-playground/validator/v10/options.go delete mode 100644 vendor/github.com/klauspost/compress/flate/deflate.go delete mode 100644 vendor/github.com/klauspost/compress/flate/dict_decoder.go delete mode 100644 vendor/github.com/klauspost/compress/flate/fast_encoder.go delete mode 100644 vendor/github.com/klauspost/compress/flate/huffman_bit_writer.go delete mode 100644 vendor/github.com/klauspost/compress/flate/huffman_code.go delete mode 100644 vendor/github.com/klauspost/compress/flate/huffman_sortByFreq.go delete mode 100644 vendor/github.com/klauspost/compress/flate/huffman_sortByLiteral.go delete mode 100644 vendor/github.com/klauspost/compress/flate/inflate.go delete mode 100644 vendor/github.com/klauspost/compress/flate/inflate_gen.go delete mode 100644 vendor/github.com/klauspost/compress/flate/level1.go delete mode 100644 vendor/github.com/klauspost/compress/flate/level2.go delete mode 100644 vendor/github.com/klauspost/compress/flate/level3.go delete mode 100644 vendor/github.com/klauspost/compress/flate/level4.go delete mode 100644 vendor/github.com/klauspost/compress/flate/level5.go delete mode 100644 vendor/github.com/klauspost/compress/flate/level6.go delete mode 100644 vendor/github.com/klauspost/compress/flate/regmask_amd64.go delete mode 100644 vendor/github.com/klauspost/compress/flate/regmask_other.go delete mode 100644 vendor/github.com/klauspost/compress/flate/stateless.go delete mode 100644 vendor/github.com/klauspost/compress/flate/token.go create mode 100644 vendor/github.com/leodido/go-urn/kind.go create mode 100644 vendor/github.com/leodido/go-urn/options.go create mode 100644 vendor/github.com/leodido/go-urn/parsing_mode.go create mode 100644 vendor/github.com/leodido/go-urn/scim.go create mode 100644 vendor/github.com/leodido/go-urn/scim/schema/type.go create mode 100644 vendor/github.com/leodido/go-urn/urn8141.go create mode 100644 vendor/github.com/pelletier/go-toml/v2/unstable/unmarshaler.go delete mode 100644 vendor/github.com/spf13/cobra/active_help.md delete mode 100644 vendor/github.com/spf13/cobra/bash_completions.md delete mode 100644 vendor/github.com/spf13/cobra/fish_completions.md delete mode 100644 vendor/github.com/spf13/cobra/powershell_completions.md delete mode 100644 vendor/github.com/spf13/cobra/projects_using_cobra.md delete mode 100644 vendor/github.com/spf13/cobra/shell_completions.md delete mode 100644 vendor/github.com/spf13/cobra/user_guide.md delete mode 100644 vendor/github.com/spf13/cobra/zsh_completions.md delete mode 100644 vendor/golang.org/x/crypto/blake2s/register.go delete mode 100644 vendor/golang.org/x/crypto/curve25519/curve25519_compat.go delete mode 100644 vendor/golang.org/x/crypto/curve25519/curve25519_go120.go delete mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/README delete mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/fe.go delete mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.go delete mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64.s delete mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/fe_amd64_noasm.go delete mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.go delete mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64.s delete mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/fe_arm64_noasm.go delete mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/fe_generic.go delete mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/sync.checkpoint delete mode 100644 vendor/golang.org/x/crypto/curve25519/internal/field/sync.sh delete mode 100644 vendor/golang.org/x/crypto/sha3/hashes_generic.go create mode 100644 vendor/golang.org/x/crypto/sha3/hashes_noasm.go delete mode 100644 vendor/golang.org/x/crypto/sha3/register.go delete mode 100644 vendor/golang.org/x/crypto/sha3/shake_generic.go create mode 100644 vendor/golang.org/x/crypto/sha3/shake_noasm.go delete mode 100644 vendor/golang.org/x/crypto/sha3/xor_generic.go delete mode 100644 vendor/golang.org/x/crypto/sha3/xor_unaligned.go create mode 100644 vendor/golang.org/x/net/http2/config.go create mode 100644 vendor/golang.org/x/net/http2/config_go124.go create mode 100644 vendor/golang.org/x/net/http2/config_pre_go124.go create mode 100644 vendor/golang.org/x/net/http2/timer.go create mode 100644 vendor/golang.org/x/sys/cpu/cpu_linux_riscv64.go create mode 100644 vendor/golang.org/x/sys/unix/vgetrandom_linux.go create mode 100644 vendor/golang.org/x/sys/unix/vgetrandom_unsupported.go create mode 100644 vendor/google.golang.org/protobuf/internal/genid/go_features_gen.go delete mode 100644 vendor/google.golang.org/protobuf/internal/strs/strings_pure.go rename vendor/google.golang.org/protobuf/internal/strs/{strings_unsafe.go => strings_unsafe_go120.go} (97%) create mode 100644 vendor/google.golang.org/protobuf/internal/strs/strings_unsafe_go121.go delete mode 100644 vendor/google.golang.org/protobuf/reflect/protoreflect/value_pure.go rename vendor/google.golang.org/protobuf/reflect/protoreflect/{value_unsafe.go => value_unsafe_go120.go} (93%) create mode 100644 vendor/google.golang.org/protobuf/reflect/protoreflect/value_unsafe_go121.go delete mode 100644 vendor/nhooyr.io/websocket/.gitignore delete mode 100644 vendor/nhooyr.io/websocket/accept_js.go delete mode 100644 vendor/nhooyr.io/websocket/close_notjs.go delete mode 100644 vendor/nhooyr.io/websocket/compress_notjs.go delete mode 100644 vendor/nhooyr.io/websocket/conn_notjs.go create mode 100644 vendor/nhooyr.io/websocket/internal/util/util.go create mode 100644 vendor/nhooyr.io/websocket/make.sh create mode 100644 vendor/nhooyr.io/websocket/mask.go create mode 100644 vendor/nhooyr.io/websocket/mask_amd64.s create mode 100644 vendor/nhooyr.io/websocket/mask_arm64.s create mode 100644 vendor/nhooyr.io/websocket/mask_asm.go create mode 100644 vendor/nhooyr.io/websocket/mask_go.go create mode 100644 vendor/nhooyr.io/websocket/netconn_js.go create mode 100644 vendor/nhooyr.io/websocket/netconn_notjs.go diff --git a/go.mod b/go.mod index 0f8d7b21a..3b944eb3b 100644 --- a/go.mod +++ b/go.mod @@ -1,75 +1,75 @@ module github.com/skycoin/dmsg -go 1.21 +go 1.22 -toolchain go1.21.4 +toolchain go1.23.1 require ( github.com/ActiveState/termtest/conpty v0.5.0 - github.com/VictoriaMetrics/metrics v1.24.0 - github.com/bitfield/script v0.22.1 + github.com/VictoriaMetrics/metrics v1.35.1 + github.com/bitfield/script v0.23.0 github.com/confiant-inc/go-socks5 v0.0.0-20210816151940-c1124825b1d6 - github.com/creack/pty v1.1.18 - github.com/gin-gonic/gin v1.9.1 - github.com/go-chi/chi/v5 v5.0.11 + github.com/creack/pty v1.1.23 + github.com/gin-gonic/gin v1.10.0 + github.com/go-chi/chi/v5 v5.1.0 github.com/go-redis/redis/v8 v8.11.5 - github.com/hashicorp/yamux v0.1.1 + github.com/hashicorp/yamux v0.1.2 github.com/ivanpirog/coloredcobra v1.0.1 github.com/json-iterator/go v1.1.12 - github.com/pires/go-proxyproto v0.6.2 + github.com/pires/go-proxyproto v0.8.0 github.com/sirupsen/logrus v1.9.3 github.com/skycoin/noise v0.0.0-20180327030543-2492fe189ae6 github.com/skycoin/skycoin v0.28.0 github.com/skycoin/skywire v1.3.28 github.com/skycoin/skywire-utilities v1.3.25 - github.com/spf13/cobra v1.7.0 + github.com/spf13/cobra v1.8.1 github.com/stretchr/testify v1.9.0 - golang.org/x/net v0.21.0 - golang.org/x/sys v0.20.0 - golang.org/x/term v0.17.0 - nhooyr.io/websocket v1.8.7 + golang.org/x/net v0.30.0 + golang.org/x/sys v0.26.0 + golang.org/x/term v0.25.0 + nhooyr.io/websocket v1.8.17 ) require ( github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect - github.com/bytedance/sonic v1.10.0 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect - github.com/chenzhuoyu/iasm v0.9.0 // indirect + github.com/bytedance/sonic v1.12.3 // indirect + github.com/bytedance/sonic/loader v0.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/fatih/color v1.15.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/fatih/color v1.17.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.6 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.15.1 // indirect - github.com/goccy/go-json v0.10.2 // indirect + github.com/go-playground/validator/v10 v10.22.1 // indirect + github.com/goccy/go-json v0.10.3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/itchyny/gojq v0.12.13 // indirect - github.com/itchyny/timefmt-go v0.1.5 // indirect - github.com/klauspost/compress v1.16.7 // indirect - github.com/klauspost/cpuid/v2 v2.2.5 // indirect - github.com/leodido/go-urn v1.2.4 // indirect + github.com/itchyny/gojq v0.12.16 // indirect + github.com/itchyny/timefmt-go v0.1.6 // indirect + github.com/klauspost/cpuid/v2 v2.2.8 // indirect + github.com/leodido/go-urn v1.4.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.0.9 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/ugorji/go/codec v1.2.11 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect github.com/valyala/fastrand v1.1.0 // indirect github.com/valyala/histogram v1.2.0 // indirect - golang.org/x/arch v0.4.0 // indirect - golang.org/x/crypto v0.20.0 // indirect - golang.org/x/text v0.14.0 // indirect - google.golang.org/protobuf v1.31.0 // indirect + golang.org/x/arch v0.11.0 // indirect + golang.org/x/crypto v0.28.0 // indirect + golang.org/x/text v0.19.0 // indirect + google.golang.org/protobuf v1.35.1 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - mvdan.cc/sh/v3 v3.7.0 // indirect + mvdan.cc/sh/v3 v3.9.0 // indirect ) // Uncomment for tests with alternate branches of 'skywire-utilities' diff --git a/go.sum b/go.sum index 03201037d..9a9759752 100644 --- a/go.sum +++ b/go.sum @@ -4,110 +4,85 @@ github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/VictoriaMetrics/metrics v1.24.0 h1:ILavebReOjYctAGY5QU2F9X0MYvkcrG3aEn2RKa1Zkw= -github.com/VictoriaMetrics/metrics v1.24.0/go.mod h1:eFT25kvsTidQFHb6U0oa0rTrDRdz4xTYjpL8+UPohys= +github.com/VictoriaMetrics/metrics v1.35.1 h1:o84wtBKQbzLdDy14XeskkCZih6anG+veZ1SwJHFGwrU= +github.com/VictoriaMetrics/metrics v1.35.1/go.mod h1:r7hveu6xMdUACXvB8TYdAj8WEsKzWB0EkpJN+RDtOf8= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= -github.com/bitfield/script v0.22.1 h1:DphxoC5ssYciwd0ZS+N0Xae46geAD/0mVWh6a2NUxM4= -github.com/bitfield/script v0.22.1/go.mod h1:fv+6x4OzVsRs6qAlc7wiGq8fq1b5orhtQdtW0dwjUHI= +github.com/bitfield/script v0.23.0 h1:N0R5yLEl6wJIS9PR/A6xXwjMsplMubyxdi05N5l0X28= +github.com/bitfield/script v0.23.0/go.mod h1:fv+6x4OzVsRs6qAlc7wiGq8fq1b5orhtQdtW0dwjUHI= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= -github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= -github.com/bytedance/sonic v1.10.0 h1:qtNZduETEIWJVIyDl01BeNxur2rW9OwTQ/yBqFRkKEk= -github.com/bytedance/sonic v1.10.0/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= +github.com/bytedance/sonic v1.12.3 h1:W2MGa7RCU1QTeYRTPE3+88mVC0yXmsRQRChiyVocVjU= +github.com/bytedance/sonic v1.12.3/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM= +github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/cenkalti/backoff v1.1.0/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= -github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= -github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= -github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo= -github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= +github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= github.com/confiant-inc/go-socks5 v0.0.0-20210816151940-c1124825b1d6 h1:sRQemCQ+r6Ht7uIT0D9Xcyjed4lKpDhNKarBEPFZp3c= github.com/confiant-inc/go-socks5 v0.0.0-20210816151940-c1124825b1d6/go.mod h1:S4w2wY39ZYaWQLXNMZ6uVfIyYrKmLP2N/S2/5YIFU6o= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= -github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.23 h1:4M6+isWdcStXEf15G/RbrMPOQj1dZ7HPZCGwE4kOeP0= +github.com/creack/pty v1.1.23/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= -github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA= -github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= -github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/gabriel-vasile/mimetype v1.4.6 h1:3+PzJTKLkvgjeTbts6msPJt4DixhT4YtFNf1gtGe3zc= +github.com/gabriel-vasile/mimetype v1.4.6/go.mod h1:JX1qVKqZd40hUPpAfiNTe0Sne7hdfKSbOqqmkq8GCXc= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= -github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= -github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= -github.com/go-chi/chi/v5 v5.0.11 h1:BnpYbFZ3T3S1WMpD79r7R5ThWX40TaFB7L31Y8xqSwA= -github.com/go-chi/chi/v5 v5.0.11/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= +github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= +github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= -github.com/go-playground/validator/v10 v10.15.1 h1:BSe8uhN+xQ4r5guV/ywQI4gO59C2raYcGffYWZEjZzM= -github.com/go-playground/validator/v10 v10.15.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-playground/validator/v10 v10.22.1 h1:40JcKH+bBNGFczGuoBYgX4I6m/i27HYW8P9FDk5PbgA= +github.com/go-playground/validator/v10 v10.22.1/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= +github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= -github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= -github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= -github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= -github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= -github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= -github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= -github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= +github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/itchyny/gojq v0.12.13 h1:IxyYlHYIlspQHHTE0f3cJF0NKDMfajxViuhBLnHd/QU= -github.com/itchyny/gojq v0.12.13/go.mod h1:JzwzAqenfhrPUuwbmEz3nu3JQmFLlQTQMUcOdnu/Sf4= -github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE= -github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8= +github.com/itchyny/gojq v0.12.16 h1:yLfgLxhIr/6sJNVmYfQjTIv0jGctu6/DgDoivmxTr7g= +github.com/itchyny/gojq v0.12.16/go.mod h1:6abHbdC2uB9ogMS38XsErnfqJ94UlngIJGlRAIj4jTM= +github.com/itchyny/timefmt-go v0.1.6 h1:ia3s54iciXDdzWzwaVKXZPbiXzxxnv1SPGFfM/myJ5Q= +github.com/itchyny/timefmt-go v0.1.6/go.mod h1:RRDZYC5s9ErkjQvTvvU7keJjxUYzIISJGxm9/mAERQg= github.com/ivanpirog/coloredcobra v1.0.1 h1:aURSdEmlR90/tSiWS0dMjdwOvCVUeYLfltLfbgNxrN4= github.com/ivanpirog/coloredcobra v1.0.1/go.mod h1:iho4nEKcnwZFiniGSdcgdvRgZNjxm+h20acv8vqmN6Q= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= +github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -118,9 +93,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= -github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= -github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -130,8 +104,8 @@ github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= @@ -140,7 +114,6 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= @@ -150,14 +123,14 @@ github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042 github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0= -github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= -github.com/pires/go-proxyproto v0.6.2 h1:KAZ7UteSOt6urjme6ZldyFm4wDe/z0ZUP0Yv0Dos0d8= -github.com/pires/go-proxyproto v0.6.2/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/pires/go-proxyproto v0.8.0 h1:5unRmEAPbHXHuLjDg01CxJWf91cw3lKHc/0xzKpXEe0= +github.com/pires/go-proxyproto v0.8.0/go.mod h1:iknsfgnH8EkjrMeMyvfKByp9TiBZCKZM0jx2xmKqnVY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= @@ -178,8 +151,8 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= -github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -192,37 +165,31 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/toqueteos/webbrowser v1.1.0/go.mod h1:Hqqqmzj8AHn+VlZyVjaRWY20i25hoOZGAABCcg2el4A= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/valyala/fastrand v1.1.0 h1:f+5HkLW4rsgzdNoleUOB69hyT9IlD2ZQh9GyDMfb5G8= github.com/valyala/fastrand v1.1.0/go.mod h1:HWqCzkrkg6QXT8V2EXWvXCoow7vLwOFN002oeRzjapQ= github.com/valyala/histogram v1.2.0 h1:wyYGAZZt3CpwUiIb9AU/Zbllg1llXyrtApRS815OLoQ= github.com/valyala/histogram v1.2.0/go.mod h1:Hb4kBwb4UxsaNbbbh+RRz8ZR6pdodR57tzWUS3BUzXY= -golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc= -golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.11.0 h1:KXV8WWKCXm6tRpLirl2szsO5j/oOODwZf4hATmGVNs4= +golang.org/x/arch v0.11.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181015023909-0c41d7ab0a0e/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.20.0 h1:jmAMJJZXr5KiCw05dfYK9QnqaqKLYXijU23lsEdcQqg= -golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181023152157-44b849a8bc13/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -235,38 +202,30 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= +golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E= -golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -mvdan.cc/sh/v3 v3.7.0 h1:lSTjdP/1xsddtaKfGg7Myu7DnlHItd3/M2tomOcNNBg= -mvdan.cc/sh/v3 v3.7.0/go.mod h1:K2gwkaesF/D7av7Kxl0HbF5kGOd2ArupNTX3X44+8l8= -nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= -nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +mvdan.cc/sh/v3 v3.9.0 h1:it14fyjCdQUk4jf/aYxLO3FG8jFarR9GzMCtnlvvD7c= +mvdan.cc/sh/v3 v3.9.0/go.mod h1:cdBk8bgoiBI7lSZqK5JhUuq7OB64VQ7fgm85xelw3Nk= +nhooyr.io/websocket v1.8.17 h1:KEVeLJkUywCKVsnLIDlD/5gtayKp8VoCkksHCGGfT9Y= +nhooyr.io/websocket v1.8.17/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/vendor/github.com/VictoriaMetrics/metrics/README.md b/vendor/github.com/VictoriaMetrics/metrics/README.md index e1a2537cb..b01d81e85 100644 --- a/vendor/github.com/VictoriaMetrics/metrics/README.md +++ b/vendor/github.com/VictoriaMetrics/metrics/README.md @@ -73,8 +73,11 @@ http.HandleFunc("/metrics", func(w http.ResponseWriter, req *http.Request) { metrics.InitPush("http://victoria-metrics:8428/api/v1/import/prometheus", 10*time.Second, `instance="foobar"`, true) ``` -See [docs](http://godoc.org/github.com/VictoriaMetrics/metrics) for more info. +By default, exposed metrics [do not have](https://github.com/VictoriaMetrics/metrics/issues/48#issuecomment-1620765811) +`TYPE` or `HELP` meta information. Call [`ExposeMetadata(true)`](https://pkg.go.dev/github.com/VictoriaMetrics/metrics#ExposeMetadata) +in order to generate `TYPE` and `HELP` meta information per each metric. +See [docs](https://pkg.go.dev/github.com/VictoriaMetrics/metrics) for more info. ### Users diff --git a/vendor/github.com/VictoriaMetrics/metrics/counter.go b/vendor/github.com/VictoriaMetrics/metrics/counter.go index dfe947794..1076e80c2 100644 --- a/vendor/github.com/VictoriaMetrics/metrics/counter.go +++ b/vendor/github.com/VictoriaMetrics/metrics/counter.go @@ -42,6 +42,11 @@ func (c *Counter) Add(n int) { atomic.AddUint64(&c.n, uint64(n)) } +// AddInt64 adds n to c. +func (c *Counter) AddInt64(n int64) { + atomic.AddUint64(&c.n, uint64(n)) +} + // Get returns the current value for c. func (c *Counter) Get() uint64 { return atomic.LoadUint64(&c.n) @@ -58,6 +63,10 @@ func (c *Counter) marshalTo(prefix string, w io.Writer) { fmt.Fprintf(w, "%s %d\n", prefix, v) } +func (c *Counter) metricType() string { + return "counter" +} + // GetOrCreateCounter returns registered counter with the given name // or creates new counter if the registry doesn't contain counter with // the given name. diff --git a/vendor/github.com/VictoriaMetrics/metrics/floatcounter.go b/vendor/github.com/VictoriaMetrics/metrics/floatcounter.go index f89879099..8bd9fa67a 100644 --- a/vendor/github.com/VictoriaMetrics/metrics/floatcounter.go +++ b/vendor/github.com/VictoriaMetrics/metrics/floatcounter.go @@ -63,6 +63,10 @@ func (fc *FloatCounter) marshalTo(prefix string, w io.Writer) { fmt.Fprintf(w, "%s %g\n", prefix, v) } +func (fc *FloatCounter) metricType() string { + return "counter" +} + // GetOrCreateFloatCounter returns registered FloatCounter with the given name // or creates new FloatCounter if the registry doesn't contain FloatCounter with // the given name. diff --git a/vendor/github.com/VictoriaMetrics/metrics/gauge.go b/vendor/github.com/VictoriaMetrics/metrics/gauge.go index 9084fc4d7..3573e1445 100644 --- a/vendor/github.com/VictoriaMetrics/metrics/gauge.go +++ b/vendor/github.com/VictoriaMetrics/metrics/gauge.go @@ -3,10 +3,11 @@ package metrics import ( "fmt" "io" + "math" + "sync/atomic" ) -// NewGauge registers and returns gauge with the given name, which calls f -// to obtain gauge value. +// NewGauge registers and returns gauge with the given name, which calls f to obtain gauge value. // // name must be valid Prometheus-compatible metric with possible labels. // For instance, @@ -16,6 +17,7 @@ import ( // - foo{bar="baz",aaa="b"} // // f must be safe for concurrent calls. +// if f is nil, then it is expected that the gauge value is changed via Set(), Inc(), Dec() and Add() calls. // // The returned gauge is safe to use from concurrent goroutines. // @@ -25,19 +27,68 @@ func NewGauge(name string, f func() float64) *Gauge { } // Gauge is a float64 gauge. -// -// See also Counter, which could be used as a gauge with Set and Dec calls. type Gauge struct { + // valueBits contains uint64 representation of float64 passed to Gauge.Set. + valueBits uint64 + + // f is a callback, which is called for returning the gauge value. f func() float64 } // Get returns the current value for g. func (g *Gauge) Get() float64 { - return g.f() + if f := g.f; f != nil { + return f() + } + n := atomic.LoadUint64(&g.valueBits) + return math.Float64frombits(n) +} + +// Set sets g value to v. +// +// The g must be created with nil callback in order to be able to call this function. +func (g *Gauge) Set(v float64) { + if g.f != nil { + panic(fmt.Errorf("cannot call Set on gauge created with non-nil callback")) + } + n := math.Float64bits(v) + atomic.StoreUint64(&g.valueBits, n) +} + +// Inc increments g by 1. +// +// The g must be created with nil callback in order to be able to call this function. +func (g *Gauge) Inc() { + g.Add(1) +} + +// Dec decrements g by 1. +// +// The g must be created with nil callback in order to be able to call this function. +func (g *Gauge) Dec() { + g.Add(-1) +} + +// Add adds fAdd to g. fAdd may be positive and negative. +// +// The g must be created with nil callback in order to be able to call this function. +func (g *Gauge) Add(fAdd float64) { + if g.f != nil { + panic(fmt.Errorf("cannot call Set on gauge created with non-nil callback")) + } + for { + n := atomic.LoadUint64(&g.valueBits) + f := math.Float64frombits(n) + fNew := f + fAdd + nNew := math.Float64bits(fNew) + if atomic.CompareAndSwapUint64(&g.valueBits, n, nNew) { + break + } + } } func (g *Gauge) marshalTo(prefix string, w io.Writer) { - v := g.f() + v := g.Get() if float64(int64(v)) == v { // Marshal integer values without scientific notation fmt.Fprintf(w, "%s %d\n", prefix, int64(v)) @@ -46,6 +97,10 @@ func (g *Gauge) marshalTo(prefix string, w io.Writer) { } } +func (g *Gauge) metricType() string { + return "gauge" +} + // GetOrCreateGauge returns registered gauge with the given name // or creates new gauge if the registry doesn't contain gauge with // the given name. diff --git a/vendor/github.com/VictoriaMetrics/metrics/go_metrics.go b/vendor/github.com/VictoriaMetrics/metrics/go_metrics.go index f8b606731..d8b949de7 100644 --- a/vendor/github.com/VictoriaMetrics/metrics/go_metrics.go +++ b/vendor/github.com/VictoriaMetrics/metrics/go_metrics.go @@ -3,41 +3,78 @@ package metrics import ( "fmt" "io" + "log" + "math" "runtime" + runtimemetrics "runtime/metrics" + "strings" "github.com/valyala/histogram" ) +// See https://pkg.go.dev/runtime/metrics#hdr-Supported_metrics +var runtimeMetrics = [][2]string{ + {"/sched/latencies:seconds", "go_sched_latencies_seconds"}, + {"/sync/mutex/wait/total:seconds", "go_mutex_wait_seconds_total"}, + {"/cpu/classes/gc/mark/assist:cpu-seconds", "go_gc_mark_assist_cpu_seconds_total"}, + {"/cpu/classes/gc/total:cpu-seconds", "go_gc_cpu_seconds_total"}, + {"/gc/pauses:seconds", "go_gc_pauses_seconds"}, + {"/cpu/classes/scavenge/total:cpu-seconds", "go_scavenge_cpu_seconds_total"}, + {"/gc/gomemlimit:bytes", "go_memlimit_bytes"}, +} + +var supportedRuntimeMetrics = initSupportedRuntimeMetrics(runtimeMetrics) + +func initSupportedRuntimeMetrics(rms [][2]string) [][2]string { + exposedMetrics := make(map[string]struct{}) + for _, d := range runtimemetrics.All() { + exposedMetrics[d.Name] = struct{}{} + } + var supportedMetrics [][2]string + for _, rm := range rms { + metricName := rm[0] + if _, ok := exposedMetrics[metricName]; ok { + supportedMetrics = append(supportedMetrics, rm) + } else { + log.Printf("github.com/VictoriaMetrics/metrics: do not expose %s metric, since the corresponding metric %s isn't supported in the current Go runtime", rm[1], metricName) + } + } + return supportedMetrics +} + func writeGoMetrics(w io.Writer) { + writeRuntimeMetrics(w) + var ms runtime.MemStats runtime.ReadMemStats(&ms) - fmt.Fprintf(w, "go_memstats_alloc_bytes %d\n", ms.Alloc) - fmt.Fprintf(w, "go_memstats_alloc_bytes_total %d\n", ms.TotalAlloc) - fmt.Fprintf(w, "go_memstats_buck_hash_sys_bytes %d\n", ms.BuckHashSys) - fmt.Fprintf(w, "go_memstats_frees_total %d\n", ms.Frees) - fmt.Fprintf(w, "go_memstats_gc_cpu_fraction %g\n", ms.GCCPUFraction) - fmt.Fprintf(w, "go_memstats_gc_sys_bytes %d\n", ms.GCSys) - fmt.Fprintf(w, "go_memstats_heap_alloc_bytes %d\n", ms.HeapAlloc) - fmt.Fprintf(w, "go_memstats_heap_idle_bytes %d\n", ms.HeapIdle) - fmt.Fprintf(w, "go_memstats_heap_inuse_bytes %d\n", ms.HeapInuse) - fmt.Fprintf(w, "go_memstats_heap_objects %d\n", ms.HeapObjects) - fmt.Fprintf(w, "go_memstats_heap_released_bytes %d\n", ms.HeapReleased) - fmt.Fprintf(w, "go_memstats_heap_sys_bytes %d\n", ms.HeapSys) - fmt.Fprintf(w, "go_memstats_last_gc_time_seconds %g\n", float64(ms.LastGC)/1e9) - fmt.Fprintf(w, "go_memstats_lookups_total %d\n", ms.Lookups) - fmt.Fprintf(w, "go_memstats_mallocs_total %d\n", ms.Mallocs) - fmt.Fprintf(w, "go_memstats_mcache_inuse_bytes %d\n", ms.MCacheInuse) - fmt.Fprintf(w, "go_memstats_mcache_sys_bytes %d\n", ms.MCacheSys) - fmt.Fprintf(w, "go_memstats_mspan_inuse_bytes %d\n", ms.MSpanInuse) - fmt.Fprintf(w, "go_memstats_mspan_sys_bytes %d\n", ms.MSpanSys) - fmt.Fprintf(w, "go_memstats_next_gc_bytes %d\n", ms.NextGC) - fmt.Fprintf(w, "go_memstats_other_sys_bytes %d\n", ms.OtherSys) - fmt.Fprintf(w, "go_memstats_stack_inuse_bytes %d\n", ms.StackInuse) - fmt.Fprintf(w, "go_memstats_stack_sys_bytes %d\n", ms.StackSys) - fmt.Fprintf(w, "go_memstats_sys_bytes %d\n", ms.Sys) - - fmt.Fprintf(w, "go_cgo_calls_count %d\n", runtime.NumCgoCall()) - fmt.Fprintf(w, "go_cpu_count %d\n", runtime.NumCPU()) + WriteGaugeUint64(w, "go_memstats_alloc_bytes", ms.Alloc) + WriteCounterUint64(w, "go_memstats_alloc_bytes_total", ms.TotalAlloc) + WriteGaugeUint64(w, "go_memstats_buck_hash_sys_bytes", ms.BuckHashSys) + WriteCounterUint64(w, "go_memstats_frees_total", ms.Frees) + WriteGaugeFloat64(w, "go_memstats_gc_cpu_fraction", ms.GCCPUFraction) + WriteGaugeUint64(w, "go_memstats_gc_sys_bytes", ms.GCSys) + + WriteGaugeUint64(w, "go_memstats_heap_alloc_bytes", ms.HeapAlloc) + WriteGaugeUint64(w, "go_memstats_heap_idle_bytes", ms.HeapIdle) + WriteGaugeUint64(w, "go_memstats_heap_inuse_bytes", ms.HeapInuse) + WriteGaugeUint64(w, "go_memstats_heap_objects", ms.HeapObjects) + WriteGaugeUint64(w, "go_memstats_heap_released_bytes", ms.HeapReleased) + WriteGaugeUint64(w, "go_memstats_heap_sys_bytes", ms.HeapSys) + WriteGaugeFloat64(w, "go_memstats_last_gc_time_seconds", float64(ms.LastGC)/1e9) + WriteCounterUint64(w, "go_memstats_lookups_total", ms.Lookups) + WriteCounterUint64(w, "go_memstats_mallocs_total", ms.Mallocs) + WriteGaugeUint64(w, "go_memstats_mcache_inuse_bytes", ms.MCacheInuse) + WriteGaugeUint64(w, "go_memstats_mcache_sys_bytes", ms.MCacheSys) + WriteGaugeUint64(w, "go_memstats_mspan_inuse_bytes", ms.MSpanInuse) + WriteGaugeUint64(w, "go_memstats_mspan_sys_bytes", ms.MSpanSys) + WriteGaugeUint64(w, "go_memstats_next_gc_bytes", ms.NextGC) + WriteGaugeUint64(w, "go_memstats_other_sys_bytes", ms.OtherSys) + WriteGaugeUint64(w, "go_memstats_stack_inuse_bytes", ms.StackInuse) + WriteGaugeUint64(w, "go_memstats_stack_sys_bytes", ms.StackSys) + WriteGaugeUint64(w, "go_memstats_sys_bytes", ms.Sys) + + WriteCounterUint64(w, "go_cgo_calls_count", uint64(runtime.NumCgoCall())) + WriteGaugeUint64(w, "go_cpu_count", uint64(runtime.NumCPU())) gcPauses := histogram.NewFast() for _, pauseNs := range ms.PauseNs[:] { @@ -45,20 +82,103 @@ func writeGoMetrics(w io.Writer) { } phis := []float64{0, 0.25, 0.5, 0.75, 1} quantiles := make([]float64, 0, len(phis)) + WriteMetadataIfNeeded(w, "go_gc_duration_seconds", "summary") for i, q := range gcPauses.Quantiles(quantiles[:0], phis) { fmt.Fprintf(w, `go_gc_duration_seconds{quantile="%g"} %g`+"\n", phis[i], q) } - fmt.Fprintf(w, `go_gc_duration_seconds_sum %g`+"\n", float64(ms.PauseTotalNs)/1e9) - fmt.Fprintf(w, `go_gc_duration_seconds_count %d`+"\n", ms.NumGC) - fmt.Fprintf(w, `go_gc_forced_count %d`+"\n", ms.NumForcedGC) + fmt.Fprintf(w, "go_gc_duration_seconds_sum %g\n", float64(ms.PauseTotalNs)/1e9) + fmt.Fprintf(w, "go_gc_duration_seconds_count %d\n", ms.NumGC) + + WriteCounterUint64(w, "go_gc_forced_count", uint64(ms.NumForcedGC)) - fmt.Fprintf(w, `go_gomaxprocs %d`+"\n", runtime.GOMAXPROCS(0)) - fmt.Fprintf(w, `go_goroutines %d`+"\n", runtime.NumGoroutine()) + WriteGaugeUint64(w, "go_gomaxprocs", uint64(runtime.GOMAXPROCS(0))) + WriteGaugeUint64(w, "go_goroutines", uint64(runtime.NumGoroutine())) numThread, _ := runtime.ThreadCreateProfile(nil) - fmt.Fprintf(w, `go_threads %d`+"\n", numThread) + WriteGaugeUint64(w, "go_threads", uint64(numThread)) // Export build details. + WriteMetadataIfNeeded(w, "go_info", "gauge") fmt.Fprintf(w, "go_info{version=%q} 1\n", runtime.Version()) + + WriteMetadataIfNeeded(w, "go_info_ext", "gauge") fmt.Fprintf(w, "go_info_ext{compiler=%q, GOARCH=%q, GOOS=%q, GOROOT=%q} 1\n", runtime.Compiler, runtime.GOARCH, runtime.GOOS, runtime.GOROOT()) } + +func writeRuntimeMetrics(w io.Writer) { + samples := make([]runtimemetrics.Sample, len(supportedRuntimeMetrics)) + for i, rm := range supportedRuntimeMetrics { + samples[i].Name = rm[0] + } + runtimemetrics.Read(samples) + for i, rm := range supportedRuntimeMetrics { + writeRuntimeMetric(w, rm[1], &samples[i]) + } +} + +func writeRuntimeMetric(w io.Writer, name string, sample *runtimemetrics.Sample) { + kind := sample.Value.Kind() + switch kind { + case runtimemetrics.KindBad: + panic(fmt.Errorf("BUG: unexpected runtimemetrics.KindBad for sample.Name=%q", sample.Name)) + case runtimemetrics.KindUint64: + v := sample.Value.Uint64() + if strings.HasSuffix(name, "_total") { + WriteCounterUint64(w, name, v) + } else { + WriteGaugeUint64(w, name, v) + } + case runtimemetrics.KindFloat64: + v := sample.Value.Float64() + if isCounterName(name) { + WriteCounterFloat64(w, name, v) + } else { + WriteGaugeFloat64(w, name, v) + } + case runtimemetrics.KindFloat64Histogram: + h := sample.Value.Float64Histogram() + writeRuntimeHistogramMetric(w, name, h) + default: + panic(fmt.Errorf("unexpected metric kind=%d", kind)) + } +} + +func writeRuntimeHistogramMetric(w io.Writer, name string, h *runtimemetrics.Float64Histogram) { + buckets := h.Buckets + counts := h.Counts + if len(buckets) != len(counts)+1 { + panic(fmt.Errorf("the number of buckets must be bigger than the number of counts by 1 in histogram %s; got buckets=%d, counts=%d", name, len(buckets), len(counts))) + } + tailCount := uint64(0) + if strings.HasSuffix(name, "_seconds") { + // Limit the maximum bucket to 1 second, since Go runtime exposes buckets with 10K seconds, + // which have little sense. At the same time such buckets may lead to high cardinality issues + // at the scraper side. + for len(buckets) > 0 && buckets[len(buckets)-1] > 1 { + buckets = buckets[:len(buckets)-1] + tailCount += counts[len(counts)-1] + counts = counts[:len(counts)-1] + } + } + + iStep := float64(len(buckets)) / maxRuntimeHistogramBuckets + + totalCount := uint64(0) + iNext := 0.0 + WriteMetadataIfNeeded(w, name, "histogram") + for i, count := range counts { + totalCount += count + if float64(i) >= iNext { + iNext += iStep + le := buckets[i+1] + if !math.IsInf(le, 1) { + fmt.Fprintf(w, `%s_bucket{le="%g"} %d`+"\n", name, le, totalCount) + } + } + } + totalCount += tailCount + fmt.Fprintf(w, `%s_bucket{le="+Inf"} %d`+"\n", name, totalCount) +} + +// Limit the number of buckets for Go runtime histograms in order to prevent from high cardinality issues at scraper side. +const maxRuntimeHistogramBuckets = 30 diff --git a/vendor/github.com/VictoriaMetrics/metrics/histogram.go b/vendor/github.com/VictoriaMetrics/metrics/histogram.go index a57668177..d703ae82f 100644 --- a/vendor/github.com/VictoriaMetrics/metrics/histogram.go +++ b/vendor/github.com/VictoriaMetrics/metrics/histogram.go @@ -36,7 +36,7 @@ var bucketMultiplier = math.Pow(10, 1.0/bucketsPerDecimal) // // Histogram buckets can be converted to Prometheus-like buckets with `le` labels // with `prometheus_buckets(_bucket)` function from PromQL extensions in VictoriaMetrics. -// (see https://github.com/VictoriaMetrics/VictoriaMetrics/wiki/MetricsQL ): +// (see https://docs.victoriametrics.com/metricsql/ ): // // prometheus_buckets(request_duration_bucket) // @@ -47,13 +47,21 @@ var bucketMultiplier = math.Pow(10, 1.0/bucketsPerDecimal) // Zero histogram is usable. type Histogram struct { // Mu gurantees synchronous update for all the counters and sum. + // + // Do not use sync.RWMutex, since it has zero sense from performance PoV. + // It only complicates the code. mu sync.Mutex + // decimalBuckets contains counters for histogram buckets decimalBuckets [decimalBucketsCount]*[bucketsPerDecimal]uint64 + // lower is the number of values, which hit the lower bucket lower uint64 + + // upper is the number of values, which hit the upper bucket upper uint64 + // sum is the sum of all the values put into Histogram sum float64 } @@ -109,6 +117,34 @@ func (h *Histogram) Update(v float64) { h.mu.Unlock() } +// Merge merges src to h +func (h *Histogram) Merge(src *Histogram) { + h.mu.Lock() + defer h.mu.Unlock() + + src.mu.Lock() + defer src.mu.Unlock() + + h.lower += src.lower + h.upper += src.upper + h.sum += src.sum + + for i, dbSrc := range src.decimalBuckets { + if dbSrc == nil { + continue + } + dbDst := h.decimalBuckets[i] + if dbDst == nil { + var b [bucketsPerDecimal]uint64 + dbDst = &b + h.decimalBuckets[i] = dbDst + } + for j := range dbSrc { + dbDst[j] += dbSrc[j] + } + } +} + // VisitNonZeroBuckets calls f for all buckets with non-zero counters. // // vmrange contains "..." string with bucket bounds. The lower bound @@ -228,3 +264,7 @@ func (h *Histogram) getSum() float64 { h.mu.Unlock() return sum } + +func (h *Histogram) metricType() string { + return "histogram" +} diff --git a/vendor/github.com/VictoriaMetrics/metrics/metrics.go b/vendor/github.com/VictoriaMetrics/metrics/metrics.go index 7dfa97219..74e97352c 100644 --- a/vendor/github.com/VictoriaMetrics/metrics/metrics.go +++ b/vendor/github.com/VictoriaMetrics/metrics/metrics.go @@ -13,9 +13,12 @@ package metrics import ( + "fmt" "io" "sort" + "strings" "sync" + "sync/atomic" "unsafe" ) @@ -27,6 +30,7 @@ type namedMetric struct { type metric interface { marshalTo(prefix string, w io.Writer) + metricType() string } var defaultSet = NewSet() @@ -51,16 +55,33 @@ func RegisterSet(s *Set) { // UnregisterSet stops exporting metrics for the given s via global WritePrometheus() call. // -// Call s.UnregisterAllMetrics() after unregistering s if it is no longer used. -func UnregisterSet(s *Set) { +// If destroySet is set to true, then s.UnregisterAllMetrics() is called on s after unregistering it, +// so s becomes destroyed. Otherwise the s can be registered again in the set by passing it to RegisterSet(). +func UnregisterSet(s *Set, destroySet bool) { registeredSetsLock.Lock() delete(registeredSets, s) registeredSetsLock.Unlock() + + if destroySet { + s.UnregisterAllMetrics() + } } -// WritePrometheus writes all the metrics from default set and all the registered sets in Prometheus format to w. +// RegisterMetricsWriter registers writeMetrics callback for including metrics in the output generated by WritePrometheus. +// +// The writeMetrics callback must write metrics to w in Prometheus text exposition format without timestamps and trailing comments. +// The last line generated by writeMetrics must end with \n. +// See https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md#text-based-format +// +// It is OK to register multiple writeMetrics callbacks - all of them will be called sequentially for gererating the output at WritePrometheus. +func RegisterMetricsWriter(writeMetrics func(w io.Writer)) { + defaultSet.RegisterMetricsWriter(writeMetrics) +} + +// WritePrometheus writes all the metrics in Prometheus format from the default set, all the added sets and metrics writers to w. // // Additional sets can be registered via RegisterSet() call. +// Additional metric writers can be registered via RegisterMetricsWriter() call. // // If exposeProcessMetrics is true, then various `go_*` and `process_*` metrics // are exposed for the current process. @@ -134,10 +155,26 @@ func WritePrometheus(w io.Writer, exposeProcessMetrics bool) { // // - process_io_storage_written_bytes_total - the number of bytes actually written to disk // +// - go_sched_latencies_seconds - time spent by goroutines in ready state before they start execution +// +// - go_mutex_wait_seconds_total - summary time spent by all the goroutines while waiting for locked mutex +// +// - go_gc_mark_assist_cpu_seconds_total - summary CPU time spent by goroutines in GC mark assist state +// +// - go_gc_cpu_seconds_total - summary time spent in GC +// +// - go_gc_pauses_seconds - duration of GC pauses +// +// - go_scavenge_cpu_seconds_total - CPU time spent on returning the memory to OS +// +// - go_memlimit_bytes - the GOMEMLIMIT env var value +// // - go_memstats_alloc_bytes - memory usage for Go objects in the heap // // - go_memstats_alloc_bytes_total - the cumulative counter for total size of allocated Go objects // +// - go_memstats_buck_hash_sys_bytes - bytes of memory in profiling bucket hash tables +// // - go_memstats_frees_total - the cumulative counter for number of freed Go objects // // - go_memstats_gc_cpu_fraction - the fraction of CPU spent in Go garbage collector @@ -148,20 +185,42 @@ func WritePrometheus(w io.Writer, exposeProcessMetrics bool) { // // - go_memstats_heap_idle_bytes - idle memory ready for new Go object allocations // +// - go_memstats_heap_inuse_bytes - bytes in in-use spans +// // - go_memstats_heap_objects - the number of Go objects in the heap // +// - go_memstats_heap_released_bytes - bytes of physical memory returned to the OS +// // - go_memstats_heap_sys_bytes - memory requested for Go objects from the OS // +// - go_memstats_last_gc_time_seconds - unix timestamp the last garbage collection finished +// +// - go_memstats_lookups_total - the number of pointer lookups performed by the runtime +// // - go_memstats_mallocs_total - the number of allocations for Go objects // +// - go_memstats_mcache_inuse_bytes - bytes of allocated mcache structures +// +// - go_memstats_mcache_sys_bytes - bytes of memory obtained from the OS for mcache structures +// +// - go_memstats_mspan_inuse_bytes - bytes of allocated mspan structures +// +// - go_memstats_mspan_sys_bytes - bytes of memory obtained from the OS for mspan structures +// // - go_memstats_next_gc_bytes - the target heap size when the next garbage collection should start // +// - go_memstats_other_sys_bytes - bytes of memory in miscellaneous off-heap runtime allocations +// // - go_memstats_stack_inuse_bytes - memory used for goroutine stacks // // - go_memstats_stack_sys_bytes - memory requested fromthe OS for goroutine stacks // // - go_memstats_sys_bytes - memory requested by Go runtime from the OS // +// - go_cgo_calls_count - the total number of CGO calls +// +// - go_cpu_count - the number of CPU cores on the host where the app runs +// // The WriteProcessMetrics func is usually called in combination with writing Set metrics // inside "/metrics" handler: // @@ -170,7 +229,7 @@ func WritePrometheus(w io.Writer, exposeProcessMetrics bool) { // metrics.WriteProcessMetrics(w) // }) // -// See also WrteFDMetrics. +// See also WriteFDMetrics. func WriteProcessMetrics(w io.Writer) { writeGoMetrics(w) writeProcessMetrics(w) @@ -190,6 +249,8 @@ func UnregisterMetric(name string) bool { } // UnregisterAllMetrics unregisters all the metrics from default set. +// +// It also unregisters writeMetrics callbacks passed to RegisterMetricsWriter. func UnregisterAllMetrics() { defaultSet.UnregisterAllMetrics() } @@ -203,3 +264,76 @@ func ListMetricNames() []string { func GetDefaultSet() *Set { return defaultSet } + +// ExposeMetadata allows enabling adding TYPE and HELP metadata to the exposed metrics globally. +// +// It is safe to call this method multiple times. It is allowed to change it in runtime. +// ExposeMetadata is set to false by default. +func ExposeMetadata(v bool) { + n := 0 + if v { + n = 1 + } + atomic.StoreUint32(&exposeMetadata, uint32(n)) +} + +func isMetadataEnabled() bool { + n := atomic.LoadUint32(&exposeMetadata) + return n != 0 +} + +var exposeMetadata uint32 + +func isCounterName(name string) bool { + return strings.HasSuffix(name, "_total") +} + +// WriteGaugeUint64 writes gauge metric with the given name and value to w in Prometheus text exposition format. +func WriteGaugeUint64(w io.Writer, name string, value uint64) { + writeMetricUint64(w, name, "gauge", value) +} + +// WriteGaugeFloat64 writes gauge metric with the given name and value to w in Prometheus text exposition format. +func WriteGaugeFloat64(w io.Writer, name string, value float64) { + writeMetricFloat64(w, name, "gauge", value) +} + +// WriteCounterUint64 writes counter metric with the given name and value to w in Prometheus text exposition format. +func WriteCounterUint64(w io.Writer, name string, value uint64) { + writeMetricUint64(w, name, "counter", value) +} + +// WriteCounterFloat64 writes counter metric with the given name and value to w in Prometheus text exposition format. +func WriteCounterFloat64(w io.Writer, name string, value float64) { + writeMetricFloat64(w, name, "counter", value) +} + +func writeMetricUint64(w io.Writer, metricName, metricType string, value uint64) { + WriteMetadataIfNeeded(w, metricName, metricType) + fmt.Fprintf(w, "%s %d\n", metricName, value) +} + +func writeMetricFloat64(w io.Writer, metricName, metricType string, value float64) { + WriteMetadataIfNeeded(w, metricName, metricType) + fmt.Fprintf(w, "%s %g\n", metricName, value) +} + +// WriteMetadataIfNeeded writes HELP and TYPE metadata for the given metricName and metricType if this is globally enabled via ExposeMetadata(). +// +// If the metadata exposition isn't enabled, then this function is no-op. +func WriteMetadataIfNeeded(w io.Writer, metricName, metricType string) { + if !isMetadataEnabled() { + return + } + metricFamily := getMetricFamily(metricName) + fmt.Fprintf(w, "# HELP %s\n", metricFamily) + fmt.Fprintf(w, "# TYPE %s %s\n", metricFamily, metricType) +} + +func getMetricFamily(metricName string) string { + n := strings.IndexByte(metricName, '{') + if n < 0 { + return metricName + } + return metricName[:n] +} diff --git a/vendor/github.com/VictoriaMetrics/metrics/process_metrics_linux.go b/vendor/github.com/VictoriaMetrics/metrics/process_metrics_linux.go index 48def1cba..e4587b717 100644 --- a/vendor/github.com/VictoriaMetrics/metrics/process_metrics_linux.go +++ b/vendor/github.com/VictoriaMetrics/metrics/process_metrics_linux.go @@ -16,6 +16,11 @@ import ( // See https://github.com/prometheus/procfs/blob/a4ac0826abceb44c40fc71daed2b301db498b93e/proc_stat.go#L40 . const userHZ = 100 +// Different environments may have different page size. +// +// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6457 +var pageSizeBytes = uint64(os.Getpagesize()) + // See http://man7.org/linux/man-pages/man5/proc.5.html type procStat struct { State byte @@ -74,15 +79,15 @@ func writeProcessMetrics(w io.Writer) { utime := float64(p.Utime) / userHZ stime := float64(p.Stime) / userHZ - fmt.Fprintf(w, "process_cpu_seconds_system_total %g\n", stime) - fmt.Fprintf(w, "process_cpu_seconds_total %g\n", utime+stime) - fmt.Fprintf(w, "process_cpu_seconds_user_total %g\n", utime) - fmt.Fprintf(w, "process_major_pagefaults_total %d\n", p.Majflt) - fmt.Fprintf(w, "process_minor_pagefaults_total %d\n", p.Minflt) - fmt.Fprintf(w, "process_num_threads %d\n", p.NumThreads) - fmt.Fprintf(w, "process_resident_memory_bytes %d\n", p.Rss*4096) - fmt.Fprintf(w, "process_start_time_seconds %d\n", startTimeSeconds) - fmt.Fprintf(w, "process_virtual_memory_bytes %d\n", p.Vsize) + WriteCounterFloat64(w, "process_cpu_seconds_system_total", stime) + WriteCounterFloat64(w, "process_cpu_seconds_total", utime+stime) + WriteCounterFloat64(w, "process_cpu_seconds_user_total", utime) + WriteCounterUint64(w, "process_major_pagefaults_total", uint64(p.Majflt)) + WriteCounterUint64(w, "process_minor_pagefaults_total", uint64(p.Minflt)) + WriteGaugeUint64(w, "process_num_threads", uint64(p.NumThreads)) + WriteGaugeUint64(w, "process_resident_memory_bytes", uint64(p.Rss)*pageSizeBytes) + WriteGaugeUint64(w, "process_start_time_seconds", uint64(startTimeSeconds)) + WriteGaugeUint64(w, "process_virtual_memory_bytes", uint64(p.Vsize)) writeProcessMemMetrics(w) writeIOMetrics(w) } @@ -133,12 +138,12 @@ func writeIOMetrics(w io.Writer) { writeBytes = getInt(s) } } - fmt.Fprintf(w, "process_io_read_bytes_total %d\n", rchar) - fmt.Fprintf(w, "process_io_written_bytes_total %d\n", wchar) - fmt.Fprintf(w, "process_io_read_syscalls_total %d\n", syscr) - fmt.Fprintf(w, "process_io_write_syscalls_total %d\n", syscw) - fmt.Fprintf(w, "process_io_storage_read_bytes_total %d\n", readBytes) - fmt.Fprintf(w, "process_io_storage_written_bytes_total %d\n", writeBytes) + WriteGaugeUint64(w, "process_io_read_bytes_total", uint64(rchar)) + WriteGaugeUint64(w, "process_io_written_bytes_total", uint64(wchar)) + WriteGaugeUint64(w, "process_io_read_syscalls_total", uint64(syscr)) + WriteGaugeUint64(w, "process_io_write_syscalls_total", uint64(syscw)) + WriteGaugeUint64(w, "process_io_storage_read_bytes_total", uint64(readBytes)) + WriteGaugeUint64(w, "process_io_storage_written_bytes_total", uint64(writeBytes)) } var startTimeSeconds = time.Now().Unix() @@ -155,8 +160,8 @@ func writeFDMetrics(w io.Writer) { log.Printf("ERROR: metrics: cannot determine the limit on open file descritors: %s", err) return } - fmt.Fprintf(w, "process_max_fds %d\n", maxOpenFDs) - fmt.Fprintf(w, "process_open_fds %d\n", totalOpenFDs) + WriteGaugeUint64(w, "process_max_fds", maxOpenFDs) + WriteGaugeUint64(w, "process_open_fds", totalOpenFDs) } func getOpenFDsCount(path string) (uint64, error) { @@ -224,11 +229,11 @@ func writeProcessMemMetrics(w io.Writer) { log.Printf("ERROR: metrics: cannot determine memory status: %s", err) return } - fmt.Fprintf(w, "process_virtual_memory_peak_bytes %d\n", ms.vmPeak) - fmt.Fprintf(w, "process_resident_memory_peak_bytes %d\n", ms.rssPeak) - fmt.Fprintf(w, "process_resident_memory_anon_bytes %d\n", ms.rssAnon) - fmt.Fprintf(w, "process_resident_memory_file_bytes %d\n", ms.rssFile) - fmt.Fprintf(w, "process_resident_memory_shared_bytes %d\n", ms.rssShmem) + WriteGaugeUint64(w, "process_virtual_memory_peak_bytes", ms.vmPeak) + WriteGaugeUint64(w, "process_resident_memory_peak_bytes", ms.rssPeak) + WriteGaugeUint64(w, "process_resident_memory_anon_bytes", ms.rssAnon) + WriteGaugeUint64(w, "process_resident_memory_file_bytes", ms.rssFile) + WriteGaugeUint64(w, "process_resident_memory_shared_bytes", ms.rssShmem) } diff --git a/vendor/github.com/VictoriaMetrics/metrics/process_metrics_windows.go b/vendor/github.com/VictoriaMetrics/metrics/process_metrics_windows.go index e824ada94..bda7c82f7 100644 --- a/vendor/github.com/VictoriaMetrics/metrics/process_metrics_windows.go +++ b/vendor/github.com/VictoriaMetrics/metrics/process_metrics_windows.go @@ -4,7 +4,6 @@ package metrics import ( - "fmt" "io" "log" "syscall" @@ -55,16 +54,16 @@ func writeProcessMetrics(w io.Writer) { log.Printf("ERROR: metrics: cannot read process memory information: %s", err) return } - stimeSeconds := (uint64(stime.HighDateTime)<<32 + uint64(stime.LowDateTime)) / 1e7 - utimeSeconds := (uint64(utime.HighDateTime)<<32 + uint64(utime.LowDateTime)) / 1e7 - fmt.Fprintf(w, "process_cpu_seconds_system_total %d\n", stimeSeconds) - fmt.Fprintf(w, "process_cpu_seconds_total %d\n", stimeSeconds+utimeSeconds) - fmt.Fprintf(w, "process_cpu_seconds_user_total %d\n", stimeSeconds) - fmt.Fprintf(w, "process_pagefaults_total %d\n", mc.PageFaultCount) - fmt.Fprintf(w, "process_start_time_seconds %d\n", startTime.Nanoseconds()/1e9) - fmt.Fprintf(w, "process_virtual_memory_bytes %d\n", mc.PrivateUsage) - fmt.Fprintf(w, "process_resident_memory_peak_bytes %d\n", mc.PeakWorkingSetSize) - fmt.Fprintf(w, "process_resident_memory_bytes %d\n", mc.WorkingSetSize) + stimeSeconds := float64(uint64(stime.HighDateTime)<<32+uint64(stime.LowDateTime)) / 1e7 + utimeSeconds := float64(uint64(utime.HighDateTime)<<32+uint64(utime.LowDateTime)) / 1e7 + WriteCounterFloat64(w, "process_cpu_seconds_system_total", stimeSeconds) + WriteCounterFloat64(w, "process_cpu_seconds_total", stimeSeconds+utimeSeconds) + WriteCounterFloat64(w, "process_cpu_seconds_user_total", stimeSeconds) + WriteCounterUint64(w, "process_pagefaults_total", uint64(mc.PageFaultCount)) + WriteGaugeUint64(w, "process_start_time_seconds", uint64(startTime.Nanoseconds())/1e9) + WriteGaugeUint64(w, "process_virtual_memory_bytes", uint64(mc.PrivateUsage)) + WriteGaugeUint64(w, "process_resident_memory_peak_bytes", uint64(mc.PeakWorkingSetSize)) + WriteGaugeUint64(w, "process_resident_memory_bytes", uint64(mc.WorkingSetSize)) } func writeFDMetrics(w io.Writer) { @@ -80,6 +79,6 @@ func writeFDMetrics(w io.Writer) { } // it seems to be hard-coded limit for 64-bit systems // https://learn.microsoft.com/en-us/archive/blogs/markrussinovich/pushing-the-limits-of-windows-handles#maximum-number-of-handles - fmt.Fprintf(w, "process_max_fds %d\n", 16777216) - fmt.Fprintf(w, "process_open_fds %d\n", count) + WriteGaugeUint64(w, "process_max_fds", 16777216) + WriteGaugeUint64(w, "process_open_fds", uint64(count)) } diff --git a/vendor/github.com/VictoriaMetrics/metrics/push.go b/vendor/github.com/VictoriaMetrics/metrics/push.go index 4215f48ab..f33886f9b 100644 --- a/vendor/github.com/VictoriaMetrics/metrics/push.go +++ b/vendor/github.com/VictoriaMetrics/metrics/push.go @@ -2,17 +2,69 @@ package metrics import ( "bytes" + "context" + "errors" "fmt" "io" "io/ioutil" "log" "net/http" "net/url" + "strings" + "sync" "time" "compress/gzip" ) +// PushOptions is the list of options, which may be applied to InitPushWithOptions(). +type PushOptions struct { + // ExtraLabels is an optional comma-separated list of `label="value"` labels, which must be added to all the metrics before pushing them to pushURL. + ExtraLabels string + + // Headers is an optional list of HTTP headers to add to every push request to pushURL. + // + // Every item in the list must have the form `Header: value`. For example, `Authorization: Custom my-top-secret`. + Headers []string + + // Whether to disable HTTP request body compression before sending the metrics to pushURL. + // + // By default the compression is enabled. + DisableCompression bool + + // Method is HTTP request method to use when pushing metrics to pushURL. + // + // By default the Method is GET. + Method string + + // Optional WaitGroup for waiting until all the push workers created with this WaitGroup are stopped. + WaitGroup *sync.WaitGroup +} + +// InitPushWithOptions sets up periodic push for globally registered metrics to the given pushURL with the given interval. +// +// The periodic push is stopped when ctx is canceled. +// It is possible to wait until the background metrics push worker is stopped on a WaitGroup passed via opts.WaitGroup. +// +// If pushProcessMetrics is set to true, then 'process_*' and `go_*` metrics are also pushed to pushURL. +// +// opts may contain additional configuration options if non-nil. +// +// The metrics are pushed to pushURL in Prometheus text exposition format. +// See https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md#text-based-format +// +// It is recommended pushing metrics to /api/v1/import/prometheus endpoint according to +// https://docs.victoriametrics.com/#how-to-import-data-in-prometheus-exposition-format +// +// It is OK calling InitPushWithOptions multiple times with different pushURL - +// in this case metrics are pushed to all the provided pushURL urls. +func InitPushWithOptions(ctx context.Context, pushURL string, interval time.Duration, pushProcessMetrics bool, opts *PushOptions) error { + writeMetrics := func(w io.Writer) { + WritePrometheus(w, pushProcessMetrics) + } + return InitPushExtWithOptions(ctx, pushURL, interval, writeMetrics, opts) +} + // InitPushProcessMetrics sets up periodic push for 'process_*' metrics to the given pushURL with the given interval. // // extraLabels may contain comma-separated list of `label="value"` labels, which will be added @@ -27,10 +79,7 @@ import ( // It is OK calling InitPushProcessMetrics multiple times with different pushURL - // in this case metrics are pushed to all the provided pushURL urls. func InitPushProcessMetrics(pushURL string, interval time.Duration, extraLabels string) error { - writeMetrics := func(w io.Writer) { - WriteProcessMetrics(w) - } - return InitPushExt(pushURL, interval, extraLabels, writeMetrics) + return InitPushExt(pushURL, interval, extraLabels, WriteProcessMetrics) } // InitPush sets up periodic push for globally registered metrics to the given pushURL with the given interval. @@ -38,7 +87,7 @@ func InitPushProcessMetrics(pushURL string, interval time.Duration, extraLabels // extraLabels may contain comma-separated list of `label="value"` labels, which will be added // to all the metrics before pushing them to pushURL. // -// If pushProcessMetrics is set to true, then 'process_*' metrics are also pushed to pushURL. +// If pushProcessMetrics is set to true, then 'process_*' and `go_*` metrics are also pushed to pushURL. // // The metrics are pushed to pushURL in Prometheus text exposition format. // See https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md#text-based-format @@ -55,12 +104,46 @@ func InitPush(pushURL string, interval time.Duration, extraLabels string, pushPr return InitPushExt(pushURL, interval, extraLabels, writeMetrics) } +// PushMetrics pushes globally registered metrics to pushURL. +// +// If pushProcessMetrics is set to true, then 'process_*' and `go_*` metrics are also pushed to pushURL. +// +// opts may contain additional configuration options if non-nil. +// +// It is recommended pushing metrics to /api/v1/import/prometheus endpoint according to +// https://docs.victoriametrics.com/#how-to-import-data-in-prometheus-exposition-format +func PushMetrics(ctx context.Context, pushURL string, pushProcessMetrics bool, opts *PushOptions) error { + writeMetrics := func(w io.Writer) { + WritePrometheus(w, pushProcessMetrics) + } + return PushMetricsExt(ctx, pushURL, writeMetrics, opts) +} + +// InitPushWithOptions sets up periodic push for metrics from s to the given pushURL with the given interval. +// +// The periodic push is stopped when the ctx is canceled. +// It is possible to wait until the background metrics push worker is stopped on a WaitGroup passed via opts.WaitGroup. +// +// opts may contain additional configuration options if non-nil. +// +// The metrics are pushed to pushURL in Prometheus text exposition format. +// See https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md#text-based-format +// +// It is recommended pushing metrics to /api/v1/import/prometheus endpoint according to +// https://docs.victoriametrics.com/#how-to-import-data-in-prometheus-exposition-format +// +// It is OK calling InitPushWithOptions multiple times with different pushURL - +// in this case metrics are pushed to all the provided pushURL urls. +func (s *Set) InitPushWithOptions(ctx context.Context, pushURL string, interval time.Duration, opts *PushOptions) error { + return InitPushExtWithOptions(ctx, pushURL, interval, s.WritePrometheus, opts) +} + // InitPush sets up periodic push for metrics from s to the given pushURL with the given interval. // // extraLabels may contain comma-separated list of `label="value"` labels, which will be added // to all the metrics before pushing them to pushURL. // -// / The metrics are pushed to pushURL in Prometheus text exposition format. +// The metrics are pushed to pushURL in Prometheus text exposition format. // See https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md#text-based-format // // It is recommended pushing metrics to /api/v1/import/prometheus endpoint according to @@ -69,10 +152,17 @@ func InitPush(pushURL string, interval time.Duration, extraLabels string, pushPr // It is OK calling InitPush multiple times with different pushURL - // in this case metrics are pushed to all the provided pushURL urls. func (s *Set) InitPush(pushURL string, interval time.Duration, extraLabels string) error { - writeMetrics := func(w io.Writer) { - s.WritePrometheus(w) - } - return InitPushExt(pushURL, interval, extraLabels, writeMetrics) + return InitPushExt(pushURL, interval, extraLabels, s.WritePrometheus) +} + +// PushMetrics pushes s metrics to pushURL. +// +// opts may contain additional configuration options if non-nil. +// +// It is recommended pushing metrics to /api/v1/import/prometheus endpoint according to +// https://docs.victoriametrics.com/#how-to-import-data-in-prometheus-exposition-format +func (s *Set) PushMetrics(ctx context.Context, pushURL string, opts *PushOptions) error { + return PushMetricsExt(ctx, pushURL, s.WritePrometheus, opts) } // InitPushExt sets up periodic push for metrics obtained by calling writeMetrics with the given interval. @@ -90,94 +180,246 @@ func (s *Set) InitPush(pushURL string, interval time.Duration, extraLabels strin // in this case metrics are pushed to all the provided pushURL urls. // // It is OK calling InitPushExt multiple times with different writeMetrics - -// in this case all the metrics generated by writeMetrics callbacks are writte to pushURL. +// in this case all the metrics generated by writeMetrics callbacks are written to pushURL. func InitPushExt(pushURL string, interval time.Duration, extraLabels string, writeMetrics func(w io.Writer)) error { + opts := &PushOptions{ + ExtraLabels: extraLabels, + } + return InitPushExtWithOptions(context.Background(), pushURL, interval, writeMetrics, opts) +} + +// InitPushExtWithOptions sets up periodic push for metrics obtained by calling writeMetrics with the given interval. +// +// The writeMetrics callback must write metrics to w in Prometheus text exposition format without timestamps and trailing comments. +// See https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md#text-based-format +// +// The periodic push is stopped when the ctx is canceled. +// It is possible to wait until the background metrics push worker is stopped on a WaitGroup passed via opts.WaitGroup. +// +// opts may contain additional configuration options if non-nil. +// +// It is recommended pushing metrics to /api/v1/import/prometheus endpoint according to +// https://docs.victoriametrics.com/#how-to-import-data-in-prometheus-exposition-format +// +// It is OK calling InitPushExtWithOptions multiple times with different pushURL - +// in this case metrics are pushed to all the provided pushURL urls. +// +// It is OK calling InitPushExtWithOptions multiple times with different writeMetrics - +// in this case all the metrics generated by writeMetrics callbacks are written to pushURL. +func InitPushExtWithOptions(ctx context.Context, pushURL string, interval time.Duration, writeMetrics func(w io.Writer), opts *PushOptions) error { + pc, err := newPushContext(pushURL, opts) + if err != nil { + return err + } + + // validate interval if interval <= 0 { return fmt.Errorf("interval must be positive; got %s", interval) } - if err := validateTags(extraLabels); err != nil { - return fmt.Errorf("invalid extraLabels=%q: %w", extraLabels, err) + pushMetricsSet.GetOrCreateFloatCounter(fmt.Sprintf(`metrics_push_interval_seconds{url=%q}`, pc.pushURLRedacted)).Set(interval.Seconds()) + + var wg *sync.WaitGroup + if opts != nil { + wg = opts.WaitGroup + if wg != nil { + wg.Add(1) + } + } + go func() { + ticker := time.NewTicker(interval) + defer ticker.Stop() + stopCh := ctx.Done() + for { + select { + case <-ticker.C: + ctxLocal, cancel := context.WithTimeout(ctx, interval+time.Second) + err := pc.pushMetrics(ctxLocal, writeMetrics) + cancel() + if err != nil { + log.Printf("ERROR: metrics.push: %s", err) + } + case <-stopCh: + if wg != nil { + wg.Done() + } + return + } + } + }() + + return nil +} + +// PushMetricsExt pushes metrics generated by wirteMetrics to pushURL. +// +// The writeMetrics callback must write metrics to w in Prometheus text exposition format without timestamps and trailing comments. +// See https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md#text-based-format +// +// opts may contain additional configuration options if non-nil. +// +// It is recommended pushing metrics to /api/v1/import/prometheus endpoint according to +// https://docs.victoriametrics.com/#how-to-import-data-in-prometheus-exposition-format +func PushMetricsExt(ctx context.Context, pushURL string, writeMetrics func(w io.Writer), opts *PushOptions) error { + pc, err := newPushContext(pushURL, opts) + if err != nil { + return err } + return pc.pushMetrics(ctx, writeMetrics) +} + +type pushContext struct { + pushURL *url.URL + method string + pushURLRedacted string + extraLabels string + headers http.Header + disableCompression bool + + client *http.Client + + pushesTotal *Counter + bytesPushedTotal *Counter + pushBlockSize *Histogram + pushDuration *Histogram + pushErrors *Counter +} + +func newPushContext(pushURL string, opts *PushOptions) (*pushContext, error) { + if opts == nil { + opts = &PushOptions{} + } + + // validate pushURL pu, err := url.Parse(pushURL) if err != nil { - return fmt.Errorf("cannot parse pushURL=%q: %w", pushURL, err) + return nil, fmt.Errorf("cannot parse pushURL=%q: %w", pushURL, err) } if pu.Scheme != "http" && pu.Scheme != "https" { - return fmt.Errorf("unsupported scheme in pushURL=%q; expecting 'http' or 'https'", pushURL) + return nil, fmt.Errorf("unsupported scheme in pushURL=%q; expecting 'http' or 'https'", pushURL) } if pu.Host == "" { - return fmt.Errorf("missing host in pushURL=%q", pushURL) + return nil, fmt.Errorf("missing host in pushURL=%q", pushURL) + } + + method := opts.Method + if method == "" { + method = http.MethodGet + } + + // validate ExtraLabels + extraLabels := opts.ExtraLabels + if err := validateTags(extraLabels); err != nil { + return nil, fmt.Errorf("invalid extraLabels=%q: %w", extraLabels, err) + } + + // validate Headers + headers := make(http.Header) + for _, h := range opts.Headers { + n := strings.IndexByte(h, ':') + if n < 0 { + return nil, fmt.Errorf("missing `:` delimiter in the header %q", h) + } + name := strings.TrimSpace(h[:n]) + value := strings.TrimSpace(h[n+1:]) + headers.Add(name, value) } + pushURLRedacted := pu.Redacted() - c := &http.Client{ - Timeout: interval, - } - pushesTotal := pushMetrics.GetOrCreateCounter(fmt.Sprintf(`metrics_push_total{url=%q}`, pushURLRedacted)) - pushErrorsTotal := pushMetrics.GetOrCreateCounter(fmt.Sprintf(`metrics_push_errors_total{url=%q}`, pushURLRedacted)) - bytesPushedTotal := pushMetrics.GetOrCreateCounter(fmt.Sprintf(`metrics_push_bytes_pushed_total{url=%q}`, pushURLRedacted)) - pushDuration := pushMetrics.GetOrCreateHistogram(fmt.Sprintf(`metrics_push_duration_seconds{url=%q}`, pushURLRedacted)) - pushBlockSize := pushMetrics.GetOrCreateHistogram(fmt.Sprintf(`metrics_push_block_size_bytes{url=%q}`, pushURLRedacted)) - pushMetrics.GetOrCreateFloatCounter(fmt.Sprintf(`metrics_push_interval_seconds{url=%q}`, pushURLRedacted)).Set(interval.Seconds()) - go func() { - ticker := time.NewTicker(interval) - var bb bytes.Buffer - var tmpBuf []byte - zw := gzip.NewWriter(&bb) - for range ticker.C { - bb.Reset() - writeMetrics(&bb) - if len(extraLabels) > 0 { - tmpBuf = addExtraLabels(tmpBuf[:0], bb.Bytes(), extraLabels) - bb.Reset() - if _, err := bb.Write(tmpBuf); err != nil { - panic(fmt.Errorf("BUG: cannot write %d bytes to bytes.Buffer: %s", len(tmpBuf), err)) - } - } - tmpBuf = append(tmpBuf[:0], bb.Bytes()...) - bb.Reset() - zw.Reset(&bb) - if _, err := zw.Write(tmpBuf); err != nil { - panic(fmt.Errorf("BUG: cannot write %d bytes to gzip writer: %s", len(tmpBuf), err)) - } - if err := zw.Close(); err != nil { - panic(fmt.Errorf("BUG: cannot flush metrics to gzip writer: %s", err)) - } - pushesTotal.Inc() - blockLen := bb.Len() - bytesPushedTotal.Add(blockLen) - pushBlockSize.Update(float64(blockLen)) - req, err := http.NewRequest("GET", pushURL, &bb) - if err != nil { - panic(fmt.Errorf("BUG: metrics.push: cannot initialize request for metrics push to %q: %w", pushURLRedacted, err)) - } - req.Header.Set("Content-Type", "text/plain") - req.Header.Set("Content-Encoding", "gzip") - startTime := time.Now() - resp, err := c.Do(req) - pushDuration.UpdateDuration(startTime) - if err != nil { - log.Printf("ERROR: metrics.push: cannot push metrics to %q: %s", pushURLRedacted, err) - pushErrorsTotal.Inc() - continue - } - if resp.StatusCode/100 != 2 { - body, _ := ioutil.ReadAll(resp.Body) - _ = resp.Body.Close() - log.Printf("ERROR: metrics.push: unexpected status code in response from %q: %d; expecting 2xx; response body: %q", - pushURLRedacted, resp.StatusCode, body) - pushErrorsTotal.Inc() - continue - } - _ = resp.Body.Close() + client := &http.Client{} + return &pushContext{ + pushURL: pu, + method: method, + pushURLRedacted: pushURLRedacted, + extraLabels: extraLabels, + headers: headers, + disableCompression: opts.DisableCompression, + + client: client, + + pushesTotal: pushMetricsSet.GetOrCreateCounter(fmt.Sprintf(`metrics_push_total{url=%q}`, pushURLRedacted)), + bytesPushedTotal: pushMetricsSet.GetOrCreateCounter(fmt.Sprintf(`metrics_push_bytes_pushed_total{url=%q}`, pushURLRedacted)), + pushBlockSize: pushMetricsSet.GetOrCreateHistogram(fmt.Sprintf(`metrics_push_block_size_bytes{url=%q}`, pushURLRedacted)), + pushDuration: pushMetricsSet.GetOrCreateHistogram(fmt.Sprintf(`metrics_push_duration_seconds{url=%q}`, pushURLRedacted)), + pushErrors: pushMetricsSet.GetOrCreateCounter(fmt.Sprintf(`metrics_push_errors_total{url=%q}`, pushURLRedacted)), + }, nil +} + +func (pc *pushContext) pushMetrics(ctx context.Context, writeMetrics func(w io.Writer)) error { + bb := getBytesBuffer() + defer putBytesBuffer(bb) + + writeMetrics(bb) + + if len(pc.extraLabels) > 0 { + bbTmp := getBytesBuffer() + bbTmp.B = append(bbTmp.B[:0], bb.B...) + bb.B = addExtraLabels(bb.B[:0], bbTmp.B, pc.extraLabels) + putBytesBuffer(bbTmp) + } + if !pc.disableCompression { + bbTmp := getBytesBuffer() + bbTmp.B = append(bbTmp.B[:0], bb.B...) + bb.B = bb.B[:0] + zw := getGzipWriter(bb) + if _, err := zw.Write(bbTmp.B); err != nil { + panic(fmt.Errorf("BUG: cannot write %d bytes to gzip writer: %s", len(bbTmp.B), err)) } - }() + if err := zw.Close(); err != nil { + panic(fmt.Errorf("BUG: cannot flush metrics to gzip writer: %s", err)) + } + putGzipWriter(zw) + putBytesBuffer(bbTmp) + } + + // Update metrics + pc.pushesTotal.Inc() + blockLen := len(bb.B) + pc.bytesPushedTotal.Add(blockLen) + pc.pushBlockSize.Update(float64(blockLen)) + + // Prepare the request to sent to pc.pushURL + reqBody := bytes.NewReader(bb.B) + req, err := http.NewRequestWithContext(ctx, pc.method, pc.pushURL.String(), reqBody) + if err != nil { + panic(fmt.Errorf("BUG: metrics.push: cannot initialize request for metrics push to %q: %w", pc.pushURLRedacted, err)) + } + + req.Header.Set("Content-Type", "text/plain") + // Set the needed headers, and `Content-Type` allowed be overwrited. + for name, values := range pc.headers { + for _, value := range values { + req.Header.Add(name, value) + } + } + if !pc.disableCompression { + req.Header.Set("Content-Encoding", "gzip") + } + + // Perform the request + startTime := time.Now() + resp, err := pc.client.Do(req) + pc.pushDuration.UpdateDuration(startTime) + if err != nil { + if errors.Is(err, context.Canceled) { + return nil + } + pc.pushErrors.Inc() + return fmt.Errorf("cannot push metrics to %q: %s", pc.pushURLRedacted, err) + } + if resp.StatusCode/100 != 2 { + body, _ := ioutil.ReadAll(resp.Body) + _ = resp.Body.Close() + pc.pushErrors.Inc() + return fmt.Errorf("unexpected status code in response from %q: %d; expecting 2xx; response body: %q", pc.pushURLRedacted, resp.StatusCode, body) + } + _ = resp.Body.Close() return nil } -var pushMetrics = NewSet() +var pushMetricsSet = NewSet() func writePushMetrics(w io.Writer) { - pushMetrics.WritePrometheus(w) + pushMetricsSet.WritePrometheus(w) } func addExtraLabels(dst, src []byte, extraLabels string) []byte { @@ -225,3 +467,44 @@ func addExtraLabels(dst, src []byte, extraLabels string) []byte { } var bashBytes = []byte("#") + +func getBytesBuffer() *bytesBuffer { + v := bytesBufferPool.Get() + if v == nil { + return &bytesBuffer{} + } + return v.(*bytesBuffer) +} + +func putBytesBuffer(bb *bytesBuffer) { + bb.B = bb.B[:0] + bytesBufferPool.Put(bb) +} + +var bytesBufferPool sync.Pool + +type bytesBuffer struct { + B []byte +} + +func (bb *bytesBuffer) Write(p []byte) (int, error) { + bb.B = append(bb.B, p...) + return len(p), nil +} + +func getGzipWriter(w io.Writer) *gzip.Writer { + v := gzipWriterPool.Get() + if v == nil { + return gzip.NewWriter(w) + } + zw := v.(*gzip.Writer) + zw.Reset(w) + return zw +} + +func putGzipWriter(zw *gzip.Writer) { + zw.Reset(io.Discard) + gzipWriterPool.Put(zw) +} + +var gzipWriterPool sync.Pool diff --git a/vendor/github.com/VictoriaMetrics/metrics/set.go b/vendor/github.com/VictoriaMetrics/metrics/set.go index 79355ea38..868a01c94 100644 --- a/vendor/github.com/VictoriaMetrics/metrics/set.go +++ b/vendor/github.com/VictoriaMetrics/metrics/set.go @@ -19,6 +19,8 @@ type Set struct { a []*namedMetric m map[string]*namedMetric summaries []*Summary + + metricsWriters []func(w io.Writer) } // NewSet creates new set of metrics. @@ -45,14 +47,27 @@ func (s *Set) WritePrometheus(w io.Writer) { sort.Slice(s.a, lessFunc) } sa := append([]*namedMetric(nil), s.a...) + metricsWriters := s.metricsWriters s.mu.Unlock() - // Call marshalTo without the global lock, since certain metric types such as Gauge - // can call a callback, which, in turn, can try calling s.mu.Lock again. + prevMetricFamily := "" for _, nm := range sa { + metricFamily := getMetricFamily(nm.name) + if metricFamily != prevMetricFamily { + // write meta info only once per metric family + metricType := nm.metric.metricType() + WriteMetadataIfNeeded(&bb, nm.name, metricType) + prevMetricFamily = metricFamily + } + // Call marshalTo without the global lock, since certain metric types such as Gauge + // can call a callback, which, in turn, can try calling s.mu.Lock again. nm.metric.marshalTo(nm.name, &bb) } w.Write(bb.Bytes()) + + for _, writeMetrics := range metricsWriters { + writeMetrics(w) + } } // NewHistogram creates and returns new histogram in s with the given name. @@ -243,9 +258,6 @@ func (s *Set) GetOrCreateFloatCounter(name string) *FloatCounter { // // The returned gauge is safe to use from concurrent goroutines. func (s *Set) NewGauge(name string, f func() float64) *Gauge { - if f == nil { - panic(fmt.Errorf("BUG: f cannot be nil")) - } g := &Gauge{ f: f, } @@ -272,9 +284,6 @@ func (s *Set) GetOrCreateGauge(name string, f func() float64) *Gauge { s.mu.Unlock() if nm == nil { // Slow path - create and register missing gauge. - if f == nil { - panic(fmt.Errorf("BUG: f cannot be nil")) - } if err := validateMetric(name); err != nil { panic(fmt.Errorf("BUG: invalid metric name %q: %s", name, err)) } @@ -521,14 +530,22 @@ func (s *Set) unregisterMetricLocked(nm *namedMetric) bool { } // UnregisterAllMetrics de-registers all metrics registered in s. +// +// It also de-registers writeMetrics callbacks passed to RegisterMetricsWriter. func (s *Set) UnregisterAllMetrics() { metricNames := s.ListMetricNames() for _, name := range metricNames { s.UnregisterMetric(name) } + + s.mu.Lock() + s.metricsWriters = nil + s.mu.Unlock() } // ListMetricNames returns sorted list of all the metrics in s. +// +// The returned list doesn't include metrics generated by metricsWriter passed to RegisterMetricsWriter. func (s *Set) ListMetricNames() []string { s.mu.Lock() defer s.mu.Unlock() @@ -542,3 +559,17 @@ func (s *Set) ListMetricNames() []string { sort.Strings(metricNames) return metricNames } + +// RegisterMetricsWriter registers writeMetrics callback for including metrics in the output generated by s.WritePrometheus. +// +// The writeMetrics callback must write metrics to w in Prometheus text exposition format without timestamps and trailing comments. +// The last line generated by writeMetrics must end with \n. +// See https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md#text-based-format +// +// It is OK to reguster multiple writeMetrics callbacks - all of them will be called sequentially for gererating the output at s.WritePrometheus. +func (s *Set) RegisterMetricsWriter(writeMetrics func(w io.Writer)) { + s.mu.Lock() + defer s.mu.Unlock() + + s.metricsWriters = append(s.metricsWriters, writeMetrics) +} diff --git a/vendor/github.com/VictoriaMetrics/metrics/summary.go b/vendor/github.com/VictoriaMetrics/metrics/summary.go index 52183d22b..057b67bc5 100644 --- a/vendor/github.com/VictoriaMetrics/metrics/summary.go +++ b/vendor/github.com/VictoriaMetrics/metrics/summary.go @@ -119,6 +119,10 @@ func (sm *Summary) marshalTo(prefix string, w io.Writer) { } } +func (sm *Summary) metricType() string { + return "summary" +} + func splitMetricName(name string) (string, string) { n := strings.IndexByte(name, '{') if n < 0 { @@ -196,6 +200,10 @@ func (qv *quantileValue) marshalTo(prefix string, w io.Writer) { } } +func (qv *quantileValue) metricType() string { + return "unsupported" +} + func addTag(name, tag string) string { if len(name) == 0 || name[len(name)-1] != '}' { return fmt.Sprintf("%s{%s}", name, tag) diff --git a/vendor/github.com/bitfield/script/README.md b/vendor/github.com/bitfield/script/README.md index a06a70c19..98e87ec4d 100644 --- a/vendor/github.com/bitfield/script/README.md +++ b/vendor/github.com/bitfield/script/README.md @@ -1,7 +1,8 @@ [![Go Reference](https://pkg.go.dev/badge/github.com/bitfield/script.svg)](https://pkg.go.dev/github.com/bitfield/script) [![Go Report Card](https://goreportcard.com/badge/github.com/bitfield/script)](https://goreportcard.com/report/github.com/bitfield/script) [![Mentioned in Awesome Go](https://awesome.re/mentioned-badge-flat.svg)](https://github.com/avelino/awesome-go) -![Tests](https://github.com/bitfield/script/actions/workflows/test.yml/badge.svg) +![CI](https://github.com/bitfield/script/actions/workflows/ci.yml/badge.svg) +![Audit](https://github.com/bitfield/script/actions/workflows/audit.yml/badge.svg) ```go import "github.com/bitfield/script" @@ -33,6 +34,7 @@ If you're already familiar with shell scripting and the Unix toolset, here is a | `>` | [`WriteFile`](https://pkg.go.dev/github.com/bitfield/script#Pipe.WriteFile) | | `>>` | [`AppendFile`](https://pkg.go.dev/github.com/bitfield/script#Pipe.AppendFile) | | `$*` | [`Args`](https://pkg.go.dev/github.com/bitfield/script#Args) | +| `base64` | [`DecodeBase64`](https://pkg.go.dev/github.com/bitfield/script#Pipe.DecodeBase64) / [`EncodeBase64`](https://pkg.go.dev/github.com/bitfield/script#Pipe.EncodeBase64) | | `basename` | [`Basename`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Basename) | | `cat` | [`File`](https://pkg.go.dev/github.com/bitfield/script#File) / [`Concat`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Concat) | | `curl` | [`Do`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Do) / [`Get`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Get) / [`Post`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Post) | @@ -267,18 +269,31 @@ These are functions that create a pipe with a given contents: | Source | Contents | | -------- | ------------- | -| [`Args`](https://pkg.go.dev/github.com/bitfield/script#Args) | command-line arguments -| [`Do`](https://pkg.go.dev/github.com/bitfield/script#Do) | HTTP response -| [`Echo`](https://pkg.go.dev/github.com/bitfield/script#Echo) | a string -| [`Exec`](https://pkg.go.dev/github.com/bitfield/script#Exec) | command output -| [`File`](https://pkg.go.dev/github.com/bitfield/script#File) | file contents -| [`FindFiles`](https://pkg.go.dev/github.com/bitfield/script#FindFiles) | recursive file listing -| [`Get`](https://pkg.go.dev/github.com/bitfield/script#Get) | HTTP response -| [`IfExists`](https://pkg.go.dev/github.com/bitfield/script#IfExists) | do something only if some file exists -| [`ListFiles`](https://pkg.go.dev/github.com/bitfield/script#ListFiles) | file listing (including wildcards) -| [`Post`](https://pkg.go.dev/github.com/bitfield/script#Post) | HTTP response -| [`Slice`](https://pkg.go.dev/github.com/bitfield/script#Slice) | slice elements, one per line -| [`Stdin`](https://pkg.go.dev/github.com/bitfield/script#Stdin) | standard input +| [`Args`](https://pkg.go.dev/github.com/bitfield/script#Args) | command-line arguments | +| [`Do`](https://pkg.go.dev/github.com/bitfield/script#Do) | HTTP response | +| [`Echo`](https://pkg.go.dev/github.com/bitfield/script#Echo) | a string | +| [`Exec`](https://pkg.go.dev/github.com/bitfield/script#Exec) | command output | +| [`File`](https://pkg.go.dev/github.com/bitfield/script#File) | file contents | +| [`FindFiles`](https://pkg.go.dev/github.com/bitfield/script#FindFiles) | recursive file listing | +| [`Get`](https://pkg.go.dev/github.com/bitfield/script#Get) | HTTP response | +| [`IfExists`](https://pkg.go.dev/github.com/bitfield/script#IfExists) | do something only if some file exists | +| [`ListFiles`](https://pkg.go.dev/github.com/bitfield/script#ListFiles) | file listing (including wildcards) | +| [`Post`](https://pkg.go.dev/github.com/bitfield/script#Post) | HTTP response | +| [`Slice`](https://pkg.go.dev/github.com/bitfield/script#Slice) | slice elements, one per line | +| [`Stdin`](https://pkg.go.dev/github.com/bitfield/script#Stdin) | standard input | + +## Modifiers + +These are methods on a pipe that change its configuration: + +| Source | Modifies | +| -------- | ------------- | +| [`WithEnv`](https://pkg.go.dev/github.com/bitfield/script#Pipe.WithEnv) | environment for commands | +| [`WithError`](https://pkg.go.dev/github.com/bitfield/script#Pipe.WithError) | pipe error status | +| [`WithHTTPClient`](https://pkg.go.dev/github.com/bitfield/script#Pipe.WithHTTPClient) | client for HTTP requests | +| [`WithReader`](https://pkg.go.dev/github.com/bitfield/script#Pipe.WithReader) | pipe source | +| [`WithStderr`](https://pkg.go.dev/github.com/bitfield/script#Pipe.WithStderr) | standard error output stream for command | +| [`WithStdout`](https://pkg.go.dev/github.com/bitfield/script#Pipe.WithStdout) | standard output stream for pipe | ## Filters @@ -289,9 +304,11 @@ Filters are methods on an existing pipe that also return a pipe, allowing you to | [`Basename`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Basename) | removes leading path components from each line, leaving only the filename | | [`Column`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Column) | Nth column of input | | [`Concat`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Concat) | contents of multiple files | +| [`DecodeBase64`](https://pkg.go.dev/github.com/bitfield/script#Pipe.DecodeBase64) | input decoded from base64 | | [`Dirname`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Dirname) | removes filename from each line, leaving only leading path components | | [`Do`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Do) | response to supplied HTTP request | | [`Echo`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Echo) | all input replaced by given string | +| [`EncodeBase64`](https://pkg.go.dev/github.com/bitfield/script#Pipe.EncodeBase64) | input encoded to base64 | | [`Exec`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Exec) | filtered through external command | | [`ExecForEach`](https://pkg.go.dev/github.com/bitfield/script#Pipe.ExecForEach) | execute given command template for each line of input | | [`Filter`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Filter) | user-supplied function filtering a reader to a writer | @@ -329,13 +346,16 @@ Sinks are methods that return some data from a pipe, ending the pipeline and ext | [`Slice`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Slice) | | data as `[]string`, error | | [`Stdout`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Stdout) | standard output | bytes written, error | | [`String`](https://pkg.go.dev/github.com/bitfield/script#Pipe.String) | | data as `string`, error | -| [`Wait`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Wait) | | none | +| [`Wait`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Wait) | | error | | [`WriteFile`](https://pkg.go.dev/github.com/bitfield/script#Pipe.WriteFile) | specified file, truncating if it exists | bytes written, error | # What's new | Version | New | | ----------- | ------- | +| 0.23.0 | [`WithEnv`](https://pkg.go.dev/github.com/bitfield/script#Pipe.WithEnv) | +| | [`DecodeBase64`](https://pkg.go.dev/github.com/bitfield/script#Pipe.DecodeBase64) / [`EncodeBase64`](https://pkg.go.dev/github.com/bitfield/script#Pipe.EncodeBase64) | +| | [`Wait`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Wait) returns error | | v0.22.0 | [`Tee`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Tee), [`WithStderr`](https://pkg.go.dev/github.com/bitfield/script#Pipe.WithStderr) | | v0.21.0 | HTTP support: [`Do`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Do), [`Get`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Get), [`Post`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Post) | | v0.20.0 | [`JQ`](https://pkg.go.dev/github.com/bitfield/script#Pipe.JQ) | @@ -346,7 +366,7 @@ See the [contributor's guide](CONTRIBUTING.md) for some helpful tips if you'd li # Links -- [Scripting with Go](https://bitfieldconsulting.com/golang/scripting) +- [Scripting with Go](https://bitfieldconsulting.com/posts/scripting) - [Code Club: Script](https://www.youtube.com/watch?v=6S5EqzVwpEg) - [Bitfield Consulting](https://bitfieldconsulting.com/) - [Go books by John Arundel](https://bitfieldconsulting.com/books) diff --git a/vendor/github.com/bitfield/script/script.go b/vendor/github.com/bitfield/script/script.go index c471f74b4..e25b1c488 100644 --- a/vendor/github.com/bitfield/script/script.go +++ b/vendor/github.com/bitfield/script/script.go @@ -4,6 +4,7 @@ import ( "bufio" "container/ring" "crypto/sha256" + "encoding/base64" "encoding/hex" "encoding/json" "fmt" @@ -27,13 +28,14 @@ import ( // Pipe represents a pipe object with an associated [ReadAutoCloser]. type Pipe struct { // Reader is the underlying reader. - Reader ReadAutoCloser - stdout, stderr io.Writer - httpClient *http.Client + Reader ReadAutoCloser + stdout io.Writer + httpClient *http.Client - // because pipe stages are concurrent, protect 'err' - mu *sync.Mutex - err error + mu *sync.Mutex + err error + stderr io.Writer + env []string } // Args creates a pipe containing the program's command-line arguments from @@ -166,6 +168,7 @@ func NewPipe() *Pipe { mu: new(sync.Mutex), stdout: os.Stdout, httpClient: http.DefaultClient, + env: nil, } } @@ -275,6 +278,18 @@ func (p *Pipe) CountLines() (lines int, err error) { return lines, p.Error() } +// DecodeBase64 produces the string represented by the base64 encoded input. +func (p *Pipe) DecodeBase64() *Pipe { + return p.Filter(func(r io.Reader, w io.Writer) error { + decoder := base64.NewDecoder(base64.StdEncoding, r) + _, err := io.Copy(w, decoder) + if err != nil { + return err + } + return nil + }) +} + // Dirname reads paths from the pipe, one per line, and produces only the // parent directories of each path. For example, /usr/local/bin/foo would // become just /usr/local/bin. This is the complementary operation to @@ -347,7 +362,29 @@ func (p *Pipe) Echo(s string) *Pipe { return p.WithReader(strings.NewReader(s)) } +// EncodeBase64 produces the base64 encoding of the input. +func (p *Pipe) EncodeBase64() *Pipe { + return p.Filter(func(r io.Reader, w io.Writer) error { + encoder := base64.NewEncoder(base64.StdEncoding, w) + defer encoder.Close() + _, err := io.Copy(encoder, r) + if err != nil { + return err + } + return nil + }) +} + +func (p *Pipe) environment() []string { + p.mu.Lock() + defer p.mu.Unlock() + return p.env +} + // Error returns any error present on the pipe, or nil otherwise. +// Error is not a sink and does not wait until the pipe reaches +// completion. To wait for completion before returning the error, +// see [Pipe.Wait]. func (p *Pipe) Error() error { if p.mu == nil { // uninitialised pipe return nil @@ -362,6 +399,11 @@ func (p *Pipe) Error() error { // error output). The effect of this is to filter the contents of the pipe // through the external command. // +// # Environment +// +// The command inherits the current process's environment, optionally modified +// by [Pipe.WithEnv]. +// // # Error handling // // If the command had a non-zero exit status, the pipe's error status will also @@ -385,8 +427,13 @@ func (p *Pipe) Exec(cmdLine string) *Pipe { cmd.Stdin = r cmd.Stdout = w cmd.Stderr = w - if p.stderr != nil { - cmd.Stderr = p.stderr + pipeStderr := p.stdErr() + if pipeStderr != nil { + cmd.Stderr = pipeStderr + } + pipeEnv := p.environment() + if pipeEnv != nil { + cmd.Env = pipeEnv } err = cmd.Start() if err != nil { @@ -399,7 +446,8 @@ func (p *Pipe) Exec(cmdLine string) *Pipe { // ExecForEach renders cmdLine as a Go template for each line of input, running // the resulting command, and produces the combined output of all these -// commands in sequence. See [Pipe.Exec] for error handling details. +// commands in sequence. See [Pipe.Exec] for details on error handling and +// environment variables. // // This is mostly useful for substituting data into commands using Go template // syntax. For example: @@ -425,8 +473,12 @@ func (p *Pipe) ExecForEach(cmdLine string) *Pipe { cmd := exec.Command(args[0], args[1:]...) cmd.Stdout = w cmd.Stderr = w - if p.stderr != nil { - cmd.Stderr = p.stderr + pipeStderr := p.stdErr() + if pipeStderr != nil { + cmd.Stderr = pipeStderr + } + if p.env != nil { + cmd.Env = p.env } err = cmd.Start() if err != nil { @@ -810,6 +862,18 @@ func (p *Pipe) Slice() ([]string, error) { return result, p.Error() } +// stdErr returns the pipe's configured standard error writer for commands run +// via [Pipe.Exec] and [Pipe.ExecForEach]. The default is nil, which means that +// error output will go to the pipe. +func (p *Pipe) stdErr() io.Writer { + if p.mu == nil { // uninitialised pipe + return nil + } + p.mu.Lock() + defer p.mu.Unlock() + return p.stderr +} + // Stdout copies the pipe's contents to its configured standard output (using // [Pipe.WithStdout]), or to [os.Stdout] otherwise, and returns the number of // bytes successfully written, together with any error. @@ -848,14 +912,25 @@ func (p *Pipe) Tee(writers ...io.Writer) *Pipe { return p.WithReader(io.TeeReader(p.Reader, teeWriter)) } -// Wait reads the pipe to completion and discards the result. This is mostly -// useful for waiting until concurrent filters have completed (see -// [Pipe.Filter]). -func (p *Pipe) Wait() { +// Wait reads the pipe to completion and returns any error present on +// the pipe, or nil otherwise. This is mostly useful for waiting until +// concurrent filters have completed (see [Pipe.Filter]). +func (p *Pipe) Wait() error { _, err := io.Copy(io.Discard, p) if err != nil { p.SetError(err) } + return p.Error() +} + +// WithEnv sets the environment for subsequent [Pipe.Exec] and [Pipe.ExecForEach] +// commands to the string slice env, using the same format as [os/exec.Cmd.Env]. +// An empty slice unsets all existing environment variables. +func (p *Pipe) WithEnv(env []string) *Pipe { + p.mu.Lock() + defer p.mu.Unlock() + p.env = env + return p } // WithError sets the error err on the pipe. @@ -883,10 +958,11 @@ func (p *Pipe) WithReader(r io.Reader) *Pipe { return p } -// WithStderr redirects the standard error output for commands run via -// [Pipe.Exec] or [Pipe.ExecForEach] to the writer w, instead of going to the -// pipe as it normally would. +// WithStderr sets the standard error output for [Pipe.Exec] or +// [Pipe.ExecForEach] commands to w, instead of the pipe. func (p *Pipe) WithStderr(w io.Writer) *Pipe { + p.mu.Lock() + defer p.mu.Unlock() p.stderr = w return p } diff --git a/vendor/github.com/bytedance/sonic/.gitignore b/vendor/github.com/bytedance/sonic/.gitignore index 0d8844705..fa60f43a2 100644 --- a/vendor/github.com/bytedance/sonic/.gitignore +++ b/vendor/github.com/bytedance/sonic/.gitignore @@ -49,4 +49,7 @@ ast/bench.sh !testdata/*.json.gz fuzz/testdata -*__debug_bin \ No newline at end of file +*__debug_bin* +*pprof +*coverage.txt +tools/venv/* \ No newline at end of file diff --git a/vendor/github.com/bytedance/sonic/.gitmodules b/vendor/github.com/bytedance/sonic/.gitmodules index b8d11c921..ea84b991a 100644 --- a/vendor/github.com/bytedance/sonic/.gitmodules +++ b/vendor/github.com/bytedance/sonic/.gitmodules @@ -1,3 +1,6 @@ -[submodule "tools/asm2asm"] +[submodule "cloudwego"] path = tools/asm2asm - url = https://github.com/chenzhuoyu/asm2asm + url = https://github.com/cloudwego/asm2asm.git +[submodule "tools/simde"] + path = tools/simde + url = https://github.com/simd-everywhere/simde.git diff --git a/vendor/github.com/bytedance/sonic/Makefile b/vendor/github.com/bytedance/sonic/Makefile deleted file mode 100644 index c672c313e..000000000 --- a/vendor/github.com/bytedance/sonic/Makefile +++ /dev/null @@ -1,111 +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. -# - -ARCH := avx avx2 sse -TMP_DIR := output -OUT_DIR := internal/native -SRC_FILE := native/native.c - -CPU_avx := amd64 -CPU_avx2 := amd64 -CPU_sse := amd64 - -TMPL_avx := fastint_amd64_test fastfloat_amd64_test native_amd64_test recover_amd64_test -TMPL_avx2 := fastint_amd64_test fastfloat_amd64_test native_amd64_test recover_amd64_test -TMPL_sse := fastint_amd64_test fastfloat_amd64_test native_amd64_test recover_amd64_test - -CFLAGS_avx := -msse -mno-sse4 -mavx -mpclmul -mno-avx2 -mstack-alignment=0 -DUSE_AVX=1 -DUSE_AVX2=0 -CFLAGS_avx2 := -msse -mno-sse4 -mavx -mpclmul -mavx2 -mstack-alignment=0 -DUSE_AVX=1 -DUSE_AVX2=1 -CFLAGS_sse := -msse -mno-sse4 -mno-avx -mno-avx2 -mpclmul - -CC_amd64 := clang -ASM2ASM_amd64 := tools/asm2asm/asm2asm.py - -CFLAGS := -mno-red-zone -CFLAGS += -target x86_64-apple-macos11 -CFLAGS += -fno-asynchronous-unwind-tables -CFLAGS += -fno-builtin -CFLAGS += -fno-exceptions -CFLAGS += -fno-rtti -CFLAGS += -fno-stack-protector -CFLAGS += -nostdlib -CFLAGS += -O3 -CFLAGS += -Wall -Werror - -NATIVE_SRC := $(wildcard native/*.h) -NATIVE_SRC += $(wildcard native/*.c) - -.PHONY: all clean ${ARCH} - -define build_tmpl - $(eval @arch := $(1)) - $(eval @tmpl := $(2)) - $(eval @dest := $(3)) - -${@dest}: ${@tmpl} - mkdir -p $(dir ${@dest}) - echo '// Code generated by Makefile, DO NOT EDIT.' > ${@dest} - echo >> ${@dest} - sed -e 's/{{PACKAGE}}/${@arch}/g' ${@tmpl} >> ${@dest} -endef - -define build_arch - $(eval @cpu := $(value CPU_$(1))) - $(eval @deps := $(foreach tmpl,$(value TMPL_$(1)),${OUT_DIR}/$(1)/${tmpl}.go)) - $(eval @asmin := ${TMP_DIR}/$(1)/native.s) - $(eval @asmout := ${OUT_DIR}/$(1)/native_text_${@cpu}.go) - $(eval @stubin := ${OUT_DIR}/native_${@cpu}.tmpl) - $(eval @stubout := ${OUT_DIR}/$(1)/native_${@cpu}.go) - -$(1): ${@asmout} ${@deps} - -${@asmout}: ${@stubout} ${NATIVE_SRC} - mkdir -p ${TMP_DIR}/$(1) - $${CC_${@cpu}} $${CFLAGS} $${CFLAGS_$(1)} -S -o ${TMP_DIR}/$(1)/native.s ${SRC_FILE} - python3 $${ASM2ASM_${@cpu}} -r ${@stubout} ${TMP_DIR}/$(1)/native.s - -$(eval $(call \ - build_tmpl, \ - $(1), \ - ${@stubin}, \ - ${@stubout} \ -)) - -$(foreach \ - tmpl, \ - $(value TMPL_$(1)), \ - $(eval $(call \ - build_tmpl, \ - $(1), \ - ${OUT_DIR}/${tmpl}.tmpl, \ - ${OUT_DIR}/$(1)/${tmpl}.go \ - )) \ -) -endef - -all: ${ARCH} - -clean: - for arch in ${ARCH}; do \ - rm -vfr ${TMP_DIR}/$${arch}; \ - rm -vfr ${OUT_DIR}/$${arch}; \ - done - -$(foreach \ - arch, \ - ${ARCH}, \ - $(eval $(call build_arch,${arch})) \ -) diff --git a/vendor/github.com/bytedance/sonic/README.md b/vendor/github.com/bytedance/sonic/README.md index 42772018c..5f609b1c3 100644 --- a/vendor/github.com/bytedance/sonic/README.md +++ b/vendor/github.com/bytedance/sonic/README.md @@ -5,18 +5,27 @@ English | [中文](README_ZH_CN.md) A blazingly fast JSON serializing & deserializing library, accelerated by JIT (just-in-time compiling) and SIMD (single-instruction-multiple-data). ## Requirement -- Go 1.16~1.21 -- Linux / MacOS / Windows(need go1.17 above) -- Amd64 ARCH + +- Go: 1.17~1.23 +- OS: Linux / MacOS / Windows +- CPU: AMD64 / ARM64(need go1.20 above) ## Features + - Runtime object binding without code generation - Complete APIs for JSON value manipulation - Fast, fast, fast! +## APIs + +see [go.dev](https://pkg.go.dev/github.com/bytedance/sonic) + ## Benchmarks + For **all sizes** of json and **all scenarios** of usage, **Sonic performs best**. + - [Medium](https://github.com/bytedance/sonic/blob/main/decoder/testdata_test.go#L19) (13KB, 300+ key, 6 layers) + ```powershell goversion: 1.17.1 goos: darwin @@ -81,14 +90,16 @@ BenchmarkLoadNode_Parallel/LoadAll()-16 5493 ns/op 2370.6 BenchmarkLoadNode/Interface()-16 17722 ns/op 734.85 MB/s 13323 B/op 88 allocs/op BenchmarkLoadNode_Parallel/Interface()-16 10330 ns/op 1260.70 MB/s 15178 B/op 88 allocs/op ``` + - [Small](https://github.com/bytedance/sonic/blob/main/testdata/small.go) (400B, 11 keys, 3 layers) ![small benchmarks](./docs/imgs/bench-small.png) - [Large](https://github.com/bytedance/sonic/blob/main/testdata/twitter.json) (635KB, 10000+ key, 6 layers) ![large benchmarks](./docs/imgs/bench-large.png) -See [bench.sh](https://github.com/bytedance/sonic/blob/main/bench.sh) for benchmark codes. +See [bench.sh](https://github.com/bytedance/sonic/blob/main/scripts/bench.sh) for benchmark codes. ## How it works + See [INTRODUCTION.md](./docs/INTRODUCTION.md). ## Usage @@ -96,6 +107,7 @@ See [INTRODUCTION.md](./docs/INTRODUCTION.md). ### Marshal/Unmarshal Default behaviors are mostly consistent with `encoding/json`, except HTML escaping form (see [Escape HTML](https://github.com/bytedance/sonic/blob/main/README.md#escape-html)) and `SortKeys` feature (optional support see [Sort Keys](https://github.com/bytedance/sonic/blob/main/README.md#sort-keys)) that is **NOT** in conformity to [RFC8259](https://datatracker.ietf.org/doc/html/rfc8259). + ```go import "github.com/bytedance/sonic" @@ -107,8 +119,11 @@ err := sonic.Unmarshal(output, &data) ``` ### Streaming IO -Sonic supports decoding json from `io.Reader` or encoding objects into `io.`Writer`, aims at handling multiple values as well as reducing memory consumption. + +Sonic supports decoding json from `io.Reader` or encoding objects into `io.Writer`, aims at handling multiple values as well as reducing memory consumption. + - encoder + ```go var o1 = map[string]interface{}{ "a": "b", @@ -123,7 +138,9 @@ fmt.Println(w.String()) // {"a":"b"} // 1 ``` + - decoder + ```go var o = map[string]interface{}{} var r = strings.NewReader(`{"a":"b"}{"1":"2"}`) @@ -136,6 +153,7 @@ fmt.Printf("%+v", o) ``` ### Use Number/Use Int64 + ```go import "github.com/bytedance/sonic/decoder" @@ -164,7 +182,9 @@ fm := root.Interface().(float64) // jn == jm ``` ### Sort Keys + On account of the performance loss from sorting (roughly 10%), sonic doesn't enable this feature by default. If your component depends on it to work (like [zstd](https://github.com/facebook/zstd)), Use it like this: + ```go import "github.com/bytedance/sonic" import "github.com/bytedance/sonic/encoder" @@ -177,19 +197,26 @@ v, err := encoder.Encode(m, encoder.SortMapKeys) var root := sonic.Get(JSON) err := root.SortKeys() ``` + ### Escape HTML + On account of the performance loss (roughly 15%), sonic doesn't enable this feature by default. You can use `encoder.EscapeHTML` option to open this feature (align with `encoding/json.HTMLEscape`). + ```go import "github.com/bytedance/sonic" v := map[string]string{"&&":"<>"} ret, err := Encode(v, EscapeHTML) // ret == `{"\u0026\u0026":{"X":"\u003c\u003e"}}` ``` + ### Compact Format + Sonic encodes primitive objects (struct/map...) as compact-format JSON by default, except marshaling `json.RawMessage` or `json.Marshaler`: sonic ensures validating their output JSON but **DONOT** compacting them for performance concerns. We provide the option `encoder.CompactMarshaler` to add compacting process. ### Print Error + If there invalid syntax in input JSON, sonic will return `decoder.SyntaxError`, which supports pretty-printing of error position + ```go import "github.com/bytedance/sonic" import "github.com/bytedance/sonic/decoder" @@ -215,7 +242,9 @@ if err != nil { ``` #### Mismatched Types [Sonic v1.6.0] + If there a **mismatch-typed** value for a given key, sonic will report `decoder.MismatchTypeError` (if there are many, report the last one), but still skip wrong the value and keep decoding next JSON. + ```go import "github.com/bytedance/sonic" import "github.com/bytedance/sonic/decoder" @@ -228,10 +257,15 @@ err := UnmarshalString(`{"A":"1","B":1}`, &data) println(err.Error()) // Mismatch type int with value string "at index 5: mismatched type with value\n\n\t{\"A\":\"1\",\"B\":1}\n\t.....^.........\n" fmt.Printf("%+v", data) // {A:0 B:1} ``` + ### Ast.Node + Sonic/ast.Node is a completely self-contained AST for JSON. It implements serialization and deserialization both and provides robust APIs for obtaining and modification of generic data. + #### Get/Index + Search partial JSON by given paths, which must be non-negative integer or string, or nil + ```go import "github.com/bytedance/sonic" @@ -245,10 +279,29 @@ raw := root.Raw() // == string(input) root, err := sonic.Get(input, "key1", 1, "key2") sub := root.Get("key3").Index(2).Int64() // == 3 ``` + **Tip**: since `Index()` uses offset to locate data, which is much faster than scanning like `Get()`, we suggest you use it as much as possible. And sonic also provides another API `IndexOrGet()` to underlying use offset as well as ensure the key is matched. +#### SearchOption + +`Searcher` provides some options for user to meet different needs: + +```go +opts := ast.SearchOption{ CopyReturn: true ... } +val, err := sonic.GetWithOptions(JSON, opts, "key") +``` + +- CopyReturn +Indicate the searcher to copy the result JSON string instead of refer from the input. This can help to reduce memory usage if you cache the results +- ConcurentRead +Since `ast.Node` use `Lazy-Load` design, it doesn't support Concurrently-Read by default. If you want to read it concurrently, please specify it. +- ValidateJSON +Indicate the searcher to validate the entire JSON. This option is enabled by default, which slow down the search speed a little. + #### Set/Unset + Modify the json content by Set()/Unset() + ```go import "github.com/bytedance/sonic" @@ -265,7 +318,9 @@ println(root.Get("key4").Check()) // "value not exist" ``` #### Serialize + To encode `ast.Node` as json, use `MarshalJson()` or `json.Marshal()` (MUST pass the node's pointer) + ```go import ( "encoding/json" @@ -279,6 +334,7 @@ println(string(buf) == string(exp)) // true ``` #### APIs + - validation: `Check()`, `Error()`, `Valid()`, `Exist()` - searching: `Index()`, `Get()`, `IndexPair()`, `IndexOrGet()`, `GetByPath()` - go-type casting: `Int64()`, `Float64()`, `String()`, `Number()`, `Bool()`, `Map[UseNumber|UseNode]()`, `Array[UseNumber|UseNode]()`, `Interface[UseNumber|UseNode]()` @@ -287,7 +343,9 @@ println(string(buf) == string(exp)) // true - modification: `Set()`, `SetByIndex()`, `Add()` ### Ast.Visitor + Sonic provides an advanced API for fully parsing JSON into non-standard types (neither `struct` not `map[string]interface{}`) without using any intermediate representation (`ast.Node` or `interface{}`). For example, you might have the following types which are like `interface{}` but actually not `interface{}`: + ```go type UserNode interface {} @@ -302,7 +360,9 @@ type ( UserArray struct{ Value []UserNode } ) ``` + Sonic provides the following API to return **the preorder traversal of a JSON AST**. The `ast.Visitor` is a SAX style interface which is used in some C++ JSON library. You should implement `ast.Visitor` by yourself and pass it to `ast.Preorder()` method. In your visitor you can make your custom types to represent JSON values. There may be an O(n) space container (such as stack) in your visitor to record the object / array hierarchy. + ```go func Preorder(str string, visitor Visitor, opts *VisitorOptions) error @@ -323,20 +383,20 @@ type Visitor interface { See [ast/visitor.go](https://github.com/bytedance/sonic/blob/main/ast/visitor.go) for detailed usage. We also implement a demo visitor for `UserNode` in [ast/visitor_test.go](https://github.com/bytedance/sonic/blob/main/ast/visitor_test.go). ## Compatibility -Sonic **DOES NOT** ensure to support all environments, due to the difficulty of developing high-performance codes. For developers who use sonic to build their applications in different environments, we have the following suggestions: -- Developing on **Mac M1**: Make sure you have Rosetta 2 installed on your machine, and set `GOARCH=amd64` when building your application. Rosetta 2 can automatically translate x86 binaries to arm64 binaries and run x86 applications on Mac M1. -- Developing on **Linux arm64**: You can install qemu and use the `qemu-x86_64 -cpu max` command to convert x86 binaries to amr64 binaries for applications built with sonic. The qemu can achieve a similar transfer effect to Rosetta 2 on Mac M1. +For developers who want to use sonic to meet diffirent scenarios, we provide some integrated configs as `sonic.API` -For developers who want to use sonic on Linux arm64 without qemu, or those who want to handle JSON strictly consistent with `encoding/json`, we provide some compatible APIs as `sonic.API` -- `ConfigDefault`: the sonic's default config (`EscapeHTML=false`,`SortKeys=false`...) to run on sonic-supporting environment. It will fall back to `encoding/json` with the corresponding config, and some options like `SortKeys=false` will be invalid. -- `ConfigStd`: the std-compatible config (`EscapeHTML=true`,`SortKeys=true`...) to run on sonic-supporting environment. It will fall back to `encoding/json`. -- `ConfigFastest`: the fastest config (`NoQuoteTextMarshaler=true`) to run on sonic-supporting environment. It will fall back to `encoding/json` with the corresponding config, and some options will be invalid. +- `ConfigDefault`: the sonic's default config (`EscapeHTML=false`,`SortKeys=false`...) to run sonic fast meanwhile ensure security. +- `ConfigStd`: the std-compatible config (`EscapeHTML=true`,`SortKeys=true`...) +- `ConfigFastest`: the fastest config (`NoQuoteTextMarshaler=true`) to run on sonic as fast as possible. +Sonic **DOES NOT** ensure to support all environments, due to the difficulty of developing high-performance codes. On non-sonic-supporting environment, the implementation will fall back to `encoding/json`. Thus beflow configs will all equal to `ConfigStd`. ## Tips ### Pretouch + Since Sonic uses [golang-asm](https://github.com/twitchyliquid64/golang-asm) as a JIT assembler, which is NOT very suitable for runtime compiling, first-hit running of a huge schema may cause request-timeout or even process-OOM. For better stability, we advise **using `Pretouch()` for huge-schema or compact-memory applications** before `Marshal()/Unmarshal()`. + ```go import ( "reflect" @@ -362,17 +422,23 @@ func init() { ``` ### Copy string -When decoding **string values without any escaped characters**, sonic references them from the origin JSON buffer instead of mallocing a new buffer to copy. This helps a lot for CPU performance but may leave the whole JSON buffer in memory as long as the decoded objects are being used. In practice, we found the extra memory introduced by referring JSON buffer is usually 20% ~ 80% of decoded objects. Once an application holds these objects for a long time (for example, cache the decoded objects for reusing), its in-use memory on the server may go up. We provide the option `decoder.CopyString()` for users to choose not to reference the JSON buffer, which may cause a decline in CPU performance to some degree. + +When decoding **string values without any escaped characters**, sonic references them from the origin JSON buffer instead of mallocing a new buffer to copy. This helps a lot for CPU performance but may leave the whole JSON buffer in memory as long as the decoded objects are being used. In practice, we found the extra memory introduced by referring JSON buffer is usually 20% ~ 80% of decoded objects. Once an application holds these objects for a long time (for example, cache the decoded objects for reusing), its in-use memory on the server may go up. - `Config.CopyString`/`decoder.CopyString()`: We provide the option for `Decode()` / `Unmarshal()` users to choose not to reference the JSON buffer, which may cause a decline in CPU performance to some degree. + +- `GetFromStringNoCopy()`: For memory safety, `sonic.Get()` / `sonic.GetFromString()` now copies return JSON. If users want to get json more quickly and not care about memory usage, you can use `GetFromStringNoCopy()` to return a JSON directly referenced from source. ### Pass string or []byte? + For alignment to `encoding/json`, we provide API to pass `[]byte` as an argument, but the string-to-bytes copy is conducted at the same time considering safety, which may lose performance when the origin JSON is huge. Therefore, you can use `UnmarshalString()` and `GetFromString()` to pass a string, as long as your origin data is a string or **nocopy-cast** is safe for your []byte. We also provide API `MarshalString()` for convenient **nocopy-cast** of encoded JSON []byte, which is safe since sonic's output bytes is always duplicated and unique. ### Accelerate `encoding.TextMarshaler` -To ensure data security, sonic.Encoder quotes and escapes string values from `encoding.TextMarshaler` interfaces by default, which may degrade performance much if most of your data is in form of them. We provide `encoder.NoQuoteTextMarshaler` to skip these operations, which means you **MUST** ensure their output string escaped and quoted following [RFC8259](https://datatracker.ietf.org/doc/html/rfc8259). +To ensure data security, sonic.Encoder quotes and escapes string values from `encoding.TextMarshaler` interfaces by default, which may degrade performance much if most of your data is in form of them. We provide `encoder.NoQuoteTextMarshaler` to skip these operations, which means you **MUST** ensure their output string escaped and quoted following [RFC8259](https://datatracker.ietf.org/doc/html/rfc8259). ### Better performance for generic data + In **fully-parsed** scenario, `Unmarshal()` performs better than `Get()`+`Node.Interface()`. But if you only have a part of the schema for specific json, you can combine `Get()` and `Unmarshal()` together: + ```go import "github.com/bytedance/sonic" @@ -380,7 +446,9 @@ node, err := sonic.GetFromString(_TwitterJson, "statuses", 3, "user") var user User // your partial schema... err = sonic.UnmarshalString(node.Raw(), &user) ``` + Even if you don't have any schema, use `ast.Node` as the container of generic values instead of `map` or `interface`: + ```go import "github.com/bytedance/sonic" @@ -391,7 +459,9 @@ err = user.Check() // err = user.LoadAll() // only call this when you want to use 'user' concurrently... go someFunc(user) ``` + Why? Because `ast.Node` stores its children using `array`: + - `Array`'s performance is **much better** than `Map` when Inserting (Deserialize) and Scanning (Serialize) data; - **Hashing** (`map[x]`) is not as efficient as **Indexing** (`array[x]`), which `ast.Node` can conduct on **both array and object**; - Using `Interface()`/`Map()` means Sonic must parse all the underlying values, while `ast.Node` can parse them **on demand**. @@ -399,6 +469,7 @@ Why? Because `ast.Node` stores its children using `array`: **CAUTION:** `ast.Node` **DOESN'T** ensure concurrent security directly, due to its **lazy-load** design. However, you can call `Node.Load()`/`Node.LoadAll()` to achieve that, which may bring performance reduction while it still works faster than converting to `map` or `interface{}` ### Ast.Node or Ast.Visitor? + For generic data, `ast.Node` should be enough for your needs in most cases. However, `ast.Node` is designed for partially processing JSON string. It has some special designs such as lazy-load which might not be suitable for directly parsing the whole JSON string like `Unmarshal()`. Although `ast.Node` is better then `map` or `interface{}`, it's also a kind of intermediate representation after all if your final types are customized and you have to convert the above types to your custom types after parsing. @@ -407,5 +478,18 @@ For better performance, in previous case the `ast.Visitor` will be the better ch But `ast.Visitor` is not a very handy API. You might need to write a lot of code to implement your visitor and carefully maintain the tree hierarchy during decoding. Please read the comments in [ast/visitor.go](https://github.com/bytedance/sonic/blob/main/ast/visitor.go) carefully if you decide to use this API. +### Buffer Size + +Sonic use memory pool in many places like `encoder.Encode`, `ast.Node.MarshalJSON` to improve performace, which may produce more memory usage (in-use) when server's load is high. See [issue 614](https://github.com/bytedance/sonic/issues/614). Therefore, we introduce some options to let user control the behavior of memory pool. See [option](https://pkg.go.dev/github.com/bytedance/sonic@v1.11.9/option#pkg-variables) package. + +### Faster JSON skip + +For security, sonic use [FSM](native/skip_one.c) algorithm to validate JSON when decoding raw JSON or encoding `json.Marshaler`, which is much slower (1~10x) than [SIMD-searching-pair](native/skip_one_fast.c) algorithm. If user has many redundant JSON value and DO NOT NEED to strictly validate JSON correctness, you can enable below options: + +- `Config.NoValidateSkipJSON`: for faster skipping JSON when decoding, such as unknown fields, json.Unmarshaler(json.RawMessage), mismatched values, and redundant array elements +- `Config.NoValidateJSONMarshaler`: avoid validating JSON when encoding `json.Marshaler` +- `SearchOption.ValidateJSON`: indicates if validate located JSON value when `Get` + ## Community + Sonic is a subproject of [CloudWeGo](https://www.cloudwego.io/). We are committed to building a cloud native ecosystem. diff --git a/vendor/github.com/bytedance/sonic/README_ZH_CN.md b/vendor/github.com/bytedance/sonic/README_ZH_CN.md index dc5cfb5df..4f8980c53 100644 --- a/vendor/github.com/bytedance/sonic/README_ZH_CN.md +++ b/vendor/github.com/bytedance/sonic/README_ZH_CN.md @@ -6,9 +6,13 @@ ## 依赖 -- Go 1.16~1.20 -- Linux / MacOS / Windows(需要 Go1.17 以上) -- Amd64 架构 +- Go: 1.17~1.23 +- OS: Linux / MacOS / Windows +- CPU: AMD64 / ARM64(需要 Go1.20 以上) + +## 接口 + +详见 [go.dev](https://pkg.go.dev/github.com/bytedance/sonic) ## 特色 @@ -19,7 +23,9 @@ ## 基准测试 对于**所有大小**的 json 和**所有使用场景**, **Sonic 表现均为最佳**。 + - [中型](https://github.com/bytedance/sonic/blob/main/decoder/testdata_test.go#L19) (13kB, 300+ 键, 6 层) + ```powershell goversion: 1.17.1 goos: darwin @@ -84,12 +90,13 @@ BenchmarkLoadNode_Parallel/LoadAll()-16 5493 ns/op 2370.6 BenchmarkLoadNode/Interface()-16 17722 ns/op 734.85 MB/s 13323 B/op 88 allocs/op BenchmarkLoadNode_Parallel/Interface()-16 10330 ns/op 1260.70 MB/s 15178 B/op 88 allocs/op ``` + - [小型](https://github.com/bytedance/sonic/blob/main/testdata/small.go) (400B, 11 个键, 3 层) ![small benchmarks](./docs/imgs/bench-small.png) - [大型](https://github.com/bytedance/sonic/blob/main/testdata/twitter.json) (635kB, 10000+ 个键, 6 层) ![large benchmarks](./docs/imgs/bench-large.png) -要查看基准测试代码,请参阅 [bench.sh](https://github.com/bytedance/sonic/blob/main/bench.sh) 。 +要查看基准测试代码,请参阅 [bench.sh](https://github.com/bytedance/sonic/blob/main/scripts/bench.sh) 。 ## 工作原理 @@ -100,6 +107,7 @@ BenchmarkLoadNode_Parallel/Interface()-16 10330 ns/op 1260.7 ### 序列化/反序列化 默认的行为基本上与 `encoding/json` 相一致,除了 HTML 转义形式(参见 [Escape HTML](https://github.com/bytedance/sonic/blob/main/README.md#escape-html)) 和 `SortKeys` 功能(参见 [Sort Keys](https://github.com/bytedance/sonic/blob/main/README.md#sort-keys))**没有**遵循 [RFC8259](https://datatracker.ietf.org/doc/html/rfc8259) 。 + ```go import "github.com/bytedance/sonic" @@ -113,7 +121,9 @@ err := sonic.Unmarshal(output, &data) ### 流式输入输出 Sonic 支持解码 `io.Reader` 中输入的 json,或将对象编码为 json 后输出至 `io.Writer`,以处理多个值并减少内存消耗。 + - 编码器 + ```go var o1 = map[string]interface{}{ "a": "b", @@ -128,7 +138,9 @@ fmt.Println(w.String()) // {"a":"b"} // 1 ``` + - 解码器 + ```go var o = map[string]interface{}{} var r = strings.NewReader(`{"a":"b"}{"1":"2"}`) @@ -172,6 +184,7 @@ fm := root.Interface().(float64) // jn == jm ### 对键排序 考虑到排序带来的性能损失(约 10% ), sonic 默认不会启用这个功能。如果你的组件依赖这个行为(如 [zstd](https://github.com/facebook/zstd)) ,可以仿照下面的例子: + ```go import "github.com/bytedance/sonic" import "github.com/bytedance/sonic/encoder" @@ -188,6 +201,7 @@ err := root.SortKeys() ### HTML 转义 考虑到性能损失(约15%), sonic 默认不会启用这个功能。你可以使用 `encoder.EscapeHTML` 选项来开启(与 `encoding/json.HTMLEscape` 行为一致)。 + ```go import "github.com/bytedance/sonic" @@ -196,11 +210,13 @@ ret, err := Encode(v, EscapeHTML) // ret == `{"\u0026\u0026":{"X":"\u003c\u003e" ``` ### 紧凑格式 + Sonic 默认将基本类型( `struct` , `map` 等)编码为紧凑格式的 JSON ,除非使用 `json.RawMessage` or `json.Marshaler` 进行编码: sonic 确保输出的 JSON 合法,但出于性能考虑,**不会**加工成紧凑格式。我们提供选项 `encoder.CompactMarshaler` 来添加此过程, ### 打印错误 如果输入的 JSON 存在无效的语法,sonic 将返回 `decoder.SyntaxError`,该错误支持错误位置的美化输出。 + ```go import "github.com/bytedance/sonic" import "github.com/bytedance/sonic/decoder" @@ -228,6 +244,7 @@ if err != nil { #### 类型不匹配 [Sonic v1.6.0] 如果给定键中存在**类型不匹配**的值, sonic 会抛出 `decoder.MismatchTypeError` (如果有多个,只会报告最后一个),但仍会跳过错误的值并解码下一个 JSON 。 + ```go import "github.com/bytedance/sonic" import "github.com/bytedance/sonic/decoder" @@ -240,13 +257,15 @@ err := UnmarshalString(`{"A":"1","B":1}`, &data) println(err.Error()) // Mismatch type int with value string "at index 5: mismatched type with value\n\n\t{\"A\":\"1\",\"B\":1}\n\t.....^.........\n" fmt.Printf("%+v", data) // {A:0 B:1} ``` + ### `Ast.Node` -Sonic/ast.Node 是完全独立的 JSON 抽象语法树库。它实现了序列化和反序列化,并提供了获取和修改通用数据的鲁棒的 API。 +Sonic/ast.Node 是完全独立的 JSON 抽象语法树库。它实现了序列化和反序列化,并提供了获取和修改JSON数据的鲁棒的 API。 #### 查找/索引 通过给定的路径搜索 JSON 片段,路径必须为非负整数,字符串或 `nil` 。 + ```go import "github.com/bytedance/sonic" @@ -260,11 +279,29 @@ raw := root.Raw() // == string(input) root, err := sonic.Get(input, "key1", 1, "key2") sub := root.Get("key3").Index(2).Int64() // == 3 ``` + **注意**:由于 `Index()` 使用偏移量来定位数据,比使用扫描的 `Get()` 要快的多,建议尽可能的使用 `Index` 。 Sonic 也提供了另一个 API, `IndexOrGet()` ,以偏移量为基础并且也确保键的匹配。 +#### 查找选项 + +`ast.Searcher`提供了一些选项,以满足用户的不同需求: + +``` +opts:= ast.SearchOption{CopyReturn: true…} +Val, err:= sonic。gettwithoptions (JSON, opts, "key") +``` + +- CopyReturn +指示搜索器复制结果JSON字符串,而不是从输入引用。如果用户缓存结果,这有助于减少内存使用 +- ConcurentRead +因为`ast.Node`使用`Lazy-Load`设计,默认不支持并发读取。如果您想同时读取,请指定它。 +- ValidateJSON +指示搜索器来验证整个JSON。默认情况下启用该选项, 但是对于查找速度有一定影响。 + #### 修改 -使用 ` Set()` / `Unset()` 修改 json 的内容 +使用 `Set()` / `Unset()` 修改 json 的内容 + ```go import "github.com/bytedance/sonic" @@ -281,7 +318,9 @@ println(root.Get("key4").Check()) // "value not exist" ``` #### 序列化 + 要将 `ast.Node` 编码为 json ,使用 `MarshalJson()` 或者 `json.Marshal()` (必须传递指向节点的指针) + ```go import ( "encoding/json" @@ -295,6 +334,7 @@ println(string(buf) == string(exp)) // true ``` #### APIs + - 合法性检查: `Check()`, `Error()`, `Valid()`, `Exist()` - 索引: `Index()`, `Get()`, `IndexPair()`, `IndexOrGet()`, `GetByPath()` - 转换至 go 内置类型: `Int64()`, `Float64()`, `String()`, `Number()`, `Bool()`, `Map[UseNumber|UseNode]()`, `Array[UseNumber|UseNode]()`, `Interface[UseNumber|UseNode]()` @@ -303,7 +343,9 @@ println(string(buf) == string(exp)) // true - 修改: `Set()`, `SetByIndex()`, `Add()` ### `Ast.Visitor` + Sonic 提供了一个高级的 API 用于直接全量解析 JSON 到非标准容器里 (既不是 `struct` 也不是 `map[string]interface{}`) 且不需要借助任何中间表示 (`ast.Node` 或 `interface{}`)。举个例子,你可能定义了下述的类型,它们看起来像 `interface{}`,但实际上并不是: + ```go type UserNode interface {} @@ -318,7 +360,9 @@ type ( UserArray struct{ Value []UserNode } ) ``` + Sonic 提供了下述的 API 来返回 **“对 JSON AST 的前序遍历”**。`ast.Visitor` 是一个 SAX 风格的接口,这在某些 C++ 的 JSON 解析库中被使用到。你需要自己实现一个 `ast.Visitor`,将它传递给 `ast.Preorder()` 方法。在你的实现中你可以使用自定义的类型来表示 JSON 的值。在你的 `ast.Visitor` 中,可能需要有一个 O(n) 空间复杂度的容器(比如说栈)来记录 object / array 的层级。 + ```go func Preorder(str string, visitor Visitor, opts *VisitorOptions) error @@ -335,23 +379,24 @@ type Visitor interface { OnArrayEnd() error } ``` + 详细用法参看 [ast/visitor.go](https://github.com/bytedance/sonic/blob/main/ast/visitor.go),我们还为 `UserNode` 实现了一个示例 `ast.Visitor`,你可以在 [ast/visitor_test.go](https://github.com/bytedance/sonic/blob/main/ast/visitor_test.go) 中找到它。 ## 兼容性 -由于开发高性能代码的困难性, Sonic **不**保证对所有环境的支持。对于在不同环境中使用 Sonic 构建应用程序的开发者,我们有以下建议: -- 在 **Mac M1** 上开发:确保在您的计算机上安装了 Rosetta 2,并在构建时设置 `GOARCH=amd64` 。 Rosetta 2 可以自动将 x86 二进制文件转换为 arm64 二进制文件,并在 Mac M1 上运行 x86 应用程序。 -- 在 **Linux arm64** 上开发:您可以安装 qemu 并使用 `qemu-x86_64 -cpu max` 命令来将 x86 二进制文件转换为 arm64 二进制文件。qemu可以实现与Mac M1上的Rosetta 2类似的转换效果。 +对于想要使用sonic来满足不同场景的开发人员,我们提供了一些集成配置: -对于希望在不使用 qemu 下使用 sonic 的开发者,或者希望处理 JSON 时与 `encoding/JSON` 严格保持一致的开发者,我们在 `sonic.API` 中提供了一些兼容性 API -- `ConfigDefault`: 在支持 sonic 的环境下 sonic 的默认配置(`EscapeHTML=false`,`SortKeys=false`等)。行为与具有相应配置的 `encoding/json` 一致,一些选项,如 `SortKeys=false` 将无效。 -- `ConfigStd`: 在支持 sonic 的环境下与标准库兼容的配置(`EscapeHTML=true`,`SortKeys=true`等)。行为与 `encoding/json` 一致。 -- `ConfigFastest`: 在支持 sonic 的环境下运行最快的配置(`NoQuoteTextMarshaler=true`)。行为与具有相应配置的 `encoding/json` 一致,某些选项将无效。 +- `ConfigDefault`: sonic的默认配置 (`EscapeHTML=false`, `SortKeys=false`…) 保证性能同时兼顾安全性。 +- `ConfigStd`: 与 `encoding/json` 保证完全兼容的配置 +- `ConfigFastest`: 最快的配置(`NoQuoteTextMarshaler=true...`) 保证性能最优但是会缺少一些安全性检查(validate UTF8 等) +Sonic **不**确保支持所有环境,由于开发高性能代码的困难。在不支持声音的环境中,实现将回落到 `encoding/json`。因此上述配置将全部等于`ConfigStd`。 ## 注意事项 ### 预热 + 由于 Sonic 使用 [golang-asm](https://github.com/twitchyliquid64/golang-asm) 作为 JIT 汇编器,这个库并不适用于运行时编译,第一次运行一个大型模式可能会导致请求超时甚至进程内存溢出。为了更好地稳定性,我们建议在运行大型模式或在内存有限的应用中,在使用 `Marshal()/Unmarshal()` 前运行 `Pretouch()`。 + ```go import ( "reflect" @@ -381,16 +426,17 @@ func init() { 当解码 **没有转义字符的字符串**时, sonic 会从原始的 JSON 缓冲区内引用而不是复制到新的一个缓冲区中。这对 CPU 的性能方面很有帮助,但是可能因此在解码后对象仍在使用的时候将整个 JSON 缓冲区保留在内存中。实践中我们发现,通过引用 JSON 缓冲区引入的额外内存通常是解码后对象的 20% 至 80% ,一旦应用长期保留这些对象(如缓存以备重用),服务器所使用的内存可能会增加。我们提供了选项 `decoder.CopyString()` 供用户选择,不引用 JSON 缓冲区。这可能在一定程度上降低 CPU 性能。 ### 传递字符串还是字节数组? + 为了和 `encoding/json` 保持一致,我们提供了传递 `[]byte` 作为参数的 API ,但考虑到安全性,字符串到字节的复制是同时进行的,这在原始 JSON 非常大时可能会导致性能损失。因此,你可以使用 `UnmarshalString()` 和 `GetFromString()` 来传递字符串,只要你的原始数据是字符串,或**零拷贝类型转换**对于你的字节数组是安全的。我们也提供了 `MarshalString()` 的 API ,以便对编码的 JSON 字节数组进行**零拷贝类型转换**,因为 sonic 输出的字节始终是重复并且唯一的,所以这样是安全的。 ### 加速 `encoding.TextMarshaler` 为了保证数据安全性, `sonic.Encoder` 默认会对来自 `encoding.TextMarshaler` 接口的字符串进行引用和转义,如果大部分数据都是这种形式那可能会导致很大的性能损失。我们提供了 `encoder.NoQuoteTextMarshaler` 选项来跳过这些操作,但你**必须**保证他们的输出字符串依照 [RFC8259](https://datatracker.ietf.org/doc/html/rfc8259) 进行了转义和引用。 - ### 泛型的性能优化 在 **完全解析**的场景下, `Unmarshal()` 表现得比 `Get()`+`Node.Interface()` 更好。但是如果你只有特定 JSON 的部分模式,你可以将 `Get()` 和 `Unmarshal()` 结合使用: + ```go import "github.com/bytedance/sonic" @@ -398,7 +444,9 @@ node, err := sonic.GetFromString(_TwitterJson, "statuses", 3, "user") var user User // your partial schema... err = sonic.UnmarshalString(node.Raw(), &user) ``` + 甚至如果你没有任何模式,可以用 `ast.Node` 代替 `map` 或 `interface` 作为泛型的容器: + ```go import "github.com/bytedance/sonic" @@ -409,7 +457,9 @@ err = user.Check() // err = user.LoadAll() // only call this when you want to use 'user' concurrently... go someFunc(user) ``` + 为什么?因为 `ast.Node` 使用 `array` 来存储其子节点: + - 在插入(反序列化)和扫描(序列化)数据时,`Array` 的性能比 `Map` **好得多**; - **哈希**(`map[x]`)的效率不如**索引**(`array[x]`)高效,而 `ast.Node` 可以在数组和对象上使用索引; - 使用 `Interface()` / `Map()` 意味着 sonic 必须解析所有的底层值,而 `ast.Node` 可以**按需解析**它们。 @@ -417,6 +467,7 @@ go someFunc(user) **注意**:由于 `ast.Node` 的惰性加载设计,其**不能**直接保证并发安全性,但你可以调用 `Node.Load()` / `Node.LoadAll()` 来实现并发安全。尽管可能会带来性能损失,但仍比转换成 `map` 或 `interface{}` 更为高效。 ### 使用 `ast.Node` 还是 `ast.Visitor`? + 对于泛型数据的解析,`ast.Node` 在大多数场景上应该能够满足你的需求。 然而,`ast.Node` 是一种针对部分解析 JSON 而设计的泛型容器,它包含一些特殊设计,比如惰性加载,如果你希望像 `Unmarshal()` 那样直接解析整个 JSON,这些设计可能并不合适。尽管 `ast.Node` 相较于 `map` 或 `interface{}` 来说是更好的一种泛型容器,但它毕竟也是一种中间表示,如果你的最终类型是自定义的,你还得在解析完成后将上述类型转化成你自定义的类型。 @@ -425,6 +476,18 @@ go someFunc(user) 但是,`ast.Visitor` 并不是一个很易用的 API。你可能需要写大量的代码去实现自己的 `ast.Visitor`,并且需要在解析过程中仔细维护树的层级。如果你决定要使用这个 API,请先仔细阅读 [ast/visitor.go](https://github.com/bytedance/sonic/blob/main/ast/visitor.go) 中的注释。 +### 缓冲区大小 + +Sonic在许多地方使用内存池,如`encoder.Encode`, `ast.Node.MarshalJSON`等来提高性能,这可能会在服务器负载高时产生更多的内存使用(in-use)。参见[issue 614](https://github.com/bytedance/sonic/issues/614)。因此,我们引入了一些选项来让用户配置内存池的行为。参见[option](https://pkg.go.dev/github.com/bytedance/sonic@v1.11.9/option#pkg-variables)包。 + +### 更快的 JSON Skip + +为了安全起见,在跳过原始JSON 时,sonic decoder 默认使用[FSM](native/skip_one.c)算法扫描来跳过同时校验 JSON。它相比[SIMD-searching-pair](native/skip_one_fast.c)算法跳过要慢得多(1~10倍)。如果用户有很多冗余的JSON值,并且不需要严格验证JSON的正确性,你可以启用以下选项: + +- `Config.NoValidateSkipJSON`: 用于在解码时更快地跳过JSON,例如未知字段,`json.RawMessage`,不匹配的值和冗余的数组元素等 +- `Config.NoValidateJSONMarshaler`: 编码JSON时避免验证JSON。封送拆收器 +- `SearchOption.ValidateJSON`: 指示当`Get`时是否验证定位的JSON值 + ## 社区 Sonic 是 [CloudWeGo](https://www.cloudwego.io/) 下的一个子项目。我们致力于构建云原生生态系统。 diff --git a/vendor/github.com/bytedance/sonic/api.go b/vendor/github.com/bytedance/sonic/api.go index fa738f21d..af6be70a4 100644 --- a/vendor/github.com/bytedance/sonic/api.go +++ b/vendor/github.com/bytedance/sonic/api.go @@ -20,8 +20,19 @@ import ( `io` `github.com/bytedance/sonic/ast` + `github.com/bytedance/sonic/internal/rt` ) +const ( + // UseStdJSON indicates you are using fallback implementation (encoding/json) + UseStdJSON = iota + // UseSonicJSON indicates you are using real sonic implementation + UseSonicJSON +) + +// APIKind is the kind of API, 0 is std json, 1 is sonic. +const APIKind = apiKind + // Config is a combination of sonic/encoder.Options and sonic/decoder.Options type Config struct { // EscapeHTML indicates encoder to escape all HTML characters @@ -68,11 +79,25 @@ type Config struct { // ValidateString indicates decoder and encoder to valid string values: decoder will return errors // when unescaped control chars(\u0000-\u001f) in the string value of JSON. - ValidateString bool + ValidateString bool + + // NoValidateJSONMarshaler indicates that the encoder should not validate the output string + // after encoding the JSONMarshaler to JSON. + NoValidateJSONMarshaler bool + + // NoValidateJSONSkip indicates the decoder should not validate the JSON value when skipping it, + // such as unknown-fields, mismatched-type, redundant elements.. + NoValidateJSONSkip bool + + // NoEncoderNewline indicates that the encoder should not add a newline after every message + NoEncoderNewline bool + + // Encode Infinity or Nan float into `null`, instead of returning an error. + EncodeNullForInfOrNan bool } var ( - // ConfigDefault is the default config of APIs, aiming at efficiency and safty. + // ConfigDefault is the default config of APIs, aiming at efficiency and safety. ConfigDefault = Config{}.Froze() // ConfigStd is the standard config of APIs, aiming at being compatible with encoding/json. @@ -87,6 +112,8 @@ var ( // ConfigFastest is the fastest config of APIs, aiming at speed. ConfigFastest = Config{ NoQuoteTextMarshaler: true, + NoValidateJSONMarshaler: true, + NoValidateJSONSkip: true, }.Froze() ) @@ -109,7 +136,7 @@ type API interface { NewEncoder(writer io.Writer) Encoder // NewDecoder create a Decoder holding reader NewDecoder(reader io.Reader) Decoder - // Valid validates the JSON-encoded bytes and reportes if it is valid + // Valid validates the JSON-encoded bytes and reports if it is valid Valid(data []byte) bool } @@ -148,6 +175,13 @@ func Marshal(val interface{}) ([]byte, error) { return ConfigDefault.Marshal(val) } +// MarshalIndent is like Marshal but applies Indent to format the output. +// Each JSON element in the output will begin on a new line beginning with prefix +// followed by one or more copies of indent according to the indentation nesting. +func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { + return ConfigDefault.MarshalIndent(v, prefix, indent) +} + // MarshalString returns the JSON encoding string of v. func MarshalString(val interface{}) (string, error) { return ConfigDefault.MarshalToString(val) @@ -165,27 +199,49 @@ func UnmarshalString(buf string, val interface{}) error { return ConfigDefault.UnmarshalFromString(buf, val) } -// Get searches the given path from json, -// and returns its representing ast.Node. +// Get searches and locates the given path from src json, +// and returns a ast.Node representing the partially json. // // Each path arg must be integer or string: // - Integer is target index(>=0), means searching current node as array. // - String is target key, means searching current node as object. // // -// Note, the api expects the json is well-formed at least, -// otherwise it may return unexpected result. +// Notice: It expects the src json is **Well-formed** and **Immutable** when calling, +// otherwise it may return unexpected result. +// Considering memory safety, the returned JSON is **Copied** from the input func Get(src []byte, path ...interface{}) (ast.Node, error) { - return GetFromString(string(src), path...) + return GetCopyFromString(rt.Mem2Str(src), path...) } -// GetFromString is same with Get except src is string, -// which can reduce unnecessary memory copy. +//GetWithOptions searches and locates the given path from src json, +// with specific options of ast.Searcher +func GetWithOptions(src []byte, opts ast.SearchOptions, path ...interface{}) (ast.Node, error) { + s := ast.NewSearcher(rt.Mem2Str(src)) + s.SearchOptions = opts + return s.GetByPath(path...) +} + +// GetFromString is same with Get except src is string. +// +// WARNING: The returned JSON is **Referenced** from the input. +// Caching or long-time holding the returned node may cause OOM. +// If your src is big, consider use GetFromStringCopy(). func GetFromString(src string, path ...interface{}) (ast.Node, error) { return ast.NewSearcher(src).GetByPath(path...) } +// GetCopyFromString is same with Get except src is string +func GetCopyFromString(src string, path ...interface{}) (ast.Node, error) { + return ast.NewSearcher(src).GetByPathCopy(path...) +} + // Valid reports whether data is a valid JSON encoding. func Valid(data []byte) bool { return ConfigDefault.Valid(data) } + +// Valid reports whether data is a valid JSON encoding. +func ValidString(data string) bool { + return ConfigDefault.Valid(rt.Str2Mem(data)) +} diff --git a/vendor/github.com/bytedance/sonic/ast/api_amd64.go b/vendor/github.com/bytedance/sonic/ast/api.go similarity index 71% rename from vendor/github.com/bytedance/sonic/ast/api_amd64.go rename to vendor/github.com/bytedance/sonic/ast/api.go index da6738efd..7c8253aa1 100644 --- a/vendor/github.com/bytedance/sonic/ast/api_amd64.go +++ b/vendor/github.com/bytedance/sonic/ast/api.go @@ -1,4 +1,5 @@ -// +build amd64,go1.16,!go1.22 +//go:build (amd64 && go1.17 && !go1.24) || (arm64 && go1.20 && !go1.24) +// +build amd64,go1.17,!go1.24 arm64,go1.20,!go1.24 /* * Copyright 2022 ByteDance Inc. @@ -27,7 +28,7 @@ import ( `github.com/bytedance/sonic/internal/native/types` `github.com/bytedance/sonic/internal/rt` uq `github.com/bytedance/sonic/unquote` - `github.com/chenzhuoyu/base64x` + `github.com/bytedance/sonic/utf8` ) var typeByte = rt.UnpackEface(byte(0)).Type @@ -60,7 +61,7 @@ func quote(buf *[]byte, val string) { } // double buf size - *b = growslice(typeByte, *b, b.Cap*2) + *b = rt.GrowSlice(typeByte, *b, b.Cap*2) // ret is the complement of consumed input ret = ^ret // update input buffer @@ -77,14 +78,6 @@ func unquote(src string) (string, types.ParsingError) { return uq.String(src) } -func decodeBase64(src string) ([]byte, error) { - return base64x.StdEncoding.DecodeString(src) -} - -func encodeBase64(src []byte) string { - return base64x.StdEncoding.EncodeToString(src) -} - func (self *Parser) decodeValue() (val types.JsonState) { sv := (*rt.GoString)(unsafe.Pointer(&self.s)) flag := types.F_USE_NUMBER @@ -110,7 +103,7 @@ func (self *Parser) skip() (int, types.ParsingError) { func (self *Node) encodeInterface(buf *[]byte) error { //WARN: NOT compatible with json.Encoder - return encoder.EncodeInto(buf, self.packAny(), 0) + return encoder.EncodeInto(buf, self.packAny(), encoder.NoEncoderNewline) } func (self *Parser) skipFast() (int, types.ParsingError) { @@ -121,10 +114,15 @@ func (self *Parser) skipFast() (int, types.ParsingError) { return start, 0 } -func (self *Parser) getByPath(path ...interface{}) (int, types.ParsingError) { - fsm := types.NewStateMachine() +func (self *Parser) getByPath(validate bool, path ...interface{}) (int, types.ParsingError) { + var fsm *types.StateMachine + if validate { + fsm = types.NewStateMachine() + } start := native.GetByPath(&self.s, &self.p, &path, fsm) - types.FreeStateMachine(fsm) + if validate { + types.FreeStateMachine(fsm) + } runtime.KeepAlive(path) if start < 0 { return self.p, types.ParsingError(-start) @@ -132,26 +130,6 @@ func (self *Parser) getByPath(path ...interface{}) (int, types.ParsingError) { return start, 0 } -func (self *Searcher) GetByPath(path ...interface{}) (Node, error) { - var err types.ParsingError - var start int - - self.parser.p = 0 - start, err = self.parser.getByPath(path...) - if err != 0 { - // for compatibility with old version - if err == types.ERR_NOT_FOUND { - return Node{}, ErrNotExist - } - if err == types.ERR_UNSUPPORT_TYPE { - panic("path must be either int(>=0) or string") - } - return Node{}, self.parser.syntaxError(err) - } - - t := switchRawType(self.parser.s[start]) - if t == _V_NONE { - return Node{}, self.parser.ExportError(err) - } - return newRawNode(self.parser.s[start:self.parser.p], t), nil +func validate_utf8(str string) bool { + return utf8.ValidateString(str) } diff --git a/vendor/github.com/bytedance/sonic/ast/api_compat.go b/vendor/github.com/bytedance/sonic/ast/api_compat.go index 7b475eb61..a349afc0b 100644 --- a/vendor/github.com/bytedance/sonic/ast/api_compat.go +++ b/vendor/github.com/bytedance/sonic/ast/api_compat.go @@ -1,40 +1,40 @@ -// +build !amd64 !go1.16 go1.22 +// +build !amd64,!arm64 go1.24 !go1.17 arm64,!go1.20 /* - * Copyright 2022 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. - */ +* Copyright 2022 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 ast import ( - `encoding/base64` `encoding/json` - `fmt` + `unicode/utf8` `github.com/bytedance/sonic/internal/native/types` `github.com/bytedance/sonic/internal/rt` ) func init() { - println("WARNING: sonic only supports Go1.16~1.20 && CPU amd64, but your environment is not suitable") + println("WARNING:(ast) sonic only supports go1.17~1.23, but your environment is not suitable") } func quote(buf *[]byte, val string) { quoteString(buf, val) } +// unquote unescapes a internal JSON string (it doesn't count quotas at the begining and end) func unquote(src string) (string, types.ParsingError) { sp := rt.IndexChar(src, -1) out, ok := unquoteBytes(rt.BytesFrom(sp, len(src)+2, len(src)+2)) @@ -44,13 +44,6 @@ func unquote(src string) (string, types.ParsingError) { return rt.Mem2Str(out), 0 } -func decodeBase64(src string) ([]byte, error) { - return base64.StdEncoding.DecodeString(src) -} - -func encodeBase64(src []byte) string { - return base64.StdEncoding.EncodeToString(src) -} func (self *Parser) decodeValue() (val types.JsonState) { e, v := decodeValue(self.s, self.p, self.dbuf == nil) @@ -88,37 +81,34 @@ func (self *Node) encodeInterface(buf *[]byte) error { return nil } -func (self *Searcher) GetByPath(path ...interface{}) (Node, error) { - self.parser.p = 0 - - var err types.ParsingError +func (self *Parser) getByPath(validate bool, path ...interface{}) (int, types.ParsingError) { for _, p := range path { if idx, ok := p.(int); ok && idx >= 0 { - if err = self.parser.searchIndex(idx); err != 0 { - return Node{}, self.parser.ExportError(err) + if err := self.searchIndex(idx); err != 0 { + return self.p, err } } else if key, ok := p.(string); ok { - if err = self.parser.searchKey(key); err != 0 { - return Node{}, self.parser.ExportError(err) + if err := self.searchKey(key); err != 0 { + return self.p, err } } else { panic("path must be either int(>=0) or string") } } - var start = self.parser.p - if start, err = self.parser.skip(); err != 0 { - return Node{}, self.parser.ExportError(err) + var start int + var e types.ParsingError + if validate { + start, e = self.skip() + } else { + start, e = self.skipFast() } - ns := len(self.parser.s) - if self.parser.p > ns || start >= ns || start>=self.parser.p { - return Node{}, fmt.Errorf("skip %d char out of json boundary", start) - } - - t := switchRawType(self.parser.s[start]) - if t == _V_NONE { - return Node{}, self.parser.ExportError(err) + if e != 0 { + return self.p, e } + return start, 0 +} - return newRawNode(self.parser.s[start:self.parser.p], t), nil -} \ No newline at end of file +func validate_utf8(str string) bool { + return utf8.ValidString(str) +} diff --git a/vendor/github.com/bytedance/sonic/ast/buffer.go b/vendor/github.com/bytedance/sonic/ast/buffer.go index 93f4ff47a..04701ef5b 100644 --- a/vendor/github.com/bytedance/sonic/ast/buffer.go +++ b/vendor/github.com/bytedance/sonic/ast/buffer.go @@ -17,8 +17,10 @@ package ast import ( - `sort` - `unsafe` + "sort" + "unsafe" + + "github.com/bytedance/sonic/internal/caching" ) type nodeChunk [_DEFAULT_NODE_CAP]Node @@ -58,29 +60,82 @@ func (self *linkedNodes) At(i int) (*Node) { return nil } -func (self *linkedNodes) Add(v Node) { - if self.size < _DEFAULT_NODE_CAP { - self.head[self.size] = v - self.size++ +func (self *linkedNodes) MoveOne(source int, target int) { + if source == target { + return + } + if source < 0 || source >= self.size || target < 0 || target >= self.size { + return + } + // reserve source + n := *self.At(source) + if source < target { + // move every element (source,target] one step back + for i:=source; itarget; i-- { + *self.At(i) = *self.At(i-1) + } + } + // set target + *self.At(target) = n +} + +func (self *linkedNodes) Pop() { + if self == nil || self.size == 0 { + return + } + self.Set(self.size-1, Node{}) + self.size-- +} + +func (self *linkedNodes) Push(v Node) { + self.Set(self.size, v) +} + + +func (self *linkedNodes) Set(i int, v Node) { + if i < _DEFAULT_NODE_CAP { + self.head[i] = v + if self.size <= i { + self.size = i+1 + } return } + a, b := i/_DEFAULT_NODE_CAP-1, i%_DEFAULT_NODE_CAP + if a < 0 { + self.head[b] = v + } else { + self.growTailLength(a+1) + var n = &self.tail[a] + if *n == nil { + *n = new(nodeChunk) + } + (*n)[b] = v + } + if self.size <= i { + self.size = i+1 + } +} - a, b, c := self.size/_DEFAULT_NODE_CAP-1 , self.size%_DEFAULT_NODE_CAP, cap(self.tail) - if a - c >= 0 { +func (self *linkedNodes) growTailLength(l int) { + if l <= len(self.tail) { + return + } + c := cap(self.tail) + for c < l { c += 1 + c>>_APPEND_GROW_SHIFT - tmp := make([]*nodeChunk, a + 1, c) - copy(tmp, self.tail) - self.tail = tmp - } else if a >= len(self.tail) { - self.tail = self.tail[:a+1] } - - var n = &self.tail[a] - if *n == nil { - *n = new(nodeChunk) + if c == cap(self.tail) { + self.tail = self.tail[:l] + return } - (*n)[b] = v - self.size++ + tmp := make([]*nodeChunk, l, c) + copy(tmp, self.tail) + self.tail = tmp } func (self *linkedNodes) ToSlice(con []Node) { @@ -135,11 +190,22 @@ func (self *linkedNodes) FromSlice(con []Node) { type pairChunk [_DEFAULT_NODE_CAP]Pair type linkedPairs struct { + index map[uint64]int head pairChunk tail []*pairChunk size int } +func (self *linkedPairs) BuildIndex() { + if self.index == nil { + self.index = make(map[uint64]int, self.size) + } + for i:=0; i= 0 { - c += 1 + c>>_APPEND_GROW_SHIFT - tmp := make([]*pairChunk, a + 1, c) - copy(tmp, self.tail) - self.tail = tmp - } else if a >= len(self.tail) { - self.tail = self.tail[:a+1] +func (self *linkedPairs) Unset(i int) { + if self.index != nil { + p := self.At(i) + delete(self.index, p.hash) } + self.set(i, Pair{}) +} - var n = &self.tail[a] - if *n == nil { - *n = new(pairChunk) +func (self *linkedPairs) Set(i int, v Pair) { + if self.index != nil { + h := v.hash + self.index[h] = i } - (*n)[b] = v - self.size++ + self.set(i, v) +} + +func (self *linkedPairs) set(i int, v Pair) { + if i < _DEFAULT_NODE_CAP { + self.head[i] = v + if self.size <= i { + self.size = i+1 + } + return + } + a, b := i/_DEFAULT_NODE_CAP-1, i%_DEFAULT_NODE_CAP + if a < 0 { + self.head[b] = v + } else { + self.growTailLength(a+1) + var n = &self.tail[a] + if *n == nil { + *n = new(pairChunk) + } + (*n)[b] = v + } + if self.size <= i { + self.size = i+1 + } +} + +func (self *linkedPairs) growTailLength(l int) { + if l <= len(self.tail) { + return + } + c := cap(self.tail) + for c < l { + c += 1 + c>>_APPEND_GROW_SHIFT + } + if c == cap(self.tail) { + self.tail = self.tail[:l] + return + } + tmp := make([]*pairChunk, l, c) + copy(tmp, self.tail) + self.tail = tmp } // linear search func (self *linkedPairs) Get(key string) (*Pair, int) { + if self.index != nil { + // fast-path + i, ok := self.index[caching.StrHash(key)] + if ok { + n := self.At(i) + if n.Key == key { + return n, i + } + // hash conflicts + goto linear_search + } else { + return nil, -1 + } + } +linear_search: for i:=0; i len(src) { return -int(types.ERR_EOF) } - if src[pos:ret] == bytesNull { + if src[pos:ret] == strNull { return ret } else { return -int(types.ERR_INVALID_CHAR) @@ -583,3 +586,36 @@ func skipArray(src string, pos int) (ret int, start int) { pos++ } } + +// DecodeString decodes a JSON string from pos and return golang string. +// - needEsc indicates if to unescaped escaping chars +// - hasEsc tells if the returned string has escaping chars +// - validStr enables validating UTF8 charset +// +func _DecodeString(src string, pos int, needEsc bool, validStr bool) (v string, ret int, hasEsc bool) { + p := NewParserObj(src) + p.p = pos + switch val := p.decodeValue(); val.Vt { + case types.V_STRING: + str := p.s[val.Iv : p.p-1] + if validStr && !validate_utf8(str) { + return "", -int(types.ERR_INVALID_UTF8), false + } + /* fast path: no escape sequence */ + if val.Ep == -1 { + return str, p.p, false + } else if !needEsc { + return str, p.p, true + } + /* unquote the string */ + out, err := unquote(str) + /* check for errors */ + if err != 0 { + return "", -int(err), true + } else { + return out, p.p, true + } + default: + return "", -int(_ERR_UNSUPPORT_TYPE), false + } +} diff --git a/vendor/github.com/bytedance/sonic/ast/encode.go b/vendor/github.com/bytedance/sonic/ast/encode.go index 263ae5a9d..eae0bd258 100644 --- a/vendor/github.com/bytedance/sonic/ast/encode.go +++ b/vendor/github.com/bytedance/sonic/ast/encode.go @@ -17,12 +17,11 @@ package ast import ( - `sync` - `unicode/utf8` -) + "sync" + "unicode/utf8" -const ( - _MaxBuffer = 1024 // 1KB buffer size + "github.com/bytedance/sonic/internal/rt" + "github.com/bytedance/sonic/option" ) func quoteString(e *[]byte, s string) { @@ -30,7 +29,7 @@ func quoteString(e *[]byte, s string) { start := 0 for i := 0; i < len(s); { if b := s[i]; b < utf8.RuneSelf { - if safeSet[b] { + if rt.SafeSet[b] { i++ continue } @@ -54,8 +53,8 @@ func quoteString(e *[]byte, s string) { // user-controlled strings are rendered into JSON // and served to some browsers. *e = append(*e, `u00`...) - *e = append(*e, hex[b>>4]) - *e = append(*e, hex[b&0xF]) + *e = append(*e, rt.Hex[b>>4]) + *e = append(*e, rt.Hex[b&0xF]) } i++ start = i @@ -76,7 +75,7 @@ func quoteString(e *[]byte, s string) { *e = append(*e, s[start:i]...) } *e = append(*e, `\u202`...) - *e = append(*e, hex[c&0xF]) + *e = append(*e, rt.Hex[c&0xF]) i += size start = i continue @@ -92,16 +91,24 @@ func quoteString(e *[]byte, s string) { var bytesPool = sync.Pool{} func (self *Node) MarshalJSON() ([]byte, error) { + if self == nil { + return bytesNull, nil + } + buf := newBuffer() err := self.encode(buf) if err != nil { freeBuffer(buf) return nil, err } - - ret := make([]byte, len(*buf)) - copy(ret, *buf) - freeBuffer(buf) + var ret []byte + if !rt.CanSizeResue(cap(*buf)) { + ret = *buf + } else { + ret = make([]byte, len(*buf)) + copy(ret, *buf) + freeBuffer(buf) + } return ret, err } @@ -109,21 +116,24 @@ func newBuffer() *[]byte { if ret := bytesPool.Get(); ret != nil { return ret.(*[]byte) } else { - buf := make([]byte, 0, _MaxBuffer) + buf := make([]byte, 0, option.DefaultAstBufferSize) return &buf } } func freeBuffer(buf *[]byte) { + if !rt.CanSizeResue(cap(*buf)) { + return + } *buf = (*buf)[:0] bytesPool.Put(buf) } func (self *Node) encode(buf *[]byte) error { - if self.IsRaw() { + if self.isRaw() { return self.encodeRaw(buf) } - switch self.Type() { + switch int(self.itype()) { case V_NONE : return ErrNotExist case V_ERROR : return self.Check() case V_NULL : return self.encodeNull(buf) @@ -139,16 +149,21 @@ func (self *Node) encode(buf *[]byte) error { } func (self *Node) encodeRaw(buf *[]byte) error { - raw, err := self.Raw() - if err != nil { - return err + lock := self.rlock() + if !self.isRaw() { + self.runlock() + return self.encode(buf) + } + raw := self.toString() + if lock { + self.runlock() } *buf = append(*buf, raw...) return nil } func (self *Node) encodeNull(buf *[]byte) error { - *buf = append(*buf, bytesNull...) + *buf = append(*buf, strNull...) return nil } @@ -193,20 +208,9 @@ func (self *Node) encodeArray(buf *[]byte) error { *buf = append(*buf, '[') - var s = (*linkedNodes)(self.p) var started bool - if nb > 0 { - n := s.At(0) - if n.Exists() { - if err := n.encode(buf); err != nil { - return err - } - started = true - } - } - - for i := 1; i < nb; i++ { - n := s.At(i) + for i := 0; i < nb; i++ { + n := self.nodeAt(i) if !n.Exists() { continue } @@ -250,21 +254,10 @@ func (self *Node) encodeObject(buf *[]byte) error { *buf = append(*buf, '{') - var s = (*linkedPairs)(self.p) var started bool - if nb > 0 { - n := s.At(0) - if n.Value.Exists() { - if err := n.encode(buf); err != nil { - return err - } - started = true - } - } - - for i := 1; i < nb; i++ { - n := s.At(i) - if !n.Value.Exists() { + for i := 0; i < nb; i++ { + n := self.pairAt(i) + if n == nil || !n.Value.Exists() { continue } if started { diff --git a/vendor/github.com/bytedance/sonic/ast/error.go b/vendor/github.com/bytedance/sonic/ast/error.go index 00a04468e..3716e7a91 100644 --- a/vendor/github.com/bytedance/sonic/ast/error.go +++ b/vendor/github.com/bytedance/sonic/ast/error.go @@ -17,6 +17,10 @@ func newError(err types.ParsingError, msg string) *Node { } } +func newErrorPair(err SyntaxError) *Pair { + return &Pair{0, "", *newSyntaxError(err)} +} + // Error returns error message if the node is invalid func (self Node) Error() string { if self.t != V_ERROR { @@ -79,7 +83,7 @@ func (self SyntaxError) description() string { /* check for empty source */ if self.Src == "" { - return fmt.Sprintf("no sources available: %#v", self) + return fmt.Sprintf("no sources available, the input json is empty: %#v", self) } /* prevent slicing before the beginning */ diff --git a/vendor/github.com/bytedance/sonic/ast/iterator.go b/vendor/github.com/bytedance/sonic/ast/iterator.go index 3c4187a9c..076647154 100644 --- a/vendor/github.com/bytedance/sonic/ast/iterator.go +++ b/vendor/github.com/bytedance/sonic/ast/iterator.go @@ -17,30 +17,48 @@ package ast import ( - `fmt` + "fmt" - `github.com/bytedance/sonic/internal/native/types` + "github.com/bytedance/sonic/internal/caching" + "github.com/bytedance/sonic/internal/native/types" ) type Pair struct { + hash uint64 Key string Value Node } +func NewPair(key string, val Node) Pair { + return Pair{ + hash: caching.StrHash(key), + Key: key, + Value: val, + } +} + // Values returns iterator for array's children traversal func (self *Node) Values() (ListIterator, error) { - if err := self.should(types.V_ARRAY, "an array"); err != nil { + if err := self.should(types.V_ARRAY); err != nil { return ListIterator{}, err } - return ListIterator{Iterator{p: self}}, nil + return self.values(), nil +} + +func (self *Node) values() ListIterator { + return ListIterator{Iterator{p: self}} } // Properties returns iterator for object's children traversal func (self *Node) Properties() (ObjectIterator, error) { - if err := self.should(types.V_OBJECT, "an object"); err != nil { + if err := self.should(types.V_OBJECT); err != nil { return ObjectIterator{}, err } - return ObjectIterator{Iterator{p: self}}, nil + return self.properties(), nil +} + +func (self *Node) properties() ObjectIterator { + return ObjectIterator{Iterator{p: self}} } type Iterator struct { @@ -114,7 +132,7 @@ next_start: } else { n := self.p.pairAt(self.i) self.i++ - if !n.Value.Exists() { + if n == nil || !n.Value.Exists() { goto next_start } return n @@ -160,6 +178,9 @@ type Scanner func(path Sequence, node *Node) bool // // NOTICE: A unsetted node WON'T trigger sc, but its index still counts into Path.Index func (self *Node) ForEach(sc Scanner) error { + if err := self.checkRaw(); err != nil { + return err + } switch self.itype() { case types.V_ARRAY: iter, err := self.Values() diff --git a/vendor/github.com/bytedance/sonic/ast/node.go b/vendor/github.com/bytedance/sonic/ast/node.go index 444c8fe42..0fbcf7835 100644 --- a/vendor/github.com/bytedance/sonic/ast/node.go +++ b/vendor/github.com/bytedance/sonic/ast/node.go @@ -17,22 +17,15 @@ package ast import ( - `encoding/json` - `fmt` - `strconv` - `unsafe` - `reflect` - - `github.com/bytedance/sonic/internal/native/types` - `github.com/bytedance/sonic/internal/rt` -) - -const ( - _CAP_BITS = 32 - _LEN_MASK = 1 << _CAP_BITS - 1 - - _NODE_SIZE = unsafe.Sizeof(Node{}) - _PAIR_SIZE = unsafe.Sizeof(Pair{}) + "encoding/json" + "fmt" + "strconv" + "sync" + "sync/atomic" + "unsafe" + + "github.com/bytedance/sonic/internal/native/types" + "github.com/bytedance/sonic/internal/rt" ) const ( @@ -45,7 +38,7 @@ const ( _V_ARRAY_LAZY = _V_LAZY | types.V_ARRAY _V_OBJECT_LAZY = _V_LAZY | types.V_OBJECT _MASK_LAZY = _V_LAZY - 1 - _MASK_RAW = _V_RAW - 1 + _MASK_RAW = _V_RAW - 1 ) const ( @@ -61,21 +54,18 @@ const ( V_ANY = int(_V_ANY) ) -var ( - byteType = rt.UnpackType(reflect.TypeOf(byte(0))) -) - type Node struct { t types.ValueType l uint p unsafe.Pointer + m *sync.RWMutex } // UnmarshalJSON is just an adapter to json.Unmarshaler. // If you want better performance, use Searcher.GetByPath() directly func (self *Node) UnmarshalJSON(data []byte) (err error) { - *self, err = NewSearcher(string(data)).GetByPath() - return + *self = NewRaw(string(data)) + return self.Check() } /** Node Type Accessor **/ @@ -92,17 +82,39 @@ func (self *Node) UnmarshalJSON(data []byte) (err error) { // V_STRING = 7 (json value string) // V_NUMBER = 33 (json value number ) // V_ANY = 34 (golang interface{}) +// +// Deprecated: not concurrent safe. Use TypeSafe instead func (self Node) Type() int { return int(self.t & _MASK_LAZY & _MASK_RAW) } -func (self Node) itype() types.ValueType { +// Type concurrently-safe returns json type represented by the node +// It will be one of belows: +// V_NONE = 0 (empty node, key not exists) +// V_ERROR = 1 (error node) +// V_NULL = 2 (json value `null`, key exists) +// V_TRUE = 3 (json value `true`) +// V_FALSE = 4 (json value `false`) +// V_ARRAY = 5 (json value array) +// V_OBJECT = 6 (json value object) +// V_STRING = 7 (json value string) +// V_NUMBER = 33 (json value number ) +// V_ANY = 34 (golang interface{}) +func (self *Node) TypeSafe() int { + return int(self.loadt() & _MASK_LAZY & _MASK_RAW) +} + +func (self *Node) itype() types.ValueType { return self.t & _MASK_LAZY & _MASK_RAW } // Exists returns false only if the self is nil or empty node V_NONE func (self *Node) Exists() bool { - return self.Valid() && self.t != _V_NONE + if self == nil { + return false + } + t := self.loadt() + return t != V_ERROR && t != _V_NONE } // Valid reports if self is NOT V_ERROR or nil @@ -110,7 +122,7 @@ func (self *Node) Valid() bool { if self == nil { return false } - return self.t != V_ERROR + return self.loadt() != V_ERROR } // Check checks if the node itself is valid, and return: @@ -119,45 +131,63 @@ func (self *Node) Valid() bool { func (self *Node) Check() error { if self == nil { return ErrNotExist - } else if self.t != V_ERROR { + } else if self.loadt() != V_ERROR { return nil } else { return self } } -// IsRaw returns true if node's underlying value is raw json +// isRaw returns true if node's underlying value is raw json +// +// Deprecated: not concurent safe func (self Node) IsRaw() bool { - return self.t&_V_RAW != 0 + return self.t & _V_RAW != 0 +} + +// IsRaw returns true if node's underlying value is raw json +func (self *Node) isRaw() bool { + return self.loadt() & _V_RAW != 0 } func (self *Node) isLazy() bool { - return self != nil && self.t&_V_LAZY != 0 + return self != nil && self.t & _V_LAZY != 0 } func (self *Node) isAny() bool { - return self != nil && self.t == _V_ANY + return self != nil && self.loadt() == _V_ANY } /** Simple Value Methods **/ // Raw returns json representation of the node, func (self *Node) Raw() (string, error) { - if !self.IsRaw() { + if self == nil { + return "", ErrNotExist + } + lock := self.rlock() + if !self.isRaw() { + if lock { + self.runlock() + } buf, err := self.MarshalJSON() return rt.Mem2Str(buf), err } - return self.toString(), nil + ret := self.toString() + if lock { + self.runlock() + } + return ret, nil } func (self *Node) checkRaw() error { if err := self.Check(); err != nil { return err } - if self.IsRaw() { + if self.isRaw() { self.parseRaw(false) } - return nil + return self.Check() } // Bool returns bool value represented by this node, @@ -501,7 +531,6 @@ func (self *Node) StrictFloat64() (float64, error) { // Len returns children count of a array|object|string node // WARN: For partially loaded node, it also works but only counts the parsed children -// WARN: For ARRAY|OBJECT nodes which has been conducted `UnsetXX()`, its length WON'T change func (self *Node) Len() (int, error) { if err := self.checkRaw(); err != nil { return 0, err @@ -515,7 +544,7 @@ func (self *Node) Len() (int, error) { } } -func (self Node) len() int { +func (self *Node) len() int { return int(self.l) } @@ -538,14 +567,19 @@ func (self *Node) Cap() (int, error) { // // If self is V_NONE or V_NULL, it becomes V_OBJECT and sets the node at the key. func (self *Node) Set(key string, node Node) (bool, error) { - if self != nil && (self.t == _V_NONE || self.t == types.V_NULL) { - *self = NewObject([]Pair{{key, node}}) - return false, nil + if err := self.checkRaw(); err != nil { + return false, err } - if err := node.Check(); err != nil { return false, err } + + if self.t == _V_NONE || self.t == types.V_NULL { + *self = NewObject([]Pair{NewPair(key, node)}) + return false, nil + } else if self.itype() != types.V_OBJECT { + return false, ErrUnsupportType + } p := self.Get(key) @@ -555,7 +589,7 @@ func (self *Node) Set(key string, node Node) (bool, error) { *self = newObject(new(linkedPairs)) } s := (*linkedPairs)(self.p) - s.Add(Pair{key, node}) + s.Push(NewPair(key, node)) self.l++ return false, nil @@ -572,18 +606,22 @@ func (self *Node) SetAny(key string, val interface{}) (bool, error) { return self.Set(key, NewAny(val)) } -// Unset RESET the node of given key under object parent, and reports if the key has existed. -// WARN: After conducting `UnsetXX()`, the node's length WON'T change +// Unset REMOVE (soft) the node of given key under object parent, and reports if the key has existed. func (self *Node) Unset(key string) (bool, error) { - self.must(types.V_OBJECT, "an object") + if err := self.should(types.V_OBJECT); err != nil { + return false, err + } + // NOTICE: must get acurate length before deduct + if err := self.skipAllKey(); err != nil { + return false, err + } p, i := self.skipKey(key) if !p.Exists() { return false, nil } else if err := p.Check(); err != nil { return false, err } - - self.removePair(i) + self.removePairAt(i) return true, nil } @@ -591,10 +629,18 @@ func (self *Node) Unset(key string) (bool, error) { // // The index must be within self's children. func (self *Node) SetByIndex(index int, node Node) (bool, error) { + if err := self.checkRaw(); err != nil { + return false, err + } if err := node.Check(); err != nil { return false, err } + if index == 0 && (self.t == _V_NONE || self.t == types.V_NULL) { + *self = NewArray([]Node{node}) + return false, nil + } + p := self.Index(index) if !p.Exists() { return false, ErrNotExist @@ -611,18 +657,28 @@ func (self *Node) SetAnyByIndex(index int, val interface{}) (bool, error) { return self.SetByIndex(index, NewAny(val)) } -// UnsetByIndex remove the node of given index -// WARN: After conducting `UnsetXX()`, the node's length WON'T change +// UnsetByIndex REOMVE (softly) the node of given index. +// +// WARN: this will change address of elements, which is a dangerous action. +// Use Unset() for object or Pop() for array instead. func (self *Node) UnsetByIndex(index int) (bool, error) { + if err := self.checkRaw(); err != nil { + return false, err + } + var p *Node it := self.itype() + if it == types.V_ARRAY { - p = self.Index(index) - }else if it == types.V_OBJECT { - if err := self.checkRaw(); err != nil { + if err := self.skipAllIndex(); err != nil { + return false, err + } + p = self.nodeAt(index) + } else if it == types.V_OBJECT { + if err := self.skipAllKey(); err != nil { return false, err } - pr := self.skipIndexPair(index) + pr := self.pairAt(index) if pr == nil { return false, ErrNotExist } @@ -635,6 +691,12 @@ func (self *Node) UnsetByIndex(index int) (bool, error) { return false, ErrNotExist } + // last elem + if index == self.len() - 1 { + return true, self.Pop() + } + + // not last elem, self.len() change but linked-chunk not change if it == types.V_ARRAY { self.removeNode(index) }else if it == types.V_OBJECT { @@ -647,21 +709,112 @@ func (self *Node) UnsetByIndex(index int) (bool, error) { // // If self is V_NONE or V_NULL, it becomes V_ARRAY and sets the node at index 0. func (self *Node) Add(node Node) error { + if err := self.checkRaw(); err != nil { + return err + } + if self != nil && (self.t == _V_NONE || self.t == types.V_NULL) { *self = NewArray([]Node{node}) return nil } + if err := self.should(types.V_ARRAY); err != nil { + return err + } s, err := self.unsafeArray() if err != nil { return err } - s.Add(node) + // Notice: array won't have unset node in tail + s.Push(node) self.l++ return nil } +// Pop remove the last child of the V_Array or V_Object node. +func (self *Node) Pop() error { + if err := self.checkRaw(); err != nil { + return err + } + + if it := self.itype(); it == types.V_ARRAY { + s, err := self.unsafeArray() + if err != nil { + return err + } + // remove tail unset nodes + for i := s.Len()-1; i >= 0; i-- { + if s.At(i).Exists() { + s.Pop() + self.l-- + break + } + s.Pop() + } + + } else if it == types.V_OBJECT { + s, err := self.unsafeMap() + if err != nil { + return err + } + // remove tail unset nodes + for i := s.Len()-1; i >= 0; i-- { + if p := s.At(i); p != nil && p.Value.Exists() { + s.Pop() + self.l-- + break + } + s.Pop() + } + + } else { + return ErrUnsupportType + } + + return nil +} + +// Move moves the child at src index to dst index, +// meanwhile slides sliblings from src+1 to dst. +// +// WARN: this will change address of elements, which is a dangerous action. +func (self *Node) Move(dst, src int) error { + if err := self.should(types.V_ARRAY); err != nil { + return err + } + + s, err := self.unsafeArray() + if err != nil { + return err + } + + // check if any unset node exists + if l := s.Len(); self.len() != l { + di, si := dst, src + // find real pos of src and dst + for i := 0; i < l; i++ { + if s.At(i).Exists() { + di-- + si-- + } + if di == -1 { + dst = i + di-- + } + if si == -1 { + src = i + si-- + } + if di == -2 && si == -2 { + break + } + } + } + + s.MoveOne(src, dst) + return nil +} // SetAny wraps val with V_ANY node, and Add() the node. func (self *Node) AddAny(val interface{}) error { @@ -699,7 +852,7 @@ func (self *Node) GetByPath(path ...interface{}) *Node { // Get loads given key of an object node on demands func (self *Node) Get(key string) *Node { - if err := self.should(types.V_OBJECT, "an object"); err != nil { + if err := self.should(types.V_OBJECT); err != nil { return unwrapError(err) } n, _ := self.skipKey(key) @@ -708,8 +861,6 @@ func (self *Node) Get(key string) *Node { // Index indexies node at given idx, // node type CAN be either V_OBJECT or V_ARRAY -// WARN: After conducting `UnsetXX()`, the node's length WON'T change, -// thus its children's indexing WON'T change too func (self *Node) Index(idx int) *Node { if err := self.checkRaw(); err != nil { return unwrapError(err) @@ -733,28 +884,37 @@ func (self *Node) Index(idx int) *Node { // IndexPair indexies pair at given idx, // node type MUST be either V_OBJECT -// WARN: After conducting `UnsetXX()`, the node's length WON'T change, -// thus its children's indexing WON'T change too func (self *Node) IndexPair(idx int) *Pair { - if err := self.should(types.V_OBJECT, "an object"); err != nil { + if err := self.should(types.V_OBJECT); err != nil { return nil } return self.skipIndexPair(idx) } -// IndexOrGet firstly use idx to index a value and check if its key matches -// If not, then use the key to search value -func (self *Node) IndexOrGet(idx int, key string) *Node { - if err := self.should(types.V_OBJECT, "an object"); err != nil { - return unwrapError(err) +func (self *Node) indexOrGet(idx int, key string) (*Node, int) { + if err := self.should(types.V_OBJECT); err != nil { + return unwrapError(err), idx } pr := self.skipIndexPair(idx) if pr != nil && pr.Key == key { - return &pr.Value + return &pr.Value, idx } - n, _ := self.skipKey(key) - return n + + return self.skipKey(key) +} + +// IndexOrGet firstly use idx to index a value and check if its key matches +// If not, then use the key to search value +func (self *Node) IndexOrGet(idx int, key string) *Node { + node, _ := self.indexOrGet(idx, key) + return node +} + +// IndexOrGetWithIdx attempts to retrieve a node by index and key, returning the node and its correct index. +// If the key does not match at the given index, it searches by key and returns the node with its updated index. +func (self *Node) IndexOrGetWithIdx(idx int, key string) (*Node, int) { + return self.indexOrGet(idx, key) } /** Generic Value Converters **/ @@ -769,10 +929,10 @@ func (self *Node) Map() (map[string]interface{}, error) { return nil, ErrUnsupportType } } - if err := self.should(types.V_OBJECT, "an object"); err != nil { + if err := self.should(types.V_OBJECT); err != nil { return nil, err } - if err := self.loadAllKey(); err != nil { + if err := self.loadAllKey(false); err != nil { return nil, err } return self.toGenericObject() @@ -788,10 +948,10 @@ func (self *Node) MapUseNumber() (map[string]interface{}, error) { return nil, ErrUnsupportType } } - if err := self.should(types.V_OBJECT, "an object"); err != nil { + if err := self.should(types.V_OBJECT); err != nil { return nil, err } - if err := self.loadAllKey(); err != nil { + if err := self.loadAllKey(false); err != nil { return nil, err } return self.toGenericObjectUseNumber() @@ -808,7 +968,7 @@ func (self *Node) MapUseNode() (map[string]Node, error) { return nil, ErrUnsupportType } } - if err := self.should(types.V_OBJECT, "an object"); err != nil { + if err := self.should(types.V_OBJECT); err != nil { return nil, err } if err := self.skipAllKey(); err != nil { @@ -831,10 +991,8 @@ func (self *Node) MapUseNode() (map[string]Node, error) { // return self.toGenericObjectUsePair() // } +//go:nocheckptr func (self *Node) unsafeMap() (*linkedPairs, error) { - if err := self.should(types.V_OBJECT, "an object"); err != nil { - return nil, err - } if err := self.skipAllKey(); err != nil { return nil, err } @@ -846,7 +1004,39 @@ func (self *Node) unsafeMap() (*linkedPairs, error) { // SortKeys sorts children of a V_OBJECT node in ascending key-order. // If recurse is true, it recursively sorts children's children as long as a V_OBJECT node is found. -func (self *Node) SortKeys(recurse bool) (err error) { +func (self *Node) SortKeys(recurse bool) error { + // check raw node first + if err := self.checkRaw(); err != nil { + return err + } + if self.itype() == types.V_OBJECT { + return self.sortKeys(recurse) + } else if self.itype() == types.V_ARRAY { + var err error + err2 := self.ForEach(func(path Sequence, node *Node) bool { + it := node.itype() + if it == types.V_ARRAY || it == types.V_OBJECT { + err = node.SortKeys(recurse) + if err != nil { + return false + } + } + return true + }) + if err != nil { + return err + } + return err2 + } else { + return nil + } +} + +func (self *Node) sortKeys(recurse bool) (err error) { + // check raw node first + if err := self.checkRaw(); err != nil { + return err + } ps, err := self.unsafeMap() if err != nil { return err @@ -856,7 +1046,7 @@ func (self *Node) SortKeys(recurse bool) (err error) { var sc Scanner sc = func(path Sequence, node *Node) bool { if node.itype() == types.V_OBJECT { - if err := node.SortKeys(recurse); err != nil { + if err := node.sortKeys(recurse); err != nil { return false } } @@ -867,7 +1057,9 @@ func (self *Node) SortKeys(recurse bool) (err error) { } return true } - self.ForEach(sc) + if err := self.ForEach(sc); err != nil { + return err + } } return nil } @@ -882,10 +1074,10 @@ func (self *Node) Array() ([]interface{}, error) { return nil, ErrUnsupportType } } - if err := self.should(types.V_ARRAY, "an array"); err != nil { + if err := self.should(types.V_ARRAY); err != nil { return nil, err } - if err := self.loadAllIndex(); err != nil { + if err := self.loadAllIndex(false); err != nil { return nil, err } return self.toGenericArray() @@ -901,10 +1093,10 @@ func (self *Node) ArrayUseNumber() ([]interface{}, error) { return nil, ErrUnsupportType } } - if err := self.should(types.V_ARRAY, "an array"); err != nil { + if err := self.should(types.V_ARRAY); err != nil { return nil, err } - if err := self.loadAllIndex(); err != nil { + if err := self.loadAllIndex(false); err != nil { return nil, err } return self.toGenericArrayUseNumber() @@ -921,7 +1113,7 @@ func (self *Node) ArrayUseNode() ([]Node, error) { return nil, ErrUnsupportType } } - if err := self.should(types.V_ARRAY, "an array"); err != nil { + if err := self.should(types.V_ARRAY); err != nil { return nil, err } if err := self.skipAllIndex(); err != nil { @@ -946,9 +1138,6 @@ func (self *Node) ArrayUseNode() ([]Node, error) { // } func (self *Node) unsafeArray() (*linkedNodes, error) { - if err := self.should(types.V_ARRAY, "an array"); err != nil { - return nil, err - } if err := self.skipAllIndex(); err != nil { return nil, err } @@ -980,12 +1169,12 @@ func (self *Node) Interface() (interface{}, error) { } return v, nil case _V_ARRAY_LAZY : - if err := self.loadAllIndex(); err != nil { + if err := self.loadAllIndex(false); err != nil { return nil, err } return self.toGenericArray() case _V_OBJECT_LAZY : - if err := self.loadAllKey(); err != nil { + if err := self.loadAllKey(false); err != nil { return nil, err } return self.toGenericObject() @@ -1019,12 +1208,12 @@ func (self *Node) InterfaceUseNumber() (interface{}, error) { case types.V_STRING : return self.toString(), nil case _V_NUMBER : return self.toNumber(), nil case _V_ARRAY_LAZY : - if err := self.loadAllIndex(); err != nil { + if err := self.loadAllIndex(false); err != nil { return nil, err } return self.toGenericArrayUseNumber() case _V_OBJECT_LAZY : - if err := self.loadAllKey(); err != nil { + if err := self.loadAllKey(false); err != nil { return nil, err } return self.toGenericObjectUseNumber() @@ -1056,105 +1245,30 @@ func (self *Node) InterfaceUseNode() (interface{}, error) { } } -// LoadAll loads all the node's children and children's children as parsed. -// After calling it, the node can be safely used on concurrency +// LoadAll loads the node's children +// and ensure all its children can be READ concurrently (include its children's children) func (self *Node) LoadAll() error { - if self.IsRaw() { - self.parseRaw(true) - return self.Check() - } - - switch self.itype() { - case types.V_ARRAY: - e := self.len() - if err := self.loadAllIndex(); err != nil { - return err - } - for i := 0; i < e; i++ { - n := self.nodeAt(i) - if n.IsRaw() { - n.parseRaw(true) - } - if err := n.Check(); err != nil { - return err - } - } - return nil - case types.V_OBJECT: - e := self.len() - if err := self.loadAllKey(); err != nil { - return err - } - for i := 0; i < e; i++ { - n := self.pairAt(i) - if n.Value.IsRaw() { - n.Value.parseRaw(true) - } - if err := n.Value.Check(); err != nil { - return err - } - } - return nil - default: - return self.Check() - } + return self.Load() } // Load loads the node's children as parsed. -// After calling it, only the node itself can be used on concurrency (not include its children) +// and ensure all its children can be READ concurrently (include its children's children) func (self *Node) Load() error { - if self.IsRaw() { - self.parseRaw(false) - return self.Load() - } - switch self.t { - case _V_ARRAY_LAZY: - return self.skipAllIndex() - case _V_OBJECT_LAZY: - return self.skipAllKey() - default: - return self.Check() + case _V_ARRAY_LAZY: self.loadAllIndex(true) + case _V_OBJECT_LAZY: self.loadAllKey(true) + case V_ERROR: return self + case V_NONE: return nil + } + if self.m == nil { + self.m = new(sync.RWMutex) } + return self.checkRaw() } /**---------------------------------- Internal Helper Methods ----------------------------------**/ -var ( - _NODE_TYPE = rt.UnpackEface(Node{}).Type - _PAIR_TYPE = rt.UnpackEface(Pair{}).Type -) - -// func (self *Node) setCapAndLen(cap int, len int) { -// if self.t == types.V_ARRAY || self.t == types.V_OBJECT || self.t == _V_ARRAY_LAZY || self.t == _V_OBJECT_LAZY { -// self.l = uint32(len) -// self.c = uint32(cap) -// } else { -// panic("value does not have a length") -// } -// } - -func (self *Node) unsafe_next() *Node { - return (*Node)(unsafe.Pointer(uintptr(unsafe.Pointer(self)) + _NODE_SIZE)) -} - -func (self *Pair) unsafe_next() *Pair { - return (*Pair)(unsafe.Pointer(uintptr(unsafe.Pointer(self)) + _PAIR_SIZE)) -} - -func (self *Node) must(t types.ValueType, s string) { - if err := self.checkRaw(); err != nil { - panic(err) - } - if err := self.Check(); err != nil { - panic(err) - } - if self.itype() != t { - panic("value cannot be represented as " + s) - } -} - -func (self *Node) should(t types.ValueType, s string) error { +func (self *Node) should(t types.ValueType) error { if err := self.checkRaw(); err != nil { return err } @@ -1171,6 +1285,19 @@ func (self *Node) nodeAt(i int) *Node { p = &stack.v } else { p = (*linkedNodes)(self.p) + if l := p.Len(); l != self.len() { + // some nodes got unset, iterate to skip them + for j:=0; j _Threshold_Index { + v.BuildIndex() + } return Node{ t: types.V_OBJECT, l: uint(v.Len()), @@ -1640,53 +1802,42 @@ func newObject(v *linkedPairs) Node { } func (self *Node) setObject(v *linkedPairs) { + if v.size > _Threshold_Index { + v.BuildIndex() + } self.t = types.V_OBJECT self.l = uint(v.Len()) self.p = unsafe.Pointer(v) } -func newRawNode(str string, typ types.ValueType) Node { - return Node{ - t: _V_RAW | typ, - p: rt.StrPtr(str), - l: uint(len(str)), - } -} - func (self *Node) parseRaw(full bool) { + lock := self.lock() + defer self.unlock() + if !self.isRaw() { + return + } raw := self.toString() parser := NewParserObj(raw) + var e types.ParsingError if full { parser.noLazy = true - parser.skipValue = false + *self, e = parser.Parse() + } else if lock { + var n Node + parser.noLazy = true + parser.loadOnce = true + n, e = parser.Parse() + self.assign(n) + } else { + *self, e = parser.Parse() } - var e types.ParsingError - *self, e = parser.Parse() if e != 0 { *self = *newSyntaxError(parser.syntaxError(e)) } } -var typeJumpTable = [256]types.ValueType{ - '"' : types.V_STRING, - '-' : _V_NUMBER, - '0' : _V_NUMBER, - '1' : _V_NUMBER, - '2' : _V_NUMBER, - '3' : _V_NUMBER, - '4' : _V_NUMBER, - '5' : _V_NUMBER, - '6' : _V_NUMBER, - '7' : _V_NUMBER, - '8' : _V_NUMBER, - '9' : _V_NUMBER, - '[' : types.V_ARRAY, - 'f' : types.V_FALSE, - 'n' : types.V_NULL, - 't' : types.V_TRUE, - '{' : types.V_OBJECT, -} - -func switchRawType(c byte) types.ValueType { - return typeJumpTable[c] +func (self *Node) assign(n Node) { + self.l = n.l + self.p = n.p + atomic.StoreInt64(&self.t, n.t) } diff --git a/vendor/github.com/bytedance/sonic/ast/parser.go b/vendor/github.com/bytedance/sonic/ast/parser.go index cb16f20bb..30bd1f451 100644 --- a/vendor/github.com/bytedance/sonic/ast/parser.go +++ b/vendor/github.com/bytedance/sonic/ast/parser.go @@ -17,14 +17,16 @@ package ast import ( - `fmt` + "fmt" + "sync" + "sync/atomic" - `github.com/bytedance/sonic/internal/native/types` - `github.com/bytedance/sonic/internal/rt` + "github.com/bytedance/sonic/internal/native/types" + "github.com/bytedance/sonic/internal/rt" ) const ( - _DEFAULT_NODE_CAP int = 8 + _DEFAULT_NODE_CAP int = 16 _APPEND_GROW_SHIFT = 1 ) @@ -45,6 +47,7 @@ type Parser struct { p int s string noLazy bool + loadOnce bool skipValue bool dbuf *byte } @@ -115,6 +118,10 @@ func (self *Parser) lspace(sp int) int { return sp } +func (self *Parser) backward() { + for ; self.p >= 0 && isSpace(self.s[self.p]); self.p-=1 {} +} + func (self *Parser) decodeArray(ret *linkedNodes) (Node, types.ParsingError) { sp := self.p ns := len(self.s) @@ -148,7 +155,7 @@ func (self *Parser) decodeArray(ret *linkedNodes) (Node, types.ParsingError) { if t == _V_NONE { return Node{}, types.ERR_INVALID_CHAR } - val = newRawNode(self.s[start:self.p], t) + val = newRawNode(self.s[start:self.p], t, false) }else{ /* decode the value */ if val, err = self.Parse(); err != 0 { @@ -157,7 +164,7 @@ func (self *Parser) decodeArray(ret *linkedNodes) (Node, types.ParsingError) { } /* add the value to result */ - ret.Add(val) + ret.Push(val) self.p = self.lspace(self.p) /* check for EOF */ @@ -234,7 +241,7 @@ func (self *Parser) decodeObject(ret *linkedPairs) (Node, types.ParsingError) { if t == _V_NONE { return Node{}, types.ERR_INVALID_CHAR } - val = newRawNode(self.s[start:self.p], t) + val = newRawNode(self.s[start:self.p], t, false) } else { /* decode the value */ if val, err = self.Parse(); err != 0 { @@ -244,7 +251,7 @@ func (self *Parser) decodeObject(ret *linkedPairs) (Node, types.ParsingError) { /* add the value to result */ // FIXME: ret's address may change here, thus previous referred node in ret may be invalid !! - ret.Add(Pair{Key: key, Value: val}) + ret.Push(NewPair(key, val)) self.p = self.lspace(self.p) /* check for EOF */ @@ -291,6 +298,10 @@ func (self *Parser) Pos() int { return self.p } + +// Parse returns a ast.Node representing the parser's JSON. +// NOTICE: the specific parsing lazy dependens parser's option +// It only parse first layer and first child for Object or Array be default func (self *Parser) Parse() (Node, types.ParsingError) { switch val := self.decodeValue(); val.Vt { case types.V_EOF : return Node{}, types.ERR_EOF @@ -299,22 +310,48 @@ func (self *Parser) Parse() (Node, types.ParsingError) { case types.V_FALSE : return falseNode, 0 case types.V_STRING : return self.decodeString(val.Iv, val.Ep) case types.V_ARRAY: + s := self.p - 1; if p := skipBlank(self.s, self.p); p >= self.p && self.s[p] == ']' { self.p = p + 1 return Node{t: types.V_ARRAY}, 0 } if self.noLazy { + if self.loadOnce { + self.noLazy = false + } return self.decodeArray(new(linkedNodes)) } + // NOTICE: loadOnce always keep raw json for object or array + if self.loadOnce { + self.p = s + s, e := self.skipFast() + if e != 0 { + return Node{}, e + } + return newRawNode(self.s[s:self.p], types.V_ARRAY, true), 0 + } return newLazyArray(self), 0 case types.V_OBJECT: + s := self.p - 1; if p := skipBlank(self.s, self.p); p >= self.p && self.s[p] == '}' { self.p = p + 1 return Node{t: types.V_OBJECT}, 0 } + // NOTICE: loadOnce always keep raw json for object or array if self.noLazy { + if self.loadOnce { + self.noLazy = false + } return self.decodeObject(new(linkedPairs)) } + if self.loadOnce { + self.p = s + s, e := self.skipFast() + if e != 0 { + return Node{}, e + } + return newRawNode(self.s[s:self.p], types.V_OBJECT, true), 0 + } return newLazyObject(self), 0 case types.V_DOUBLE : return NewNumber(self.s[val.Ep:self.p]), 0 case types.V_INTEGER : return NewNumber(self.s[val.Ep:self.p]), 0 @@ -471,11 +508,11 @@ func (self *Node) skipNextNode() *Node { if t == _V_NONE { return newSyntaxError(parser.syntaxError(types.ERR_INVALID_CHAR)) } - val = newRawNode(parser.s[start:parser.p], t) + val = newRawNode(parser.s[start:parser.p], t, false) } /* add the value to result */ - ret.Add(val) + ret.Push(val) self.l++ parser.p = parser.lspace(parser.p) @@ -510,7 +547,7 @@ func (self *Node) skipNextPair() (*Pair) { /* check for EOF */ if parser.p = parser.lspace(sp); parser.p >= ns { - return &Pair{"", *newSyntaxError(parser.syntaxError(types.ERR_EOF))} + return newErrorPair(parser.syntaxError(types.ERR_EOF)) } /* check for empty object */ @@ -527,7 +564,7 @@ func (self *Node) skipNextPair() (*Pair) { /* decode the key */ if njs = parser.decodeValue(); njs.Vt != types.V_STRING { - return &Pair{"", *newSyntaxError(parser.syntaxError(types.ERR_INVALID_CHAR))} + return newErrorPair(parser.syntaxError(types.ERR_INVALID_CHAR)) } /* extract the key */ @@ -537,34 +574,34 @@ func (self *Node) skipNextPair() (*Pair) { /* check for escape sequence */ if njs.Ep != -1 { if key, err = unquote(key); err != 0 { - return &Pair{key, *newSyntaxError(parser.syntaxError(err))} + return newErrorPair(parser.syntaxError(err)) } } /* expect a ':' delimiter */ if err = parser.delim(); err != 0 { - return &Pair{key, *newSyntaxError(parser.syntaxError(err))} + return newErrorPair(parser.syntaxError(err)) } /* skip the value */ if start, err := parser.skipFast(); err != 0 { - return &Pair{key, *newSyntaxError(parser.syntaxError(err))} + return newErrorPair(parser.syntaxError(err)) } else { t := switchRawType(parser.s[start]) if t == _V_NONE { - return &Pair{key, *newSyntaxError(parser.syntaxError(types.ERR_INVALID_CHAR))} + return newErrorPair(parser.syntaxError(types.ERR_INVALID_CHAR)) } - val = newRawNode(parser.s[start:parser.p], t) + val = newRawNode(parser.s[start:parser.p], t, false) } /* add the value to result */ - ret.Add(Pair{Key: key, Value: val}) + ret.Push(NewPair(key, val)) self.l++ parser.p = parser.lspace(parser.p) /* check for EOF */ if parser.p >= ns { - return &Pair{key, *newSyntaxError(parser.syntaxError(types.ERR_EOF))} + return newErrorPair(parser.syntaxError(types.ERR_EOF)) } /* check for the next character */ @@ -577,7 +614,7 @@ func (self *Node) skipNextPair() (*Pair) { self.setObject(ret) return ret.At(ret.Len()-1) default: - return &Pair{key, *newSyntaxError(parser.syntaxError(types.ERR_INVALID_CHAR))} + return newErrorPair(parser.syntaxError(types.ERR_INVALID_CHAR)) } } @@ -653,3 +690,77 @@ func (self *Parser) ExportError(err types.ParsingError) error { Code: err, }.Description()) } + +func backward(src string, i int) int { + for ; i>=0 && isSpace(src[i]); i-- {} + return i +} + + +func newRawNode(str string, typ types.ValueType, lock bool) Node { + ret := Node{ + t: typ | _V_RAW, + p: rt.StrPtr(str), + l: uint(len(str)), + } + if lock { + ret.m = new(sync.RWMutex) + } + return ret +} + +var typeJumpTable = [256]types.ValueType{ + '"' : types.V_STRING, + '-' : _V_NUMBER, + '0' : _V_NUMBER, + '1' : _V_NUMBER, + '2' : _V_NUMBER, + '3' : _V_NUMBER, + '4' : _V_NUMBER, + '5' : _V_NUMBER, + '6' : _V_NUMBER, + '7' : _V_NUMBER, + '8' : _V_NUMBER, + '9' : _V_NUMBER, + '[' : types.V_ARRAY, + 'f' : types.V_FALSE, + 'n' : types.V_NULL, + 't' : types.V_TRUE, + '{' : types.V_OBJECT, +} + +func switchRawType(c byte) types.ValueType { + return typeJumpTable[c] +} + +func (self *Node) loadt() types.ValueType { + return (types.ValueType)(atomic.LoadInt64(&self.t)) +} + +func (self *Node) lock() bool { + if m := self.m; m != nil { + m.Lock() + return true + } + return false +} + +func (self *Node) unlock() { + if m := self.m; m != nil { + m.Unlock() + } +} + +func (self *Node) rlock() bool { + if m := self.m; m != nil { + m.RLock() + return true + } + return false +} + +func (self *Node) runlock() { + if m := self.m; m != nil { + m.RUnlock() + } +} diff --git a/vendor/github.com/bytedance/sonic/ast/search.go b/vendor/github.com/bytedance/sonic/ast/search.go index bb6fceaa7..9a5fb9420 100644 --- a/vendor/github.com/bytedance/sonic/ast/search.go +++ b/vendor/github.com/bytedance/sonic/ast/search.go @@ -16,8 +16,28 @@ package ast +import ( + `github.com/bytedance/sonic/internal/rt` + `github.com/bytedance/sonic/internal/native/types` +) + +// SearchOptions controls Searcher's behavior +type SearchOptions struct { + // ValidateJSON indicates the searcher to validate the entire JSON + ValidateJSON bool + + // CopyReturn indicates the searcher to copy the result JSON instead of refer from the input + // This can help to reduce memory usage if you cache the results + CopyReturn bool + + // ConcurrentRead indicates the searcher to return a concurrently-READ-safe node, + // including: GetByPath/Get/Index/GetOrIndex/Int64/Bool/Float64/String/Number/Interface/Array/Map/Raw/MarshalJSON + ConcurrentRead bool +} + type Searcher struct { parser Parser + SearchOptions } func NewSearcher(str string) *Searcher { @@ -26,5 +46,112 @@ func NewSearcher(str string) *Searcher { s: str, noLazy: false, }, + SearchOptions: SearchOptions{ + ValidateJSON: true, + }, + } +} + +// GetByPathCopy search in depth from top json and returns a **Copied** json node at the path location +func (self *Searcher) GetByPathCopy(path ...interface{}) (Node, error) { + self.CopyReturn = true + return self.getByPath(path...) +} + +// GetByPathNoCopy search in depth from top json and returns a **Referenced** json node at the path location +// +// WARN: this search directly refer partial json from top json, which has faster speed, +// may consumes more memory. +func (self *Searcher) GetByPath(path ...interface{}) (Node, error) { + return self.getByPath(path...) +} + +func (self *Searcher) getByPath(path ...interface{}) (Node, error) { + var err types.ParsingError + var start int + + self.parser.p = 0 + start, err = self.parser.getByPath(self.ValidateJSON, path...) + if err != 0 { + // for compatibility with old version + if err == types.ERR_NOT_FOUND { + return Node{}, ErrNotExist + } + if err == types.ERR_UNSUPPORT_TYPE { + panic("path must be either int(>=0) or string") + } + return Node{}, self.parser.syntaxError(err) + } + + t := switchRawType(self.parser.s[start]) + if t == _V_NONE { + return Node{}, self.parser.ExportError(err) + } + + // copy string to reducing memory usage + var raw string + if self.CopyReturn { + raw = rt.Mem2Str([]byte(self.parser.s[start:self.parser.p])) + } else { + raw = self.parser.s[start:self.parser.p] + } + return newRawNode(raw, t, self.ConcurrentRead), nil +} + +// GetByPath searches a path and returns relaction and types of target +func _GetByPath(src string, path ...interface{}) (start int, end int, typ int, err error) { + p := NewParserObj(src) + s, e := p.getByPath(false, path...) + if e != 0 { + // for compatibility with old version + if e == types.ERR_NOT_FOUND { + return -1, -1, 0, ErrNotExist + } + if e == types.ERR_UNSUPPORT_TYPE { + panic("path must be either int(>=0) or string") + } + return -1, -1, 0, p.syntaxError(e) + } + + t := switchRawType(p.s[s]) + if t == _V_NONE { + return -1, -1, 0, ErrNotExist + } + if t == _V_NUMBER { + p.p = 1 + backward(p.s, p.p-1) + } + return s, p.p, int(t), nil +} + +// ValidSyntax check if a json has a valid JSON syntax, +// while not validate UTF-8 charset +func _ValidSyntax(json string) bool { + p := NewParserObj(json) + _, e := p.skip() + if e != 0 { + return false + } + if skipBlank(p.s, p.p) != -int(types.ERR_EOF) { + return false + } + return true +} + +// SkipFast skip a json value in fast-skip algs, +// while not strictly validate JSON syntax and UTF-8 charset. +func _SkipFast(src string, i int) (int, int, error) { + p := NewParserObj(src) + p.p = i + s, e := p.skipFast() + if e != 0 { + return -1, -1, p.ExportError(e) + } + t := switchRawType(p.s[s]) + if t == _V_NONE { + return -1, -1, ErrNotExist + } + if t == _V_NUMBER { + p.p = 1 + backward(p.s, p.p-1) } + return s, p.p, nil } diff --git a/vendor/github.com/bytedance/sonic/ast/stubs.go b/vendor/github.com/bytedance/sonic/ast/stubs.go new file mode 100644 index 000000000..53bf3b8aa --- /dev/null +++ b/vendor/github.com/bytedance/sonic/ast/stubs.go @@ -0,0 +1,142 @@ +/* + * 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 ast + +import ( + "unicode/utf8" + "unsafe" + + "github.com/bytedance/sonic/internal/rt" +) + +//go:noescape +//go:linkname memmove runtime.memmove +//goland:noinspection GoUnusedParameter +func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr) + +//go:linkname unsafe_NewArray reflect.unsafe_NewArray +//goland:noinspection GoUnusedParameter +func unsafe_NewArray(typ *rt.GoType, n int) unsafe.Pointer + +//go:nosplit +func mem2ptr(s []byte) unsafe.Pointer { + return (*rt.GoSlice)(unsafe.Pointer(&s)).Ptr +} + +var safeSet = [utf8.RuneSelf]bool{ + ' ': true, + '!': true, + '"': false, + '#': true, + '$': true, + '%': true, + '&': true, + '\'': true, + '(': true, + ')': true, + '*': true, + '+': true, + ',': true, + '-': true, + '.': true, + '/': true, + '0': true, + '1': true, + '2': true, + '3': true, + '4': true, + '5': true, + '6': true, + '7': true, + '8': true, + '9': true, + ':': true, + ';': true, + '<': true, + '=': true, + '>': true, + '?': true, + '@': true, + 'A': true, + 'B': true, + 'C': true, + 'D': true, + 'E': true, + 'F': true, + 'G': true, + 'H': true, + 'I': true, + 'J': true, + 'K': true, + 'L': true, + 'M': true, + 'N': true, + 'O': true, + 'P': true, + 'Q': true, + 'R': true, + 'S': true, + 'T': true, + 'U': true, + 'V': true, + 'W': true, + 'X': true, + 'Y': true, + 'Z': true, + '[': true, + '\\': false, + ']': true, + '^': true, + '_': true, + '`': true, + 'a': true, + 'b': true, + 'c': true, + 'd': true, + 'e': true, + 'f': true, + 'g': true, + 'h': true, + 'i': true, + 'j': true, + 'k': true, + 'l': true, + 'm': true, + 'n': true, + 'o': true, + 'p': true, + 'q': true, + 'r': true, + 's': true, + 't': true, + 'u': true, + 'v': true, + 'w': true, + 'x': true, + 'y': true, + 'z': true, + '{': true, + '|': true, + '}': true, + '~': true, + '\u007f': true, +} + +var hex = "0123456789abcdef" + +//go:linkname unquoteBytes encoding/json.unquoteBytes +func unquoteBytes(s []byte) (t []byte, ok bool) diff --git a/vendor/github.com/bytedance/sonic/ast/stubs_go115.go b/vendor/github.com/bytedance/sonic/ast/stubs_go115.go deleted file mode 100644 index 37b9451f0..000000000 --- a/vendor/github.com/bytedance/sonic/ast/stubs_go115.go +++ /dev/null @@ -1,55 +0,0 @@ -// +build !go1.20 - -/* - * 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 ast - -import ( - `unsafe` - `unicode/utf8` - - `github.com/bytedance/sonic/internal/rt` -) - -//go:noescape -//go:linkname memmove runtime.memmove -//goland:noinspection GoUnusedParameter -func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr) - -//go:linkname unsafe_NewArray reflect.unsafe_NewArray -//goland:noinspection GoUnusedParameter -func unsafe_NewArray(typ *rt.GoType, n int) unsafe.Pointer - -//go:linkname growslice runtime.growslice -//goland:noinspection GoUnusedParameter -func growslice(et *rt.GoType, old rt.GoSlice, cap int) rt.GoSlice - -//go:nosplit -func mem2ptr(s []byte) unsafe.Pointer { - return (*rt.GoSlice)(unsafe.Pointer(&s)).Ptr -} - -var ( - //go:linkname safeSet encoding/json.safeSet - safeSet [utf8.RuneSelf]bool - - //go:linkname hex encoding/json.hex - hex string -) - -//go:linkname unquoteBytes encoding/json.unquoteBytes -func unquoteBytes(s []byte) (t []byte, ok bool) \ No newline at end of file diff --git a/vendor/github.com/bytedance/sonic/ast/stubs_go120.go b/vendor/github.com/bytedance/sonic/ast/stubs_go120.go deleted file mode 100644 index 6f830529d..000000000 --- a/vendor/github.com/bytedance/sonic/ast/stubs_go120.go +++ /dev/null @@ -1,55 +0,0 @@ -// +build go1.20 - -/* - * 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 ast - -import ( - `unsafe` - `unicode/utf8` - - `github.com/bytedance/sonic/internal/rt` -) - -//go:noescape -//go:linkname memmove runtime.memmove -//goland:noinspection GoUnusedParameter -func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr) - -//go:linkname unsafe_NewArray reflect.unsafe_NewArray -//goland:noinspection GoUnusedParameter -func unsafe_NewArray(typ *rt.GoType, n int) unsafe.Pointer - -//go:linkname growslice reflect.growslice -//goland:noinspection GoUnusedParameter -func growslice(et *rt.GoType, old rt.GoSlice, cap int) rt.GoSlice - -//go:nosplit -func mem2ptr(s []byte) unsafe.Pointer { - return (*rt.GoSlice)(unsafe.Pointer(&s)).Ptr -} - -var ( - //go:linkname safeSet encoding/json.safeSet - safeSet [utf8.RuneSelf]bool - - //go:linkname hex encoding/json.hex - hex string -) - -//go:linkname unquoteBytes encoding/json.unquoteBytes -func unquoteBytes(s []byte) (t []byte, ok bool) diff --git a/vendor/github.com/bytedance/sonic/ast/visitor.go b/vendor/github.com/bytedance/sonic/ast/visitor.go index 4019c31a2..dc0478513 100644 --- a/vendor/github.com/bytedance/sonic/ast/visitor.go +++ b/vendor/github.com/bytedance/sonic/ast/visitor.go @@ -18,6 +18,7 @@ package ast import ( `encoding/json` + `errors` `github.com/bytedance/sonic/internal/native/types` ) @@ -25,7 +26,7 @@ import ( // Visitor handles the callbacks during preorder traversal of a JSON AST. // // According to the JSON RFC8259, a JSON AST can be defined by -// the following rules without seperator / whitespace tokens. +// the following rules without separator / whitespace tokens. // // JSON-AST = value // value = false / null / true / object / array / number / string @@ -174,6 +175,19 @@ func (self *traverser) decodeArray() error { sp := self.parser.p ns := len(self.parser.s) + /* allocate array space and parse every element */ + if err := self.visitor.OnArrayBegin(_DEFAULT_NODE_CAP); err != nil { + if err == VisitOPSkip { + // NOTICE: for user needs to skip entiry object + self.parser.p -= 1 + if _, e := self.parser.skipFast(); e != 0 { + return e + } + return self.visitor.OnArrayEnd() + } + return err + } + /* check for EOF */ self.parser.p = self.parser.lspace(sp) if self.parser.p >= ns { @@ -183,16 +197,9 @@ func (self *traverser) decodeArray() error { /* check for empty array */ if self.parser.s[self.parser.p] == ']' { self.parser.p++ - if err := self.visitor.OnArrayBegin(0); err != nil { - return err - } return self.visitor.OnArrayEnd() } - /* allocate array space and parse every element */ - if err := self.visitor.OnArrayBegin(_DEFAULT_NODE_CAP); err != nil { - return err - } for { /* decode the value */ if err := self.decodeValue(); err != nil { @@ -223,6 +230,19 @@ func (self *traverser) decodeObject() error { sp := self.parser.p ns := len(self.parser.s) + /* allocate object space and decode each pair */ + if err := self.visitor.OnObjectBegin(_DEFAULT_NODE_CAP); err != nil { + if err == VisitOPSkip { + // NOTICE: for user needs to skip entiry object + self.parser.p -= 1 + if _, e := self.parser.skipFast(); e != 0 { + return e + } + return self.visitor.OnObjectEnd() + } + return err + } + /* check for EOF */ self.parser.p = self.parser.lspace(sp) if self.parser.p >= ns { @@ -232,16 +252,9 @@ func (self *traverser) decodeObject() error { /* check for empty object */ if self.parser.s[self.parser.p] == '}' { self.parser.p++ - if err := self.visitor.OnObjectBegin(0); err != nil { - return err - } return self.visitor.OnObjectEnd() } - /* allocate object space and decode each pair */ - if err := self.visitor.OnObjectBegin(_DEFAULT_NODE_CAP); err != nil { - return err - } for { var njs types.JsonState var err types.ParsingError @@ -313,3 +326,7 @@ func (self *traverser) decodeString(iv int64, ep int) error { } return self.visitor.OnString(out) } + +// If visitor return this error on `OnObjectBegin()` or `OnArrayBegin()`, +// the transverer will skip entiry object or array +var VisitOPSkip = errors.New("") diff --git a/vendor/github.com/bytedance/sonic/compat.go b/vendor/github.com/bytedance/sonic/compat.go index ec414c0cf..b32342a84 100644 --- a/vendor/github.com/bytedance/sonic/compat.go +++ b/vendor/github.com/bytedance/sonic/compat.go @@ -1,4 +1,4 @@ -// +build !amd64 !go1.16 go1.22 +// +build !amd64,!arm64 go1.24 !go1.17 arm64,!go1.20 /* * Copyright 2021 ByteDance Inc. @@ -27,6 +27,8 @@ import ( `github.com/bytedance/sonic/option` ) +const apiKind = UseStdJSON + type frozenConfig struct { Config } diff --git a/vendor/github.com/bytedance/sonic/decoder/decoder_compat.go b/vendor/github.com/bytedance/sonic/decoder/decoder_compat.go index 466d842e8..81e1ae4e3 100644 --- a/vendor/github.com/bytedance/sonic/decoder/decoder_compat.go +++ b/vendor/github.com/bytedance/sonic/decoder/decoder_compat.go @@ -1,4 +1,4 @@ -// +build !amd64 !go1.16 go1.22 +// +build !amd64,!arm64 go1.24 !go1.17 arm64,!go1.20 /* * Copyright 2023 ByteDance Inc. @@ -30,7 +30,7 @@ import ( ) func init() { - println("WARNING: sonic only supports Go1.16~1.20 && CPU amd64, but your environment is not suitable") + println("WARNING: sonic/decoder only supports (Go1.17~1.23 && CPU amd64) or (go1.20~1.23 && CPU arm64), but your environment is not suitable") } const ( @@ -42,6 +42,7 @@ const ( _F_use_number = types.B_USE_NUMBER _F_validate_string = types.B_VALIDATE_STRING _F_allow_control = types.B_ALLOW_CONTROL + _F_no_validate_json = types.B_NO_VALIDATE_JSON ) type Options uint64 @@ -53,6 +54,7 @@ const ( OptionDisableUnknown Options = 1 << _F_disable_unknown OptionCopyString Options = 1 << _F_copy_string OptionValidateString Options = 1 << _F_validate_string + OptionNoValidateJSON Options = 1 << _F_no_validate_json ) func (self *Decoder) SetOptions(opts Options) { @@ -112,10 +114,10 @@ func (self *Decoder) CheckTrailings() error { func (self *Decoder) Decode(val interface{}) error { r := bytes.NewBufferString(self.s) dec := json.NewDecoder(r) - if (self.f | uint64(OptionUseNumber)) != 0 { + if (self.f & uint64(OptionUseNumber)) != 0 { dec.UseNumber() } - if (self.f | uint64(OptionDisableUnknown)) != 0 { + if (self.f & uint64(OptionDisableUnknown)) != 0 { dec.DisallowUnknownFields() } return dec.Decode(val) diff --git a/vendor/github.com/bytedance/sonic/decoder/decoder_amd64.go b/vendor/github.com/bytedance/sonic/decoder/decoder_native.go similarity index 64% rename from vendor/github.com/bytedance/sonic/decoder/decoder_amd64.go rename to vendor/github.com/bytedance/sonic/decoder/decoder_native.go index 7c2845514..9317d57f6 100644 --- a/vendor/github.com/bytedance/sonic/decoder/decoder_amd64.go +++ b/vendor/github.com/bytedance/sonic/decoder/decoder_native.go @@ -1,4 +1,6 @@ -// +build amd64,go1.16,!go1.22 +//go:build (amd64 && go1.17 && !go1.24) || (arm64 && go1.20 && !go1.24) +// +build amd64,go1.17,!go1.24 arm64,go1.20,!go1.24 + /* * Copyright 2023 ByteDance Inc. @@ -19,50 +21,51 @@ package decoder import ( - `github.com/bytedance/sonic/internal/decoder` + `github.com/bytedance/sonic/internal/decoder/api` ) // Decoder is the decoder context object -type Decoder = decoder.Decoder +type Decoder = api.Decoder // SyntaxError represents json syntax error -type SyntaxError = decoder.SyntaxError +type SyntaxError = api.SyntaxError // MismatchTypeError represents dismatching between json and object -type MismatchTypeError = decoder.MismatchTypeError +type MismatchTypeError = api.MismatchTypeError // Options for decode. -type Options = decoder.Options +type Options = api.Options const ( - OptionUseInt64 Options = decoder.OptionUseInt64 - OptionUseNumber Options = decoder.OptionUseNumber - OptionUseUnicodeErrors Options = decoder.OptionUseUnicodeErrors - OptionDisableUnknown Options = decoder.OptionDisableUnknown - OptionCopyString Options = decoder.OptionCopyString - OptionValidateString Options = decoder.OptionValidateString + OptionUseInt64 Options = api.OptionUseInt64 + OptionUseNumber Options = api.OptionUseNumber + OptionUseUnicodeErrors Options = api.OptionUseUnicodeErrors + OptionDisableUnknown Options = api.OptionDisableUnknown + OptionCopyString Options = api.OptionCopyString + OptionValidateString Options = api.OptionValidateString + OptionNoValidateJSON Options = api.OptionNoValidateJSON ) // StreamDecoder is the decoder context object for streaming input. -type StreamDecoder = decoder.StreamDecoder +type StreamDecoder = api.StreamDecoder var ( // NewDecoder creates a new decoder instance. - NewDecoder = decoder.NewDecoder + NewDecoder = api.NewDecoder // NewStreamDecoder adapts to encoding/json.NewDecoder API. // // NewStreamDecoder returns a new decoder that reads from r. - NewStreamDecoder = decoder.NewStreamDecoder + NewStreamDecoder = api.NewStreamDecoder // Pretouch compiles vt ahead-of-time to avoid JIT compilation on-the-fly, in // order to reduce the first-hit latency. // // Opts are the compile options, for example, "option.WithCompileRecursiveDepth" is // a compile option to set the depth of recursive compile for the nested struct type. - Pretouch = decoder.Pretouch + Pretouch = api.Pretouch // Skip skips only one json value, and returns first non-blank character position and its ending position if it is valid. // Otherwise, returns negative error code using start and invalid character position using end - Skip = decoder.Skip + Skip = api.Skip ) diff --git a/vendor/github.com/bytedance/sonic/encoder/encoder_compat.go b/vendor/github.com/bytedance/sonic/encoder/encoder_compat.go index 222eea5b2..254defa20 100644 --- a/vendor/github.com/bytedance/sonic/encoder/encoder_compat.go +++ b/vendor/github.com/bytedance/sonic/encoder/encoder_compat.go @@ -1,4 +1,4 @@ -// +build !amd64 !go1.16 go1.22 +// +build !amd64,!arm64 go1.24 !go1.17 arm64,!go1.20 /* * Copyright 2023 ByteDance Inc. @@ -28,9 +28,12 @@ import ( ) func init() { - println("WARNING: sonic only supports Go1.16~1.20 && CPU amd64, but your environment is not suitable") + println("WARNING:(encoder) sonic only supports (Go1.17~1.23 && CPU amd64) or (G01.20~1.23 && CPU arm64) , but your environment is not suitable") } +// EnableFallback indicates if encoder use fallback +const EnableFallback = true + // Options is a set of encoding options. type Options uint64 @@ -41,6 +44,8 @@ const ( bitNoQuoteTextMarshaler bitNoNullSliceOrMap bitValidateString + bitNoValidateJSONMarshaler + bitNoEncoderNewline // used for recursive compile bitPointerValue = 63 @@ -72,6 +77,13 @@ const ( // 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 @@ -116,6 +128,24 @@ func (self *Encoder) SetValidateString(f bool) { } } +// 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 { @@ -161,15 +191,19 @@ func Encode(val interface{}, opts Options) ([]byte, error) { // 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 + 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() + l := len(*buf) + if l > 0 && (opts & NoEncoderNewline != 0) && (*buf)[l-1] == '\n' { + *buf = (*buf)[:l-1] + } + return err } // HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029 diff --git a/vendor/github.com/bytedance/sonic/encoder/encoder_amd64.go b/vendor/github.com/bytedance/sonic/encoder/encoder_native.go similarity index 86% rename from vendor/github.com/bytedance/sonic/encoder/encoder_amd64.go rename to vendor/github.com/bytedance/sonic/encoder/encoder_native.go index 0ef336b72..b300ebf08 100644 --- a/vendor/github.com/bytedance/sonic/encoder/encoder_amd64.go +++ b/vendor/github.com/bytedance/sonic/encoder/encoder_native.go @@ -1,4 +1,4 @@ -// +build amd64,go1.16,!go1.22 +// +build amd64,go1.17,!go1.24 arm64,go1.20,!go1.24 /* * Copyright 2023 ByteDance Inc. @@ -22,6 +22,8 @@ import ( `github.com/bytedance/sonic/internal/encoder` ) +// EnableFallback indicates if encoder use fallback +const EnableFallback = false // Encoder represents a specific set of encoder configurations. type Encoder = encoder.Encoder @@ -59,8 +61,18 @@ const ( // before encoding it into JSON. ValidateString Options = encoder.ValidateString + // NoValidateJSONMarshaler indicates that the encoder should not validate the output string + // after encoding the JSONMarshaler to JSON. + NoValidateJSONMarshaler Options = encoder.NoValidateJSONMarshaler + + // NoEncoderNewline indicates that the encoder should not add a newline after every message + NoEncoderNewline Options = encoder.NoEncoderNewline + // CompatibleWithStd is used to be compatible with std encoder. CompatibleWithStd Options = encoder.CompatibleWithStd + + // Encode Infinity or Nan float into `null`, instead of returning an error. + EncodeNullForInfOrNan Options = encoder.EncodeNullForInfOrNan ) diff --git a/vendor/github.com/bytedance/sonic/go.work b/vendor/github.com/bytedance/sonic/go.work index e21d6f872..8d2af51b9 100644 --- a/vendor/github.com/bytedance/sonic/go.work +++ b/vendor/github.com/bytedance/sonic/go.work @@ -2,7 +2,8 @@ go 1.18 use ( . - ./generic_test - ./fuzz ./external_jsonlib_test + ./fuzz + ./generic_test + ./loader ) diff --git a/vendor/github.com/bytedance/sonic/go.work.sum b/vendor/github.com/bytedance/sonic/go.work.sum new file mode 100644 index 000000000..d59625879 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/go.work.sum @@ -0,0 +1 @@ +github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= diff --git a/vendor/github.com/bytedance/sonic/internal/base64/b64_amd64.go b/vendor/github.com/bytedance/sonic/internal/base64/b64_amd64.go new file mode 100644 index 000000000..01f99f931 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/base64/b64_amd64.go @@ -0,0 +1,46 @@ +// +build amd64,go1.16 + +/** + * 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 base64 + +import ( + "github.com/cloudwego/base64x" +) + +func DecodeBase64(src string) ([]byte, error) { + return base64x.StdEncoding.DecodeString(src) +} + +func EncodeBase64(buf []byte, src []byte) []byte { + if len(src) == 0 { + return append(buf, '"', '"') + } + buf = append(buf, '"') + need := base64x.StdEncoding.EncodedLen(len(src)) + if cap(buf) - len(buf) < need { + tmp := make([]byte, len(buf), len(buf) + need*2) + copy(tmp, buf) + buf = tmp + } + base64x.StdEncoding.Encode(buf[len(buf):cap(buf)], src) + buf = buf[:len(buf) + need] + buf = append(buf, '"') + return buf +} + + \ No newline at end of file diff --git a/vendor/github.com/bytedance/sonic/internal/base64/b64_compat.go b/vendor/github.com/bytedance/sonic/internal/base64/b64_compat.go new file mode 100644 index 000000000..ba8f8b562 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/base64/b64_compat.go @@ -0,0 +1,44 @@ +// +build !amd64 !go1.16 + +/* + * Copyright 2022 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 base64 + +import ( + "encoding/base64" +) + +func EncodeBase64(buf []byte, src []byte) []byte { + if len(src) == 0 { + return append(buf, '"', '"') + } + buf = append(buf, '"') + need := base64.StdEncoding.EncodedLen(len(src)) + if cap(buf) - len(buf) < need { + tmp := make([]byte, len(buf), len(buf) + need*2) + copy(tmp, buf) + buf = tmp + } + base64.StdEncoding.Encode(buf[len(buf):cap(buf)], src) + buf = buf[:len(buf) + need] + buf = append(buf, '"') + return buf +} + +func DecodeBase64(src string) ([]byte, error) { + return base64.StdEncoding.DecodeString(src) +} diff --git a/vendor/github.com/bytedance/sonic/internal/cpu/features.go b/vendor/github.com/bytedance/sonic/internal/cpu/features.go index f9ee3b8f3..fd4dbda3c 100644 --- a/vendor/github.com/bytedance/sonic/internal/cpu/features.go +++ b/vendor/github.com/bytedance/sonic/internal/cpu/features.go @@ -24,7 +24,6 @@ import ( ) var ( - HasAVX = cpuid.CPU.Has(cpuid.AVX) HasAVX2 = cpuid.CPU.Has(cpuid.AVX2) HasSSE = cpuid.CPU.Has(cpuid.SSE) ) @@ -33,7 +32,8 @@ func init() { switch v := os.Getenv("SONIC_MODE"); v { case "" : break case "auto" : break - case "noavx" : HasAVX = false; fallthrough + case "noavx" : HasAVX2 = false + // will also disable avx, act as `noavx`, we remain it to make sure forward compatibility case "noavx2" : HasAVX2 = false default : panic(fmt.Sprintf("invalid mode: '%s', should be one of 'auto', 'noavx', 'noavx2'", v)) } diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/decoder.go b/vendor/github.com/bytedance/sonic/internal/decoder/api/decoder.go similarity index 57% rename from vendor/github.com/bytedance/sonic/internal/decoder/decoder.go rename to vendor/github.com/bytedance/sonic/internal/decoder/api/decoder.go index 8453db861..0dc01998f 100644 --- a/vendor/github.com/bytedance/sonic/internal/decoder/decoder.go +++ b/vendor/github.com/bytedance/sonic/internal/decoder/api/decoder.go @@ -14,51 +14,52 @@ * limitations under the License. */ -package decoder +package api import ( - `unsafe` - `encoding/json` `reflect` - `runtime` `github.com/bytedance/sonic/internal/native` `github.com/bytedance/sonic/internal/native/types` + `github.com/bytedance/sonic/internal/decoder/consts` + `github.com/bytedance/sonic/internal/decoder/errors` `github.com/bytedance/sonic/internal/rt` `github.com/bytedance/sonic/option` - `github.com/bytedance/sonic/utf8` ) const ( - _F_use_int64 = 0 - _F_disable_urc = 2 - _F_disable_unknown = 3 - _F_copy_string = 4 - - _F_use_number = types.B_USE_NUMBER - _F_validate_string = types.B_VALIDATE_STRING - _F_allow_control = types.B_ALLOW_CONTROL + _F_allow_control = consts.F_allow_control + _F_copy_string = consts.F_copy_string + _F_disable_unknown = consts.F_disable_unknown + _F_disable_urc = consts.F_disable_urc + _F_use_int64 = consts.F_use_int64 + _F_use_number = consts.F_use_number + _F_validate_string = consts.F_validate_string + + _MaxStack = consts.MaxStack + + OptionUseInt64 = consts.OptionUseInt64 + OptionUseNumber = consts.OptionUseNumber + OptionUseUnicodeErrors = consts.OptionUseUnicodeErrors + OptionDisableUnknown = consts.OptionDisableUnknown + OptionCopyString = consts.OptionCopyString + OptionValidateString = consts.OptionValidateString + OptionNoValidateJSON = consts.OptionNoValidateJSON ) -type Options uint64 - -const ( - OptionUseInt64 Options = 1 << _F_use_int64 - OptionUseNumber Options = 1 << _F_use_number - OptionUseUnicodeErrors Options = 1 << _F_disable_urc - OptionDisableUnknown Options = 1 << _F_disable_unknown - OptionCopyString Options = 1 << _F_copy_string - OptionValidateString Options = 1 << _F_validate_string +type ( + Options = consts.Options + MismatchTypeError = errors.MismatchTypeError + SyntaxError = errors.SyntaxError ) func (self *Decoder) SetOptions(opts Options) { - if (opts & OptionUseNumber != 0) && (opts & OptionUseInt64 != 0) { + if (opts & consts.OptionUseNumber != 0) && (opts & consts.OptionUseInt64 != 0) { panic("can't set OptionUseInt64 and OptionUseNumber both!") } self.f = uint64(opts) } - // Decoder is the decoder context object type Decoder struct { i int @@ -109,44 +110,7 @@ func (self *Decoder) CheckTrailings() error { // Decode parses the JSON-encoded data from current position and stores the result // in the value pointed to by val. func (self *Decoder) Decode(val interface{}) error { - /* validate json if needed */ - if (self.f & (1 << _F_validate_string)) != 0 && !utf8.ValidateString(self.s){ - dbuf := utf8.CorrectWith(nil, rt.Str2Mem(self.s), "\ufffd") - self.s = rt.Mem2Str(dbuf) - } - - vv := rt.UnpackEface(val) - vp := vv.Value - - /* check for nil type */ - if vv.Type == nil { - return &json.InvalidUnmarshalError{} - } - - /* must be a non-nil pointer */ - if vp == nil || vv.Type.Kind() != reflect.Ptr { - return &json.InvalidUnmarshalError{Type: vv.Type.Pack()} - } - - etp := rt.PtrElem(vv.Type) - - /* check the defined pointer type for issue 379 */ - if vv.Type.IsNamed() { - newp := vp - etp = vv.Type - vp = unsafe.Pointer(&newp) - } - - /* create a new stack, and call the decoder */ - sb := newStack() - nb, err := decodeTypedPointer(self.s, self.i, etp, vp, sb, self.f) - /* return the stack back */ - self.i = nb - freeStack(sb) - - /* avoid GC ahead */ - runtime.KeepAlive(vv) - return err + return decodeImpl(&self.s, &self.i, self.f, val) } // UseInt64 indicates the Decoder to unmarshal an integer into an interface{} as an @@ -194,53 +158,7 @@ func (self *Decoder) ValidateString() { // Opts are the compile options, for example, "option.WithCompileRecursiveDepth" is // a compile option to set the depth of recursive compile for the nested struct type. func Pretouch(vt reflect.Type, opts ...option.CompileOption) error { - cfg := option.DefaultCompileOptions() - for _, opt := range opts { - opt(&cfg) - } - return pretouchRec(map[reflect.Type]bool{vt:true}, cfg) -} - -func pretouchType(_vt reflect.Type, opts option.CompileOptions) (map[reflect.Type]bool, error) { - /* compile function */ - compiler := newCompiler().apply(opts) - decoder := func(vt *rt.GoType, _ ...interface{}) (interface{}, error) { - if pp, err := compiler.compile(_vt); err != nil { - return nil, err - } else { - as := newAssembler(pp) - as.name = _vt.String() - return as.Load(), nil - } - } - - /* find or compile */ - vt := rt.UnpackType(_vt) - if val := programCache.Get(vt); val != nil { - return nil, nil - } else if _, err := programCache.Compute(vt, decoder); err == nil { - return compiler.rec, nil - } else { - return nil, err - } -} - -func pretouchRec(vtm map[reflect.Type]bool, opts option.CompileOptions) error { - if opts.RecursiveDepth < 0 || len(vtm) == 0 { - return nil - } - next := make(map[reflect.Type]bool) - for vt := range(vtm) { - sub, err := pretouchType(vt, opts) - if err != nil { - return err - } - for svt := range(sub) { - next[svt] = true - } - } - opts.RecursiveDepth -= 1 - return pretouchRec(next, opts) + return pretouchImpl(vt, opts...) } // Skip skips only one json value, and returns first non-blank character position and its ending position if it is valid. diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/api/decoder_amd64.go b/vendor/github.com/bytedance/sonic/internal/decoder/api/decoder_amd64.go new file mode 100644 index 000000000..4e1c3f42c --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/api/decoder_amd64.go @@ -0,0 +1,38 @@ +//go:build go1.17 && !go1.24 +// +build go1.17,!go1.24 + +/* + * 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 api + +import ( + "github.com/bytedance/sonic/internal/envs" + "github.com/bytedance/sonic/internal/decoder/jitdec" + "github.com/bytedance/sonic/internal/decoder/optdec" +) + +var ( + pretouchImpl = jitdec.Pretouch + decodeImpl = jitdec.Decode +) + + func init() { + if envs.UseOptDec { + pretouchImpl = optdec.Pretouch + decodeImpl = optdec.Decode + } + } diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/api/decoder_arm64.go b/vendor/github.com/bytedance/sonic/internal/decoder/api/decoder_arm64.go new file mode 100644 index 000000000..65a9478b4 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/api/decoder_arm64.go @@ -0,0 +1,38 @@ +// +build go1.17,!go1.24 + +/* + * 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 api + +import ( + `github.com/bytedance/sonic/internal/decoder/optdec` + `github.com/bytedance/sonic/internal/envs` +) + +var ( + pretouchImpl = optdec.Pretouch + decodeImpl = optdec.Decode +) + + +func init() { + // whe in aarch64. we enable all optimize + envs.EnableOptDec() + envs.EnableFastMap() +} + + diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/stream.go b/vendor/github.com/bytedance/sonic/internal/decoder/api/stream.go similarity index 60% rename from vendor/github.com/bytedance/sonic/internal/decoder/stream.go rename to vendor/github.com/bytedance/sonic/internal/decoder/api/stream.go index a3716435a..8a8102dd5 100644 --- a/vendor/github.com/bytedance/sonic/internal/decoder/stream.go +++ b/vendor/github.com/bytedance/sonic/internal/decoder/api/stream.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package decoder +package api import ( `bytes` @@ -23,11 +23,12 @@ import ( `github.com/bytedance/sonic/internal/native` `github.com/bytedance/sonic/internal/native/types` + `github.com/bytedance/sonic/internal/rt` `github.com/bytedance/sonic/option` ) var ( - minLeftBufferShift uint = 1 + minLeftBufferShift uint = 1 ) // StreamDecoder is the decoder context object for streaming input. @@ -46,6 +47,12 @@ var bufPool = sync.Pool{ }, } +func freeBytes(buf []byte) { + if rt.CanSizeResue(cap(buf)) { + bufPool.Put(buf[:0]) + } +} + // NewStreamDecoder adapts to encoding/json.NewDecoder API. // // NewStreamDecoder returns a new decoder that reads from r. @@ -58,90 +65,53 @@ func NewStreamDecoder(r io.Reader) *StreamDecoder { // Either io error from underlying io.Reader (except io.EOF) // or syntax error from data will be recorded and stop subsequently decoding. func (self *StreamDecoder) Decode(val interface{}) (err error) { - if self.err != nil { - return self.err - } - - var buf = self.buf[self.scanp:] - var p = 0 - var recycle bool - if cap(buf) == 0 { - buf = bufPool.Get().([]byte) - recycle = true - } - - var first = true - var repeat = true - -read_more: - for { - l := len(buf) - realloc(&buf) - n, err := self.r.Read(buf[l:cap(buf)]) - buf = buf[:l+n] - if err != nil { - repeat = false - if err == io.EOF { - if len(buf) == 0 { - return err - } - break - } - self.err = err - return err - } - if n > 0 || first { - break - } - } - first = false - - l := len(buf) - if l > 0 { - self.Decoder.Reset(string(buf)) - - var x int - if ret := native.SkipOneFast(&self.s, &x); ret < 0 { - if repeat { - goto read_more + // read more data into buf + if self.More() { + var s = self.scanp + try_skip: + var e = len(self.buf) + var src = rt.Mem2Str(self.buf[s:e]) + // try skip + var x = 0; + if y := native.SkipOneFast(&src, &x); y < 0 { + if self.readMore() { + goto try_skip } else { - err = SyntaxError{x, self.s, types.ParsingError(-ret), ""} - self.err = err + err = SyntaxError{e, self.s, types.ParsingError(-s), ""} + self.setErr(err) return } + } else { + s = y + s + e = x + s } - + + // must copy string here for safety + self.Decoder.Reset(string(self.buf[s:e])) err = self.Decoder.Decode(val) if err != nil { - self.err = err + self.setErr(err) + return } - p = self.Decoder.Pos() - self.scanned += int64(p) - self.scanp = 0 - } - - if l > p { - // remain undecoded bytes, so copy them into self.buf - self.buf = append(self.buf[:0], buf[p:]...) - } else { - self.buf = nil - recycle = true - } + self.scanp = e + _, empty := self.scan() + if empty { + // no remain valid bytes, thus we just recycle buffer + mem := self.buf + self.buf = nil + freeBytes(mem) + } else { + // remain undecoded bytes, move them onto head + n := copy(self.buf, self.buf[self.scanp:]) + self.buf = self.buf[:n] + } - if recycle { - buf = buf[:0] - bufPool.Put(buf) - } - return err -} + self.scanned += int64(self.scanp) + self.scanp = 0 + } -func (self StreamDecoder) repeatable(err error) bool { - if ee, ok := err.(SyntaxError); ok && - (ee.Code == types.ERR_EOF || (ee.Code == types.ERR_INVALID_CHAR && self.i >= len(self.s)-1)) { - return true - } - return false + return self.err } // InputOffset returns the input stream byte offset of the current decoder position. @@ -166,28 +136,72 @@ func (self *StreamDecoder) More() bool { return err == nil && c != ']' && c != '}' } +// More reports whether there is another element in the +// current array or object being parsed. +func (self *StreamDecoder) readMore() bool { + if self.err != nil { + return false + } + + var err error + var n int + for { + // Grow buffer if not large enough. + l := len(self.buf) + realloc(&self.buf) + + n, err = self.r.Read(self.buf[l:cap(self.buf)]) + self.buf = self.buf[: l+n] + + self.scanp = l + _, empty := self.scan() + if !empty { + return true + } + + // buffer has been scanned, now report any error + if err != nil { + self.setErr(err) + return false + } + } +} + +func (self *StreamDecoder) setErr(err error) { + self.err = err + mem := self.buf[:0] + self.buf = nil + freeBytes(mem) +} + func (self *StreamDecoder) peek() (byte, error) { var err error for { - for i := self.scanp; i < len(self.buf); i++ { - c := self.buf[i] - if isSpace(c) { - continue - } - self.scanp = i - return c, nil + c, empty := self.scan() + if !empty { + return byte(c), nil } // buffer has been scanned, now report any error if err != nil { - if err != io.EOF { - self.err = err - } + self.setErr(err) return 0, err } err = self.refill() } } +func (self *StreamDecoder) scan() (byte, bool) { + for i := self.scanp; i < len(self.buf); i++ { + c := self.buf[i] + if isSpace(c) { + continue + } + self.scanp = i + return c, false + } + return 0, true +} + func isSpace(c byte) bool { return types.SPACE_MASK & (1 << c) != 0 } @@ -212,17 +226,23 @@ func (self *StreamDecoder) refill() error { return err } -func realloc(buf *[]byte) { +func realloc(buf *[]byte) bool { l := uint(len(*buf)) c := uint(cap(*buf)) + if c == 0 { + *buf = bufPool.Get().([]byte) + return true + } if c - l <= c >> minLeftBufferShift { e := l+(l>>minLeftBufferShift) - if e < option.DefaultDecoderBufferSize { - e = option.DefaultDecoderBufferSize + if e <= c { + e = c*2 } tmp := make([]byte, l, e) copy(tmp, *buf) *buf = tmp + return true } + return false } diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/asm_stubs_amd64_go116.go b/vendor/github.com/bytedance/sonic/internal/decoder/asm_stubs_amd64_go116.go deleted file mode 100644 index 4c4c850ac..000000000 --- a/vendor/github.com/bytedance/sonic/internal/decoder/asm_stubs_amd64_go116.go +++ /dev/null @@ -1,130 +0,0 @@ -// +build go1.16,!go1.17 - -// Copyright 2023 CloudWeGo Authors -// -// 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 ( - `strconv` - _ `unsafe` - - `github.com/bytedance/sonic/internal/jit` - `github.com/bytedance/sonic/internal/rt` - `github.com/twitchyliquid64/golang-asm/obj` - `github.com/twitchyliquid64/golang-asm/obj/x86` -) - -var _runtime_writeBarrier uintptr = rt.GcwbAddr() - -//go:linkname gcWriteBarrierAX runtime.gcWriteBarrier -func gcWriteBarrierAX() - -var ( - _V_writeBarrier = jit.Imm(int64(_runtime_writeBarrier)) - - _F_gcWriteBarrierAX = jit.Func(gcWriteBarrierAX) -) - -func (self *_Assembler) WritePtrAX(i int, rec obj.Addr, saveDI bool) { - self.Emit("MOVQ", _V_writeBarrier, _R10) - self.Emit("CMPL", jit.Ptr(_R10, 0), jit.Imm(0)) - self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}") - if saveDI { - self.save(_DI) - } - self.Emit("LEAQ", rec, _DI) - self.Emit("MOVQ", _F_gcWriteBarrierAX, _R10) // MOVQ ${fn}, AX - self.Rjmp("CALL", _R10) - if saveDI { - self.load(_DI) - } - self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}") - self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}") - self.Emit("MOVQ", _AX, rec) - self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}") -} - -func (self *_Assembler) WriteRecNotAX(i int, ptr obj.Addr, rec obj.Addr, saveDI bool, saveAX bool) { - if rec.Reg == x86.REG_AX || rec.Index == x86.REG_AX { - panic("rec contains AX!") - } - self.Emit("MOVQ", _V_writeBarrier, _R10) - self.Emit("CMPL", jit.Ptr(_R10, 0), jit.Imm(0)) - self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}") - if saveAX { - self.Emit("XCHGQ", ptr, _AX) - } else { - self.Emit("MOVQ", ptr, _AX) - } - if saveDI { - self.save(_DI) - } - self.Emit("LEAQ", rec, _DI) - self.Emit("MOVQ", _F_gcWriteBarrierAX, _R10) // MOVQ ${fn}, AX - self.Rjmp("CALL", _R10) - if saveDI { - self.load(_DI) - } - if saveAX { - self.Emit("XCHGQ", ptr, _AX) - } - self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}") - self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}") - self.Emit("MOVQ", ptr, rec) - self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}") -} - - -func (self *_ValueDecoder) WritePtrAX(i int, rec obj.Addr, saveDI bool) { - self.Emit("MOVQ", _V_writeBarrier, _R10) - self.Emit("CMPL", jit.Ptr(_R10, 0), jit.Imm(0)) - self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}") - if saveDI { - self.save(_DI) - } - self.Emit("LEAQ", rec, _DI) - self.Emit("MOVQ", _F_gcWriteBarrierAX, _R10) // MOVQ ${fn}, AX - self.Rjmp("CALL", _R10) - if saveDI { - self.load(_DI) - } - self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}") - self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}") - self.Emit("MOVQ", _AX, rec) - self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}") -} - -func (self *_ValueDecoder) WriteRecNotAX(i int, ptr obj.Addr, rec obj.Addr, saveDI bool) { - if rec.Reg == x86.REG_AX || rec.Index == x86.REG_AX { - panic("rec contains AX!") - } - self.Emit("MOVQ", _V_writeBarrier, _R10) - self.Emit("CMPL", jit.Ptr(_R10, 0), jit.Imm(0)) - self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}") - self.Emit("MOVQ", ptr, _AX) - if saveDI { - self.save(_DI) - } - self.Emit("LEAQ", rec, _DI) - self.Emit("MOVQ", _F_gcWriteBarrierAX, _R10) // MOVQ ${fn}, AX - self.Rjmp("CALL", _R10) - if saveDI { - self.load(_DI) - } - self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}") - self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}") - self.Emit("MOVQ", ptr, rec) - self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}") -} diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/assembler_stkabi_amd64.go b/vendor/github.com/bytedance/sonic/internal/decoder/assembler_stkabi_amd64.go deleted file mode 100644 index 57a38b420..000000000 --- a/vendor/github.com/bytedance/sonic/internal/decoder/assembler_stkabi_amd64.go +++ /dev/null @@ -1,1949 +0,0 @@ -// +build go1.16,!go1.17 - -/* - * 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 ( - `encoding/json` - `fmt` - `math` - `reflect` - `unsafe` - - `github.com/bytedance/sonic/internal/caching` - `github.com/bytedance/sonic/internal/jit` - `github.com/bytedance/sonic/internal/native` - `github.com/bytedance/sonic/internal/native/types` - `github.com/bytedance/sonic/internal/rt` - `github.com/twitchyliquid64/golang-asm/obj` -) - -/** Register Allocations - * - * State Registers: - * - * %rbx : stack base - * %r12 : input pointer - * %r13 : input length - * %r14 : input cursor - * %r15 : value pointer - * - * Error Registers: - * - * %r10 : error type register - * %r11 : error pointer register - */ - -/** Function Prototype & Stack Map - * - * 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) - * ic : 16(FP) - * vp : 24(FP) - * sb : 32(FP) - * fv : 40(FP) - * sv : 56(FP) - * err.vt : 72(FP) - * err.vp : 80(FP) - */ - -const ( - _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 = 144 // 144 bytes for local variables -) - -const ( - _FP_offs = _FP_fargs + _FP_saves + _FP_locals - _FP_size = _FP_offs + 8 // 8 bytes for the parent frame pointer - _FP_base = _FP_size + 8 // 8 bytes for the return address -) - -const ( - _IM_null = 0x6c6c756e // 'null' - _IM_true = 0x65757274 // 'true' - _IM_alse = 0x65736c61 // 'alse' ('false' without the 'f') -) - -const ( - _BM_space = (1 << ' ') | (1 << '\t') | (1 << '\r') | (1 << '\n') -) - -const ( - _MODE_JSON = 1 << 3 // base64 mode -) - -const ( - _LB_error = "_error" - _LB_im_error = "_im_error" - _LB_eof_error = "_eof_error" - _LB_type_error = "_type_error" - _LB_field_error = "_field_error" - _LB_range_error = "_range_error" - _LB_stack_error = "_stack_error" - _LB_base64_error = "_base64_error" - _LB_unquote_error = "_unquote_error" - _LB_parsing_error = "_parsing_error" - _LB_parsing_error_v = "_parsing_error_v" - _LB_mismatch_error = "_mismatch_error" -) - -const ( - _LB_char_0_error = "_char_0_error" - _LB_char_1_error = "_char_1_error" - _LB_char_2_error = "_char_2_error" - _LB_char_3_error = "_char_3_error" - _LB_char_4_error = "_char_4_error" - _LB_char_m2_error = "_char_m2_error" - _LB_char_m3_error = "_char_m3_error" -) - -const ( - _LB_skip_one = "_skip_one" - _LB_skip_key_value = "_skip_key_value" -) - -var ( - _AX = jit.Reg("AX") - _CX = jit.Reg("CX") - _DX = jit.Reg("DX") - _DI = jit.Reg("DI") - _SI = jit.Reg("SI") - _BP = jit.Reg("BP") - _SP = jit.Reg("SP") - _R8 = jit.Reg("R8") - _R9 = jit.Reg("R9") - _X0 = jit.Reg("X0") - _X1 = jit.Reg("X1") -) - -var ( - _ST = jit.Reg("BX") - _IP = jit.Reg("R12") - _IL = jit.Reg("R13") - _IC = jit.Reg("R14") - _VP = jit.Reg("R15") -) - -var ( - _R10 = jit.Reg("R10") // used for gcWriteBarrier - _DF = jit.Reg("R10") // reuse R10 in generic decoder for flags - _ET = jit.Reg("R10") - _EP = jit.Reg("R11") -) - -var ( - _ARG_s = _ARG_sp - _ARG_sp = jit.Ptr(_SP, _FP_base) - _ARG_sl = jit.Ptr(_SP, _FP_base + 8) - _ARG_ic = jit.Ptr(_SP, _FP_base + 16) - _ARG_vp = jit.Ptr(_SP, _FP_base + 24) - _ARG_sb = jit.Ptr(_SP, _FP_base + 32) - _ARG_fv = jit.Ptr(_SP, _FP_base + 40) -) - -var ( - _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_st = _VAR_st_Vt - _VAR_sr = jit.Ptr(_SP, _FP_fargs + _FP_saves) -) - - -var ( - _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_st_Db = jit.Ptr(_SP, _FP_fargs + _FP_saves + 32) - _VAR_st_Dc = jit.Ptr(_SP, _FP_fargs + _FP_saves + 40) -) - -var ( - _VAR_ss_AX = jit.Ptr(_SP, _FP_fargs + _FP_saves + 48) - _VAR_ss_CX = jit.Ptr(_SP, _FP_fargs + _FP_saves + 56) - _VAR_ss_SI = jit.Ptr(_SP, _FP_fargs + _FP_saves + 64) - _VAR_ss_R8 = jit.Ptr(_SP, _FP_fargs + _FP_saves + 72) - _VAR_ss_R9 = jit.Ptr(_SP, _FP_fargs + _FP_saves + 80) -) - -var ( - _VAR_bs_p = jit.Ptr(_SP, _FP_fargs + _FP_saves + 88) - _VAR_bs_n = jit.Ptr(_SP, _FP_fargs + _FP_saves + 96) - _VAR_bs_LR = jit.Ptr(_SP, _FP_fargs + _FP_saves + 104) -) - -var _VAR_fl = jit.Ptr(_SP, _FP_fargs + _FP_saves + 112) - -var ( - _VAR_et = jit.Ptr(_SP, _FP_fargs + _FP_saves + 120) // save dismatched type - _VAR_ic = jit.Ptr(_SP, _FP_fargs + _FP_saves + 128) // save dismatched position - _VAR_pc = jit.Ptr(_SP, _FP_fargs + _FP_saves + 136) // save skip return pc -) - -type _Assembler struct { - jit.BaseAssembler - p _Program - name string -} - -func newAssembler(p _Program) *_Assembler { - return new(_Assembler).Init(p) -} - -/** Assembler Interface **/ - -func (self *_Assembler) Load() _Decoder { - return ptodec(self.BaseAssembler.Load("decode_"+self.name, _FP_size, _FP_args, argPtrs, localPtrs)) -} - -func (self *_Assembler) Init(p _Program) *_Assembler { - self.p = p - self.BaseAssembler.Init(self.compile) - return self -} - -func (self *_Assembler) compile() { - self.prologue() - self.instrs() - self.epilogue() - self.copy_string() - self.escape_string() - self.escape_string_twice() - self.skip_one() - self.skip_key_value() - self.mismatch_error() - self.type_error() - self.field_error() - self.range_error() - self.stack_error() - self.base64_error() - self.parsing_error() -} - -/** Assembler Stages **/ - -var _OpFuncTab = [256]func(*_Assembler, *_Instr) { - _OP_any : (*_Assembler)._asm_OP_any, - _OP_dyn : (*_Assembler)._asm_OP_dyn, - _OP_str : (*_Assembler)._asm_OP_str, - _OP_bin : (*_Assembler)._asm_OP_bin, - _OP_bool : (*_Assembler)._asm_OP_bool, - _OP_num : (*_Assembler)._asm_OP_num, - _OP_i8 : (*_Assembler)._asm_OP_i8, - _OP_i16 : (*_Assembler)._asm_OP_i16, - _OP_i32 : (*_Assembler)._asm_OP_i32, - _OP_i64 : (*_Assembler)._asm_OP_i64, - _OP_u8 : (*_Assembler)._asm_OP_u8, - _OP_u16 : (*_Assembler)._asm_OP_u16, - _OP_u32 : (*_Assembler)._asm_OP_u32, - _OP_u64 : (*_Assembler)._asm_OP_u64, - _OP_f32 : (*_Assembler)._asm_OP_f32, - _OP_f64 : (*_Assembler)._asm_OP_f64, - _OP_unquote : (*_Assembler)._asm_OP_unquote, - _OP_nil_1 : (*_Assembler)._asm_OP_nil_1, - _OP_nil_2 : (*_Assembler)._asm_OP_nil_2, - _OP_nil_3 : (*_Assembler)._asm_OP_nil_3, - _OP_deref : (*_Assembler)._asm_OP_deref, - _OP_index : (*_Assembler)._asm_OP_index, - _OP_is_null : (*_Assembler)._asm_OP_is_null, - _OP_is_null_quote : (*_Assembler)._asm_OP_is_null_quote, - _OP_map_init : (*_Assembler)._asm_OP_map_init, - _OP_map_key_i8 : (*_Assembler)._asm_OP_map_key_i8, - _OP_map_key_i16 : (*_Assembler)._asm_OP_map_key_i16, - _OP_map_key_i32 : (*_Assembler)._asm_OP_map_key_i32, - _OP_map_key_i64 : (*_Assembler)._asm_OP_map_key_i64, - _OP_map_key_u8 : (*_Assembler)._asm_OP_map_key_u8, - _OP_map_key_u16 : (*_Assembler)._asm_OP_map_key_u16, - _OP_map_key_u32 : (*_Assembler)._asm_OP_map_key_u32, - _OP_map_key_u64 : (*_Assembler)._asm_OP_map_key_u64, - _OP_map_key_f32 : (*_Assembler)._asm_OP_map_key_f32, - _OP_map_key_f64 : (*_Assembler)._asm_OP_map_key_f64, - _OP_map_key_str : (*_Assembler)._asm_OP_map_key_str, - _OP_map_key_utext : (*_Assembler)._asm_OP_map_key_utext, - _OP_map_key_utext_p : (*_Assembler)._asm_OP_map_key_utext_p, - _OP_array_skip : (*_Assembler)._asm_OP_array_skip, - _OP_array_clear : (*_Assembler)._asm_OP_array_clear, - _OP_array_clear_p : (*_Assembler)._asm_OP_array_clear_p, - _OP_slice_init : (*_Assembler)._asm_OP_slice_init, - _OP_slice_append : (*_Assembler)._asm_OP_slice_append, - _OP_object_skip : (*_Assembler)._asm_OP_object_skip, - _OP_object_next : (*_Assembler)._asm_OP_object_next, - _OP_struct_field : (*_Assembler)._asm_OP_struct_field, - _OP_unmarshal : (*_Assembler)._asm_OP_unmarshal, - _OP_unmarshal_p : (*_Assembler)._asm_OP_unmarshal_p, - _OP_unmarshal_text : (*_Assembler)._asm_OP_unmarshal_text, - _OP_unmarshal_text_p : (*_Assembler)._asm_OP_unmarshal_text_p, - _OP_lspace : (*_Assembler)._asm_OP_lspace, - _OP_match_char : (*_Assembler)._asm_OP_match_char, - _OP_check_char : (*_Assembler)._asm_OP_check_char, - _OP_load : (*_Assembler)._asm_OP_load, - _OP_save : (*_Assembler)._asm_OP_save, - _OP_drop : (*_Assembler)._asm_OP_drop, - _OP_drop_2 : (*_Assembler)._asm_OP_drop_2, - _OP_recurse : (*_Assembler)._asm_OP_recurse, - _OP_goto : (*_Assembler)._asm_OP_goto, - _OP_switch : (*_Assembler)._asm_OP_switch, - _OP_check_char_0 : (*_Assembler)._asm_OP_check_char_0, - _OP_dismatch_err : (*_Assembler)._asm_OP_dismatch_err, - _OP_go_skip : (*_Assembler)._asm_OP_go_skip, - _OP_add : (*_Assembler)._asm_OP_add, - _OP_check_empty : (*_Assembler)._asm_OP_check_empty, -} - -func (self *_Assembler) instr(v *_Instr) { - if fn := _OpFuncTab[v.op()]; fn != nil { - fn(self, v) - } else { - panic(fmt.Sprintf("invalid opcode: %d", v.op())) - } -} - -func (self *_Assembler) instrs() { - for i, v := range self.p { - self.Mark(i) - self.instr(&v) - self.debug_instr(i, &v) - } -} - -func (self *_Assembler) epilogue() { - self.Mark(len(self.p)) - self.Emit("XORL", _EP, _EP) // XORL EP, EP - self.Emit("MOVQ", _VAR_et, _ET) // MOVQ VAR_et, ET - self.Emit("TESTQ", _ET, _ET) // TESTQ ET, ET - self.Sjmp("JNZ", _LB_mismatch_error) // JNZ _LB_mismatch_error - self.Link(_LB_error) // _error: - self.Emit("MOVQ", _IC, _RET_rc) // MOVQ IC, rc<>+40(FP) - self.Emit("MOVQ", _ET, _RET_et) // MOVQ ET, et<>+48(FP) - self.Emit("MOVQ", _EP, _RET_ep) // MOVQ EP, ep<>+56(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 -} - -func (self *_Assembler) prologue() { - self.Emit("SUBQ", jit.Imm(_FP_size), _SP) // SUBQ $_FP_size, SP - self.Emit("MOVQ", _BP, jit.Ptr(_SP, _FP_offs)) // MOVQ BP, _FP_offs(SP) - self.Emit("LEAQ", jit.Ptr(_SP, _FP_offs), _BP) // LEAQ _FP_offs(SP), BP - self.Emit("MOVQ", _ARG_sp, _IP) // MOVQ s.p<>+0(FP), IP - self.Emit("MOVQ", _ARG_sl, _IL) // MOVQ s.l<>+8(FP), IL - self.Emit("MOVQ", _ARG_ic, _IC) // MOVQ ic<>+16(FP), IC - self.Emit("MOVQ", _ARG_vp, _VP) // MOVQ vp<>+24(FP), VP - self.Emit("MOVQ", _ARG_sb, _ST) // MOVQ vp<>+32(FP), ST - // initialize digital buffer first - self.Emit("MOVQ", jit.Imm(_MaxDigitNums), _VAR_st_Dc) // MOVQ $_MaxDigitNums, ss.Dcap - self.Emit("LEAQ", jit.Ptr(_ST, _DbufOffset), _AX) // LEAQ _DbufOffset(ST), AX - self.Emit("MOVQ", _AX, _VAR_st_Db) // MOVQ AX, ss.Dbuf - self.Emit("XORL", _AX, _AX) // XORL AX, AX - self.Emit("MOVQ", _AX, _VAR_et) // MOVQ AX, ss.Dp -} - -/** Function Calling Helpers **/ - -var _REG_go = []obj.Addr { - _ST, - _VP, - _IP, - _IL, - _IC, -} - -func (self *_Assembler) save(r ...obj.Addr) { - for i, v := range r { - if i > _FP_saves / 8 - 1 { - panic("too many registers to save") - } else { - self.Emit("MOVQ", v, jit.Ptr(_SP, _FP_fargs + int64(i) * 8)) - } - } -} - -func (self *_Assembler) load(r ...obj.Addr) { - for i, v := range r { - if i > _FP_saves / 8 - 1 { - panic("too many registers to load") - } else { - self.Emit("MOVQ", jit.Ptr(_SP, _FP_fargs + int64(i) * 8), v) - } - } -} - -func (self *_Assembler) call(fn obj.Addr) { - self.Emit("MOVQ", fn, _AX) // MOVQ ${fn}, AX - self.Rjmp("CALL", _AX) // CALL AX -} - -func (self *_Assembler) call_go(fn obj.Addr) { - self.save(_REG_go...) // SAVE $REG_go - self.call(fn) // CALL ${fn} - self.load(_REG_go...) // LOAD $REG_go -} - -func (self *_Assembler) call_sf(fn obj.Addr) { - self.Emit("LEAQ", _ARG_s, _DI) // LEAQ s<>+0(FP), DI - self.Emit("MOVQ", _IC, _ARG_ic) // MOVQ IC, ic<>+16(FP) - self.Emit("LEAQ", _ARG_ic, _SI) // LEAQ ic<>+16(FP), SI - self.Emit("LEAQ", jit.Ptr(_ST, _FsmOffset), _DX) // LEAQ _FsmOffset(ST), DX - self.Emit("MOVQ", _ARG_fv, _CX) - self.call(fn) // CALL ${fn} - self.Emit("MOVQ", _ARG_ic, _IC) // MOVQ ic<>+16(FP), IC -} - -func (self *_Assembler) call_vf(fn obj.Addr) { - self.Emit("LEAQ", _ARG_s, _DI) // LEAQ s<>+0(FP), DI - self.Emit("MOVQ", _IC, _ARG_ic) // MOVQ IC, ic<>+16(FP) - self.Emit("LEAQ", _ARG_ic, _SI) // LEAQ ic<>+16(FP), SI - self.Emit("LEAQ", _VAR_st, _DX) // LEAQ st, DX - self.call(fn) // CALL ${fn} - self.Emit("MOVQ", _ARG_ic, _IC) // MOVQ ic<>+16(FP), IC -} - -/** Assembler Error Handlers **/ - -var ( - _F_convT64 = jit.Func(convT64) - _F_error_wrap = jit.Func(error_wrap) - _F_error_type = jit.Func(error_type) - _F_error_field = jit.Func(error_field) - _F_error_value = jit.Func(error_value) - _F_error_mismatch = jit.Func(error_mismatch) -) - -var ( - _I_int8 , _T_int8 = rtype(reflect.TypeOf(int8(0))) - _I_int16 , _T_int16 = rtype(reflect.TypeOf(int16(0))) - _I_int32 , _T_int32 = rtype(reflect.TypeOf(int32(0))) - _I_uint8 , _T_uint8 = rtype(reflect.TypeOf(uint8(0))) - _I_uint16 , _T_uint16 = rtype(reflect.TypeOf(uint16(0))) - _I_uint32 , _T_uint32 = rtype(reflect.TypeOf(uint32(0))) - _I_float32 , _T_float32 = rtype(reflect.TypeOf(float32(0))) -) - -var ( - _T_error = rt.UnpackType(errorType) - _I_base64_CorruptInputError = jit.Itab(_T_error, base64CorruptInputError) -) - -var ( - _V_stackOverflow = jit.Imm(int64(uintptr(unsafe.Pointer(&stackOverflow)))) - _I_json_UnsupportedValueError = jit.Itab(_T_error, reflect.TypeOf(new(json.UnsupportedValueError))) - _I_json_MismatchTypeError = jit.Itab(_T_error, reflect.TypeOf(new(MismatchTypeError))) -) - -func (self *_Assembler) type_error() { - self.Link(_LB_type_error) // _type_error: - self.Emit("MOVQ", _ET, jit.Ptr(_SP, 0)) // MOVQ ET, (SP) - self.call_go(_F_error_type) // CALL_GO error_type - self.Emit("MOVQ", jit.Ptr(_SP, 8), _ET) // MOVQ 8(SP), ET - self.Emit("MOVQ", jit.Ptr(_SP, 16), _EP) // MOVQ 16(SP), EP - self.Sjmp("JMP" , _LB_error) // JMP _error -} - - -func (self *_Assembler) mismatch_error() { - self.Link(_LB_mismatch_error) // _type_error: - self.Emit("MOVQ", _VAR_et, _ET) // MOVQ _VAR_et, ET - self.Emit("MOVQ", _VAR_ic, _EP) // MOVQ _VAR_ic, EP - self.Emit("MOVQ", _I_json_MismatchTypeError, _AX) // MOVQ _I_json_MismatchTypeError, AX - self.Emit("CMPQ", _ET, _AX) // CMPQ ET, AX - self.Sjmp("JE" , _LB_error) // JE _LB_error - self.Emit("MOVQ", _ARG_sp, _AX) - self.Emit("MOVQ", _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP) - self.Emit("MOVQ", _ARG_sl, _CX) - self.Emit("MOVQ", _CX, jit.Ptr(_SP, 8)) // MOVQ CX, 8(SP) - self.Emit("MOVQ", _VAR_ic, _AX) - self.Emit("MOVQ", _AX, jit.Ptr(_SP, 16)) // MOVQ AX, 16(SP) - self.Emit("MOVQ", _VAR_et, _CX) - self.Emit("MOVQ", _CX, jit.Ptr(_SP, 24)) // MOVQ CX, 24(SP) - self.call_go(_F_error_mismatch) // CALL_GO error_type - self.Emit("MOVQ", jit.Ptr(_SP, 32), _ET) // MOVQ 32(SP), ET - self.Emit("MOVQ", jit.Ptr(_SP, 40), _EP) // MOVQ 40(SP), EP - self.Sjmp("JMP" , _LB_error) // JMP _error -} - -func (self *_Assembler) _asm_OP_dismatch_err(p *_Instr) { - self.Emit("MOVQ", _IC, _VAR_ic) - self.Emit("MOVQ", jit.Type(p.vt()), _ET) - self.Emit("MOVQ", _ET, _VAR_et) -} - -func (self *_Assembler) _asm_OP_go_skip(p *_Instr) { - self.Byte(0x4c, 0x8d, 0x0d) // LEAQ (PC), R9 - self.Xref(p.vi(), 4) - self.Emit("MOVQ", _R9, _VAR_pc) - self.Sjmp("JMP" , _LB_skip_one) // JMP _skip_one -} - -func (self *_Assembler) skip_one() { - self.Link(_LB_skip_one) // _skip: - self.Emit("MOVQ", _VAR_ic, _IC) // MOVQ _VAR_ic, IC - self.call_sf(_F_skip_one) // CALL_SF skip_one - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JS" , _LB_parsing_error_v) // JS _parse_error_v - self.Emit("MOVQ" , _VAR_pc, _R9) // MOVQ pc, R9 - self.Rjmp("JMP" , _R9) // JMP (R9) -} - - -func (self *_Assembler) skip_key_value() { - self.Link(_LB_skip_key_value) // _skip: - // skip the key - self.Emit("MOVQ", _VAR_ic, _IC) // MOVQ _VAR_ic, IC - self.call_sf(_F_skip_one) // CALL_SF skip_one - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JS" , _LB_parsing_error_v) // JS _parse_error_v - // match char ':' - self.lspace("_global_1") - self.Emit("CMPB", jit.Sib(_IP, _IC, 1, 0), jit.Imm(':')) - self.Sjmp("JNE" , _LB_parsing_error_v) // JNE _parse_error_v - self.Emit("ADDQ", jit.Imm(1), _IC) // ADDQ $1, IC - self.lspace("_global_2") - // skip the value - self.call_sf(_F_skip_one) // CALL_SF skip_one - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JS" , _LB_parsing_error_v) // JS _parse_error_v - // jump back to specified address - self.Emit("MOVQ" , _VAR_pc, _R9) // MOVQ pc, R9 - self.Rjmp("JMP" , _R9) // JMP (R9) -} - -func (self *_Assembler) field_error() { - self.Link(_LB_field_error) // _field_error: - self.Emit("MOVOU", _VAR_sv, _X0) // MOVOU sv, X0 - self.Emit("MOVOU", _X0, jit.Ptr(_SP, 0)) // MOVOU X0, (SP) - self.call_go(_F_error_field) // CALL_GO error_field - self.Emit("MOVQ" , jit.Ptr(_SP, 16), _ET) // MOVQ 16(SP), ET - self.Emit("MOVQ" , jit.Ptr(_SP, 24), _EP) // MOVQ 24(SP), EP - self.Sjmp("JMP" , _LB_error) // JMP _error -} - -func (self *_Assembler) range_error() { - self.Link(_LB_range_error) // _range_error: - self.slice_from(_VAR_st_Ep, 0) // SLICE st.Ep, $0 - self.Emit("MOVQ", _DI, jit.Ptr(_SP, 0)) // MOVQ DI, (SP) - self.Emit("MOVQ", _SI, jit.Ptr(_SP, 8)) // MOVQ SI, 8(SP) - self.Emit("MOVQ", _ET, jit.Ptr(_SP, 16)) // MOVQ ET, 16(SP) - self.Emit("MOVQ", _EP, jit.Ptr(_SP, 24)) // MOVQ EP, 24(SP) - self.call_go(_F_error_value) // CALL_GO error_value - self.Emit("MOVQ", jit.Ptr(_SP, 32), _ET) // MOVQ 32(SP), ET - self.Emit("MOVQ", jit.Ptr(_SP, 40), _EP) // MOVQ 40(SP), EP - self.Sjmp("JMP" , _LB_error) // JMP _error -} - -func (self *_Assembler) stack_error() { - self.Link(_LB_stack_error) // _stack_error: - self.Emit("MOVQ", _V_stackOverflow, _EP) // MOVQ ${_V_stackOverflow}, EP - self.Emit("MOVQ", _I_json_UnsupportedValueError, _ET) // MOVQ ${_I_json_UnsupportedValueError}, ET - self.Sjmp("JMP" , _LB_error) // JMP _error -} - -func (self *_Assembler) base64_error() { - self.Link(_LB_base64_error) - self.Emit("NEGQ", _AX) // NEGQ AX - self.Emit("SUBQ", jit.Imm(1), _AX) // SUBQ $1, AX - self.Emit("MOVQ", _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP) - self.call_go(_F_convT64) // CALL_GO convT64 - self.Emit("MOVQ", jit.Ptr(_SP, 8), _EP) // MOVQ 8(SP), EP - self.Emit("MOVQ", _I_base64_CorruptInputError, _ET) // MOVQ ${itab(base64.CorruptInputError)}, ET - self.Sjmp("JMP" , _LB_error) // JMP _error -} - -func (self *_Assembler) parsing_error() { - self.Link(_LB_eof_error) // _eof_error: - self.Emit("MOVQ" , _IL, _IC) // MOVQ IL, IC - self.Emit("MOVL" , jit.Imm(int64(types.ERR_EOF)), _EP) // MOVL ${types.ERR_EOF}, EP - self.Sjmp("JMP" , _LB_parsing_error) // JMP _parsing_error - self.Link(_LB_unquote_error) // _unquote_error: - self.Emit("SUBQ" , _VAR_sr, _SI) // SUBQ sr, SI - self.Emit("SUBQ" , _SI, _IC) // SUBQ IL, IC - self.Link(_LB_parsing_error_v) // _parsing_error_v: - self.Emit("MOVQ" , _AX, _EP) // MOVQ AX, EP - self.Emit("NEGQ" , _EP) // NEGQ EP - self.Sjmp("JMP" , _LB_parsing_error) // JMP _parsing_error - self.Link(_LB_char_m3_error) // _char_m3_error: - self.Emit("SUBQ" , jit.Imm(1), _IC) // SUBQ $1, IC - self.Link(_LB_char_m2_error) // _char_m2_error: - self.Emit("SUBQ" , jit.Imm(2), _IC) // SUBQ $2, IC - self.Sjmp("JMP" , _LB_char_0_error) // JMP _char_0_error - self.Link(_LB_im_error) // _im_error: - self.Emit("CMPB" , _CX, jit.Sib(_IP, _IC, 1, 0)) // CMPB CX, (IP)(IC) - self.Sjmp("JNE" , _LB_char_0_error) // JNE _char_0_error - self.Emit("SHRL" , jit.Imm(8), _CX) // SHRL $8, CX - self.Emit("CMPB" , _CX, jit.Sib(_IP, _IC, 1, 1)) // CMPB CX, 1(IP)(IC) - self.Sjmp("JNE" , _LB_char_1_error) // JNE _char_1_error - self.Emit("SHRL" , jit.Imm(8), _CX) // SHRL $8, CX - self.Emit("CMPB" , _CX, jit.Sib(_IP, _IC, 1, 2)) // CMPB CX, 2(IP)(IC) - self.Sjmp("JNE" , _LB_char_2_error) // JNE _char_2_error - self.Sjmp("JMP" , _LB_char_3_error) // JNE _char_3_error - self.Link(_LB_char_4_error) // _char_4_error: - self.Emit("ADDQ" , jit.Imm(1), _IC) // ADDQ $1, IC - self.Link(_LB_char_3_error) // _char_3_error: - self.Emit("ADDQ" , jit.Imm(1), _IC) // ADDQ $1, IC - self.Link(_LB_char_2_error) // _char_2_error: - self.Emit("ADDQ" , jit.Imm(1), _IC) // ADDQ $1, IC - self.Link(_LB_char_1_error) // _char_1_error: - self.Emit("ADDQ" , jit.Imm(1), _IC) // ADDQ $1, IC - self.Link(_LB_char_0_error) // _char_0_error: - self.Emit("MOVL" , jit.Imm(int64(types.ERR_INVALID_CHAR)), _EP) // MOVL ${types.ERR_INVALID_CHAR}, EP - self.Link(_LB_parsing_error) // _parsing_error: - self.Emit("MOVOU", _ARG_s, _X0) // MOVOU s, X0 - self.Emit("MOVOU", _X0, jit.Ptr(_SP, 0)) // MOVOU X0, (SP) - self.Emit("MOVQ" , _IC, jit.Ptr(_SP, 16)) // MOVQ IC, 16(SP) - self.Emit("MOVQ" , _EP, jit.Ptr(_SP, 24)) // MOVQ EP, 24(SP) - self.call_go(_F_error_wrap) // CALL_GO error_wrap - self.Emit("MOVQ" , jit.Ptr(_SP, 32), _ET) // MOVQ 32(SP), ET - self.Emit("MOVQ" , jit.Ptr(_SP, 40), _EP) // MOVQ 40(SP), EP - self.Sjmp("JMP" , _LB_error) // JMP _error -} - -/** Memory Management Routines **/ - -var ( - _T_byte = jit.Type(byteType) - _F_mallocgc = jit.Func(mallocgc) -) - -func (self *_Assembler) malloc(nb obj.Addr, ret obj.Addr) { - self.Emit("XORL", _AX, _AX) // XORL AX, AX - self.Emit("MOVQ", _T_byte, _CX) // MOVQ ${type(byte)}, CX - self.Emit("MOVQ", nb, jit.Ptr(_SP, 0)) // MOVQ ${nb}, (SP) - self.Emit("MOVQ", _CX, jit.Ptr(_SP, 8)) // MOVQ CX, 8(SP) - self.Emit("MOVQ", _AX, jit.Ptr(_SP, 16)) // MOVQ AX, 16(SP) - self.call_go(_F_mallocgc) // CALL_GO mallocgc - self.Emit("MOVQ", jit.Ptr(_SP, 24), ret) // MOVQ 24(SP), ${ret} -} - -func (self *_Assembler) valloc(vt reflect.Type, ret obj.Addr) { - self.Emit("MOVQ", jit.Imm(int64(vt.Size())), _AX) // MOVQ ${vt.Size()}, AX - self.Emit("MOVQ", _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP) - self.Emit("MOVQ", jit.Type(vt), _AX) // MOVQ ${vt}, AX - self.Emit("MOVQ", _AX, jit.Ptr(_SP, 8)) // MOVQ AX, 8(SP) - self.Emit("MOVB", jit.Imm(1), jit.Ptr(_SP, 16)) // MOVB $1, 16(SP) - self.call_go(_F_mallocgc) // CALL_GO mallocgc - self.Emit("MOVQ", jit.Ptr(_SP, 24), ret) // MOVQ 24(SP), ${ret} -} - -func (self *_Assembler) vfollow(vt reflect.Type) { - self.Emit("MOVQ" , jit.Ptr(_VP, 0), _AX) // MOVQ (VP), AX - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JNZ" , "_end_{n}") // JNZ _end_{n} - self.valloc(vt, _AX) // VALLOC ${vt}, AX - self.WritePtrAX(1, jit.Ptr(_VP, 0), false) // MOVQ AX, (VP) - self.Link("_end_{n}") // _end_{n}: - self.Emit("MOVQ" , _AX, _VP) // MOVQ AX, VP -} - -/** Value Parsing Routines **/ - -var ( - _F_vstring = jit.Imm(int64(native.S_vstring)) - _F_vnumber = jit.Imm(int64(native.S_vnumber)) - _F_vsigned = jit.Imm(int64(native.S_vsigned)) - _F_vunsigned = jit.Imm(int64(native.S_vunsigned)) -) - -func (self *_Assembler) check_err(vt reflect.Type, pin string, pin2 int) { - self.Emit("MOVQ" , _VAR_st_Vt, _AX) // MOVQ st.Vt, AX - self.Emit("TESTQ", _AX, _AX) // CMPQ AX, ${native.V_STRING} - // try to skip the value - if vt != nil { - self.Sjmp("JNS" , "_check_err_{n}") // JNE _parsing_error_v - self.Emit("MOVQ", jit.Type(vt), _ET) - self.Emit("MOVQ", _ET, _VAR_et) - if pin2 != -1 { - self.Emit("SUBQ", jit.Imm(1), _BP) - self.Emit("MOVQ", _BP, _VAR_ic) - self.Byte(0x4c , 0x8d, 0x0d) // LEAQ (PC), R9 - self.Xref(pin2, 4) - self.Emit("MOVQ", _R9, _VAR_pc) - self.Sjmp("JMP" , _LB_skip_key_value) - } else { - self.Emit("MOVQ", _BP, _VAR_ic) - self.Byte(0x4c , 0x8d, 0x0d) // LEAQ (PC), R9 - self.Sref(pin, 4) - self.Emit("MOVQ", _R9, _VAR_pc) - self.Sjmp("JMP" , _LB_skip_one) - } - self.Link("_check_err_{n}") - } else { - self.Sjmp("JS" , _LB_parsing_error_v) // JNE _parsing_error_v - } -} - -func (self *_Assembler) check_eof(d int64) { - if d == 1 { - self.Emit("CMPQ", _IC, _IL) // CMPQ IC, IL - self.Sjmp("JAE" , _LB_eof_error) // JAE _eof_error - } else { - self.Emit("LEAQ", jit.Ptr(_IC, d), _AX) // LEAQ ${d}(IC), AX - self.Emit("CMPQ", _AX, _IL) // CMPQ AX, IL - self.Sjmp("JA" , _LB_eof_error) // JA _eof_error - } -} - -func (self *_Assembler) parse_string() { // parse_string has a validate flag params in the last - self.Emit("MOVQ", _ARG_fv, _CX) - self.call_vf(_F_vstring) - self.check_err(nil, "", -1) -} - -func (self *_Assembler) parse_number(vt reflect.Type, pin string, pin2 int) { - self.Emit("MOVQ", _IC, _BP) - self.call_vf(_F_vnumber) // call vnumber - self.check_err(vt, pin, pin2) -} - -func (self *_Assembler) parse_signed(vt reflect.Type, pin string, pin2 int) { - self.Emit("MOVQ", _IC, _BP) - self.call_vf(_F_vsigned) - self.check_err(vt, pin, pin2) -} - -func (self *_Assembler) parse_unsigned(vt reflect.Type, pin string, pin2 int) { - self.Emit("MOVQ", _IC, _BP) - self.call_vf(_F_vunsigned) - self.check_err(vt, pin, pin2) -} - -// Pointer: DI, Size: SI, Return: R9 -func (self *_Assembler) copy_string() { - self.Link("_copy_string") - self.Emit("MOVQ", _DI, _VAR_bs_p) - self.Emit("MOVQ", _SI, _VAR_bs_n) - self.Emit("MOVQ", _R9, _VAR_bs_LR) - self.malloc(_SI, _AX) - self.Emit("MOVQ", _AX, _VAR_sv_p) - self.Emit("MOVQ", _AX, jit.Ptr(_SP, 0)) - self.Emit("MOVQ", _VAR_bs_p, _DI) - self.Emit("MOVQ", _DI, jit.Ptr(_SP, 8)) - self.Emit("MOVQ", _VAR_bs_n, _SI) - self.Emit("MOVQ", _SI, jit.Ptr(_SP, 16)) - self.call_go(_F_memmove) - self.Emit("MOVQ", _VAR_sv_p, _DI) - self.Emit("MOVQ", _VAR_bs_n, _SI) - self.Emit("MOVQ", _VAR_bs_LR, _R9) - self.Rjmp("JMP", _R9) -} - -// Pointer: DI, Size: SI, Return: R9 -func (self *_Assembler) escape_string() { - self.Link("_escape_string") - self.Emit("MOVQ" , _DI, _VAR_bs_p) - self.Emit("MOVQ" , _SI, _VAR_bs_n) - self.Emit("MOVQ" , _R9, _VAR_bs_LR) - self.malloc(_SI, _DX) // MALLOC SI, DX - self.Emit("MOVQ" , _DX, _VAR_sv_p) - self.Emit("MOVQ" , _VAR_bs_p, _DI) - self.Emit("MOVQ" , _VAR_bs_n, _SI) - 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 - self.Emit("SETCC", _R8) // SETCC R8 - self.Emit("SHLQ" , jit.Imm(types.B_UNICODE_REPLACE), _R8) // SHLQ ${types.B_UNICODE_REPLACE}, R8 - self.call(_F_unquote) // CALL unquote - self.Emit("MOVQ" , _VAR_bs_n, _SI) // MOVQ ${n}, SI - self.Emit("ADDQ" , jit.Imm(1), _SI) // ADDQ $1, SI - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JS" , _LB_unquote_error) // JS _unquote_error - self.Emit("MOVQ" , _AX, _SI) - self.Emit("MOVQ" , _VAR_sv_p, _DI) - self.Emit("MOVQ" , _VAR_bs_LR, _R9) - self.Rjmp("JMP", _R9) -} - -func (self *_Assembler) escape_string_twice() { - self.Link("_escape_string_twice") - self.Emit("MOVQ" , _DI, _VAR_bs_p) - self.Emit("MOVQ" , _SI, _VAR_bs_n) - self.Emit("MOVQ" , _R9, _VAR_bs_LR) - self.malloc(_SI, _DX) // MALLOC SI, DX - self.Emit("MOVQ" , _DX, _VAR_sv_p) - self.Emit("MOVQ" , _VAR_bs_p, _DI) - self.Emit("MOVQ" , _VAR_bs_n, _SI) - 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 - self.Emit("XORL" , _AX, _AX) // XORL AX, AX - self.Emit("SETCC", _AX) // SETCC AX - self.Emit("SHLQ" , jit.Imm(types.B_UNICODE_REPLACE), _AX) // SHLQ ${types.B_UNICODE_REPLACE}, AX - self.Emit("ORQ" , _AX, _R8) // ORQ AX, R8 - self.call(_F_unquote) // CALL unquote - self.Emit("MOVQ" , _VAR_bs_n, _SI) // MOVQ ${n}, SI - self.Emit("ADDQ" , jit.Imm(3), _SI) // ADDQ $3, SI - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JS" , _LB_unquote_error) // JS _unquote_error - self.Emit("MOVQ" , _AX, _SI) - self.Emit("MOVQ" , _VAR_sv_p, _DI) - self.Emit("MOVQ" , _VAR_bs_LR, _R9) - self.Rjmp("JMP", _R9) -} - -/** Range Checking Routines **/ - -var ( - _V_max_f32 = jit.Imm(int64(uintptr(unsafe.Pointer(_Vp_max_f32)))) - _V_min_f32 = jit.Imm(int64(uintptr(unsafe.Pointer(_Vp_min_f32)))) -) - -var ( - _Vp_max_f32 = new(float32) - _Vp_min_f32 = new(float32) -) - -func init() { - *_Vp_max_f32 = math.MaxFloat32 - *_Vp_min_f32 = -math.MaxFloat32 -} - -func (self *_Assembler) range_single() { - self.Emit("CVTSD2SS", _VAR_st_Dv, _X0) // CVTSD2SS st.Dv, X0 - self.Emit("MOVQ" , _V_max_f32, _AX) // MOVQ _max_f32, AX - self.Emit("MOVQ" , jit.Gitab(_I_float32), _ET) // MOVQ ${itab(float32)}, ET - self.Emit("MOVQ" , jit.Gtype(_T_float32), _EP) // MOVQ ${type(float32)}, EP - self.Emit("UCOMISS" , jit.Ptr(_AX, 0), _X0) // UCOMISS (AX), X0 - self.Sjmp("JA" , _LB_range_error) // JA _range_error - self.Emit("MOVQ" , _V_min_f32, _AX) // MOVQ _min_f32, AX - self.Emit("UCOMISS" , jit.Ptr(_AX, 0), _X0) // UCOMISS (AX), X0 - self.Sjmp("JB" , _LB_range_error) // JB _range_error -} - -func (self *_Assembler) range_signed(i *rt.GoItab, t *rt.GoType, a int64, b int64) { - self.Emit("MOVQ", _VAR_st_Iv, _AX) // MOVQ st.Iv, AX - self.Emit("MOVQ", jit.Gitab(i), _ET) // MOVQ ${i}, ET - self.Emit("MOVQ", jit.Gtype(t), _EP) // MOVQ ${t}, EP - self.Emit("CMPQ", _AX, jit.Imm(a)) // CMPQ AX, ${a} - self.Sjmp("JL" , _LB_range_error) // JL _range_error - self.Emit("CMPQ", _AX, jit.Imm(b)) // CMPQ AX, ${B} - self.Sjmp("JG" , _LB_range_error) // JG _range_error -} - -func (self *_Assembler) range_unsigned(i *rt.GoItab, t *rt.GoType, v uint64) { - self.Emit("MOVQ" , _VAR_st_Iv, _AX) // MOVQ st.Iv, AX - self.Emit("MOVQ" , jit.Gitab(i), _ET) // MOVQ ${i}, ET - self.Emit("MOVQ" , jit.Gtype(t), _EP) // MOVQ ${t}, EP - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JS" , _LB_range_error) // JS _range_error - self.Emit("CMPQ" , _AX, jit.Imm(int64(v))) // CMPQ AX, ${a} - self.Sjmp("JA" , _LB_range_error) // JA _range_error -} - -/** String Manipulating Routines **/ - -var ( - _F_unquote = jit.Imm(int64(native.S_unquote)) -) - -func (self *_Assembler) slice_from(p obj.Addr, d int64) { - self.Emit("MOVQ", p, _SI) // MOVQ ${p}, SI - self.slice_from_r(_SI, d) // SLICE_R SI, ${d} -} - -func (self *_Assembler) slice_from_r(p obj.Addr, d int64) { - self.Emit("LEAQ", jit.Sib(_IP, p, 1, 0), _DI) // LEAQ (IP)(${p}), DI - self.Emit("NEGQ", p) // NEGQ ${p} - 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, stack bool, copy bool) { - self.slice_from(_VAR_st_Iv, -1) // SLICE st.Iv, $-1 - self.Emit("CMPQ" , _VAR_st_Ep, jit.Imm(-1)) // CMPQ st.Ep, $-1 - self.Sjmp("JE" , "_noescape_{n}") // JE _noescape_{n} - self.Byte(0x4c, 0x8d, 0x0d) // LEAQ (PC), R9 - self.Sref("_unquote_once_write_{n}", 4) - self.Sjmp("JMP" , "_escape_string") - self.Link("_noescape_{n}") // _noescape_{n}: - if copy { - self.Emit("BTQ" , jit.Imm(_F_copy_string), _ARG_fv) - self.Sjmp("JNC", "_unquote_once_write_{n}") - self.Byte(0x4c, 0x8d, 0x0d) // LEAQ (PC), R9 - self.Sref("_unquote_once_write_{n}", 4) - self.Sjmp("JMP", "_copy_string") - } - self.Link("_unquote_once_write_{n}") - self.Emit("MOVQ" , _SI, n) // MOVQ SI, ${n} - if stack { - self.Emit("MOVQ", _DI, p) - } else { - self.WriteRecNotAX(10, _DI, p, false, false) - } -} - -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), $'\\' - self.Sjmp("JNE" , _LB_char_m3_error) // JNE _char_m3_error - self.Emit("CMPB" , jit.Sib(_IP, _IC, 1, -2), jit.Imm('"')) // CMPB -2(IP)(IC), $'"' - self.Sjmp("JNE" , _LB_char_m2_error) // JNE _char_m2_error - self.slice_from(_VAR_st_Iv, -3) // SLICE st.Iv, $-3 - self.Emit("MOVQ" , _SI, _AX) // MOVQ SI, AX - self.Emit("ADDQ" , _VAR_st_Iv, _AX) // ADDQ st.Iv, AX - self.Emit("CMPQ" , _VAR_st_Ep, _AX) // CMPQ st.Ep, AX - self.Sjmp("JE" , "_noescape_{n}") // JE _noescape_{n} - self.Byte(0x4c, 0x8d, 0x0d) // LEAQ (PC), R9 - self.Sref("_unquote_twice_write_{n}", 4) - self.Sjmp("JMP" , "_escape_string_twice") - self.Link("_noescape_{n}") // _noescape_{n}: - self.Emit("BTQ" , jit.Imm(_F_copy_string), _ARG_fv) - self.Sjmp("JNC", "_unquote_twice_write_{n}") - self.Byte(0x4c, 0x8d, 0x0d) // LEAQ (PC), R9 - self.Sref("_unquote_twice_write_{n}", 4) - self.Sjmp("JMP", "_copy_string") - self.Link("_unquote_twice_write_{n}") - self.Emit("MOVQ" , _SI, n) // MOVQ SI, ${n} - if stack { - self.Emit("MOVQ", _DI, p) - } else { - self.WriteRecNotAX(12, _DI, p, false, false) - } -} - -/** Memory Clearing Routines **/ - -var ( - _F_memclrHasPointers = jit.Func(memclrHasPointers) - _F_memclrNoHeapPointers = jit.Func(memclrNoHeapPointers) -) - -func (self *_Assembler) mem_clear_fn(ptrfree bool) { - if !ptrfree { - self.call_go(_F_memclrHasPointers) - } else { - self.call_go(_F_memclrNoHeapPointers) - } -} - -func (self *_Assembler) mem_clear_rem(size int64, ptrfree bool) { - self.Emit("MOVQ", jit.Imm(size), _CX) // MOVQ ${size}, CX - self.Emit("MOVQ", jit.Ptr(_ST, 0), _AX) // MOVQ (ST), AX - self.Emit("MOVQ", jit.Sib(_ST, _AX, 1, 0), _AX) // MOVQ (ST)(AX), AX - self.Emit("SUBQ", _VP, _AX) // SUBQ VP, AX - self.Emit("ADDQ", _AX, _CX) // ADDQ AX, CX - self.Emit("MOVQ", _VP, jit.Ptr(_SP, 0)) // MOVQ VP, (SP) - self.Emit("MOVQ", _CX, jit.Ptr(_SP, 8)) // MOVQ CX, 8(SP) - self.mem_clear_fn(ptrfree) // CALL_GO memclr{Has,NoHeap}Pointers -} - -/** Map Assigning Routines **/ - -var ( - _F_mapassign = jit.Func(mapassign) - _F_mapassign_fast32 = jit.Func(mapassign_fast32) - _F_mapassign_faststr = jit.Func(mapassign_faststr) - _F_mapassign_fast64ptr = jit.Func(mapassign_fast64ptr) -) - -var ( - _F_decodeJsonUnmarshaler obj.Addr - _F_decodeTextUnmarshaler obj.Addr -) - -func init() { - _F_decodeJsonUnmarshaler = jit.Func(decodeJsonUnmarshaler) - _F_decodeTextUnmarshaler = jit.Func(decodeTextUnmarshaler) -} - -func (self *_Assembler) mapaccess_ptr(t reflect.Type) { - if rt.MapType(rt.UnpackType(t)).IndirectElem() { - self.vfollow(t.Elem()) - } -} - -func (self *_Assembler) mapassign_std(t reflect.Type, v obj.Addr) { - self.Emit("LEAQ", v, _AX) // LEAQ ${v}, AX - self.mapassign_call(t, _F_mapassign) // MAPASSIGN ${t}, mapassign -} - -func (self *_Assembler) mapassign_str_fast(t reflect.Type, p obj.Addr, n obj.Addr) { - self.Emit("MOVQ", jit.Type(t), _AX) // MOVQ ${t}, AX - self.Emit("MOVQ", _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP) - self.Emit("MOVQ", _VP, jit.Ptr(_SP, 8)) // MOVQ VP, 8(SP) - self.Emit("MOVQ", p, jit.Ptr(_SP, 16)) // MOVQ ${p}, 16(SP) - self.Emit("MOVQ", n, jit.Ptr(_SP, 24)) // MOVQ ${n}, 24(SP) - self.call_go(_F_mapassign_faststr) // CALL_GO ${fn} - self.Emit("MOVQ", jit.Ptr(_SP, 32), _VP) // MOVQ 32(SP), VP - self.mapaccess_ptr(t) -} - -func (self *_Assembler) mapassign_call(t reflect.Type, fn obj.Addr) { - self.Emit("MOVQ", jit.Type(t), _SI) // MOVQ ${t}, SI - self.Emit("MOVQ", _SI, jit.Ptr(_SP, 0)) // MOVQ SI, (SP) - self.Emit("MOVQ", _VP, jit.Ptr(_SP, 8)) // MOVQ VP, 8(SP) - self.Emit("MOVQ", _AX, jit.Ptr(_SP, 16)) // MOVQ AX, 16(SP) - self.call_go(fn) // CALL_GO ${fn} - self.Emit("MOVQ", jit.Ptr(_SP, 24), _VP) // MOVQ 24(SP), VP -} - -func (self *_Assembler) mapassign_fastx(t reflect.Type, fn obj.Addr) { - self.mapassign_call(t, fn) - self.mapaccess_ptr(t) -} - -func (self *_Assembler) mapassign_utext(t reflect.Type, addressable bool) { - pv := false - vk := t.Key() - tk := t.Key() - - /* deref pointer if needed */ - if vk.Kind() == reflect.Ptr { - pv = true - vk = vk.Elem() - } - - /* addressable value with pointer receiver */ - if addressable { - pv = false - tk = reflect.PtrTo(tk) - } - - /* 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) - self.Emit("MOVOU", _VAR_sv, _X0) // MOVOU sv, X0 - self.Emit("MOVOU", _X0, jit.Ptr(_SP, 16)) // MOVOU X0, 16(SP) - self.call_go(_F_decodeTextUnmarshaler) // CALL_GO decodeTextUnmarshaler - self.Emit("MOVQ" , jit.Ptr(_SP, 32), _ET) // MOVQ 32(SP), ET - 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) - - /* select the correct assignment function */ - if !pv { - self.mapassign_call(t, _F_mapassign) - } else { - self.mapassign_fastx(t, _F_mapassign_fast64ptr) - } -} - -/** External Unmarshaler Routines **/ - -var ( - _F_skip_one = jit.Imm(int64(native.S_skip_one)) - _F_skip_number = jit.Imm(int64(native.S_skip_number)) -) - -func (self *_Assembler) unmarshal_json(t reflect.Type, deref bool) { - self.call_sf(_F_skip_one) // CALL_SF skip_one - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JS" , _LB_parsing_error_v) // JS _parse_error_v - self.slice_from_r(_AX, 0) // SLICE_R AX, $0 - self.Emit("MOVQ" , _DI, _VAR_sv_p) // MOVQ DI, sv.p - self.Emit("MOVQ" , _SI, _VAR_sv_n) // MOVQ SI, sv.n - self.unmarshal_func(t, _F_decodeJsonUnmarshaler, deref) // UNMARSHAL json, ${t}, ${deref} -} - -func (self *_Assembler) unmarshal_text(t reflect.Type, deref bool) { - self.parse_string() // PARSE STRING - self.unquote_once(_VAR_sv_p, _VAR_sv_n, true, true) // UNQUOTE once, sv.p, sv.n - self.unmarshal_func(t, _F_decodeTextUnmarshaler, deref) // UNMARSHAL text, ${t}, ${deref} -} - -func (self *_Assembler) unmarshal_func(t reflect.Type, fn obj.Addr, deref bool) { - pt := t - vk := t.Kind() - - /* allocate the field if needed */ - if deref && vk == reflect.Ptr { - self.Emit("MOVQ" , _VP, _AX) // MOVQ VP, AX - self.Emit("MOVQ" , jit.Ptr(_AX, 0), _AX) // MOVQ (AX), AX - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JNZ" , "_deref_{n}") // JNZ _deref_{n} - self.valloc(t.Elem(), _AX) // VALLOC ${t.Elem()}, AX - self.WritePtrAX(3, jit.Ptr(_VP, 0), false) // MOVQ AX, (VP) - self.Link("_deref_{n}") // _deref_{n}: - } - - /* set value type */ - self.Emit("MOVQ", jit.Type(pt), _CX) // MOVQ ${pt}, CX - self.Emit("MOVQ", _CX, jit.Ptr(_SP, 0)) // MOVQ CX, (SP) - - /* set value pointer */ - if deref && vk == reflect.Ptr { - self.Emit("MOVQ", _AX, jit.Ptr(_SP, 8)) // MOVQ AX, 8(SP) - } else { - self.Emit("MOVQ", _VP, jit.Ptr(_SP, 8)) // MOVQ VP, 8(SP) - } - - /* set the source string and call the unmarshaler */ - self.Emit("MOVOU", _VAR_sv, _X0) // MOVOU sv, X0 - self.Emit("MOVOU", _X0, jit.Ptr(_SP, 16)) // MOVOU X0, 16(SP) - self.call_go(fn) // CALL_GO ${fn} - self.Emit("MOVQ" , jit.Ptr(_SP, 32), _ET) // MOVQ 32(SP), ET - 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 -} - -/** Dynamic Decoding Routine **/ - -var ( - _F_decodeTypedPointer obj.Addr -) - -func init() { - _F_decodeTypedPointer = jit.Func(decodeTypedPointer) -} - -func (self *_Assembler) decode_dynamic(vt obj.Addr, vp obj.Addr) { - self.Emit("MOVQ" , _ARG_fv, _CX) // MOVQ fv, CX - self.Emit("MOVOU", _ARG_sp, _X0) // MOVOU sp, X0 - self.Emit("MOVOU", _X0, jit.Ptr(_SP, 0)) // MOVOU X0, (SP) - self.Emit("MOVQ" , _IC, jit.Ptr(_SP, 16)) // MOVQ IC, 16(SP) - self.Emit("MOVQ" , vt, jit.Ptr(_SP, 24)) // MOVQ ${vt}, 24(SP) - self.Emit("MOVQ" , vp, jit.Ptr(_SP, 32)) // MOVQ ${vp}, 32(SP) - self.Emit("MOVQ" , _ST, jit.Ptr(_SP, 40)) // MOVQ ST, 40(SP) - self.Emit("MOVQ" , _CX, jit.Ptr(_SP, 48)) // MOVQ CX, 48(SP) - self.call_go(_F_decodeTypedPointer) // CALL_GO decodeTypedPointer - self.Emit("MOVQ" , jit.Ptr(_SP, 64), _ET) // MOVQ 64(SP), ET - self.Emit("MOVQ" , jit.Ptr(_SP, 72), _EP) // MOVQ 72(SP), EP - self.Emit("MOVQ" , jit.Ptr(_SP, 56), _IC) // MOVQ 56(SP), IC - self.Emit("TESTQ", _ET, _ET) // TESTQ ET, ET - self.Sjmp("JE", "_decode_dynamic_end_{n}") // JE, _decode_dynamic_end_{n} - self.Emit("MOVQ", _I_json_MismatchTypeError, _AX) // MOVQ _I_json_MismatchTypeError, AX - self.Emit("CMPQ", _ET, _AX) // CMPQ ET, AX - self.Sjmp("JNE" , _LB_error) // JNE LB_error - self.Emit("MOVQ", _EP, _VAR_ic) // MOVQ EP, VAR_ic - self.Emit("MOVQ", _ET, _VAR_et) // MOVQ ET, VAR_et - self.Link("_decode_dynamic_end_{n}") - -} - -/** OpCode Assembler Functions **/ - -var ( - _F_memequal = jit.Func(memequal) - _F_memmove = jit.Func(memmove) - _F_growslice = jit.Func(growslice) - _F_makeslice = jit.Func(makeslice) - _F_makemap_small = jit.Func(makemap_small) - _F_mapassign_fast64 = jit.Func(mapassign_fast64) -) - -var ( - _F_lspace = jit.Imm(int64(native.S_lspace)) - _F_strhash = jit.Imm(int64(caching.S_strhash)) -) - -var ( - _F_b64decode = jit.Imm(int64(_subr__b64decode)) - _F_decodeValue = jit.Imm(int64(_subr_decode_value)) -) - -var ( - _F_skip_array = jit.Imm(int64(native.S_skip_array)) - _F_skip_object = jit.Imm(int64(native.S_skip_object)) -) - -var ( - _F_FieldMap_GetCaseInsensitive obj.Addr - _Empty_Slice = make([]byte, 0) - _Zero_Base = int64(uintptr(((*rt.GoSlice)(unsafe.Pointer(&_Empty_Slice))).Ptr)) -) - -const ( - _MODE_AVX2 = 1 << 2 -) - -const ( - _Fe_ID = int64(unsafe.Offsetof(caching.FieldEntry{}.ID)) - _Fe_Name = int64(unsafe.Offsetof(caching.FieldEntry{}.Name)) - _Fe_Hash = int64(unsafe.Offsetof(caching.FieldEntry{}.Hash)) -) - -const ( - _Vk_Ptr = int64(reflect.Ptr) - _Gt_KindFlags = int64(unsafe.Offsetof(rt.GoType{}.KindFlags)) -) - -func init() { - _F_FieldMap_GetCaseInsensitive = jit.Func((*caching.FieldMap).GetCaseInsensitive) -} - -func (self *_Assembler) _asm_OP_any(_ *_Instr) { - self.Emit("MOVQ" , jit.Ptr(_VP, 8), _CX) // MOVQ 8(VP), CX - self.Emit("TESTQ" , _CX, _CX) // TESTQ CX, CX - self.Sjmp("JZ" , "_decode_{n}") // JZ _decode_{n} - self.Emit("CMPQ" , _CX, _VP) // CMPQ CX, VP - self.Sjmp("JE" , "_decode_{n}") // JE _decode_{n} - self.Emit("MOVQ" , jit.Ptr(_VP, 0), _AX) // MOVQ (VP), AX - self.Emit("MOVBLZX", jit.Ptr(_AX, _Gt_KindFlags), _DX) // MOVBLZX _Gt_KindFlags(AX), DX - self.Emit("ANDL" , jit.Imm(rt.F_kind_mask), _DX) // ANDL ${F_kind_mask}, DX - self.Emit("CMPL" , _DX, jit.Imm(_Vk_Ptr)) // CMPL DX, ${reflect.Ptr} - self.Sjmp("JNE" , "_decode_{n}") // JNE _decode_{n} - self.Emit("LEAQ" , jit.Ptr(_VP, 8), _DI) // LEAQ 8(VP), DI - self.decode_dynamic(_AX, _DI) // DECODE AX, DI - self.Sjmp("JMP" , "_decode_end_{n}") // JMP _decode_end_{n} - self.Link("_decode_{n}") // _decode_{n}: - 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("TESTQ" , _EP, _EP) // TESTQ EP, EP - self.Sjmp("JNZ" , _LB_parsing_error) // JNZ _parsing_error - self.Link("_decode_end_{n}") // _decode_end_{n}: -} - -func (self *_Assembler) _asm_OP_dyn(p *_Instr) { - self.Emit("MOVQ" , jit.Type(p.vt()), _ET) // MOVQ ${p.vt()}, ET - self.Emit("CMPQ" , jit.Ptr(_VP, 8), jit.Imm(0)) // CMPQ 8(VP), $0 - self.Sjmp("JE" , _LB_type_error) // JE _type_error - self.Emit("MOVQ" , jit.Ptr(_VP, 0), _AX) // MOVQ (VP), AX - self.Emit("MOVQ" , jit.Ptr(_AX, 8), _AX) // MOVQ 8(AX), AX - self.Emit("MOVBLZX", jit.Ptr(_AX, _Gt_KindFlags), _DX) // MOVBLZX _Gt_KindFlags(AX), DX - self.Emit("ANDL" , jit.Imm(rt.F_kind_mask), _DX) // ANDL ${F_kind_mask}, DX - self.Emit("CMPL" , _DX, jit.Imm(_Vk_Ptr)) // CMPL DX, ${reflect.Ptr} - self.Sjmp("JNE" , _LB_type_error) // JNE _type_error - self.Emit("LEAQ" , jit.Ptr(_VP, 8), _DI) // LEAQ 8(VP), DI - self.decode_dynamic(_AX, _DI) // DECODE AX, DI - self.Link("_decode_end_{n}") // _decode_end_{n}: -} - -func (self *_Assembler) _asm_OP_str(_ *_Instr) { - self.parse_string() // PARSE STRING - self.unquote_once(jit.Ptr(_VP, 0), jit.Ptr(_VP, 8), false, true) // UNQUOTE once, (VP), 8(VP) -} - -func (self *_Assembler) _asm_OP_bin(_ *_Instr) { - self.parse_string() // PARSE STRING - self.slice_from(_VAR_st_Iv, -1) // SLICE st.Iv, $-1 - self.Emit("MOVQ" , _DI, jit.Ptr(_VP, 0)) // MOVQ DI, (VP) - self.Emit("MOVQ" , _SI, jit.Ptr(_VP, 8)) // MOVQ SI, 8(VP) - self.Emit("SHRQ" , jit.Imm(2), _SI) // SHRQ $2, SI - self.Emit("LEAQ" , jit.Sib(_SI, _SI, 2, 0), _SI) // LEAQ (SI)(SI*2), SI - self.Emit("MOVQ" , _SI, jit.Ptr(_VP, 16)) // MOVQ SI, 16(VP) - self.malloc(_SI, _SI) // MALLOC SI, SI - - // TODO: due to base64x's bug, only use AVX mode now - self.Emit("MOVL", jit.Imm(_MODE_JSON), _CX) // MOVL $_MODE_JSON, CX - - /* call the decoder */ - self.Emit("XORL" , _DX, _DX) // XORL DX, DX - self.Emit("MOVQ" , _VP, _DI) // MOVQ VP, DI - - self.Emit("MOVQ" , jit.Ptr(_VP, 0), _R9) // MOVQ SI, (VP) - self.WriteRecNotAX(4, _SI, jit.Ptr(_VP, 0), true, false) // XCHGQ SI, (VP) - self.Emit("MOVQ" , _R9, _SI) - - self.Emit("XCHGQ", _DX, jit.Ptr(_VP, 8)) // XCHGQ DX, 8(VP) - self.call(_F_b64decode) // CALL b64decode - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JS" , _LB_base64_error) // JS _base64_error - self.Emit("MOVQ" , _AX, jit.Ptr(_VP, 8)) // MOVQ AX, 8(VP) -} - -func (self *_Assembler) _asm_OP_bool(_ *_Instr) { - self.Emit("LEAQ", jit.Ptr(_IC, 4), _AX) // LEAQ 4(IC), AX - self.Emit("CMPQ", _AX, _IL) // CMPQ AX, IL - self.Sjmp("JA" , _LB_eof_error) // JA _eof_error - self.Emit("CMPB", jit.Sib(_IP, _IC, 1, 0), jit.Imm('f')) // CMPB (IP)(IC), $'f' - self.Sjmp("JE" , "_false_{n}") // JE _false_{n} - self.Emit("MOVL", jit.Imm(_IM_true), _CX) // MOVL $"true", CX - self.Emit("CMPL", _CX, jit.Sib(_IP, _IC, 1, 0)) // CMPL CX, (IP)(IC) - self.Sjmp("JE" , "_bool_true_{n}") - - // try to skip the value - self.Emit("MOVQ", _IC, _VAR_ic) - self.Emit("MOVQ", _T_bool, _ET) - self.Emit("MOVQ", _ET, _VAR_et) - self.Byte(0x4c, 0x8d, 0x0d) // LEAQ (PC), R9 - self.Sref("_end_{n}", 4) - self.Emit("MOVQ", _R9, _VAR_pc) - self.Sjmp("JMP" , _LB_skip_one) - - self.Link("_bool_true_{n}") - self.Emit("MOVQ", _AX, _IC) // MOVQ AX, IC - self.Emit("MOVB", jit.Imm(1), jit.Ptr(_VP, 0)) // MOVB $1, (VP) - self.Sjmp("JMP" , "_end_{n}") // JMP _end_{n} - self.Link("_false_{n}") // _false_{n}: - self.Emit("ADDQ", jit.Imm(1), _AX) // ADDQ $1, AX - self.Emit("ADDQ", jit.Imm(1), _IC) // ADDQ $1, IC - self.Emit("CMPQ", _AX, _IL) // CMPQ AX, IL - self.Sjmp("JA" , _LB_eof_error) // JA _eof_error - self.Emit("MOVL", jit.Imm(_IM_alse), _CX) // MOVL $"alse", CX - self.Emit("CMPL", _CX, jit.Sib(_IP, _IC, 1, 0)) // CMPL CX, (IP)(IC) - self.Sjmp("JNE" , _LB_im_error) // JNE _im_error - self.Emit("MOVQ", _AX, _IC) // MOVQ AX, IC - self.Emit("XORL", _AX, _AX) // XORL AX, AX - self.Emit("MOVB", _AX, jit.Ptr(_VP, 0)) // MOVB AX, (VP) - self.Link("_end_{n}") // _end_{n}: -} - -func (self *_Assembler) _asm_OP_num(_ *_Instr) { - self.Emit("MOVQ", jit.Imm(0), _VAR_fl) - self.Emit("CMPB", jit.Sib(_IP, _IC, 1, 0), jit.Imm('"')) - self.Emit("MOVQ", _IC, _BP) - self.Sjmp("JNE", "_skip_number_{n}") - self.Emit("MOVQ", jit.Imm(1), _VAR_fl) - self.Emit("ADDQ", jit.Imm(1), _IC) - self.Link("_skip_number_{n}") - - /* call skip_number */ - self.call_sf(_F_skip_number) // CALL_SF skip_one - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JNS" , "_num_next_{n}") - - /* call skip one */ - self.Emit("MOVQ", _BP, _VAR_ic) - self.Emit("MOVQ", _T_number, _ET) - self.Emit("MOVQ", _ET, _VAR_et) - self.Byte(0x4c, 0x8d, 0x0d) - self.Sref("_num_end_{n}", 4) - self.Emit("MOVQ", _R9, _VAR_pc) - self.Sjmp("JMP" , _LB_skip_one) - - /* assgin string */ - self.Link("_num_next_{n}") - self.slice_from_r(_AX, 0) - self.Emit("BTQ", jit.Imm(_F_copy_string), _ARG_fv) - self.Sjmp("JNC", "_num_write_{n}") - self.Byte(0x4c, 0x8d, 0x0d) // LEAQ (PC), R9 - self.Sref("_num_write_{n}", 4) - self.Sjmp("JMP", "_copy_string") - self.Link("_num_write_{n}") - self.Emit("MOVQ", _SI, jit.Ptr(_VP, 8)) // MOVQ SI, 8(VP) - self.WriteRecNotAX(13, _DI, jit.Ptr(_VP, 0), false, false) - - /* check if quoted */ - self.Emit("CMPQ", _VAR_fl, jit.Imm(1)) - self.Sjmp("JNE", "_num_end_{n}") - self.Emit("CMPB", jit.Sib(_IP, _IC, 1, 0), jit.Imm('"')) - self.Sjmp("JNE", _LB_char_0_error) - self.Emit("ADDQ", jit.Imm(1), _IC) - self.Link("_num_end_{n}") -} - -func (self *_Assembler) _asm_OP_i8(ins *_Instr) { - var pin = "_i8_end_{n}" - self.parse_signed(int8Type, pin, -1) // PARSE int8 - self.range_signed(_I_int8, _T_int8, math.MinInt8, math.MaxInt8) // RANGE int8 - self.Emit("MOVB", _AX, jit.Ptr(_VP, 0)) // MOVB AX, (VP) - self.Link(pin) -} - -func (self *_Assembler) _asm_OP_i16(ins *_Instr) { - var pin = "_i16_end_{n}" - self.parse_signed(int16Type, pin, -1) // PARSE int16 - self.range_signed(_I_int16, _T_int16, math.MinInt16, math.MaxInt16) // RANGE int16 - self.Emit("MOVW", _AX, jit.Ptr(_VP, 0)) // MOVW AX, (VP) - self.Link(pin) -} - -func (self *_Assembler) _asm_OP_i32(ins *_Instr) { - var pin = "_i32_end_{n}" - self.parse_signed(int32Type, pin, -1) // PARSE int32 - self.range_signed(_I_int32, _T_int32, math.MinInt32, math.MaxInt32) // RANGE int32 - self.Emit("MOVL", _AX, jit.Ptr(_VP, 0)) // MOVL AX, (VP) - self.Link(pin) -} - -func (self *_Assembler) _asm_OP_i64(ins *_Instr) { - var pin = "_i64_end_{n}" - self.parse_signed(int64Type, pin, -1) // PARSE int64 - self.Emit("MOVQ", _VAR_st_Iv, _AX) // MOVQ st.Iv, AX - self.Emit("MOVQ", _AX, jit.Ptr(_VP, 0)) // MOVQ AX, (VP) - self.Link(pin) -} - -func (self *_Assembler) _asm_OP_u8(ins *_Instr) { - var pin = "_u8_end_{n}" - self.parse_unsigned(uint8Type, pin, -1) // PARSE uint8 - self.range_unsigned(_I_uint8, _T_uint8, math.MaxUint8) // RANGE uint8 - self.Emit("MOVB", _AX, jit.Ptr(_VP, 0)) // MOVB AX, (VP) - self.Link(pin) -} - -func (self *_Assembler) _asm_OP_u16(ins *_Instr) { - var pin = "_u16_end_{n}" - self.parse_unsigned(uint16Type, pin, -1) // PARSE uint16 - self.range_unsigned(_I_uint16, _T_uint16, math.MaxUint16) // RANGE uint16 - self.Emit("MOVW", _AX, jit.Ptr(_VP, 0)) // MOVW AX, (VP) - self.Link(pin) -} - -func (self *_Assembler) _asm_OP_u32(ins *_Instr) { - var pin = "_u32_end_{n}" - self.parse_unsigned(uint32Type, pin, -1) // PARSE uint32 - self.range_unsigned(_I_uint32, _T_uint32, math.MaxUint32) // RANGE uint32 - self.Emit("MOVL", _AX, jit.Ptr(_VP, 0)) // MOVL AX, (VP) - self.Link(pin) -} - -func (self *_Assembler) _asm_OP_u64(ins *_Instr) { - var pin = "_u64_end_{n}" - self.parse_unsigned(uint64Type, pin, -1) // PARSE uint64 - self.Emit("MOVQ", _VAR_st_Iv, _AX) // MOVQ st.Iv, AX - self.Emit("MOVQ", _AX, jit.Ptr(_VP, 0)) // MOVQ AX, (VP) - self.Link(pin) -} - -func (self *_Assembler) _asm_OP_f32(ins *_Instr) { - var pin = "_f32_end_{n}" - self.parse_number(float32Type, pin, -1) // PARSE NUMBER - self.range_single() // RANGE float32 - self.Emit("MOVSS", _X0, jit.Ptr(_VP, 0)) // MOVSS X0, (VP) - self.Link(pin) -} - -func (self *_Assembler) _asm_OP_f64(ins *_Instr) { - var pin = "_f64_end_{n}" - self.parse_number(float64Type, pin, -1) // PARSE NUMBER - self.Emit("MOVSD", _VAR_st_Dv, _X0) // MOVSD st.Dv, X0 - self.Emit("MOVSD", _X0, jit.Ptr(_VP, 0)) // MOVSD X0, (VP) - self.Link(pin) -} - -func (self *_Assembler) _asm_OP_unquote(ins *_Instr) { - self.check_eof(2) - self.Emit("CMPB", jit.Sib(_IP, _IC, 1, 0), jit.Imm('\\')) // CMPB (IP)(IC), $'\\' - self.Sjmp("JNE" , _LB_char_0_error) // JNE _char_0_error - self.Emit("CMPB", jit.Sib(_IP, _IC, 1, 1), jit.Imm('"')) // CMPB 1(IP)(IC), $'"' - 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), false) // UNQUOTE twice, (VP), 8(VP) -} - -func (self *_Assembler) _asm_OP_nil_1(_ *_Instr) { - self.Emit("XORL", _AX, _AX) // XORL AX, AX - self.Emit("MOVQ", _AX, jit.Ptr(_VP, 0)) // MOVQ AX, (VP) -} - -func (self *_Assembler) _asm_OP_nil_2(_ *_Instr) { - self.Emit("PXOR" , _X0, _X0) // PXOR X0, X0 - self.Emit("MOVOU", _X0, jit.Ptr(_VP, 0)) // MOVOU X0, (VP) -} - -func (self *_Assembler) _asm_OP_nil_3(_ *_Instr) { - self.Emit("XORL" , _AX, _AX) // XORL AX, AX - self.Emit("PXOR" , _X0, _X0) // PXOR X0, X0 - self.Emit("MOVOU", _X0, jit.Ptr(_VP, 0)) // MOVOU X0, (VP) - self.Emit("MOVQ" , _AX, jit.Ptr(_VP, 16)) // MOVOU X0, 16(VP) -} - -func (self *_Assembler) _asm_OP_deref(p *_Instr) { - self.vfollow(p.vt()) -} - -func (self *_Assembler) _asm_OP_index(p *_Instr) { - self.Emit("MOVQ", jit.Imm(p.i64()), _AX) // MOVQ ${p.vi()}, AX - self.Emit("ADDQ", _AX, _VP) // ADDQ _AX, _VP -} - -func (self *_Assembler) _asm_OP_is_null(p *_Instr) { - self.Emit("LEAQ" , jit.Ptr(_IC, 4), _AX) // LEAQ 4(IC), AX - self.Emit("CMPQ" , _AX, _IL) // CMPQ AX, IL - self.Sjmp("JA" , "_not_null_{n}") // JA _not_null_{n} - self.Emit("CMPL" , jit.Sib(_IP, _IC, 1, 0), jit.Imm(_IM_null)) // CMPL (IP)(IC), $"null" - self.Emit("CMOVQEQ", _AX, _IC) // CMOVQEQ AX, IC - self.Xjmp("JE" , p.vi()) // JE {p.vi()} - self.Link("_not_null_{n}") // _not_null_{n}: -} - -func (self *_Assembler) _asm_OP_is_null_quote(p *_Instr) { - self.Emit("LEAQ" , jit.Ptr(_IC, 5), _AX) // LEAQ 4(IC), AX - self.Emit("CMPQ" , _AX, _IL) // CMPQ AX, IL - self.Sjmp("JA" , "_not_null_quote_{n}") // JA _not_null_quote_{n} - self.Emit("CMPL" , jit.Sib(_IP, _IC, 1, 0), jit.Imm(_IM_null)) // CMPL (IP)(IC), $"null" - self.Sjmp("JNE" , "_not_null_quote_{n}") // JNE _not_null_quote_{n} - self.Emit("CMPB" , jit.Sib(_IP, _IC, 1, 4), jit.Imm('"')) // CMPB 4(IP)(IC), $'"' - self.Emit("CMOVQEQ", _AX, _IC) // CMOVQEQ AX, IC - self.Xjmp("JE" , p.vi()) // JE {p.vi()} - self.Link("_not_null_quote_{n}") // _not_null_quote_{n}: -} - -func (self *_Assembler) _asm_OP_map_init(_ *_Instr) { - self.Emit("MOVQ" , jit.Ptr(_VP, 0), _AX) // MOVQ (VP), AX - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JNZ" , "_end_{n}") // JNZ _end_{n} - self.call_go(_F_makemap_small) // CALL_GO makemap_small - self.Emit("MOVQ" , jit.Ptr(_SP, 0), _AX) // MOVQ (SP), AX - self.WritePtrAX(6, jit.Ptr(_VP, 0), false) // MOVQ AX, (VP) - self.Link("_end_{n}") // _end_{n}: - self.Emit("MOVQ" , _AX, _VP) // MOVQ AX, VP -} - -func (self *_Assembler) _asm_OP_map_key_i8(p *_Instr) { - self.parse_signed(int8Type, "", p.vi()) // PARSE int8 - self.range_signed(_I_int8, _T_int8, math.MinInt8, math.MaxInt8) // RANGE int8 - self.match_char('"') - self.mapassign_std(p.vt(), _VAR_st_Iv) // MAPASSIGN int8, mapassign, st.Iv -} - -func (self *_Assembler) _asm_OP_map_key_i16(p *_Instr) { - self.parse_signed(int16Type, "", p.vi()) // PARSE int16 - self.range_signed(_I_int16, _T_int16, math.MinInt16, math.MaxInt16) // RANGE int16 - self.match_char('"') - self.mapassign_std(p.vt(), _VAR_st_Iv) // MAPASSIGN int16, mapassign, st.Iv -} - -func (self *_Assembler) _asm_OP_map_key_i32(p *_Instr) { - self.parse_signed(int32Type, "", p.vi()) // PARSE int32 - self.range_signed(_I_int32, _T_int32, math.MinInt32, math.MaxInt32) // RANGE int32 - self.match_char('"') - if vt := p.vt(); !mapfast(vt) { - self.mapassign_std(vt, _VAR_st_Iv) // MAPASSIGN int32, mapassign, st.Iv - } else { - self.mapassign_fastx(vt, _F_mapassign_fast32) // MAPASSIGN int32, mapassign_fast32 - } -} - -func (self *_Assembler) _asm_OP_map_key_i64(p *_Instr) { - self.parse_signed(int64Type, "", p.vi()) // PARSE int64 - self.match_char('"') - if vt := p.vt(); !mapfast(vt) { - self.mapassign_std(vt, _VAR_st_Iv) // MAPASSIGN int64, mapassign, st.Iv - } else { - self.Emit("MOVQ", _VAR_st_Iv, _AX) // MOVQ st.Iv, AX - self.mapassign_fastx(vt, _F_mapassign_fast64) // MAPASSIGN int64, mapassign_fast64 - } -} - -func (self *_Assembler) _asm_OP_map_key_u8(p *_Instr) { - self.parse_unsigned(uint8Type, "", p.vi()) // PARSE uint8 - self.range_unsigned(_I_uint8, _T_uint8, math.MaxUint8) // RANGE uint8 - self.match_char('"') - self.mapassign_std(p.vt(), _VAR_st_Iv) // MAPASSIGN uint8, vt.Iv -} - -func (self *_Assembler) _asm_OP_map_key_u16(p *_Instr) { - self.parse_unsigned(uint16Type, "", p.vi()) // PARSE uint16 - self.range_unsigned(_I_uint16, _T_uint16, math.MaxUint16) // RANGE uint16 - self.match_char('"') - self.mapassign_std(p.vt(), _VAR_st_Iv) // MAPASSIGN uint16, vt.Iv -} - -func (self *_Assembler) _asm_OP_map_key_u32(p *_Instr) { - self.parse_unsigned(uint32Type, "", p.vi()) // PARSE uint32 - self.range_unsigned(_I_uint32, _T_uint32, math.MaxUint32) // RANGE uint32 - self.match_char('"') - if vt := p.vt(); !mapfast(vt) { - self.mapassign_std(vt, _VAR_st_Iv) // MAPASSIGN uint32, vt.Iv - } else { - self.mapassign_fastx(vt, _F_mapassign_fast32) // MAPASSIGN uint32, mapassign_fast32 - } -} - -func (self *_Assembler) _asm_OP_map_key_u64(p *_Instr) { - self.parse_unsigned(uint64Type, "", p.vi()) // PARSE uint64 - self.match_char('"') - if vt := p.vt(); !mapfast(vt) { - self.mapassign_std(vt, _VAR_st_Iv) // MAPASSIGN uint64, vt.Iv - } else { - self.Emit("MOVQ", _VAR_st_Iv, _AX) // MOVQ st.Iv, AX - self.mapassign_fastx(vt, _F_mapassign_fast64) // MAPASSIGN uint64, mapassign_fast64 - } -} - -func (self *_Assembler) _asm_OP_map_key_f32(p *_Instr) { - self.parse_number(float32Type, "", p.vi()) // PARSE NUMBER - self.range_single() // RANGE float32 - self.Emit("MOVSS", _X0, _VAR_st_Dv) // MOVSS X0, st.Dv - self.match_char('"') - self.mapassign_std(p.vt(), _VAR_st_Dv) // MAPASSIGN ${p.vt()}, mapassign, st.Dv -} - -func (self *_Assembler) _asm_OP_map_key_f64(p *_Instr) { - self.parse_number(float64Type, "", p.vi()) // PARSE NUMBER - self.match_char('"') - self.mapassign_std(p.vt(), _VAR_st_Dv) // MAPASSIGN ${p.vt()}, mapassign, st.Dv -} - -func (self *_Assembler) _asm_OP_map_key_str(p *_Instr) { - self.parse_string() // PARSE STRING - self.unquote_once(_VAR_sv_p, _VAR_sv_n, true, true) // UNQUOTE once, sv.p, sv.n - if vt := p.vt(); !mapfast(vt) { - 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 - self.mapassign_str_fast(vt, _DI, _SI) // MAPASSIGN string, DI, SI - } -} - -func (self *_Assembler) _asm_OP_map_key_utext(p *_Instr) { - self.parse_string() // PARSE STRING - self.unquote_once(_VAR_sv_p, _VAR_sv_n, true, 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, true, false) // UNQUOTE once, sv.p, sv.n - self.mapassign_utext(p.vt(), true) // MAPASSIGN utext, ${p.vt()}, true -} - -func (self *_Assembler) _asm_OP_array_skip(_ *_Instr) { - self.call_sf(_F_skip_array) // CALL_SF skip_array - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JS" , _LB_parsing_error_v) // JS _parse_error_v -} - -func (self *_Assembler) _asm_OP_array_clear(p *_Instr) { - self.mem_clear_rem(p.i64(), true) -} - -func (self *_Assembler) _asm_OP_array_clear_p(p *_Instr) { - self.mem_clear_rem(p.i64(), false) -} - -func (self *_Assembler) _asm_OP_slice_init(p *_Instr) { - self.Emit("XORL" , _AX, _AX) // XORL AX, AX - self.Emit("MOVQ" , _AX, jit.Ptr(_VP, 8)) // MOVQ AX, 8(VP) - self.Emit("MOVQ" , jit.Ptr(_VP, 16), _AX) // MOVQ 16(VP), AX - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JNZ" , "_done_{n}") // JNZ _done_{n} - self.Emit("MOVQ" , jit.Imm(_MinSlice), _CX) // MOVQ ${_MinSlice}, CX - self.Emit("MOVQ" , _CX, jit.Ptr(_VP, 16)) // MOVQ CX, 16(VP) - self.Emit("MOVQ" , jit.Type(p.vt()), _DX) // MOVQ ${p.vt()}, DX - self.Emit("MOVQ" , _DX, jit.Ptr(_SP, 0)) // MOVQ DX, (SP) - self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 8)) // MOVQ AX, 8(SP) - self.Emit("MOVQ" , _CX, jit.Ptr(_SP, 16)) // MOVQ CX, 16(SP) - self.call_go(_F_makeslice) // CALL_GO makeslice - self.Emit("MOVQ" , jit.Ptr(_SP, 24), _AX) // MOVQ 24(SP), AX - self.WritePtrAX(7, jit.Ptr(_VP, 0), false) // MOVQ AX, (VP) - self.Link("_done_{n}") // _done_{n}: - self.Emit("XORL" , _AX, _AX) // XORL AX, AX - self.Emit("MOVQ" , _AX, jit.Ptr(_VP, 8)) // MOVQ AX, 8(VP) -} - -func (self *_Assembler) _asm_OP_check_empty(p *_Instr) { - rbracket := p.vb() - if rbracket == ']' { - self.check_eof(1) - self.Emit("LEAQ", jit.Ptr(_IC, 1), _AX) // LEAQ 1(IC), AX - self.Emit("CMPB", jit.Sib(_IP, _IC, 1, 0), jit.Imm(int64(rbracket))) // CMPB (IP)(IC), ']' - self.Sjmp("JNE" , "_not_empty_array_{n}") // JNE _not_empty_array_{n} - self.Emit("MOVQ", _AX, _IC) // MOVQ AX, IC - self.StorePtr(_Zero_Base, jit.Ptr(_VP, 0), _AX) // MOVQ $zerobase, (VP) - self.Emit("PXOR" , _X0, _X0) // PXOR X0, X0 - self.Emit("MOVOU", _X0, jit.Ptr(_VP, 8)) // MOVOU X0, 8(VP) - self.Xjmp("JMP" , p.vi()) // JMP {p.vi()} - self.Link("_not_empty_array_{n}") - } else { - panic("only implement check empty array here!") - } -} - -func (self *_Assembler) _asm_OP_slice_append(p *_Instr) { - self.Emit("MOVQ" , jit.Ptr(_VP, 8), _AX) // MOVQ 8(VP), AX - self.Emit("CMPQ" , _AX, jit.Ptr(_VP, 16)) // CMPQ AX, 16(VP) - self.Sjmp("JB" , "_index_{n}") // JB _index_{n} - self.Emit("MOVQ" , jit.Type(p.vt()), _AX) // MOVQ ${p.vt()}, AX - self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP) - self.Emit("MOVOU", jit.Ptr(_VP, 0), _X0) // MOVOU (VP), X0 - self.Emit("MOVOU", _X0, jit.Ptr(_SP, 8)) // MOVOU X0, 8(SP) - self.Emit("MOVQ" , jit.Ptr(_VP, 16), _AX) // MOVQ 16(VP), AX - self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 24)) // MOVQ AX, 24(SP) - self.Emit("SHLQ" , jit.Imm(1), _AX) // SHLQ $1, AX - self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 32)) // MOVQ AX, 32(SP) - self.call_go(_F_growslice) // CALL_GO growslice - self.Emit("MOVQ" , jit.Ptr(_SP, 40), _DI) // MOVQ 40(SP), DI - self.Emit("MOVQ" , jit.Ptr(_SP, 48), _AX) // MOVQ 48(SP), AX - self.Emit("MOVQ" , jit.Ptr(_SP, 56), _SI) // MOVQ 56(SP), SI - self.WriteRecNotAX(8, _DI, jit.Ptr(_VP, 0), true, true)// MOVQ DI, (VP) - self.Emit("MOVQ" , _AX, jit.Ptr(_VP, 8)) // MOVQ AX, 8(VP) - self.Emit("MOVQ" , _SI, jit.Ptr(_VP, 16)) // MOVQ SI, 16(VP) - - // because growslice not zero memory {oldcap, newlen} when append et not has ptrdata. - // but we should zero it, avoid decode it as random values. - if rt.UnpackType(p.vt()).PtrData == 0 { - self.Emit("SUBQ" , _AX, _SI) // MOVQ AX, SI - - self.Emit("ADDQ" , jit.Imm(1), jit.Ptr(_VP, 8)) // ADDQ $1, 8(VP) - self.Emit("MOVQ" , _DI, _VP) // MOVQ DI, VP - self.Emit("MOVQ" , jit.Imm(int64(p.vlen())), _CX) // MOVQ ${p.vlen()}, CX - self.From("MULQ" , _CX) // MULQ CX - self.Emit("ADDQ" , _AX, _VP) // ADDQ AX, VP - - self.Emit("MOVQ" , _SI, _AX) // MOVQ SI, AX - self.From("MULQ" , _CX) // MULQ CX - self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 8)) // MOVQ AX, 8(SP) - - self.Emit("MOVQ" , _VP, jit.Ptr(_SP, 0)) // MOVQ VP, (SP) - self.mem_clear_fn(true) // CALL_GO memclr{Has,NoHeap} - self.Sjmp("JMP", "_append_slice_end_{n}") // JMP _append_slice_end_{n} - } - - self.Link("_index_{n}") // _index_{n}: - self.Emit("ADDQ" , jit.Imm(1), jit.Ptr(_VP, 8)) // ADDQ $1, 8(VP) - self.Emit("MOVQ" , jit.Ptr(_VP, 0), _VP) // MOVQ (VP), VP - self.Emit("MOVQ" , jit.Imm(int64(p.vlen())), _CX) // MOVQ ${p.vlen()}, CX - self.From("MULQ" , _CX) // MULQ CX - self.Emit("ADDQ" , _AX, _VP) // ADDQ AX, VP - self.Link("_append_slice_end_{n}") -} - -func (self *_Assembler) _asm_OP_object_skip(_ *_Instr) { - self.call_sf(_F_skip_object) // CALL_SF skip_object - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JS" , _LB_parsing_error_v) // JS _parse_error_v -} - -func (self *_Assembler) _asm_OP_object_next(_ *_Instr) { - self.call_sf(_F_skip_one) // CALL_SF skip_one - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JS" , _LB_parsing_error_v) // JS _parse_error_v -} - -func (self *_Assembler) _asm_OP_struct_field(p *_Instr) { - assert_eq(caching.FieldEntrySize, 32, "invalid field entry size") - 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, true, false) // 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) - self.Emit("MOVQ" , _CX, jit.Ptr(_SP, 8)) // MOVQ CX, 8(SP) - self.call_go(_F_strhash) // CALL_GO strhash - self.Emit("MOVQ" , jit.Ptr(_SP, 16), _AX) // MOVQ 16(SP), AX - self.Emit("MOVQ" , _AX, _R9) // MOVQ AX, R9 - self.Emit("MOVQ" , jit.Imm(freezeFields(p.vf())), _CX) // MOVQ ${p.vf()}, CX - self.Emit("MOVQ" , jit.Ptr(_CX, caching.FieldMap_b), _SI) // MOVQ FieldMap.b(CX), SI - self.Emit("MOVQ" , jit.Ptr(_CX, caching.FieldMap_N), _CX) // MOVQ FieldMap.N(CX), CX - self.Emit("TESTQ", _CX, _CX) // TESTQ CX, CX - self.Sjmp("JZ" , "_try_lowercase_{n}") // JZ _try_lowercase_{n} - self.Link("_loop_{n}") // _loop_{n}: - self.Emit("XORL" , _DX, _DX) // XORL DX, DX - self.From("DIVQ" , _CX) // DIVQ CX - self.Emit("LEAQ" , jit.Ptr(_DX, 1), _AX) // LEAQ 1(DX), AX - self.Emit("SHLQ" , jit.Imm(5), _DX) // SHLQ $5, DX - self.Emit("LEAQ" , jit.Sib(_SI, _DX, 1, 0), _DI) // LEAQ (SI)(DX), DI - self.Emit("MOVQ" , jit.Ptr(_DI, _Fe_Hash), _R8) // MOVQ FieldEntry.Hash(DI), R8 - self.Emit("TESTQ", _R8, _R8) // TESTQ R8, R8 - self.Sjmp("JZ" , "_try_lowercase_{n}") // JZ _try_lowercase_{n} - self.Emit("CMPQ" , _R8, _R9) // CMPQ R8, R9 - self.Sjmp("JNE" , "_loop_{n}") // JNE _loop_{n} - self.Emit("MOVQ" , jit.Ptr(_DI, _Fe_Name + 8), _DX) // MOVQ FieldEntry.Name+8(DI), DX - self.Emit("CMPQ" , _DX, _VAR_sv_n) // CMPQ DX, sv.n - self.Sjmp("JNE" , "_loop_{n}") // JNE _loop_{n} - self.Emit("MOVQ" , jit.Ptr(_DI, _Fe_ID), _R8) // MOVQ FieldEntry.ID(DI), R8 - self.Emit("MOVQ" , _AX, _VAR_ss_AX) // MOVQ AX, ss.AX - self.Emit("MOVQ" , _CX, _VAR_ss_CX) // MOVQ CX, ss.CX - self.Emit("MOVQ" , _SI, _VAR_ss_SI) // MOVQ SI, ss.SI - self.Emit("MOVQ" , _R8, _VAR_ss_R8) // MOVQ R8, ss.R8 - self.Emit("MOVQ" , _R9, _VAR_ss_R9) // MOVQ R9, ss.R9 - self.Emit("MOVQ" , _VAR_sv_p, _AX) // MOVQ _VAR_sv_p, AX - self.Emit("MOVQ" , jit.Ptr(_DI, _Fe_Name), _CX) // MOVQ FieldEntry.Name(DI), CX - self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP) - self.Emit("MOVQ" , _CX, jit.Ptr(_SP, 8)) // MOVQ CX, 8(SP) - self.Emit("MOVQ" , _DX, jit.Ptr(_SP, 16)) // MOVQ DX, 16(SP) - self.call_go(_F_memequal) // CALL_GO memequal - self.Emit("MOVQ" , _VAR_ss_AX, _AX) // MOVQ ss.AX, AX - self.Emit("MOVQ" , _VAR_ss_CX, _CX) // MOVQ ss.CX, CX - self.Emit("MOVQ" , _VAR_ss_SI, _SI) // MOVQ ss.SI, SI - self.Emit("MOVQ" , _VAR_ss_R9, _R9) // MOVQ ss.R9, R9 - self.Emit("MOVB" , jit.Ptr(_SP, 24), _DX) // MOVB 24(SP), DX - self.Emit("TESTB", _DX, _DX) // TESTB DX, DX - self.Sjmp("JZ" , "_loop_{n}") // JZ _loop_{n} - self.Emit("MOVQ" , _VAR_ss_R8, _R8) // MOVQ ss.R8, R8 - self.Emit("MOVQ" , _R8, _VAR_sr) // MOVQ R8, sr - self.Sjmp("JMP" , "_end_{n}") // JMP _end_{n} - self.Link("_try_lowercase_{n}") // _try_lowercase_{n}: - self.Emit("MOVQ" , jit.Imm(referenceFields(p.vf())), _AX) // MOVQ ${p.vf()}, AX - self.Emit("MOVOU", _VAR_sv, _X0) // MOVOU sv, X0 - self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP) - self.Emit("MOVOU", _X0, jit.Ptr(_SP, 8)) // MOVOU X0, 8(SP) - self.call_go(_F_FieldMap_GetCaseInsensitive) // CALL_GO FieldMap::GetCaseInsensitive - self.Emit("MOVQ" , jit.Ptr(_SP, 24), _AX) // MOVQ 24(SP), AX - self.Emit("MOVQ" , _AX, _VAR_sr) // MOVQ AX, _VAR_sr - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JNS" , "_end_{n}") // JNS _end_{n} - self.Emit("BTQ" , jit.Imm(_F_disable_unknown), _ARG_fv) // BTQ ${_F_disable_unknown}, fv - self.Sjmp("JC" , _LB_field_error) // JC _field_error - self.Link("_end_{n}") // _end_{n}: -} - -func (self *_Assembler) _asm_OP_unmarshal(p *_Instr) { - self.unmarshal_json(p.vt(), true) -} - -func (self *_Assembler) _asm_OP_unmarshal_p(p *_Instr) { - self.unmarshal_json(p.vt(), false) -} - -func (self *_Assembler) _asm_OP_unmarshal_text(p *_Instr) { - self.unmarshal_text(p.vt(), true) -} - -func (self *_Assembler) _asm_OP_unmarshal_text_p(p *_Instr) { - self.unmarshal_text(p.vt(), false) -} - -func (self *_Assembler) _asm_OP_lspace(_ *_Instr) { - self.lspace("_{n}") -} - -func (self *_Assembler) lspace(subfix string) { - var label = "_lspace" + subfix - - self.Emit("CMPQ" , _IC, _IL) // CMPQ IC, IL - self.Sjmp("JAE" , _LB_eof_error) // JAE _eof_error - self.Emit("MOVQ" , jit.Imm(_BM_space), _DX) // MOVQ _BM_space, DX - self.Emit("MOVBQZX", jit.Sib(_IP, _IC, 1, 0), _AX) // MOVBQZX (IP)(IC), AX - self.Emit("CMPQ" , _AX, jit.Imm(' ')) // CMPQ AX, $' ' - self.Sjmp("JA" , label) // JA _nospace_{n} - self.Emit("BTQ" , _AX, _DX) // BTQ AX, DX - self.Sjmp("JNC" , label) // JNC _nospace_{n} - - /* test up to 4 characters */ - for i := 0; i < 3; i++ { - self.Emit("ADDQ" , jit.Imm(1), _IC) // ADDQ $1, IC - self.Emit("CMPQ" , _IC, _IL) // CMPQ IC, IL - self.Sjmp("JAE" , _LB_eof_error) // JAE _eof_error - self.Emit("MOVBQZX", jit.Sib(_IP, _IC, 1, 0), _AX) // MOVBQZX (IP)(IC), AX - self.Emit("CMPQ" , _AX, jit.Imm(' ')) // CMPQ AX, $' ' - self.Sjmp("JA" , label) // JA _nospace_{n} - self.Emit("BTQ" , _AX, _DX) // BTQ AX, DX - self.Sjmp("JNC" , label) // JNC _nospace_{n} - } - - /* handle over to the native function */ - self.Emit("MOVQ" , _IP, _DI) // MOVQ IP, DI - self.Emit("MOVQ" , _IL, _SI) // MOVQ IL, SI - self.Emit("MOVQ" , _IC, _DX) // MOVQ IC, DX - self.call(_F_lspace) // CALL lspace - self.Emit("TESTQ" , _AX, _AX) // TESTQ AX, AX - self.Sjmp("JS" , _LB_parsing_error_v) // JS _parsing_error_v - self.Emit("CMPQ" , _AX, _IL) // CMPQ AX, IL - self.Sjmp("JAE" , _LB_eof_error) // JAE _eof_error - self.Emit("MOVQ" , _AX, _IC) // MOVQ AX, IC - self.Link(label) // _nospace_{n}: -} - -func (self *_Assembler) _asm_OP_match_char(p *_Instr) { - self.match_char(p.vb()) -} - -func (self *_Assembler) match_char(char byte) { - self.check_eof(1) - self.Emit("CMPB", jit.Sib(_IP, _IC, 1, 0), jit.Imm(int64(char))) // CMPB (IP)(IC), ${p.vb()} - self.Sjmp("JNE" , _LB_char_0_error) // JNE _char_0_error - self.Emit("ADDQ", jit.Imm(1), _IC) // ADDQ $1, IC -} - -func (self *_Assembler) _asm_OP_check_char(p *_Instr) { - self.check_eof(1) - self.Emit("LEAQ" , jit.Ptr(_IC, 1), _AX) // LEAQ 1(IC), AX - self.Emit("CMPB" , jit.Sib(_IP, _IC, 1, 0), jit.Imm(int64(p.vb()))) // CMPB (IP)(IC), ${p.vb()} - self.Emit("CMOVQEQ", _AX, _IC) // CMOVQEQ AX, IC - self.Xjmp("JE" , p.vi()) // JE {p.vi()} -} - -func (self *_Assembler) _asm_OP_check_char_0(p *_Instr) { - self.check_eof(1) - self.Emit("CMPB", jit.Sib(_IP, _IC, 1, 0), jit.Imm(int64(p.vb()))) // CMPB (IP)(IC), ${p.vb()} - self.Xjmp("JE" , p.vi()) // JE {p.vi()} -} - -func (self *_Assembler) _asm_OP_add(p *_Instr) { - self.Emit("ADDQ", jit.Imm(int64(p.vi())), _IC) // ADDQ ${p.vi()}, IC -} - -func (self *_Assembler) _asm_OP_load(_ *_Instr) { - self.Emit("MOVQ", jit.Ptr(_ST, 0), _AX) // MOVQ (ST), AX - self.Emit("MOVQ", jit.Sib(_ST, _AX, 1, 0), _VP) // MOVQ (ST)(AX), VP -} - -func (self *_Assembler) _asm_OP_save(_ *_Instr) { - self.Emit("MOVQ", jit.Ptr(_ST, 0), _CX) // MOVQ (ST), CX - 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) -} - -func (self *_Assembler) _asm_OP_drop(_ *_Instr) { - self.Emit("MOVQ", jit.Ptr(_ST, 0), _AX) // MOVQ (ST), AX - self.Emit("SUBQ", jit.Imm(8), _AX) // SUBQ $8, AX - self.Emit("MOVQ", jit.Sib(_ST, _AX, 1, 8), _VP) // MOVQ 8(ST)(AX), VP - self.Emit("MOVQ", _AX, jit.Ptr(_ST, 0)) // MOVQ AX, (ST) - self.Emit("XORL", _ET, _ET) // XORL ET, ET - self.Emit("MOVQ", _ET, jit.Sib(_ST, _AX, 1, 8)) // MOVQ ET, 8(ST)(AX) -} - -func (self *_Assembler) _asm_OP_drop_2(_ *_Instr) { - self.Emit("MOVQ" , jit.Ptr(_ST, 0), _AX) // MOVQ (ST), AX - self.Emit("SUBQ" , jit.Imm(16), _AX) // SUBQ $16, AX - self.Emit("MOVQ" , jit.Sib(_ST, _AX, 1, 8), _VP) // MOVQ 8(ST)(AX), VP - self.Emit("MOVQ" , _AX, jit.Ptr(_ST, 0)) // MOVQ AX, (ST) - self.Emit("PXOR" , _X0, _X0) // PXOR X0, X0 - self.Emit("MOVOU", _X0, jit.Sib(_ST, _AX, 1, 8)) // MOVOU X0, 8(ST)(AX) -} - -func (self *_Assembler) _asm_OP_recurse(p *_Instr) { - self.Emit("MOVQ", jit.Type(p.vt()), _AX) // MOVQ ${p.vt()}, AX - self.decode_dynamic(_AX, _VP) // DECODE AX, VP -} - -func (self *_Assembler) _asm_OP_goto(p *_Instr) { - self.Xjmp("JMP", p.vi()) -} - -func (self *_Assembler) _asm_OP_switch(p *_Instr) { - self.Emit("MOVQ", _VAR_sr, _AX) // MOVQ sr, AX - self.Emit("CMPQ", _AX, jit.Imm(p.i64())) // CMPQ AX, ${len(p.vs())} - self.Sjmp("JAE" , "_default_{n}") // JAE _default_{n} - - /* jump table selector */ - self.Byte(0x48, 0x8d, 0x3d) // LEAQ ?(PC), DI - self.Sref("_switch_table_{n}", 4) // .... &_switch_table_{n} - self.Emit("MOVLQSX", jit.Sib(_DI, _AX, 4, 0), _AX) // MOVLQSX (DI)(AX*4), AX - self.Emit("ADDQ" , _DI, _AX) // ADDQ DI, AX - self.Rjmp("JMP" , _AX) // JMP AX - self.Link("_switch_table_{n}") // _switch_table_{n}: - - /* generate the jump table */ - for i, v := range p.vs() { - self.Xref(v, int64(-i) * 4) - } - - /* default case */ - self.Link("_default_{n}") - self.NOP() -} - -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) -} diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/consts/option.go b/vendor/github.com/bytedance/sonic/internal/decoder/consts/option.go new file mode 100644 index 000000000..4195ebda7 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/consts/option.go @@ -0,0 +1,36 @@ + +package consts + +import ( + `github.com/bytedance/sonic/internal/native/types` +) + + +const ( + F_use_int64 = 0 + F_disable_urc = 2 + F_disable_unknown = 3 + F_copy_string = 4 + + + F_use_number = types.B_USE_NUMBER + F_validate_string = types.B_VALIDATE_STRING + F_allow_control = types.B_ALLOW_CONTROL + F_no_validate_json = types.B_NO_VALIDATE_JSON +) + +type Options uint64 + +const ( + OptionUseInt64 Options = 1 << F_use_int64 + OptionUseNumber Options = 1 << F_use_number + OptionUseUnicodeErrors Options = 1 << F_disable_urc + OptionDisableUnknown Options = 1 << F_disable_unknown + OptionCopyString Options = 1 << F_copy_string + OptionValidateString Options = 1 << F_validate_string + OptionNoValidateJSON Options = 1 << F_no_validate_json +) + +const ( + MaxStack = 4096 +) \ No newline at end of file diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/errors.go b/vendor/github.com/bytedance/sonic/internal/decoder/errors/errors.go similarity index 90% rename from vendor/github.com/bytedance/sonic/internal/decoder/errors.go rename to vendor/github.com/bytedance/sonic/internal/decoder/errors/errors.go index 4453f5cfe..9f05e8b6a 100644 --- a/vendor/github.com/bytedance/sonic/internal/decoder/errors.go +++ b/vendor/github.com/bytedance/sonic/internal/decoder/errors/errors.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package decoder +package errors import ( `encoding/json` @@ -46,7 +46,7 @@ func (self SyntaxError) Description() string { func (self SyntaxError) description() string { /* check for empty source */ if self.Src == "" { - return fmt.Sprintf("no sources available: %#v", self) + return fmt.Sprintf("no sources available, the input json is empty: %#v", self) } p, x, q, y := calcBounds(len(self.Src), self.Pos) @@ -112,12 +112,12 @@ func clamp_zero(v int) int { /** JIT Error Helpers **/ -var stackOverflow = &json.UnsupportedValueError { +var StackOverflow = &json.UnsupportedValueError { Str : "Value nesting too deep", Value : reflect.ValueOf("..."), } -func error_wrap(src string, pos int, code types.ParsingError) error { +func ErrorWrap(src string, pos int, code types.ParsingError) error { return *error_wrap_heap(src, pos, code) } @@ -130,7 +130,7 @@ func error_wrap_heap(src string, pos int, code types.ParsingError) *SyntaxError } } -func error_type(vt *rt.GoType) error { +func ErrorType(vt *rt.GoType) error { return &json.UnmarshalTypeError{Type: vt.Pack()} } @@ -171,7 +171,7 @@ func (self MismatchTypeError) Description() string { return fmt.Sprintf("Mismatch type %s with value %s %s", self.Type.String(), swithchJSONType(self.Src, self.Pos), se.description()) } -func error_mismatch(src string, pos int, vt *rt.GoType) error { +func ErrorMismatch(src string, pos int, vt *rt.GoType) error { return &MismatchTypeError { Pos : pos, Src : src, @@ -179,11 +179,11 @@ func error_mismatch(src string, pos int, vt *rt.GoType) error { } } -func error_field(name string) error { +func ErrorField(name string) error { return errors.New("json: unknown field " + strconv.Quote(name)) } -func error_value(value string, vtype reflect.Type) error { +func ErrorValue(value string, vtype reflect.Type) error { return &json.UnmarshalTypeError { Type : vtype, Value : value, diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/generic_stkabi_amd64.go b/vendor/github.com/bytedance/sonic/internal/decoder/generic_stkabi_amd64.go deleted file mode 100644 index 8ce5c2926..000000000 --- a/vendor/github.com/bytedance/sonic/internal/decoder/generic_stkabi_amd64.go +++ /dev/null @@ -1,733 +0,0 @@ -// +build go1.16,!go1.17 - -/* - * 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 ( - `encoding/json` - `fmt` - `reflect` - - `github.com/bytedance/sonic/internal/jit` - `github.com/bytedance/sonic/internal/native` - `github.com/bytedance/sonic/internal/native/types` - `github.com/twitchyliquid64/golang-asm/obj` -) - -/** Crucial Registers: - * - * ST(BX) : ro, decoder stack - * DF(R10) : ro, decoder flags - * EP(R11) : wo, error pointer - * IP(R12) : ro, input pointer - * IL(R13) : ro, input length - * IC(R14) : rw, input cursor - * VP(R15) : ro, value pointer (to an interface{}) - */ - -const ( - _VD_args = 8 // 8 bytes for passing arguments to this functions - _VD_fargs = 64 // 64 bytes for passing arguments to other Go functions - _VD_saves = 40 // 40 bytes for saving the registers before CALL instructions - _VD_locals = 88 // 88 bytes for local variables -) - -const ( - _VD_offs = _VD_fargs + _VD_saves + _VD_locals - _VD_size = _VD_offs + 8 // 8 bytes for the parent frame pointer -) - -var ( - _VAR_ss = _VAR_ss_Vt - _VAR_df = jit.Ptr(_SP, _VD_fargs + _VD_saves) -) - -var ( - _VAR_ss_Vt = jit.Ptr(_SP, _VD_fargs + _VD_saves + 8) - _VAR_ss_Dv = jit.Ptr(_SP, _VD_fargs + _VD_saves + 16) - _VAR_ss_Iv = jit.Ptr(_SP, _VD_fargs + _VD_saves + 24) - _VAR_ss_Ep = jit.Ptr(_SP, _VD_fargs + _VD_saves + 32) - _VAR_ss_Db = jit.Ptr(_SP, _VD_fargs + _VD_saves + 40) - _VAR_ss_Dc = jit.Ptr(_SP, _VD_fargs + _VD_saves + 48) -) - -var ( - _VAR_cs_LR = jit.Ptr(_SP, _VD_fargs + _VD_saves + 56) - _VAR_cs_p = jit.Ptr(_SP, _VD_fargs + _VD_saves + 64) - _VAR_cs_n = jit.Ptr(_SP, _VD_fargs + _VD_saves + 72) - _VAR_cs_d = jit.Ptr(_SP, _VD_fargs + _VD_saves + 80) -) - -type _ValueDecoder struct { - jit.BaseAssembler -} - -func (self *_ValueDecoder) build() uintptr { - self.Init(self.compile) - return *(*uintptr)(self.Load("decode_value", _VD_size, _VD_args, argPtrs_generic, localPtrs_generic)) -} - -/** Function Calling Helpers **/ - -func (self *_ValueDecoder) save(r ...obj.Addr) { - for i, v := range r { - if i > _VD_saves / 8 - 1 { - panic("too many registers to save") - } else { - self.Emit("MOVQ", v, jit.Ptr(_SP, _VD_fargs + int64(i) * 8)) - } - } -} - -func (self *_ValueDecoder) load(r ...obj.Addr) { - for i, v := range r { - if i > _VD_saves / 8 - 1 { - panic("too many registers to load") - } else { - self.Emit("MOVQ", jit.Ptr(_SP, _VD_fargs + int64(i) * 8), v) - } - } -} - -func (self *_ValueDecoder) call(fn obj.Addr) { - self.Emit("MOVQ", fn, _AX) // MOVQ ${fn}, AX - self.Rjmp("CALL", _AX) // CALL AX -} - -func (self *_ValueDecoder) call_go(fn obj.Addr) { - self.save(_REG_go...) // SAVE $REG_go - self.call(fn) // CALL ${fn} - self.load(_REG_go...) // LOAD $REG_go -} - -/** Decoder Assembler **/ - -const ( - _S_val = iota + 1 - _S_arr - _S_arr_0 - _S_obj - _S_obj_0 - _S_obj_delim - _S_obj_sep -) - -const ( - _S_omask_key = (1 << _S_obj_0) | (1 << _S_obj_sep) - _S_omask_end = (1 << _S_obj_0) | (1 << _S_obj) - _S_vmask = (1 << _S_val) | (1 << _S_arr_0) -) - -const ( - _A_init_len = 1 - _A_init_cap = 16 -) - -const ( - _ST_Sp = 0 - _ST_Vt = _PtrBytes - _ST_Vp = _PtrBytes * (types.MAX_RECURSE + 1) -) - -var ( - _V_true = jit.Imm(int64(pbool(true))) - _V_false = jit.Imm(int64(pbool(false))) - _F_value = jit.Imm(int64(native.S_value)) -) - -var ( - _V_max = jit.Imm(int64(types.V_MAX)) - _E_eof = jit.Imm(int64(types.ERR_EOF)) - _E_invalid = jit.Imm(int64(types.ERR_INVALID_CHAR)) - _E_recurse = jit.Imm(int64(types.ERR_RECURSE_EXCEED_MAX)) -) - -var ( - _F_convTslice = jit.Func(convTslice) - _F_convTstring = jit.Func(convTstring) - _F_invalid_vtype = jit.Func(invalid_vtype) -) - -var ( - _T_map = jit.Type(reflect.TypeOf((map[string]interface{})(nil))) - _T_bool = jit.Type(reflect.TypeOf(false)) - _T_int64 = jit.Type(reflect.TypeOf(int64(0))) - _T_eface = jit.Type(reflect.TypeOf((*interface{})(nil)).Elem()) - _T_slice = jit.Type(reflect.TypeOf(([]interface{})(nil))) - _T_string = jit.Type(reflect.TypeOf("")) - _T_number = jit.Type(reflect.TypeOf(json.Number(""))) - _T_float64 = jit.Type(reflect.TypeOf(float64(0))) -) - -var _R_tab = map[int]string { - '[': "_decode_V_ARRAY", - '{': "_decode_V_OBJECT", - ':': "_decode_V_KEY_SEP", - ',': "_decode_V_ELEM_SEP", - ']': "_decode_V_ARRAY_END", - '}': "_decode_V_OBJECT_END", -} - -func (self *_ValueDecoder) compile() { - self.Emit("SUBQ", jit.Imm(_VD_size), _SP) // SUBQ $_VD_size, SP - self.Emit("MOVQ", _BP, jit.Ptr(_SP, _VD_offs)) // MOVQ BP, _VD_offs(SP) - self.Emit("LEAQ", jit.Ptr(_SP, _VD_offs), _BP) // LEAQ _VD_offs(SP), BP - - /* initialize the state machine */ - self.Emit("XORL", _CX, _CX) // XORL CX, CX - self.Emit("MOVQ", _DF, _VAR_df) // MOVQ DF, df - /* initialize digital buffer first */ - self.Emit("MOVQ", jit.Imm(_MaxDigitNums), _VAR_ss_Dc) // MOVQ $_MaxDigitNums, ss.Dcap - self.Emit("LEAQ", jit.Ptr(_ST, _DbufOffset), _AX) // LEAQ _DbufOffset(ST), AX - self.Emit("MOVQ", _AX, _VAR_ss_Db) // MOVQ AX, ss.Dbuf - /* add ST offset */ - self.Emit("ADDQ", jit.Imm(_FsmOffset), _ST) // ADDQ _FsmOffset, _ST - self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp - self.WriteRecNotAX(0, _VP, jit.Ptr(_ST, _ST_Vp), false) // MOVQ VP, ST.Vp[0] - self.Emit("MOVQ", jit.Imm(_S_val), jit.Ptr(_ST, _ST_Vt)) // MOVQ _S_val, ST.Vt[0] - self.Sjmp("JMP" , "_next") // JMP _next - - /* set the value from previous round */ - self.Link("_set_value") // _set_value: - self.Emit("MOVL" , jit.Imm(_S_vmask), _DX) // MOVL _S_vmask, DX - self.Emit("MOVQ" , jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX - self.Emit("MOVQ" , jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX - self.Emit("BTQ" , _AX, _DX) // BTQ AX, DX - self.Sjmp("JNC" , "_vtype_error") // JNC _vtype_error - self.Emit("XORL" , _SI, _SI) // XORL SI, SI - self.Emit("SUBQ" , jit.Imm(1), jit.Ptr(_ST, _ST_Sp)) // SUBQ $1, ST.Sp - self.Emit("XCHGQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // XCHGQ ST.Vp[CX], SI - self.Emit("MOVQ" , _R8, jit.Ptr(_SI, 0)) // MOVQ R8, (SI) - self.WriteRecNotAX(1, _R9, jit.Ptr(_SI, 8), false) // MOVQ R9, 8(SI) - - /* check for value stack */ - self.Link("_next") // _next: - self.Emit("MOVQ" , jit.Ptr(_ST, _ST_Sp), _AX) // MOVQ ST.Sp, AX - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JS" , "_return") // JS _return - - /* fast path: test up to 4 characters manually */ - self.Emit("CMPQ" , _IC, _IL) // CMPQ IC, IL - self.Sjmp("JAE" , "_decode_V_EOF") // JAE _decode_V_EOF - self.Emit("MOVBQZX", jit.Sib(_IP, _IC, 1, 0), _AX) // MOVBQZX (IP)(IC), AX - self.Emit("MOVQ" , jit.Imm(_BM_space), _DX) // MOVQ _BM_space, DX - self.Emit("CMPQ" , _AX, jit.Imm(' ')) // CMPQ AX, $' ' - self.Sjmp("JA" , "_decode_fast") // JA _decode_fast - self.Emit("BTQ" , _AX, _DX) // BTQ _AX, _DX - self.Sjmp("JNC" , "_decode_fast") // JNC _decode_fast - self.Emit("ADDQ" , jit.Imm(1), _IC) // ADDQ $1, IC - - /* at least 1 to 3 spaces */ - for i := 0; i < 3; i++ { - self.Emit("CMPQ" , _IC, _IL) // CMPQ IC, IL - self.Sjmp("JAE" , "_decode_V_EOF") // JAE _decode_V_EOF - self.Emit("MOVBQZX", jit.Sib(_IP, _IC, 1, 0), _AX) // MOVBQZX (IP)(IC), AX - self.Emit("CMPQ" , _AX, jit.Imm(' ')) // CMPQ AX, $' ' - self.Sjmp("JA" , "_decode_fast") // JA _decode_fast - self.Emit("BTQ" , _AX, _DX) // BTQ _AX, _DX - self.Sjmp("JNC" , "_decode_fast") // JNC _decode_fast - self.Emit("ADDQ" , jit.Imm(1), _IC) // ADDQ $1, IC - } - - /* at least 4 spaces */ - self.Emit("CMPQ" , _IC, _IL) // CMPQ IC, IL - self.Sjmp("JAE" , "_decode_V_EOF") // JAE _decode_V_EOF - self.Emit("MOVBQZX", jit.Sib(_IP, _IC, 1, 0), _AX) // MOVBQZX (IP)(IC), AX - - /* fast path: use lookup table to select decoder */ - self.Link("_decode_fast") // _decode_fast: - self.Byte(0x48, 0x8d, 0x3d) // LEAQ ?(PC), DI - self.Sref("_decode_tab", 4) // .... &_decode_tab - self.Emit("MOVLQSX", jit.Sib(_DI, _AX, 4, 0), _AX) // MOVLQSX (DI)(AX*4), AX - self.Emit("TESTQ" , _AX, _AX) // TESTQ AX, AX - self.Sjmp("JZ" , "_decode_native") // JZ _decode_native - self.Emit("ADDQ" , jit.Imm(1), _IC) // ADDQ $1, IC - self.Emit("ADDQ" , _DI, _AX) // ADDQ DI, AX - self.Rjmp("JMP" , _AX) // JMP AX - - /* decode with native decoder */ - self.Link("_decode_native") // _decode_native: - self.Emit("MOVQ", _IP, _DI) // MOVQ IP, DI - self.Emit("MOVQ", _IL, _SI) // MOVQ IL, SI - self.Emit("MOVQ", _IC, _DX) // MOVQ IC, DX - self.Emit("LEAQ", _VAR_ss, _CX) // LEAQ ss, CX - self.Emit("MOVQ", _VAR_df, _R8) // MOVQ $df, R8 - self.Emit("BTSQ", jit.Imm(_F_allow_control), _R8) // ANDQ $1<<_F_allow_control, R8 - self.call(_F_value) // CALL value - self.Emit("MOVQ", _AX, _IC) // MOVQ AX, IC - - /* check for errors */ - self.Emit("MOVQ" , _VAR_ss_Vt, _AX) // MOVQ ss.Vt, AX - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JS" , "_parsing_error") - self.Sjmp("JZ" , "_invalid_vtype") // JZ _invalid_vtype - self.Emit("CMPQ" , _AX, _V_max) // CMPQ AX, _V_max - self.Sjmp("JA" , "_invalid_vtype") // JA _invalid_vtype - - /* jump table selector */ - self.Byte(0x48, 0x8d, 0x3d) // LEAQ ?(PC), DI - self.Sref("_switch_table", 4) // .... &_switch_table - self.Emit("MOVLQSX", jit.Sib(_DI, _AX, 4, -4), _AX) // MOVLQSX -4(DI)(AX*4), AX - self.Emit("ADDQ" , _DI, _AX) // ADDQ DI, AX - self.Rjmp("JMP" , _AX) // JMP AX - - /** V_EOF **/ - self.Link("_decode_V_EOF") // _decode_V_EOF: - self.Emit("MOVL", _E_eof, _EP) // MOVL _E_eof, EP - self.Sjmp("JMP" , "_error") // JMP _error - - /** V_NULL **/ - self.Link("_decode_V_NULL") // _decode_V_NULL: - self.Emit("XORL", _R8, _R8) // XORL R8, R8 - self.Emit("XORL", _R9, _R9) // XORL R9, R9 - self.Emit("LEAQ", jit.Ptr(_IC, -4), _DI) // LEAQ -4(IC), DI - self.Sjmp("JMP" , "_set_value") // JMP _set_value - - /** V_TRUE **/ - self.Link("_decode_V_TRUE") // _decode_V_TRUE: - self.Emit("MOVQ", _T_bool, _R8) // MOVQ _T_bool, R8 - // TODO: maybe modified by users? - self.Emit("MOVQ", _V_true, _R9) // MOVQ _V_true, R9 - self.Emit("LEAQ", jit.Ptr(_IC, -4), _DI) // LEAQ -4(IC), DI - self.Sjmp("JMP" , "_set_value") // JMP _set_value - - /** V_FALSE **/ - self.Link("_decode_V_FALSE") // _decode_V_FALSE: - self.Emit("MOVQ", _T_bool, _R8) // MOVQ _T_bool, R8 - self.Emit("MOVQ", _V_false, _R9) // MOVQ _V_false, R9 - self.Emit("LEAQ", jit.Ptr(_IC, -5), _DI) // LEAQ -5(IC), DI - self.Sjmp("JMP" , "_set_value") // JMP _set_value - - /** V_ARRAY **/ - self.Link("_decode_V_ARRAY") // _decode_V_ARRAY - self.Emit("MOVL", jit.Imm(_S_vmask), _DX) // MOVL _S_vmask, DX - self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX - self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX - self.Emit("BTQ" , _AX, _DX) // BTQ AX, DX - self.Sjmp("JNC" , "_invalid_char") // JNC _invalid_char - - /* create a new array */ - self.Emit("MOVQ", _T_eface, _AX) // MOVQ _T_eface, AX - self.Emit("MOVQ", _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP) - self.Emit("MOVQ", jit.Imm(_A_init_len), jit.Ptr(_SP, 8)) // MOVQ _A_init_len, 8(SP) - self.Emit("MOVQ", jit.Imm(_A_init_cap), jit.Ptr(_SP, 16)) // MOVQ _A_init_cap, 16(SP) - self.call_go(_F_makeslice) // CALL_GO runtime.makeslice - self.Emit("MOVQ", jit.Ptr(_SP, 24), _DX) // MOVQ 24(SP), DX - - /* pack into an interface */ - self.Emit("MOVQ", _DX, jit.Ptr(_SP, 0)) // MOVQ DX, (SP) - self.Emit("MOVQ", jit.Imm(_A_init_len), jit.Ptr(_SP, 8)) // MOVQ _A_init_len, 8(SP) - self.Emit("MOVQ", jit.Imm(_A_init_cap), jit.Ptr(_SP, 16)) // MOVQ _A_init_cap, 16(SP) - self.call_go(_F_convTslice) // CALL_GO runtime.convTslice - self.Emit("MOVQ", jit.Ptr(_SP, 24), _R8) // MOVQ 24(SP), R8 - - /* replace current state with an array */ - self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX - self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI - self.Emit("MOVQ", jit.Imm(_S_arr), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_arr, ST.Vt[CX] - self.Emit("MOVQ", _T_slice, _AX) // MOVQ _T_slice, AX - self.Emit("MOVQ", _AX, jit.Ptr(_SI, 0)) // MOVQ AX, (SI) - self.WriteRecNotAX(2, _R8, jit.Ptr(_SI, 8), false) // MOVQ R8, 8(SI) - - /* 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("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] - self.Emit("MOVQ", jit.Imm(_S_arr_0), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_arr_0, ST.Vt[CX] - self.Sjmp("JMP" , "_next") // JMP _next - - /** V_OBJECT **/ - self.Link("_decode_V_OBJECT") // _decode_V_OBJECT: - self.Emit("MOVL", jit.Imm(_S_vmask), _DX) // MOVL _S_vmask, DX - self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX - self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX - self.Emit("BTQ" , _AX, _DX) // BTQ AX, DX - self.Sjmp("JNC" , "_invalid_char") // JNC _invalid_char - self.call_go(_F_makemap_small) // CALL_GO runtime.makemap_small - self.Emit("MOVQ", jit.Ptr(_SP, 0), _AX) // MOVQ (SP), AX - self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX - self.Emit("MOVQ", jit.Imm(_S_obj_0), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_obj, ST.Vt[CX] - self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI - self.Emit("MOVQ", _T_map, _DX) // MOVQ _T_map, DX - self.Emit("MOVQ", _DX, jit.Ptr(_SI, 0)) // MOVQ DX, (SI) - self.WritePtrAX(4, jit.Ptr(_SI, 8), false) // MOVQ AX, 8(SI) - self.Sjmp("JMP" , "_next") // JMP _next - - /** V_STRING **/ - self.Link("_decode_V_STRING") // _decode_V_STRING: - self.Emit("MOVQ", _VAR_ss_Iv, _CX) // MOVQ ss.Iv, CX - self.Emit("MOVQ", _IC, _AX) // MOVQ IC, AX - self.Emit("SUBQ", _CX, _AX) // SUBQ CX, AX - - /* check for escapes */ - self.Emit("CMPQ", _VAR_ss_Ep, jit.Imm(-1)) // CMPQ ss.Ep, $-1 - self.Sjmp("JNE" , "_unquote") // JNE _unquote - self.Emit("SUBQ", jit.Imm(1), _AX) // SUBQ $1, AX - self.Emit("LEAQ", jit.Sib(_IP, _CX, 1, 0), _R8) // LEAQ (IP)(CX), R8 - self.Byte(0x48, 0x8d, 0x3d) // LEAQ (PC), DI - self.Sref("_copy_string_end", 4) - self.Emit("BTQ", jit.Imm(_F_copy_string), _VAR_df) - self.Sjmp("JC", "copy_string") - self.Link("_copy_string_end") - self.Emit("XORL", _DX, _DX) // XORL DX, DX - /* strings with no escape sequences */ - self.Link("_noescape") // _noescape: - self.Emit("MOVL", jit.Imm(_S_omask_key), _DI) // MOVL _S_omask, DI - self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX - self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _SI) // MOVQ ST.Vt[CX], SI - self.Emit("BTQ" , _SI, _DI) // BTQ SI, DI - self.Sjmp("JC" , "_object_key") // JC _object_key - - /* check for pre-packed strings, avoid 1 allocation */ - self.Emit("TESTQ", _DX, _DX) // TESTQ DX, DX - self.Sjmp("JNZ" , "_packed_str") // JNZ _packed_str - self.Emit("MOVQ" , _R8, jit.Ptr(_SP, 0)) // MOVQ R8, (SP) - self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 8)) // MOVQ AX, 8(SP) - self.call_go(_F_convTstring) // CALL_GO runtime.convTstring - self.Emit("MOVQ" , jit.Ptr(_SP, 16), _R9) // MOVQ 16(SP), R9 - - /* packed string already in R9 */ - self.Link("_packed_str") // _packed_str: - self.Emit("MOVQ", _T_string, _R8) // MOVQ _T_string, R8 - self.Emit("MOVQ", _VAR_ss_Iv, _DI) // MOVQ ss.Iv, DI - self.Emit("SUBQ", jit.Imm(1), _DI) // SUBQ $1, DI - self.Sjmp("JMP" , "_set_value") // JMP _set_value - - /* the string is an object key, get the map */ - self.Link("_object_key") - self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX - self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI - self.Emit("MOVQ", jit.Ptr(_SI, 8), _SI) // MOVQ 8(SI), SI - - /* 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("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] - - /* add a new slot int the map */ - self.Emit("MOVQ", _T_map, _DX) // MOVQ _T_map, DX - self.Emit("MOVQ", _DX, jit.Ptr(_SP, 0)) // MOVQ DX, (SP) - self.Emit("MOVQ", _SI, jit.Ptr(_SP, 8)) // MOVQ SI, 8(SP) - self.Emit("MOVQ", _R8, jit.Ptr(_SP, 16)) // MOVQ R9, 16(SP) - self.Emit("MOVQ", _AX, jit.Ptr(_SP, 24)) // MOVQ AX, 24(SP) - self.call_go(_F_mapassign_faststr) // CALL_GO runtime.mapassign_faststr - self.Emit("MOVQ", jit.Ptr(_SP, 32), _AX) // MOVQ 32(SP), AX - - /* add to the pointer stack */ - self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX - self.WritePtrAX(6, jit.Sib(_ST, _CX, 8, _ST_Vp), false) // MOVQ AX, ST.Vp[CX] - self.Sjmp("JMP" , "_next") // JMP _next - - /* allocate memory to store the string header and unquoted result */ - self.Link("_unquote") // _unquote: - self.Emit("ADDQ", jit.Imm(15), _AX) // ADDQ $15, AX - self.Emit("MOVQ", _T_byte, _CX) // MOVQ _T_byte, CX - self.Emit("MOVQ", _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP) - self.Emit("MOVQ", _CX, jit.Ptr(_SP, 8)) // MOVQ CX, 8(SP) - self.Emit("MOVB", jit.Imm(0), jit.Ptr(_SP, 16)) // MOVB $0, 16(SP) - self.call_go(_F_mallocgc) // CALL_GO runtime.mallocgc - self.Emit("MOVQ", jit.Ptr(_SP, 24), _R9) // MOVQ 24(SP), R9 - - /* prepare the unquoting parameters */ - self.Emit("MOVQ" , _VAR_ss_Iv, _CX) // MOVQ ss.Iv, CX - self.Emit("LEAQ" , jit.Sib(_IP, _CX, 1, 0), _DI) // LEAQ (IP)(CX), DI - self.Emit("NEGQ" , _CX) // NEGQ CX - self.Emit("LEAQ" , jit.Sib(_IC, _CX, 1, -1), _SI) // LEAQ -1(IC)(CX), SI - self.Emit("LEAQ" , jit.Ptr(_R9, 16), _DX) // LEAQ 16(R8), DX - self.Emit("LEAQ" , _VAR_ss_Ep, _CX) // LEAQ ss.Ep, CX - self.Emit("XORL" , _R8, _R8) // XORL R8, R8 - self.Emit("BTQ" , jit.Imm(_F_disable_urc), _VAR_df) // BTQ ${_F_disable_urc}, fv - self.Emit("SETCC", _R8) // SETCC R8 - self.Emit("SHLQ" , jit.Imm(types.B_UNICODE_REPLACE), _R8) // SHLQ ${types.B_UNICODE_REPLACE}, R8 - - /* unquote the string, with R9 been preserved */ - self.save(_R9) // SAVE R9 - self.call(_F_unquote) // CALL unquote - self.load(_R9) // LOAD R9 - - /* check for errors */ - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JS" , "_unquote_error") // JS _unquote_error - self.Emit("MOVL" , jit.Imm(1), _DX) // MOVL $1, DX - self.Emit("LEAQ" , jit.Ptr(_R9, 16), _R8) // ADDQ $16, R8 - self.Emit("MOVQ" , _R8, jit.Ptr(_R9, 0)) // MOVQ R8, (R9) - self.Emit("MOVQ" , _AX, jit.Ptr(_R9, 8)) // MOVQ AX, 8(R9) - self.Sjmp("JMP" , "_noescape") // JMP _noescape - - /** V_DOUBLE **/ - self.Link("_decode_V_DOUBLE") // _decode_V_DOUBLE: - self.Emit("BTQ" , jit.Imm(_F_use_number), _VAR_df) // BTQ _F_use_number, df - self.Sjmp("JC" , "_use_number") // JC _use_number - self.Emit("MOVSD", _VAR_ss_Dv, _X0) // MOVSD ss.Dv, X0 - self.Sjmp("JMP" , "_use_float64") // JMP _use_float64 - - /** V_INTEGER **/ - self.Link("_decode_V_INTEGER") // _decode_V_INTEGER: - self.Emit("BTQ" , jit.Imm(_F_use_number), _VAR_df) // BTQ _F_use_number, df - self.Sjmp("JC" , "_use_number") // JC _use_number - self.Emit("BTQ" , jit.Imm(_F_use_int64), _VAR_df) // BTQ _F_use_int64, df - self.Sjmp("JC" , "_use_int64") // JC _use_int64 - self.Emit("MOVQ" , _VAR_ss_Iv, _AX) // MOVQ ss.Iv, AX - self.Emit("CVTSQ2SD", _AX, _X0) // CVTSQ2SD AX, X0 - - /* represent numbers as `float64` */ - self.Link("_use_float64") // _use_float64: - self.Emit("MOVSD", _X0, jit.Ptr(_SP, 0)) // MOVSD X0, (SP) - self.call_go(_F_convT64) // CALL_GO runtime.convT64 - self.Emit("MOVQ" , _T_float64, _R8) // MOVQ _T_float64, R8 - self.Emit("MOVQ" , jit.Ptr(_SP, 8), _R9) // MOVQ 8(SP), R9 - self.Emit("MOVQ" , _VAR_ss_Ep, _DI) // MOVQ ss.Ep, DI - self.Sjmp("JMP" , "_set_value") // JMP _set_value - - /* represent numbers as `json.Number` */ - self.Link("_use_number") // _use_number - self.Emit("MOVQ", _VAR_ss_Ep, _AX) // MOVQ ss.Ep, AX - self.Emit("LEAQ", jit.Sib(_IP, _AX, 1, 0), _SI) // LEAQ (IP)(AX), SI - self.Emit("MOVQ", _IC, _CX) // MOVQ IC, CX - self.Emit("SUBQ", _AX, _CX) // SUBQ AX, CX - self.Emit("MOVQ", _SI, jit.Ptr(_SP, 0)) // MOVQ SI, (SP) - self.Emit("MOVQ", _CX, jit.Ptr(_SP, 8)) // MOVQ CX, 8(SP) - self.call_go(_F_convTstring) // CALL_GO runtime.convTstring - self.Emit("MOVQ", _T_number, _R8) // MOVQ _T_number, R8 - self.Emit("MOVQ", jit.Ptr(_SP, 16), _R9) // MOVQ 16(SP), R9 - self.Emit("MOVQ", _VAR_ss_Ep, _DI) // MOVQ ss.Ep, DI - self.Sjmp("JMP" , "_set_value") // JMP _set_value - - /* represent numbers as `int64` */ - self.Link("_use_int64") // _use_int64: - self.Emit("MOVQ", _VAR_ss_Iv, _AX) // MOVQ ss.Iv, AX - self.Emit("MOVQ", _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP) - self.call_go(_F_convT64) // CALL_GO runtime.convT64 - self.Emit("MOVQ", _T_int64, _R8) // MOVQ _T_int64, R8 - self.Emit("MOVQ", jit.Ptr(_SP, 8), _R9) // MOVQ 8(SP), R9 - self.Emit("MOVQ", _VAR_ss_Ep, _DI) // MOVQ ss.Ep, DI - self.Sjmp("JMP" , "_set_value") // JMP _set_value - - /** V_KEY_SEP **/ - self.Link("_decode_V_KEY_SEP") // _decode_V_KEY_SEP: - // self.Byte(0xcc) - self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX - self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX - self.Emit("CMPQ", _AX, jit.Imm(_S_obj_delim)) // CMPQ AX, _S_obj_delim - self.Sjmp("JNE" , "_invalid_char") // JNE _invalid_char - self.Emit("MOVQ", jit.Imm(_S_val), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_val, ST.Vt[CX] - self.Emit("MOVQ", jit.Imm(_S_obj), jit.Sib(_ST, _CX, 8, _ST_Vt - 8)) // MOVQ _S_obj, ST.Vt[CX - 1] - self.Sjmp("JMP" , "_next") // JMP _next - - /** V_ELEM_SEP **/ - self.Link("_decode_V_ELEM_SEP") // _decode_V_ELEM_SEP: - self.Emit("MOVQ" , jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX - self.Emit("MOVQ" , jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX - self.Emit("CMPQ" , _AX, jit.Imm(_S_arr)) // CMPQ _AX, _S_arr - self.Sjmp("JE" , "_array_sep") // JZ _next - self.Emit("CMPQ" , _AX, jit.Imm(_S_obj)) // CMPQ _AX, _S_arr - self.Sjmp("JNE" , "_invalid_char") // JNE _invalid_char - self.Emit("MOVQ" , jit.Imm(_S_obj_sep), jit.Sib(_ST, _CX, 8, _ST_Vt)) - self.Sjmp("JMP" , "_next") // JMP _next - - /* arrays */ - self.Link("_array_sep") - self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI - self.Emit("MOVQ", jit.Ptr(_SI, 8), _SI) // MOVQ 8(SI), SI - self.Emit("MOVQ", jit.Ptr(_SI, 8), _DX) // MOVQ 8(SI), DX - self.Emit("CMPQ", _DX, jit.Ptr(_SI, 16)) // CMPQ DX, 16(SI) - self.Sjmp("JAE" , "_array_more") // JAE _array_more - - /* add a slot for the new element */ - self.Link("_array_append") // _array_append: - 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 - self.WriteRecNotAX(7 , _SI, jit.Sib(_ST, _CX, 8, _ST_Vp), false) // MOVQ SI, ST.Vp[CX] - self.Emit("MOVQ", jit.Imm(_S_val), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_val, ST.Vt[CX} - self.Sjmp("JMP" , "_next") // JMP _next - - /** V_ARRAY_END **/ - self.Link("_decode_V_ARRAY_END") // _decode_V_ARRAY_END: - self.Emit("XORL", _DX, _DX) // XORL DX, DX - self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX - self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX - self.Emit("CMPQ", _AX, jit.Imm(_S_arr_0)) // CMPQ AX, _S_arr_0 - self.Sjmp("JE" , "_first_item") // JE _first_item - self.Emit("CMPQ", _AX, jit.Imm(_S_arr)) // CMPQ AX, _S_arr - self.Sjmp("JNE" , "_invalid_char") // JNE _invalid_char - self.Emit("SUBQ", jit.Imm(1), jit.Ptr(_ST, _ST_Sp)) // SUBQ $1, ST.Sp - self.Emit("MOVQ", _DX, jit.Sib(_ST, _CX, 8, _ST_Vp)) // MOVQ DX, ST.Vp[CX] - self.Sjmp("JMP" , "_next") // JMP _next - - /* first element of an array */ - self.Link("_first_item") // _first_item: - self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX - self.Emit("SUBQ", jit.Imm(2), jit.Ptr(_ST, _ST_Sp)) // SUBQ $2, ST.Sp - self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp - 8), _SI) // MOVQ ST.Vp[CX - 1], SI - self.Emit("MOVQ", jit.Ptr(_SI, 8), _SI) // MOVQ 8(SI), SI - self.Emit("MOVQ", _DX, jit.Sib(_ST, _CX, 8, _ST_Vp - 8)) // MOVQ DX, ST.Vp[CX - 1] - self.Emit("MOVQ", _DX, jit.Sib(_ST, _CX, 8, _ST_Vp)) // MOVQ DX, ST.Vp[CX] - self.Emit("MOVQ", _DX, jit.Ptr(_SI, 8)) // MOVQ DX, 8(SI) - self.Sjmp("JMP" , "_next") // JMP _next - - /** V_OBJECT_END **/ - self.Link("_decode_V_OBJECT_END") // _decode_V_OBJECT_END: - self.Emit("MOVL", jit.Imm(_S_omask_end), _DX) // MOVL _S_omask, DI - self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX - self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX - self.Emit("BTQ" , _AX, _DX) - self.Sjmp("JNC" , "_invalid_char") // JNE _invalid_char - self.Emit("XORL", _AX, _AX) // XORL AX, AX - self.Emit("SUBQ", jit.Imm(1), jit.Ptr(_ST, _ST_Sp)) // SUBQ $1, ST.Sp - self.Emit("MOVQ", _AX, jit.Sib(_ST, _CX, 8, _ST_Vp)) // MOVQ AX, ST.Vp[CX] - self.Sjmp("JMP" , "_next") // JMP _next - - /* return from decoder */ - self.Link("_return") // _return: - self.Emit("XORL", _EP, _EP) // XORL EP, EP - self.Emit("MOVQ", _EP, jit.Ptr(_ST, _ST_Vp)) // MOVQ EP, ST.Vp[0] - self.Link("_epilogue") // _epilogue: - self.Emit("SUBQ", jit.Imm(_FsmOffset), _ST) // SUBQ _FsmOffset, _ST - self.Emit("MOVQ", jit.Ptr(_SP, _VD_offs), _BP) // MOVQ _VD_offs(SP), BP - self.Emit("ADDQ", jit.Imm(_VD_size), _SP) // ADDQ $_VD_size, SP - self.Emit("RET") // RET - - /* array expand */ - self.Link("_array_more") // _array_more: - self.Emit("MOVQ" , _T_eface, _AX) // MOVQ _T_eface, AX - self.Emit("MOVOU", jit.Ptr(_SI, 0), _X0) // MOVOU (SI), X0 - self.Emit("MOVQ" , jit.Ptr(_SI, 16), _DX) // MOVQ 16(SI), DX - self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP) - self.Emit("MOVOU", _X0, jit.Ptr(_SP, 8)) // MOVOU X0, 8(SP) - self.Emit("MOVQ" , _DX, jit.Ptr(_SP, 24)) // MOVQ DX, 24(SP) - self.Emit("SHLQ" , jit.Imm(1), _DX) // SHLQ $1, DX - self.Emit("MOVQ" , _DX, jit.Ptr(_SP, 32)) // MOVQ DX, 32(SP) - self.call_go(_F_growslice) // CALL_GO runtime.growslice - self.Emit("MOVQ" , jit.Ptr(_SP, 40), _DI) // MOVOU 40(SP), DI - self.Emit("MOVQ" , jit.Ptr(_SP, 48), _DX) // MOVOU 48(SP), DX - self.Emit("MOVQ" , jit.Ptr(_SP, 56), _AX) // MOVQ 56(SP), AX - - /* update the slice */ - self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX - self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI - self.Emit("MOVQ", jit.Ptr(_SI, 8), _SI) // MOVQ 8(SI), SI - self.Emit("MOVQ", _DX, jit.Ptr(_SI, 8)) // MOVQ DX, 8(SI) - self.Emit("MOVQ", _AX, jit.Ptr(_SI, 16)) // MOVQ AX, 16(AX) - self.WriteRecNotAX(8 , _DI, jit.Ptr(_SI, 0), false) // MOVQ R10, (SI) - self.Sjmp("JMP" , "_array_append") // JMP _array_append - - /* copy string */ - self.Link("copy_string") // pointer: R8, length: AX, return addr: DI - // self.Byte(0xcc) - self.Emit("MOVQ", _R8, _VAR_cs_p) - self.Emit("MOVQ", _AX, _VAR_cs_n) - self.Emit("MOVQ", _DI, _VAR_cs_LR) - self.Emit("MOVQ", _T_byte, _R8) - self.Emit("MOVQ", _R8, jit.Ptr(_SP, 0)) - self.Emit("MOVQ", _AX, jit.Ptr(_SP, 8)) - self.Emit("MOVQ", _AX, jit.Ptr(_SP, 16)) - self.call_go(_F_makeslice) - self.Emit("MOVQ", jit.Ptr(_SP, 24), _R8) - self.Emit("MOVQ", _R8, _VAR_cs_d) - self.Emit("MOVQ", _R8, jit.Ptr(_SP, 0)) - self.Emit("MOVQ", _VAR_cs_p, _R8) - self.Emit("MOVQ", _R8, jit.Ptr(_SP, 8)) - self.Emit("MOVQ", _VAR_cs_n, _AX) - self.Emit("MOVQ", _AX, jit.Ptr(_SP, 16)) - self.call_go(_F_memmove) - self.Emit("MOVQ", _VAR_cs_d, _R8) - self.Emit("MOVQ", _VAR_cs_n, _AX) - self.Emit("MOVQ", _VAR_cs_LR, _DI) - // self.Byte(0xcc) - self.Rjmp("JMP", _DI) - - /* error handlers */ - self.Link("_stack_overflow") - self.Emit("MOVL" , _E_recurse, _EP) // MOVQ _E_recurse, EP - self.Sjmp("JMP" , "_error") // JMP _error - self.Link("_vtype_error") // _vtype_error: - self.Emit("MOVQ" , _DI, _IC) // MOVQ DI, IC - self.Emit("MOVL" , _E_invalid, _EP) // MOVL _E_invalid, EP - self.Sjmp("JMP" , "_error") // JMP _error - self.Link("_invalid_char") // _invalid_char: - self.Emit("SUBQ" , jit.Imm(1), _IC) // SUBQ $1, IC - self.Emit("MOVL" , _E_invalid, _EP) // MOVL _E_invalid, EP - self.Sjmp("JMP" , "_error") // JMP _error - self.Link("_unquote_error") // _unquote_error: - self.Emit("MOVQ" , _VAR_ss_Iv, _IC) // MOVQ ss.Iv, IC - self.Emit("SUBQ" , jit.Imm(1), _IC) // SUBQ $1, IC - self.Link("_parsing_error") // _parsing_error: - self.Emit("NEGQ" , _AX) // NEGQ AX - self.Emit("MOVQ" , _AX, _EP) // MOVQ AX, EP - self.Link("_error") // _error: - self.Emit("PXOR" , _X0, _X0) // PXOR X0, X0 - self.Emit("MOVOU", _X0, jit.Ptr(_VP, 0)) // MOVOU X0, (VP) - self.Sjmp("JMP" , "_epilogue") // JMP _epilogue - - /* invalid value type, never returns */ - self.Link("_invalid_vtype") - self.Emit("MOVQ", _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP) - self.call(_F_invalid_vtype) // CALL invalid_type - self.Emit("UD2") // UD2 - - /* switch jump table */ - self.Link("_switch_table") // _switch_table: - self.Sref("_decode_V_EOF", 0) // SREF &_decode_V_EOF, $0 - self.Sref("_decode_V_NULL", -4) // SREF &_decode_V_NULL, $-4 - self.Sref("_decode_V_TRUE", -8) // SREF &_decode_V_TRUE, $-8 - self.Sref("_decode_V_FALSE", -12) // SREF &_decode_V_FALSE, $-12 - self.Sref("_decode_V_ARRAY", -16) // SREF &_decode_V_ARRAY, $-16 - self.Sref("_decode_V_OBJECT", -20) // SREF &_decode_V_OBJECT, $-20 - self.Sref("_decode_V_STRING", -24) // SREF &_decode_V_STRING, $-24 - self.Sref("_decode_V_DOUBLE", -28) // SREF &_decode_V_DOUBLE, $-28 - self.Sref("_decode_V_INTEGER", -32) // SREF &_decode_V_INTEGER, $-32 - self.Sref("_decode_V_KEY_SEP", -36) // SREF &_decode_V_KEY_SEP, $-36 - self.Sref("_decode_V_ELEM_SEP", -40) // SREF &_decode_V_ELEM_SEP, $-40 - self.Sref("_decode_V_ARRAY_END", -44) // SREF &_decode_V_ARRAY_END, $-44 - self.Sref("_decode_V_OBJECT_END", -48) // SREF &_decode_V_OBJECT_END, $-48 - - /* fast character lookup table */ - self.Link("_decode_tab") // _decode_tab: - self.Sref("_decode_V_EOF", 0) // SREF &_decode_V_EOF, $0 - - /* generate rest of the tabs */ - for i := 1; i < 256; i++ { - if to, ok := _R_tab[i]; ok { - self.Sref(to, -int64(i) * 4) - } else { - self.Byte(0x00, 0x00, 0x00, 0x00) - } - } -} - -/** Generic Decoder **/ - -var ( - _subr_decode_value = new(_ValueDecoder).build() -) - -//go:nosplit -func invalid_vtype(vt types.ValueType) { - throw(fmt.Sprintf("invalid value type: %d", vt)) -} diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/asm.s b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/asm.s similarity index 100% rename from vendor/github.com/bytedance/sonic/internal/decoder/asm.s rename to vendor/github.com/bytedance/sonic/internal/decoder/jitdec/asm.s diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/asm_stubs_amd64_go117.go b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/asm_stubs_amd64_go117.go similarity index 99% rename from vendor/github.com/bytedance/sonic/internal/decoder/asm_stubs_amd64_go117.go rename to vendor/github.com/bytedance/sonic/internal/decoder/jitdec/asm_stubs_amd64_go117.go index b0125a792..48f73e5bf 100644 --- a/vendor/github.com/bytedance/sonic/internal/decoder/asm_stubs_amd64_go117.go +++ b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/asm_stubs_amd64_go117.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package decoder +package jitdec import ( `strconv` diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/asm_stubs_amd64_go121.go b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/asm_stubs_amd64_go121.go similarity index 98% rename from vendor/github.com/bytedance/sonic/internal/decoder/asm_stubs_amd64_go121.go rename to vendor/github.com/bytedance/sonic/internal/decoder/jitdec/asm_stubs_amd64_go121.go index 018892f59..cbec3d248 100644 --- a/vendor/github.com/bytedance/sonic/internal/decoder/asm_stubs_amd64_go121.go +++ b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/asm_stubs_amd64_go121.go @@ -1,4 +1,4 @@ -// +build go1.21,!go1.22 +// +build go1.21,!go1.24 // Copyright 2023 CloudWeGo Authors // @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package decoder +package jitdec import ( `strconv` @@ -81,7 +81,6 @@ func (self *_Assembler) WriteRecNotAX(i int, ptr obj.Addr, rec obj.Addr, saveDI self.Emit("MOVQ", ptr, jit.Ptr(_R11, 0)) self.Emit("MOVQ", rec, _AX) self.Emit("MOVQ", _AX, jit.Ptr(_R11, 8)) - self.load(_R11) if saveAX { self.load(_AX, _R11) } else { diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/assembler_regabi_amd64.go b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/assembler_regabi_amd64.go similarity index 96% rename from vendor/github.com/bytedance/sonic/internal/decoder/assembler_regabi_amd64.go rename to vendor/github.com/bytedance/sonic/internal/decoder/jitdec/assembler_regabi_amd64.go index 3d223e14e..4ff3b1962 100644 --- a/vendor/github.com/bytedance/sonic/internal/decoder/assembler_regabi_amd64.go +++ b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/assembler_regabi_amd64.go @@ -1,5 +1,5 @@ -//go:build go1.17 && !go1.22 -// +build go1.17,!go1.22 +//go:build go1.17 && !go1.24 +// +build go1.17,!go1.24 /* * Copyright 2021 ByteDance Inc. @@ -17,21 +17,22 @@ * limitations under the License. */ -package decoder +package jitdec import ( - `encoding/json` - `fmt` - `math` - `reflect` - `unsafe` - - `github.com/bytedance/sonic/internal/caching` - `github.com/bytedance/sonic/internal/jit` - `github.com/bytedance/sonic/internal/native` - `github.com/bytedance/sonic/internal/native/types` - `github.com/bytedance/sonic/internal/rt` - `github.com/twitchyliquid64/golang-asm/obj` + "encoding/json" + "fmt" + "math" + "reflect" + "strings" + "unsafe" + + "github.com/bytedance/sonic/internal/caching" + "github.com/bytedance/sonic/internal/jit" + "github.com/bytedance/sonic/internal/native" + "github.com/bytedance/sonic/internal/native/types" + "github.com/bytedance/sonic/internal/rt" + "github.com/twitchyliquid64/golang-asm/obj" ) /** Register Allocations @@ -135,6 +136,7 @@ var ( _R9 = jit.Reg("R9") _X0 = jit.Reg("X0") _X1 = jit.Reg("X1") + _X15 = jit.Reg("X15") ) var ( @@ -292,7 +294,6 @@ var _OpFuncTab = [256]func(*_Assembler, *_Instr) { _OP_array_clear_p : (*_Assembler)._asm_OP_array_clear_p, _OP_slice_init : (*_Assembler)._asm_OP_slice_init, _OP_slice_append : (*_Assembler)._asm_OP_slice_append, - _OP_object_skip : (*_Assembler)._asm_OP_object_skip, _OP_object_next : (*_Assembler)._asm_OP_object_next, _OP_struct_field : (*_Assembler)._asm_OP_struct_field, _OP_unmarshal : (*_Assembler)._asm_OP_unmarshal, @@ -312,6 +313,7 @@ var _OpFuncTab = [256]func(*_Assembler, *_Instr) { _OP_check_char_0 : (*_Assembler)._asm_OP_check_char_0, _OP_dismatch_err : (*_Assembler)._asm_OP_dismatch_err, _OP_go_skip : (*_Assembler)._asm_OP_go_skip, + _OP_skip_emtpy : (*_Assembler)._asm_OP_skip_empty, _OP_add : (*_Assembler)._asm_OP_add, _OP_check_empty : (*_Assembler)._asm_OP_check_empty, _OP_debug : (*_Assembler)._asm_OP_debug, @@ -385,7 +387,7 @@ func (self *_Assembler) prologue() { var ( _REG_go = []obj.Addr { _ST, _VP, _IP, _IL, _IC } - _REG_rt = []obj.Addr { _ST, _VP, _IP, _IL, _IC, _IL } + _REG_rt = []obj.Addr { _ST, _VP, _IP, _IL, _IC } ) func (self *_Assembler) save(r ...obj.Addr) { @@ -420,9 +422,10 @@ func (self *_Assembler) call_go(fn obj.Addr) { } func (self *_Assembler) callc(fn obj.Addr) { - self.Emit("XCHGQ", _IP, _BP) + self.save(_IP) self.call(fn) - self.Emit("XCHGQ", _IP, _BP) + self.Emit("XORPS", _X15, _X15) + self.load(_IP) } func (self *_Assembler) call_c(fn obj.Addr) { @@ -491,9 +494,9 @@ func (self *_Assembler) type_error() { func (self *_Assembler) mismatch_error() { self.Link(_LB_mismatch_error) // _type_error: self.Emit("MOVQ", _VAR_et, _ET) // MOVQ _VAR_et, ET - self.Emit("MOVQ", _VAR_ic, _EP) // MOVQ _VAR_ic, EP self.Emit("MOVQ", _I_json_MismatchTypeError, _CX) // MOVQ _I_json_MismatchType, CX self.Emit("CMPQ", _ET, _CX) // CMPQ ET, CX + self.Emit("MOVQ", jit.Ptr(_ST, _EpOffset), _EP) // MOVQ stack.Ep, EP self.Sjmp("JE" , _LB_error) // JE _LB_error self.Emit("MOVQ", _ARG_sp, _AX) self.Emit("MOVQ", _ARG_sl, _BX) @@ -599,6 +602,28 @@ func (self *_Assembler) _asm_OP_go_skip(p *_Instr) { self.Sjmp("JMP" , _LB_skip_one) // JMP _skip_one } +var _F_IndexByte = jit.Func(strings.IndexByte) + +func (self *_Assembler) _asm_OP_skip_empty(p *_Instr) { + // self.Byte(0xcc) + self.call_sf(_F_skip_one) // CALL_SF skip_one + // self.Byte(0xcc) + self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX + self.Sjmp("JS" , _LB_parsing_error_v) // JS _parse_error_v + self.Emit("BTQ", jit.Imm(_F_disable_unknown), _ARG_fv) + self.Xjmp("JNC", p.vi()) + self.Emit("LEAQ", jit.Sib(_IC, _AX, 1, 0), _BX) + self.Emit("MOVQ", _BX, _ARG_sv_n) + self.Emit("LEAQ", jit.Sib(_IP, _AX, 1, 0), _AX) + self.Emit("MOVQ", _AX, _ARG_sv_p) + self.Emit("MOVQ", jit.Imm(':'), _CX) + self.call_go(_F_IndexByte) + // self.Byte(0xcc) + self.Emit("TESTQ", _AX, _AX) + // disallow unknown field + self.Sjmp("JNS", _LB_field_error) +} + func (self *_Assembler) skip_one() { self.Link(_LB_skip_one) // _skip: self.Emit("MOVQ", _VAR_ic, _IC) // MOVQ _VAR_ic, IC @@ -606,7 +631,6 @@ func (self *_Assembler) skip_one() { self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX self.Sjmp("JS" , _LB_parsing_error_v) // JS _parse_error_v self.Emit("MOVQ" , _VAR_pc, _R9) // MOVQ pc, R9 - // self.Byte(0xcc) self.Rjmp("JMP" , _R9) // JMP (R9) } @@ -972,11 +996,13 @@ var ( var ( _F_decodeJsonUnmarshaler obj.Addr + _F_decodeJsonUnmarshalerQuoted obj.Addr _F_decodeTextUnmarshaler obj.Addr ) func init() { _F_decodeJsonUnmarshaler = jit.Func(decodeJsonUnmarshaler) + _F_decodeJsonUnmarshalerQuoted = jit.Func(decodeJsonUnmarshalerQuoted) _F_decodeTextUnmarshaler = jit.Func(decodeTextUnmarshaler) } @@ -1057,18 +1083,18 @@ func (self *_Assembler) mapassign_utext(t reflect.Type, addressable bool) { var ( _F_skip_one = jit.Imm(int64(native.S_skip_one)) _F_skip_array = jit.Imm(int64(native.S_skip_array)) - _F_skip_object = jit.Imm(int64(native.S_skip_object)) _F_skip_number = jit.Imm(int64(native.S_skip_number)) ) -func (self *_Assembler) unmarshal_json(t reflect.Type, deref bool) { +func (self *_Assembler) unmarshal_json(t reflect.Type, deref bool, f obj.Addr) { self.call_sf(_F_skip_one) // CALL_SF skip_one self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX self.Sjmp("JS" , _LB_parsing_error_v) // JS _parse_error_v + self.Emit("MOVQ", _IC, _VAR_ic) // store for mismatche error skip self.slice_from_r(_AX, 0) // SLICE_R AX, $0 self.Emit("MOVQ" , _DI, _ARG_sv_p) // MOVQ DI, sv.p self.Emit("MOVQ" , _SI, _ARG_sv_n) // MOVQ SI, sv.n - self.unmarshal_func(t, _F_decodeJsonUnmarshaler, deref) // UNMARSHAL json, ${t}, ${deref} + self.unmarshal_func(t, f, deref) // UNMARSHAL json, ${t}, ${deref} } func (self *_Assembler) unmarshal_text(t reflect.Type, deref bool) { @@ -1103,7 +1129,15 @@ func (self *_Assembler) unmarshal_func(t reflect.Type, fn obj.Addr, deref bool) self.Emit("MOVQ" , _ARG_sv_n, _DI) // MOVQ sv.n, DI self.call_go(fn) // CALL_GO ${fn} self.Emit("TESTQ", _ET, _ET) // TESTQ ET, ET - self.Sjmp("JNZ" , _LB_error) // JNZ _error + self.Sjmp("JZ" , "_unmarshal_func_end_{n}") // JNZ _error + self.Emit("MOVQ", _I_json_MismatchTypeError, _CX) // MOVQ ET, VAR.et + self.Emit("CMPQ", _ET, _CX) // check if MismatchedError + self.Sjmp("JNE" , _LB_error) + self.Emit("MOVQ", jit.Type(t), _CX) // store current type + self.Emit("MOVQ", _CX, _VAR_et) // store current type + self.Emit("MOVQ", _VAR_ic, _IC) // recover the pos + self.Emit("XORL", _ET, _ET) + self.Link("_unmarshal_func_end_{n}") } /** Dynamic Decoding Routine **/ @@ -1136,8 +1170,8 @@ func (self *_Assembler) decode_dynamic(vt obj.Addr, vp obj.Addr) { self.Emit("MOVQ", _I_json_MismatchTypeError, _CX) // MOVQ _I_json_MismatchTypeError, CX self.Emit("CMPQ", _ET, _CX) // CMPQ ET, CX self.Sjmp("JNE", _LB_error) // JNE LB_error - self.Emit("MOVQ", _EP, _VAR_ic) // MOVQ EP, VAR_ic self.Emit("MOVQ", _ET, _VAR_et) // MOVQ ET, VAR_et + self.WriteRecNotAX(14, _EP, jit.Ptr(_ST, _EpOffset), false, false) // MOVQ EP, stack.Ep self.Link("_decode_dynamic_end_{n}") } @@ -1146,7 +1180,7 @@ func (self *_Assembler) decode_dynamic(vt obj.Addr, vp obj.Addr) { var ( _F_memequal = jit.Func(memequal) _F_memmove = jit.Func(memmove) - _F_growslice = jit.Func(growslice) + _F_growslice = jit.Func(rt.GrowSlice) _F_makeslice = jit.Func(makeslice) _F_makemap_small = jit.Func(makemap_small) _F_mapassign_fast64 = jit.Func(mapassign_fast64) @@ -1164,7 +1198,7 @@ var ( var ( _F_FieldMap_GetCaseInsensitive obj.Addr - _Empty_Slice = make([]byte, 0) + _Empty_Slice = []byte{} _Zero_Base = int64(uintptr(((*rt.GoSlice)(unsafe.Pointer(&_Empty_Slice))).Ptr)) ) @@ -1641,7 +1675,8 @@ func (self *_Assembler) _asm_OP_check_empty(p *_Instr) { self.Emit("CMPB", jit.Sib(_IP, _IC, 1, 0), jit.Imm(int64(rbracket))) // CMPB (IP)(IC), ']' self.Sjmp("JNE" , "_not_empty_array_{n}") // JNE _not_empty_array_{n} self.Emit("MOVQ", _AX, _IC) // MOVQ AX, IC - self.StorePtr(_Zero_Base, jit.Ptr(_VP, 0), _AX) // MOVQ $zerobase, (VP) + self.Emit("MOVQ", jit.Imm(_Zero_Base), _AX) + self.WritePtrAX(9, jit.Ptr(_VP, 0), false) self.Emit("PXOR", _X0, _X0) // PXOR X0, X0 self.Emit("MOVOU", _X0, jit.Ptr(_VP, 8)) // MOVOU X0, 8(VP) self.Xjmp("JMP" , p.vi()) // JMP {p.vi()} @@ -1697,12 +1732,6 @@ func (self *_Assembler) _asm_OP_slice_append(p *_Instr) { self.Link("_append_slice_end_{n}") } -func (self *_Assembler) _asm_OP_object_skip(_ *_Instr) { - self.call_sf(_F_skip_object) // CALL_SF skip_object - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JS" , _LB_parsing_error_v) // JS _parse_error_v -} - func (self *_Assembler) _asm_OP_object_next(_ *_Instr) { self.call_sf(_F_skip_one) // CALL_SF skip_one self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX @@ -1773,11 +1802,19 @@ func (self *_Assembler) _asm_OP_struct_field(p *_Instr) { } func (self *_Assembler) _asm_OP_unmarshal(p *_Instr) { - self.unmarshal_json(p.vt(), true) + if iv := p.i64(); iv != 0 { + self.unmarshal_json(p.vt(), true, _F_decodeJsonUnmarshalerQuoted) + } else { + self.unmarshal_json(p.vt(), true, _F_decodeJsonUnmarshaler) + } } func (self *_Assembler) _asm_OP_unmarshal_p(p *_Instr) { - self.unmarshal_json(p.vt(), false) + if iv := p.i64(); iv != 0 { + self.unmarshal_json(p.vt(), false, _F_decodeJsonUnmarshalerQuoted) + } else { + self.unmarshal_json(p.vt(), false, _F_decodeJsonUnmarshaler) + } } func (self *_Assembler) _asm_OP_unmarshal_text(p *_Instr) { diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/compiler.go b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/compiler.go similarity index 93% rename from vendor/github.com/bytedance/sonic/internal/decoder/compiler.go rename to vendor/github.com/bytedance/sonic/internal/decoder/jitdec/compiler.go index e9e2b77fc..a097d171d 100644 --- a/vendor/github.com/bytedance/sonic/internal/decoder/compiler.go +++ b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/compiler.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package decoder +package jitdec import ( `encoding/json` @@ -77,7 +77,6 @@ const ( _OP_array_clear_p _OP_slice_init _OP_slice_append - _OP_object_skip _OP_object_next _OP_struct_field _OP_unmarshal @@ -97,6 +96,7 @@ const ( _OP_check_char_0 _OP_dismatch_err _OP_go_skip + _OP_skip_emtpy _OP_add _OP_check_empty _OP_debug @@ -155,7 +155,6 @@ var _OpNames = [256]string { _OP_array_skip : "array_skip", _OP_slice_init : "slice_init", _OP_slice_append : "slice_append", - _OP_object_skip : "object_skip", _OP_object_next : "object_next", _OP_struct_field : "struct_field", _OP_unmarshal : "unmarshal", @@ -271,6 +270,13 @@ func newInsVt(op _Op, vt reflect.Type) _Instr { } } +func newInsVtI(op _Op, vt reflect.Type, iv int) _Instr { + return _Instr { + u: packOp(op) | rt.PackInt(iv), + p: unsafe.Pointer(rt.UnpackType(vt)), + } +} + func newInsVf(op _Op, vf *caching.FieldMap) _Instr { return _Instr { u: packOp(op), @@ -452,6 +458,10 @@ func (self *_Program) rtt(op _Op, vt reflect.Type) { *self = append(*self, newInsVt(op, vt)) } +func (self *_Program) rtti(op _Op, vt reflect.Type, iv int) { + *self = append(*self, newInsVtI(op, vt, iv)) +} + func (self *_Program) fmv(op _Op, vf *caching.FieldMap) { *self = append(*self, newInsVf(op, vf)) } @@ -527,40 +537,66 @@ func (self *_Compiler) compile(vt reflect.Type) (ret _Program, err error) { return } -func (self *_Compiler) compileOne(p *_Program, sp int, vt reflect.Type) { - /* check for recursive nesting */ - ok := self.tab[vt] - if ok { - p.rtt(_OP_recurse, vt) - return - } +const ( + checkMarshalerFlags_quoted = 1 +) +func (self *_Compiler) checkMarshaler(p *_Program, vt reflect.Type, flags int, exec bool) bool { pt := reflect.PtrTo(vt) /* check for `json.Unmarshaler` with pointer receiver */ if pt.Implements(jsonUnmarshalerType) { - p.rtt(_OP_unmarshal_p, pt) - return + if exec { + p.add(_OP_lspace) + p.rtti(_OP_unmarshal_p, pt, flags) + } + return true } /* check for `json.Unmarshaler` */ if vt.Implements(jsonUnmarshalerType) { - p.add(_OP_lspace) - self.compileUnmarshalJson(p, vt) - return + if exec { + p.add(_OP_lspace) + self.compileUnmarshalJson(p, vt, flags) + } + return true + } + + if flags == checkMarshalerFlags_quoted { + // text marshaler shouldn't be supported for quoted string + return false } /* check for `encoding.TextMarshaler` with pointer receiver */ if pt.Implements(encodingTextUnmarshalerType) { - p.add(_OP_lspace) - self.compileUnmarshalTextPtr(p, pt) - return + if exec { + p.add(_OP_lspace) + self.compileUnmarshalTextPtr(p, pt, flags) + } + return true } /* check for `encoding.TextUnmarshaler` */ if vt.Implements(encodingTextUnmarshalerType) { - p.add(_OP_lspace) - self.compileUnmarshalText(p, vt) + if exec { + p.add(_OP_lspace) + self.compileUnmarshalText(p, vt, flags) + } + return true + } + + return false +} + +func (self *_Compiler) compileOne(p *_Program, sp int, vt reflect.Type) { + /* check for recursive nesting */ + ok := self.tab[vt] + if ok { + p.rtt(_OP_recurse, vt) + return + } + + if self.checkMarshaler(p, vt, 0, true) { return } @@ -683,17 +719,9 @@ func (self *_Compiler) compilePtr(p *_Program, sp int, et reflect.Type) { /* dereference all the way down */ for et.Kind() == reflect.Ptr { - if et.Implements(jsonUnmarshalerType) { - p.rtt(_OP_unmarshal_p, et) - return - } - - if et.Implements(encodingTextUnmarshalerType) { - p.add(_OP_lspace) - self.compileUnmarshalTextPtr(p, et) + if self.checkMarshaler(p, et, 0, true) { return } - et = et.Elem() p.rtt(_OP_deref, et) } @@ -706,7 +734,7 @@ func (self *_Compiler) compilePtr(p *_Program, sp int, et reflect.Type) { /* enter the recursion */ p.add(_OP_lspace) self.tab[et] = true - + /* not inline the pointer type * recursing the defined pointer type's elem will casue issue379. */ @@ -716,8 +744,12 @@ func (self *_Compiler) compilePtr(p *_Program, sp int, et reflect.Type) { j := p.pc() p.add(_OP_goto) + + // set val pointer as nil p.pin(i) p.add(_OP_nil_1) + + // nothing todo p.pin(j) } @@ -869,7 +901,24 @@ func (self *_Compiler) compileStructBody(p *_Program, sp int, vt reflect.Type) { n := p.pc() p.add(_OP_is_null) - skip := self.checkIfSkip(p, vt, '{') + j := p.pc() + p.chr(_OP_check_char_0, '{') + p.rtt(_OP_dismatch_err, vt) + + /* special case for empty object */ + if len(fv) == 0 { + p.pin(j) + s := p.pc() + p.add(_OP_skip_emtpy) + p.pin(s) + p.pin(n) + return + } + + skip := p.pc() + p.add(_OP_go_skip) + p.pin(j) + p.int(_OP_add, 1) p.add(_OP_save) p.add(_OP_lspace) @@ -887,11 +936,6 @@ func (self *_Compiler) compileStructBody(p *_Program, sp int, vt reflect.Type) { p.chr(_OP_check_char, '}') p.chr(_OP_match_char, ',') - /* special case of an empty struct */ - if len(fv) == 0 { - p.add(_OP_object_skip) - goto end_of_object - } /* match the remaining fields */ p.add(_OP_lspace) @@ -927,7 +971,6 @@ func (self *_Compiler) compileStructBody(p *_Program, sp int, vt reflect.Type) { p.int(_OP_goto, y0) } -end_of_object: p.pin(x) p.pin(y1) p.add(_OP_drop) @@ -935,7 +978,22 @@ end_of_object: p.pin(skip) } +func (self *_Compiler) compileStructFieldStrUnmarshal(p *_Program, vt reflect.Type) { + p.add(_OP_lspace) + n0 := p.pc() + p.add(_OP_is_null) + self.checkMarshaler(p, vt, checkMarshalerFlags_quoted, true) + p.pin(n0) +} + func (self *_Compiler) compileStructFieldStr(p *_Program, sp int, vt reflect.Type) { + // according to std, json.Unmarshaler should be called before stringize + // see https://github.com/bytedance/sonic/issues/670 + if self.checkMarshaler(p, vt, checkMarshalerFlags_quoted, false) { + self.compileStructFieldStrUnmarshal(p, vt) + return + } + n1 := -1 ft := vt sv := false @@ -1103,7 +1161,7 @@ func (self *_Compiler) compileUnmarshalEnd(p *_Program, vt reflect.Type, i int) p.pin(j) } -func (self *_Compiler) compileUnmarshalJson(p *_Program, vt reflect.Type) { +func (self *_Compiler) compileUnmarshalJson(p *_Program, vt reflect.Type, flags int) { i := p.pc() v := _OP_unmarshal p.add(_OP_is_null) @@ -1114,11 +1172,11 @@ func (self *_Compiler) compileUnmarshalJson(p *_Program, vt reflect.Type) { } /* call the unmarshaler */ - p.rtt(v, vt) + p.rtti(v, vt, flags) self.compileUnmarshalEnd(p, vt, i) } -func (self *_Compiler) compileUnmarshalText(p *_Program, vt reflect.Type) { +func (self *_Compiler) compileUnmarshalText(p *_Program, vt reflect.Type, iv int) { i := p.pc() v := _OP_unmarshal_text p.add(_OP_is_null) @@ -1131,15 +1189,15 @@ func (self *_Compiler) compileUnmarshalText(p *_Program, vt reflect.Type) { } /* call the unmarshaler */ - p.rtt(v, vt) + p.rtti(v, vt, iv) self.compileUnmarshalEnd(p, vt, i) } -func (self *_Compiler) compileUnmarshalTextPtr(p *_Program, vt reflect.Type) { +func (self *_Compiler) compileUnmarshalTextPtr(p *_Program, vt reflect.Type, iv int) { i := p.pc() p.add(_OP_is_null) p.chr(_OP_match_char, '"') - p.rtt(_OP_unmarshal_text_p, vt) + p.rtti(_OP_unmarshal_text_p, vt, iv) p.pin(i) } diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/debug.go b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/debug.go similarity index 99% rename from vendor/github.com/bytedance/sonic/internal/decoder/debug.go rename to vendor/github.com/bytedance/sonic/internal/decoder/jitdec/debug.go index d5537ed9a..b59a3e571 100644 --- a/vendor/github.com/bytedance/sonic/internal/decoder/debug.go +++ b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/debug.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package decoder +package jitdec import ( `os` diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/decoder.go b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/decoder.go new file mode 100644 index 000000000..bbb4b4b61 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/decoder.go @@ -0,0 +1,140 @@ +package jitdec + +import ( + `unsafe` + `encoding/json` + `reflect` + `runtime` + + `github.com/bytedance/sonic/internal/decoder/consts` + `github.com/bytedance/sonic/internal/decoder/errors` + `github.com/bytedance/sonic/internal/rt` + `github.com/bytedance/sonic/utf8` + `github.com/bytedance/sonic/option` +) + +type ( + MismatchTypeError = errors.MismatchTypeError + SyntaxError = errors.SyntaxError +) + +const ( + _F_allow_control = consts.F_allow_control + _F_copy_string = consts.F_copy_string + _F_disable_unknown = consts.F_disable_unknown + _F_disable_urc = consts.F_disable_urc + _F_use_int64 = consts.F_use_int64 + _F_use_number = consts.F_use_number + _F_no_validate_json = consts.F_no_validate_json + _F_validate_string = consts.F_validate_string +) + +var ( + error_wrap = errors.ErrorWrap + error_type = errors.ErrorType + error_field = errors.ErrorField + error_value = errors.ErrorValue + error_mismatch = errors.ErrorMismatch + stackOverflow = errors.StackOverflow +) + + +// Decode parses the JSON-encoded data from current position and stores the result +// in the value pointed to by val. +func Decode(s *string, i *int, f uint64, val interface{}) error { + /* validate json if needed */ + if (f & (1 << _F_validate_string)) != 0 && !utf8.ValidateString(*s){ + dbuf := utf8.CorrectWith(nil, rt.Str2Mem(*s), "\ufffd") + *s = rt.Mem2Str(dbuf) + } + + vv := rt.UnpackEface(val) + vp := vv.Value + + /* check for nil type */ + if vv.Type == nil { + return &json.InvalidUnmarshalError{} + } + + /* must be a non-nil pointer */ + if vp == nil || vv.Type.Kind() != reflect.Ptr { + return &json.InvalidUnmarshalError{Type: vv.Type.Pack()} + } + + etp := rt.PtrElem(vv.Type) + + /* check the defined pointer type for issue 379 */ + if vv.Type.IsNamed() { + newp := vp + etp = vv.Type + vp = unsafe.Pointer(&newp) + } + + /* create a new stack, and call the decoder */ + sb := newStack() + nb, err := decodeTypedPointer(*s, *i, etp, vp, sb, f) + /* return the stack back */ + *i = nb + freeStack(sb) + + /* avoid GC ahead */ + runtime.KeepAlive(vv) + return err +} + + +// Pretouch compiles vt ahead-of-time to avoid JIT compilation on-the-fly, in +// order to reduce the first-hit latency. +// +// Opts are the compile options, for example, "option.WithCompileRecursiveDepth" is +// a compile option to set the depth of recursive compile for the nested struct type. +func Pretouch(vt reflect.Type, opts ...option.CompileOption) error { + cfg := option.DefaultCompileOptions() + for _, opt := range opts { + opt(&cfg) + } + return pretouchRec(map[reflect.Type]bool{vt:true}, cfg) +} + +func pretouchType(_vt reflect.Type, opts option.CompileOptions) (map[reflect.Type]bool, error) { + /* compile function */ + compiler := newCompiler().apply(opts) + decoder := func(vt *rt.GoType, _ ...interface{}) (interface{}, error) { + if pp, err := compiler.compile(_vt); err != nil { + return nil, err + } else { + as := newAssembler(pp) + as.name = _vt.String() + return as.Load(), nil + } + } + + /* find or compile */ + vt := rt.UnpackType(_vt) + if val := programCache.Get(vt); val != nil { + return nil, nil + } else if _, err := programCache.Compute(vt, decoder); err == nil { + return compiler.rec, nil + } else { + return nil, err + } +} + +func pretouchRec(vtm map[reflect.Type]bool, opts option.CompileOptions) error { + if opts.RecursiveDepth < 0 || len(vtm) == 0 { + return nil + } + next := make(map[reflect.Type]bool) + for vt := range(vtm) { + sub, err := pretouchType(vt, opts) + if err != nil { + return err + } + for svt := range(sub) { + next[svt] = true + } + } + opts.RecursiveDepth -= 1 + return pretouchRec(next, opts) +} + diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/generic_regabi_amd64.go b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/generic_regabi_amd64.go similarity index 99% rename from vendor/github.com/bytedance/sonic/internal/decoder/generic_regabi_amd64.go rename to vendor/github.com/bytedance/sonic/internal/decoder/jitdec/generic_regabi_amd64.go index 337af054c..e6d5e3e84 100644 --- a/vendor/github.com/bytedance/sonic/internal/decoder/generic_regabi_amd64.go +++ b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/generic_regabi_amd64.go @@ -1,4 +1,4 @@ -// +build go1.17,!go1.22 +// +build go1.17,!go1.24 /* * Copyright 2021 ByteDance Inc. @@ -16,7 +16,7 @@ * limitations under the License. */ -package decoder +package jitdec import ( `encoding/json` @@ -119,9 +119,9 @@ func (self *_ValueDecoder) call_go(fn obj.Addr) { } func (self *_ValueDecoder) callc(fn obj.Addr) { - self.Emit("XCHGQ", _IP, _BP) + self.save(_IP) self.call(fn) - self.Emit("XCHGQ", _IP, _BP) + self.load(_IP) } func (self *_ValueDecoder) call_c(fn obj.Addr) { diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/generic_regabi_amd64_test.s b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/generic_regabi_amd64_test.s similarity index 97% rename from vendor/github.com/bytedance/sonic/internal/decoder/generic_regabi_amd64_test.s rename to vendor/github.com/bytedance/sonic/internal/decoder/jitdec/generic_regabi_amd64_test.s index 1c46928de..19ed3752f 100644 --- a/vendor/github.com/bytedance/sonic/internal/decoder/generic_regabi_amd64_test.s +++ b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/generic_regabi_amd64_test.s @@ -1,4 +1,4 @@ -// +build go1.17,!go1.22 +// +build go1.17,!go1.24 // // Copyright 2021 ByteDance Inc. diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/pools.go b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/pools.go similarity index 97% rename from vendor/github.com/bytedance/sonic/internal/decoder/pools.go rename to vendor/github.com/bytedance/sonic/internal/decoder/jitdec/pools.go index bcd14cc64..01868cb2f 100644 --- a/vendor/github.com/bytedance/sonic/internal/decoder/pools.go +++ b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/pools.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package decoder +package jitdec import ( `sync` @@ -36,6 +36,7 @@ const ( _PtrBytes = _PTR_SIZE / 8 _FsmOffset = (_MaxStack + 1) * _PtrBytes _DbufOffset = _FsmOffset + int64(unsafe.Sizeof(types.StateMachine{})) + types.MAX_RECURSE * _PtrBytes + _EpOffset = _DbufOffset + _MaxDigitNums _StackSize = unsafe.Sizeof(_Stack{}) ) @@ -53,6 +54,7 @@ type _Stack struct { mm types.StateMachine vp [types.MAX_RECURSE]unsafe.Pointer dp [_MaxDigitNums]byte + ep unsafe.Pointer } type _Decoder func( diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/primitives.go b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/primitives.go similarity index 84% rename from vendor/github.com/bytedance/sonic/internal/decoder/primitives.go rename to vendor/github.com/bytedance/sonic/internal/decoder/jitdec/primitives.go index d6053e2cb..5adfc038a 100644 --- a/vendor/github.com/bytedance/sonic/internal/decoder/primitives.go +++ b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/primitives.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package decoder +package jitdec import ( `encoding` @@ -30,9 +30,7 @@ func decodeTypedPointer(s string, i int, vt *rt.GoType, vp unsafe.Pointer, sb *_ return 0, err } else { rt.MoreStack(_FP_size + _VD_size + native.MaxFrameSize) - rt.StopProf() ret, err := fn(s, i, vp, sb, fv, "", nil) - rt.StartProf() return ret, err } } @@ -41,6 +39,13 @@ func decodeJsonUnmarshaler(vv interface{}, s string) error { return vv.(json.Unmarshaler).UnmarshalJSON(rt.Str2Mem(s)) } +func decodeJsonUnmarshalerQuoted(vv interface{}, s string) error { + if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' { + return &MismatchTypeError{} + } + return vv.(json.Unmarshaler).UnmarshalJSON(rt.Str2Mem(s[1:len(s)-1])) +} + func decodeTextUnmarshaler(vv interface{}, s string) error { return vv.(encoding.TextUnmarshaler).UnmarshalText(rt.Str2Mem(s)) } diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/stubs_go116.go b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/stubs_go116.go similarity index 91% rename from vendor/github.com/bytedance/sonic/internal/decoder/stubs_go116.go rename to vendor/github.com/bytedance/sonic/internal/decoder/jitdec/stubs_go116.go index c6e133d8c..8fa7c32fc 100644 --- a/vendor/github.com/bytedance/sonic/internal/decoder/stubs_go116.go +++ b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/stubs_go116.go @@ -1,4 +1,4 @@ -// +build go1.16,!go1.20 +// +build go1.17,!go1.20 /* * Copyright 2021 ByteDance Inc. @@ -16,18 +16,18 @@ * limitations under the License. */ -package decoder +package jitdec import ( `unsafe` `reflect` - _ `github.com/chenzhuoyu/base64x` + _ `github.com/cloudwego/base64x` `github.com/bytedance/sonic/internal/rt` ) -//go:linkname _subr__b64decode github.com/chenzhuoyu/base64x._subr__b64decode +//go:linkname _subr__b64decode github.com/cloudwego/base64x._subr__b64decode var _subr__b64decode uintptr // runtime.maxElementSize @@ -72,11 +72,6 @@ func mallocgc(size uintptr, typ *rt.GoType, needzero bool) unsafe.Pointer //goland:noinspection GoUnusedParameter func makeslice(et *rt.GoType, len int, cap int) unsafe.Pointer -//go:noescape -//go:linkname growslice runtime.growslice -//goland:noinspection GoUnusedParameter -func growslice(et *rt.GoType, old rt.GoSlice, cap int) rt.GoSlice - //go:linkname makemap_small runtime.makemap_small func makemap_small() unsafe.Pointer diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/stubs_go120.go b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/stubs_go120.go similarity index 91% rename from vendor/github.com/bytedance/sonic/internal/decoder/stubs_go120.go rename to vendor/github.com/bytedance/sonic/internal/decoder/jitdec/stubs_go120.go index 73960ea14..a6dad26d7 100644 --- a/vendor/github.com/bytedance/sonic/internal/decoder/stubs_go120.go +++ b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/stubs_go120.go @@ -16,18 +16,18 @@ * limitations under the License. */ -package decoder +package jitdec import ( `unsafe` `reflect` - _ `github.com/chenzhuoyu/base64x` + _ `github.com/cloudwego/base64x` `github.com/bytedance/sonic/internal/rt` ) -//go:linkname _subr__b64decode github.com/chenzhuoyu/base64x._subr__b64decode +//go:linkname _subr__b64decode github.com/cloudwego/base64x._subr__b64decode var _subr__b64decode uintptr // runtime.maxElementSize @@ -72,11 +72,6 @@ func mallocgc(size uintptr, typ *rt.GoType, needzero bool) unsafe.Pointer //goland:noinspection GoUnusedParameter func makeslice(et *rt.GoType, len int, cap int) unsafe.Pointer -//go:noescape -//go:linkname growslice reflect.growslice -//goland:noinspection GoUnusedParameter -func growslice(et *rt.GoType, old rt.GoSlice, cap int) rt.GoSlice - //go:linkname makemap_small runtime.makemap_small func makemap_small() unsafe.Pointer diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/types.go b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/types.go similarity index 99% rename from vendor/github.com/bytedance/sonic/internal/decoder/types.go rename to vendor/github.com/bytedance/sonic/internal/decoder/jitdec/types.go index 6fc0e706c..c196eb5b7 100644 --- a/vendor/github.com/bytedance/sonic/internal/decoder/types.go +++ b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/types.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package decoder +package jitdec import ( `encoding` diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/utils.go b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/utils.go similarity index 98% rename from vendor/github.com/bytedance/sonic/internal/decoder/utils.go rename to vendor/github.com/bytedance/sonic/internal/decoder/jitdec/utils.go index 23ee5d501..0a7a20289 100644 --- a/vendor/github.com/bytedance/sonic/internal/decoder/utils.go +++ b/vendor/github.com/bytedance/sonic/internal/decoder/jitdec/utils.go @@ -14,7 +14,7 @@ * limitations under the License. */ -package decoder +package jitdec import ( `unsafe` diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/compile_struct.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/compile_struct.go new file mode 100644 index 000000000..713fb6561 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/compile_struct.go @@ -0,0 +1,174 @@ +package optdec + +import ( + "fmt" + "reflect" + + caching "github.com/bytedance/sonic/internal/optcaching" + "github.com/bytedance/sonic/internal/rt" + "github.com/bytedance/sonic/internal/resolver" +) + +const ( + _MAX_FIELDS = 50 // cutoff at 50 fields struct +) + +func (c *compiler) compileIntStringOption(vt reflect.Type) decFunc { + switch vt.Size() { + case 4: + switch vt.Kind() { + case reflect.Uint: + fallthrough + case reflect.Uintptr: + return &u32StringDecoder{} + case reflect.Int: + return &i32StringDecoder{} + } + case 8: + switch vt.Kind() { + case reflect.Uint: + fallthrough + case reflect.Uintptr: + return &u64StringDecoder{} + case reflect.Int: + return &i64StringDecoder{} + } + default: + panic("not supported pointer size: " + fmt.Sprint(vt.Size())) + } + panic("unreachable") +} + +func isInteger(vt reflect.Type) bool { + switch vt.Kind() { + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint, reflect.Uintptr, reflect.Int: return true + default: return false + } +} + +func (c *compiler) assertStringOptTypes(vt reflect.Type) { + if c.depth > _CompileMaxDepth { + panic(*stackOverflow) + } + + c.depth += 1 + defer func () { + c.depth -= 1 + }() + + if isInteger(vt) { + return + } + + switch vt.Kind() { + case reflect.String, reflect.Bool, reflect.Float32, reflect.Float64: + return + case reflect.Ptr: c.assertStringOptTypes(vt.Elem()) + default: + panicForInvalidStrType(vt) + } +} + +func (c *compiler) compileFieldStringOption(vt reflect.Type) decFunc { + c.assertStringOptTypes(vt) + unmDec := c.tryCompilePtrUnmarshaler(vt, true) + if unmDec != nil { + return unmDec + } + + switch vt.Kind() { + case reflect.String: + if vt == jsonNumberType { + return &numberStringDecoder{} + } + return &strStringDecoder{} + case reflect.Bool: + return &boolStringDecoder{} + case reflect.Int8: + return &i8StringDecoder{} + case reflect.Int16: + return &i16StringDecoder{} + case reflect.Int32: + return &i32StringDecoder{} + case reflect.Int64: + return &i64StringDecoder{} + case reflect.Uint8: + return &u8StringDecoder{} + case reflect.Uint16: + return &u16StringDecoder{} + case reflect.Uint32: + return &u32StringDecoder{} + case reflect.Uint64: + return &u64StringDecoder{} + case reflect.Float32: + return &f32StringDecoder{} + case reflect.Float64: + return &f64StringDecoder{} + case reflect.Uint: + fallthrough + case reflect.Uintptr: + fallthrough + case reflect.Int: + return c.compileIntStringOption(vt) + case reflect.Ptr: + return &ptrStrDecoder{ + typ: rt.UnpackType(vt.Elem()), + deref: c.compileFieldStringOption(vt.Elem()), + } + default: + panicForInvalidStrType(vt) + return nil + } +} + +func (c *compiler) compileStruct(vt reflect.Type) decFunc { + c.enter(vt) + defer c.exit(vt) + if c.namedPtr { + c.namedPtr = false + return c.compileStructBody(vt) + } + + if c.depth >= c.opts.MaxInlineDepth + 1 || (c.counts > 0 && vt.NumField() >= _MAX_FIELDS) { + return &recuriveDecoder{ + typ: rt.UnpackType(vt), + } + } else { + return c.compileStructBody(vt) + } +} + +func (c *compiler) compileStructBody(vt reflect.Type) decFunc { + fv := resolver.ResolveStruct(vt) + entries := make([]fieldEntry, 0, len(fv)) + + for _, f := range fv { + var dec decFunc + /* dealt with field tag options */ + if f.Opts&resolver.F_stringize != 0 { + dec = c.compileFieldStringOption(f.Type) + } else { + dec = c.compile(f.Type) + } + + /* deal with embedded pointer fields */ + if f.Path[0].Kind == resolver.F_deref { + dec = &embeddedFieldPtrDecoder{ + field: f, + fieldDec: dec, + fieldName: f.Name, + } + } + + entries = append(entries, fieldEntry{ + FieldMeta: f, + fieldDec: dec, + }) + } + return &structDecoder{ + fieldMap: caching.NewFieldLookup(fv), + fields: entries, + structName: vt.Name(), + typ: vt, + } +} diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/compiler.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/compiler.go new file mode 100644 index 000000000..fd164af93 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/compiler.go @@ -0,0 +1,449 @@ +package optdec + +import ( + "encoding/json" + "fmt" + "reflect" + + "github.com/bytedance/sonic/option" + "github.com/bytedance/sonic/internal/rt" + "github.com/bytedance/sonic/internal/caching" +) + +var ( + programCache = caching.CreateProgramCache() +) + +func findOrCompile(vt *rt.GoType) (decFunc, error) { + makeDecoder := func(vt *rt.GoType, _ ...interface{}) (interface{}, error) { + ret, err := newCompiler().compileType(vt.Pack()) + return ret, err + } + if val := programCache.Get(vt); val != nil { + return val.(decFunc), nil + } else if ret, err := programCache.Compute(vt, makeDecoder); err == nil { + return ret.(decFunc), nil + } else { + return nil, err + } +} + +type compiler struct { + visited map[reflect.Type]bool + depth int + counts int + opts option.CompileOptions + namedPtr bool +} + +func newCompiler() *compiler { + return &compiler{ + visited: make(map[reflect.Type]bool), + opts: option.DefaultCompileOptions(), + } +} + +func (self *compiler) apply(opts option.CompileOptions) *compiler { + self.opts = opts + return self +} + +const _CompileMaxDepth = 4096 + +func (c *compiler) enter(vt reflect.Type) { + c.visited[vt] = true + c.depth += 1 + + if c.depth > _CompileMaxDepth { + panic(*stackOverflow) + } +} + +func (c *compiler) exit(vt reflect.Type) { + c.visited[vt] = false + c.depth -= 1 +} + +func (c *compiler) compileInt(vt reflect.Type) decFunc { + switch vt.Size() { + case 4: + switch vt.Kind() { + case reflect.Uint: + fallthrough + case reflect.Uintptr: + return &u32Decoder{} + case reflect.Int: + return &i32Decoder{} + } + case 8: + switch vt.Kind() { + case reflect.Uint: + fallthrough + case reflect.Uintptr: + return &u64Decoder{} + case reflect.Int: + return &i64Decoder{} + } + default: + panic("not supported pointer size: " + fmt.Sprint(vt.Size())) + } + panic("unreachable") +} + +func (c *compiler) rescue(ep *error) { + if val := recover(); val != nil { + if err, ok := val.(error); ok { + *ep = err + } else { + panic(val) + } + } +} + +func (c *compiler) compileType(vt reflect.Type) (rt decFunc, err error) { + defer c.rescue(&err) + rt = c.compile(vt) + return rt, err +} + +func (c *compiler) compile(vt reflect.Type) decFunc { + if c.visited[vt] { + return &recuriveDecoder{ + typ: rt.UnpackType(vt), + } + } + + dec := c.tryCompilePtrUnmarshaler(vt, false) + if dec != nil { + return dec + } + + return c.compileBasic(vt) +} + +func (c *compiler) compileBasic(vt reflect.Type) decFunc { + defer func() { + c.counts += 1 + }() + switch vt.Kind() { + case reflect.Bool: + return &boolDecoder{} + case reflect.Int8: + return &i8Decoder{} + case reflect.Int16: + return &i16Decoder{} + case reflect.Int32: + return &i32Decoder{} + case reflect.Int64: + return &i64Decoder{} + case reflect.Uint8: + return &u8Decoder{} + case reflect.Uint16: + return &u16Decoder{} + case reflect.Uint32: + return &u32Decoder{} + case reflect.Uint64: + return &u64Decoder{} + case reflect.Float32: + return &f32Decoder{} + case reflect.Float64: + return &f64Decoder{} + case reflect.Uint: + fallthrough + case reflect.Uintptr: + fallthrough + case reflect.Int: + return c.compileInt(vt) + case reflect.String: + return c.compileString(vt) + case reflect.Array: + return c.compileArray(vt) + case reflect.Interface: + return c.compileInterface(vt) + case reflect.Map: + return c.compileMap(vt) + case reflect.Ptr: + return c.compilePtr(vt) + case reflect.Slice: + return c.compileSlice(vt) + case reflect.Struct: + return c.compileStruct(vt) + default: + panic(&json.UnmarshalTypeError{Type: vt}) + } +} + +func (c *compiler) compilePtr(vt reflect.Type) decFunc { + c.enter(vt) + defer c.exit(vt) + + // specail logic for Named Ptr, issue 379 + if reflect.PtrTo(vt.Elem()) != vt { + c.namedPtr = true + return &ptrDecoder{ + typ: rt.UnpackType(vt.Elem()), + deref: c.compileBasic(vt.Elem()), + } + } + + return &ptrDecoder{ + typ: rt.UnpackType(vt.Elem()), + deref: c.compile(vt.Elem()), + } +} + +func (c *compiler) compileArray(vt reflect.Type) decFunc { + c.enter(vt) + defer c.exit(vt) + return &arrayDecoder{ + len: vt.Len(), + elemType: rt.UnpackType(vt.Elem()), + elemDec: c.compile(vt.Elem()), + typ: vt, + } +} + +func (c *compiler) compileString(vt reflect.Type) decFunc { + if vt == jsonNumberType { + return &numberDecoder{} + } + return &stringDecoder{} + +} + +func (c *compiler) tryCompileSliceUnmarshaler(vt reflect.Type) decFunc { + pt := reflect.PtrTo(vt.Elem()) + if pt.Implements(jsonUnmarshalerType) { + return &sliceDecoder{ + elemType: rt.UnpackType(vt.Elem()), + elemDec: c.compile(vt.Elem()), + typ: vt, + } + } + + if pt.Implements(encodingTextUnmarshalerType) { + return &sliceDecoder{ + elemType: rt.UnpackType(vt.Elem()), + elemDec: c.compile(vt.Elem()), + typ: vt, + } + } + return nil +} + +func (c *compiler) compileSlice(vt reflect.Type) decFunc { + c.enter(vt) + defer c.exit(vt) + + // Some common slice, use a decoder, to avoid function calls + et := rt.UnpackType(vt.Elem()) + + /* first checking `[]byte` */ + if et.Kind() == reflect.Uint8 /* []byte */ { + return c.compileSliceBytes(vt) + } + + dec := c.tryCompileSliceUnmarshaler(vt) + if dec != nil { + return dec + } + + if vt == reflect.TypeOf([]interface{}{}) { + return &sliceEfaceDecoder{} + } + if et.IsInt32() { + return &sliceI32Decoder{} + } + if et.IsInt64() { + return &sliceI64Decoder{} + } + if et.IsUint32() { + return &sliceU32Decoder{} + } + if et.IsUint64() { + return &sliceU64Decoder{} + } + if et.Kind() == reflect.String { + return &sliceStringDecoder{} + } + + return &sliceDecoder{ + elemType: rt.UnpackType(vt.Elem()), + elemDec: c.compile(vt.Elem()), + typ: vt, + } +} + +func (c *compiler) compileSliceBytes(vt reflect.Type) decFunc { + ep := reflect.PtrTo(vt.Elem()) + + if ep.Implements(jsonUnmarshalerType) { + return &sliceBytesUnmarshalerDecoder{ + elemType: rt.UnpackType(vt.Elem()), + elemDec: c.compile(vt.Elem()), + typ: vt, + } + } + + if ep.Implements(encodingTextUnmarshalerType) { + return &sliceBytesUnmarshalerDecoder{ + elemType: rt.UnpackType(vt.Elem()), + elemDec: c.compile(vt.Elem()), + typ: vt, + } + } + + return &sliceBytesDecoder{} +} + +func (c *compiler) compileInterface(vt reflect.Type) decFunc { + c.enter(vt) + defer c.exit(vt) + if vt.NumMethod() == 0 { + return &efaceDecoder{} + } + + if vt.Implements(jsonUnmarshalerType) { + return &unmarshalJSONDecoder{ + typ: rt.UnpackType(vt), + } + } + + if vt.Implements(encodingTextUnmarshalerType) { + return &unmarshalTextDecoder{ + typ: rt.UnpackType(vt), + } + } + + return &ifaceDecoder{ + typ: rt.UnpackType(vt), + } +} + +func (c *compiler) compileMap(vt reflect.Type) decFunc { + c.enter(vt) + defer c.exit(vt) + // check the key unmarshaler at first + decKey := tryCompileKeyUnmarshaler(vt) + if decKey != nil { + return &mapDecoder{ + mapType: rt.MapType(rt.UnpackType(vt)), + keyDec: decKey, + elemDec: c.compile(vt.Elem()), + } + } + + // Most common map, use a decoder, to avoid function calls + if vt == reflect.TypeOf(map[string]interface{}{}) { + return &mapEfaceDecoder{} + } else if vt == reflect.TypeOf(map[string]string{}) { + return &mapStringDecoder{} + } + + // Some common integer map later + mt := rt.MapType(rt.UnpackType(vt)) + + if mt.Key.Kind() == reflect.String { + return &mapStrKeyDecoder{ + mapType: mt, + assign: rt.GetMapStrAssign(vt), + elemDec: c.compile(vt.Elem()), + } + } + + if mt.Key.IsInt64() { + return &mapI64KeyDecoder{ + mapType: mt, + elemDec: c.compile(vt.Elem()), + assign: rt.GetMap64Assign(vt), + } + } + + if mt.Key.IsInt32() { + return &mapI32KeyDecoder{ + mapType: mt, + elemDec: c.compile(vt.Elem()), + assign: rt.GetMap32Assign(vt), + } + } + + if mt.Key.IsUint64() { + return &mapU64KeyDecoder{ + mapType: mt, + elemDec: c.compile(vt.Elem()), + assign: rt.GetMap64Assign(vt), + } + } + + if mt.Key.IsUint32() { + return &mapU32KeyDecoder{ + mapType: mt, + elemDec: c.compile(vt.Elem()), + assign: rt.GetMap32Assign(vt), + } + } + + // Generic map + return &mapDecoder{ + mapType: mt, + keyDec: c.compileMapKey(vt), + elemDec: c.compile(vt.Elem()), + } +} + +func tryCompileKeyUnmarshaler(vt reflect.Type) decKey { + pt := reflect.PtrTo(vt.Key()) + + /* check for `encoding.TextUnmarshaler` with pointer receiver */ + if pt.Implements(encodingTextUnmarshalerType) { + return decodeKeyTextUnmarshaler + } + + /* not support map key with `json.Unmarshaler` */ + return nil +} + +func (c *compiler) compileMapKey(vt reflect.Type) decKey { + switch vt.Key().Kind() { + case reflect.Int8: + return decodeKeyI8 + case reflect.Int16: + return decodeKeyI16 + case reflect.Uint8: + return decodeKeyU8 + case reflect.Uint16: + return decodeKeyU16 + default: + panic(&json.UnmarshalTypeError{Type: vt}) + } +} + +// maybe vt is a named type, and not a pointer receiver, see issue 379 +func (c *compiler) tryCompilePtrUnmarshaler(vt reflect.Type, strOpt bool) decFunc { + pt := reflect.PtrTo(vt) + + /* check for `json.Unmarshaler` with pointer receiver */ + if pt.Implements(jsonUnmarshalerType) { + return &unmarshalJSONDecoder{ + typ: rt.UnpackType(pt), + strOpt: strOpt, + } + } + + /* check for `encoding.TextMarshaler` with pointer receiver */ + if pt.Implements(encodingTextUnmarshalerType) { + /* TextUnmarshal not support ,strig tag */ + if strOpt { + panicForInvalidStrType(vt) + } + return &unmarshalTextDecoder{ + typ: rt.UnpackType(pt), + } + } + + return nil +} + +func panicForInvalidStrType(vt reflect.Type) { + panic(error_type(rt.UnpackType(vt))) +} diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/const.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/const.go new file mode 100644 index 000000000..77879fafe --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/const.go @@ -0,0 +1,60 @@ +package optdec + +import "math" + +/* +Copied from sonic-rs +// JSON Value Type +const NULL: u64 = 0; +const BOOL: u64 = 2; +const FALSE: u64 = BOOL; +const TRUE: u64 = (1 << 3) | BOOL; +const NUMBER: u64 = 3; +const UINT: u64 = NUMBER; +const SINT: u64 = (1 << 3) | NUMBER; +const REAL: u64 = (2 << 3) | NUMBER; +const RAWNUMBER: u64 = (3 << 3) | NUMBER; +const STRING: u64 = 4; +const STRING_COMMON: u64 = STRING; +const STRING_HASESCAPED: u64 = (1 << 3) | STRING; +const OBJECT: u64 = 6; +const ARRAY: u64 = 7; + +/// JSON Type Mask +const POS_MASK: u64 = (!0) << 32; +const POS_BITS: u64 = 32; +const TYPE_MASK: u64 = 0xFF; +const TYPE_BITS: u64 = 8; + +*/ + +const ( + // BasicType: 3 bits + KNull = 0 // xxxxx000 + KBool = 2 // xxxxx010 + KNumber = 3 // xxxxx011 + KString = 4 // xxxxx100 + KRaw = 5 // xxxxx101 + KObject = 6 // xxxxx110 + KArray = 7 // xxxxx111 + + // SubType: 2 bits + KFalse = (0 << 3) | KBool // xxx00_010, 2 + KTrue = (1 << 3) | KBool // xxx01_010, 10 + KUint = (0 << 3) | KNumber // xxx00_011, 3 + KSint = (1 << 3) | KNumber // xxx01_011, 11 + KReal = (2 << 3) | KNumber // xxx10_011, 19 + KRawNumber = (3 << 3) | KNumber // xxx11_011, 27 + KStringCommon = KString // xxx00_100, 4 + KStringEscaped = (1 << 3) | KString // xxx01_100, 12 +) + +const ( + PosMask = math.MaxUint64 << 32 + PosBits = 32 + TypeMask = 0xFF + TypeBits = 8 + + ConLenMask = uint64(math.MaxUint32) + ConLenBits = 32 +) diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/context.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/context.go new file mode 100644 index 000000000..93ed9b7e0 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/context.go @@ -0,0 +1,3 @@ +package optdec + +type context = Context diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/decoder.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/decoder.go new file mode 100644 index 000000000..81eed34ea --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/decoder.go @@ -0,0 +1,160 @@ +package optdec + +import ( + "reflect" + "unsafe" + + "encoding/json" + "github.com/bytedance/sonic/internal/rt" + "github.com/bytedance/sonic/option" + "github.com/bytedance/sonic/internal/decoder/errors" + "github.com/bytedance/sonic/internal/decoder/consts" +) + + +type ( + MismatchTypeError = errors.MismatchTypeError + SyntaxError = errors.SyntaxError +) + +const ( + _F_allow_control = consts.F_allow_control + _F_copy_string = consts.F_copy_string + _F_disable_unknown = consts.F_disable_unknown + _F_disable_urc = consts.F_disable_urc + _F_use_int64 = consts.F_use_int64 + _F_use_number = consts.F_use_number + _F_validate_string = consts.F_validate_string +) + +type Options = consts.Options + +const ( + OptionUseInt64 = consts.OptionUseInt64 + OptionUseNumber = consts.OptionUseNumber + OptionUseUnicodeErrors = consts.OptionUseUnicodeErrors + OptionDisableUnknown = consts.OptionDisableUnknown + OptionCopyString = consts.OptionCopyString + OptionValidateString = consts.OptionValidateString +) + + +func Decode(s *string, i *int, f uint64, val interface{}) error { + vv := rt.UnpackEface(val) + vp := vv.Value + + /* check for nil type */ + if vv.Type == nil { + return &json.InvalidUnmarshalError{} + } + + /* must be a non-nil pointer */ + if vp == nil || vv.Type.Kind() != reflect.Ptr { + return &json.InvalidUnmarshalError{Type: vv.Type.Pack()} + } + + etp := rt.PtrElem(vv.Type) + + /* check the defined pointer type for issue 379 */ + if vv.Type.IsNamed() { + newp := vp + etp = vv.Type + vp = unsafe.Pointer(&newp) + } + + dec, err := findOrCompile(etp) + if err != nil { + return err + } + + /* parse into document */ + ctx, err := NewContext(*s, *i, uint64(f), etp) + defer ctx.Delete() + if ctx.Parser.Utf8Inv { + *s = ctx.Parser.Json + } + if err != nil { + goto fix_error; + } + err = dec.FromDom(vp, ctx.Root(), &ctx) + +fix_error: + err = fix_error(*s, *i, err) + + // update position at last + *i += ctx.Parser.Pos() + return err +} + +func fix_error(json string, pos int, err error) error { + if e, ok := err.(SyntaxError); ok { + return SyntaxError{ + Pos: int(e.Pos) + pos, + Src: json, + Msg: e.Msg, + } + } + + if e, ok := err.(MismatchTypeError); ok { + return &MismatchTypeError { + Pos: int(e.Pos) + pos, + Src: json, + Type: e.Type, + } + } + + return err +} + +// Pretouch compiles vt ahead-of-time to avoid JIT compilation on-the-fly, in +// order to reduce the first-hit latency. +// +// Opts are the compile options, for example, "option.WithCompileRecursiveDepth" is +// a compile option to set the depth of recursive compile for the nested struct type. +func Pretouch(vt reflect.Type, opts ...option.CompileOption) error { + cfg := option.DefaultCompileOptions() + for _, opt := range opts { + opt(&cfg) + } + return pretouchRec(map[reflect.Type]bool{vt:true}, cfg) +} + +func pretouchType(_vt reflect.Type, opts option.CompileOptions) (map[reflect.Type]bool, error) { + /* compile function */ + compiler := newCompiler().apply(opts) + decoder := func(vt *rt.GoType, _ ...interface{}) (interface{}, error) { + if f, err := compiler.compileType(_vt); err != nil { + return nil, err + } else { + return f, nil + } + } + + /* find or compile */ + vt := rt.UnpackType(_vt) + if val := programCache.Get(vt); val != nil { + return nil, nil + } else if _, err := programCache.Compute(vt, decoder); err == nil { + return compiler.visited, nil + } else { + return nil, err + } +} + +func pretouchRec(vtm map[reflect.Type]bool, opts option.CompileOptions) error { + if opts.RecursiveDepth < 0 || len(vtm) == 0 { + return nil + } + next := make(map[reflect.Type]bool) + for vt := range(vtm) { + sub, err := pretouchType(vt, opts) + if err != nil { + return err + } + for svt := range(sub) { + next[svt] = true + } + } + opts.RecursiveDepth -= 1 + return pretouchRec(next, opts) +} diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/errors.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/errors.go new file mode 100644 index 000000000..db0af547b --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/errors.go @@ -0,0 +1,73 @@ +/* + * 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 optdec + + import ( + "encoding/json" + "errors" + "reflect" + "strconv" + + "github.com/bytedance/sonic/internal/rt" + ) + + /** JIT Error Helpers **/ + + var stackOverflow = &json.UnsupportedValueError{ + Str: "Value nesting too deep", + Value: reflect.ValueOf("..."), + } + + func error_type(vt *rt.GoType) error { + return &json.UnmarshalTypeError{Type: vt.Pack()} + } + + func error_mismatch(node Node, ctx *context, typ reflect.Type) error { + return MismatchTypeError{ + Pos: node.Position(), + Src: ctx.Parser.Json, + Type: typ, + } + } + + func newUnmatched(pos int, vt *rt.GoType) error { + return MismatchTypeError{ + Pos: pos, + Src: "", + Type: vt.Pack(), + } + } + + func error_field(name string) error { + return errors.New("json: unknown field " + strconv.Quote(name)) + } + + func error_value(value string, vtype reflect.Type) error { + return &json.UnmarshalTypeError{ + Type: vtype, + Value: value, + } + } + + func error_syntax(pos int, src string, msg string) error { + return SyntaxError{ + Pos: pos, + Src: src, + Msg: msg, + } + } + \ No newline at end of file diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/functor.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/functor.go new file mode 100644 index 000000000..2a0523d5e --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/functor.go @@ -0,0 +1,281 @@ +package optdec + +import ( + "encoding/json" + "math" + "unsafe" + + "github.com/bytedance/sonic/internal/rt" + "github.com/bytedance/sonic/internal/resolver" +) + +type decFunc interface { + FromDom(vp unsafe.Pointer, node Node, ctx *context) error +} + +type ptrDecoder struct { + typ *rt.GoType + deref decFunc +} + +// Pointer Value is allocated in the Caller +func (d *ptrDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*unsafe.Pointer)(vp) = nil + return nil + } + + if *(*unsafe.Pointer)(vp) == nil { + *(*unsafe.Pointer)(vp) = rt.Mallocgc(d.typ.Size, d.typ, true) + } + + return d.deref.FromDom(*(*unsafe.Pointer)(vp), node, ctx) +} + +type embeddedFieldPtrDecoder struct { + field resolver.FieldMeta + fieldDec decFunc + fieldName string +} + +// Pointer Value is allocated in the Caller +func (d *embeddedFieldPtrDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + // seek into the pointer + vp = unsafe.Pointer(uintptr(vp) - uintptr(d.field.Path[0].Size)) + for _, f := range d.field.Path { + deref := rt.UnpackType(f.Type) + vp = unsafe.Pointer(uintptr(vp) + f.Size) + if f.Kind == resolver.F_deref { + if *(*unsafe.Pointer)(vp) == nil { + *(*unsafe.Pointer)(vp) = rt.Mallocgc(deref.Size, deref, true) + } + vp = *(*unsafe.Pointer)(vp) + } + } + return d.fieldDec.FromDom(vp, node, ctx) +} + +type i8Decoder struct{} + +func (d *i8Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + ret, ok := node.AsI64(ctx) + if !ok || ret > math.MaxInt8 || ret < math.MinInt8 { + return error_mismatch(node, ctx, int8Type) + } + + *(*int8)(vp) = int8(ret) + return nil +} + +type i16Decoder struct{} + +func (d *i16Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + ret, ok := node.AsI64(ctx) + if !ok || ret > math.MaxInt16 || ret < math.MinInt16 { + return error_mismatch(node, ctx, int16Type) + } + + *(*int16)(vp) = int16(ret) + return nil +} + +type i32Decoder struct{} + +func (d *i32Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + ret, ok := node.AsI64(ctx) + if !ok || ret > math.MaxInt32 || ret < math.MinInt32 { + return error_mismatch(node, ctx, int32Type) + } + + *(*int32)(vp) = int32(ret) + return nil +} + +type i64Decoder struct{} + +func (d *i64Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + ret, ok := node.AsI64(ctx) + if !ok { + return error_mismatch(node, ctx, int64Type) + } + + *(*int64)(vp) = int64(ret) + return nil +} + +type u8Decoder struct{} + +func (d *u8Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + ret, ok := node.AsU64(ctx) + if !ok || ret > math.MaxUint8 { + err := error_mismatch(node, ctx, uint8Type) + return err + } + + *(*uint8)(vp) = uint8(ret) + return nil +} + +type u16Decoder struct{} + +func (d *u16Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + ret, ok := node.AsU64(ctx) + if !ok || ret > math.MaxUint16 { + return error_mismatch(node, ctx, uint16Type) + } + *(*uint16)(vp) = uint16(ret) + return nil +} + +type u32Decoder struct{} + +func (d *u32Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + ret, ok := node.AsU64(ctx) + if !ok || ret > math.MaxUint32 { + return error_mismatch(node, ctx, uint32Type) + } + + *(*uint32)(vp) = uint32(ret) + return nil +} + +type u64Decoder struct{} + +func (d *u64Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + ret, ok := node.AsU64(ctx) + if !ok { + return error_mismatch(node, ctx, uint64Type) + } + + *(*uint64)(vp) = uint64(ret) + return nil +} + +type f32Decoder struct{} + +func (d *f32Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + ret, ok := node.AsF64(ctx) + if !ok || ret > math.MaxFloat32 || ret < -math.MaxFloat32 { + return error_mismatch(node, ctx, float32Type) + } + + *(*float32)(vp) = float32(ret) + return nil +} + +type f64Decoder struct{} + +func (d *f64Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + ret, ok := node.AsF64(ctx) + if !ok { + return error_mismatch(node, ctx, float64Type) + } + + *(*float64)(vp) = float64(ret) + return nil +} + +type boolDecoder struct { +} + +func (d *boolDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + ret, ok := node.AsBool() + if !ok { + return error_mismatch(node, ctx, boolType) + } + + *(*bool)(vp) = bool(ret) + return nil +} + +type stringDecoder struct { +} + +func (d *stringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + ret, ok := node.AsStr(ctx) + if !ok { + return error_mismatch(node, ctx, stringType) + } + *(*string)(vp) = ret + return nil +} + +type numberDecoder struct { +} + +func (d *numberDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + num, ok := node.AsNumber(ctx) + if !ok { + return error_mismatch(node, ctx, jsonNumberType) + } + *(*json.Number)(vp) = num + return nil +} + +type recuriveDecoder struct { + typ *rt.GoType +} + +func (d *recuriveDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + dec, err := findOrCompile(d.typ) + if err != nil { + return err + } + return dec.FromDom(vp, node, ctx) +} diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/helper.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/helper.go new file mode 100644 index 000000000..1d76f8051 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/helper.go @@ -0,0 +1,101 @@ +package optdec + +import ( + "encoding/json" + "strconv" + + "github.com/bytedance/sonic/internal/native" + "github.com/bytedance/sonic/internal/native/types" +) + + +func SkipNumberFast(json string, start int) (int, error) { + // find the number ending, we pasred in sonic-cpp, it alway valid + pos := start + for pos < len(json) && json[pos] != ']' && json[pos] != '}' && json[pos] != ',' { + if json[pos] >= '0' && json[pos] <= '9' || json[pos] == '.' || json[pos] == '-' || json[pos] == '+' || json[pos] == 'e' || json[pos] == 'E' { + pos += 1 + } else { + return pos, error_syntax(pos, json, "invalid number") + } + } + return pos, nil +} + +func ValidNumberFast(json string) error { + // find the number ending, we pasred in sonic-cpp, it alway valid + pos := 0 + for pos < len(json) && json[pos] != ']' && json[pos] != '}' && json[pos] != ',' { + if json[pos] >= '0' && json[pos] <= '9' || json[pos] == '.' || json[pos] == '-' || json[pos] == '+' || json[pos] == 'e' || json[pos] == 'E' { + pos += 1 + } else { + return error_syntax(pos, json, "invalid number") + } + } + + if pos == 0 { + return error_syntax(pos, json, "invalid number") + } + return nil +} + +func SkipOneFast2(json string, pos *int) (int, error) { + // find the number ending, we pasred in sonic-cpp, it alway valid + start := native.SkipOneFast(&json, pos) + if start < 0 { + return -1, error_syntax(*pos, json, types.ParsingError(-start).Error()) + } + return start, nil +} + +func SkipOneFast(json string, pos int) (string, error) { + // find the number ending, we pasred in sonic-cpp, it alway valid + start := native.SkipOneFast(&json, &pos) + if start < 0 { + // TODO: details error code + return "", error_syntax(pos, json, types.ParsingError(-start).Error()) + } + return json[start:pos], nil +} + +func ParseI64(raw string) (int64, error) { + i64, err := strconv.ParseInt(raw, 10, 64) + if err != nil { + return 0, err + } + return i64, nil +} + +func ParseBool(raw string) (bool, error) { + var b bool + err := json.Unmarshal([]byte(raw), &b) + if err != nil { + return false, err + } + return b, nil +} + +func ParseU64(raw string) (uint64, error) { + u64, err := strconv.ParseUint(raw, 10, 64) + if err != nil { + return 0, err + } + return u64, nil +} + +func ParseF64(raw string) (float64, error) { + f64, err := strconv.ParseFloat(raw, 64) + if err != nil { + return 0, err + } + return f64, nil +} + +func Unquote(raw string) (string, error) { + var u string + err := json.Unmarshal([]byte(raw), &u) + if err != nil { + return "", err + } + return u, nil +} diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/interface.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/interface.go new file mode 100644 index 000000000..0c063d55f --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/interface.go @@ -0,0 +1,169 @@ +package optdec + +import ( + "encoding" + "encoding/json" + "unsafe" + "reflect" + + "github.com/bytedance/sonic/internal/rt" +) + +type efaceDecoder struct { +} + +func (d *efaceDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*interface{})(vp) = interface{}(nil) + return nil + } + + eface := *(*rt.GoEface)(vp) + + // not pointer type, or nil pointer, or *interface{} + if eface.Value == nil || eface.Type.Kind() != reflect.Ptr || rt.PtrElem(eface.Type) == anyType { + ret, err := node.AsEface(ctx) + if err != nil { + return err + } + + *(*interface{})(vp) = ret + return nil + } + + etp := rt.PtrElem(eface.Type) + vp = eface.Value + + /* check the defined pointer type for issue 379 */ + if eface.Type.IsNamed() { + newp := vp + etp = eface.Type + vp = unsafe.Pointer(&newp) + } + + dec, err := findOrCompile(etp) + if err != nil { + return err + } + + return dec.FromDom(vp, node, ctx) +} + +type ifaceDecoder struct { + typ *rt.GoType +} + +func (d *ifaceDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*unsafe.Pointer)(vp) = nil + return nil + } + + iface := *(*rt.GoIface)(vp) + if iface.Itab == nil { + return error_type(d.typ) + } + + vt := iface.Itab.Vt + + // not pointer type, or nil pointer, or *interface{} + if vp == nil || vt.Kind() != reflect.Ptr || rt.PtrElem(vt) == anyType { + ret, err := node.AsEface(ctx) + if err != nil { + return err + } + + *(*interface{})(vp) = ret + return nil + } + + + etp := rt.PtrElem(vt) + vp = iface.Value + + /* check the defined pointer type for issue 379 */ + if vt.IsNamed() { + newp := vp + etp = vt + vp = unsafe.Pointer(&newp) + } + + dec, err := findOrCompile(etp) + if err != nil { + return err + } + + return dec.FromDom(vp, node, ctx) +} + +type unmarshalTextDecoder struct { + typ *rt.GoType +} + +func (d *unmarshalTextDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*unsafe.Pointer)(vp) = nil + return nil + } + + txt, ok := node.AsStringText(ctx) + if !ok { + return error_mismatch(node, ctx, d.typ.Pack()) + } + + v := *(*interface{})(unsafe.Pointer(&rt.GoEface{ + Type: d.typ, + Value: vp, + })) + + // fast path + if u, ok := v.(encoding.TextUnmarshaler); ok { + return u.UnmarshalText(txt) + } + + // slow path + rv := reflect.ValueOf(v) + if u, ok := rv.Interface().(encoding.TextUnmarshaler); ok { + return u.UnmarshalText(txt) + } + + return error_type(d.typ) +} + +type unmarshalJSONDecoder struct { + typ *rt.GoType + strOpt bool +} + +func (d *unmarshalJSONDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + v := *(*interface{})(unsafe.Pointer(&rt.GoEface{ + Type: d.typ, + Value: vp, + })) + + var input []byte + if d.strOpt && node.IsNull() { + input = []byte("null") + } else if d.strOpt { + s, ok := node.AsStringText(ctx) + if !ok { + return error_mismatch(node, ctx, d.typ.Pack()) + } + input = s + } else { + input = []byte(node.AsRaw(ctx)) + } + + // fast path + if u, ok := v.(json.Unmarshaler); ok { + return u.UnmarshalJSON((input)) + } + + // slow path + rv := reflect.ValueOf(v) + if u, ok := rv.Interface().(json.Unmarshaler); ok { + return u.UnmarshalJSON(input) + } + + return error_type(d.typ) +} diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/map.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/map.go new file mode 100644 index 000000000..1a2bda8f3 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/map.go @@ -0,0 +1,430 @@ +package optdec + +import ( + "encoding" + "encoding/json" + "math" + "reflect" + "unsafe" + + "github.com/bytedance/sonic/internal/rt" +) + +/** Decoder for most common map types: map[string]interface{}, map[string]string **/ + +type mapEfaceDecoder struct { +} + +func (d *mapEfaceDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*map[string]interface{})(vp) = nil + return nil + } + + return node.AsMapEface(ctx, vp) +} + +type mapStringDecoder struct { +} + +func (d *mapStringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*map[string]string)(vp) = nil + return nil + } + + return node.AsMapString(ctx, vp) +} + +/** Decoder for map with string key **/ + +type mapStrKeyDecoder struct { + mapType *rt.GoMapType + elemDec decFunc + assign rt.MapStrAssign + typ reflect.Type +} + +func (d *mapStrKeyDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*unsafe.Pointer)(vp) = nil + return nil + } + + obj, ok := node.AsObj() + if !ok { + return error_mismatch(node, ctx, d.mapType.Pack()) + } + + // allocate map + m := *(*unsafe.Pointer)(vp) + if m == nil { + m = rt.Makemap(&d.mapType.GoType, obj.Len()) + } + + var gerr error + next := obj.Children() + for i := 0; i < obj.Len(); i++ { + keyn := NewNode(next) + key, _ := keyn.AsStr(ctx) + + valn := NewNode(PtrOffset(next, 1)) + valp := d.assign(d.mapType, m, key) + err := d.elemDec.FromDom(valp, valn, ctx) + if gerr == nil && err != nil { + gerr = err + } + next = valn.Next() + } + + *(*unsafe.Pointer)(vp) = m + return gerr +} + +/** Decoder for map with int32 or int64 key **/ + +type mapI32KeyDecoder struct { + mapType *rt.GoMapType + elemDec decFunc + assign rt.Map32Assign +} + +func (d *mapI32KeyDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*unsafe.Pointer)(vp) = nil + return nil + } + + obj, ok := node.AsObj() + if !ok { + return error_mismatch(node, ctx, d.mapType.Pack()) + } + + // allocate map + m := *(*unsafe.Pointer)(vp) + if m == nil { + m = rt.Makemap(&d.mapType.GoType, obj.Len()) + } + + next := obj.Children() + var gerr error + for i := 0; i < obj.Len(); i++ { + keyn := NewNode(next) + k, ok := keyn.ParseI64(ctx) + if !ok || k > math.MaxInt32 || k < math.MinInt32 { + if gerr == nil { + gerr = error_mismatch(keyn, ctx, d.mapType.Pack()) + } + valn := NewNode(PtrOffset(next, 1)) + next = valn.Next() + continue + } + + key := int32(k) + ku32 := *(*uint32)(unsafe.Pointer(&key)) + valn := NewNode(PtrOffset(next, 1)) + valp := d.assign(d.mapType, m, ku32) + err := d.elemDec.FromDom(valp, valn, ctx) + if gerr == nil && err != nil { + gerr = err + } + + next = valn.Next() + } + + *(*unsafe.Pointer)(vp) = m + return gerr +} + +type mapI64KeyDecoder struct { + mapType *rt.GoMapType + elemDec decFunc + assign rt.Map64Assign +} + +func (d *mapI64KeyDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*unsafe.Pointer)(vp) = nil + return nil + } + + obj, ok := node.AsObj() + if !ok { + return error_mismatch(node, ctx, d.mapType.Pack()) + } + + // allocate map + m := *(*unsafe.Pointer)(vp) + if m == nil { + m = rt.Makemap(&d.mapType.GoType, obj.Len()) + } + + var gerr error + next := obj.Children() + for i := 0; i < obj.Len(); i++ { + keyn := NewNode(next) + key, ok := keyn.ParseI64(ctx) + + if !ok { + if gerr == nil { + gerr = error_mismatch(keyn, ctx, d.mapType.Pack()) + } + valn := NewNode(PtrOffset(next, 1)) + next = valn.Next() + continue + } + + ku64 := *(*uint64)(unsafe.Pointer(&key)) + valn := NewNode(PtrOffset(next, 1)) + valp := d.assign(d.mapType, m, ku64) + err := d.elemDec.FromDom(valp, valn, ctx) + if gerr == nil && err != nil { + gerr = err + } + next = valn.Next() + } + + *(*unsafe.Pointer)(vp) = m + return gerr +} + +/** Decoder for map with unt32 or uint64 key **/ + +type mapU32KeyDecoder struct { + mapType *rt.GoMapType + elemDec decFunc + assign rt.Map32Assign +} + +func (d *mapU32KeyDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*unsafe.Pointer)(vp) = nil + return nil + } + + obj, ok := node.AsObj() + if !ok { + return error_mismatch(node, ctx, d.mapType.Pack()) + } + + // allocate map + m := *(*unsafe.Pointer)(vp) + if m == nil { + m = rt.Makemap(&d.mapType.GoType, obj.Len()) + } + + var gerr error + next := obj.Children() + for i := 0; i < obj.Len(); i++ { + keyn := NewNode(next) + k, ok := keyn.ParseU64(ctx) + if !ok || k > math.MaxUint32 { + if gerr == nil { + gerr = error_mismatch(keyn, ctx, d.mapType.Pack()) + } + valn := NewNode(PtrOffset(next, 1)) + next = valn.Next() + continue + } + + key := uint32(k) + valn := NewNode(PtrOffset(next, 1)) + valp := d.assign(d.mapType, m, key) + err := d.elemDec.FromDom(valp, valn, ctx) + if gerr == nil && err != nil { + gerr = err + } + next = valn.Next() + } + + *(*unsafe.Pointer)(vp) = m + return gerr +} + +type mapU64KeyDecoder struct { + mapType *rt.GoMapType + elemDec decFunc + assign rt.Map64Assign +} + +func (d *mapU64KeyDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*unsafe.Pointer)(vp) = nil + return nil + } + + obj, ok := node.AsObj() + if !ok { + return error_mismatch(node, ctx, d.mapType.Pack()) + } + // allocate map + m := *(*unsafe.Pointer)(vp) + if m == nil { + m = rt.Makemap(&d.mapType.GoType, obj.Len()) + } + + var gerr error + next := obj.Children() + for i := 0; i < obj.Len(); i++ { + keyn := NewNode(next) + key, ok := keyn.ParseU64(ctx) + if !ok { + if gerr == nil { + gerr = error_mismatch(keyn, ctx, d.mapType.Pack()) + } + valn := NewNode(PtrOffset(next, 1)) + next = valn.Next() + continue + } + + valn := NewNode(PtrOffset(next, 1)) + valp := d.assign(d.mapType, m, key) + err := d.elemDec.FromDom(valp, valn, ctx) + if gerr == nil && err != nil { + gerr = err + } + next = valn.Next() + } + + *(*unsafe.Pointer)(vp) = m + return gerr +} + +/** Decoder for generic cases */ + +type decKey func(dec *mapDecoder, raw string, ctx *context) (interface{}, error) + +func decodeKeyU8(dec *mapDecoder, raw string, ctx *context) (interface{}, error) { + key, err := Unquote(raw) + if err != nil { + return nil, err + } + ret, err := ParseU64(key) + if err != nil { + return nil, err + } + if ret > math.MaxUint8 { + return nil, error_value(key, dec.mapType.Key.Pack()) + } + return uint8(ret), nil +} + +func decodeKeyU16(dec *mapDecoder, raw string, ctx *context) (interface{}, error) { + key, err := Unquote(raw) + if err != nil { + return nil, err + } + ret, err := ParseU64(key) + if err != nil { + return nil, err + } + if ret > math.MaxUint16 { + return nil, error_value(key, dec.mapType.Key.Pack()) + } + return uint16(ret), nil +} + +func decodeKeyI8(dec *mapDecoder, raw string, ctx *context) (interface{}, error) { + key, err := Unquote(raw) + if err != nil { + return nil, err + } + ret, err := ParseI64(key) + if err != nil { + return nil, err + } + if ret > math.MaxInt8 || ret < math.MinInt8 { + return nil, error_value(key, dec.mapType.Key.Pack()) + } + return int8(ret), nil +} + +func decodeKeyI16(dec *mapDecoder, raw string, ctx *context) (interface{}, error) { + key, err := Unquote(raw) + if err != nil { + return nil, err + } + ret, err := ParseI64(key) + if err != nil { + return nil, err + } + if ret > math.MaxInt16 || ret < math.MinInt16 { + return nil, error_value(key, dec.mapType.Key.Pack()) + } + return int16(ret), nil +} + +func decodeKeyJSONUnmarshaler(dec *mapDecoder, raw string, _ *context) (interface{}, error) { + ret := reflect.New(dec.mapType.Key.Pack()).Interface() + err := ret.(json.Unmarshaler).UnmarshalJSON([]byte(raw)) + if err != nil { + return nil, err + } + return ret, nil +} + +func decodeKeyTextUnmarshaler(dec *mapDecoder, raw string, ctx *context) (interface{}, error) { + key, err := Unquote(raw) + if err != nil { + return nil, err + } + ret := reflect.New(dec.mapType.Key.Pack()).Interface() + err = ret.(encoding.TextUnmarshaler).UnmarshalText([]byte(key)) + if err != nil { + return nil, err + } + return ret, nil +} + +type mapDecoder struct { + mapType *rt.GoMapType + keyDec decKey + elemDec decFunc +} + +func (d *mapDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*unsafe.Pointer)(vp) = nil + return nil + } + + obj, ok := node.AsObj() + if !ok { + return error_mismatch(node, ctx, d.mapType.Pack()) + } + + // allocate map + m := *(*unsafe.Pointer)(vp) + if m == nil { + m = rt.Makemap(&d.mapType.GoType, obj.Len()) + } + + next := obj.Children() + var gerr error + for i := 0; i < obj.Len(); i++ { + keyn := NewNode(next) + raw := keyn.AsRaw(ctx) + key, err := d.keyDec(d, raw, ctx) + if err != nil { + if gerr == nil { + gerr = error_mismatch(keyn, ctx, d.mapType.Pack()) + } + valn := NewNode(PtrOffset(next, 1)) + next = valn.Next() + continue + } + + valn := NewNode(PtrOffset(next, 1)) + keyp := rt.UnpackEface(key).Value + valp := rt.Mapassign(d.mapType, m, keyp) + err = d.elemDec.FromDom(valp, valn, ctx) + if gerr == nil && err != nil { + gerr = err + } + + next = valn.Next() + } + + *(*unsafe.Pointer)(vp) = m + return gerr +} diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/native.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/native.go new file mode 100644 index 000000000..29a0136ae --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/native.go @@ -0,0 +1,269 @@ +package optdec + +import ( + "fmt" + "reflect" + "unsafe" + + "sync" + + "github.com/bytedance/sonic/internal/native" + "github.com/bytedance/sonic/internal/native/types" + "github.com/bytedance/sonic/internal/rt" + "github.com/bytedance/sonic/utf8" +) + + +type ErrorCode int + +const ( + SONIC_OK = 0; + SONIC_CONTROL_CHAR = 1; + SONIC_INVALID_ESCAPED = 2; + SONIC_INVALID_NUM = 3; + SONIC_FLOAT_INF = 4; + SONIC_EOF = 5; + SONIC_INVALID_CHAR = 6; + SONIC_EXPECT_KEY = 7; + SONIC_EXPECT_COLON = 8; + SONIC_EXPECT_OBJ_COMMA_OR_END = 9; + SONIC_EXPECT_ARR_COMMA_OR_END = 10; + SONIC_VISIT_FAILED = 11; + SONIC_INVALID_ESCAPED_UTF = 12; + SONIC_INVALID_LITERAL = 13; + SONIC_STACK_OVERFLOW = 14; +) + +var ParsingErrors = []string{ + SONIC_OK : "ok", + SONIC_CONTROL_CHAR : "control chars in string", + SONIC_INVALID_ESCAPED : "invalid escaped chars in string", + SONIC_INVALID_NUM : "invalid number", + SONIC_FLOAT_INF : "float infinity", + SONIC_EOF : "eof", + SONIC_INVALID_CHAR : "invalid chars", + SONIC_EXPECT_KEY : "expect a json key", + SONIC_EXPECT_COLON : "expect a `:`", + SONIC_EXPECT_OBJ_COMMA_OR_END : "expect a `,` or `}`", + SONIC_EXPECT_ARR_COMMA_OR_END : "expect a `,` or `]`", + SONIC_VISIT_FAILED : "failed in json visitor", + SONIC_INVALID_ESCAPED_UTF : "invalid escaped unicodes", + SONIC_INVALID_LITERAL : "invalid literal(true/false/null)", + SONIC_STACK_OVERFLOW : "json is exceeded max depth 4096, cause stack overflow", +} + +func (code ErrorCode) Error() string { + return ParsingErrors[code] +} + +type node struct { + typ uint64 + val uint64 +} + +// should consitent with native/parser.c +type _nospaceBlock struct { + _ [8]byte + _ [8]byte +} + +// should consitent with native/parser.c +type nodeBuf struct { + ncur uintptr + parent int64 + depth uint64 + nstart uintptr + nend uintptr + stat jsonStat +} + +func (self *nodeBuf) init(nodes []node) { + self.ncur = uintptr(unsafe.Pointer(&nodes[0])) + self.nstart = self.ncur + self.nend = self.ncur + uintptr(cap(nodes)) * unsafe.Sizeof(node{}) + self.parent = -1 +} + +// should consitent with native/parser.c +type Parser struct { + Json string + padded []byte + nodes []node + dbuf []byte + backup []node + + options uint64 + // JSON cursor + start uintptr + cur uintptr + end uintptr + _nbk _nospaceBlock + + // node buffer cursor + nbuf nodeBuf + Utf8Inv bool + isEface bool +} + +// only when parse non-empty object/array are needed. +type jsonStat struct { + object uint32 + array uint32 + str uint32 + number uint32 + array_elems uint32 + object_keys uint32 + max_depth uint32 +} + + +var ( + defaultJsonPaddedCap uintptr = 1 << 20 // 1 Mb + defaultNodesCap uintptr = (1 << 20) / unsafe.Sizeof(node{}) // 1 Mb +) + +var parsePool sync.Pool = sync.Pool { + New: func () interface{} { + return &Parser{ + options: 0, + padded: make([]byte, 0, defaultJsonPaddedCap), + nodes: make([]node, defaultNodesCap, defaultNodesCap), + dbuf: make([]byte, types.MaxDigitNums, types.MaxDigitNums), + } + }, +} + +var padding string = "x\"x\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + +func newParser(data string, pos int, opt uint64) *Parser { + p := parsePool.Get().(*Parser) + + /* validate json if needed */ + if (opt & (1 << _F_validate_string)) != 0 && !utf8.ValidateString(data){ + dbuf := utf8.CorrectWith(nil, rt.Str2Mem(data[pos:]), "\ufffd") + dbuf = append(dbuf, padding...) + p.Json = rt.Mem2Str(dbuf[:len(dbuf) - len(padding)]) + p.Utf8Inv = true + p.start = uintptr((*rt.GoString)(unsafe.Pointer(&p.Json)).Ptr) + } else { + p.Json = data + // TODO: prevent too large JSON + p.padded = append(p.padded, data[pos:]...) + p.padded = append(p.padded, padding...) + p.start = uintptr((*rt.GoSlice)(unsafe.Pointer(&p.padded)).Ptr) + } + + p.cur = p.start + p.end = p.cur + uintptr(len(p.Json)) + p.options = opt + p.nbuf.init(p.nodes) + return p +} + + +func (p *Parser) Pos() int { + return int(p.cur - p.start) +} + +func (p *Parser) JsonBytes() []byte { + if p.Utf8Inv { + return (rt.Str2Mem(p.Json)) + } else { + return p.padded + } +} + +var nodeType = rt.UnpackType(reflect.TypeOf(node{})) + +//go:inline +func calMaxNodeCap(jsonSize int) int { + return jsonSize / 2 + 2 +} + +func (p *Parser) parse() ErrorCode { + // when decode into struct, we should decode number as possible + old := p.options + if !p.isEface { + p.options &^= 1 << _F_use_number + } + + // fast path with limited node buffer + err := ErrorCode(native.ParseWithPadding(unsafe.Pointer(p))) + if err != SONIC_VISIT_FAILED { + p.options = old + return err + } + + // check OoB here + offset := p.nbuf.ncur - p.nbuf.nstart + curLen := offset / unsafe.Sizeof(node{}) + if curLen != uintptr(len(p.nodes)) { + panic(fmt.Sprintf("current len: %d, real len: %d cap: %d", curLen, len(p.nodes), cap(p.nodes))) + } + + // node buf is not enough, continue parse + // the maxCap is always meet all valid JSON + maxCap := calMaxNodeCap(len(p.Json)) + slice := rt.GoSlice{ + Ptr: rt.Mallocgc(uintptr(maxCap) * nodeType.Size, nodeType, false), + Len: maxCap, + Cap: maxCap, + } + rt.Memmove(unsafe.Pointer(slice.Ptr), unsafe.Pointer(&p.nodes[0]), offset) + p.backup = p.nodes + p.nodes = *(*[]node)(unsafe.Pointer(&slice)) + + // update node cursor + p.nbuf.nstart = uintptr(unsafe.Pointer(&p.nodes[0])) + p.nbuf.nend = p.nbuf.nstart + uintptr(cap(p.nodes)) * unsafe.Sizeof(node{}) + p.nbuf.ncur = p.nbuf.nstart + offset + + // continue parse json + err = ErrorCode(native.ParseWithPadding(unsafe.Pointer(p))) + p.options = old + return err +} + +func (p *Parser) reset() { + p.options = 0 + p.padded = p.padded[:0] + // nodes is too large here, we will not reset it and use small backup nodes buffer + if p.backup != nil { + p.nodes = p.backup + p.backup = nil + } + p.start = 0 + p.cur = 0 + p.end = 0 + p.Json = "" + p.nbuf = nodeBuf{} + p._nbk = _nospaceBlock{} + p.Utf8Inv = false + p.isEface = false +} + +func (p *Parser) free() { + p.reset() + parsePool.Put(p) +} + +//go:noinline +func (p *Parser) fixError(code ErrorCode) error { + if code == SONIC_OK { + return nil + } + + if p.Pos() == 0 { + code = SONIC_EOF; + } + + pos := p.Pos() - 1 + return error_syntax(pos, p.Json, ParsingErrors[code]) +} + +func Parse(data string, opt uint64) error { + p := newParser(data, 0, opt) + err := p.parse() + p.free() + return err +} diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/node.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/node.go new file mode 100644 index 000000000..8b49ebb3a --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/node.go @@ -0,0 +1,1279 @@ +package optdec + +import ( + "encoding/json" + "math" + "unsafe" + + "github.com/bytedance/sonic/internal/envs" + "github.com/bytedance/sonic/internal/rt" +) + +type Context struct { + Parser *Parser + efacePool *efacePool + Stack bounedStack + Utf8Inv bool +} + +func (ctx *Context) Options() uint64 { + return ctx.Parser.options +} + +/************************* Stack and Pool Helper *******************/ + +type parentStat struct { + con unsafe.Pointer + remain uint64 +} +type bounedStack struct { + stack []parentStat + index int +} + +func newStack(size int) bounedStack { + return bounedStack{ + stack: make([]parentStat, size + 2), + index: 0, + } +} + +//go:nosplit +func (s *bounedStack) Pop() (unsafe.Pointer, int, bool){ + s.index-- + con := s.stack[s.index].con + remain := s.stack[s.index].remain &^ (uint64(1) << 63) + isObj := (s.stack[s.index].remain & (uint64(1) << 63)) != 0 + s.stack[s.index].con = nil + s.stack[s.index].remain = 0 + return con, int(remain), isObj +} + +//go:nosplit +func (s *bounedStack) Push(p unsafe.Pointer, remain int, isObj bool) { + s.stack[s.index].con = p + s.stack[s.index].remain = uint64(remain) + if isObj { + s.stack[s.index].remain |= (uint64(1) << 63) + } + s.index++ +} + +type efacePool struct{ + t64 rt.T64Pool + tslice rt.TslicePool + tstring rt.TstringPool + efaceSlice rt.SlicePool +} + +func newEfacePool(stat *jsonStat, useNumber bool) *efacePool { + strs := int(stat.str) + nums := 0 + if useNumber { + strs += int(stat.number) + } else { + nums = int(stat.number) + } + + return &efacePool{ + t64: rt.NewT64Pool(nums), + tslice: rt.NewTslicePool(int(stat.array)), + tstring: rt.NewTstringPool(strs), + efaceSlice: rt.NewPool(rt.AnyType, int(stat.array_elems)), + } +} + +func (self *efacePool) GetMap(hint int) unsafe.Pointer { + m := make(map[string]interface{}, hint) + return *(*unsafe.Pointer)(unsafe.Pointer(&m)) +} + +func (self *efacePool) GetSlice(hint int) unsafe.Pointer { + return unsafe.Pointer(self.efaceSlice.GetSlice(hint)) +} + +func (self *efacePool) ConvTSlice(val rt.GoSlice, typ *rt.GoType, dst unsafe.Pointer) { + self.tslice.Conv(val, typ, (*interface{})(dst)) +} + +func (self *efacePool) ConvF64(val float64, dst unsafe.Pointer) { + self.t64.Conv(castU64(val), rt.Float64Type, (*interface{})(dst)) +} + +func (self *efacePool) ConvTstring(val string, dst unsafe.Pointer) { + self.tstring.Conv(val, (*interface{})(dst)) +} + +func (self *efacePool) ConvTnum(val json.Number, dst unsafe.Pointer) { + self.tstring.ConvNum(val, (*interface{})(dst)) +} + +/********************************************************/ + +func canUseFastMap( opts uint64, root *rt.GoType) bool { + return envs.UseFastMap && (opts & (1 << _F_copy_string)) == 0 && (opts & (1 << _F_use_int64)) == 0 && (root == rt.AnyType || root == rt.MapEfaceType || root == rt.SliceEfaceType) +} + +func NewContext(json string, pos int, opts uint64, root *rt.GoType) (Context, error) { + ctx := Context{ + Parser: newParser(json, pos, opts), + } + if root == rt.AnyType || root == rt.MapEfaceType || root == rt.SliceEfaceType { + ctx.Parser.isEface = true + } + + ecode := ctx.Parser.parse() + + if ecode != 0 { + return ctx, ctx.Parser.fixError(ecode) + } + + useNumber := (opts & (1 << _F_use_number )) != 0 + if canUseFastMap(opts, root) { + ctx.efacePool = newEfacePool(&ctx.Parser.nbuf.stat, useNumber) + ctx.Stack = newStack(int(ctx.Parser.nbuf.stat.max_depth)) + } + + return ctx, nil +} + +func (ctx *Context) Delete() { + ctx.Parser.free() + ctx.Parser = nil +} + +type Node struct { + cptr uintptr +} + +func NewNode(cptr uintptr) Node { + return Node{cptr: cptr} +} + +type Dom struct { + cdom uintptr +} + +func (ctx *Context) Root() Node { + root := (uintptr)(((*rt.GoSlice)(unsafe.Pointer(&ctx.Parser.nodes))).Ptr) + return Node{cptr: root} +} + +type Array struct { + cptr uintptr +} + +type Object struct { + cptr uintptr +} + +func (obj Object) Len() int { + cobj := ptrCast(obj.cptr) + return int(uint64(cobj.val) & ConLenMask) +} + +func (arr Array) Len() int { + carr := ptrCast(arr.cptr) + return int(uint64(carr.val) & ConLenMask) +} + +// / Helper functions to eliminate CGO calls +func (val Node) Type() uint8 { + ctype := ptrCast(val.cptr) + return uint8(ctype.typ & TypeMask) +} + +func (val Node) Next() uintptr { + if val.Type() != KObject && val.Type() != KArray { + return PtrOffset(val.cptr, 1) + } + cobj := ptrCast(val.cptr) + offset := int64(uint64(cobj.val) >> ConLenBits) + return PtrOffset(val.cptr, offset) +} + +func (val *Node) next() { + *val = NewNode(val.Next()) +} + +type NodeIter struct { + next uintptr +} + +func NewNodeIter(node Node) NodeIter { + return NodeIter{next: node.cptr} +} + +func (iter *NodeIter) Next() Node { + ret := NewNode(iter.next) + iter.next = PtrOffset(iter.next, 1) + return ret +} + + +func (iter *NodeIter) Peek() Node { + return NewNode(iter.next) +} + +func (val Node) U64() uint64 { + cnum := ptrCast(val.cptr) + return *(*uint64)((unsafe.Pointer)(&(cnum.val))) +} + +func (val Node) I64() int64 { + cnum := ptrCast(val.cptr) + return *(*int64)((unsafe.Pointer)(&(cnum.val))) +} + +func (val Node) IsNull() bool { + return val.Type() == KNull +} + +func (val Node) IsNumber() bool { + return val.Type() & KNumber != 0 +} + +func (val Node) F64() float64 { + cnum := ptrCast(val.cptr) + return *(*float64)((unsafe.Pointer)(&(cnum.val))) +} + +func (val Node) Bool() bool { + return val.Type() == KTrue +} + +func (self Node) AsU64(ctx *Context) (uint64, bool) { + if self.Type() == KUint { + return self.U64(), true + } else if self.Type() == KRawNumber { + num, err := ParseU64(self.Raw(ctx)) + if err != nil { + return 0, false + } + return num, true + } else { + return 0, false + } +} + +func (val *Node) AsObj() (Object, bool) { + var ret Object + if val.Type() != KObject { + return ret, false + } + return Object{ + cptr: val.cptr, + }, true +} + +func (val Node) Obj() Object { + return Object{cptr: val.cptr} +} + +func (val Node) Arr() Array { + return Array{cptr: val.cptr} +} + +func (val *Node) AsArr() (Array, bool) { + var ret Array + if val.Type() != KArray { + return ret, false + } + return Array{ + cptr: val.cptr, + }, true +} + +func (self Node) AsI64(ctx *Context) (int64, bool) { + typ := self.Type() + if typ == KUint && self.U64() <= math.MaxInt64 { + return int64(self.U64()), true + } else if typ == KSint { + return self.I64(), true + } else if typ == KRawNumber { + val, err := self.Number(ctx).Int64() + if err != nil { + return 0, false + } + return val, true + } else { + return 0, false + } +} + +/********* Parse Node String into Value ***************/ + +func (val Node) ParseI64(ctx *Context) (int64, bool) { + s, ok := val.AsStrRef(ctx) + if !ok { + return 0, false + } + + if s == "null" { + return 0, true + } + + i, err := ParseI64(s) + if err != nil { + return 0, false + } + return i, true +} + +func (val Node) ParseBool(ctx *Context) (bool, bool) { + s, ok := val.AsStrRef(ctx) + if !ok { + return false, false + } + + if s == "null" { + return false, true + } + + b, err := ParseBool(s) + if err != nil { + return false, false + } + return b, true +} + +func (val Node) ParseU64(ctx *Context) (uint64, bool) { + s, ok := val.AsStrRef(ctx) + if !ok { + return 0, false + } + + if s == "null" { + return 0, true + } + + i, err := ParseU64(s) + if err != nil { + return 0, false + } + return i, true +} + +func (val Node) ParseF64(ctx *Context) (float64, bool) { + s, ok := val.AsStrRef(ctx) + if !ok { + return 0, false + } + + if s == "null" { + return 0, true + } + + i, err := ParseF64(s) + if err != nil { + return 0, false + } + return i, true +} + +func (val Node) ParseString(ctx *Context) (string, bool) { + // shoud not use AsStrRef + s, ok := val.AsStr(ctx) + if !ok { + return "", false + } + + if s == "null" { + return "", true + } + + s, err := Unquote(s) + if err != nil { + return "", false + } + return s, true +} + + +func (val Node) ParseNumber(ctx *Context) (json.Number, bool) { + // shoud not use AsStrRef + s, ok := val.AsStr(ctx) + if !ok { + return json.Number(""), false + } + + if s == "null" { + return json.Number(""), true + } + + end, err := SkipNumberFast(s, 0) + // has error or trailing chars + if err != nil || end != len(s) { + return json.Number(""), false + } + return json.Number(s), true +} + + + +func (val Node) AsF64(ctx *Context) (float64, bool) { + switch val.Type() { + case KUint: return float64(val.U64()), true + case KSint: return float64(val.I64()), true + case KReal: return float64(val.F64()), true + case KRawNumber: f, err := val.Number(ctx).Float64(); return f, err == nil + default: return 0, false + } +} + +func (val Node) AsBool() (bool, bool) { + switch val.Type() { + case KTrue: return true, true + case KFalse: return false, true + default: return false, false + } +} + +func (val Node) AsStr(ctx *Context) (string, bool) { + switch val.Type() { + case KStringCommon: + s := val.StringRef(ctx) + if (ctx.Options() & (1 << _F_copy_string) == 0) { + return s, true + } + return string(rt.Str2Mem(s)), true + case KStringEscaped: + return val.StringCopyEsc(ctx), true + default: return "", false + } +} + +func (val Node) AsStrRef(ctx *Context) (string, bool) { + switch val.Type() { + case KStringEscaped: + node := ptrCast(val.cptr) + offset := val.Position() + len := int(node.val) + return rt.Mem2Str(ctx.Parser.JsonBytes()[offset : offset + len]), true + case KStringCommon: + return val.StringRef(ctx), true + default: + return "", false + } +} + +func (val Node) AsBytesRef(ctx *Context) ([]byte, bool) { + switch val.Type() { + case KStringEscaped: + node := ptrCast(val.cptr) + offset := val.Position() + len := int(node.val) + return ctx.Parser.JsonBytes()[offset : offset + len], true + case KStringCommon: + return rt.Str2Mem(val.StringRef(ctx)), true + default: + return nil, false + } +} + +func (val Node) AsStringText(ctx *Context) ([]byte, bool) { + if !val.IsStr() { + return nil, false + } + + // clone to new bytes + s, b := val.AsStrRef(ctx) + return []byte(s), b +} + +func (val Node) IsStr() bool { + return (val.Type() == KStringCommon) || (val.Type() == KStringEscaped) +} + +func (val Node) IsRawNumber() bool { + return val.Type() == KRawNumber +} + +func (val Node) Number(ctx *Context) json.Number { + return json.Number(val.Raw(ctx)) +} + +func (val Node) Raw(ctx *Context) string { + node := ptrCast(val.cptr) + len := int(node.val) + offset := val.Position() + return ctx.Parser.Json[offset:int(offset+len)] +} + +func (val Node) Position() int { + node := ptrCast(val.cptr) + return int(node.typ >> PosBits) +} + +func (val Node) AsNumber(ctx *Context) (json.Number, bool) { + // parse JSON string as number + if val.IsStr() { + s, _ := val.AsStr(ctx) + err := ValidNumberFast(s) + if err != nil { + return "", false + } + + return json.Number(s), true + } + + return val.NonstrAsNumber(ctx) +} + +func (val Node) NonstrAsNumber(ctx *Context) (json.Number, bool) { + // deal with raw number + if val.IsRawNumber() { + return val.Number(ctx), true + } + + // deal with parse number + if !val.IsNumber() { + return json.Number(""), false + } + + start := val.Position() + end, err := SkipNumberFast(ctx.Parser.Json, start) + if err != nil { + return "", false + } + return json.Number(ctx.Parser.Json[start:end]), true +} + +func (val Node) AsRaw(ctx *Context) string { + // fast path for unescaped strings + switch val.Type() { + case KNull: + return "null" + case KTrue: + return "true" + case KFalse: + return "false" + case KStringCommon: + node := ptrCast(val.cptr) + len := int(node.val) + offset := val.Position() + // add start abd end quote + ref := rt.Str2Mem(ctx.Parser.Json)[offset-1 : offset+len+1] + return rt.Mem2Str(ref) + case KRawNumber: fallthrough + case KRaw: return val.Raw(ctx) + case KStringEscaped: + raw, _ := SkipOneFast(ctx.Parser.Json, val.Position() - 1) + return raw + default: + raw, err := SkipOneFast(ctx.Parser.Json, val.Position()) + if err != nil { + break + } + return raw + } + panic("should always be valid json here") +} + +// reference from the input JSON as possible +func (val Node) StringRef(ctx *Context) string { + return val.Raw(ctx) +} + +//go:nocheckptr +func ptrCast(p uintptr) *node { + return (*node)(unsafe.Pointer(p)) +} + +func (val Node) StringCopyEsc(ctx *Context) string { + // check whether there are in padded + node := ptrCast(val.cptr) + len := int(node.val) + offset := val.Position() + return string(ctx.Parser.JsonBytes()[offset : offset + len]) +} + +func (val Node) Object() Object { + return Object{cptr: val.cptr} +} + +func (val Node) Array() Array { + return Array{cptr: val.cptr} +} + +func (val *Array) Children() uintptr { + return PtrOffset(val.cptr, 1) +} + +func (val *Object) Children() uintptr { + return PtrOffset(val.cptr, 1) +} + +func (val *Node) Equal(ctx *Context, lhs string) bool { + // check whether escaped + cstr := ptrCast(val.cptr) + offset := int(val.Position()) + len := int(cstr.val) + return lhs == ctx.Parser.Json[offset:offset+len] +} + +func (node *Node) AsMapEface(ctx *Context, vp unsafe.Pointer) error { + if node.IsNull() { + return nil + } + + obj, ok := node.AsObj() + if !ok { + return newUnmatched(node.Position(), rt.MapEfaceType) + } + + var err, gerr error + size := obj.Len() + + var m map[string]interface{} + if *(*unsafe.Pointer)(vp) == nil { + if ctx.efacePool != nil { + p := ctx.efacePool.GetMap(size) + m = *(*map[string]interface{})(unsafe.Pointer(&p)) + } else { + m = make(map[string]interface{}, size) + } + } else { + m = *(*map[string]interface{})(vp) + } + + next := obj.Children() + for i := 0; i < size; i++ { + knode := NewNode(next) + key, _ := knode.AsStr(ctx) + val := NewNode(PtrOffset(next, 1)) + m[key], err = val.AsEface(ctx) + next = val.cptr + if gerr == nil && err != nil { + gerr = err + } + } + + *(*map[string]interface{})(vp) = m + return gerr +} + +func (node *Node) AsMapString(ctx *Context, vp unsafe.Pointer) error { + obj, ok := node.AsObj() + if !ok { + return newUnmatched(node.Position(), rt.MapStringType) + } + + size := obj.Len() + + var m map[string]string + if *(*unsafe.Pointer)(vp) == nil { + m = make(map[string]string, size) + } else { + m = *(*map[string]string)(vp) + } + + var gerr error + next := obj.Children() + for i := 0; i < size; i++ { + knode := NewNode(next) + key, _ := knode.AsStr(ctx) + val := NewNode(PtrOffset(next, 1)) + m[key], ok = val.AsStr(ctx) + if !ok { + if gerr == nil { + gerr = newUnmatched(val.Position(), rt.StringType) + } + next = val.Next() + } else { + next = PtrOffset(val.cptr, 1) + } + } + + *(*map[string]string)(vp) = m + return gerr +} + +func (node *Node) AsSliceEface(ctx *Context, vp unsafe.Pointer) error { + arr, ok := node.AsArr() + if !ok { + return newUnmatched(node.Position(), rt.SliceEfaceType) + } + + size := arr.Len() + var s []interface{} + if size != 0 && ctx.efacePool != nil { + slice := rt.GoSlice { + Ptr: ctx.efacePool.GetSlice(size), + Len: size, + Cap: size, + } + *(*rt.GoSlice)(unsafe.Pointer(&s)) = slice + } else { + s = *(*[]interface{})((unsafe.Pointer)(rt.MakeSlice(vp, rt.AnyType, size))) + } + + *node = NewNode(arr.Children()) + + var err, gerr error + for i := 0; i < size; i++ { + s[i], err = node.AsEface(ctx) + if gerr == nil && err != nil { + gerr = err + } + } + + *(*[]interface{})(vp) = s + return nil +} + +func (node *Node) AsSliceI32(ctx *Context, vp unsafe.Pointer) error { + arr, ok := node.AsArr() + if !ok { + return newUnmatched(node.Position(), rt.SliceI32Type) + } + + size := arr.Len() + s := *(*[]int32)((unsafe.Pointer)(rt.MakeSlice(vp, rt.Int32Type, size))) + next := arr.Children() + + var gerr error + for i := 0; i < size; i++ { + val := NewNode(next) + ret, ok := val.AsI64(ctx) + if !ok || ret > math.MaxInt32 || ret < math.MinInt32 { + if gerr == nil { + gerr = newUnmatched(val.Position(), rt.Int32Type) + } + next = val.Next() + } else { + s[i] = int32(ret) + next = PtrOffset(val.cptr, 1) + } + } + + *(*[]int32)(vp) = s + return gerr +} + +func (node *Node) AsSliceI64(ctx *Context, vp unsafe.Pointer) error { + arr, ok := node.AsArr() + if !ok { + return newUnmatched(node.Position(), rt.SliceI64Type) + } + + size := arr.Len() + s := *(*[]int64)((unsafe.Pointer)(rt.MakeSlice(vp, rt.Int64Type, size))) + next := arr.Children() + + var gerr error + for i := 0; i < size; i++ { + val := NewNode(next) + + ret, ok := val.AsI64(ctx) + if !ok { + if gerr == nil { + gerr = newUnmatched(val.Position(), rt.Int64Type) + } + next = val.Next() + } else { + s[i] = ret + next = PtrOffset(val.cptr, 1) + } + } + + *(*[]int64)(vp) = s + return gerr +} + +func (node *Node) AsSliceU32(ctx *Context, vp unsafe.Pointer) error { + arr, ok := node.AsArr() + if !ok { + return newUnmatched(node.Position(), rt.SliceU32Type) + } + + size := arr.Len() + next := arr.Children() + s := *(*[]uint32)((unsafe.Pointer)(rt.MakeSlice(vp, rt.Uint32Type, size))) + + var gerr error + for i := 0; i < size; i++ { + val := NewNode(next) + ret, ok := val.AsU64(ctx) + if !ok || ret > math.MaxUint32 { + if gerr == nil { + gerr = newUnmatched(val.Position(), rt.Uint32Type) + } + next = val.Next() + } else { + s[i] = uint32(ret) + next = PtrOffset(val.cptr, 1) + } + } + + *(*[]uint32)(vp) = s + return gerr +} + +func (node *Node) AsSliceU64(ctx *Context, vp unsafe.Pointer) error { + arr, ok := node.AsArr() + if !ok { + return newUnmatched(node.Position(), rt.SliceU64Type) + } + + size := arr.Len() + next := arr.Children() + + s := *(*[]uint64)((unsafe.Pointer)(rt.MakeSlice(vp, rt.Uint64Type, size))) + var gerr error + for i := 0; i < size; i++ { + val := NewNode(next) + ret, ok := val.AsU64(ctx) + if !ok { + if gerr == nil { + gerr = newUnmatched(val.Position(), rt.Uint64Type) + } + next = val.Next() + } else { + s[i] = ret + next = PtrOffset(val.cptr, 1) + } + } + + *(*[]uint64)(vp) = s + return gerr +} + +func (node *Node) AsSliceString(ctx *Context, vp unsafe.Pointer) error { + arr, ok := node.AsArr() + if !ok { + return newUnmatched(node.Position(), rt.SliceStringType) + } + + size := arr.Len() + next := arr.Children() + s := *(*[]string)((unsafe.Pointer)(rt.MakeSlice(vp, rt.StringType, size))) + + var gerr error + for i := 0; i < size; i++ { + val := NewNode(next) + ret, ok := val.AsStr(ctx) + if !ok { + if gerr == nil { + gerr = newUnmatched(val.Position(), rt.StringType) + } + next = val.Next() + } else { + s[i] = ret + next = PtrOffset(val.cptr, 1) + } + } + + *(*[]string)(vp) = s + return gerr +} + +func (node *Node) AsSliceBytes(ctx *Context) ([]byte, error) { + b, ok := node.AsBytesRef(ctx) + if !ok { + return nil, newUnmatched(node.Position(), rt.BytesType) + } + + b64, err := rt.DecodeBase64(b) + if err != nil { + return nil, newUnmatched(node.Position(), rt.BytesType) + } + return b64, nil +} + +// AsEface will always ok, because we have parse in native. +func (node *Node) AsEface(ctx *Context) (interface{}, error) { + if ctx.efacePool != nil { + iter := NewNodeIter(*node) + v := AsEfaceFast(&iter, ctx) + *node = iter.Peek() + return v, nil + } else { + return node.AsEfaceFallback(ctx) + } +} + +func parseSingleNode(node Node, ctx *Context) interface{} { + var v interface{} + switch node.Type() { + case KObject: v = map[string]interface{}{} + case KArray: v = []interface{}{} + case KStringCommon: v = node.StringRef(ctx) + case KStringEscaped: v = node.StringCopyEsc(ctx) + case KTrue: v = true + case KFalse: v = false + case KNull: v = nil + case KUint: v = float64(node.U64()) + case KSint: v = float64(node.I64()) + case KReal: v = float64(node.F64()) + case KRawNumber: v = node.Number(ctx) + default: panic("unreachable for as eface") + } + return v +} + +func castU64(val float64) uint64 { + return *((*uint64)(unsafe.Pointer((&val)))) +} + +func AsEfaceFast(iter *NodeIter, ctx *Context) interface{} { + var mp, sp, parent unsafe.Pointer // current container pointer + var node Node + var size int + var isObj bool + var slice rt.GoSlice + var val unsafe.Pointer + var vt **rt.GoType + var vp *unsafe.Pointer + var rootM unsafe.Pointer + var rootS rt.GoSlice + var root interface{} + var key string + + node = iter.Next() + + switch node.Type() { + case KObject: + size = node.Object().Len() + if size != 0 { + ctx.Stack.Push(nil, 0, true) + mp = ctx.efacePool.GetMap(size) + rootM = mp + isObj = true + goto _object_key + } else { + return rt.GoEface { + Type: rt.MapEfaceType, + Value: ctx.efacePool.GetMap(0), + }.Pack() + } + case KArray: + size = node.Array().Len() + if size != 0 { + ctx.Stack.Push(nil, 0, false) + sp = ctx.efacePool.GetSlice(size) + slice = rt.GoSlice { + Ptr: sp, + Len: size, + Cap: size, + } + rootS = slice + isObj = false + val = sp + goto _arr_val; + } else { + ctx.efacePool.ConvTSlice(rt.EmptySlice, rt.SliceEfaceType, unsafe.Pointer(&root)) + } + case KStringCommon: ctx.efacePool.ConvTstring(node.StringRef(ctx), unsafe.Pointer(&root)) + case KStringEscaped: ctx.efacePool.ConvTstring(node.StringCopyEsc(ctx), unsafe.Pointer(&root)) + case KTrue: root = true + case KFalse: root = false + case KNull: root = nil + case KUint: ctx.efacePool.ConvF64(float64(node.U64()), unsafe.Pointer(&root)) + case KSint: ctx.efacePool.ConvF64(float64(node.I64()), unsafe.Pointer(&root)) + case KReal: ctx.efacePool.ConvF64(node.F64(), unsafe.Pointer(&root)) + case KRawNumber: ctx.efacePool.ConvTnum(node.Number(ctx), unsafe.Pointer(&root)) + default: panic("unreachable for as eface") + } + return root + +_object_key: + node = iter.Next() + if node.Type() == KStringCommon { + key = node.StringRef(ctx) + } else { + key = node.StringCopyEsc(ctx) + } + + // interface{} slot in map bucket + val = rt.Mapassign_faststr(rt.MapEfaceMapType, mp, key) + vt = &(*rt.GoEface)(val).Type + vp = &(*rt.GoEface)(val).Value + + // parse value node + node = iter.Next() + switch node.Type() { + case KObject: + newSize := node.Object().Len() + newMp := ctx.efacePool.GetMap(newSize) + *vt = rt.MapEfaceType + *vp = newMp + remain := size - 1 + isObj = true + if newSize != 0 { + if remain > 0 { + ctx.Stack.Push(mp, remain, true) + } + mp = newMp + size = newSize + goto _object_key; + } + case KArray: + newSize := node.Array().Len() + if newSize == 0 { + ctx.efacePool.ConvTSlice(rt.EmptySlice, rt.SliceEfaceType, val) + break; + } + + newSp := ctx.efacePool.GetSlice(newSize) + // pack to []interface{} + ctx.efacePool.ConvTSlice(rt.GoSlice{ + Ptr: newSp, + Len: newSize, + Cap: newSize, + }, rt.SliceEfaceType, val) + remain := size - 1 + if remain > 0 { + ctx.Stack.Push(mp, remain, true) + } + val = newSp + isObj = false + size = newSize + goto _arr_val; + case KStringCommon: + ctx.efacePool.ConvTstring(node.StringRef(ctx), val) + case KStringEscaped: + ctx.efacePool.ConvTstring(node.StringCopyEsc(ctx), val) + case KTrue: + rt.ConvTBool(true, (*interface{})(val)) + case KFalse: + rt.ConvTBool(false, (*interface{})(val)) + case KNull: /* skip */ + case KUint: + ctx.efacePool.ConvF64(float64(node.U64()), val) + case KSint: + ctx.efacePool.ConvF64(float64(node.I64()), val) + case KReal: + ctx.efacePool.ConvF64(node.F64(), val) + case KRawNumber: + ctx.efacePool.ConvTnum(node.Number(ctx), val) + default: + panic("unreachable for as eface") + } + + // check size + size -= 1 + if size != 0 { + goto _object_key; + } + + parent, size, isObj = ctx.Stack.Pop() + + // parent is empty + if parent == nil { + if isObj { + return rt.GoEface { + Type: rt.MapEfaceType, + Value: rootM, + }.Pack() + } else { + ctx.efacePool.ConvTSlice(rootS, rt.SliceEfaceType, (unsafe.Pointer)(&root)) + return root + } + } + + // continue to parse parent + if isObj { + mp = parent + goto _object_key; + } else { + val = rt.PtrAdd(parent, rt.AnyType.Size) + goto _arr_val; + } + +_arr_val: + // interface{} slot in slice + vt = &(*rt.GoEface)(val).Type + vp = &(*rt.GoEface)(val).Value + + // parse value node + node = iter.Next() + switch node.Type() { + case KObject: + newSize := node.Object().Len() + newMp := ctx.efacePool.GetMap(newSize) + *vt = rt.MapEfaceType + *vp = newMp + remain := size - 1 + if newSize != 0 { + // push next array elem into stack + if remain > 0 { + ctx.Stack.Push(val, remain, false) + } + mp = newMp + size = newSize + isObj = true + goto _object_key; + } + case KArray: + newSize := node.Array().Len() + if newSize == 0 { + ctx.efacePool.ConvTSlice(rt.EmptySlice, rt.SliceEfaceType, val) + break; + } + + newSp := ctx.efacePool.GetSlice(newSize) + // pack to []interface{} + ctx.efacePool.ConvTSlice(rt.GoSlice { + Ptr: newSp, + Len: newSize, + Cap: newSize, + }, rt.SliceEfaceType, val) + + remain := size - 1 + if remain > 0 { + ctx.Stack.Push(val, remain, false) + } + + val = newSp + isObj = false + size = newSize + goto _arr_val; + case KStringCommon: + ctx.efacePool.ConvTstring(node.StringRef(ctx), val) + case KStringEscaped: + ctx.efacePool.ConvTstring(node.StringCopyEsc(ctx), val) + case KTrue: + rt.ConvTBool(true, (*interface{})(val)) + case KFalse: + rt.ConvTBool(false, (*interface{})(val)) + case KNull: /* skip */ + case KUint: + ctx.efacePool.ConvF64(float64(node.U64()), val) + case KSint: + ctx.efacePool.ConvF64(float64(node.I64()), val) + case KReal: + ctx.efacePool.ConvF64(node.F64(), val) + case KRawNumber: + ctx.efacePool.ConvTnum(node.Number(ctx), val) + default: panic("unreachable for as eface") + } + + // check size + size -= 1 + if size != 0 { + val = rt.PtrAdd(val, rt.AnyType.Size) + goto _arr_val; + } + + + parent, size, isObj = ctx.Stack.Pop() + + // parent is empty + if parent == nil { + if isObj { + return rt.GoEface { + Type: rt.MapEfaceType, + Value: rootM, + }.Pack() + } else { + ctx.efacePool.ConvTSlice(rootS, rt.SliceEfaceType, unsafe.Pointer(&root)) + return root + } + } + + // continue to parse parent + if isObj { + mp = parent + goto _object_key; + } else { + val = rt.PtrAdd(parent, rt.AnyType.Size) + goto _arr_val; + } +} + +func (node *Node) AsEfaceFallback(ctx *Context) (interface{}, error) { + switch node.Type() { + case KObject: + obj := node.Object() + size := obj.Len() + m := make(map[string]interface{}, size) + *node = NewNode(obj.Children()) + var gerr, err error + for i := 0; i < size; i++ { + key, _ := node.AsStr(ctx) + *node = NewNode(PtrOffset(node.cptr, 1)) + m[key], err = node.AsEfaceFallback(ctx) + if gerr == nil && err != nil { + gerr = err + } + } + return m, gerr + case KArray: + arr := node.Array() + size := arr.Len() + a := make([]interface{}, size) + *node = NewNode(arr.Children()) + var gerr, err error + for i := 0; i < size; i++ { + a[i], err = node.AsEfaceFallback(ctx) + if gerr == nil && err != nil { + gerr = err + } + } + return a, gerr + case KStringCommon: + str, _ := node.AsStr(ctx) + *node = NewNode(PtrOffset(node.cptr, 1)) + return str, nil + case KStringEscaped: + str := node.StringCopyEsc(ctx) + *node = NewNode(PtrOffset(node.cptr, 1)) + return str, nil + case KTrue: + *node = NewNode(PtrOffset(node.cptr, 1)) + return true, nil + case KFalse: + *node = NewNode(PtrOffset(node.cptr, 1)) + return false, nil + case KNull: + *node = NewNode(PtrOffset(node.cptr, 1)) + return nil, nil + default: + // use float64 + if ctx.Parser.options & (1 << _F_use_number) != 0 { + num, ok := node.AsNumber(ctx) + if !ok { + // skip the unmacthed type + *node = NewNode(node.Next()) + return nil, newUnmatched(node.Position(), rt.JsonNumberType) + } else { + *node = NewNode(PtrOffset(node.cptr, 1)) + return num, nil + } + } else if ctx.Parser.options & (1 << _F_use_int64) != 0 { + // first try int64 + i, ok := node.AsI64(ctx) + if ok { + *node = NewNode(PtrOffset(node.cptr, 1)) + return i, nil + } + + // is not integer, then use float64 + f, ok := node.AsF64(ctx) + if ok { + *node = NewNode(PtrOffset(node.cptr, 1)) + return f, nil + } + + // skip the unmacthed type + *node = NewNode(node.Next()) + return nil, newUnmatched(node.Position(), rt.Int64Type) + } else { + num, ok := node.AsF64(ctx) + if !ok { + // skip the unmacthed type + *node = NewNode(node.Next()) + return nil, newUnmatched(node.Position(), rt.Float64Type) + } else { + *node = NewNode(PtrOffset(node.cptr, 1)) + return num, nil + } + } + } +} + +//go:nosplit +func PtrOffset(ptr uintptr, off int64) uintptr { + return uintptr(int64(ptr) + off * int64(unsafe.Sizeof(node{}))) +} diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/slice.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/slice.go new file mode 100644 index 000000000..a94e422b3 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/slice.go @@ -0,0 +1,224 @@ +package optdec + +import ( + "reflect" + "unsafe" + + "github.com/bytedance/sonic/internal/rt" +) + +type sliceDecoder struct { + elemType *rt.GoType + elemDec decFunc + typ reflect.Type +} + +var ( + emptyPtr = &struct{}{} +) + +func (d *sliceDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*rt.GoSlice)(vp) = rt.GoSlice{} + return nil + } + + arr, ok := node.AsArr() + if !ok { + return error_mismatch(node, ctx, d.typ) + } + + slice := rt.MakeSlice(vp, d.elemType, arr.Len()) + elems := slice.Ptr + next := arr.Children() + + var gerr error + for i := 0; i < arr.Len(); i++ { + val := NewNode(next) + elem := unsafe.Pointer(uintptr(elems) + uintptr(i)*d.elemType.Size) + err := d.elemDec.FromDom(elem, val, ctx) + if gerr == nil && err != nil { + gerr = err + } + next = val.Next() + } + + *(*rt.GoSlice)(vp) = *slice + return gerr +} + +type arrayDecoder struct { + len int + elemType *rt.GoType + elemDec decFunc + typ reflect.Type +} + +//go:nocheckptr +func (d *arrayDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + arr, ok := node.AsArr() + if !ok { + return error_mismatch(node, ctx, d.typ) + } + + next := arr.Children() + i := 0 + + var gerr error + for ; i < d.len && i < arr.Len(); i++ { + elem := unsafe.Pointer(uintptr(vp) + uintptr(i)*d.elemType.Size) + val := NewNode(next) + err := d.elemDec.FromDom(elem, val, ctx) + if gerr == nil && err != nil { + gerr = err + } + next = val.Next() + } + + /* zero rest of array */ + ptr := unsafe.Pointer(uintptr(vp) + uintptr(i)*d.elemType.Size) + n := uintptr(d.len-i) * d.elemType.Size + rt.ClearMemory(d.elemType, ptr, n) + return gerr +} + +type sliceEfaceDecoder struct { +} + +func (d *sliceEfaceDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*rt.GoSlice)(vp) = rt.GoSlice{} + return nil + } + + return node.AsSliceEface(ctx, vp) +} + +type sliceI32Decoder struct { +} + +func (d *sliceI32Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*rt.GoSlice)(vp) = rt.GoSlice{} + return nil + } + + return node.AsSliceI32(ctx, vp) +} + +type sliceI64Decoder struct { +} + +func (d *sliceI64Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*rt.GoSlice)(vp) = rt.GoSlice{} + return nil + } + + return node.AsSliceI64(ctx, vp) +} + +type sliceU32Decoder struct { +} + +func (d *sliceU32Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*rt.GoSlice)(vp) = rt.GoSlice{} + return nil + } + + return node.AsSliceU32(ctx, vp) +} + +type sliceU64Decoder struct { +} + +func (d *sliceU64Decoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*rt.GoSlice)(vp) = rt.GoSlice{} + return nil + } + + return node.AsSliceU64(ctx, vp) +} + +type sliceStringDecoder struct { +} + +func (d *sliceStringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*rt.GoSlice)(vp) = rt.GoSlice{} + return nil + } + + return node.AsSliceString(ctx, vp) +} + +type sliceBytesDecoder struct { +} + +func (d *sliceBytesDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*rt.GoSlice)(vp) = rt.GoSlice{} + return nil + } + + s, err := node.AsSliceBytes(ctx) + if err != nil { + return err + } + + *(*[]byte)(vp) = s + return nil +} + +type sliceBytesUnmarshalerDecoder struct { + elemType *rt.GoType + elemDec decFunc + typ reflect.Type +} + +func (d *sliceBytesUnmarshalerDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*rt.GoSlice)(vp) = rt.GoSlice{} + return nil + } + + /* parse JSON string into `[]byte` */ + if node.IsStr() { + slice, err := node.AsSliceBytes(ctx) + if err != nil { + return err + } + *(*[]byte)(vp) = slice + return nil + } + + /* parse JSON array into `[]byte` */ + arr, ok := node.AsArr() + if !ok { + return error_mismatch(node, ctx, d.typ) + } + + slice := rt.MakeSlice(vp, d.elemType, arr.Len()) + elems := slice.Ptr + + var gerr error + next := arr.Children() + for i := 0; i < arr.Len(); i++ { + child := NewNode(next) + elem := unsafe.Pointer(uintptr(elems) + uintptr(i)*d.elemType.Size) + err := d.elemDec.FromDom(elem, child, ctx) + if gerr == nil && err != nil { + gerr = err + } + next = child.Next() + } + + *(*rt.GoSlice)(vp) = *slice + return gerr +} diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/stringopts.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/stringopts.go new file mode 100644 index 000000000..627b5ebea --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/stringopts.go @@ -0,0 +1,360 @@ +package optdec + +import ( + "encoding/json" + "math" + "unsafe" + + "github.com/bytedance/sonic/internal/rt" +) + +type ptrStrDecoder struct { + typ *rt.GoType + deref decFunc +} + +// Pointer Value is allocated in the Caller +func (d *ptrStrDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + *(*unsafe.Pointer)(vp) = nil + return nil + } + + s, ok := node.AsStrRef(ctx) + if !ok { + return error_mismatch(node, ctx, stringType) + } + + if s == "null" { + *(*unsafe.Pointer)(vp) = nil + return nil + } + + if *(*unsafe.Pointer)(vp) == nil { + *(*unsafe.Pointer)(vp) = rt.Mallocgc(d.typ.Size, d.typ, true) + } + + return d.deref.FromDom(*(*unsafe.Pointer)(vp), node, ctx) +} + +type boolStringDecoder struct { +} + +func (d *boolStringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + s, ok := node.AsStrRef(ctx) + if !ok { + return error_mismatch(node, ctx, stringType) + } + + if s == "null" { + return nil + } + + b, err := ParseBool(s) + if err != nil { + return error_mismatch(node, ctx, boolType) + } + + *(*bool)(vp) = b + return nil +} + +func parseI64(node Node, ctx *context) (int64, error, bool) { + if node.IsNull() { + return 0, nil, true + } + + s, ok := node.AsStrRef(ctx) + if !ok { + return 0, error_mismatch(node, ctx, stringType), false + } + + if s == "null" { + return 0, nil, true + } + + ret, err := ParseI64(s) + return ret, err, false +} + +type i8StringDecoder struct{} + +func (d *i8StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + ret, err, null := parseI64(node, ctx) + if null { + return nil + } + + if err != nil { + return err + } + + if ret > math.MaxInt8 || ret < math.MinInt8 { + return error_mismatch(node, ctx, int8Type) + } + + *(*int8)(vp) = int8(ret) + return nil +} + +type i16StringDecoder struct{} + +func (d *i16StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + ret, err, null := parseI64(node, ctx) + if null { + return nil + } + + if err != nil { + return err + } + + if ret > math.MaxInt16 || ret < math.MinInt16 { + return error_mismatch(node, ctx, int16Type) + } + + *(*int16)(vp) = int16(ret) + return nil +} + +type i32StringDecoder struct{} + +func (d *i32StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + ret, err, null := parseI64(node, ctx) + if null { + return nil + } + + if err != nil { + return err + } + + if ret > math.MaxInt32 || ret < math.MinInt32 { + return error_mismatch(node, ctx, int32Type) + } + + *(*int32)(vp) = int32(ret) + return nil +} + +type i64StringDecoder struct{} + +func (d *i64StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + ret, err, null := parseI64(node, ctx) + if null { + return nil + } + + if err != nil { + return err + } + + *(*int64)(vp) = int64(ret) + return nil +} + +func parseU64(node Node, ctx *context) (uint64, error, bool) { + if node.IsNull() { + return 0, nil, true + } + + s, ok := node.AsStrRef(ctx) + if !ok { + return 0, error_mismatch(node, ctx, stringType), false + } + + if s == "null" { + return 0, nil, true + } + + ret, err := ParseU64(s) + return ret, err, false +} + +type u8StringDecoder struct{} + +func (d *u8StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + ret, err, null := parseU64(node, ctx) + if null { + return nil + } + + if err != nil { + return err + } + + if ret > math.MaxUint8 { + return error_mismatch(node, ctx, uint8Type) + } + + *(*uint8)(vp) = uint8(ret) + return nil +} + +type u16StringDecoder struct{} + +func (d *u16StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + ret, err, null := parseU64(node, ctx) + if null { + return nil + } + + if err != nil { + return err + } + + if ret > math.MaxUint16 { + return error_mismatch(node, ctx, uint16Type) + } + + *(*uint16)(vp) = uint16(ret) + return nil +} + +type u32StringDecoder struct{} + +func (d *u32StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + ret, err, null := parseU64(node, ctx) + if null { + return nil + } + + if err != nil { + return err + } + + if ret > math.MaxUint32 { + return error_mismatch(node, ctx, uint32Type) + } + + *(*uint32)(vp) = uint32(ret) + return nil +} + + +type u64StringDecoder struct{} + +func (d *u64StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + ret, err, null := parseU64(node, ctx) + if null { + return nil + } + + if err != nil { + return err + } + + *(*uint64)(vp) = uint64(ret) + return nil +} + +type f32StringDecoder struct{} + +func (d *f32StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + s, ok := node.AsStrRef(ctx) + if !ok { + return error_mismatch(node, ctx, stringType) + } + + if s == "null" { + return nil + } + + ret, err := ParseF64(s) + if err != nil || ret > math.MaxFloat32 || ret < -math.MaxFloat32 { + return error_mismatch(node, ctx, float32Type) + } + + *(*float32)(vp) = float32(ret) + return nil +} + +type f64StringDecoder struct{} + +func (d *f64StringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + s, ok := node.AsStrRef(ctx) + if !ok { + return error_mismatch(node, ctx, stringType) + } + + if s == "null" { + return nil + } + + ret, err := ParseF64(s) + if err != nil { + return error_mismatch(node, ctx, float64Type) + } + + *(*float64)(vp) = float64(ret) + return nil +} + +/* parse string field with string options */ +type strStringDecoder struct{} + +func (d *strStringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + s, ok := node.AsStrRef(ctx) + if !ok { + return error_mismatch(node, ctx, stringType) + } + + if s == "null" { + return nil + } + + s, err := Unquote(s) + if err != nil { + return error_mismatch(node, ctx, stringType) + } + + *(*string)(vp) = s + return nil +} + +type numberStringDecoder struct{} + +func (d *numberStringDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + s, ok := node.AsStrRef(ctx) + if !ok { + return error_mismatch(node, ctx, stringType) + } + + if s == "null" { + return nil + } + + num, ok := node.ParseNumber(ctx) + if !ok { + return error_mismatch(node, ctx, jsonNumberType) + } + + end, err := SkipNumberFast(s, 0) + // has error or trailing chars + if err != nil || end != len(s) { + return error_mismatch(node, ctx, jsonNumberType) + } + + *(*json.Number)(vp) = json.Number(num) + return nil +} diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/structs.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/structs.go new file mode 100644 index 000000000..bce2758f1 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/structs.go @@ -0,0 +1,61 @@ +package optdec + +import ( + "reflect" + "unsafe" + + caching "github.com/bytedance/sonic/internal/optcaching" + "github.com/bytedance/sonic/internal/resolver" +) + +type fieldEntry struct { + resolver.FieldMeta + fieldDec decFunc +} + +type structDecoder struct { + fieldMap caching.FieldLookup + fields []fieldEntry + structName string + typ reflect.Type +} + +func (d *structDecoder) FromDom(vp unsafe.Pointer, node Node, ctx *context) error { + if node.IsNull() { + return nil + } + + var gerr error + obj, ok := node.AsObj() + if !ok { + return error_mismatch(node, ctx, d.typ) + } + + next := obj.Children() + for i := 0; i < obj.Len(); i++ { + key, _ := NewNode(next).AsStrRef(ctx) + val := NewNode(PtrOffset(next, 1)) + next = val.Next() + + // find field idx + idx := d.fieldMap.Get(key) + if idx == -1 { + if Options(ctx.Options())&OptionDisableUnknown != 0 { + return error_field(key) + } + continue + } + + offset := d.fields[idx].Path[0].Size + elem := unsafe.Pointer(uintptr(vp) + offset) + err := d.fields[idx].fieldDec.FromDom(elem, val, ctx) + + // deal with mismatch type errors + if gerr == nil && err != nil { + // TODO: better error info + gerr = err + } + } + return gerr +} + diff --git a/vendor/github.com/bytedance/sonic/internal/decoder/optdec/types.go b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/types.go new file mode 100644 index 000000000..fe1433eec --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/decoder/optdec/types.go @@ -0,0 +1,60 @@ +/* + * 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 optdec + +import ( + "encoding" + "encoding/base64" + "encoding/json" + "reflect" + "unsafe" + + "github.com/bytedance/sonic/internal/rt" +) + +var ( + boolType = reflect.TypeOf(bool(false)) + byteType = reflect.TypeOf(byte(0)) + intType = reflect.TypeOf(int(0)) + int8Type = reflect.TypeOf(int8(0)) + int16Type = reflect.TypeOf(int16(0)) + int32Type = reflect.TypeOf(int32(0)) + int64Type = reflect.TypeOf(int64(0)) + uintType = reflect.TypeOf(uint(0)) + uint8Type = reflect.TypeOf(uint8(0)) + uint16Type = reflect.TypeOf(uint16(0)) + uint32Type = reflect.TypeOf(uint32(0)) + uint64Type = reflect.TypeOf(uint64(0)) + float32Type = reflect.TypeOf(float32(0)) + float64Type = reflect.TypeOf(float64(0)) + stringType = reflect.TypeOf("") + bytesType = reflect.TypeOf([]byte(nil)) + jsonNumberType = reflect.TypeOf(json.Number("")) + base64CorruptInputError = reflect.TypeOf(base64.CorruptInputError(0)) + anyType = rt.UnpackType(reflect.TypeOf((*interface{})(nil)).Elem()) +) + +var ( + errorType = reflect.TypeOf((*error)(nil)).Elem() + jsonUnmarshalerType = reflect.TypeOf((*json.Unmarshaler)(nil)).Elem() + encodingTextUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() +) + +func rtype(t reflect.Type) (*rt.GoItab, *rt.GoType) { + p := (*rt.GoIface)(unsafe.Pointer(&t)) + return p.Itab, (*rt.GoType)(p.Value) +} diff --git a/vendor/github.com/bytedance/sonic/internal/encoder/mapiter.go b/vendor/github.com/bytedance/sonic/internal/encoder/alg/mapiter.go similarity index 52% rename from vendor/github.com/bytedance/sonic/internal/encoder/mapiter.go rename to vendor/github.com/bytedance/sonic/internal/encoder/alg/mapiter.go index 8a322b3af..5d9956a90 100644 --- a/vendor/github.com/bytedance/sonic/internal/encoder/mapiter.go +++ b/vendor/github.com/bytedance/sonic/internal/encoder/alg/mapiter.go @@ -14,15 +14,16 @@ * limitations under the License. */ -package encoder +package alg import ( "encoding" "reflect" + "strconv" "sync" "unsafe" - "github.com/bytedance/sonic/internal/native" + "github.com/bytedance/sonic/internal/encoder/vars" "github.com/bytedance/sonic/internal/rt" ) @@ -32,8 +33,8 @@ type _MapPair struct { m [32]byte } -type _MapIterator struct { - it rt.GoMapIterator // must be the first field +type MapIterator struct { + It rt.GoMapIterator // must be the first field kv rt.GoSlice // slice of _MapPair ki int } @@ -44,43 +45,43 @@ var ( ) func init() { - if unsafe.Offsetof(_MapIterator{}.it) != 0 { + if unsafe.Offsetof(MapIterator{}.It) != 0 { panic("_MapIterator.it is not the first field") } } -func newIterator() *_MapIterator { +func newIterator() *MapIterator { if v := iteratorPool.Get(); v == nil { - return new(_MapIterator) + return new(MapIterator) } else { - return resetIterator(v.(*_MapIterator)) + return resetIterator(v.(*MapIterator)) } } -func resetIterator(p *_MapIterator) *_MapIterator { +func resetIterator(p *MapIterator) *MapIterator { p.ki = 0 - p.it = rt.GoMapIterator{} + p.It = rt.GoMapIterator{} p.kv.Len = 0 return p } -func (self *_MapIterator) at(i int) *_MapPair { +func (self *MapIterator) at(i int) *_MapPair { return (*_MapPair)(unsafe.Pointer(uintptr(self.kv.Ptr) + uintptr(i) * unsafe.Sizeof(_MapPair{}))) } -func (self *_MapIterator) add() (p *_MapPair) { +func (self *MapIterator) add() (p *_MapPair) { p = self.at(self.kv.Len) self.kv.Len++ return } -func (self *_MapIterator) data() (p []_MapPair) { +func (self *MapIterator) data() (p []_MapPair) { *(*rt.GoSlice)(unsafe.Pointer(&p)) = self.kv return } -func (self *_MapIterator) append(t *rt.GoType, k unsafe.Pointer, v unsafe.Pointer) (err error) { +func (self *MapIterator) append(t *rt.GoType, k unsafe.Pointer, v unsafe.Pointer) (err error) { p := self.add() p.v = v @@ -94,26 +95,26 @@ func (self *_MapIterator) append(t *rt.GoType, k unsafe.Pointer, v unsafe.Pointe return nil } -func (self *_MapIterator) appendGeneric(p *_MapPair, t *rt.GoType, v reflect.Kind, k unsafe.Pointer) error { +func (self *MapIterator) appendGeneric(p *_MapPair, t *rt.GoType, v reflect.Kind, k unsafe.Pointer) error { switch v { - case reflect.Int : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], int64(*(*int)(k)))]) ; return nil - case reflect.Int8 : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], int64(*(*int8)(k)))]) ; return nil - case reflect.Int16 : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], int64(*(*int16)(k)))]) ; return nil - case reflect.Int32 : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], int64(*(*int32)(k)))]) ; return nil - case reflect.Int64 : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], *(*int64)(k))]) ; return nil - case reflect.Uint : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uint)(k)))]) ; return nil - case reflect.Uint8 : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uint8)(k)))]) ; return nil - case reflect.Uint16 : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uint16)(k)))]) ; return nil - case reflect.Uint32 : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uint32)(k)))]) ; return nil - case reflect.Uint64 : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], *(*uint64)(k))]) ; return nil - case reflect.Uintptr : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uintptr)(k)))]) ; return nil + case reflect.Int : p.k = rt.Mem2Str(strconv.AppendInt(p.m[:0], int64(*(*int)(k)), 10)) ; return nil + case reflect.Int8 : p.k = rt.Mem2Str(strconv.AppendInt(p.m[:0], int64(*(*int8)(k)), 10)) ; return nil + case reflect.Int16 : p.k = rt.Mem2Str(strconv.AppendInt(p.m[:0], int64(*(*int16)(k)), 10)) ; return nil + case reflect.Int32 : p.k = rt.Mem2Str(strconv.AppendInt(p.m[:0], int64(*(*int32)(k)), 10)) ; return nil + case reflect.Int64 : p.k = rt.Mem2Str(strconv.AppendInt(p.m[:0], int64(*(*int64)(k)), 10)) ; return nil + case reflect.Uint : p.k = rt.Mem2Str(strconv.AppendUint(p.m[:0], uint64(*(*uint)(k)), 10)) ; return nil + case reflect.Uint8 : p.k = rt.Mem2Str(strconv.AppendUint(p.m[:0], uint64(*(*uint8)(k)), 10)) ; return nil + case reflect.Uint16 : p.k = rt.Mem2Str(strconv.AppendUint(p.m[:0], uint64(*(*uint16)(k)), 10)) ; return nil + case reflect.Uint32 : p.k = rt.Mem2Str(strconv.AppendUint(p.m[:0], uint64(*(*uint32)(k)), 10)) ; return nil + case reflect.Uint64 : p.k = rt.Mem2Str(strconv.AppendUint(p.m[:0], uint64(*(*uint64)(k)), 10)) ; return nil + case reflect.Uintptr : p.k = rt.Mem2Str(strconv.AppendUint(p.m[:0], uint64(*(*uintptr)(k)), 10)) ; return nil case reflect.Interface : return self.appendInterface(p, t, k) case reflect.Struct, reflect.Ptr : return self.appendConcrete(p, t, k) default : panic("unexpected map key type") } } -func (self *_MapIterator) appendConcrete(p *_MapPair, t *rt.GoType, k unsafe.Pointer) (err error) { +func (self *MapIterator) appendConcrete(p *_MapPair, t *rt.GoType, k unsafe.Pointer) (err error) { // compiler has already checked that the type implements the encoding.MarshalText interface if !t.Indirect() { k = *(*unsafe.Pointer)(k) @@ -127,7 +128,7 @@ func (self *_MapIterator) appendConcrete(p *_MapPair, t *rt.GoType, k unsafe.Poi return } -func (self *_MapIterator) appendInterface(p *_MapPair, t *rt.GoType, k unsafe.Pointer) (err error) { +func (self *MapIterator) appendInterface(p *_MapPair, t *rt.GoType, k unsafe.Pointer) (err error) { if len(rt.IfaceType(t).Methods) == 0 { panic("unexpected map key type") } else if p.k, err = asText(k); err == nil { @@ -137,17 +138,17 @@ func (self *_MapIterator) appendInterface(p *_MapPair, t *rt.GoType, k unsafe.Po } } -func iteratorStop(p *_MapIterator) { +func IteratorStop(p *MapIterator) { iteratorPool.Put(p) } -func iteratorNext(p *_MapIterator) { +func IteratorNext(p *MapIterator) { i := p.ki - t := &p.it + t := &p.It /* check for unordered iteration */ if i < 0 { - mapiternext(t) + rt.Mapiternext(t) return } @@ -164,25 +165,25 @@ func iteratorNext(p *_MapIterator) { p.ki++ } -func iteratorStart(t *rt.GoMapType, m *rt.GoMap, fv uint64) (*_MapIterator, error) { +func IteratorStart(t *rt.GoMapType, m *rt.GoMap, fv uint64) (*MapIterator, error) { it := newIterator() - mapiterinit(t, m, &it.it) + rt.Mapiterinit(t, m, &it.It) /* check for key-sorting, empty map don't need sorting */ - if m.Count == 0 || (fv & uint64(SortMapKeys)) == 0 { + if m.Count == 0 || (fv & (1< it.kv.Cap { - it.kv = growslice(iteratorPair, it.kv, m.Count) + it.kv = rt.GrowSlice(iteratorPair, it.kv, m.Count) } /* dump all the key-value pairs */ - for ; it.it.K != nil; mapiternext(&it.it) { - if err := it.append(t.Key, it.it.K, it.it.V); err != nil { - iteratorStop(it) + for ; it.It.K != nil; rt.Mapiternext(&it.It) { + if err := it.append(t.Key, it.It.K, it.It.V); err != nil { + IteratorStop(it) return nil, err } } @@ -193,7 +194,13 @@ func iteratorStart(t *rt.GoMapType, m *rt.GoMap, fv uint64) (*_MapIterator, erro } /* load the first pair into iterator */ - it.it.V = it.at(0).v - it.it.K = unsafe.Pointer(&it.at(0).k) + it.It.V = it.at(0).v + it.It.K = unsafe.Pointer(&it.at(0).k) return it, nil } + +func asText(v unsafe.Pointer) (string, error) { + text := rt.AssertI2I(rt.UnpackType(vars.EncodingTextMarshalerType), *(*rt.GoIface)(v)) + r, e := (*(*encoding.TextMarshaler)(unsafe.Pointer(&text))).MarshalText() + return rt.Mem2Str(r), e +} diff --git a/vendor/github.com/bytedance/sonic/internal/encoder/alg/opts.go b/vendor/github.com/bytedance/sonic/internal/encoder/alg/opts.go new file mode 100644 index 000000000..c19e2de4e --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/encoder/alg/opts.go @@ -0,0 +1,31 @@ +/** + * Copyright 2024 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 alg + +const ( + BitSortMapKeys = iota + BitEscapeHTML + BitCompactMarshaler + BitNoQuoteTextMarshaler + BitNoNullSliceOrMap + BitValidateString + BitNoValidateJSONMarshaler + BitNoEncoderNewline + BitEncodeNullForInfOrNan + + BitPointerValue = 63 +) diff --git a/vendor/github.com/bytedance/sonic/internal/encoder/alg/primitives.go b/vendor/github.com/bytedance/sonic/internal/encoder/alg/primitives.go new file mode 100644 index 000000000..63fa01890 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/encoder/alg/primitives.go @@ -0,0 +1,95 @@ +/** + * Copyright 2024 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 alg + +import ( + "encoding" + "encoding/json" + + "github.com/bytedance/sonic/internal/encoder/vars" + "github.com/bytedance/sonic/internal/rt" +) + +func Compact(p *[]byte, v []byte) error { + buf := vars.NewBuffer() + err := json.Compact(buf, v) + + /* check for errors */ + if err != nil { + return err + } + + /* add to result */ + v = buf.Bytes() + *p = append(*p, v...) + + /* return the buffer into pool */ + vars.FreeBuffer(buf) + return nil +} + +func EncodeNil(rb *[]byte) error { + *rb = append(*rb, 'n', 'u', 'l', 'l') + return nil +} + +// func Make_EncodeTypedPointer(computor func(*rt.GoType, ...interface{}) (interface{}, error)) func(*[]byte, *rt.GoType, *unsafe.Pointer, *vars.Stack, uint64) error { +// return func(buf *[]byte, vt *rt.GoType, vp *unsafe.Pointer, sb *vars.Stack, fv uint64) error { +// if vt == nil { +// return EncodeNil(buf) +// } else if fn, err := vars.FindOrCompile(vt, (fv&(1< 0 { + // output buffer + dp := unsafe.Pointer(uintptr(b.Ptr) + uintptr(b.Len)) + dn := b.Cap - b.Len + // call native.Quote, dn is byte count it outputs + opts := uint64(0) + if double { + opts = types.F_DOUBLE_UNQUOTE + } + ret := native.Quote(sp, nb, dp, &dn, opts) + // update *buf length + b.Len += dn + + // no need more output + if ret >= 0 { + break + } + + // double buf size + *b = rt.GrowSlice(typeByte, *b, b.Cap*2) + // ret is the complement of consumed input + ret = ^ret + // update input buffer + nb -= ret + sp = unsafe.Pointer(uintptr(sp) + uintptr(ret)) + } + + runtime.KeepAlive(buf) + runtime.KeepAlive(sp) + if double { + buf = append(buf, `\""`...) + } else { + buf = append(buf, `"`...) + } + + return buf +} + +func HtmlEscape(dst []byte, src []byte) []byte { + var sidx int + + dst = append(dst, src[:0]...) // avoid check nil dst + sbuf := (*rt.GoSlice)(unsafe.Pointer(&src)) + dbuf := (*rt.GoSlice)(unsafe.Pointer(&dst)) + + /* grow dst if it is shorter */ + if cap(dst)-len(dst) < len(src)+types.BufPaddingSize { + cap := len(src)*3/2 + types.BufPaddingSize + *dbuf = rt.GrowSlice(typeByte, *dbuf, cap) + } + + for sidx < sbuf.Len { + sp := rt.Add(sbuf.Ptr, uintptr(sidx)) + dp := rt.Add(dbuf.Ptr, uintptr(dbuf.Len)) + + sn := sbuf.Len - sidx + dn := dbuf.Cap - dbuf.Len + nb := native.HTMLEscape(sp, sn, dp, &dn) + + /* check for errors */ + if dbuf.Len += dn; nb >= 0 { + break + } + + /* not enough space, grow the slice and try again */ + sidx += ^nb + *dbuf = rt.GrowSlice(typeByte, *dbuf, dbuf.Cap*2) + } + return dst +} + +func F64toa(buf []byte, v float64) ([]byte) { + if v == 0 { + return append(buf, '0') + } + buf = rt.GuardSlice2(buf, 64) + ret := native.F64toa((*byte)(rt.IndexByte(buf, len(buf))), v) + if ret > 0 { + return buf[:len(buf)+ret] + } else { + return buf + } +} + +func F32toa(buf []byte, v float32) ([]byte) { + if v == 0 { + return append(buf, '0') + } + buf = rt.GuardSlice2(buf, 64) + ret := native.F32toa((*byte)(rt.IndexByte(buf, len(buf))), v) + if ret > 0 { + return buf[:len(buf)+ret] + } else { + return buf + } +} + +func I64toa(buf []byte, v int64) ([]byte) { + buf = rt.GuardSlice2(buf, 32) + ret := native.I64toa((*byte)(rt.IndexByte(buf, len(buf))), v) + if ret > 0 { + return buf[:len(buf)+ret] + } else { + return buf + } +} + +func U64toa(buf []byte, v uint64) ([]byte) { + buf = rt.GuardSlice2(buf, 32) + ret := native.U64toa((*byte)(rt.IndexByte(buf, len(buf))), v) + if ret > 0 { + return buf[:len(buf)+ret] + } else { + return buf + } +} + diff --git a/vendor/github.com/bytedance/sonic/internal/encoder/alg/spec_compat.go b/vendor/github.com/bytedance/sonic/internal/encoder/alg/spec_compat.go new file mode 100644 index 000000000..c15cbf7d8 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/encoder/alg/spec_compat.go @@ -0,0 +1,148 @@ +// +build !amd64,!arm64 go1.24 !go1.16 arm64,!go1.20 + +/** + * Copyright 2024 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 alg + +import ( + _ "unsafe" + "unicode/utf8" + "strconv" + "bytes" + "encoding/json" + + "github.com/bytedance/sonic/internal/rt" +) + +// Valid validates json and returns first non-blank character position, +// if it is only one valid json value. +// Otherwise returns invalid character position using start. +// +// Note: it does not check for the invalid UTF-8 characters. +func Valid(data []byte) (ok bool, start int) { + ok = json.Valid(data) + return ok, 0 +} + +var typeByte = rt.UnpackEface(byte(0)).Type + +func Quote(e []byte, s string, double bool) []byte { + if len(s) == 0 { + if double { + return append(e, `"\"\""`...) + } + return append(e, `""`...) + } + + b := e + ss := len(e) + e = append(e, '"') + start := 0 + + for i := 0; i < len(s); { + if b := s[i]; b < utf8.RuneSelf { + if rt.SafeSet[b] { + i++ + continue + } + if start < i { + e = append(e, s[start:i]...) + } + e = append(e, '\\') + switch b { + case '\\', '"': + e = append(e, b) + case '\n': + e = append(e, 'n') + case '\r': + e = append(e, 'r') + case '\t': + e = append(e, 't') + default: + // This encodes bytes < 0x20 except for \t, \n and \r. + // If escapeHTML is set, it also escapes <, >, and & + // because they can lead to security holes when + // user-controlled strings are rendered into JSON + // and served to some browsers. + e = append(e, `u00`...) + e = append(e, rt.Hex[b>>4]) + e = append(e, rt.Hex[b&0xF]) + } + i++ + start = i + continue + } + c, size := utf8.DecodeRuneInString(s[i:]) + // if correct && c == utf8.RuneError && size == 1 { + // if start < i { + // e = append(e, s[start:i]...) + // } + // e = append(e, `\ufffd`...) + // i += size + // start = i + // continue + // } + if c == '\u2028' || c == '\u2029' { + if start < i { + e = append(e, s[start:i]...) + } + e = append(e, `\u202`...) + e = append(e, rt.Hex[c&0xF]) + i += size + start = i + continue + } + i += size + } + + if start < len(s) { + e = append(e, s[start:]...) + } + e = append(e, '"') + + if double { + return strconv.AppendQuote(b, string(e[ss:])) + } else { + return e + } +} + +func HtmlEscape(dst []byte, src []byte) []byte { + buf := bytes.NewBuffer(dst) + json.HTMLEscape(buf, src) + return buf.Bytes() +} + +func F64toa(buf []byte, v float64) ([]byte) { + bs := bytes.NewBuffer(buf) + _ = json.NewEncoder(bs).Encode(v) + return bs.Bytes() +} + +func F32toa(buf []byte, v float32) ([]byte) { + bs := bytes.NewBuffer(buf) + _ = json.NewEncoder(bs).Encode(v) + return bs.Bytes() +} + +func I64toa(buf []byte, v int64) ([]byte) { + return strconv.AppendInt(buf, int64(v), 10) +} + +func U64toa(buf []byte, v uint64) ([]byte) { + return strconv.AppendUint(buf, v, 10) +} diff --git a/vendor/github.com/bytedance/sonic/internal/encoder/asm_stubs_amd64_go116.go b/vendor/github.com/bytedance/sonic/internal/encoder/asm_stubs_amd64_go116.go deleted file mode 100644 index 0a99f30ab..000000000 --- a/vendor/github.com/bytedance/sonic/internal/encoder/asm_stubs_amd64_go116.go +++ /dev/null @@ -1,51 +0,0 @@ -// +build go1.16,!go1.17 - -// Copyright 2023 CloudWeGo Authors -// -// 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 ( - `strconv` - - `github.com/bytedance/sonic/internal/jit` - `github.com/twitchyliquid64/golang-asm/obj` - `github.com/twitchyliquid64/golang-asm/obj/x86` -) - -var ( - _V_writeBarrier = jit.Imm(int64(_runtime_writeBarrier)) - - _F_gcWriteBarrierAX = jit.Func(gcWriteBarrierAX) -) - -func (self *_Assembler) WritePtr(i int, ptr obj.Addr, rec obj.Addr) { - if rec.Reg == x86.REG_AX || rec.Index == x86.REG_AX { - panic("rec contains AX!") - } - self.Emit("MOVQ", _V_writeBarrier, _R10) - self.Emit("CMPL", jit.Ptr(_R10, 0), jit.Imm(0)) - self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}") - self.Emit("MOVQ", ptr, _AX) - self.xsave(_DI) - self.Emit("LEAQ", rec, _DI) - self.Emit("MOVQ", _F_gcWriteBarrierAX, _R10) // MOVQ ${fn}, AX - self.Rjmp("CALL", _R10) - self.xload(_DI) - self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}") - self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}") - self.Emit("MOVQ", ptr, rec) - self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}") -} - diff --git a/vendor/github.com/bytedance/sonic/internal/encoder/assembler_regabi_amd64.go b/vendor/github.com/bytedance/sonic/internal/encoder/assembler_regabi_amd64.go deleted file mode 100644 index a89364b14..000000000 --- a/vendor/github.com/bytedance/sonic/internal/encoder/assembler_regabi_amd64.go +++ /dev/null @@ -1,1177 +0,0 @@ -//go:build go1.17 && !go1.22 -// +build go1.17,!go1.22 - -/* - * 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 ( - `fmt` - `reflect` - `strconv` - `unsafe` - - `github.com/bytedance/sonic/internal/cpu` - `github.com/bytedance/sonic/internal/jit` - `github.com/bytedance/sonic/internal/native/types` - `github.com/twitchyliquid64/golang-asm/obj` - `github.com/twitchyliquid64/golang-asm/obj/x86` - - `github.com/bytedance/sonic/internal/native` - `github.com/bytedance/sonic/internal/rt` -) - -/** Register Allocations - * - * State Registers: - * - * %rbx : stack base - * %rdi : result pointer - * %rsi : result length - * %rdx : result capacity - * %r12 : sp->p - * %r13 : sp->q - * %r14 : sp->x - * %r15 : sp->f - * - * Error Registers: - * - * %r10 : error type register - * %r11 : error pointer register - */ - -/** Function Prototype & Stack Map - * - * func (buf *[]byte, p unsafe.Pointer, sb *_Stack, fv uint64) (err error) - * - * buf : (FP) - * p : 8(FP) - * sb : 16(FP) - * fv : 24(FP) - * err.vt : 32(FP) - * err.vp : 40(FP) - */ - -const ( - _S_cond = iota - _S_init -) - -const ( - _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 -) - -const ( - _FP_loffs = _FP_fargs + _FP_saves - _FP_offs = _FP_loffs + _FP_locals - // _FP_offs = _FP_loffs + _FP_locals + _FP_debug - _FP_size = _FP_offs + 8 // 8 bytes for the parent frame pointer - _FP_base = _FP_size + 8 // 8 bytes for the return address -) - -const ( - _FM_exp32 = 0x7f800000 - _FM_exp64 = 0x7ff0000000000000 -) - -const ( - _IM_null = 0x6c6c756e // 'null' - _IM_true = 0x65757274 // 'true' - _IM_fals = 0x736c6166 // 'fals' ('false' without the 'e') - _IM_open = 0x00225c22 // '"\"∅' - _IM_array = 0x5d5b // '[]' - _IM_object = 0x7d7b // '{}' - _IM_mulv = -0x5555555555555555 -) - -const ( - _LB_more_space = "_more_space" - _LB_more_space_return = "_more_space_return_" -) - -const ( - _LB_error = "_error" - _LB_error_too_deep = "_error_too_deep" - _LB_error_invalid_number = "_error_invalid_number" - _LB_error_nan_or_infinite = "_error_nan_or_infinite" - _LB_panic = "_panic" -) - -var ( - _AX = jit.Reg("AX") - _BX = jit.Reg("BX") - _CX = jit.Reg("CX") - _DX = jit.Reg("DX") - _DI = jit.Reg("DI") - _SI = jit.Reg("SI") - _BP = jit.Reg("BP") - _SP = jit.Reg("SP") - _R8 = jit.Reg("R8") - _R9 = jit.Reg("R9") -) - -var ( - _X0 = jit.Reg("X0") - _Y0 = jit.Reg("Y0") -) - -var ( - _ST = jit.Reg("R15") // can't use R14 since it's always scratched by Go... - _RP = jit.Reg("DI") - _RL = jit.Reg("SI") - _RC = jit.Reg("DX") -) - -var ( - _LR = jit.Reg("R9") - _ET = jit.Reg("AX") - _EP = jit.Reg("BX") -) - -var ( - _SP_p = jit.Reg("R10") // saved on BX when call_c - _SP_q = jit.Reg("R11") // saved on BP when call_c - _SP_x = jit.Reg("R12") - _SP_f = jit.Reg("R13") -) - -var ( - _ARG_rb = jit.Ptr(_SP, _FP_base) - _ARG_vp = jit.Ptr(_SP, _FP_base + 8) - _ARG_sb = jit.Ptr(_SP, _FP_base + 16) - _ARG_fv = jit.Ptr(_SP, _FP_base + 24) -) - -var ( - _RET_et = _ET - _RET_ep = _EP -) - -var ( - _VAR_sp = jit.Ptr(_SP, _FP_fargs + _FP_saves) - _VAR_dn = jit.Ptr(_SP, _FP_fargs + _FP_saves + 8) - _VAR_vp = jit.Ptr(_SP, _FP_fargs + _FP_saves + 16) -) - -var ( - _REG_ffi = []obj.Addr{ _RP, _RL, _RC} - _REG_b64 = []obj.Addr{_SP_p, _SP_q} - - _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, _RL} -) - -type _Assembler struct { - jit.BaseAssembler - p _Program - x int - name string -} - -func newAssembler(p _Program) *_Assembler { - return new(_Assembler).Init(p) -} - -/** Assembler Interface **/ - -func (self *_Assembler) Load() _Encoder { - return ptoenc(self.BaseAssembler.Load("encode_"+self.name, _FP_size, _FP_args, argPtrs, localPtrs)) -} - -func (self *_Assembler) Init(p _Program) *_Assembler { - self.p = p - self.BaseAssembler.Init(self.compile) - return self -} - -func (self *_Assembler) compile() { - self.prologue() - self.instrs() - self.epilogue() - self.builtins() -} - -/** Assembler Stages **/ - -var _OpFuncTab = [256]func(*_Assembler, *_Instr) { - _OP_null : (*_Assembler)._asm_OP_null, - _OP_empty_arr : (*_Assembler)._asm_OP_empty_arr, - _OP_empty_obj : (*_Assembler)._asm_OP_empty_obj, - _OP_bool : (*_Assembler)._asm_OP_bool, - _OP_i8 : (*_Assembler)._asm_OP_i8, - _OP_i16 : (*_Assembler)._asm_OP_i16, - _OP_i32 : (*_Assembler)._asm_OP_i32, - _OP_i64 : (*_Assembler)._asm_OP_i64, - _OP_u8 : (*_Assembler)._asm_OP_u8, - _OP_u16 : (*_Assembler)._asm_OP_u16, - _OP_u32 : (*_Assembler)._asm_OP_u32, - _OP_u64 : (*_Assembler)._asm_OP_u64, - _OP_f32 : (*_Assembler)._asm_OP_f32, - _OP_f64 : (*_Assembler)._asm_OP_f64, - _OP_str : (*_Assembler)._asm_OP_str, - _OP_bin : (*_Assembler)._asm_OP_bin, - _OP_quote : (*_Assembler)._asm_OP_quote, - _OP_number : (*_Assembler)._asm_OP_number, - _OP_eface : (*_Assembler)._asm_OP_eface, - _OP_iface : (*_Assembler)._asm_OP_iface, - _OP_byte : (*_Assembler)._asm_OP_byte, - _OP_text : (*_Assembler)._asm_OP_text, - _OP_deref : (*_Assembler)._asm_OP_deref, - _OP_index : (*_Assembler)._asm_OP_index, - _OP_load : (*_Assembler)._asm_OP_load, - _OP_save : (*_Assembler)._asm_OP_save, - _OP_drop : (*_Assembler)._asm_OP_drop, - _OP_drop_2 : (*_Assembler)._asm_OP_drop_2, - _OP_recurse : (*_Assembler)._asm_OP_recurse, - _OP_is_nil : (*_Assembler)._asm_OP_is_nil, - _OP_is_nil_p1 : (*_Assembler)._asm_OP_is_nil_p1, - _OP_is_zero_1 : (*_Assembler)._asm_OP_is_zero_1, - _OP_is_zero_2 : (*_Assembler)._asm_OP_is_zero_2, - _OP_is_zero_4 : (*_Assembler)._asm_OP_is_zero_4, - _OP_is_zero_8 : (*_Assembler)._asm_OP_is_zero_8, - _OP_is_zero_map : (*_Assembler)._asm_OP_is_zero_map, - _OP_goto : (*_Assembler)._asm_OP_goto, - _OP_map_iter : (*_Assembler)._asm_OP_map_iter, - _OP_map_stop : (*_Assembler)._asm_OP_map_stop, - _OP_map_check_key : (*_Assembler)._asm_OP_map_check_key, - _OP_map_write_key : (*_Assembler)._asm_OP_map_write_key, - _OP_map_value_next : (*_Assembler)._asm_OP_map_value_next, - _OP_slice_len : (*_Assembler)._asm_OP_slice_len, - _OP_slice_next : (*_Assembler)._asm_OP_slice_next, - _OP_marshal : (*_Assembler)._asm_OP_marshal, - _OP_marshal_p : (*_Assembler)._asm_OP_marshal_p, - _OP_marshal_text : (*_Assembler)._asm_OP_marshal_text, - _OP_marshal_text_p : (*_Assembler)._asm_OP_marshal_text_p, - _OP_cond_set : (*_Assembler)._asm_OP_cond_set, - _OP_cond_testc : (*_Assembler)._asm_OP_cond_testc, -} - -func (self *_Assembler) instr(v *_Instr) { - if fn := _OpFuncTab[v.op()]; fn != nil { - fn(self, v) - } else { - panic(fmt.Sprintf("invalid opcode: %d", v.op())) - } -} - -func (self *_Assembler) instrs() { - for i, v := range self.p { - self.Mark(i) - self.instr(&v) - self.debug_instr(i, &v) - } -} - -func (self *_Assembler) builtins() { - self.more_space() - self.error_too_deep() - self.error_invalid_number() - self.error_nan_or_infinite() - self.go_panic() -} - -func (self *_Assembler) epilogue() { - self.Mark(len(self.p)) - self.Emit("XORL", _ET, _ET) - self.Emit("XORL", _EP, _EP) - 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 -} - -func (self *_Assembler) prologue() { - self.Emit("SUBQ", jit.Imm(_FP_size), _SP) // SUBQ $_FP_size, SP - self.Emit("MOVQ", _BP, jit.Ptr(_SP, _FP_offs)) // MOVQ BP, _FP_offs(SP) - self.Emit("LEAQ", jit.Ptr(_SP, _FP_offs), _BP) // LEAQ _FP_offs(SP), BP - self.Emit("MOVQ", _AX, _ARG_rb) // MOVQ AX, rb<>+0(FP) - self.Emit("MOVQ", _BX, _ARG_vp) // MOVQ BX, vp<>+8(FP) - self.Emit("MOVQ", _CX, _ARG_sb) // MOVQ CX, sb<>+16(FP) - self.Emit("MOVQ", _DI, _ARG_fv) // MOVQ DI, rb<>+24(FP) - self.Emit("MOVQ", jit.Ptr(_AX, 0), _RP) // MOVQ (AX) , DI - self.Emit("MOVQ", jit.Ptr(_AX, 8), _RL) // MOVQ 8(AX) , SI - self.Emit("MOVQ", jit.Ptr(_AX, 16), _RC) // MOVQ 16(AX), DX - self.Emit("MOVQ", _BX, _SP_p) // MOVQ BX, R10 - self.Emit("MOVQ", _CX, _ST) // MOVQ CX, R8 - self.Emit("XORL", _SP_x, _SP_x) // XORL R10, R12 - self.Emit("XORL", _SP_f, _SP_f) // XORL R11, R13 - self.Emit("XORL", _SP_q, _SP_q) // XORL R13, R11 -} - -/** Assembler Inline Functions **/ - -func (self *_Assembler) xsave(reg ...obj.Addr) { - for i, v := range reg { - if i > _FP_saves / 8 - 1 { - panic("too many registers to save") - } else { - self.Emit("MOVQ", v, jit.Ptr(_SP, _FP_fargs + int64(i) * 8)) - } - } -} - -func (self *_Assembler) xload(reg ...obj.Addr) { - for i, v := range reg { - if i > _FP_saves / 8 - 1 { - panic("too many registers to load") - } else { - self.Emit("MOVQ", jit.Ptr(_SP, _FP_fargs + int64(i) * 8), v) - } - } -} - -func (self *_Assembler) rbuf_di() { - if _RP.Reg != x86.REG_DI { - panic("register allocation messed up: RP != DI") - } else { - self.Emit("ADDQ", _RL, _RP) - } -} - -func (self *_Assembler) store_int(nd int, fn obj.Addr, ins string) { - self.check_size(nd) - self.save_c() // SAVE $C_regs - self.rbuf_di() // MOVQ RP, DI - self.Emit(ins, jit.Ptr(_SP_p, 0), _SI) // $ins (SP.p), SI - self.call_c(fn) // CALL_C $fn - self.Emit("ADDQ", _AX, _RL) // ADDQ AX, RL -} - -func (self *_Assembler) store_str(s string) { - i := 0 - m := rt.Str2Mem(s) - - /* 8-byte stores */ - for i <= len(m) - 8 { - self.Emit("MOVQ", jit.Imm(rt.Get64(m[i:])), _AX) // MOVQ $s[i:], AX - self.Emit("MOVQ", _AX, jit.Sib(_RP, _RL, 1, int64(i))) // MOVQ AX, i(RP)(RL) - i += 8 - } - - /* 4-byte stores */ - if i <= len(m) - 4 { - self.Emit("MOVL", jit.Imm(int64(rt.Get32(m[i:]))), jit.Sib(_RP, _RL, 1, int64(i))) // MOVL $s[i:], i(RP)(RL) - i += 4 - } - - /* 2-byte stores */ - if i <= len(m) - 2 { - self.Emit("MOVW", jit.Imm(int64(rt.Get16(m[i:]))), jit.Sib(_RP, _RL, 1, int64(i))) // MOVW $s[i:], i(RP)(RL) - i += 2 - } - - /* last byte */ - if i < len(m) { - self.Emit("MOVB", jit.Imm(int64(m[i])), jit.Sib(_RP, _RL, 1, int64(i))) // MOVB $s[i:], i(RP)(RL) - } -} - -func (self *_Assembler) check_size(n int) { - self.check_size_rl(jit.Ptr(_RL, int64(n))) -} - -func (self *_Assembler) check_size_r(r obj.Addr, d int) { - self.check_size_rl(jit.Sib(_RL, r, 1, int64(d))) -} - -func (self *_Assembler) check_size_rl(v obj.Addr) { - idx := self.x - key := _LB_more_space_return + strconv.Itoa(idx) - - /* the following code relies on LR == R9 to work */ - if _LR.Reg != x86.REG_R9 { - panic("register allocation messed up: LR != R9") - } - - /* check for buffer capacity */ - self.x++ - self.Emit("LEAQ", v, _AX) // LEAQ $v, AX - self.Emit("CMPQ", _AX, _RC) // CMPQ AX, RC - self.Sjmp("JBE" , key) // JBE _more_space_return_{n} - self.slice_grow_ax(key) // GROW $key - self.Link(key) // _more_space_return_{n}: -} - -func (self *_Assembler) slice_grow_ax(ret string) { - self.Byte(0x4c, 0x8d, 0x0d) // LEAQ ?(PC), R9 - self.Sref(ret, 4) // .... &ret - self.Sjmp("JMP" , _LB_more_space) // JMP _more_space -} - -/** State Stack Helpers **/ - -const ( - _StateSize = int64(unsafe.Sizeof(_State{})) - _StackLimit = _MaxStack * _StateSize -) - -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("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.WritePtr(0, _SP_p, jit.Sib(_ST, _CX, 1, 24)) // MOVQ SP.p, 24(ST)(CX) - self.WritePtr(1, _SP_q, jit.Sib(_ST, _CX, 1, 32)) // MOVQ SP.q, 32(ST)(CX) - self.Emit("MOVQ", _R9, jit.Ptr(_ST, 0)) // MOVQ R9, (ST) -} - -func (self *_Assembler) drop_state(decr int64) { - self.Emit("MOVQ" , jit.Ptr(_ST, 0), _AX) // MOVQ (ST), AX - self.Emit("SUBQ" , jit.Imm(decr), _AX) // SUBQ $decr, AX - self.Emit("MOVQ" , _AX, jit.Ptr(_ST, 0)) // MOVQ AX, (ST) - self.Emit("MOVQ" , jit.Sib(_ST, _AX, 1, 8), _SP_x) // MOVQ 8(ST)(AX), SP.x - self.Emit("MOVQ" , jit.Sib(_ST, _AX, 1, 16), _SP_f) // MOVQ 16(ST)(AX), SP.f - self.Emit("MOVQ" , jit.Sib(_ST, _AX, 1, 24), _SP_p) // MOVQ 24(ST)(AX), SP.p - self.Emit("MOVQ" , jit.Sib(_ST, _AX, 1, 32), _SP_q) // MOVQ 32(ST)(AX), SP.q - self.Emit("PXOR" , _X0, _X0) // PXOR X0, X0 - self.Emit("MOVOU", _X0, jit.Sib(_ST, _AX, 1, 8)) // MOVOU X0, 8(ST)(AX) - self.Emit("MOVOU", _X0, jit.Sib(_ST, _AX, 1, 24)) // MOVOU X0, 24(ST)(AX) -} - -/** Buffer Helpers **/ - -func (self *_Assembler) add_char(ch byte) { - self.Emit("MOVB", jit.Imm(int64(ch)), jit.Sib(_RP, _RL, 1, 0)) // MOVB $ch, (RP)(RL) - self.Emit("ADDQ", jit.Imm(1), _RL) // ADDQ $1, RL -} - -func (self *_Assembler) add_long(ch uint32, n int64) { - self.Emit("MOVL", jit.Imm(int64(ch)), jit.Sib(_RP, _RL, 1, 0)) // MOVL $ch, (RP)(RL) - self.Emit("ADDQ", jit.Imm(n), _RL) // ADDQ $n, RL -} - -func (self *_Assembler) add_text(ss string) { - self.store_str(ss) // TEXT $ss - self.Emit("ADDQ", jit.Imm(int64(len(ss))), _RL) // ADDQ ${len(ss)}, RL -} - -// get *buf at AX -func (self *_Assembler) prep_buffer_AX() { - self.Emit("MOVQ", _ARG_rb, _AX) // MOVQ rb<>+0(FP), AX - self.Emit("MOVQ", _RL, jit.Ptr(_AX, 8)) // MOVQ RL, 8(AX) -} - -func (self *_Assembler) save_buffer() { - self.Emit("MOVQ", _ARG_rb, _CX) // MOVQ rb<>+0(FP), CX - self.Emit("MOVQ", _RP, jit.Ptr(_CX, 0)) // MOVQ RP, (CX) - self.Emit("MOVQ", _RL, jit.Ptr(_CX, 8)) // MOVQ RL, 8(CX) - self.Emit("MOVQ", _RC, jit.Ptr(_CX, 16)) // MOVQ RC, 16(CX) -} - -// get *buf at AX -func (self *_Assembler) load_buffer_AX() { - self.Emit("MOVQ", _ARG_rb, _AX) // MOVQ rb<>+0(FP), AX - self.Emit("MOVQ", jit.Ptr(_AX, 0), _RP) // MOVQ (AX), RP - self.Emit("MOVQ", jit.Ptr(_AX, 8), _RL) // MOVQ 8(AX), RL - self.Emit("MOVQ", jit.Ptr(_AX, 16), _RC) // MOVQ 16(AX), RC -} - -/** Function Interface Helpers **/ - -func (self *_Assembler) call(pc obj.Addr) { - self.Emit("MOVQ", pc, _LR) // MOVQ $pc, AX - self.Rjmp("CALL", _LR) // CALL AX -} - -func (self *_Assembler) save_c() { - self.xsave(_REG_ffi...) // SAVE $REG_ffi -} - -func (self *_Assembler) call_b64(pc obj.Addr) { - self.xsave(_REG_b64...) // SAVE $REG_all - self.call(pc) // CALL $pc - self.xload(_REG_b64...) // LOAD $REG_ffi -} - -func (self *_Assembler) call_c(pc obj.Addr) { - self.Emit("XCHGQ", _SP_p, _BX) - self.Emit("XCHGQ", _SP_q, _BP) - self.call(pc) // CALL $pc - self.xload(_REG_ffi...) // LOAD $REG_ffi - self.Emit("XCHGQ", _SP_p, _BX) - self.Emit("XCHGQ", _SP_q, _BP) -} - -func (self *_Assembler) call_go(pc obj.Addr) { - self.xsave(_REG_all...) // SAVE $REG_all - self.call(pc) // CALL $pc - self.xload(_REG_all...) // LOAD $REG_all -} - -func (self *_Assembler) call_more_space(pc obj.Addr) { - self.xsave(_REG_ms...) // SAVE $REG_all - self.call(pc) // CALL $pc - self.xload(_REG_ms...) // LOAD $REG_all -} - -func (self *_Assembler) call_encoder(pc obj.Addr) { - self.xsave(_REG_enc...) // SAVE $REG_all - self.call(pc) // CALL $pc - self.xload(_REG_enc...) // LOAD $REG_all -} - -func (self *_Assembler) call_marshaler(fn obj.Addr, it *rt.GoType, vt reflect.Type) { - switch vt.Kind() { - case reflect.Interface : self.call_marshaler_i(fn, it) - case reflect.Ptr, reflect.Map : self.call_marshaler_v(fn, it, vt, true) - // struct/array of 1 direct iface type can be direct - default : self.call_marshaler_v(fn, it, vt, !rt.UnpackType(vt).Indirect()) - } -} - -func (self *_Assembler) call_marshaler_i(fn obj.Addr, it *rt.GoType) { - self.Emit("MOVQ" , jit.Ptr(_SP_p, 0), _AX) // MOVQ (SP.p), AX - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JZ" , "_null_{n}") // JZ _null_{n} - self.Emit("MOVQ" , _AX, _BX) // MOVQ AX, BX - self.Emit("MOVQ" , jit.Ptr(_SP_p, 8), _CX) // MOVQ 8(SP.p), CX - self.Emit("MOVQ" , jit.Gtype(it), _AX) // MOVQ $it, AX - self.call_go(_F_assertI2I) // CALL_GO assertI2I - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JZ" , "_null_{n}") // JZ _null_{n} - self.Emit("MOVQ", _BX, _CX) // MOVQ BX, CX - self.Emit("MOVQ", _AX, _BX) // MOVQ AX, BX - self.prep_buffer_AX() - self.Emit("MOVQ", _ARG_fv, _DI) // MOVQ ARG.fv, DI - self.call_go(fn) // CALL $fn - self.Emit("TESTQ", _ET, _ET) // TESTQ ET, ET - self.Sjmp("JNZ" , _LB_error) // JNZ _error - self.load_buffer_AX() - self.Sjmp("JMP" , "_done_{n}") // JMP _done_{n} - self.Link("_null_{n}") // _null_{n}: - self.check_size(4) // SIZE $4 - self.Emit("MOVL", jit.Imm(_IM_null), jit.Sib(_RP, _RL, 1, 0)) // MOVL $'null', (RP)(RL*1) - self.Emit("ADDQ", jit.Imm(4), _RL) // ADDQ $4, RL - self.Link("_done_{n}") // _done_{n}: -} - -func (self *_Assembler) call_marshaler_v(fn obj.Addr, it *rt.GoType, vt reflect.Type, deref bool) { - self.prep_buffer_AX() // MOVE {buf}, (SP) - self.Emit("MOVQ", jit.Itab(it, vt), _BX) // MOVQ $(itab(it, vt)), BX - - /* dereference the pointer if needed */ - if !deref { - self.Emit("MOVQ", _SP_p, _CX) // MOVQ SP.p, CX - } else { - self.Emit("MOVQ", jit.Ptr(_SP_p, 0), _CX) // MOVQ 0(SP.p), CX - } - - /* call the encoder, and perform error checks */ - self.Emit("MOVQ", _ARG_fv, _DI) // MOVQ ARG.fv, DI - self.call_go(fn) // CALL $fn - self.Emit("TESTQ", _ET, _ET) // TESTQ ET, ET - self.Sjmp("JNZ" , _LB_error) // JNZ _error - self.load_buffer_AX() -} - -/** Builtin: _more_space **/ - -var ( - _T_byte = jit.Type(byteType) - _F_growslice = jit.Func(growslice) -) - -// AX must saving n -func (self *_Assembler) more_space() { - self.Link(_LB_more_space) - self.Emit("MOVQ", _RP, _BX) // MOVQ DI, BX - self.Emit("MOVQ", _RL, _CX) // MOVQ SI, CX - self.Emit("MOVQ", _RC, _DI) // MOVQ DX, DI - self.Emit("MOVQ", _AX, _SI) // MOVQ AX, SI - self.Emit("MOVQ", _T_byte, _AX) // MOVQ $_T_byte, AX - self.call_more_space(_F_growslice) // CALL $pc - self.Emit("MOVQ", _AX, _RP) // MOVQ AX, DI - self.Emit("MOVQ", _BX, _RL) // MOVQ BX, SI - self.Emit("MOVQ", _CX, _RC) // MOVQ CX, DX - self.save_buffer() // SAVE {buf} - self.Rjmp("JMP" , _LR) // JMP LR -} - -/** Builtin Errors **/ - -var ( - _V_ERR_too_deep = jit.Imm(int64(uintptr(unsafe.Pointer(_ERR_too_deep)))) - _V_ERR_nan_or_infinite = jit.Imm(int64(uintptr(unsafe.Pointer(_ERR_nan_or_infinite)))) - _I_json_UnsupportedValueError = jit.Itab(rt.UnpackType(errorType), jsonUnsupportedValueType) -) - -func (self *_Assembler) error_too_deep() { - self.Link(_LB_error_too_deep) - self.Emit("MOVQ", _V_ERR_too_deep, _EP) // MOVQ $_V_ERR_too_deep, EP - self.Emit("MOVQ", _I_json_UnsupportedValueError, _ET) // MOVQ $_I_json_UnsupportedValuError, ET - self.Sjmp("JMP" , _LB_error) // JMP _error -} - -func (self *_Assembler) error_invalid_number() { - self.Link(_LB_error_invalid_number) - self.Emit("MOVQ", jit.Ptr(_SP_p, 0), _AX) // MOVQ 0(SP), AX - self.Emit("MOVQ", jit.Ptr(_SP_p, 8), _BX) // MOVQ 8(SP), BX - self.call_go(_F_error_number) // CALL_GO error_number - self.Sjmp("JMP" , _LB_error) // JMP _error -} - -func (self *_Assembler) error_nan_or_infinite() { - self.Link(_LB_error_nan_or_infinite) - self.Emit("MOVQ", _V_ERR_nan_or_infinite, _EP) // MOVQ $_V_ERR_nan_or_infinite, EP - self.Emit("MOVQ", _I_json_UnsupportedValueError, _ET) // MOVQ $_I_json_UnsupportedValuError, ET - self.Sjmp("JMP" , _LB_error) // JMP _error -} - -/** String Encoding Routine **/ - -var ( - _F_quote = jit.Imm(int64(native.S_quote)) - _F_panic = jit.Func(goPanic) -) - -func (self *_Assembler) go_panic() { - self.Link(_LB_panic) - self.Emit("MOVQ", _SP_p, _BX) - self.call_go(_F_panic) -} - -func (self *_Assembler) encode_string(doubleQuote bool) { - self.Emit("MOVQ" , jit.Ptr(_SP_p, 8), _AX) // MOVQ 8(SP.p), AX - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JZ" , "_str_empty_{n}") // JZ _str_empty_{n} - self.Emit("CMPQ", jit.Ptr(_SP_p, 0), jit.Imm(0)) - self.Sjmp("JNE" , "_str_next_{n}") - self.Emit("MOVQ", jit.Imm(int64(panicNilPointerOfNonEmptyString)), _AX) - self.Sjmp("JMP", _LB_panic) - self.Link("_str_next_{n}") - - /* openning quote, check for double quote */ - if !doubleQuote { - self.check_size_r(_AX, 2) // SIZE $2 - self.add_char('"') // CHAR $'"' - } else { - self.check_size_r(_AX, 6) // SIZE $6 - self.add_long(_IM_open, 3) // TEXT $`"\"` - } - - /* quoting loop */ - self.Emit("XORL", _AX, _AX) // XORL AX, AX - self.Emit("MOVQ", _AX, _VAR_sp) // MOVQ AX, sp - self.Link("_str_loop_{n}") // _str_loop_{n}: - self.save_c() // SAVE $REG_ffi - - /* load the output buffer first, and then input buffer, - * because the parameter registers collide with RP / RL / RC */ - self.Emit("MOVQ", _RC, _CX) // MOVQ RC, CX - self.Emit("SUBQ", _RL, _CX) // SUBQ RL, CX - self.Emit("MOVQ", _CX, _VAR_dn) // MOVQ CX, dn - self.Emit("LEAQ", jit.Sib(_RP, _RL, 1, 0), _DX) // LEAQ (RP)(RL), DX - self.Emit("LEAQ", _VAR_dn, _CX) // LEAQ dn, CX - self.Emit("MOVQ", _VAR_sp, _AX) // MOVQ sp, AX - self.Emit("MOVQ", jit.Ptr(_SP_p, 0), _DI) // MOVQ (SP.p), DI - self.Emit("MOVQ", jit.Ptr(_SP_p, 8), _SI) // MOVQ 8(SP.p), SI - self.Emit("ADDQ", _AX, _DI) // ADDQ AX, DI - self.Emit("SUBQ", _AX, _SI) // SUBQ AX, SI - - /* set the flags based on `doubleQuote` */ - if !doubleQuote { - self.Emit("XORL", _R8, _R8) // XORL R8, R8 - } else { - self.Emit("MOVL", jit.Imm(types.F_DOUBLE_UNQUOTE), _R8) // MOVL ${types.F_DOUBLE_UNQUOTE}, R8 - } - - /* call the native quoter */ - self.call_c(_F_quote) // CALL quote - self.Emit("ADDQ" , _VAR_dn, _RL) // ADDQ dn, RL - - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JS" , "_str_space_{n}") // JS _str_space_{n} - - /* close the string, check for double quote */ - if !doubleQuote { - self.check_size(1) // SIZE $1 - self.add_char('"') // CHAR $'"' - self.Sjmp("JMP", "_str_end_{n}") // JMP _str_end_{n} - } else { - self.check_size(3) // SIZE $3 - self.add_text("\\\"\"") // TEXT $'\""' - self.Sjmp("JMP", "_str_end_{n}") // JMP _str_end_{n} - } - - /* not enough space to contain the quoted string */ - self.Link("_str_space_{n}") // _str_space_{n}: - self.Emit("NOTQ", _AX) // NOTQ AX - self.Emit("ADDQ", _AX, _VAR_sp) // ADDQ AX, sp - self.Emit("LEAQ", jit.Sib(_RC, _RC, 1, 0), _AX) // LEAQ (RC)(RC), AX - self.slice_grow_ax("_str_loop_{n}") // GROW _str_loop_{n} - - /* empty string, check for double quote */ - if !doubleQuote { - self.Link("_str_empty_{n}") // _str_empty_{n}: - self.check_size(2) // SIZE $2 - self.add_text("\"\"") // TEXT $'""' - self.Link("_str_end_{n}") // _str_end_{n}: - } else { - self.Link("_str_empty_{n}") // _str_empty_{n}: - self.check_size(6) // SIZE $6 - self.add_text("\"\\\"\\\"\"") // TEXT $'"\"\""' - self.Link("_str_end_{n}") // _str_end_{n}: - } -} - -/** OpCode Assembler Functions **/ - -var ( - _T_json_Marshaler = rt.UnpackType(jsonMarshalerType) - _T_encoding_TextMarshaler = rt.UnpackType(encodingTextMarshalerType) -) - -var ( - _F_f64toa = jit.Imm(int64(native.S_f64toa)) - _F_f32toa = jit.Imm(int64(native.S_f32toa)) - _F_i64toa = jit.Imm(int64(native.S_i64toa)) - _F_u64toa = jit.Imm(int64(native.S_u64toa)) - _F_b64encode = jit.Imm(int64(_subr__b64encode)) -) - -var ( - _F_memmove = jit.Func(memmove) - _F_error_number = jit.Func(error_number) - _F_isValidNumber = jit.Func(isValidNumber) -) - -var ( - _F_iteratorStop = jit.Func(iteratorStop) - _F_iteratorNext = jit.Func(iteratorNext) - _F_iteratorStart = jit.Func(iteratorStart) -) - -var ( - _F_encodeTypedPointer obj.Addr - _F_encodeJsonMarshaler obj.Addr - _F_encodeTextMarshaler obj.Addr -) - -const ( - _MODE_AVX2 = 1 << 2 -) - -func init() { - _F_encodeTypedPointer = jit.Func(encodeTypedPointer) - _F_encodeJsonMarshaler = jit.Func(encodeJsonMarshaler) - _F_encodeTextMarshaler = jit.Func(encodeTextMarshaler) -} - -func (self *_Assembler) _asm_OP_null(_ *_Instr) { - self.check_size(4) - self.Emit("MOVL", jit.Imm(_IM_null), jit.Sib(_RP, _RL, 1, 0)) // MOVL $'null', (RP)(RL*1) - self.Emit("ADDQ", jit.Imm(4), _RL) // ADDQ $4, RL -} - -func (self *_Assembler) _asm_OP_empty_arr(_ *_Instr) { - self.Emit("BTQ", jit.Imm(int64(bitNoNullSliceOrMap)), _ARG_fv) - self.Sjmp("JC", "_empty_arr_{n}") - self._asm_OP_null(nil) - self.Sjmp("JMP", "_empty_arr_end_{n}") - self.Link("_empty_arr_{n}") - self.check_size(2) - self.Emit("MOVW", jit.Imm(_IM_array), jit.Sib(_RP, _RL, 1, 0)) - self.Emit("ADDQ", jit.Imm(2), _RL) - self.Link("_empty_arr_end_{n}") -} - -func (self *_Assembler) _asm_OP_empty_obj(_ *_Instr) { - self.Emit("BTQ", jit.Imm(int64(bitNoNullSliceOrMap)), _ARG_fv) - self.Sjmp("JC", "_empty_obj_{n}") - self._asm_OP_null(nil) - self.Sjmp("JMP", "_empty_obj_end_{n}") - self.Link("_empty_obj_{n}") - self.check_size(2) - self.Emit("MOVW", jit.Imm(_IM_object), jit.Sib(_RP, _RL, 1, 0)) - self.Emit("ADDQ", jit.Imm(2), _RL) - self.Link("_empty_obj_end_{n}") -} - -func (self *_Assembler) _asm_OP_bool(_ *_Instr) { - self.Emit("CMPB", jit.Ptr(_SP_p, 0), jit.Imm(0)) // CMPB (SP.p), $0 - self.Sjmp("JE" , "_false_{n}") // JE _false_{n} - self.check_size(4) // SIZE $4 - self.Emit("MOVL", jit.Imm(_IM_true), jit.Sib(_RP, _RL, 1, 0)) // MOVL $'true', (RP)(RL*1) - self.Emit("ADDQ", jit.Imm(4), _RL) // ADDQ $4, RL - self.Sjmp("JMP" , "_end_{n}") // JMP _end_{n} - self.Link("_false_{n}") // _false_{n}: - self.check_size(5) // SIZE $5 - self.Emit("MOVL", jit.Imm(_IM_fals), jit.Sib(_RP, _RL, 1, 0)) // MOVL $'fals', (RP)(RL*1) - self.Emit("MOVB", jit.Imm('e'), jit.Sib(_RP, _RL, 1, 4)) // MOVB $'e', 4(RP)(RL*1) - self.Emit("ADDQ", jit.Imm(5), _RL) // ADDQ $5, RL - self.Link("_end_{n}") // _end_{n}: -} - -func (self *_Assembler) _asm_OP_i8(_ *_Instr) { - self.store_int(4, _F_i64toa, "MOVBQSX") -} - -func (self *_Assembler) _asm_OP_i16(_ *_Instr) { - self.store_int(6, _F_i64toa, "MOVWQSX") -} - -func (self *_Assembler) _asm_OP_i32(_ *_Instr) { - self.store_int(17, _F_i64toa, "MOVLQSX") -} - -func (self *_Assembler) _asm_OP_i64(_ *_Instr) { - self.store_int(21, _F_i64toa, "MOVQ") -} - -func (self *_Assembler) _asm_OP_u8(_ *_Instr) { - self.store_int(3, _F_u64toa, "MOVBQZX") -} - -func (self *_Assembler) _asm_OP_u16(_ *_Instr) { - self.store_int(5, _F_u64toa, "MOVWQZX") -} - -func (self *_Assembler) _asm_OP_u32(_ *_Instr) { - self.store_int(16, _F_u64toa, "MOVLQZX") -} - -func (self *_Assembler) _asm_OP_u64(_ *_Instr) { - self.store_int(20, _F_u64toa, "MOVQ") -} - -func (self *_Assembler) _asm_OP_f32(_ *_Instr) { - self.check_size(32) - self.Emit("MOVL" , jit.Ptr(_SP_p, 0), _AX) // MOVL (SP.p), AX - self.Emit("ANDL" , jit.Imm(_FM_exp32), _AX) // ANDL $_FM_exp32, AX - self.Emit("XORL" , jit.Imm(_FM_exp32), _AX) // XORL $_FM_exp32, AX - self.Sjmp("JZ" , _LB_error_nan_or_infinite) // JZ _error_nan_or_infinite - self.save_c() // SAVE $C_regs - self.rbuf_di() // MOVQ RP, DI - self.Emit("MOVSS" , jit.Ptr(_SP_p, 0), _X0) // MOVSS (SP.p), X0 - self.call_c(_F_f32toa) // CALL_C f64toa - self.Emit("ADDQ" , _AX, _RL) // ADDQ AX, RL -} - -func (self *_Assembler) _asm_OP_f64(_ *_Instr) { - self.check_size(32) - self.Emit("MOVQ" , jit.Ptr(_SP_p, 0), _AX) // MOVQ (SP.p), AX - self.Emit("MOVQ" , jit.Imm(_FM_exp64), _CX) // MOVQ $_FM_exp64, CX - self.Emit("ANDQ" , _CX, _AX) // ANDQ CX, AX - self.Emit("XORQ" , _CX, _AX) // XORQ CX, AX - self.Sjmp("JZ" , _LB_error_nan_or_infinite) // JZ _error_nan_or_infinite - self.save_c() // SAVE $C_regs - self.rbuf_di() // MOVQ RP, DI - self.Emit("MOVSD" , jit.Ptr(_SP_p, 0), _X0) // MOVSD (SP.p), X0 - self.call_c(_F_f64toa) // CALL_C f64toa - self.Emit("ADDQ" , _AX, _RL) // ADDQ AX, RL -} - -func (self *_Assembler) _asm_OP_str(_ *_Instr) { - self.encode_string(false) -} - -func (self *_Assembler) _asm_OP_bin(_ *_Instr) { - self.Emit("MOVQ", jit.Ptr(_SP_p, 8), _AX) // MOVQ 8(SP.p), AX - self.Emit("ADDQ", jit.Imm(2), _AX) // ADDQ $2, AX - self.Emit("MOVQ", jit.Imm(_IM_mulv), _CX) // MOVQ $_MF_mulv, CX - self.Emit("MOVQ", _DX, _BX) // MOVQ DX, BX - self.From("MULQ", _CX) // MULQ CX - self.Emit("LEAQ", jit.Sib(_DX, _DX, 1, 1), _AX) // LEAQ 1(DX)(DX), AX - self.Emit("ORQ" , jit.Imm(2), _AX) // ORQ $2, AX - self.Emit("MOVQ", _BX, _DX) // MOVQ BX, DX - self.check_size_r(_AX, 0) // SIZE AX - self.add_char('"') // CHAR $'"' - self.Emit("MOVQ", _ARG_rb, _DI) // MOVQ rb<>+0(FP), DI - self.Emit("MOVQ", _RL, jit.Ptr(_DI, 8)) // MOVQ SI, 8(DI) - self.Emit("MOVQ", _SP_p, _SI) // MOVQ SP.p, SI - - /* check for AVX2 support */ - if !cpu.HasAVX2 { - self.Emit("XORL", _DX, _DX) // XORL DX, DX - } else { - self.Emit("MOVL", jit.Imm(_MODE_AVX2), _DX) // MOVL $_MODE_AVX2, DX - } - - /* call the encoder */ - self.call_b64(_F_b64encode) // CALL b64encode - self.load_buffer_AX() // LOAD {buf} - self.add_char('"') // CHAR $'"' -} - -func (self *_Assembler) _asm_OP_quote(_ *_Instr) { - self.encode_string(true) -} - -func (self *_Assembler) _asm_OP_number(_ *_Instr) { - self.Emit("MOVQ" , jit.Ptr(_SP_p, 8), _BX) // MOVQ (SP.p), BX - self.Emit("TESTQ", _BX, _BX) // TESTQ BX, BX - self.Sjmp("JZ" , "_empty_{n}") - self.Emit("MOVQ" , jit.Ptr(_SP_p, 0), _AX) // MOVQ (SP.p), AX - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JNZ" , "_number_next_{n}") - self.Emit("MOVQ", jit.Imm(int64(panicNilPointerOfNonEmptyString)), _AX) - self.Sjmp("JMP", _LB_panic) - self.Link("_number_next_{n}") - self.call_go(_F_isValidNumber) // CALL_GO isValidNumber - self.Emit("CMPB" , _AX, jit.Imm(0)) // CMPB AX, $0 - self.Sjmp("JE" , _LB_error_invalid_number) // JE _error_invalid_number - self.Emit("MOVQ" , jit.Ptr(_SP_p, 8), _BX) // MOVQ (SP.p), BX - self.check_size_r(_BX, 0) // SIZE BX - self.Emit("LEAQ" , jit.Sib(_RP, _RL, 1, 0), _AX) // LEAQ (RP)(RL), AX - self.Emit("ADDQ" , jit.Ptr(_SP_p, 8), _RL) // ADDQ 8(SP.p), RL - self.Emit("MOVQ", jit.Ptr(_SP_p, 0), _BX) // MOVOU (SP.p), BX - self.Emit("MOVQ", jit.Ptr(_SP_p, 8), _CX) // MOVOU X0, 8(SP) - self.call_go(_F_memmove) // CALL_GO memmove - self.Emit("MOVQ", _ARG_rb, _AX) // MOVQ rb<>+0(FP), AX - self.Emit("MOVQ", _RL, jit.Ptr(_AX, 8)) // MOVQ RL, 8(AX) - self.Sjmp("JMP" , "_done_{n}") // JMP _done_{n} - self.Link("_empty_{n}") // _empty_{n} - self.check_size(1) // SIZE $1 - self.add_char('0') // CHAR $'0' - self.Link("_done_{n}") // _done_{n}: -} - -func (self *_Assembler) _asm_OP_eface(_ *_Instr) { - self.prep_buffer_AX() // MOVE {buf}, AX - self.Emit("MOVQ" , jit.Ptr(_SP_p, 0), _BX) // MOVQ (SP.p), BX - self.Emit("LEAQ" , jit.Ptr(_SP_p, 8), _CX) // LEAQ 8(SP.p), CX - self.Emit("MOVQ" , _ST, _DI) // MOVQ ST, DI - self.Emit("MOVQ" , _ARG_fv, _SI) // MOVQ fv, AX - self.call_encoder(_F_encodeTypedPointer) // CALL encodeTypedPointer - self.Emit("TESTQ", _ET, _ET) // TESTQ ET, ET - self.Sjmp("JNZ" , _LB_error) // JNZ _error - self.load_buffer_AX() -} - -func (self *_Assembler) _asm_OP_iface(_ *_Instr) { - self.prep_buffer_AX() // MOVE {buf}, AX - self.Emit("MOVQ" , jit.Ptr(_SP_p, 0), _CX) // MOVQ (SP.p), CX - self.Emit("MOVQ" , jit.Ptr(_CX, 8), _BX) // MOVQ 8(CX), BX - self.Emit("LEAQ" , jit.Ptr(_SP_p, 8), _CX) // LEAQ 8(SP.p), CX - self.Emit("MOVQ" , _ST, _DI) // MOVQ ST, DI - self.Emit("MOVQ" , _ARG_fv, _SI) // MOVQ fv, AX - self.call_encoder(_F_encodeTypedPointer) // CALL encodeTypedPointer - self.Emit("TESTQ", _ET, _ET) // TESTQ ET, ET - self.Sjmp("JNZ" , _LB_error) // JNZ _error - self.load_buffer_AX() -} - -func (self *_Assembler) _asm_OP_byte(p *_Instr) { - self.check_size(1) - self.Emit("MOVB", jit.Imm(p.i64()), jit.Sib(_RP, _RL, 1, 0)) // MOVL p.vi(), (RP)(RL*1) - self.Emit("ADDQ", jit.Imm(1), _RL) // ADDQ $1, RL -} - -func (self *_Assembler) _asm_OP_text(p *_Instr) { - self.check_size(len(p.vs())) // SIZE ${len(p.vs())} - self.add_text(p.vs()) // TEXT ${p.vs()} -} - -func (self *_Assembler) _asm_OP_deref(_ *_Instr) { - self.Emit("MOVQ", jit.Ptr(_SP_p, 0), _SP_p) // MOVQ (SP.p), SP.p -} - -func (self *_Assembler) _asm_OP_index(p *_Instr) { - self.Emit("MOVQ", jit.Imm(p.i64()), _AX) // MOVQ $p.vi(), AX - self.Emit("ADDQ", _AX, _SP_p) // ADDQ AX, SP.p -} - -func (self *_Assembler) _asm_OP_load(_ *_Instr) { - self.Emit("MOVQ", jit.Ptr(_ST, 0), _AX) // MOVQ (ST), AX - self.Emit("MOVQ", jit.Sib(_ST, _AX, 1, -24), _SP_x) // MOVQ -24(ST)(AX), SP.x - self.Emit("MOVQ", jit.Sib(_ST, _AX, 1, -8), _SP_p) // MOVQ -8(ST)(AX), SP.p - self.Emit("MOVQ", jit.Sib(_ST, _AX, 1, 0), _SP_q) // MOVQ (ST)(AX), SP.q -} - -func (self *_Assembler) _asm_OP_save(_ *_Instr) { - self.save_state() -} - -func (self *_Assembler) _asm_OP_drop(_ *_Instr) { - self.drop_state(_StateSize) -} - -func (self *_Assembler) _asm_OP_drop_2(_ *_Instr) { - self.drop_state(_StateSize * 2) // DROP $(_StateSize * 2) - self.Emit("MOVOU", _X0, jit.Sib(_ST, _AX, 1, 56)) // MOVOU X0, 56(ST)(AX) -} - -func (self *_Assembler) _asm_OP_recurse(p *_Instr) { - self.prep_buffer_AX() // MOVE {buf}, (SP) - vt, pv := p.vp() - self.Emit("MOVQ", jit.Type(vt), _BX) // MOVQ $(type(p.vt())), BX - - /* check for indirection */ - if !rt.UnpackType(vt).Indirect() { - self.Emit("MOVQ", _SP_p, _CX) // MOVQ SP.p, CX - } else { - self.Emit("MOVQ", _SP_p, _VAR_vp) // MOVQ SP.p, VAR.vp - self.Emit("LEAQ", _VAR_vp, _CX) // LEAQ VAR.vp, CX - } - - /* call the encoder */ - self.Emit("MOVQ" , _ST, _DI) // MOVQ ST, DI - self.Emit("MOVQ" , _ARG_fv, _SI) // MOVQ $fv, SI - if pv { - self.Emit("BTCQ", jit.Imm(bitPointerValue), _SI) // BTCQ $1, SI - } - self.call_encoder(_F_encodeTypedPointer) // CALL encodeTypedPointer - self.Emit("TESTQ", _ET, _ET) // TESTQ ET, ET - self.Sjmp("JNZ" , _LB_error) // JNZ _error - self.load_buffer_AX() -} - -func (self *_Assembler) _asm_OP_is_nil(p *_Instr) { - self.Emit("CMPQ", jit.Ptr(_SP_p, 0), jit.Imm(0)) // CMPQ (SP.p), $0 - self.Xjmp("JE" , p.vi()) // JE p.vi() -} - -func (self *_Assembler) _asm_OP_is_nil_p1(p *_Instr) { - self.Emit("CMPQ", jit.Ptr(_SP_p, 8), jit.Imm(0)) // CMPQ 8(SP.p), $0 - self.Xjmp("JE" , p.vi()) // JE p.vi() -} - -func (self *_Assembler) _asm_OP_is_zero_1(p *_Instr) { - self.Emit("CMPB", jit.Ptr(_SP_p, 0), jit.Imm(0)) // CMPB (SP.p), $0 - self.Xjmp("JE" , p.vi()) // JE p.vi() -} - -func (self *_Assembler) _asm_OP_is_zero_2(p *_Instr) { - self.Emit("CMPW", jit.Ptr(_SP_p, 0), jit.Imm(0)) // CMPW (SP.p), $0 - self.Xjmp("JE" , p.vi()) // JE p.vi() -} - -func (self *_Assembler) _asm_OP_is_zero_4(p *_Instr) { - self.Emit("CMPL", jit.Ptr(_SP_p, 0), jit.Imm(0)) // CMPL (SP.p), $0 - self.Xjmp("JE" , p.vi()) // JE p.vi() -} - -func (self *_Assembler) _asm_OP_is_zero_8(p *_Instr) { - self.Emit("CMPQ", jit.Ptr(_SP_p, 0), jit.Imm(0)) // CMPQ (SP.p), $0 - self.Xjmp("JE" , p.vi()) // JE p.vi() -} - -func (self *_Assembler) _asm_OP_is_zero_map(p *_Instr) { - self.Emit("MOVQ" , jit.Ptr(_SP_p, 0), _AX) // MOVQ (SP.p), AX - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Xjmp("JZ" , p.vi()) // JZ p.vi() - self.Emit("CMPQ" , jit.Ptr(_AX, 0), jit.Imm(0)) // CMPQ (AX), $0 - self.Xjmp("JE" , p.vi()) // JE p.vi() -} - -func (self *_Assembler) _asm_OP_goto(p *_Instr) { - self.Xjmp("JMP", p.vi()) -} - -func (self *_Assembler) _asm_OP_map_iter(p *_Instr) { - self.Emit("MOVQ" , jit.Type(p.vt()), _AX) // MOVQ $p.vt(), AX - self.Emit("MOVQ" , jit.Ptr(_SP_p, 0), _BX) // MOVQ (SP.p), BX - self.Emit("MOVQ" , _ARG_fv, _CX) // MOVQ fv, CX - self.call_go(_F_iteratorStart) // CALL_GO iteratorStart - self.Emit("MOVQ" , _AX, _SP_q) // MOVQ AX, SP.q - self.Emit("MOVQ" , _BX, _ET) // MOVQ 32(SP), ET - self.Emit("MOVQ" , _CX, _EP) // MOVQ 40(SP), EP - self.Emit("TESTQ", _ET, _ET) // TESTQ ET, ET - self.Sjmp("JNZ" , _LB_error) // JNZ _error -} - -func (self *_Assembler) _asm_OP_map_stop(_ *_Instr) { - self.Emit("MOVQ", _SP_q, _AX) // MOVQ SP.q, AX - self.call_go(_F_iteratorStop) // CALL_GO iteratorStop - self.Emit("XORL", _SP_q, _SP_q) // XORL SP.q, SP.q -} - -func (self *_Assembler) _asm_OP_map_check_key(p *_Instr) { - self.Emit("MOVQ" , jit.Ptr(_SP_q, 0), _SP_p) // MOVQ (SP.q), SP.p - self.Emit("TESTQ", _SP_p, _SP_p) // TESTQ SP.p, SP.p - self.Xjmp("JZ" , p.vi()) // JNZ p.vi() -} - -func (self *_Assembler) _asm_OP_map_write_key(p *_Instr) { - self.Emit("BTQ", jit.Imm(bitSortMapKeys), _ARG_fv) // BTQ ${SortMapKeys}, fv - self.Sjmp("JNC", "_unordered_key_{n}") // JNC _unordered_key_{n} - self.encode_string(false) // STR $false - self.Xjmp("JMP", p.vi()) // JMP ${p.vi()} - self.Link("_unordered_key_{n}") // _unordered_key_{n}: -} - -func (self *_Assembler) _asm_OP_map_value_next(_ *_Instr) { - self.Emit("MOVQ", jit.Ptr(_SP_q, 8), _SP_p) // MOVQ 8(SP.q), SP.p - self.Emit("MOVQ", _SP_q, _AX) // MOVQ SP.q, AX - self.call_go(_F_iteratorNext) // CALL_GO iteratorNext -} - -func (self *_Assembler) _asm_OP_slice_len(_ *_Instr) { - self.Emit("MOVQ" , jit.Ptr(_SP_p, 8), _SP_x) // MOVQ 8(SP.p), SP.x - self.Emit("MOVQ" , jit.Ptr(_SP_p, 0), _SP_p) // MOVQ (SP.p), SP.p - self.Emit("ORQ" , jit.Imm(1 << _S_init), _SP_f) // ORQ $(1<<_S_init), SP.f -} - -func (self *_Assembler) _asm_OP_slice_next(p *_Instr) { - self.Emit("TESTQ" , _SP_x, _SP_x) // TESTQ SP.x, SP.x - self.Xjmp("JZ" , p.vi()) // JZ p.vi() - self.Emit("SUBQ" , jit.Imm(1), _SP_x) // SUBQ $1, SP.x - self.Emit("BTRQ" , jit.Imm(_S_init), _SP_f) // BTRQ $_S_init, SP.f - self.Emit("LEAQ" , jit.Ptr(_SP_p, int64(p.vlen())), _AX) // LEAQ $(p.vlen())(SP.p), AX - self.Emit("CMOVQCC", _AX, _SP_p) // CMOVQNC AX, SP.p -} - -func (self *_Assembler) _asm_OP_marshal(p *_Instr) { - self.call_marshaler(_F_encodeJsonMarshaler, _T_json_Marshaler, p.vt()) -} - -func (self *_Assembler) _asm_OP_marshal_p(p *_Instr) { - if p.vk() != reflect.Ptr { - panic("marshal_p: invalid type") - } else { - self.call_marshaler_v(_F_encodeJsonMarshaler, _T_json_Marshaler, p.vt(), false) - } -} - -func (self *_Assembler) _asm_OP_marshal_text(p *_Instr) { - self.call_marshaler(_F_encodeTextMarshaler, _T_encoding_TextMarshaler, p.vt()) -} - -func (self *_Assembler) _asm_OP_marshal_text_p(p *_Instr) { - if p.vk() != reflect.Ptr { - panic("marshal_text_p: invalid type") - } else { - self.call_marshaler_v(_F_encodeTextMarshaler, _T_encoding_TextMarshaler, p.vt(), false) - } -} - -func (self *_Assembler) _asm_OP_cond_set(_ *_Instr) { - self.Emit("ORQ", jit.Imm(1 << _S_cond), _SP_f) // ORQ $(1<<_S_cond), SP.f -} - -func (self *_Assembler) _asm_OP_cond_testc(p *_Instr) { - self.Emit("BTRQ", jit.Imm(_S_cond), _SP_f) // BTRQ $_S_cond, SP.f - self.Xjmp("JC" , p.vi()) -} - -func (self *_Assembler) print_gc(i int, p1 *_Instr, p2 *_Instr) { - self.Emit("MOVQ", jit.Imm(int64(p2.op())), _CX) // MOVQ $(p2.op()), AX - self.Emit("MOVQ", jit.Imm(int64(p1.op())), _BX) // MOVQ $(p1.op()), BX - self.Emit("MOVQ", jit.Imm(int64(i)), _AX) // MOVQ $(i), CX - self.call_go(_F_println) -} diff --git a/vendor/github.com/bytedance/sonic/internal/encoder/assembler_stkabi_amd64.go b/vendor/github.com/bytedance/sonic/internal/encoder/assembler_stkabi_amd64.go deleted file mode 100644 index 89dafc84e..000000000 --- a/vendor/github.com/bytedance/sonic/internal/encoder/assembler_stkabi_amd64.go +++ /dev/null @@ -1,1175 +0,0 @@ -// +build go1.16,!go1.17 - -/* - * 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 ( - `fmt` - `reflect` - `strconv` - `unsafe` - - `github.com/bytedance/sonic/internal/cpu` - `github.com/bytedance/sonic/internal/jit` - `github.com/bytedance/sonic/internal/native/types` - `github.com/twitchyliquid64/golang-asm/obj` - `github.com/twitchyliquid64/golang-asm/obj/x86` - - `github.com/bytedance/sonic/internal/native` - `github.com/bytedance/sonic/internal/rt` -) - -/** Register Allocations - * - * State Registers: - * - * %rbx : stack base - * %rdi : result pointer - * %rsi : result length - * %rdx : result capacity - * %r12 : sp->p - * %r13 : sp->q - * %r14 : sp->x - * %r15 : sp->f - * - * Error Registers: - * - * %r10 : error type register - * %r11 : error pointer register - */ - -/** Function Prototype & Stack Map - * - * func (buf *[]byte, p unsafe.Pointer, sb *_Stack, fv uint64) (err error) - * - * buf : (FP) - * p : 8(FP) - * sb : 16(FP) - * fv : 24(FP) - * err.vt : 32(FP) - * err.vp : 40(FP) - */ - -const ( - _S_cond = iota - _S_init -) - -const ( - _FP_args = 48 // 48 bytes for passing arguments to this function - _FP_fargs = 64 // 64 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 -) - -const ( - _FP_offs = _FP_fargs + _FP_saves + _FP_locals - _FP_size = _FP_offs + 8 // 8 bytes for the parent frame pointer - _FP_base = _FP_size + 8 // 8 bytes for the return address -) - -const ( - _FM_exp32 = 0x7f800000 - _FM_exp64 = 0x7ff0000000000000 -) - -const ( - _IM_null = 0x6c6c756e // 'null' - _IM_true = 0x65757274 // 'true' - _IM_fals = 0x736c6166 // 'fals' ('false' without the 'e') - _IM_open = 0x00225c22 // '"\"∅' - _IM_array = 0x5d5b // '[]' - _IM_object = 0x7d7b // '{}' - _IM_mulv = -0x5555555555555555 -) - -const ( - _LB_more_space = "_more_space" - _LB_more_space_return = "_more_space_return_" -) - -const ( - _LB_error = "_error" - _LB_error_too_deep = "_error_too_deep" - _LB_error_invalid_number = "_error_invalid_number" - _LB_error_nan_or_infinite = "_error_nan_or_infinite" - _LB_panic = "_panic" -) - -var ( - _AX = jit.Reg("AX") - _CX = jit.Reg("CX") - _DX = jit.Reg("DX") - _DI = jit.Reg("DI") - _SI = jit.Reg("SI") - _BP = jit.Reg("BP") - _SP = jit.Reg("SP") - _R8 = jit.Reg("R8") -) - -var ( - _X0 = jit.Reg("X0") - _Y0 = jit.Reg("Y0") -) - -var ( - _ST = jit.Reg("BX") - _RP = jit.Reg("DI") - _RL = jit.Reg("SI") - _RC = jit.Reg("DX") -) - -var ( - _LR = jit.Reg("R9") - _R10 = jit.Reg("R10") // used for gcWriterBarrier - _ET = jit.Reg("R10") - _EP = jit.Reg("R11") -) - -var ( - _SP_p = jit.Reg("R12") - _SP_q = jit.Reg("R13") - _SP_x = jit.Reg("R14") - _SP_f = jit.Reg("R15") -) - -var ( - _ARG_rb = jit.Ptr(_SP, _FP_base) - _ARG_vp = jit.Ptr(_SP, _FP_base + 8) - _ARG_sb = jit.Ptr(_SP, _FP_base + 16) - _ARG_fv = jit.Ptr(_SP, _FP_base + 24) -) - -var ( - _RET_et = jit.Ptr(_SP, _FP_base + 32) - _RET_ep = jit.Ptr(_SP, _FP_base + 40) -) - -var ( - _VAR_sp = jit.Ptr(_SP, _FP_fargs + _FP_saves) - _VAR_dn = jit.Ptr(_SP, _FP_fargs + _FP_saves + 8) - _VAR_vp = jit.Ptr(_SP, _FP_fargs + _FP_saves + 16) -) - -var ( - _REG_ffi = []obj.Addr{_RP, _RL, _RC} - _REG_enc = []obj.Addr{_ST, _SP_x, _SP_f, _SP_p, _SP_q, _RL} - _REG_jsr = []obj.Addr{_ST, _SP_x, _SP_f, _SP_p, _SP_q, _LR} - _REG_all = []obj.Addr{_ST, _SP_x, _SP_f, _SP_p, _SP_q, _RP, _RL, _RC} -) - -type _Assembler struct { - jit.BaseAssembler - p _Program - x int - name string -} - -func newAssembler(p _Program) *_Assembler { - return new(_Assembler).Init(p) -} - -/** Assembler Interface **/ -func (self *_Assembler) Load() _Encoder { - return ptoenc(self.BaseAssembler.Load("encode_"+self.name, _FP_size, _FP_args, argPtrs, localPtrs)) -} - -func (self *_Assembler) Init(p _Program) *_Assembler { - self.p = p - self.BaseAssembler.Init(self.compile) - return self -} - -func (self *_Assembler) compile() { - self.prologue() - self.instrs() - self.epilogue() - self.builtins() -} - -/** Assembler Stages **/ - -var _OpFuncTab = [256]func(*_Assembler, *_Instr) { - _OP_null : (*_Assembler)._asm_OP_null, - _OP_empty_arr : (*_Assembler)._asm_OP_empty_arr, - _OP_empty_obj : (*_Assembler)._asm_OP_empty_obj, - _OP_bool : (*_Assembler)._asm_OP_bool, - _OP_i8 : (*_Assembler)._asm_OP_i8, - _OP_i16 : (*_Assembler)._asm_OP_i16, - _OP_i32 : (*_Assembler)._asm_OP_i32, - _OP_i64 : (*_Assembler)._asm_OP_i64, - _OP_u8 : (*_Assembler)._asm_OP_u8, - _OP_u16 : (*_Assembler)._asm_OP_u16, - _OP_u32 : (*_Assembler)._asm_OP_u32, - _OP_u64 : (*_Assembler)._asm_OP_u64, - _OP_f32 : (*_Assembler)._asm_OP_f32, - _OP_f64 : (*_Assembler)._asm_OP_f64, - _OP_str : (*_Assembler)._asm_OP_str, - _OP_bin : (*_Assembler)._asm_OP_bin, - _OP_quote : (*_Assembler)._asm_OP_quote, - _OP_number : (*_Assembler)._asm_OP_number, - _OP_eface : (*_Assembler)._asm_OP_eface, - _OP_iface : (*_Assembler)._asm_OP_iface, - _OP_byte : (*_Assembler)._asm_OP_byte, - _OP_text : (*_Assembler)._asm_OP_text, - _OP_deref : (*_Assembler)._asm_OP_deref, - _OP_index : (*_Assembler)._asm_OP_index, - _OP_load : (*_Assembler)._asm_OP_load, - _OP_save : (*_Assembler)._asm_OP_save, - _OP_drop : (*_Assembler)._asm_OP_drop, - _OP_drop_2 : (*_Assembler)._asm_OP_drop_2, - _OP_recurse : (*_Assembler)._asm_OP_recurse, - _OP_is_nil : (*_Assembler)._asm_OP_is_nil, - _OP_is_nil_p1 : (*_Assembler)._asm_OP_is_nil_p1, - _OP_is_zero_1 : (*_Assembler)._asm_OP_is_zero_1, - _OP_is_zero_2 : (*_Assembler)._asm_OP_is_zero_2, - _OP_is_zero_4 : (*_Assembler)._asm_OP_is_zero_4, - _OP_is_zero_8 : (*_Assembler)._asm_OP_is_zero_8, - _OP_is_zero_map : (*_Assembler)._asm_OP_is_zero_map, - _OP_goto : (*_Assembler)._asm_OP_goto, - _OP_map_iter : (*_Assembler)._asm_OP_map_iter, - _OP_map_stop : (*_Assembler)._asm_OP_map_stop, - _OP_map_check_key : (*_Assembler)._asm_OP_map_check_key, - _OP_map_write_key : (*_Assembler)._asm_OP_map_write_key, - _OP_map_value_next : (*_Assembler)._asm_OP_map_value_next, - _OP_slice_len : (*_Assembler)._asm_OP_slice_len, - _OP_slice_next : (*_Assembler)._asm_OP_slice_next, - _OP_marshal : (*_Assembler)._asm_OP_marshal, - _OP_marshal_p : (*_Assembler)._asm_OP_marshal_p, - _OP_marshal_text : (*_Assembler)._asm_OP_marshal_text, - _OP_marshal_text_p : (*_Assembler)._asm_OP_marshal_text_p, - _OP_cond_set : (*_Assembler)._asm_OP_cond_set, - _OP_cond_testc : (*_Assembler)._asm_OP_cond_testc, -} - -func (self *_Assembler) instr(v *_Instr) { - if fn := _OpFuncTab[v.op()]; fn != nil { - fn(self, v) - } else { - panic(fmt.Sprintf("invalid opcode: %d", v.op())) - } -} - -func (self *_Assembler) instrs() { - for i, v := range self.p { - self.Mark(i) - self.instr(&v) - self.debug_instr(i, &v) - } -} - -func (self *_Assembler) builtins() { - self.more_space() - self.error_too_deep() - self.error_invalid_number() - self.error_nan_or_infinite() - self.go_panic() -} - -func (self *_Assembler) epilogue() { - self.Mark(len(self.p)) - self.Emit("XORL", _ET, _ET) - self.Emit("XORL", _EP, _EP) - self.Link(_LB_error) - self.Emit("MOVQ", _ARG_rb, _AX) // MOVQ rb<>+0(FP), AX - self.Emit("MOVQ", _RL, jit.Ptr(_AX, 8)) // MOVQ RL, 8(AX) - self.Emit("MOVQ", _ET, _RET_et) // MOVQ ET, et<>+24(FP) - self.Emit("MOVQ", _EP, _RET_ep) // MOVQ EP, ep<>+32(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 -} - -func (self *_Assembler) prologue() { - self.Emit("SUBQ", jit.Imm(_FP_size), _SP) // SUBQ $_FP_size, SP - self.Emit("MOVQ", _BP, jit.Ptr(_SP, _FP_offs)) // MOVQ BP, _FP_offs(SP) - self.Emit("LEAQ", jit.Ptr(_SP, _FP_offs), _BP) // LEAQ _FP_offs(SP), BP - self.load_buffer() // LOAD {buf} - self.Emit("MOVQ", _ARG_vp, _SP_p) // MOVQ vp<>+8(FP), SP.p - self.Emit("MOVQ", _ARG_sb, _ST) // MOVQ sb<>+16(FP), ST - self.Emit("XORL", _SP_x, _SP_x) // XORL SP.x, SP.x - self.Emit("XORL", _SP_f, _SP_f) // XORL SP.f, SP.f - self.Emit("XORL", _SP_q, _SP_q) // XORL SP.q, SP.q -} - -/** Assembler Inline Functions **/ - -func (self *_Assembler) xsave(reg ...obj.Addr) { - for i, v := range reg { - if i > _FP_saves / 8 - 1 { - panic("too many registers to save") - } else { - self.Emit("MOVQ", v, jit.Ptr(_SP, _FP_fargs + int64(i) * 8)) - } - } -} - -func (self *_Assembler) xload(reg ...obj.Addr) { - for i, v := range reg { - if i > _FP_saves / 8 - 1 { - panic("too many registers to load") - } else { - self.Emit("MOVQ", jit.Ptr(_SP, _FP_fargs + int64(i) * 8), v) - } - } -} - -func (self *_Assembler) rbuf_di() { - if _RP.Reg != x86.REG_DI { - panic("register allocation messed up: RP != DI") - } else { - self.Emit("ADDQ", _RL, _RP) - } -} - -func (self *_Assembler) store_int(nd int, fn obj.Addr, ins string) { - self.check_size(nd) - self.save_c() // SAVE $C_regs - self.rbuf_di() // MOVQ RP, DI - self.Emit(ins, jit.Ptr(_SP_p, 0), _SI) // $ins (SP.p), SI - self.call_c(fn) // CALL_C $fn - self.Emit("ADDQ", _AX, _RL) // ADDQ AX, RL -} - -func (self *_Assembler) store_str(s string) { - i := 0 - m := rt.Str2Mem(s) - - /* 8-byte stores */ - for i <= len(m) - 8 { - self.Emit("MOVQ", jit.Imm(rt.Get64(m[i:])), _AX) // MOVQ $s[i:], AX - self.Emit("MOVQ", _AX, jit.Sib(_RP, _RL, 1, int64(i))) // MOVQ AX, i(RP)(RL) - i += 8 - } - - /* 4-byte stores */ - if i <= len(m) - 4 { - self.Emit("MOVL", jit.Imm(int64(rt.Get32(m[i:]))), jit.Sib(_RP, _RL, 1, int64(i))) // MOVL $s[i:], i(RP)(RL) - i += 4 - } - - /* 2-byte stores */ - if i <= len(m) - 2 { - self.Emit("MOVW", jit.Imm(int64(rt.Get16(m[i:]))), jit.Sib(_RP, _RL, 1, int64(i))) // MOVW $s[i:], i(RP)(RL) - i += 2 - } - - /* last byte */ - if i < len(m) { - self.Emit("MOVB", jit.Imm(int64(m[i])), jit.Sib(_RP, _RL, 1, int64(i))) // MOVB $s[i:], i(RP)(RL) - } -} - -func (self *_Assembler) check_size(n int) { - self.check_size_rl(jit.Ptr(_RL, int64(n))) -} - -func (self *_Assembler) check_size_r(r obj.Addr, d int) { - self.check_size_rl(jit.Sib(_RL, r, 1, int64(d))) -} - -func (self *_Assembler) check_size_rl(v obj.Addr) { - idx := self.x - key := _LB_more_space_return + strconv.Itoa(idx) - - /* the following code relies on LR == R9 to work */ - if _LR.Reg != x86.REG_R9 { - panic("register allocation messed up: LR != R9") - } - - /* check for buffer capacity */ - self.x++ - self.Emit("LEAQ", v, _AX) // LEAQ $v, AX - self.Emit("CMPQ", _AX, _RC) // CMPQ AX, RC - self.Sjmp("JBE" , key) // JBE _more_space_return_{n} - self.slice_grow_ax(key) // GROW $key - self.Link(key) // _more_space_return_{n}: -} - -func (self *_Assembler) slice_grow_ax(ret string) { - self.Byte(0x4c, 0x8d, 0x0d) // LEAQ ?(PC), R9 - self.Sref(ret, 4) // .... &ret - self.Sjmp("JMP" , _LB_more_space) // JMP _more_space -} - -/** State Stack Helpers **/ - -const ( - _StateSize = int64(unsafe.Sizeof(_State{})) - _StackLimit = _MaxStack * _StateSize -) - -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("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.WritePtr(0, _SP_p, jit.Sib(_ST, _CX, 1, 24)) // MOVQ SP.p, 24(ST)(CX) - self.WritePtr(1, _SP_q, jit.Sib(_ST, _CX, 1, 32)) // MOVQ SP.q, 32(ST)(CX) - self.Emit("MOVQ", _R8, jit.Ptr(_ST, 0)) // MOVQ R8, (ST) -} - -func (self *_Assembler) drop_state(decr int64) { - self.Emit("MOVQ" , jit.Ptr(_ST, 0), _AX) // MOVQ (ST), AX - self.Emit("SUBQ" , jit.Imm(decr), _AX) // SUBQ $decr, AX - self.Emit("MOVQ" , _AX, jit.Ptr(_ST, 0)) // MOVQ AX, (ST) - self.Emit("MOVQ" , jit.Sib(_ST, _AX, 1, 8), _SP_x) // MOVQ 8(ST)(AX), SP.x - self.Emit("MOVQ" , jit.Sib(_ST, _AX, 1, 16), _SP_f) // MOVQ 16(ST)(AX), SP.f - self.Emit("MOVQ" , jit.Sib(_ST, _AX, 1, 24), _SP_p) // MOVQ 24(ST)(AX), SP.p - self.Emit("MOVQ" , jit.Sib(_ST, _AX, 1, 32), _SP_q) // MOVQ 32(ST)(AX), SP.q - self.Emit("PXOR" , _X0, _X0) // PXOR X0, X0 - self.Emit("MOVOU", _X0, jit.Sib(_ST, _AX, 1, 8)) // MOVOU X0, 8(ST)(AX) - self.Emit("MOVOU", _X0, jit.Sib(_ST, _AX, 1, 24)) // MOVOU X0, 24(ST)(AX) -} - -/** Buffer Helpers **/ - -func (self *_Assembler) add_char(ch byte) { - self.Emit("MOVB", jit.Imm(int64(ch)), jit.Sib(_RP, _RL, 1, 0)) // MOVB $ch, (RP)(RL) - self.Emit("ADDQ", jit.Imm(1), _RL) // ADDQ $1, RL -} - -func (self *_Assembler) add_long(ch uint32, n int64) { - self.Emit("MOVL", jit.Imm(int64(ch)), jit.Sib(_RP, _RL, 1, 0)) // MOVL $ch, (RP)(RL) - self.Emit("ADDQ", jit.Imm(n), _RL) // ADDQ $n, RL -} - -func (self *_Assembler) add_text(ss string) { - self.store_str(ss) // TEXT $ss - self.Emit("ADDQ", jit.Imm(int64(len(ss))), _RL) // ADDQ ${len(ss)}, RL -} - -func (self *_Assembler) prep_buffer() { - self.Emit("MOVQ", _ARG_rb, _AX) // MOVQ rb<>+0(FP), AX - self.Emit("MOVQ", _RL, jit.Ptr(_AX, 8)) // MOVQ RL, 8(AX) - self.Emit("MOVQ", _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP) -} - -func (self *_Assembler) prep_buffer_c() { - self.Emit("MOVQ", _ARG_rb, _DI) // MOVQ rb<>+0(FP), DI - self.Emit("MOVQ", _RL, jit.Ptr(_DI, 8)) // MOVQ RL, 8(DI) -} - -func (self *_Assembler) save_buffer() { - self.Emit("MOVQ", _ARG_rb, _CX) // MOVQ rb<>+0(FP), CX - self.Emit("MOVQ", _RP, jit.Ptr(_CX, 0)) // MOVQ RP, (CX) - self.Emit("MOVQ", _RL, jit.Ptr(_CX, 8)) // MOVQ RL, 8(CX) - self.Emit("MOVQ", _RC, jit.Ptr(_CX, 16)) // MOVQ RC, 16(CX) -} - -func (self *_Assembler) load_buffer() { - self.Emit("MOVQ", _ARG_rb, _AX) // MOVQ rb<>+0(FP), AX - self.Emit("MOVQ", jit.Ptr(_AX, 0), _RP) // MOVQ (AX), RP - self.Emit("MOVQ", jit.Ptr(_AX, 8), _RL) // MOVQ 8(AX), RL - self.Emit("MOVQ", jit.Ptr(_AX, 16), _RC) // MOVQ 16(AX), RC -} - -/** Function Interface Helpers **/ - -func (self *_Assembler) call(pc obj.Addr) { - self.Emit("MOVQ", pc, _AX) // MOVQ $pc, AX - self.Rjmp("CALL", _AX) // CALL AX -} - -func (self *_Assembler) save_c() { - self.xsave(_REG_ffi...) // SAVE $REG_ffi -} - -func (self *_Assembler) call_c(pc obj.Addr) { - self.call(pc) // CALL $pc - self.xload(_REG_ffi...) // LOAD $REG_ffi -} - -func (self *_Assembler) call_go(pc obj.Addr) { - self.xsave(_REG_all...) // SAVE $REG_all - self.call(pc) // CALL $pc - self.xload(_REG_all...) // LOAD $REG_all -} - -func (self *_Assembler) call_encoder(pc obj.Addr) { - self.xsave(_REG_enc...) // SAVE $REG_enc - self.call(pc) // CALL $pc - self.xload(_REG_enc...) // LOAD $REG_enc - self.load_buffer() // LOAD {buf} -} - -func (self *_Assembler) call_marshaler(fn obj.Addr, it *rt.GoType, vt reflect.Type) { - switch vt.Kind() { - case reflect.Interface : self.call_marshaler_i(fn, it) - case reflect.Ptr, reflect.Map: self.call_marshaler_v(fn, it, vt, true) - // struct/array of 1 direct iface type can be direct - default : self.call_marshaler_v(fn, it, vt, !rt.UnpackType(vt).Indirect()) - } -} - -func (self *_Assembler) call_marshaler_i(fn obj.Addr, it *rt.GoType) { - self.Emit("MOVQ" , jit.Gtype(it), _AX) // MOVQ $it, AX - self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP) - self.Emit("MOVQ" , jit.Ptr(_SP_p, 0), _AX) // MOVQ (SP.p), AX - self.Emit("MOVQ" , jit.Ptr(_SP_p, 8), _CX) // MOVQ 8(SP.p), CX - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JZ" , "_null_{n}") // JZ _null_{n} - self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 8)) // MOVQ AX, 8(SP) - self.Emit("MOVQ" , _CX, jit.Ptr(_SP, 16)) // MOVQ CX, 16(SP) - self.call_go(_F_assertI2I) // CALL_GO assertI2I - self.prep_buffer() // MOVE {buf}, (SP) - self.Emit("MOVOU", jit.Ptr(_SP, 24), _X0) // MOVOU 24(SP), X0 - self.Emit("MOVOU", _X0, jit.Ptr(_SP, 8)) // MOVOU X0, 8(SP) - self.Emit("MOVQ", _ARG_fv, _CX) // MOVQ ARG.fv, CX - self.Emit("MOVQ", _CX, jit.Ptr(_SP, 24)) // MOVQ CX, 24(SP) - self.call_encoder(fn) // CALL $fn - self.Emit("MOVQ" , jit.Ptr(_SP, 32), _ET) // MOVQ 32(SP), ET - 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.Sjmp("JMP" , "_done_{n}") // JMP _done_{n} - self.Link("_null_{n}") // _null_{n}: - self.check_size(4) // SIZE $4 - self.Emit("MOVL", jit.Imm(_IM_null), jit.Sib(_RP, _RL, 1, 0)) // MOVL $'null', (RP)(RL*1) - self.Emit("ADDQ", jit.Imm(4), _RL) // ADDQ $4, RL - self.Link("_done_{n}") // _done_{n}: -} - -func (self *_Assembler) call_marshaler_v(fn obj.Addr, it *rt.GoType, vt reflect.Type, deref bool) { - self.prep_buffer() // MOVE {buf}, (SP) - self.Emit("MOVQ", jit.Itab(it, vt), _AX) // MOVQ $(itab(it, vt)), AX - self.Emit("MOVQ", _AX, jit.Ptr(_SP, 8)) // MOVQ AX, 8(SP) - - /* dereference the pointer if needed */ - if !deref { - self.Emit("MOVQ", _SP_p, jit.Ptr(_SP, 16)) // MOVQ SP.p, 16(SP) - } else { - self.Emit("MOVQ", jit.Ptr(_SP_p, 0), _AX) // MOVQ (SP.p), AX - self.Emit("MOVQ", _AX, jit.Ptr(_SP, 16)) // MOVQ AX, 16(SP) - } - - /* call the encoder, and perform error checks */ - self.Emit("MOVQ", _ARG_fv, _CX) // MOVQ ARG.fv, CX - self.Emit("MOVQ", _CX, jit.Ptr(_SP, 24)) // MOVQ CX, 24(SP) - self.call_encoder(fn) // CALL $fn - self.Emit("MOVQ" , jit.Ptr(_SP, 32), _ET) // MOVQ 32(SP), ET - 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 -} - -/** Builtin: _more_space **/ - -var ( - _T_byte = jit.Type(byteType) - _F_growslice = jit.Func(growslice) -) - -func (self *_Assembler) more_space() { - self.Link(_LB_more_space) - self.Emit("MOVQ", _T_byte, _AX) // MOVQ $_T_byte, _AX - self.Emit("MOVQ", _AX, jit.Ptr(_SP, 0)) // MOVQ _AX, (SP) - self.Emit("MOVQ", _RP, jit.Ptr(_SP, 8)) // MOVQ RP, 8(SP) - self.Emit("MOVQ", _RL, jit.Ptr(_SP, 16)) // MOVQ RL, 16(SP) - self.Emit("MOVQ", _RC, jit.Ptr(_SP, 24)) // MOVQ RC, 24(SP) - self.Emit("MOVQ", _AX, jit.Ptr(_SP, 32)) // MOVQ AX, 32(SP) - self.xsave(_REG_jsr...) // SAVE $REG_jsr - self.call(_F_growslice) // CALL $pc - self.xload(_REG_jsr...) // LOAD $REG_jsr - self.Emit("MOVQ", jit.Ptr(_SP, 40), _RP) // MOVQ 40(SP), RP - self.Emit("MOVQ", jit.Ptr(_SP, 48), _RL) // MOVQ 48(SP), RL - self.Emit("MOVQ", jit.Ptr(_SP, 56), _RC) // MOVQ 56(SP), RC - self.save_buffer() // SAVE {buf} - self.Rjmp("JMP" , _LR) // JMP LR -} - -/** Builtin Errors **/ - -var ( - _V_ERR_too_deep = jit.Imm(int64(uintptr(unsafe.Pointer(_ERR_too_deep)))) - _V_ERR_nan_or_infinite = jit.Imm(int64(uintptr(unsafe.Pointer(_ERR_nan_or_infinite)))) - _I_json_UnsupportedValueError = jit.Itab(rt.UnpackType(errorType), jsonUnsupportedValueType) -) - -func (self *_Assembler) error_too_deep() { - self.Link(_LB_error_too_deep) - self.Emit("MOVQ", _V_ERR_too_deep, _EP) // MOVQ $_V_ERR_too_deep, EP - self.Emit("MOVQ", _I_json_UnsupportedValueError, _ET) // MOVQ $_I_json_UnsupportedValuError, ET - self.Sjmp("JMP" , _LB_error) // JMP _error -} - -func (self *_Assembler) error_invalid_number() { - self.Link(_LB_error_invalid_number) - self.call_go(_F_error_number) // CALL_GO error_number - self.Emit("MOVQ", jit.Ptr(_SP, 16), _ET) // MOVQ 16(SP), ET - self.Emit("MOVQ", jit.Ptr(_SP, 24), _EP) // MOVQ 24(SP), EP - self.Sjmp("JMP" , _LB_error) // JMP _error -} - -func (self *_Assembler) error_nan_or_infinite() { - self.Link(_LB_error_nan_or_infinite) - self.Emit("MOVQ", _V_ERR_nan_or_infinite, _EP) // MOVQ $_V_ERR_nan_or_infinite, EP - self.Emit("MOVQ", _I_json_UnsupportedValueError, _ET) // MOVQ $_I_json_UnsupportedValuError, ET - self.Sjmp("JMP" , _LB_error) // JMP _error -} - -/** String Encoding Routine **/ - -var ( - _F_quote = jit.Imm(int64(native.S_quote)) - _F_panic = jit.Func(goPanic) -) - -func (self *_Assembler) go_panic() { - self.Link(_LB_panic) - self.Emit("MOVQ", _SP_p, jit.Ptr(_SP, 8)) - self.call_go(_F_panic) -} - -func (self *_Assembler) encode_string(doubleQuote bool) { - self.Emit("MOVQ" , jit.Ptr(_SP_p, 8), _AX) // MOVQ 8(SP.p), AX - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JZ" , "_str_empty_{n}") // JZ _str_empty_{n} - self.Emit("CMPQ", jit.Ptr(_SP_p, 0), jit.Imm(0)) - self.Sjmp("JNE" , "_str_next_{n}") - self.Emit("MOVQ", jit.Imm(int64(panicNilPointerOfNonEmptyString)), jit.Ptr(_SP, 0)) - self.Sjmp("JMP", _LB_panic) - self.Link("_str_next_{n}") - - /* openning quote, check for double quote */ - if !doubleQuote { - self.check_size_r(_AX, 2) // SIZE $2 - self.add_char('"') // CHAR $'"' - } else { - self.check_size_r(_AX, 6) // SIZE $6 - self.add_long(_IM_open, 3) // TEXT $`"\"` - } - - /* quoting loop */ - self.Emit("XORL", _AX, _AX) // XORL AX, AX - self.Emit("MOVQ", _AX, _VAR_sp) // MOVQ AX, sp - self.Link("_str_loop_{n}") // _str_loop_{n}: - self.save_c() // SAVE $REG_ffi - - /* load the output buffer first, and then input buffer, - * because the parameter registers collide with RP / RL / RC */ - self.Emit("MOVQ", _RC, _CX) // MOVQ RC, CX - self.Emit("SUBQ", _RL, _CX) // SUBQ RL, CX - self.Emit("MOVQ", _CX, _VAR_dn) // MOVQ CX, dn - self.Emit("LEAQ", jit.Sib(_RP, _RL, 1, 0), _DX) // LEAQ (RP)(RL), DX - self.Emit("LEAQ", _VAR_dn, _CX) // LEAQ dn, CX - self.Emit("MOVQ", _VAR_sp, _AX) // MOVQ sp, AX - self.Emit("MOVQ", jit.Ptr(_SP_p, 0), _DI) // MOVQ (SP.p), DI - self.Emit("MOVQ", jit.Ptr(_SP_p, 8), _SI) // MOVQ 8(SP.p), SI - self.Emit("ADDQ", _AX, _DI) // ADDQ AX, DI - self.Emit("SUBQ", _AX, _SI) // SUBQ AX, SI - - /* set the flags based on `doubleQuote` */ - if !doubleQuote { - self.Emit("XORL", _R8, _R8) // XORL R8, R8 - } else { - self.Emit("MOVL", jit.Imm(types.F_DOUBLE_UNQUOTE), _R8) // MOVL ${types.F_DOUBLE_UNQUOTE}, R8 - } - - /* call the native quoter */ - self.call_c(_F_quote) // CALL quote - self.Emit("ADDQ" , _VAR_dn, _RL) // ADDQ dn, RL - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JS" , "_str_space_{n}") // JS _str_space_{n} - - /* close the string, check for double quote */ - if !doubleQuote { - self.check_size(1) // SIZE $1 - self.add_char('"') // CHAR $'"' - self.Sjmp("JMP", "_str_end_{n}") // JMP _str_end_{n} - } else { - self.check_size(3) // SIZE $3 - self.add_text("\\\"\"") // TEXT $'\""' - self.Sjmp("JMP", "_str_end_{n}") // JMP _str_end_{n} - } - - /* not enough space to contain the quoted string */ - self.Link("_str_space_{n}") // _str_space_{n}: - self.Emit("NOTQ", _AX) // NOTQ AX - self.Emit("ADDQ", _AX, _VAR_sp) // ADDQ AX, sp - self.Emit("LEAQ", jit.Sib(_RC, _RC, 1, 0), _AX) // LEAQ (RC)(RC), AX - self.slice_grow_ax("_str_loop_{n}") // GROW _str_loop_{n} - - /* empty string, check for double quote */ - if !doubleQuote { - self.Link("_str_empty_{n}") // _str_empty_{n}: - self.check_size(2) // SIZE $2 - self.add_text("\"\"") // TEXT $'""' - self.Link("_str_end_{n}") // _str_end_{n}: - } else { - self.Link("_str_empty_{n}") // _str_empty_{n}: - self.check_size(6) // SIZE $6 - self.add_text("\"\\\"\\\"\"") // TEXT $'"\"\""' - self.Link("_str_end_{n}") // _str_end_{n}: - } -} - -/** OpCode Assembler Functions **/ - -var ( - _T_json_Marshaler = rt.UnpackType(jsonMarshalerType) - _T_encoding_TextMarshaler = rt.UnpackType(encodingTextMarshalerType) -) - -var ( - _F_f64toa = jit.Imm(int64(native.S_f64toa)) - _F_f32toa = jit.Imm(int64(native.S_f32toa)) - _F_i64toa = jit.Imm(int64(native.S_i64toa)) - _F_u64toa = jit.Imm(int64(native.S_u64toa)) - _F_b64encode = jit.Imm(int64(_subr__b64encode)) -) - -var ( - _F_memmove = jit.Func(memmove) - _F_error_number = jit.Func(error_number) - _F_isValidNumber = jit.Func(isValidNumber) -) - -var ( - _F_iteratorStop = jit.Func(iteratorStop) - _F_iteratorNext = jit.Func(iteratorNext) - _F_iteratorStart = jit.Func(iteratorStart) -) - -var ( - _F_encodeTypedPointer obj.Addr - _F_encodeJsonMarshaler obj.Addr - _F_encodeTextMarshaler obj.Addr -) - -const ( - _MODE_AVX2 = 1 << 2 -) - -func init() { - _F_encodeTypedPointer = jit.Func(encodeTypedPointer) - _F_encodeJsonMarshaler = jit.Func(encodeJsonMarshaler) - _F_encodeTextMarshaler = jit.Func(encodeTextMarshaler) -} - -func (self *_Assembler) _asm_OP_null(_ *_Instr) { - self.check_size(4) - self.Emit("MOVL", jit.Imm(_IM_null), jit.Sib(_RP, _RL, 1, 0)) // MOVL $'null', (RP)(RL*1) - self.Emit("ADDQ", jit.Imm(4), _RL) // ADDQ $4, RL -} - -func (self *_Assembler) _asm_OP_empty_arr(_ *_Instr) { - self.Emit("BTQ", jit.Imm(int64(bitNoNullSliceOrMap)), _ARG_fv) - self.Sjmp("JC", "_empty_arr_{n}") - self._asm_OP_null(nil) - self.Sjmp("JMP", "_empty_arr_end_{n}") - self.Link("_empty_arr_{n}") - self.check_size(2) - self.Emit("MOVW", jit.Imm(_IM_array), jit.Sib(_RP, _RL, 1, 0)) - self.Emit("ADDQ", jit.Imm(2), _RL) - self.Link("_empty_arr_end_{n}") -} - -func (self *_Assembler) _asm_OP_empty_obj(_ *_Instr) { - self.Emit("BTQ", jit.Imm(int64(bitNoNullSliceOrMap)), _ARG_fv) - self.Sjmp("JC", "_empty_obj_{n}") - self._asm_OP_null(nil) - self.Sjmp("JMP", "_empty_obj_end_{n}") - self.Link("_empty_obj_{n}") - self.check_size(2) - self.Emit("MOVW", jit.Imm(_IM_object), jit.Sib(_RP, _RL, 1, 0)) - self.Emit("ADDQ", jit.Imm(2), _RL) - self.Link("_empty_obj_end_{n}") -} - -func (self *_Assembler) _asm_OP_bool(_ *_Instr) { - self.Emit("CMPB", jit.Ptr(_SP_p, 0), jit.Imm(0)) // CMPB (SP.p), $0 - self.Sjmp("JE" , "_false_{n}") // JE _false_{n} - self.check_size(4) // SIZE $4 - self.Emit("MOVL", jit.Imm(_IM_true), jit.Sib(_RP, _RL, 1, 0)) // MOVL $'true', (RP)(RL*1) - self.Emit("ADDQ", jit.Imm(4), _RL) // ADDQ $4, RL - self.Sjmp("JMP" , "_end_{n}") // JMP _end_{n} - self.Link("_false_{n}") // _false_{n}: - self.check_size(5) // SIZE $5 - self.Emit("MOVL", jit.Imm(_IM_fals), jit.Sib(_RP, _RL, 1, 0)) // MOVL $'fals', (RP)(RL*1) - self.Emit("MOVB", jit.Imm('e'), jit.Sib(_RP, _RL, 1, 4)) // MOVB $'e', 4(RP)(RL*1) - self.Emit("ADDQ", jit.Imm(5), _RL) // ADDQ $5, RL - self.Link("_end_{n}") // _end_{n}: -} - -func (self *_Assembler) _asm_OP_i8(_ *_Instr) { - self.store_int(4, _F_i64toa, "MOVBQSX") -} - -func (self *_Assembler) _asm_OP_i16(_ *_Instr) { - self.store_int(6, _F_i64toa, "MOVWQSX") -} - -func (self *_Assembler) _asm_OP_i32(_ *_Instr) { - self.store_int(17, _F_i64toa, "MOVLQSX") -} - -func (self *_Assembler) _asm_OP_i64(_ *_Instr) { - self.store_int(21, _F_i64toa, "MOVQ") -} - -func (self *_Assembler) _asm_OP_u8(_ *_Instr) { - self.store_int(3, _F_u64toa, "MOVBQZX") -} - -func (self *_Assembler) _asm_OP_u16(_ *_Instr) { - self.store_int(5, _F_u64toa, "MOVWQZX") -} - -func (self *_Assembler) _asm_OP_u32(_ *_Instr) { - self.store_int(16, _F_u64toa, "MOVLQZX") -} - -func (self *_Assembler) _asm_OP_u64(_ *_Instr) { - self.store_int(20, _F_u64toa, "MOVQ") -} - -func (self *_Assembler) _asm_OP_f32(_ *_Instr) { - self.check_size(32) - self.Emit("MOVL" , jit.Ptr(_SP_p, 0), _AX) // MOVL (SP.p), AX - self.Emit("ANDL" , jit.Imm(_FM_exp32), _AX) // ANDL $_FM_exp32, AX - self.Emit("XORL" , jit.Imm(_FM_exp32), _AX) // XORL $_FM_exp32, AX - self.Sjmp("JZ" , _LB_error_nan_or_infinite) // JZ _error_nan_or_infinite - self.save_c() // SAVE $C_regs - self.rbuf_di() // MOVQ RP, DI - self.Emit("MOVSS" , jit.Ptr(_SP_p, 0), _X0) // MOVSS (SP.p), X0 - self.call_c(_F_f32toa) // CALL_C f64toa - self.Emit("ADDQ" , _AX, _RL) // ADDQ AX, RL -} - -func (self *_Assembler) _asm_OP_f64(_ *_Instr) { - self.check_size(32) - self.Emit("MOVQ" , jit.Ptr(_SP_p, 0), _AX) // MOVQ (SP.p), AX - self.Emit("MOVQ" , jit.Imm(_FM_exp64), _CX) // MOVQ $_FM_exp64, CX - self.Emit("ANDQ" , _CX, _AX) // ANDQ CX, AX - self.Emit("XORQ" , _CX, _AX) // XORQ CX, AX - self.Sjmp("JZ" , _LB_error_nan_or_infinite) // JZ _error_nan_or_infinite - self.save_c() // SAVE $C_regs - self.rbuf_di() // MOVQ RP, DI - self.Emit("MOVSD" , jit.Ptr(_SP_p, 0), _X0) // MOVSD (SP.p), X0 - self.call_c(_F_f64toa) // CALL_C f64toa - self.Emit("ADDQ" , _AX, _RL) // ADDQ AX, RL -} - -func (self *_Assembler) _asm_OP_str(_ *_Instr) { - self.encode_string(false) -} - -func (self *_Assembler) _asm_OP_bin(_ *_Instr) { - self.Emit("MOVQ", jit.Ptr(_SP_p, 8), _AX) // MOVQ 8(SP.p), AX - self.Emit("ADDQ", jit.Imm(2), _AX) // ADDQ $2, AX - self.Emit("MOVQ", jit.Imm(_IM_mulv), _CX) // MOVQ $_MF_mulv, CX - self.Emit("MOVQ", _DX, _R8) // MOVQ DX, R8 - self.From("MULQ", _CX) // MULQ CX - self.Emit("LEAQ", jit.Sib(_DX, _DX, 1, 1), _AX) // LEAQ 1(DX)(DX), AX - self.Emit("ORQ" , jit.Imm(2), _AX) // ORQ $2, AX - self.Emit("MOVQ", _R8, _DX) // MOVQ R8, DX - self.check_size_r(_AX, 0) // SIZE AX - self.add_char('"') // CHAR $'"' - self.save_c() // SAVE $REG_ffi - self.prep_buffer_c() // MOVE {buf}, DI - self.Emit("MOVQ", _SP_p, _SI) // MOVQ SP.p, SI - - /* check for AVX2 support */ - if !cpu.HasAVX2 { - self.Emit("XORL", _DX, _DX) // XORL DX, DX - } else { - self.Emit("MOVL", jit.Imm(_MODE_AVX2), _DX) // MOVL $_MODE_AVX2, DX - } - - /* call the encoder */ - self.call_c(_F_b64encode) // CALL b64encode - self.load_buffer() // LOAD {buf} - self.add_char('"') // CHAR $'"' -} - -func (self *_Assembler) _asm_OP_quote(_ *_Instr) { - self.encode_string(true) -} - -func (self *_Assembler) _asm_OP_number(_ *_Instr) { - self.Emit("MOVQ" , jit.Ptr(_SP_p, 8), _CX) // MOVQ (SP.p), CX - self.Emit("TESTQ", _CX, _CX) // TESTQ CX, CX - self.Sjmp("JZ" , "_empty_{n}") // JZ _empty_{n} - self.Emit("MOVQ" , jit.Ptr(_SP_p, 0), _AX) // MOVQ (SP.p), AX - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Sjmp("JNZ" , "_number_next_{n}") - self.Emit("MOVQ", jit.Imm(int64(panicNilPointerOfNonEmptyString)), jit.Ptr(_SP, 0)) - self.Sjmp("JMP", _LB_panic) - self.Link("_number_next_{n}") - self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP) - self.Emit("MOVQ" , _CX, jit.Ptr(_SP, 8)) // MOVQ CX, 8(SP) - self.call_go(_F_isValidNumber) // CALL_GO isValidNumber - self.Emit("CMPB" , jit.Ptr(_SP, 16), jit.Imm(0)) // CMPB 16(SP), $0 - self.Sjmp("JE" , _LB_error_invalid_number) // JE _error_invalid_number - self.Emit("MOVQ" , jit.Ptr(_SP_p, 8), _AX) // MOVQ 8(SP.p), AX - self.check_size_r(_AX, 0) // SIZE AX - self.Emit("LEAQ" , jit.Sib(_RP, _RL, 1, 0), _AX) // LEAQ (RP)(RL), AX - self.Emit("ADDQ" , jit.Ptr(_SP_p, 8), _RL) // ADDQ 8(SP.p), RL - self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP) - self.Emit("MOVOU", jit.Ptr(_SP_p, 0), _X0) // MOVOU (SP.p), X0 - self.Emit("MOVOU", _X0, jit.Ptr(_SP, 8)) // MOVOU X0, 8(SP) - self.call_go(_F_memmove) // CALL_GO memmove - self.Sjmp("JMP" , "_done_{n}") // JMP _done_{n} - self.Link("_empty_{n}") // _empty_{n}: - self.check_size(1) // SIZE $1 - self.add_char('0') // CHAR $'0' - self.Link("_done_{n}") // _done_{n}: -} - -func (self *_Assembler) _asm_OP_eface(_ *_Instr) { - self.prep_buffer() // MOVE {buf}, (SP)s - self.Emit("MOVQ" , jit.Ptr(_SP_p, 0), _AX) // MOVQ (SP.p), AX - self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 8)) // MOVQ AX, 8(SP) - self.Emit("LEAQ" , jit.Ptr(_SP_p, 8), _AX) // LEAQ 8(SP.p), AX - self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 16)) // MOVQ AX, 16(SP) - self.Emit("MOVQ" , _ST, jit.Ptr(_SP, 24)) // MOVQ ST, 24(SP) - self.Emit("MOVQ" , _ARG_fv, _AX) // MOVQ fv, AX - self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 32)) // MOVQ AX, 32(SP) - self.call_encoder(_F_encodeTypedPointer) // CALL encodeTypedPointer - self.Emit("MOVQ" , jit.Ptr(_SP, 40), _ET) // MOVQ 40(SP), ET - self.Emit("MOVQ" , jit.Ptr(_SP, 48), _EP) // MOVQ 48(SP), EP - self.Emit("TESTQ", _ET, _ET) // TESTQ ET, ET - self.Sjmp("JNZ" , _LB_error) // JNZ _error -} - -func (self *_Assembler) _asm_OP_iface(_ *_Instr) { - self.prep_buffer() // MOVE {buf}, (SP) - self.Emit("MOVQ" , jit.Ptr(_SP_p, 0), _AX) // MOVQ (SP.p), AX - self.Emit("MOVQ" , jit.Ptr(_AX, 8), _AX) // MOVQ 8(AX), AX - self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 8)) // MOVQ AX, 8(SP) - self.Emit("LEAQ" , jit.Ptr(_SP_p, 8), _AX) // LEAQ 8(SP.p), AX - self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 16)) // MOVQ AX, 16(SP) - self.Emit("MOVQ" , _ST, jit.Ptr(_SP, 24)) // MOVQ ST, 24(SP) - self.Emit("MOVQ" , _ARG_fv, _AX) // MOVQ fv, AX - self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 32)) // MOVQ AX, 32(SP) - self.call_encoder(_F_encodeTypedPointer) // CALL encodeTypedPointer - self.Emit("MOVQ" , jit.Ptr(_SP, 40), _ET) // MOVQ 40(SP), ET - self.Emit("MOVQ" , jit.Ptr(_SP, 48), _EP) // MOVQ 48(SP), EP - self.Emit("TESTQ", _ET, _ET) // TESTQ ET, ET - self.Sjmp("JNZ" , _LB_error) // JNZ _error -} - -func (self *_Assembler) _asm_OP_byte(p *_Instr) { - self.check_size(1) - self.Emit("MOVB", jit.Imm(p.i64()), jit.Sib(_RP, _RL, 1, 0)) // MOVL p.vi(), (RP)(RL*1) - self.Emit("ADDQ", jit.Imm(1), _RL) // ADDQ $1, RL -} - -func (self *_Assembler) _asm_OP_text(p *_Instr) { - self.check_size(len(p.vs())) // SIZE ${len(p.vs())} - self.add_text(p.vs()) // TEXT ${p.vs()} -} - -func (self *_Assembler) _asm_OP_deref(_ *_Instr) { - self.Emit("MOVQ", jit.Ptr(_SP_p, 0), _SP_p) // MOVQ (SP.p), SP.p -} - -func (self *_Assembler) _asm_OP_index(p *_Instr) { - self.Emit("MOVQ", jit.Imm(p.i64()), _AX) // MOVQ $p.vi(), AX - self.Emit("ADDQ", _AX, _SP_p) // ADDQ AX, SP.p -} - -func (self *_Assembler) _asm_OP_load(_ *_Instr) { - self.Emit("MOVQ", jit.Ptr(_ST, 0), _AX) // MOVQ (ST), AX - self.Emit("MOVQ", jit.Sib(_ST, _AX, 1, -24), _SP_x) // MOVQ -24(ST)(AX), SP.x - self.Emit("MOVQ", jit.Sib(_ST, _AX, 1, -8), _SP_p) // MOVQ -8(ST)(AX), SP.p - self.Emit("MOVQ", jit.Sib(_ST, _AX, 1, 0), _SP_q) // MOVQ (ST)(AX), SP.q -} - -func (self *_Assembler) _asm_OP_save(_ *_Instr) { - self.save_state() -} - -func (self *_Assembler) _asm_OP_drop(_ *_Instr) { - self.drop_state(_StateSize) -} - -func (self *_Assembler) _asm_OP_drop_2(_ *_Instr) { - self.drop_state(_StateSize * 2) // DROP $(_StateSize * 2) - self.Emit("MOVOU", _X0, jit.Sib(_ST, _AX, 1, 56)) // MOVOU X0, 56(ST)(AX) -} - -func (self *_Assembler) _asm_OP_recurse(p *_Instr) { - self.prep_buffer() // MOVE {buf}, (SP) - vt, pv := p.vp() - self.Emit("MOVQ", jit.Type(vt), _AX) // MOVQ $(type(p.vt())), AX - self.Emit("MOVQ", _AX, jit.Ptr(_SP, 8)) // MOVQ AX, 8(SP) - - /* check for indirection */ - if !rt.UnpackType(vt).Indirect() { - self.Emit("MOVQ", _SP_p, _AX) // MOVQ SP.p, AX - } else { - self.Emit("MOVQ", _SP_p, _VAR_vp) // MOVQ SP.p, 48(SP) - self.Emit("LEAQ", _VAR_vp, _AX) // LEAQ 48(SP), AX - } - - /* call the encoder */ - self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 16)) // MOVQ AX, 16(SP) - self.Emit("MOVQ" , _ST, jit.Ptr(_SP, 24)) // MOVQ ST, 24(SP) - self.Emit("MOVQ" , _ARG_fv, _AX) // MOVQ fv, AX - if pv { - self.Emit("BTCQ", jit.Imm(bitPointerValue), _AX) // BTCQ $1, AX - } - self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 32)) // MOVQ AX, 32(SP) - self.call_encoder(_F_encodeTypedPointer) // CALL encodeTypedPointer - self.Emit("MOVQ" , jit.Ptr(_SP, 40), _ET) // MOVQ 40(SP), ET - self.Emit("MOVQ" , jit.Ptr(_SP, 48), _EP) // MOVQ 48(SP), EP - self.Emit("TESTQ", _ET, _ET) // TESTQ ET, ET - self.Sjmp("JNZ" , _LB_error) // JNZ _error -} - -func (self *_Assembler) _asm_OP_is_nil(p *_Instr) { - self.Emit("CMPQ", jit.Ptr(_SP_p, 0), jit.Imm(0)) // CMPQ (SP.p), $0 - self.Xjmp("JE" , p.vi()) // JE p.vi() -} - -func (self *_Assembler) _asm_OP_is_nil_p1(p *_Instr) { - self.Emit("CMPQ", jit.Ptr(_SP_p, 8), jit.Imm(0)) // CMPQ 8(SP.p), $0 - self.Xjmp("JE" , p.vi()) // JE p.vi() -} - -func (self *_Assembler) _asm_OP_is_zero_1(p *_Instr) { - self.Emit("CMPB", jit.Ptr(_SP_p, 0), jit.Imm(0)) // CMPB (SP.p), $0 - self.Xjmp("JE" , p.vi()) // JE p.vi() -} - -func (self *_Assembler) _asm_OP_is_zero_2(p *_Instr) { - self.Emit("CMPW", jit.Ptr(_SP_p, 0), jit.Imm(0)) // CMPW (SP.p), $0 - self.Xjmp("JE" , p.vi()) // JE p.vi() -} - -func (self *_Assembler) _asm_OP_is_zero_4(p *_Instr) { - self.Emit("CMPL", jit.Ptr(_SP_p, 0), jit.Imm(0)) // CMPL (SP.p), $0 - self.Xjmp("JE" , p.vi()) // JE p.vi() -} - -func (self *_Assembler) _asm_OP_is_zero_8(p *_Instr) { - self.Emit("CMPQ", jit.Ptr(_SP_p, 0), jit.Imm(0)) // CMPQ (SP.p), $0 - self.Xjmp("JE" , p.vi()) // JE p.vi() -} - -func (self *_Assembler) _asm_OP_is_zero_map(p *_Instr) { - self.Emit("MOVQ" , jit.Ptr(_SP_p, 0), _AX) // MOVQ (SP.p), AX - self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX - self.Xjmp("JZ" , p.vi()) // JZ p.vi() - self.Emit("CMPQ" , jit.Ptr(_AX, 0), jit.Imm(0)) // CMPQ (AX), $0 - self.Xjmp("JE" , p.vi()) // JE p.vi() -} - -func (self *_Assembler) _asm_OP_goto(p *_Instr) { - self.Xjmp("JMP", p.vi()) -} - -func (self *_Assembler) _asm_OP_map_iter(p *_Instr) { - self.Emit("MOVQ" , jit.Type(p.vt()), _AX) // MOVQ $p.vt(), AX - self.Emit("MOVQ" , jit.Ptr(_SP_p, 0), _CX) // MOVQ (SP.p), CX - self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP) - self.Emit("MOVQ" , _CX, jit.Ptr(_SP, 8)) // MOVQ CX, 8(SP) - self.Emit("MOVQ" , _ARG_fv, _AX) // MOVQ fv, AX - self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 16)) // MOVQ AX, 16(SP) - self.call_go(_F_iteratorStart) // CALL_GO iteratorStart - self.Emit("MOVQ" , jit.Ptr(_SP, 24), _SP_q) // MOVQ 24(SP), SP.q - self.Emit("MOVQ" , jit.Ptr(_SP, 32), _ET) // MOVQ 32(SP), ET - 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 -} - -func (self *_Assembler) _asm_OP_map_stop(_ *_Instr) { - self.Emit("MOVQ", _SP_q, jit.Ptr(_SP, 0)) // MOVQ SP.q, 0(SP) - self.call_go(_F_iteratorStop) // CALL_GO iteratorStop - self.Emit("XORL", _SP_q, _SP_q) // XORL SP.q, SP.q -} - -func (self *_Assembler) _asm_OP_map_check_key(p *_Instr) { - self.Emit("MOVQ" , jit.Ptr(_SP_q, 0), _SP_p) // MOVQ (SP.q), SP.p - self.Emit("TESTQ", _SP_p, _SP_p) // TESTQ SP.p, SP.p - self.Xjmp("JZ" , p.vi()) // JNZ p.vi() -} - -func (self *_Assembler) _asm_OP_map_write_key(p *_Instr) { - self.Emit("BTQ", jit.Imm(bitSortMapKeys), _ARG_fv) // BTQ ${SortMapKeys}, fv - self.Sjmp("JNC", "_unordered_key_{n}") // JNC _unordered_key_{n} - self.encode_string(false) // STR $false - self.Xjmp("JMP", p.vi()) // JMP ${p.vi()} - self.Link("_unordered_key_{n}") // _unordered_key_{n}: -} - -func (self *_Assembler) _asm_OP_map_value_next(_ *_Instr) { - self.Emit("MOVQ", jit.Ptr(_SP_q, 8), _SP_p) // MOVQ 8(SP.q), SP.p - self.Emit("MOVQ", _SP_q, jit.Ptr(_SP, 0)) // MOVQ SP.q, (SP) - self.call_go(_F_iteratorNext) // CALL_GO iteratorNext -} - -func (self *_Assembler) _asm_OP_slice_len(_ *_Instr) { - self.Emit("MOVQ" , jit.Ptr(_SP_p, 8), _SP_x) // MOVQ 8(SP.p), SP.x - self.Emit("MOVQ" , jit.Ptr(_SP_p, 0), _SP_p) // MOVQ (SP.p), SP.p - self.Emit("ORQ" , jit.Imm(1 << _S_init), _SP_f) // ORQ $(1<<_S_init), SP.f -} - -func (self *_Assembler) _asm_OP_slice_next(p *_Instr) { - self.Emit("TESTQ" , _SP_x, _SP_x) // TESTQ SP.x, SP.x - self.Xjmp("JZ" , p.vi()) // JZ p.vi() - self.Emit("SUBQ" , jit.Imm(1), _SP_x) // SUBQ $1, SP.x - self.Emit("BTRQ" , jit.Imm(_S_init), _SP_f) // BTRQ $_S_init, SP.f - self.Emit("LEAQ" , jit.Ptr(_SP_p, int64(p.vlen())), _AX) // LEAQ $(p.vlen())(SP.p), AX - self.Emit("CMOVQCC", _AX, _SP_p) // CMOVQNC AX, SP.p -} - -func (self *_Assembler) _asm_OP_marshal(p *_Instr) { - self.call_marshaler(_F_encodeJsonMarshaler, _T_json_Marshaler, p.vt()) -} - -func (self *_Assembler) _asm_OP_marshal_p(p *_Instr) { - if p.vk() != reflect.Ptr { - panic("marshal_p: invalid type") - } else { - self.call_marshaler_v(_F_encodeJsonMarshaler, _T_json_Marshaler, p.vt(), false) - } -} - -func (self *_Assembler) _asm_OP_marshal_text(p *_Instr) { - self.call_marshaler(_F_encodeTextMarshaler, _T_encoding_TextMarshaler, p.vt()) -} - -func (self *_Assembler) _asm_OP_marshal_text_p(p *_Instr) { - if p.vk() != reflect.Ptr { - panic("marshal_text_p: invalid type") - } else { - self.call_marshaler_v(_F_encodeTextMarshaler, _T_encoding_TextMarshaler, p.vt(), false) - } -} - -func (self *_Assembler) _asm_OP_cond_set(_ *_Instr) { - self.Emit("ORQ", jit.Imm(1 << _S_cond), _SP_f) // ORQ $(1<<_S_cond), SP.f -} - -func (self *_Assembler) _asm_OP_cond_testc(p *_Instr) { - self.Emit("BTRQ", jit.Imm(_S_cond), _SP_f) // BTRQ $_S_cond, SP.f - self.Xjmp("JC" , p.vi()) -} - -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) -} diff --git a/vendor/github.com/bytedance/sonic/internal/encoder/compiler.go b/vendor/github.com/bytedance/sonic/internal/encoder/compiler.go index a949c90f7..902fbc98b 100644 --- a/vendor/github.com/bytedance/sonic/internal/encoder/compiler.go +++ b/vendor/github.com/bytedance/sonic/internal/encoder/compiler.go @@ -17,869 +17,660 @@ package encoder import ( - `fmt` - `reflect` - `strconv` - `strings` - `unsafe` - - `github.com/bytedance/sonic/internal/resolver` - `github.com/bytedance/sonic/internal/rt` - `github.com/bytedance/sonic/option` + "reflect" + "unsafe" + + "github.com/bytedance/sonic/internal/encoder/ir" + "github.com/bytedance/sonic/internal/encoder/vars" + "github.com/bytedance/sonic/internal/encoder/vm" + "github.com/bytedance/sonic/internal/resolver" + "github.com/bytedance/sonic/internal/rt" + "github.com/bytedance/sonic/option" ) -type _Op uint8 - -const ( - _OP_null _Op = iota + 1 - _OP_empty_arr - _OP_empty_obj - _OP_bool - _OP_i8 - _OP_i16 - _OP_i32 - _OP_i64 - _OP_u8 - _OP_u16 - _OP_u32 - _OP_u64 - _OP_f32 - _OP_f64 - _OP_str - _OP_bin - _OP_quote - _OP_number - _OP_eface - _OP_iface - _OP_byte - _OP_text - _OP_deref - _OP_index - _OP_load - _OP_save - _OP_drop - _OP_drop_2 - _OP_recurse - _OP_is_nil - _OP_is_nil_p1 - _OP_is_zero_1 - _OP_is_zero_2 - _OP_is_zero_4 - _OP_is_zero_8 - _OP_is_zero_map - _OP_goto - _OP_map_iter - _OP_map_stop - _OP_map_check_key - _OP_map_write_key - _OP_map_value_next - _OP_slice_len - _OP_slice_next - _OP_marshal - _OP_marshal_p - _OP_marshal_text - _OP_marshal_text_p - _OP_cond_set - _OP_cond_testc -) - -const ( - _INT_SIZE = 32 << (^uint(0) >> 63) - _PTR_SIZE = 32 << (^uintptr(0) >> 63) - _PTR_BYTE = unsafe.Sizeof(uintptr(0)) -) - -const ( - _MAX_ILBUF = 100000 // cutoff at 100k of IL instructions - _MAX_FIELDS = 50 // cutoff at 50 fields struct -) - -var _OpNames = [256]string { - _OP_null : "null", - _OP_empty_arr : "empty_arr", - _OP_empty_obj : "empty_obj", - _OP_bool : "bool", - _OP_i8 : "i8", - _OP_i16 : "i16", - _OP_i32 : "i32", - _OP_i64 : "i64", - _OP_u8 : "u8", - _OP_u16 : "u16", - _OP_u32 : "u32", - _OP_u64 : "u64", - _OP_f32 : "f32", - _OP_f64 : "f64", - _OP_str : "str", - _OP_bin : "bin", - _OP_quote : "quote", - _OP_number : "number", - _OP_eface : "eface", - _OP_iface : "iface", - _OP_byte : "byte", - _OP_text : "text", - _OP_deref : "deref", - _OP_index : "index", - _OP_load : "load", - _OP_save : "save", - _OP_drop : "drop", - _OP_drop_2 : "drop_2", - _OP_recurse : "recurse", - _OP_is_nil : "is_nil", - _OP_is_nil_p1 : "is_nil_p1", - _OP_is_zero_1 : "is_zero_1", - _OP_is_zero_2 : "is_zero_2", - _OP_is_zero_4 : "is_zero_4", - _OP_is_zero_8 : "is_zero_8", - _OP_is_zero_map : "is_zero_map", - _OP_goto : "goto", - _OP_map_iter : "map_iter", - _OP_map_stop : "map_stop", - _OP_map_check_key : "map_check_key", - _OP_map_write_key : "map_write_key", - _OP_map_value_next : "map_value_next", - _OP_slice_len : "slice_len", - _OP_slice_next : "slice_next", - _OP_marshal : "marshal", - _OP_marshal_p : "marshal_p", - _OP_marshal_text : "marshal_text", - _OP_marshal_text_p : "marshal_text_p", - _OP_cond_set : "cond_set", - _OP_cond_testc : "cond_testc", -} - -func (self _Op) String() string { - if ret := _OpNames[self]; ret != "" { - return ret - } else { - return "" - } -} - -func _OP_int() _Op { - switch _INT_SIZE { - case 32: return _OP_i32 - case 64: return _OP_i64 - default: panic("unsupported int size") - } -} - -func _OP_uint() _Op { - switch _INT_SIZE { - case 32: return _OP_u32 - case 64: return _OP_u64 - default: panic("unsupported uint size") - } -} - -func _OP_uintptr() _Op { - switch _PTR_SIZE { - case 32: return _OP_u32 - case 64: return _OP_u64 - default: panic("unsupported pointer size") - } -} - -func _OP_is_zero_ints() _Op { - switch _INT_SIZE { - case 32: return _OP_is_zero_4 - case 64: return _OP_is_zero_8 - default: panic("unsupported integer size") - } -} - -type _Instr struct { - u uint64 // union {op: 8, _: 8, vi: 48}, vi maybe int or len(str) - p unsafe.Pointer // maybe GoString.Ptr, or *GoType -} - -func packOp(op _Op) uint64 { - return uint64(op) << 56 -} - -func newInsOp(op _Op) _Instr { - return _Instr{u: packOp(op)} -} - -func newInsVi(op _Op, vi int) _Instr { - return _Instr{u: packOp(op) | rt.PackInt(vi)} -} - -func newInsVs(op _Op, vs string) _Instr { - return _Instr { - u: packOp(op) | rt.PackInt(len(vs)), - p: (*rt.GoString)(unsafe.Pointer(&vs)).Ptr, - } -} - -func newInsVt(op _Op, vt reflect.Type) _Instr { - return _Instr { - u: packOp(op), - p: unsafe.Pointer(rt.UnpackType(vt)), - } -} - -func newInsVp(op _Op, vt reflect.Type, pv bool) _Instr { - i := 0 - if pv { - i = 1 - } - return _Instr { - u: packOp(op) | rt.PackInt(i), - p: unsafe.Pointer(rt.UnpackType(vt)), - } -} - -func (self _Instr) op() _Op { - return _Op(self.u >> 56) -} - -func (self _Instr) vi() int { - return rt.UnpackInt(self.u) -} - -func (self _Instr) vf() uint8 { - return (*rt.GoType)(self.p).KindFlags -} - -func (self _Instr) vs() (v string) { - (*rt.GoString)(unsafe.Pointer(&v)).Ptr = self.p - (*rt.GoString)(unsafe.Pointer(&v)).Len = self.vi() - return -} - -func (self _Instr) vk() reflect.Kind { - return (*rt.GoType)(self.p).Kind() -} - -func (self _Instr) vt() reflect.Type { - return (*rt.GoType)(self.p).Pack() -} - -func (self _Instr) vp() (vt reflect.Type, pv bool) { - return (*rt.GoType)(self.p).Pack(), rt.UnpackInt(self.u) == 1 -} - -func (self _Instr) i64() int64 { - return int64(self.vi()) -} - -func (self _Instr) vlen() int { - return int((*rt.GoType)(self.p).Size) -} - -func (self _Instr) isBranch() bool { - switch self.op() { - case _OP_goto : fallthrough - case _OP_is_nil : fallthrough - case _OP_is_nil_p1 : fallthrough - case _OP_is_zero_1 : fallthrough - case _OP_is_zero_2 : fallthrough - case _OP_is_zero_4 : fallthrough - case _OP_is_zero_8 : fallthrough - case _OP_map_check_key : fallthrough - case _OP_map_write_key : fallthrough - case _OP_slice_next : fallthrough - case _OP_cond_testc : return true - default : return false - } -} - -func (self _Instr) disassemble() string { - switch self.op() { - case _OP_byte : return fmt.Sprintf("%-18s%s", self.op().String(), strconv.QuoteRune(rune(self.vi()))) - case _OP_text : return fmt.Sprintf("%-18s%s", self.op().String(), strconv.Quote(self.vs())) - case _OP_index : return fmt.Sprintf("%-18s%d", self.op().String(), self.vi()) - case _OP_recurse : fallthrough - case _OP_map_iter : fallthrough - case _OP_marshal : fallthrough - case _OP_marshal_p : fallthrough - case _OP_marshal_text : fallthrough - case _OP_marshal_text_p : return fmt.Sprintf("%-18s%s", self.op().String(), self.vt()) - case _OP_goto : fallthrough - case _OP_is_nil : fallthrough - case _OP_is_nil_p1 : fallthrough - case _OP_is_zero_1 : fallthrough - case _OP_is_zero_2 : fallthrough - case _OP_is_zero_4 : fallthrough - case _OP_is_zero_8 : fallthrough - case _OP_is_zero_map : fallthrough - case _OP_cond_testc : fallthrough - case _OP_map_check_key : fallthrough - case _OP_map_write_key : return fmt.Sprintf("%-18sL_%d", self.op().String(), self.vi()) - case _OP_slice_next : return fmt.Sprintf("%-18sL_%d, %s", self.op().String(), self.vi(), self.vt()) - default : return self.op().String() - } -} - -type ( - _Program []_Instr -) - -func (self _Program) pc() int { - return len(self) -} - -func (self _Program) tag(n int) { - if n >= _MaxStack { - panic("type nesting too deep") - } -} - -func (self _Program) pin(i int) { - v := &self[i] - v.u &= 0xffff000000000000 - v.u |= rt.PackInt(self.pc()) -} - -func (self _Program) rel(v []int) { - for _, i := range v { - self.pin(i) - } -} - -func (self *_Program) add(op _Op) { - *self = append(*self, newInsOp(op)) -} - -func (self *_Program) key(op _Op) { - *self = append(*self, - newInsVi(_OP_byte, '"'), - newInsOp(op), - newInsVi(_OP_byte, '"'), - ) -} - -func (self *_Program) int(op _Op, vi int) { - *self = append(*self, newInsVi(op, vi)) -} - -func (self *_Program) str(op _Op, vs string) { - *self = append(*self, newInsVs(op, vs)) -} - -func (self *_Program) rtt(op _Op, vt reflect.Type) { - *self = append(*self, newInsVt(op, vt)) -} - -func (self *_Program) vp(op _Op, vt reflect.Type, pv bool) { - *self = append(*self, newInsVp(op, vt, pv)) -} - -func (self _Program) disassemble() string { - nb := len(self) - tab := make([]bool, nb + 1) - ret := make([]string, 0, nb + 1) - - /* prescan to get all the labels */ - for _, ins := range self { - if ins.isBranch() { - tab[ins.vi()] = true - } - } - - /* disassemble each instruction */ - for i, ins := range self { - if !tab[i] { - ret = append(ret, "\t" + ins.disassemble()) - } else { - ret = append(ret, fmt.Sprintf("L_%d:\n\t%s", i, ins.disassemble())) - } - } - - /* add the last label, if needed */ - if tab[nb] { - ret = append(ret, fmt.Sprintf("L_%d:", nb)) - } - - /* add an "end" indicator, and join all the strings */ - return strings.Join(append(ret, "\tend"), "\n") -} - -type _Compiler struct { - opts option.CompileOptions - pv bool - tab map[reflect.Type]bool - rec map[reflect.Type]uint8 -} - -func newCompiler() *_Compiler { - return &_Compiler { - opts: option.DefaultCompileOptions(), - tab: map[reflect.Type]bool{}, - rec: map[reflect.Type]uint8{}, - } -} - -func (self *_Compiler) apply(opts option.CompileOptions) *_Compiler { - self.opts = opts - if self.opts.RecursiveDepth > 0 { - self.rec = map[reflect.Type]uint8{} - } - return self -} - -func (self *_Compiler) rescue(ep *error) { - if val := recover(); val != nil { - if err, ok := val.(error); ok { - *ep = err - } else { - panic(val) - } - } -} - -func (self *_Compiler) compile(vt reflect.Type, pv bool) (ret _Program, err error) { - defer self.rescue(&err) - self.compileOne(&ret, 0, vt, pv) - return -} - -func (self *_Compiler) compileOne(p *_Program, sp int, vt reflect.Type, pv bool) { - if self.tab[vt] { - p.vp(_OP_recurse, vt, pv) - } else { - self.compileRec(p, sp, vt, pv) - } -} - -func (self *_Compiler) compileRec(p *_Program, sp int, vt reflect.Type, pv bool) { - pr := self.pv - pt := reflect.PtrTo(vt) - - /* check for addressable `json.Marshaler` with pointer receiver */ - if pv && pt.Implements(jsonMarshalerType) { - p.rtt(_OP_marshal_p, pt) - return - } - - /* check for `json.Marshaler` */ - if vt.Implements(jsonMarshalerType) { - self.compileMarshaler(p, _OP_marshal, vt, jsonMarshalerType) - return - } - - /* check for addressable `encoding.TextMarshaler` with pointer receiver */ - if pv && pt.Implements(encodingTextMarshalerType) { - p.rtt(_OP_marshal_text_p, pt) - return - } - - /* check for `encoding.TextMarshaler` */ - if vt.Implements(encodingTextMarshalerType) { - self.compileMarshaler(p, _OP_marshal_text, vt, encodingTextMarshalerType) - return - } - - /* enter the recursion, and compile the type */ - self.pv = pv - self.tab[vt] = true - self.compileOps(p, sp, vt) - - /* exit the recursion */ - self.pv = pr - delete(self.tab, vt) -} - -func (self *_Compiler) compileOps(p *_Program, sp int, vt reflect.Type) { - switch vt.Kind() { - case reflect.Bool : p.add(_OP_bool) - case reflect.Int : p.add(_OP_int()) - case reflect.Int8 : p.add(_OP_i8) - case reflect.Int16 : p.add(_OP_i16) - case reflect.Int32 : p.add(_OP_i32) - case reflect.Int64 : p.add(_OP_i64) - case reflect.Uint : p.add(_OP_uint()) - case reflect.Uint8 : p.add(_OP_u8) - case reflect.Uint16 : p.add(_OP_u16) - case reflect.Uint32 : p.add(_OP_u32) - case reflect.Uint64 : p.add(_OP_u64) - case reflect.Uintptr : p.add(_OP_uintptr()) - case reflect.Float32 : p.add(_OP_f32) - case reflect.Float64 : p.add(_OP_f64) - case reflect.String : self.compileString (p, vt) - case reflect.Array : self.compileArray (p, sp, vt.Elem(), vt.Len()) - case reflect.Interface : self.compileInterface (p, vt) - case reflect.Map : self.compileMap (p, sp, vt) - case reflect.Ptr : self.compilePtr (p, sp, vt.Elem()) - case reflect.Slice : self.compileSlice (p, sp, vt.Elem()) - case reflect.Struct : self.compileStruct (p, sp, vt) - default : panic (error_type(vt)) - } -} - -func (self *_Compiler) compileNil(p *_Program, sp int, vt reflect.Type, nil_op _Op, fn func(*_Program, int, reflect.Type)) { - x := p.pc() - p.add(_OP_is_nil) - fn(p, sp, vt) - e := p.pc() - p.add(_OP_goto) - p.pin(x) - p.add(nil_op) - p.pin(e) -} - -func (self *_Compiler) compilePtr(p *_Program, sp int, vt reflect.Type) { - self.compileNil(p, sp, vt, _OP_null, self.compilePtrBody) -} - -func (self *_Compiler) compilePtrBody(p *_Program, sp int, vt reflect.Type) { - p.tag(sp) - p.add(_OP_save) - p.add(_OP_deref) - self.compileOne(p, sp + 1, vt, true) - p.add(_OP_drop) -} - -func (self *_Compiler) compileMap(p *_Program, sp int, vt reflect.Type) { - self.compileNil(p, sp, vt, _OP_empty_obj, self.compileMapBody) -} - -func (self *_Compiler) compileMapBody(p *_Program, sp int, vt reflect.Type) { - p.tag(sp + 1) - p.int(_OP_byte, '{') - p.add(_OP_save) - p.rtt(_OP_map_iter, vt) - p.add(_OP_save) - i := p.pc() - p.add(_OP_map_check_key) - u := p.pc() - p.add(_OP_map_write_key) - self.compileMapBodyKey(p, vt.Key()) - p.pin(u) - p.int(_OP_byte, ':') - p.add(_OP_map_value_next) - self.compileOne(p, sp + 2, vt.Elem(), false) - j := p.pc() - p.add(_OP_map_check_key) - p.int(_OP_byte, ',') - v := p.pc() - p.add(_OP_map_write_key) - self.compileMapBodyKey(p, vt.Key()) - p.pin(v) - p.int(_OP_byte, ':') - p.add(_OP_map_value_next) - self.compileOne(p, sp + 2, vt.Elem(), false) - p.int(_OP_goto, j) - p.pin(i) - p.pin(j) - p.add(_OP_map_stop) - p.add(_OP_drop_2) - p.int(_OP_byte, '}') -} - -func (self *_Compiler) compileMapBodyKey(p *_Program, vk reflect.Type) { - if !vk.Implements(encodingTextMarshalerType) { - self.compileMapBodyTextKey(p, vk) - } else { - self.compileMapBodyUtextKey(p, vk) - } -} - -func (self *_Compiler) compileMapBodyTextKey(p *_Program, vk reflect.Type) { - switch vk.Kind() { - case reflect.Invalid : panic("map key is nil") - case reflect.Bool : p.key(_OP_bool) - case reflect.Int : p.key(_OP_int()) - case reflect.Int8 : p.key(_OP_i8) - case reflect.Int16 : p.key(_OP_i16) - case reflect.Int32 : p.key(_OP_i32) - case reflect.Int64 : p.key(_OP_i64) - case reflect.Uint : p.key(_OP_uint()) - case reflect.Uint8 : p.key(_OP_u8) - case reflect.Uint16 : p.key(_OP_u16) - case reflect.Uint32 : p.key(_OP_u32) - case reflect.Uint64 : p.key(_OP_u64) - case reflect.Uintptr : p.key(_OP_uintptr()) - case reflect.Float32 : p.key(_OP_f32) - case reflect.Float64 : p.key(_OP_f64) - case reflect.String : self.compileString(p, vk) - default : panic(error_type(vk)) - } -} - -func (self *_Compiler) compileMapBodyUtextKey(p *_Program, vk reflect.Type) { - if vk.Kind() != reflect.Ptr { - p.rtt(_OP_marshal_text, vk) - } else { - self.compileMapBodyUtextPtr(p, vk) - } -} - -func (self *_Compiler) compileMapBodyUtextPtr(p *_Program, vk reflect.Type) { - i := p.pc() - p.add(_OP_is_nil) - p.rtt(_OP_marshal_text, vk) - j := p.pc() - p.add(_OP_goto) - p.pin(i) - p.str(_OP_text, "\"\"") - p.pin(j) -} - -func (self *_Compiler) compileSlice(p *_Program, sp int, vt reflect.Type) { - self.compileNil(p, sp, vt, _OP_empty_arr, self.compileSliceBody) -} - -func (self *_Compiler) compileSliceBody(p *_Program, sp int, vt reflect.Type) { - if isSimpleByte(vt) { - p.add(_OP_bin) - } else { - self.compileSliceArray(p, sp, vt) - } -} - -func (self *_Compiler) compileSliceArray(p *_Program, sp int, vt reflect.Type) { - p.tag(sp) - p.int(_OP_byte, '[') - p.add(_OP_save) - p.add(_OP_slice_len) - i := p.pc() - p.rtt(_OP_slice_next, vt) - self.compileOne(p, sp + 1, vt, true) - j := p.pc() - p.rtt(_OP_slice_next, vt) - p.int(_OP_byte, ',') - self.compileOne(p, sp + 1, vt, true) - p.int(_OP_goto, j) - p.pin(i) - p.pin(j) - p.add(_OP_drop) - p.int(_OP_byte, ']') -} - -func (self *_Compiler) compileArray(p *_Program, sp int, vt reflect.Type, nb int) { - p.tag(sp) - p.int(_OP_byte, '[') - p.add(_OP_save) - - /* first item */ - if nb != 0 { - self.compileOne(p, sp + 1, vt, self.pv) - p.add(_OP_load) - } - - /* remaining items */ - for i := 1; i < nb; i++ { - p.int(_OP_byte, ',') - p.int(_OP_index, i * int(vt.Size())) - self.compileOne(p, sp + 1, vt, self.pv) - p.add(_OP_load) - } - - /* end of array */ - p.add(_OP_drop) - p.int(_OP_byte, ']') -} - -func (self *_Compiler) compileString(p *_Program, vt reflect.Type) { - if vt != jsonNumberType { - p.add(_OP_str) - } else { - p.add(_OP_number) - } -} - -func (self *_Compiler) compileStruct(p *_Program, sp int, vt reflect.Type) { - if sp >= self.opts.MaxInlineDepth || p.pc() >= _MAX_ILBUF || (sp > 0 && vt.NumField() >= _MAX_FIELDS) { - p.vp(_OP_recurse, vt, self.pv) - if self.opts.RecursiveDepth > 0 { - if self.pv { - self.rec[vt] = 1 - } else { - self.rec[vt] = 0 - } - } - } else { - self.compileStructBody(p, sp, vt) - } -} - -func (self *_Compiler) compileStructBody(p *_Program, sp int, vt reflect.Type) { - p.tag(sp) - p.int(_OP_byte, '{') - p.add(_OP_save) - p.add(_OP_cond_set) - - /* compile each field */ - for _, fv := range resolver.ResolveStruct(vt) { - var s []int - var o resolver.Offset - - /* "omitempty" for arrays */ - if fv.Type.Kind() == reflect.Array { - if fv.Type.Len() == 0 && (fv.Opts & resolver.F_omitempty) != 0 { - continue - } - } - - /* index to the field */ - for _, o = range fv.Path { - if p.int(_OP_index, int(o.Size)); o.Kind == resolver.F_deref { - s = append(s, p.pc()) - p.add(_OP_is_nil) - p.add(_OP_deref) - } - } - - /* check for "omitempty" option */ - if fv.Type.Kind() != reflect.Struct && fv.Type.Kind() != reflect.Array && (fv.Opts & resolver.F_omitempty) != 0 { - s = append(s, p.pc()) - self.compileStructFieldZero(p, fv.Type) - } - - /* add the comma if not the first element */ - i := p.pc() - p.add(_OP_cond_testc) - p.int(_OP_byte, ',') - p.pin(i) - - /* compile the key and value */ - ft := fv.Type - p.str(_OP_text, Quote(fv.Name) + ":") - - /* check for "stringnize" option */ - if (fv.Opts & resolver.F_stringize) == 0 { - self.compileOne(p, sp + 1, ft, self.pv) - } else { - self.compileStructFieldStr(p, sp + 1, ft) - } - - /* patch the skipping jumps and reload the struct pointer */ - p.rel(s) - p.add(_OP_load) - } - - /* end of object */ - p.add(_OP_drop) - p.int(_OP_byte, '}') -} - -func (self *_Compiler) compileStructFieldStr(p *_Program, sp int, vt reflect.Type) { - pc := -1 - ft := vt - sv := false - - /* dereference the pointer if needed */ - if ft.Kind() == reflect.Ptr { - ft = ft.Elem() - } - - /* check if it can be stringized */ - switch ft.Kind() { - case reflect.Bool : sv = true - case reflect.Int : sv = true - case reflect.Int8 : sv = true - case reflect.Int16 : sv = true - case reflect.Int32 : sv = true - case reflect.Int64 : sv = true - case reflect.Uint : sv = true - case reflect.Uint8 : sv = true - case reflect.Uint16 : sv = true - case reflect.Uint32 : sv = true - case reflect.Uint64 : sv = true - case reflect.Uintptr : sv = true - case reflect.Float32 : sv = true - case reflect.Float64 : sv = true - case reflect.String : sv = true - } - - /* if it's not, ignore the "string" and follow the regular path */ - if !sv { - self.compileOne(p, sp, vt, self.pv) - return - } - - /* dereference the pointer */ - if vt.Kind() == reflect.Ptr { - pc = p.pc() - vt = vt.Elem() - p.add(_OP_is_nil) - p.add(_OP_deref) - } - - /* special case of a double-quoted string */ - if ft != jsonNumberType && ft.Kind() == reflect.String { - p.add(_OP_quote) - } else { - self.compileStructFieldQuoted(p, sp, vt) - } - - /* the "null" case of the pointer */ - if pc != -1 { - e := p.pc() - p.add(_OP_goto) - p.pin(pc) - p.add(_OP_null) - p.pin(e) - } -} - -func (self *_Compiler) compileStructFieldZero(p *_Program, vt reflect.Type) { - switch vt.Kind() { - case reflect.Bool : p.add(_OP_is_zero_1) - case reflect.Int : p.add(_OP_is_zero_ints()) - case reflect.Int8 : p.add(_OP_is_zero_1) - case reflect.Int16 : p.add(_OP_is_zero_2) - case reflect.Int32 : p.add(_OP_is_zero_4) - case reflect.Int64 : p.add(_OP_is_zero_8) - case reflect.Uint : p.add(_OP_is_zero_ints()) - case reflect.Uint8 : p.add(_OP_is_zero_1) - case reflect.Uint16 : p.add(_OP_is_zero_2) - case reflect.Uint32 : p.add(_OP_is_zero_4) - case reflect.Uint64 : p.add(_OP_is_zero_8) - case reflect.Uintptr : p.add(_OP_is_nil) - case reflect.Float32 : p.add(_OP_is_zero_4) - case reflect.Float64 : p.add(_OP_is_zero_8) - case reflect.String : p.add(_OP_is_nil_p1) - case reflect.Interface : p.add(_OP_is_nil_p1) - case reflect.Map : p.add(_OP_is_zero_map) - case reflect.Ptr : p.add(_OP_is_nil) - case reflect.Slice : p.add(_OP_is_nil_p1) - default : panic(error_type(vt)) - } -} - -func (self *_Compiler) compileStructFieldQuoted(p *_Program, sp int, vt reflect.Type) { - p.int(_OP_byte, '"') - self.compileOne(p, sp, vt, self.pv) - p.int(_OP_byte, '"') -} - -func (self *_Compiler) compileInterface(p *_Program, vt reflect.Type) { - x := p.pc() - p.add(_OP_is_nil_p1) - - /* iface and efaces are different */ - if vt.NumMethod() == 0 { - p.add(_OP_eface) - } else { - p.add(_OP_iface) - } - - /* the "null" value */ - e := p.pc() - p.add(_OP_goto) - p.pin(x) - p.add(_OP_null) - p.pin(e) -} - -func (self *_Compiler) compileMarshaler(p *_Program, op _Op, vt reflect.Type, mt reflect.Type) { - pc := p.pc() - vk := vt.Kind() - - /* direct receiver */ - if vk != reflect.Ptr { - p.rtt(op, vt) - return - } - - /* value receiver with a pointer type, check for nil before calling the marshaler */ - p.add(_OP_is_nil) - p.rtt(op, vt) - i := p.pc() - p.add(_OP_goto) - p.pin(pc) - p.add(_OP_null) - p.pin(i) +func ForceUseVM() { + vm.SetCompiler(makeEncoderVM) + pretouchType = pretouchTypeVM + encodeTypedPointer = vm.EncodeTypedPointer + vars.UseVM = true +} + +var encodeTypedPointer func(buf *[]byte, vt *rt.GoType, vp *unsafe.Pointer, sb *vars.Stack, fv uint64) error + +func makeEncoderVM(vt *rt.GoType, ex ...interface{}) (interface{}, error) { + pp, err := NewCompiler().Compile(vt.Pack(), ex[0].(bool)) + if err != nil { + return nil, err + } + return &pp, nil +} + +var pretouchType func(_vt reflect.Type, opts option.CompileOptions, v uint8) (map[reflect.Type]uint8, error) + +func pretouchTypeVM(_vt reflect.Type, opts option.CompileOptions, v uint8) (map[reflect.Type]uint8, error) { + /* compile function */ + compiler := NewCompiler().apply(opts) + + /* find or compile */ + vt := rt.UnpackType(_vt) + if val := vars.GetProgram(vt); val != nil { + return nil, nil + } else if _, err := vars.ComputeProgram(vt, makeEncoderVM, v == 1); err == nil { + return compiler.rec, nil + } else { + return nil, err + } +} + +func pretouchRec(vtm map[reflect.Type]uint8, opts option.CompileOptions) error { + if opts.RecursiveDepth < 0 || len(vtm) == 0 { + return nil + } + next := make(map[reflect.Type]uint8) + for vt, v := range vtm { + sub, err := pretouchType(vt, opts, v) + if err != nil { + return err + } + for svt, v := range sub { + next[svt] = v + } + } + opts.RecursiveDepth -= 1 + return pretouchRec(next, opts) +} + +type Compiler struct { + opts option.CompileOptions + pv bool + tab map[reflect.Type]bool + rec map[reflect.Type]uint8 +} + +func NewCompiler() *Compiler { + return &Compiler{ + opts: option.DefaultCompileOptions(), + tab: map[reflect.Type]bool{}, + rec: map[reflect.Type]uint8{}, + } +} + +func (self *Compiler) apply(opts option.CompileOptions) *Compiler { + self.opts = opts + if self.opts.RecursiveDepth > 0 { + self.rec = map[reflect.Type]uint8{} + } + return self +} + +func (self *Compiler) rescue(ep *error) { + if val := recover(); val != nil { + if err, ok := val.(error); ok { + *ep = err + } else { + panic(val) + } + } +} + +func (self *Compiler) Compile(vt reflect.Type, pv bool) (ret ir.Program, err error) { + defer self.rescue(&err) + self.compileOne(&ret, 0, vt, pv) + return +} + +func (self *Compiler) compileOne(p *ir.Program, sp int, vt reflect.Type, pv bool) { + if self.tab[vt] { + p.Vp(ir.OP_recurse, vt, pv) + } else { + self.compileRec(p, sp, vt, pv) + } +} + +func (self *Compiler) tryCompileMarshaler(p *ir.Program, vt reflect.Type, pv bool) bool { + pt := reflect.PtrTo(vt) + + /* check for addressable `json.Marshaler` with pointer receiver */ + if pv && pt.Implements(vars.JsonMarshalerType) { + addMarshalerOp(p, ir.OP_marshal_p, pt, vars.JsonMarshalerType) + return true + } + + /* check for `json.Marshaler` */ + if vt.Implements(vars.JsonMarshalerType) { + self.compileMarshaler(p, ir.OP_marshal, vt, vars.JsonMarshalerType) + return true + } + + /* check for addressable `encoding.TextMarshaler` with pointer receiver */ + if pv && pt.Implements(vars.EncodingTextMarshalerType) { + addMarshalerOp(p, ir.OP_marshal_text_p, pt, vars.EncodingTextMarshalerType) + return true + } + + /* check for `encoding.TextMarshaler` */ + if vt.Implements(vars.EncodingTextMarshalerType) { + self.compileMarshaler(p, ir.OP_marshal_text, vt, vars.EncodingTextMarshalerType) + return true + } + + return false +} + +func (self *Compiler) compileRec(p *ir.Program, sp int, vt reflect.Type, pv bool) { + pr := self.pv + + if self.tryCompileMarshaler(p, vt, pv) { + return + } + + /* enter the recursion, and compile the type */ + self.pv = pv + self.tab[vt] = true + self.compileOps(p, sp, vt) + + /* exit the recursion */ + self.pv = pr + delete(self.tab, vt) +} + +func (self *Compiler) compileOps(p *ir.Program, sp int, vt reflect.Type) { + switch vt.Kind() { + case reflect.Bool: + p.Add(ir.OP_bool) + case reflect.Int: + p.Add(ir.OP_int()) + case reflect.Int8: + p.Add(ir.OP_i8) + case reflect.Int16: + p.Add(ir.OP_i16) + case reflect.Int32: + p.Add(ir.OP_i32) + case reflect.Int64: + p.Add(ir.OP_i64) + case reflect.Uint: + p.Add(ir.OP_uint()) + case reflect.Uint8: + p.Add(ir.OP_u8) + case reflect.Uint16: + p.Add(ir.OP_u16) + case reflect.Uint32: + p.Add(ir.OP_u32) + case reflect.Uint64: + p.Add(ir.OP_u64) + case reflect.Uintptr: + p.Add(ir.OP_uintptr()) + case reflect.Float32: + p.Add(ir.OP_f32) + case reflect.Float64: + p.Add(ir.OP_f64) + case reflect.String: + self.compileString(p, vt) + case reflect.Array: + self.compileArray(p, sp, vt.Elem(), vt.Len()) + case reflect.Interface: + self.compileInterface(p, vt) + case reflect.Map: + self.compileMap(p, sp, vt) + case reflect.Ptr: + self.compilePtr(p, sp, vt.Elem()) + case reflect.Slice: + self.compileSlice(p, sp, vt.Elem()) + case reflect.Struct: + self.compileStruct(p, sp, vt) + default: + panic(vars.Error_type(vt)) + } +} + +func (self *Compiler) compileNil(p *ir.Program, sp int, vt reflect.Type, nil_op ir.Op, fn func(*ir.Program, int, reflect.Type)) { + x := p.PC() + p.Add(ir.OP_is_nil) + fn(p, sp, vt) + e := p.PC() + p.Add(ir.OP_goto) + p.Pin(x) + p.Add(nil_op) + p.Pin(e) +} + +func (self *Compiler) compilePtr(p *ir.Program, sp int, vt reflect.Type) { + self.compileNil(p, sp, vt, ir.OP_null, self.compilePtrBody) +} + +func (self *Compiler) compilePtrBody(p *ir.Program, sp int, vt reflect.Type) { + p.Tag(sp) + p.Add(ir.OP_save) + p.Add(ir.OP_deref) + self.compileOne(p, sp+1, vt, true) + p.Add(ir.OP_drop) +} + +func (self *Compiler) compileMap(p *ir.Program, sp int, vt reflect.Type) { + self.compileNil(p, sp, vt, ir.OP_empty_obj, self.compileMapBody) +} + +func (self *Compiler) compileMapBody(p *ir.Program, sp int, vt reflect.Type) { + p.Tag(sp + 1) + p.Int(ir.OP_byte, '{') + e := p.PC() + p.Add(ir.OP_is_zero_map) + p.Add(ir.OP_save) + p.Rtt(ir.OP_map_iter, vt) + p.Add(ir.OP_save) + i := p.PC() + p.Add(ir.OP_map_check_key) + u := p.PC() + p.Add(ir.OP_map_write_key) + self.compileMapBodyKey(p, vt.Key()) + p.Pin(u) + p.Int(ir.OP_byte, ':') + p.Add(ir.OP_map_value_next) + self.compileOne(p, sp+2, vt.Elem(), false) + j := p.PC() + p.Add(ir.OP_map_check_key) + p.Int(ir.OP_byte, ',') + v := p.PC() + p.Add(ir.OP_map_write_key) + self.compileMapBodyKey(p, vt.Key()) + p.Pin(v) + p.Int(ir.OP_byte, ':') + p.Add(ir.OP_map_value_next) + self.compileOne(p, sp+2, vt.Elem(), false) + p.Int(ir.OP_goto, j) + p.Pin(i) + p.Pin(j) + p.Add(ir.OP_map_stop) + p.Add(ir.OP_drop_2) + p.Pin(e) + p.Int(ir.OP_byte, '}') +} + +func (self *Compiler) compileMapBodyKey(p *ir.Program, vk reflect.Type) { + if !vk.Implements(vars.EncodingTextMarshalerType) { + self.compileMapBodyTextKey(p, vk) + } else { + self.compileMapBodyUtextKey(p, vk) + } +} + +func (self *Compiler) compileMapBodyTextKey(p *ir.Program, vk reflect.Type) { + switch vk.Kind() { + case reflect.Invalid: + panic("map key is nil") + case reflect.Bool: + p.Key(ir.OP_bool) + case reflect.Int: + p.Key(ir.OP_int()) + case reflect.Int8: + p.Key(ir.OP_i8) + case reflect.Int16: + p.Key(ir.OP_i16) + case reflect.Int32: + p.Key(ir.OP_i32) + case reflect.Int64: + p.Key(ir.OP_i64) + case reflect.Uint: + p.Key(ir.OP_uint()) + case reflect.Uint8: + p.Key(ir.OP_u8) + case reflect.Uint16: + p.Key(ir.OP_u16) + case reflect.Uint32: + p.Key(ir.OP_u32) + case reflect.Uint64: + p.Key(ir.OP_u64) + case reflect.Uintptr: + p.Key(ir.OP_uintptr()) + case reflect.Float32: + p.Key(ir.OP_f32) + case reflect.Float64: + p.Key(ir.OP_f64) + case reflect.String: + self.compileString(p, vk) + default: + panic(vars.Error_type(vk)) + } +} + +func (self *Compiler) compileMapBodyUtextKey(p *ir.Program, vk reflect.Type) { + if vk.Kind() != reflect.Ptr { + addMarshalerOp(p, ir.OP_marshal_text, vk, vars.EncodingTextMarshalerType) + } else { + self.compileMapBodyUtextPtr(p, vk) + } +} + +func (self *Compiler) compileMapBodyUtextPtr(p *ir.Program, vk reflect.Type) { + i := p.PC() + p.Add(ir.OP_is_nil) + addMarshalerOp(p, ir.OP_marshal_text, vk, vars.EncodingTextMarshalerType) + j := p.PC() + p.Add(ir.OP_goto) + p.Pin(i) + p.Str(ir.OP_text, "\"\"") + p.Pin(j) +} + +func (self *Compiler) compileSlice(p *ir.Program, sp int, vt reflect.Type) { + self.compileNil(p, sp, vt, ir.OP_empty_arr, self.compileSliceBody) +} + +func (self *Compiler) compileSliceBody(p *ir.Program, sp int, vt reflect.Type) { + if vars.IsSimpleByte(vt) { + p.Add(ir.OP_bin) + } else { + self.compileSliceArray(p, sp, vt) + } +} + +func (self *Compiler) compileSliceArray(p *ir.Program, sp int, vt reflect.Type) { + p.Tag(sp) + p.Int(ir.OP_byte, '[') + e := p.PC() + p.Add(ir.OP_is_nil) + p.Add(ir.OP_save) + p.Add(ir.OP_slice_len) + i := p.PC() + p.Rtt(ir.OP_slice_next, vt) + self.compileOne(p, sp+1, vt, true) + j := p.PC() + p.Rtt(ir.OP_slice_next, vt) + p.Int(ir.OP_byte, ',') + self.compileOne(p, sp+1, vt, true) + p.Int(ir.OP_goto, j) + p.Pin(i) + p.Pin(j) + p.Add(ir.OP_drop) + p.Pin(e) + p.Int(ir.OP_byte, ']') +} + +func (self *Compiler) compileArray(p *ir.Program, sp int, vt reflect.Type, nb int) { + p.Tag(sp) + p.Int(ir.OP_byte, '[') + p.Add(ir.OP_save) + + /* first item */ + if nb != 0 { + self.compileOne(p, sp+1, vt, self.pv) + p.Add(ir.OP_load) + } + + /* remaining items */ + for i := 1; i < nb; i++ { + p.Int(ir.OP_byte, ',') + p.Int(ir.OP_index, i*int(vt.Size())) + self.compileOne(p, sp+1, vt, self.pv) + p.Add(ir.OP_load) + } + + /* end of array */ + p.Add(ir.OP_drop) + p.Int(ir.OP_byte, ']') +} + +func (self *Compiler) compileString(p *ir.Program, vt reflect.Type) { + if vt != vars.JsonNumberType { + p.Add(ir.OP_str) + } else { + p.Add(ir.OP_number) + } +} + +func (self *Compiler) compileStruct(p *ir.Program, sp int, vt reflect.Type) { + if sp >= self.opts.MaxInlineDepth || p.PC() >= vars.MAX_ILBUF || (sp > 0 && vt.NumField() >= vars.MAX_FIELDS) { + p.Vp(ir.OP_recurse, vt, self.pv) + if self.opts.RecursiveDepth > 0 { + if self.pv { + self.rec[vt] = 1 + } else { + self.rec[vt] = 0 + } + } + } else { + self.compileStructBody(p, sp, vt) + } +} + +func (self *Compiler) compileStructBody(p *ir.Program, sp int, vt reflect.Type) { + p.Tag(sp) + p.Int(ir.OP_byte, '{') + p.Add(ir.OP_save) + p.Add(ir.OP_cond_set) + + /* compile each field */ + for _, fv := range resolver.ResolveStruct(vt) { + var s []int + var o resolver.Offset + + /* "omitempty" for arrays */ + if fv.Type.Kind() == reflect.Array { + if fv.Type.Len() == 0 && (fv.Opts&resolver.F_omitempty) != 0 { + continue + } + } + + /* index to the field */ + for _, o = range fv.Path { + if p.Int(ir.OP_index, int(o.Size)); o.Kind == resolver.F_deref { + s = append(s, p.PC()) + p.Add(ir.OP_is_nil) + p.Add(ir.OP_deref) + } + } + + /* check for "omitempty" option */ + if fv.Type.Kind() != reflect.Struct && fv.Type.Kind() != reflect.Array && (fv.Opts&resolver.F_omitempty) != 0 { + s = append(s, p.PC()) + self.compileStructFieldZero(p, fv.Type) + } + + /* add the comma if not the first element */ + i := p.PC() + p.Add(ir.OP_cond_testc) + p.Int(ir.OP_byte, ',') + p.Pin(i) + + /* compile the key and value */ + ft := fv.Type + p.Str(ir.OP_text, Quote(fv.Name)+":") + + /* check for "stringnize" option */ + if (fv.Opts & resolver.F_stringize) == 0 { + self.compileOne(p, sp+1, ft, self.pv) + } else { + self.compileStructFieldStr(p, sp+1, ft) + } + + /* patch the skipping jumps and reload the struct pointer */ + p.Rel(s) + p.Add(ir.OP_load) + } + + /* end of object */ + p.Add(ir.OP_drop) + p.Int(ir.OP_byte, '}') +} + +func (self *Compiler) compileStructFieldStr(p *ir.Program, sp int, vt reflect.Type) { + // NOTICE: according to encoding/json, Marshaler type has higher priority than string option + // see issue: + if self.tryCompileMarshaler(p, vt, self.pv) { + return + } + + pc := -1 + ft := vt + sv := false + + /* dereference the pointer if needed */ + if ft.Kind() == reflect.Ptr { + ft = ft.Elem() + } + + /* check if it can be stringized */ + switch ft.Kind() { + case reflect.Bool: + sv = true + case reflect.Int: + sv = true + case reflect.Int8: + sv = true + case reflect.Int16: + sv = true + case reflect.Int32: + sv = true + case reflect.Int64: + sv = true + case reflect.Uint: + sv = true + case reflect.Uint8: + sv = true + case reflect.Uint16: + sv = true + case reflect.Uint32: + sv = true + case reflect.Uint64: + sv = true + case reflect.Uintptr: + sv = true + case reflect.Float32: + sv = true + case reflect.Float64: + sv = true + case reflect.String: + sv = true + } + + /* if it's not, ignore the "string" and follow the regular path */ + if !sv { + self.compileOne(p, sp, vt, self.pv) + return + } + + /* dereference the pointer */ + if vt.Kind() == reflect.Ptr { + pc = p.PC() + vt = vt.Elem() + p.Add(ir.OP_is_nil) + p.Add(ir.OP_deref) + } + + /* special case of a double-quoted string */ + if ft != vars.JsonNumberType && ft.Kind() == reflect.String { + p.Add(ir.OP_quote) + } else { + self.compileStructFieldQuoted(p, sp, vt) + } + + /* the "null" case of the pointer */ + if pc != -1 { + e := p.PC() + p.Add(ir.OP_goto) + p.Pin(pc) + p.Add(ir.OP_null) + p.Pin(e) + } +} + +func (self *Compiler) compileStructFieldZero(p *ir.Program, vt reflect.Type) { + switch vt.Kind() { + case reflect.Bool: + p.Add(ir.OP_is_zero_1) + case reflect.Int: + p.Add(ir.OP_is_zero_ints()) + case reflect.Int8: + p.Add(ir.OP_is_zero_1) + case reflect.Int16: + p.Add(ir.OP_is_zero_2) + case reflect.Int32: + p.Add(ir.OP_is_zero_4) + case reflect.Int64: + p.Add(ir.OP_is_zero_8) + case reflect.Uint: + p.Add(ir.OP_is_zero_ints()) + case reflect.Uint8: + p.Add(ir.OP_is_zero_1) + case reflect.Uint16: + p.Add(ir.OP_is_zero_2) + case reflect.Uint32: + p.Add(ir.OP_is_zero_4) + case reflect.Uint64: + p.Add(ir.OP_is_zero_8) + case reflect.Uintptr: + p.Add(ir.OP_is_nil) + case reflect.Float32: + p.Add(ir.OP_is_zero_4) + case reflect.Float64: + p.Add(ir.OP_is_zero_8) + case reflect.String: + p.Add(ir.OP_is_nil_p1) + case reflect.Interface: + p.Add(ir.OP_is_nil) + case reflect.Map: + p.Add(ir.OP_is_zero_map) + case reflect.Ptr: + p.Add(ir.OP_is_nil) + case reflect.Slice: + p.Add(ir.OP_is_nil_p1) + default: + panic(vars.Error_type(vt)) + } +} + +func (self *Compiler) compileStructFieldQuoted(p *ir.Program, sp int, vt reflect.Type) { + p.Int(ir.OP_byte, '"') + self.compileOne(p, sp, vt, self.pv) + p.Int(ir.OP_byte, '"') +} + +func (self *Compiler) compileInterface(p *ir.Program, vt reflect.Type) { + x := p.PC() + p.Add(ir.OP_is_nil_p1) + + /* iface and efaces are different */ + if vt.NumMethod() == 0 { + p.Add(ir.OP_eface) + } else { + p.Add(ir.OP_iface) + } + + /* the "null" value */ + e := p.PC() + p.Add(ir.OP_goto) + p.Pin(x) + p.Add(ir.OP_null) + p.Pin(e) +} + +func (self *Compiler) compileMarshaler(p *ir.Program, op ir.Op, vt reflect.Type, mt reflect.Type) { + pc := p.PC() + vk := vt.Kind() + + /* direct receiver */ + if vk != reflect.Ptr { + addMarshalerOp(p, op, vt, mt) + return + } + /* value receiver with a pointer type, check for nil before calling the marshaler */ + p.Add(ir.OP_is_nil) + + addMarshalerOp(p, op, vt, mt) + + i := p.PC() + p.Add(ir.OP_goto) + p.Pin(pc) + p.Add(ir.OP_null) + p.Pin(i) +} + +func addMarshalerOp(p *ir.Program, op ir.Op, vt reflect.Type, mt reflect.Type) { + if vars.UseVM { + itab := rt.GetItab(rt.IfaceType(rt.UnpackType(mt)), rt.UnpackType(vt), true) + p.Vtab(op, vt, itab) + } else { + // OPT: get itab here + p.Rtt(op, vt) + } } diff --git a/vendor/github.com/bytedance/sonic/internal/encoder/debug_go117.go b/vendor/github.com/bytedance/sonic/internal/encoder/debug_go117.go deleted file mode 100644 index 56a6cbf5e..000000000 --- a/vendor/github.com/bytedance/sonic/internal/encoder/debug_go117.go +++ /dev/null @@ -1,205 +0,0 @@ -// +build go1.17,!go1.22 - -/* - * 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 ( - `fmt` - `os` - `runtime` - `strings` - `unsafe` - - `github.com/bytedance/sonic/internal/jit` - `github.com/twitchyliquid64/golang-asm/obj` -) - -const _FP_debug = 128 - -var ( - debugSyncGC = os.Getenv("SONIC_SYNC_GC") != "" - debugAsyncGC = os.Getenv("SONIC_NO_ASYNC_GC") == "" - debugCheckPtr = os.Getenv("SONIC_CHECK_POINTER") != "" -) - -var ( - _Instr_End = newInsOp(_OP_is_nil) - - _F_gc = jit.Func(gc) - _F_println = jit.Func(println_wrapper) - _F_print = jit.Func(print) -) - -func (self *_Assembler) dsave(r ...obj.Addr) { - for i, v := range r { - if i > _FP_debug / 8 - 1 { - panic("too many registers to save") - } else { - self.Emit("MOVQ", v, jit.Ptr(_SP, _FP_fargs + _FP_saves + _FP_locals + int64(i) * 8)) - } - } -} - -func (self *_Assembler) dload(r ...obj.Addr) { - for i, v := range r { - if i > _FP_debug / 8 - 1 { - panic("too many registers to load") - } else { - self.Emit("MOVQ", jit.Ptr(_SP, _FP_fargs + _FP_saves + _FP_locals + int64(i) * 8), v) - } - } -} - -func println_wrapper(i int, op1 int, op2 int){ - println(i, " Intrs ", op1, _OpNames[op1], "next: ", op2, _OpNames[op2]) -} - -func print(i int){ - println(i) -} - -func gc() { - if !debugSyncGC { - return - } - runtime.GC() - // debug.FreeOSMemory() -} - -func (self *_Assembler) dcall(fn obj.Addr) { - self.Emit("MOVQ", fn, _R10) // MOVQ ${fn}, R10 - self.Rjmp("CALL", _R10) // CALL R10 -} - -func (self *_Assembler) debug_gc() { - if !debugSyncGC { - return - } - self.dsave(_REG_debug...) - self.dcall(_F_gc) - self.dload(_REG_debug...) -} - -func (self *_Assembler) debug_instr(i int, v *_Instr) { - if debugSyncGC { - 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.debug_gc() - } -} - -//go:noescape -//go:linkname checkptrBase runtime.checkptrBase -func checkptrBase(p unsafe.Pointer) uintptr - -//go:noescape -//go:linkname findObject runtime.findObject -func findObject(p, refBase, refOff uintptr) (base uintptr, s unsafe.Pointer, objIndex uintptr) - -var ( - _F_checkptr = jit.Func(checkptr) - _F_printptr = jit.Func(printptr) -) - -var ( - _R10 = jit.Reg("R10") -) -var _REG_debug = []obj.Addr { - jit.Reg("AX"), - jit.Reg("BX"), - jit.Reg("CX"), - jit.Reg("DX"), - jit.Reg("DI"), - jit.Reg("SI"), - jit.Reg("BP"), - jit.Reg("SP"), - jit.Reg("R8"), - jit.Reg("R9"), - jit.Reg("R10"), - jit.Reg("R11"), - jit.Reg("R12"), - jit.Reg("R13"), - jit.Reg("R14"), - jit.Reg("R15"), -} - -func checkptr(ptr uintptr) { - if ptr == 0 { - return - } - fmt.Printf("pointer: %x\n", ptr) - f := checkptrBase(unsafe.Pointer(uintptr(ptr))) - if f == 0 { - fmt.Printf("! unknown-based pointer: %x\n", ptr) - } else if f == 1 { - fmt.Printf("! stack pointer: %x\n", ptr) - } else { - fmt.Printf("base: %x\n", f) - } - findobj(ptr) -} - -func findobj(ptr uintptr) { - base, s, objIndex := findObject(ptr, 0, 0) - if s != nil && base == 0 { - fmt.Printf("! invalid pointer: %x\n", ptr) - } - fmt.Printf("objIndex: %d\n", objIndex) -} - -func (self *_Assembler) check_ptr(ptr obj.Addr, lea bool) { - if !debugCheckPtr { - return - } - - self.dsave(_REG_debug...) - if lea { - self.Emit("LEAQ", ptr, _R10) - } else { - self.Emit("MOVQ", ptr, _R10) - } - self.Emit("MOVQ", _R10, jit.Ptr(_SP, 0)) - self.dcall(_F_checkptr) - self.dload(_REG_debug...) -} - -func printptr(i int, ptr uintptr) { - fmt.Printf("[%d] ptr: %x\n", i, ptr) -} - -func (self *_Assembler) print_ptr(i int, ptr obj.Addr, lea bool) { - self.dsave(_REG_debug...) - if lea { - self.Emit("LEAQ", ptr, _R10) - } else { - self.Emit("MOVQ", ptr, _R10) - } - - self.Emit("MOVQ", jit.Imm(int64(i)), _AX) - self.Emit("MOVQ", _R10, _BX) - self.dcall(_F_printptr) - self.dload(_REG_debug...) -} diff --git a/vendor/github.com/bytedance/sonic/internal/encoder/encode_norace.go b/vendor/github.com/bytedance/sonic/internal/encoder/encode_norace.go new file mode 100644 index 000000000..c53206433 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/encoder/encode_norace.go @@ -0,0 +1,24 @@ +//go:build !race +// +build !race + +/* + * 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 + +func encodeIntoCheckRace(buf *[]byte, val interface{}, opts Options) error { + return encodeInto(buf, val, opts) +} diff --git a/vendor/github.com/bytedance/sonic/internal/encoder/encode_race.go b/vendor/github.com/bytedance/sonic/internal/encoder/encode_race.go new file mode 100644 index 000000000..c373c55f9 --- /dev/null +++ b/vendor/github.com/bytedance/sonic/internal/encoder/encode_race.go @@ -0,0 +1,54 @@ +//go:build race +// +build race + +/* + * 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 ( + `encoding/json` + + `github.com/bytedance/sonic/internal/rt` +) + + +func helpDetectDataRace(val interface{}) { + var out []byte + defer func() { + if v := recover(); v != nil { + // NOTICE: help user to locate where panic occurs + println("panic when encoding on: ", truncate(out)) + panic(v) + } + }() + out, _ = json.Marshal(val) +} + +func encodeIntoCheckRace(buf *[]byte, val interface{}, opts Options) error { + err := encodeInto(buf, val, opts) + /* put last to make the panic from sonic will always be caught at first */ + helpDetectDataRace(val) + return err +} + +func truncate(json []byte) string { + if len(json) <= 256 { + return rt.Mem2Str(json) + } else { + return rt.Mem2Str(json[len(json)-256:]) + } +} diff --git a/vendor/github.com/bytedance/sonic/internal/encoder/encoder.go b/vendor/github.com/bytedance/sonic/internal/encoder/encoder.go index 757e73ff0..4cba1a168 100644 --- a/vendor/github.com/bytedance/sonic/internal/encoder/encoder.go +++ b/vendor/github.com/bytedance/sonic/internal/encoder/encoder.go @@ -17,63 +17,62 @@ package encoder import ( - `bytes` - `encoding/json` - `reflect` - `runtime` - `unsafe` - - `github.com/bytedance/sonic/internal/native` - `github.com/bytedance/sonic/internal/native/types` - `github.com/bytedance/sonic/internal/rt` - `github.com/bytedance/sonic/utf8` - `github.com/bytedance/sonic/option` + "bytes" + "encoding/json" + "reflect" + "runtime" + "unsafe" + + "github.com/bytedance/sonic/utf8" + "github.com/bytedance/sonic/internal/encoder/alg" + "github.com/bytedance/sonic/internal/encoder/vars" + "github.com/bytedance/sonic/internal/rt" + "github.com/bytedance/sonic/option" ) // Options is a set of encoding options. type Options uint64 -const ( - bitSortMapKeys = iota - bitEscapeHTML - bitCompactMarshaler - bitNoQuoteTextMarshaler - bitNoNullSliceOrMap - bitValidateString - - // 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 + SortMapKeys Options = 1 << alg.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 + EscapeHTML Options = 1 << alg.BitEscapeHTML // CompactMarshaler indicates that the output JSON from json.Marshaler // is always compact and needs no validation - CompactMarshaler Options = 1 << bitCompactMarshaler + CompactMarshaler Options = 1 << alg.BitCompactMarshaler // NoQuoteTextMarshaler indicates that the output text from encoding.TextMarshaler // is always escaped string and needs no quoting - NoQuoteTextMarshaler Options = 1 << bitNoQuoteTextMarshaler + NoQuoteTextMarshaler Options = 1 << alg.BitNoQuoteTextMarshaler // NoNullSliceOrMap indicates all empty Array or Object are encoded as '[]' or '{}', - // instead of 'null' - NoNullSliceOrMap Options = 1 << bitNoNullSliceOrMap + // instead of 'null'. + // NOTE: The priority of this option is lower than json tag `omitempty`. + NoNullSliceOrMap Options = 1 << alg.BitNoNullSliceOrMap // ValidateString indicates that encoder should validate the input string // before encoding it into JSON. - ValidateString Options = 1 << bitValidateString + ValidateString Options = 1 << alg.BitValidateString + + // NoValidateJSONMarshaler indicates that the encoder should not validate the output string + // after encoding the JSONMarshaler to JSON. + NoValidateJSONMarshaler Options = 1 << alg.BitNoValidateJSONMarshaler + + // NoEncoderNewline indicates that the encoder should not add a newline after every message + NoEncoderNewline Options = 1 << alg.BitNoEncoderNewline // CompatibleWithStd is used to be compatible with std encoder. CompatibleWithStd Options = SortMapKeys | EscapeHTML | CompactMarshaler + + // Encode Infinity or Nan float into `null`, instead of returning an error. + EncodeNullForInfOrNan Options = 1 << alg.BitEncodeNullForInfOrNan ) // Encoder represents a specific set of encoder configurations. @@ -115,6 +114,25 @@ func (self *Encoder) SetValidateString(f bool) { } } +// 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 { @@ -143,53 +161,45 @@ func (enc *Encoder) SetIndent(prefix, indent string) { // Quote returns the JSON-quoted version of s. func Quote(s string) string { - var n int - var p []byte - - /* check for empty string */ - if s == "" { - return `""` - } - - /* allocate space for result */ - n = len(s) + 2 - p = make([]byte, 0, n) - - /* call the encoder */ - _ = encodeString(&p, s) - return rt.Mem2Str(p) + buf := make([]byte, 0, len(s)+2) + buf = alg.Quote(buf, s, false) + return rt.Mem2Str(buf) } // Encode returns the JSON encoding of val, encoded with opts. func Encode(val interface{}, opts Options) ([]byte, error) { var ret []byte - buf := newBytes() - err := encodeInto(&buf, val, opts) + buf := vars.NewBytes() + err := encodeIntoCheckRace(buf, val, opts) /* check for errors */ if err != nil { - freeBytes(buf) + vars.FreeBytes(buf) return nil, err } /* htmlescape or correct UTF-8 if opts enable */ old := buf - buf = encodeFinish(old, opts) - pbuf := ((*rt.GoSlice)(unsafe.Pointer(&buf))).Ptr - pold := ((*rt.GoSlice)(unsafe.Pointer(&old))).Ptr + *buf = encodeFinish(*old, opts) + pbuf := ((*rt.GoSlice)(unsafe.Pointer(buf))).Ptr + pold := ((*rt.GoSlice)(unsafe.Pointer(old))).Ptr /* return when allocated a new buffer */ if pbuf != pold { - freeBytes(old) - return buf, nil + vars.FreeBytes(old) + return *buf, nil } /* make a copy of the result */ - ret = make([]byte, len(buf)) - copy(ret, buf) - - freeBytes(buf) + if rt.CanSizeResue(cap(*buf)) { + ret = make([]byte, len(*buf)) + copy(ret, *buf) + vars.FreeBytes(buf) + } else { + ret = *buf + } + /* return the buffer into pool */ return ret, nil } @@ -197,7 +207,7 @@ func Encode(val interface{}, opts Options) ([]byte, error) { // 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 { - err := encodeInto(buf, val, opts) + err := encodeIntoCheckRace(buf, val, opts) if err != nil { return err } @@ -206,15 +216,15 @@ func EncodeInto(buf *[]byte, val interface{}, opts Options) error { } func encodeInto(buf *[]byte, val interface{}, opts Options) error { - stk := newStack() + stk := vars.NewStack() efv := rt.UnpackEface(val) err := encodeTypedPointer(buf, efv.Type, &efv.Value, stk, uint64(opts)) /* return the stack into pool */ if err != nil { - resetStack(stk) + vars.ResetStack(stk) } - freeStack(stk) + vars.FreeStack(stk) /* avoid GC ahead */ runtime.KeepAlive(buf) @@ -226,13 +236,12 @@ func encodeFinish(buf []byte, opts Options) []byte { if opts & EscapeHTML != 0 { buf = HTMLEscape(nil, buf) } - if opts & ValidateString != 0 && !utf8.Validate(buf) { + if (opts & ValidateString != 0) && !utf8.Validate(buf) { buf = utf8.CorrectWith(nil, buf, `\ufffd`) } return buf } -var typeByte = rt.UnpackType(reflect.TypeOf(byte(0))) // 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 @@ -241,7 +250,7 @@ var typeByte = rt.UnpackType(reflect.TypeOf(byte(0))) // escaping within