Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/compatibility_test-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
build:
strategy:
matrix:
go-version: [1.18.x, 1.21.x, 1.25.x]
go-version: [1.18.x, 1.21.x, 1.25.x, '1.27.0-rc.1']
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/compatibility_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ jobs:
build:
strategy:
matrix:
go-version: [1.18.x, 1.19.x, 1.20.x, 1.21.x, 1.22.x, 1.23.x, 1.24.x, 1.25.x]
os: [ubuntu-latest, ubuntu-24.04-arm, macos-latest]
go-version: [1.18.x, 1.19.x, 1.20.x, 1.21.x, 1.22.x, 1.23.x, 1.24.x, 1.25.x, '1.27.0-rc.1']
os: [ubuntu-latest, ubuntu-24.04-arm, macos-15]
Comment on lines 8 to +10
runs-on: ${{ matrix.os }}
steps:
- name: Clear repository
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-arm64.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:

strategy:
matrix:
go-version: [1.20.x, 1.22.x, 1.25.x]
go-version: [1.20.x, 1.22.x, 1.25.x, '1.27.0-rc.1']
runner_arch: [ubuntu-24.04-arm, macos-latest]

runs-on: ${{ matrix.runner_arch }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-x86.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:

strategy:
matrix:
go-version: [1.18.x, 1.21.x, 1.25.x]
go-version: [1.18.x, 1.21.x, 1.25.x, '1.27.0-rc.1']
runner_arch: [ubuntu-latest]

runs-on: ${{ matrix.runner_arch }}
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ A blazingly fast JSON serializing & deserializing library, accelerated by JI

## Requirement

- Go: 1.18~1.26
- Go: 1.18~1.27
- Notice: Go1.24.0 is not supported due to the [issue](https://github.com/golang/go/issues/71672); please use a higher Go version or pass the build flag `-ldflags="-checklinkname=0"`.
- OS: Linux / MacOS / Windows
- CPU: AMD64 / (ARM64, need go1.20 above)
Expand Down
2 changes: 1 addition & 1 deletion README_ZH_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

## 依赖

- Go: 1.18~1.26
- Go: 1.18~1.27
- 注意:Go1.24.0 由于 [issue](https://github.com/golang/go/issues/71672) 不可用,请升级到更高 Go 版本,或添加编译选项 `--ldflags="-checklinkname=0"`
- OS: Linux / MacOS / Windows
- CPU: AMD64 / (ARM64, 需要 Go1.20 以上)
Expand Down
4 changes: 2 additions & 2 deletions ast/api.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build (amd64 && go1.17 && !go1.27) || (arm64 && go1.20 && !go1.27)
// +build amd64,go1.17,!go1.27 arm64,go1.20,!go1.27
//go:build (amd64 && go1.17 && !go1.28) || (arm64 && go1.20 && !go1.28)
// +build amd64,go1.17,!go1.28 arm64,go1.20,!go1.28

/*
* Copyright 2022 ByteDance Inc.
Expand Down
4 changes: 2 additions & 2 deletions ast/api_compat.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build (!amd64 && !arm64) || go1.27 || !go1.17 || (arm64 && !go1.20)
// +build !amd64,!arm64 go1.27 !go1.17 arm64,!go1.20
//go:build (!amd64 && !arm64) || go1.28 || !go1.17 || (arm64 && !go1.20)
// +build !amd64,!arm64 go1.28 !go1.17 arm64,!go1.20

/*
* Copyright 2022 ByteDance Inc.
Expand Down
4 changes: 2 additions & 2 deletions ast/api_native_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build (amd64 && go1.17 && !go1.27) || (arm64 && go1.20 && !go1.27)
// +build amd64,go1.17,!go1.27 arm64,go1.20,!go1.27
//go:build (amd64 && go1.17 && !go1.28) || (arm64 && go1.20 && !go1.28)
// +build amd64,go1.17,!go1.28 arm64,go1.20,!go1.28

/*
* Copyright 2022 ByteDance Inc.
Expand Down
4 changes: 2 additions & 2 deletions compat.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build (!amd64 && !arm64) || go1.27 || !go1.17 || (arm64 && !go1.20)
// +build !amd64,!arm64 go1.27 !go1.17 arm64,!go1.20
//go:build (!amd64 && !arm64) || go1.28 || !go1.17 || (arm64 && !go1.20)
// +build !amd64,!arm64 go1.28 !go1.17 arm64,!go1.20

/*
* Copyright 2021 ByteDance Inc.
Expand Down
4 changes: 2 additions & 2 deletions decode_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build (amd64 && go1.17 && !go1.27) || (arm64 && go1.20 && !go1.27)
// +build amd64,go1.17,!go1.27 arm64,go1.20,!go1.27
//go:build (amd64 && go1.17 && !go1.28) || (arm64 && go1.20 && !go1.28)
// +build amd64,go1.17,!go1.28 arm64,go1.20,!go1.28

/*
* Copyright 2021 ByteDance Inc.
Expand Down
4 changes: 2 additions & 2 deletions decoder/decoder_compat.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build (!amd64 && !arm64) || go1.27 || !go1.17 || (arm64 && !go1.20)
// +build !amd64,!arm64 go1.27 !go1.17 arm64,!go1.20
//go:build (!amd64 && !arm64) || go1.28 || !go1.17 || (arm64 && !go1.20)
// +build !amd64,!arm64 go1.28 !go1.17 arm64,!go1.20

/*
* Copyright 2023 ByteDance Inc.
Expand Down
4 changes: 2 additions & 2 deletions decoder/decoder_native.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build (amd64 && go1.17 && !go1.27) || (arm64 && go1.20 && !go1.27)
// +build amd64,go1.17,!go1.27 arm64,go1.20,!go1.27
//go:build (amd64 && go1.17 && !go1.28) || (arm64 && go1.20 && !go1.28)
// +build amd64,go1.17,!go1.28 arm64,go1.20,!go1.28

/*
* Copyright 2023 ByteDance Inc.
Expand Down
4 changes: 2 additions & 2 deletions decoder/decoder_native_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build (amd64 && go1.17 && !go1.27) || (arm64 && go1.20 && !go1.27)
// +build amd64,go1.17,!go1.27 arm64,go1.20,!go1.27
//go:build (amd64 && go1.17 && !go1.28) || (arm64 && go1.20 && !go1.28)
// +build amd64,go1.17,!go1.28 arm64,go1.20,!go1.28

/*
* Copyright 2021 ByteDance Inc.
Expand Down
80 changes: 80 additions & 0 deletions docs/json-v2-alignment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Sonic and `encoding/json` v2 (Go 1.27+)

## Background

Starting with **Go 1.27**, the standard library `encoding/json` v1 package is
implemented on top of the new **json v2** implementation (`encoding/json/v2` +
`encoding/json/jsontext`) with v1 compatibility options. The v1 API remains
supported, but some edge cases still produce different errors or values when the
json v2 backend is active. Builds can temporarily opt out with
`GOEXPERIMENT=nojsonv2` (this opt-out is expected to be removed in a future Go
release).

Sonic is a drop-in replacement for `encoding/json` and currently implements
**v1 semantics**. On Go 1.27 with the default json v2 backend, a small set of
legacy parity tests still diverge between `sonic` and the standard library. This
document tracks those divergences.

> Sonic still **builds and runs correctly** on Go 1.27 (native JIT path). These
> are *semantic* differences against the new std reference, not crashes or
> miscompilations in sonic.

## How tests handle this

`issue_test` contains cases that assert byte-for-byte parity or exact error/value
parity against the *live* `encoding/json`. Those cases are gated on a
build-tag-derived constant:

- `issue_test/jsonv2_compat_test.go` (`//go:build goexperiment.jsonv2`) → `stdUsesJSONV2 = true`
- `issue_test/jsonv1_compat_test.go` (`//go:build !goexperiment.jsonv2`) → `stdUsesJSONV2 = false`

The `goexperiment.jsonv2` tag is set automatically when the json v2 backend is
active (default on Go 1.27+, unset under `GOEXPERIMENT=nojsonv2` and on Go ≤1.26).
Tests keep Sonic-only assertions where they have stable expected values and skip
only the std parity check or whole parity-only test when `stdUsesJSONV2` is true,
so:

- Go ≤ 1.26, or Go 1.27 with `GOEXPERIMENT=nojsonv2`: full parity coverage runs.
- Go 1.27 default (v2): the divergent std parity assertions are skipped.

## Known divergences (surfaced by issue_test)

| Test | Area | sonic / legacy behavior | Go 1.27 std jsonv2-backend behavior |
|------|------|---------------------|---------------------------|
| Issue460 | number → float32/float64 overflow | returns error, leaves dest at 0 | saturates dest to `±Inf` (still returns error) |
| Issue491 | marshal/unmarshal unsupported types | `map[*T]*T`, `[]chan T`, etc. error as unsupported | some pointer-keyed maps now marshal successfully; unsupported unmarshal error handling differs |
| Issue747 | map key float32/float64 | v1 parsing | v2 number/key parsing differs |
| Issue144 | `,string` option on pointer/number fields | v1 string-option semantics | v2 string-option semantics |
| Issue379 | unmarshal into `MyPtr`/`**T` with Unmarshaler | v1 pointer-allocation/Unmarshaler dispatch | v2 dispatch differs |
| Issue670 | custom `UnmarshalJSON` error cases | v1 error/typing | v2 error/typing |
| Issue758 | self-referential `interface{}` (`v = &v`) | sonic handles it | **v2 std recurses to stack overflow** (sonic is fine) |
| Issue772 | skipping iface-typed fields (non-ptr / nil) | v1 skip behavior | v2 skip behavior differs |
| Issue824 (`TestFloatMap`) | marshal `map[float64]string` | **errors** (`json: unsupported type: map[float64]string`) | **marshals successfully** (`{"1":""}`) |
| Issue827 | `TextMarshaler` types (e.g. `string3`) | v1 TextMarshaler handling | v2 TextMarshaler handling differs |

Additional documented json v2 behavior changes are likely to affect parity if
Sonic later chooses to expose a v2-compatible mode (not all currently covered by
a dedicated test):

- **Stricter UTF-8**: invalid UTF-8 bytes in JSON strings are rejected.
- **Duplicate object keys**: objects with duplicate member names are rejected.
- Error message text differs (sonic already differs here, generally tolerated).

## Decision / status

- **Supporting Go 1.27 (build + run): done.** Native path validated; full test
suite green under `GOEXPERIMENT=nojsonv2` and with the v2 parity gates above.
- **Aligning Sonic to json v2 behavior: not started — separate workstream.**
This is a larger design question (whether/when Sonic offers a v2-compatible
API). Track here as the list of behaviors to reconcile if/when that work is
scheduled.

## Reproducing locally

```sh
# v2 default (skips parity tests)
env -u GOROOT GOTOOLCHAIN=local /path/to/go1.27/bin/go test ./issue_test/...

# force v1 semantics (full parity coverage)
env -u GOROOT GOEXPERIMENT=nojsonv2 GOTOOLCHAIN=local /path/to/go1.27/bin/go test ./issue_test/...
```
4 changes: 2 additions & 2 deletions encode_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build (amd64 && go1.17 && !go1.27) || (arm64 && go1.20 && !go1.27)
// +build amd64,go1.17,!go1.27 arm64,go1.20,!go1.27
//go:build (amd64 && go1.17 && !go1.28) || (arm64 && go1.20 && !go1.28)
// +build amd64,go1.17,!go1.28 arm64,go1.20,!go1.28

/*
* Copyright 2021 ByteDance Inc.
Expand Down
4 changes: 2 additions & 2 deletions encoder/encoder_compat.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build (!amd64 && !arm64) || go1.27 || !go1.17 || (arm64 && !go1.20)
// +build !amd64,!arm64 go1.27 !go1.17 arm64,!go1.20
//go:build (!amd64 && !arm64) || go1.28 || !go1.17 || (arm64 && !go1.20)
// +build !amd64,!arm64 go1.28 !go1.17 arm64,!go1.20

/*
* Copyright 2023 ByteDance Inc.
Expand Down
4 changes: 2 additions & 2 deletions encoder/encoder_native.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build (amd64 && go1.17 && !go1.27) || (arm64 && go1.20 && !go1.27)
// +build amd64,go1.17,!go1.27 arm64,go1.20,!go1.27
//go:build (amd64 && go1.17 && !go1.28) || (arm64 && go1.20 && !go1.28)
// +build amd64,go1.17,!go1.28 arm64,go1.20,!go1.28

/*
* Copyright 2023 ByteDance Inc.
Expand Down
4 changes: 2 additions & 2 deletions encoder/encoder_native_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build (amd64 && go1.17 && !go1.27) || (arm64 && go1.20 && !go1.27)
// +build amd64,go1.17,!go1.27 arm64,go1.20,!go1.27
//go:build (amd64 && go1.17 && !go1.28) || (arm64 && go1.20 && !go1.28)
// +build amd64,go1.17,!go1.28 arm64,go1.20,!go1.28

/*
* Copyright 2021 ByteDance Inc.
Expand Down
9 changes: 5 additions & 4 deletions internal/compat/warn.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
// +build !amd64,!arm64 go1.27 !go1.17 arm64,!go1.20
//go:build (!amd64 && !arm64) || go1.28 || !go1.17 || (arm64 && !go1.20)
// +build !amd64,!arm64 go1.28 !go1.17 arm64,!go1.20

package compat

import (
"fmt"
"os"
"fmt"
"os"
)

func Warn(prefix string) {
fmt.Fprintf(os.Stderr, "WARNING: %s only supports (go1.17~1.26 and amd64 CPU) or (go1.20~1.26 and arm64 CPU), but your environment is not suitable and will fallback to encoding/json\n", prefix)
fmt.Fprintf(os.Stderr, "WARNING: %s only supports (go1.17~1.27 and amd64 CPU) or (go1.20~1.27 and arm64 CPU), but your environment is not suitable and will fallback to encoding/json\n", prefix)
}
4 changes: 2 additions & 2 deletions internal/decoder/api/decoder_amd64.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build go1.17 && !go1.27
// +build go1.17,!go1.27
//go:build go1.17 && !go1.28
// +build go1.17,!go1.28

/*
* Copyright 2021 ByteDance Inc.
Expand Down
4 changes: 2 additions & 2 deletions internal/decoder/api/decoder_arm64.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build go1.17 && !go1.27
// +build go1.17,!go1.27
//go:build go1.17 && !go1.28
// +build go1.17,!go1.28

/*
* Copyright 2021 ByteDance Inc.
Expand Down
4 changes: 2 additions & 2 deletions internal/decoder/jitdec/asm_stubs_amd64_go121.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build go1.21 && !go1.27
// +build go1.21,!go1.27
//go:build go1.21 && !go1.28
// +build go1.21,!go1.28

// Copyright 2023 CloudWeGo Authors
//
Expand Down
4 changes: 2 additions & 2 deletions internal/decoder/jitdec/assembler_regabi_amd64.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build go1.17 && !go1.27
// +build go1.17,!go1.27
//go:build go1.17 && !go1.28
// +build go1.17,!go1.28

/*
* Copyright 2021 ByteDance Inc.
Expand Down
4 changes: 2 additions & 2 deletions internal/decoder/jitdec/generic_regabi_amd64.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build go1.17 && !go1.27
// +build go1.17,!go1.27
//go:build go1.17 && !go1.28
// +build go1.17,!go1.28

/*
* Copyright 2021 ByteDance Inc.
Expand Down
4 changes: 2 additions & 2 deletions internal/encoder/alg/spec.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build (amd64 && go1.16 && !go1.27) || (arm64 && go1.20 && !go1.27)
// +build amd64,go1.16,!go1.27 arm64,go1.20,!go1.27
//go:build (amd64 && go1.16 && !go1.28) || (arm64 && go1.20 && !go1.28)
// +build amd64,go1.16,!go1.28 arm64,go1.20,!go1.28

/**
* Copyright 2024 ByteDance Inc.
Expand Down
4 changes: 2 additions & 2 deletions internal/encoder/alg/spec_compat.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build (!amd64 && !arm64) || go1.27 || !go1.16 || (arm64 && !go1.20)
// +build !amd64,!arm64 go1.27 !go1.16 arm64,!go1.20
//go:build (!amd64 && !arm64) || go1.28 || !go1.16 || (arm64 && !go1.20)
// +build !amd64,!arm64 go1.28 !go1.16 arm64,!go1.20

/**
* Copyright 2024 ByteDance Inc.
Expand Down
4 changes: 2 additions & 2 deletions internal/encoder/x86/asm_stubs_amd64_go121.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build go1.21 && !go1.27
// +build go1.21,!go1.27
//go:build go1.21 && !go1.28
// +build go1.21,!go1.28

// Copyright 2023 CloudWeGo Authors
//
Expand Down
4 changes: 2 additions & 2 deletions internal/encoder/x86/assembler_export_amd64.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build go1.17 && !go1.27
// +build go1.17,!go1.27
//go:build go1.17 && !go1.28
// +build go1.17,!go1.28

package x86

Expand Down
4 changes: 2 additions & 2 deletions internal/encoder/x86/assembler_regabi_amd64.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build go1.17 && !go1.27
// +build go1.17,!go1.27
//go:build go1.17 && !go1.28
// +build go1.17,!go1.28

/*
* Copyright 2021 ByteDance Inc.
Expand Down
4 changes: 2 additions & 2 deletions internal/encoder/x86/debug_go117.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build go1.17 && !go1.27
// +build go1.17,!go1.27
//go:build go1.17 && !go1.28
// +build go1.17,!go1.28

/*
* Copyright 2021 ByteDance Inc.
Expand Down
4 changes: 2 additions & 2 deletions internal/rt/base64_amd64.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build amd64 && go1.17 && !go1.27
// +build amd64,go1.17,!go1.27
//go:build amd64 && go1.17 && !go1.28
// +build amd64,go1.17,!go1.28

package rt

Expand Down
4 changes: 2 additions & 2 deletions internal/rt/base64_compat.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build !amd64 || !go1.17 || go1.27
// +build !amd64 !go1.17 go1.27
//go:build !amd64 || !go1.17 || go1.28
// +build !amd64 !go1.17 go1.28

package rt

Expand Down
4 changes: 2 additions & 2 deletions internal/rt/gcwb.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//go:build go1.21 && !go1.27
// +build go1.21,!go1.27
//go:build go1.21 && !go1.28
// +build go1.21,!go1.28

/*
* Copyright 2021 ByteDance Inc.
Expand Down
2 changes: 2 additions & 0 deletions internal/rt/map.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ type GoMapIterator struct {
I uint8
Bucket uintptr
CheckBucket uintptr
// different from go1.23, noswissmap
ClearSeq uint64
}
Loading
Loading