From 6049cf90473c8ef59b83f631d7758f181e349525 Mon Sep 17 00:00:00 2001 From: Li Jie Date: Thu, 6 Jun 2024 20:51:45 +0800 Subject: [PATCH 1/5] runtime: add bdwgc --- internal/runtime/bdwgc/bdwgc.go | 74 ++++++++++++++++++++++++ internal/runtime/bdwgc/llgo_autogen.lla | Bin 0 -> 409 bytes internal/runtime/z_c.go | 5 +- 3 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 internal/runtime/bdwgc/bdwgc.go create mode 100644 internal/runtime/bdwgc/llgo_autogen.lla diff --git a/internal/runtime/bdwgc/bdwgc.go b/internal/runtime/bdwgc/bdwgc.go new file mode 100644 index 00000000..f15c1bad --- /dev/null +++ b/internal/runtime/bdwgc/bdwgc.go @@ -0,0 +1,74 @@ +package bdwgc + +import "C" +import ( + _ "unsafe" + + "github.com/goplus/llgo/c" +) + +const ( + LLGoPackage = "link: $LLGO_LIB_BDWGC; $(pkg-config --libs bdw-gc); -lgc" +) + +// ----------------------------------------------------------------------------- + +//go:linkname Init C.GC_init +func Init() + +//go:linkname Malloc C.GC_malloc +func Malloc(size uintptr) c.Pointer + +//go:linkname Realloc C.GC_realloc +func Realloc(ptr c.Pointer, size uintptr) c.Pointer + +//go:linkname Free C.GC_free +func Free(ptr c.Pointer) + +// ----------------------------------------------------------------------------- + +//go:linkname RegisterFinalizer C.GC_register_finalizer +func RegisterFinalizer(obj c.Pointer, fn func(c.Pointer, c.Pointer), cd c.Pointer, old_fn *func(c.Pointer, c.Pointer), old_cd *c.Pointer) int + +//go:linkname RegisterFinalizerNoOrder C.GC_register_finalizer_no_order +func RegisterFinalizerNoOrder(obj c.Pointer, fn func(c.Pointer, c.Pointer), cd c.Pointer, old_fn *func(c.Pointer, c.Pointer), old_cd *c.Pointer) int + +//go:linkname RegisterFinalizerIgnoreSelf C.GC_register_finalizer_ignore_self +func RegisterFinalizerIgnoreSelf(obj c.Pointer, fn func(c.Pointer, c.Pointer), cd c.Pointer, old_fn *func(c.Pointer, c.Pointer), old_cd *c.Pointer) int + +//go:linkname RegisterFinalizerUnreachable C.GC_register_finalizer_unreachable +func RegisterFinalizerUnreachable(obj c.Pointer, fn func(c.Pointer, c.Pointer), cd c.Pointer, old_fn *func(c.Pointer, c.Pointer), old_cd *c.Pointer) int + +// ----------------------------------------------------------------------------- + +//go:linkname Enable C.GC_enable +func Enable() + +//go:linkname Disable C.GC_disable +func Disable() + +//go:linkname IsDisabled C.GC_is_disabled +func IsDisabled() int + +//go:linkname Gcollect C.GC_gcollect +func Gcollect() + +//go:linkname GetMemoryUse C.GC_get_memory_use +func GetMemoryUse() uintptr + +// ----------------------------------------------------------------------------- + +//go:linkname EnableIncremental C.GC_enable_incremental +func EnableIncremental() + +//go:linkname IsIncrementalMode C.GC_is_incremental_mode +func IsIncrementalMode() int + +//go:linkname IncrementalProtectionNeeds C.GC_incremental_protection_needs +func IncrementalProtectionNeeds() int + +//go:linkname StartIncrementalCollection C.GC_start_incremental_collection +func StartIncrementalCollection() + +//go:linkname CollectALittle C.GC_collect_a_little +func CollectALittle() diff --git a/internal/runtime/bdwgc/llgo_autogen.lla b/internal/runtime/bdwgc/llgo_autogen.lla new file mode 100644 index 0000000000000000000000000000000000000000..5e1a1ad7ae8ebcc246349373a8628435a9aae4dd GIT binary patch literal 409 zcmWIWW@Zs#U|`^22-tHd;+Vhes;5BSW+ny(eg+waoSgLh_{7qZ{Pfg3y_}rT5KabW z_K7iR96(%J!Og(P@|BT+0c^n9i5vY68wfaj|J@aQWtD=f@1>2RLd@LE_XTc#ygH|3 zok$b zG-*GgY@(N_)LyxcT-UTz@}C+|OeyyeZb}@_54TUn;v6?Qm0m!(7IivsHk5pPS({mg(}B z&i2=`KcAJ?y+6)+&XhYbr_N8=#_?QaYTvmfGyhdjd2d`}mcK4j@BH7Tahh}MMDIP2 y4e(}Ul4HgdUJ}5NV_*OV2*Z*_5DO#pSRtW@7IFdJtZX3Vj6fI)r1d~1FaQ9Ljg#X5 literal 0 HcmV?d00001 diff --git a/internal/runtime/z_c.go b/internal/runtime/z_c.go index c2767b6c..29eb16ff 100644 --- a/internal/runtime/z_c.go +++ b/internal/runtime/z_c.go @@ -20,17 +20,18 @@ import ( "unsafe" "github.com/goplus/llgo/internal/abi" + "github.com/goplus/llgo/internal/runtime/bdwgc" "github.com/goplus/llgo/internal/runtime/c" ) // AllocU allocates uninitialized memory. func AllocU(size uintptr) unsafe.Pointer { - return c.Malloc(size) + return bdwgc.Malloc(size) } // AllocZ allocates zero-initialized memory. func AllocZ(size uintptr) unsafe.Pointer { - ret := c.Malloc(size) + ret := bdwgc.Malloc(size) return c.Memset(ret, 0, size) } From 91e1fa6aff51b91546d6d678730acdea8c2aab6c Mon Sep 17 00:00:00 2001 From: Li Jie Date: Thu, 6 Jun 2024 20:54:32 +0800 Subject: [PATCH 2/5] test: simple llgo tests --- .github/workflows/go.yml | 42 ++++++++++++++-- _test/bdwgc.go | 101 +++++++++++++++++++++++++++++++++++++++ _test/main.go | 31 ++++++++++++ _test/run.sh | 28 +++++++++++ _test/testing/testing.go | 4 ++ c/c.go | 3 ++ 6 files changed, 204 insertions(+), 5 deletions(-) create mode 100644 _test/bdwgc.go create mode 100644 _test/main.go create mode 100644 _test/run.sh create mode 100644 _test/testing/testing.go diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index cd18a81a..95dd8c98 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -12,18 +12,27 @@ on: jobs: test-macos: - runs-on: macos-latest strategy: matrix: + os: [macos-latest, macos-12, macos-13] llvm: [17] + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - name: Update Homebrew if: matrix.llvm == 17 # needed as long as LLVM 17 is still fresh run: brew update - - name: Install LLVM ${{ matrix.llvm }} - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install llvm@${{ matrix.llvm }} + - name: Install LLVM ${{ matrix.llvm }} and bdw-gc + run: | + HOMEBREW_NO_AUTO_UPDATE=1 brew install llvm@${{ matrix.llvm }} bdw-gc + echo `brew --prefix llvm@${{ matrix.llvm }}`/bin >> $GITHUB_PATH + + - name: Clang information + run: | + echo $PATH + which clang + clang --version - name: Set up Go uses: actions/setup-go@v5 @@ -35,6 +44,14 @@ jobs: - name: Test run: go test -v ./... + + - name: Install + run: go install ./... + + - name: LLGO tests + run: | + export LLGOROOT=$PWD + bash _test/run.sh test-linux: runs-on: ubuntu-20.04 @@ -44,12 +61,19 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Install LLVM ${{ matrix.llvm }} + - name: Install LLVM ${{ matrix.llvm }} and libgc-dev run: | echo 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal-${{ matrix.llvm }} main' | sudo tee /etc/apt/sources.list.d/llvm.list wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - sudo apt-get update - sudo apt-get install --no-install-recommends llvm-${{ matrix.llvm }}-dev + sudo apt-get install --no-install-recommends clang-${{ matrix.llvm }} llvm-${{ matrix.llvm }}-dev libgc-dev + echo /usr/lib/llvm-${{ matrix.llvm }}/bin >> $GITHUB_PATH + + - name: Clang information + run: | + echo $PATH + which clang + clang --version - name: Set up Go uses: actions/setup-go@v5 @@ -61,6 +85,14 @@ jobs: - name: Test run: go test -v -coverprofile="coverage.txt" -covermode=atomic ./... + + - name: Install + run: go install ./... + + - name: LLGO tests + run: | + export LLGOROOT=$PWD + bash _test/run.sh - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v4 diff --git a/_test/bdwgc.go b/_test/bdwgc.go new file mode 100644 index 00000000..01bdcb2f --- /dev/null +++ b/_test/bdwgc.go @@ -0,0 +1,101 @@ +package main + +import ( + "unsafe" + + "github.com/goplus/llgo/_test/testing" + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/internal/runtime/bdwgc" +) + +// ------ Test malloc ------ + +func TestMalloc(t *testing.T) { + pn := (*int)(bdwgc.Malloc(unsafe.Sizeof(int(0)))) + *pn = 1 << 30 + c.Printf(c.Str("value: %d, %x, %p, %p\n"), *pn, *pn, pn, &pn) + + pl := (*int64)(bdwgc.Realloc(c.Pointer(pn), unsafe.Sizeof(int64(0)))) + *pl = 1 << 60 + c.Printf(c.Str("value: %lld, %llx, %p, %p\n"), *pl, *pl, pl, &pl) + + bdwgc.Free(c.Pointer(pl)) +} + +// ------ Test finalizer ------ + +const ( + RETURN_VALUE_FREED = 1 << 31 +) + +var called uint = 0 + +func setReturnValueFreed(pobj c.Pointer, clientData c.Pointer) { + called |= RETURN_VALUE_FREED + c.Printf(c.Str("called: %x\n"), called) +} + +func setLoopValueFreed(pobj c.Pointer, clientData c.Pointer) { + pmask := (*uint)(clientData) + called |= *pmask + c.Printf(c.Str("called: %x\n"), called) +} + +func isCalled(mask uint) bool { + return called&mask != 0 +} + +func returnValue() *int { + pn := bdwgc.Malloc(unsafe.Sizeof(int(0))) + bdwgc.RegisterFinalizer(pn, setReturnValueFreed, nil, nil, nil) + return (*int)(pn) +} + +func callFunc() { + pn := returnValue() + *pn = 1 << 30 + c.Printf(c.Str("value: %d, %x, %p, %p\n"), *pn, *pn, pn, &pn) + bdwgc.Gcollect() + check(!isCalled(RETURN_VALUE_FREED), c.Str("finalizer should not be called")) +} + +func loop() { + for i := 0; i < 5; i++ { + p := bdwgc.Malloc(unsafe.Sizeof(int(0))) + pn := (*int)(p) + *pn = i + c.Printf(c.Str("value: %d, %x, %p, %p\n"), *pn, *pn, pn, &pn) + pflag := (*uint)(c.Malloc(unsafe.Sizeof(uint(0)))) + *pflag = 1 << i + bdwgc.RegisterFinalizer(p, setLoopValueFreed, c.Pointer(pflag), nil, nil) + bdwgc.Gcollect() + check(!isCalled(1<= len(tests) { + c.Printf(c.Str("invalid test index %d"), idx) + panic("invalid test index") + } + tests[idx].F(nil) +} diff --git a/_test/run.sh b/_test/run.sh new file mode 100644 index 00000000..407453d8 --- /dev/null +++ b/_test/run.sh @@ -0,0 +1,28 @@ +#!/bin/bash +set -e +testcmd=/tmp/test +llgo build -o $testcmd ./_test +cases=$($testcmd) +total=$(echo "$cases" | wc -l | tr -d ' ') +succ=0 +for idx in $(seq 1 $((total))); do + case=$(echo "$cases" | sed -n "${idx}p") + case_id=$(echo "$case" | cut -d',' -f1) + case_name=$(echo "$case" | cut -d',' -f2) + echo "=== Test case: $case_name" + set +e + out=$("$testcmd" "$((idx-1))" 2>&1) + exit_code=$? + set -e + if [ "${exit_code:-0}" -ne 0 ]; then + echo "failed: $out" + else + succ=$((succ+1)) + echo "passed" + fi +done +echo "=== Done" +echo "$succ/$total tests passed" +if [ "$total" -ne "$succ" ]; then + exit 1 +fi diff --git a/_test/testing/testing.go b/_test/testing/testing.go new file mode 100644 index 00000000..d4b6029b --- /dev/null +++ b/_test/testing/testing.go @@ -0,0 +1,4 @@ +package testing + +type T struct { +} diff --git a/c/c.go b/c/c.go index cfa9a77c..e1071eee 100644 --- a/c/c.go +++ b/c/c.go @@ -160,3 +160,6 @@ func GetoptLong(argc Int, argv **Char, optstring *Char, longopts *Option, longin func GetoptLongOnly(argc Int, argv **Char, optstring *Char, longopts *Option, longindex *Int) Int // ----------------------------------------------------------------------------- + +//go:linkname Atoi C.atoi +func Atoi(s *Char) Int From ee848e66ac601ec9e404f0da8959e94b17c0e83e Mon Sep 17 00:00:00 2001 From: Li Jie Date: Sat, 8 Jun 2024 10:15:18 +0800 Subject: [PATCH 3/5] test: run _demo/* and _pydemo/* --- .github/workflows/go.yml | 88 ++++++++++++++-------------------- .github/workflows/test_demo.sh | 26 ++++++++++ _test/run.sh | 1 - 3 files changed, 63 insertions(+), 52 deletions(-) create mode 100644 .github/workflows/test_demo.sh diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 95dd8c98..13c496bb 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -11,22 +11,32 @@ on: jobs: - test-macos: + test: strategy: matrix: - os: [macos-latest, macos-12, macos-13] + os: [macos-latest, macos-12, macos-13, ubuntu-latest] llvm: [17] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - name: Update Homebrew - if: matrix.llvm == 17 # needed as long as LLVM 17 is still fresh + # needed as long as LLVM 17 is still fresh + if: matrix.llvm == 17 && startsWith(matrix.os, 'macos') run: brew update - name: Install LLVM ${{ matrix.llvm }} and bdw-gc + if: startsWith(matrix.os, 'macos') run: | HOMEBREW_NO_AUTO_UPDATE=1 brew install llvm@${{ matrix.llvm }} bdw-gc echo `brew --prefix llvm@${{ matrix.llvm }}`/bin >> $GITHUB_PATH + - name: Install LLVM ${{ matrix.llvm }} and libgc-dev + if: startsWith(matrix.os, 'ubuntu') + run: | + echo 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal-${{ matrix.llvm }} main' | sudo tee /etc/apt/sources.list.d/llvm.list + wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - + sudo apt-get update + sudo apt-get install --no-install-recommends clang-${{ matrix.llvm }} llvm-${{ matrix.llvm }}-dev libgc-dev + echo /usr/lib/llvm-${{ matrix.llvm }}/bin >> $GITHUB_PATH - name: Clang information run: | @@ -43,59 +53,35 @@ jobs: run: go build -v ./... - name: Test + if: matrix.os != 'ubuntu-latest' run: go test -v ./... - + - name: Test with coverage + if: matrix.os == 'ubuntu-latest' + run: go test -v -coverprofile="coverage.txt" -covermode=atomic ./... + - name: Install run: go install ./... - name: LLGO tests run: | - export LLGOROOT=$PWD - bash _test/run.sh - - test-linux: - runs-on: ubuntu-20.04 - strategy: - matrix: - llvm: [17] - steps: - - uses: actions/checkout@v4 - - - name: Install LLVM ${{ matrix.llvm }} and libgc-dev - run: | - echo 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal-${{ matrix.llvm }} main' | sudo tee /etc/apt/sources.list.d/llvm.list - wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - - sudo apt-get update - sudo apt-get install --no-install-recommends clang-${{ matrix.llvm }} llvm-${{ matrix.llvm }}-dev libgc-dev - echo /usr/lib/llvm-${{ matrix.llvm }}/bin >> $GITHUB_PATH - - - name: Clang information - run: | - echo $PATH - which clang - clang --version - - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version: '1.20' - - - name: Build - run: go build -v ./... - - - name: Test - run: go test -v -coverprofile="coverage.txt" -covermode=atomic ./... - - - name: Install - run: go install ./... + echo "Test result on ${{ matrix.os }} with LLVM ${{ matrix.llvm }}" > result.txt + LLGOROOT=$PWD bash .github/workflows/test_llgo.sh - - name: LLGO tests - run: | - export LLGOROOT=$PWD - bash _test/run.sh + - name: Test _demo and _pydemo + run: | + set +e + LLGOROOT=$PWD bash .github/workflows/test_demo.sh + exit 0 - - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@v4 - with: - token: ${{ secrets.CODECOV_TOKEN }} - slug: goplus/llgo + - name: PR comment with test result + uses: thollander/actions-comment-pull-request@v2 + with: + filePath: result.md + create_if_not_exists: true + comment_tag: test-result-on-${{ matrix.os }}-with-llvm-${{ matrix.llvm }} + + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + slug: goplus/llgo diff --git a/.github/workflows/test_demo.sh b/.github/workflows/test_demo.sh new file mode 100644 index 00000000..c10cd020 --- /dev/null +++ b/.github/workflows/test_demo.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# llgo run subdirectories under _demo and _pydemo +total=0 +failed=0 +failed_cases="" +for d in ./_demo/* ./_pydemo/*; do + total=$((total+1)) + if [ -d "$d" ]; then + echo "Testing $d" + if ! llgo run -v "$d"; then + echo "FAIL" + failed=$((failed+1)) + failed_cases="$failed_cases\n$d" + else + echo "PASS" + fi + fi +done + +echo "=== Done" +echo "$((total-failed))/$total tests passed" +if [ "$failed" -ne 0 ]; then + echo -e "Failed cases:$failed_cases" + exit 1 +fi diff --git a/_test/run.sh b/_test/run.sh index 407453d8..d048155d 100644 --- a/_test/run.sh +++ b/_test/run.sh @@ -7,7 +7,6 @@ total=$(echo "$cases" | wc -l | tr -d ' ') succ=0 for idx in $(seq 1 $((total))); do case=$(echo "$cases" | sed -n "${idx}p") - case_id=$(echo "$case" | cut -d',' -f1) case_name=$(echo "$case" | cut -d',' -f2) echo "=== Test case: $case_name" set +e From f16e721d019c5a2ecf6ffab9a6029502218bbcbe Mon Sep 17 00:00:00 2001 From: Li Jie Date: Sat, 8 Jun 2024 11:03:35 +0800 Subject: [PATCH 4/5] ci: comment test result on PR --- .github/workflows/go.yml | 2 +- .github/workflows/test_demo.sh | 9 ++++++--- .../run.sh => .github/workflows/test_llgo.sh | 19 +++++++++++++++---- 3 files changed, 22 insertions(+), 8 deletions(-) rename _test/run.sh => .github/workflows/test_llgo.sh (56%) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 13c496bb..9350681e 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -64,7 +64,7 @@ jobs: - name: LLGO tests run: | - echo "Test result on ${{ matrix.os }} with LLVM ${{ matrix.llvm }}" > result.txt + echo "Test result on ${{ matrix.os }} with LLVM ${{ matrix.llvm }}" > result.md LLGOROOT=$PWD bash .github/workflows/test_llgo.sh - name: Test _demo and _pydemo diff --git a/.github/workflows/test_demo.sh b/.github/workflows/test_demo.sh index c10cd020..6a4a5fb2 100644 --- a/.github/workflows/test_demo.sh +++ b/.github/workflows/test_demo.sh @@ -11,16 +11,19 @@ for d in ./_demo/* ./_pydemo/*; do if ! llgo run -v "$d"; then echo "FAIL" failed=$((failed+1)) - failed_cases="$failed_cases\n$d" + failed_cases="$failed_cases\n* :x: $d" else echo "PASS" fi fi done - echo "=== Done" echo "$((total-failed))/$total tests passed" + if [ "$failed" -ne 0 ]; then - echo -e "Failed cases:$failed_cases" + echo ":bangbang: Failed demo cases:" | tee -a result.md + echo -e "$failed_cases" | tee -a result.md exit 1 +else + echo ":white_check_mark: All demo tests passed" | tee -a result.md fi diff --git a/_test/run.sh b/.github/workflows/test_llgo.sh similarity index 56% rename from _test/run.sh rename to .github/workflows/test_llgo.sh index d048155d..e1838fa5 100644 --- a/_test/run.sh +++ b/.github/workflows/test_llgo.sh @@ -1,10 +1,15 @@ #!/bin/bash set -e + +export LLGOROOT=$PWD + testcmd=/tmp/test llgo build -o $testcmd ./_test cases=$($testcmd) total=$(echo "$cases" | wc -l | tr -d ' ') -succ=0 +failed=0 +failed_cases="" + for idx in $(seq 1 $((total))); do case=$(echo "$cases" | sed -n "${idx}p") case_name=$(echo "$case" | cut -d',' -f2) @@ -15,13 +20,19 @@ for idx in $(seq 1 $((total))); do set -e if [ "${exit_code:-0}" -ne 0 ]; then echo "failed: $out" + failed=$((failed+1)) + failed_cases="$failed_cases\n* :x: $case_name" else - succ=$((succ+1)) echo "passed" fi done echo "=== Done" -echo "$succ/$total tests passed" -if [ "$total" -ne "$succ" ]; then +echo "$((total-failed))/$total tests passed" + +if [ "$failed" -ne 0 ]; then + echo ":bangbang: Failed llgo cases:" | tee -a result.md + echo -e "$failed_cases" | tee -a result.md exit 1 +else + echo ":white_check_mark: All llgo tests passed" | tee -a result.md fi From 61ccaab55b66896225f2c24be50382446a7213ad Mon Sep 17 00:00:00 2001 From: Li Jie Date: Sat, 8 Jun 2024 13:20:23 +0800 Subject: [PATCH 5/5] ci: show test result --- .github/workflows/go.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 9350681e..89563e2a 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -72,12 +72,15 @@ jobs: set +e LLGOROOT=$PWD bash .github/workflows/test_demo.sh exit 0 + + - name: Show test result + run: cat result.md - name: PR comment with test result uses: thollander/actions-comment-pull-request@v2 + if: false with: filePath: result.md - create_if_not_exists: true comment_tag: test-result-on-${{ matrix.os }}-with-llvm-${{ matrix.llvm }} - name: Upload coverage reports to Codecov