From 385bd47d6154857863aa2dc658d061138d4667e0 Mon Sep 17 00:00:00 2001 From: ASDAlexander77 Date: Tue, 6 Oct 2026 19:38:21 +0100 Subject: [PATCH 1/2] README: -mm=own and Android What's new and the contents gain both. "Compile for Android" covers the targets, the NDK, the release-zip libraries and their options, an arm64 executable, and running it with adb (chmod +x: a file pushed from Windows is not executable). The memory models table and a new -mm=own subsection cover moves, borrows, the compile error when ownership cannot be proven, Shared, and --no-default-lib (no own default library yet). "Build for Android" lists the two scripts and the DefaultLib one. Co-Authored-By: Claude Opus 5.5 --- README.md | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/README.md b/README.md index e5cb8e490..0d6479a70 100644 --- a/README.md +++ b/README.md @@ -26,15 +26,19 @@ on the fly via a built-in JIT — no Node.js or JavaScript runtime required. - [As JIT](#run-as-jit) - [Debugging JIT code with GDB (Linux)](#debugging-jit-code-with-gdb-linux) - [As a native executable](#compile-as-binary-executable) + - [For Android](#compile-for-android) - [As WebAssembly](#compiling-as-wasm) - [C bindings with tsbindgen](#c-bindings-with-tsbindgen) - [Memory models](#memory-models) - [Building from source](#build) + - [For Android](#build-for-android) - [Community](#chat-room) - [License](#license) ## What's new +- New memory model **`-mm=own`**: single ownership inferred at compile time, like Rust's borrow checker. There is no collector and no reference counting, and a program whose ownership cannot be proven is a compile error. Shared ownership is opt-in with `Shared`. See [Memory models](#memory-models) +- **Android** targets (`arm64-v8a`, `x86_64`, API 29+): executables and shared libraries linked through the Android NDK. The release zip carries the collector, async runtime and default library for both ABIs. See [Compile for Android](#compile-for-android) - Implemented `try/catch` exception handling in the **JIT** on Windows (x64 SEH unwinding via a custom LLJIT runtime) - Migrared to **LLVM 22.1.8** - Migrated to **Visual Studio 2026** (Windows build chain) @@ -341,6 +345,53 @@ Result Hello World! ``` +## Compile for Android + +`tslang` cross-compiles for Android from a Windows host. It targets `arm64-v8a` +(`-mtriple=aarch64-linux-android29`) and `x86_64` (`-mtriple=x86_64-linux-android29`), and links +through the Android NDK (tested with r29 and r30). The triple has to carry the API level, and 29 +is the lowest the default library supports. Point `--android-ndk-path` (or `ANDROID_NDK_HOME`) at +the NDK. + +The Windows release zip carries the Android libraries for both ABIs: + +| Library | Option | +| --- | --- | +| `android\\lib\libgc.a` | `--gc-lib-path=\android\\lib` (only under `-mm=gc`) | +| `android\\lib\libTypeScriptAsyncRuntime.a` | `--tslang-lib-path=\android\\lib` | +| `defaultlib\...` (the default library, beside the Windows one) | `--default-lib-path=` | + +To build them from source instead, see [Build for Android](#build-for-android). + +Build an executable for arm64-v8a: + +```bat +tslang --emit=exe -mtriple=aarch64-linux-android29 --opt ^ + --android-ndk-path=C:\Android\android-ndk-r30 ^ + --default-lib-path= ^ + --gc-lib-path=\android\arm64-v8a\lib ^ + --tslang-lib-path=\android\arm64-v8a\lib ^ + hello.ts -o hello +``` + +`--emit=dll` takes the same options and builds a shared library (`-o libhello.so`) for an app to +load. Either way the output is one self-contained, position-independent binary: the default +library, collector and libc++ are linked in statically, so it needs only Bionic's libc, libm and +libdl. Android has no libcurl, so `fetch()` throws. + +Run it on a device or emulator. Run `chmod +x` because a file pushed from Windows is not executable: + +```bat +adb push hello /data/local/tmp/ +adb shell "chmod +x /data/local/tmp/hello && /data/local/tmp/hello" +``` + +Result + +```text +Hello World! +``` + ## Compiling as WASM ### WASM build on Windows @@ -620,6 +671,7 @@ How heap memory is managed is selected with `-mm=`: | `-mm=gc` | garbage collection (Boehm) | the default | | `-mm=rc` | reference counting - freed as soon as the last reference goes, no collector, no `libgc` | **does not collect reference cycles** | | `-mm=none` | nothing is ever freed | short-lived programs | +| `-mm=own` | single ownership inferred at compile time - no collector, no counting | **in development**; ownership that cannot be proven is a compile error | `-mm=gc` is the default and needs no thought. `-mm=rc` reclaims memory deterministically and holds close to the working set - a ray tracer that reaches 114 MB under `-mm=none` holds 4.1 MB, @@ -629,6 +681,50 @@ freed under it**, which is the same trade Swift makes with ARC. See **[docs/memory-models.md](docs/memory-models.md)** for which shapes leak, which do not, and what to do about it. +### `-mm=own` + +`-mm=own` works the way Rust's borrow checker does. Every heap block has exactly one owner: a +local, a field, an array element or a global. When a value is aliased, the compiler either moves +it, so the source gives it up, or borrows it for as long as the owner lives. The owner frees the +block at a point known at compile time: when its scope ends, when it is overwritten, or when it is +removed from its container. No reference counts are kept at run time. When the compiler cannot +prove a single owner, it rejects the program instead of compiling it with a leak: + +```typescript +class Node { constructor(public value: number) {} } +class Holder { node: Node; } + +function main() { + const h = new Holder(); + const g = new Holder(); + const n = new Node(1); + h.node = n; // the Node moves into h + g.node = n; // a second owner: compile error + print(h.node.value); +} +``` + +```text +owners.ts:9:5: error: 'this value' is used here after its value was moved + g.node = n; // a second owner: compile error + ^ +owners.ts:8:5: note: value moved here + h.node = n; // the Node moves into h + ^ +``` + +Shared ownership is opt-in and explicit. `Shared` keeps a count, and `.value` reads or writes +the object inside it: + +```typescript +const a = new Shared(new Node(1)); +const b = a; // both share the Node +print(a.value.value, b.value.value, Shared.count(a)); // 1 1 2 +``` + +`-mm=own` is still in development: some valid TypeScript does not compile under it yet. The +default library has no `-mm=own` build yet, so compile with `--no-default-lib`. + ## Build ### Build on Windows @@ -682,6 +778,29 @@ chmod +x *.sh ./build_tslang_release.sh ``` +### Build for Android + +The release zip already carries these libraries. To build them yourself, use a Windows host with +the Android NDK (r29 or r30) in `ANDROID_NDK_HOME` and Ninja on `PATH`. Run these after +`prepare_3rdParty.bat`, which provides the gc sources and the LLVM headers they use. Each script builds both +`arm64-v8a` and `x86_64` for API level 29, or only the ABI you pass: + +```bat +cd TypeScriptCompiler +scripts\build_gc_release_android.bat +scripts\build_tslang_runtime_release_android.bat +``` + +| Script | Builds | Pass it as | +| --- | --- | --- | +| `build_gc_release_android.bat` | Boehm GC, static, parallel marking off ([bdwgc#980](https://github.com/bdwgc/bdwgc/issues/980)) | `--gc-lib-path=3rdParty\gc\android\\release\lib` | +| `build_tslang_runtime_release_android.bat` | `libTypeScriptAsyncRuntime.a` | `--tslang-lib-path=__build\tslang-runtime\release\android\` | + +Build the default library for Android with `scripts\build_android.bat` in the +[Default Library repo](https://github.com/ASDAlexander77/TypeScriptCompilerDefaultLib/). It +builds the release and debug libraries under gc, rc and none into the same `__build\defaultlib` tree as +every other target, so `--default-lib-path=\__build` finds them. + ## License This project is licensed under the **MIT License** — see the [LICENSE](LICENSE) file for details. From 8625f8f6046510402c89dc3528193fa0eb4f3229 Mon Sep 17 00:00:00 2001 From: ASDAlexander77 Date: Tue, 6 Oct 2026 19:38:25 +0100 Subject: [PATCH 2/2] Release zip: Android libraries under android\\lib Get-ChildItem on .\android_stage\android packed that folder's children, so the zip had arm64-v8a\lib and x86_64\lib at its root rather than the android\\lib the comment above and the DefaultLib README document. Pass .\android_stage, as gcdll_stage and resourcedir_stage are passed. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/create-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml index 845e0b5b3..f9e9b2f3b 100644 --- a/.github/workflows/create-release.yml +++ b/.github/workflows/create-release.yml @@ -272,7 +272,7 @@ jobs: New-Item -ItemType Directory -Force -Path .\gcdll_stage\gcdll | Out-Null Copy-Item -Path ..\3rdParty\gcdll\x64\release\lib\gc.lib, ..\3rdParty\gcdll\x64\release\bin\gc.dll -Destination .\gcdll_stage\gcdll -ErrorAction Stop Get-ChildItem -Path ..\3rdParty\llvm\x64\release\lib\clang -Directory | ForEach-Object { $dest = ".\resourcedir_stage\lib\clang\$($_.Name)"; New-Item -ItemType Directory -Force -Path $dest | Out-Null; Copy-Item -Path (Join-Path $_.FullName "include") -Destination $dest -Recurse -ErrorAction Stop } - Get-ChildItem -Path .\tslang\msbuild\x64\release\bin\tslang.exe, .\tslang\msbuild\x64\release\bin\tsbindgen.exe, .\tslang\msbuild\x64\release\bin\TypeScriptRuntime.dll, .\tslang\msbuild\x64\release\bin\gc.dll, .\gc\msbuild\x64\release\${{ env.BUILD_TYPE }}\gc.lib, .\tslang\msbuild\x64\release\lib\TypeScriptAsyncRuntime.lib, ..\3rdParty\llvm\x64\release\bin\wasm-ld.exe, ..\TypeScriptCompilerDefaultLib\__build, .\gcdll_stage, .\resourcedir_stage, .\android_stage\android | Compress-Archive -DestinationPath ..\${{ env.ASSET_NAME }}-windows-x64.zip + Get-ChildItem -Path .\tslang\msbuild\x64\release\bin\tslang.exe, .\tslang\msbuild\x64\release\bin\tsbindgen.exe, .\tslang\msbuild\x64\release\bin\TypeScriptRuntime.dll, .\tslang\msbuild\x64\release\bin\gc.dll, .\gc\msbuild\x64\release\${{ env.BUILD_TYPE }}\gc.lib, .\tslang\msbuild\x64\release\lib\TypeScriptAsyncRuntime.lib, ..\3rdParty\llvm\x64\release\bin\wasm-ld.exe, ..\TypeScriptCompilerDefaultLib\__build, .\gcdll_stage, .\resourcedir_stage, .\android_stage | Compress-Archive -DestinationPath ..\${{ env.ASSET_NAME }}-windows-x64.zip shell: pwsh - name: Archive Zip of Windows Asset