{"id":27761215,"url":"https://github.com/tsoding/jai-wasm","last_synced_at":"2025-07-22T07:32:59.655Z","repository":{"id":38025571,"uuid":"500957852","full_name":"tsoding/jai-wasm","owner":"tsoding","description":"Jai WebAssembly Proof-of-Concept","archived":false,"fork":false,"pushed_at":"2023-01-17T11:59:14.000Z","size":1891,"stargazers_count":76,"open_issues_count":1,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-07-02T13:52:33.267Z","etag":null,"topics":["jai","wasm","webassembly"],"latest_commit_sha":null,"homepage":"https://tsoding.github.io/jai-wasm/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tsoding.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-06-07T18:23:29.000Z","updated_at":"2025-05-25T17:40:53.000Z","dependencies_parsed_at":"2023-01-21T22:03:56.221Z","dependency_job_id":null,"html_url":"https://github.com/tsoding/jai-wasm","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/tsoding/jai-wasm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tsoding%2Fjai-wasm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tsoding%2Fjai-wasm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tsoding%2Fjai-wasm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tsoding%2Fjai-wasm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tsoding","download_url":"https://codeload.github.com/tsoding/jai-wasm/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tsoding%2Fjai-wasm/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266447977,"owners_count":23930088,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-22T02:00:09.085Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["jai","wasm","webassembly"],"created_at":"2025-04-29T12:43:27.760Z","updated_at":"2025-07-22T07:32:59.634Z","avatar_url":"https://github.com/tsoding.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Jai WebAssembly Proof-of-Concept\n\n[![thumbnail](./img/thumbnail.png)](https://tsoding.github.io/jai-wasm/)\n\n*Screenshot from [https://tsoding.github.io/jai-wasm/](https://tsoding.github.io/jai-wasm/)*\n\nJai does not officially support WebAssembly compilation target. BUT! It allows you to dump [LLVM Bitcode](https://llvm.org/docs/BitCodeFormat.html) via the `Llvm_Options.output_bitcode` flag. This Proof-of-Concept demonstrates how to exploit this feature to compile Jai program to WebAssembly.\n\n## Quick Start\n\nThe compilation works only on Linux right now, sorry. You also need to have [Clang](https://clang.llvm.org/) installed on your machine.\n\n```console\n$ jai -version\nVersion: beta 0.1.051, built on 9 January 2022.\n$ jai first.jai\n$ python3 -m http.server 6969\n$ iexplore.exe http://localhost:6969/\n```\n\n## How Does it Work?\n\nFor detailed information on how everything works I recommend to read the [./first.jai](./first.jai). The main idea is to dump the LLVM Bitcode of the compiled program and translate it with Clang to WebAssembly bytecode.\n\nAlso check out [./js/load.js](./js/load.js) which loads up the final WebAssembly module and sets up the environment for it.\n\n### `#asm` Blocks\n\nThe library that comes with Jai uses quite a few `#asm` blocks. The problem is that they are not translatable to WebAssembly. We wrote a simple meta program in [./first.jai](./first.jai) that simply removes the blocks during the compilation and advises not to call the functions that had the `#asm` blocks. (If you have a better solution, please let me know).\n\n### \"invalid data symbol offset: `__type_table`\" and 64 bits\n\nIf you ever tried to compile Jai to WebAssembly you are probably familiar with that error. It happens when you try to compile the program specifically to wasm32. Jai Compiler only supports 64 bit platform and does all of its data segments computations around 64 bit pointers (at least this is how I think it works).\n\nSo to avoid that error you need to compiler with `--target=wasm64` flag of Clang which generates a binary with [memory64](https://github.com/WebAssembly/memory64) extension. But since this extension is experimental (yes, addressing memory with 64 bits is experimental in 2022...) such binary may not work everywhere. To make the binary more portable we convert it to wasm32 using [wasm64232](https://github.com/tsoding/wabt-wasm64232) utility.\n\n### Calling to JavaScript Functions via the `libwasmstub` Dynamic Library Hack\n\nTODO\n\n### Passing the Context from JavaScript\n\nEach Jai function (except the ones that are marked with `#no_context`) accepts an implicit pointer to Context. If you want to enable the Jai code to use the Context you need to figure out that pointer in JavaScript and pass it accordingly.\n\nThe way we figure it out is by calling the entry point of the Jai program from JavaScript. Literally the `main` function. Within that function we call `set_context(*context)` which jumps back to JavaScript and in JavaScript we save that pointer in a global variable somewhere.\n\nFrom now on every time we need to pass the Context to any of the Jai functions we just pass the saved pointer.\n\nFor more details see `main` procedure in [./main.jai](./main.jai) and `set_context` function in [./js/load.js](./js/load.js).\n\n## Screencast\n\nThis code was written on a livestream:\n\n[![thumbnail](./thumbnails/thumbnail.png)](https://www.youtube.com/watch?v=8_5L8yVHcII)\n\n## Contribution\n\nIf you have any questions, suggestions or something is not documented well feel free to file an Issue or a PR.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftsoding%2Fjai-wasm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftsoding%2Fjai-wasm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftsoding%2Fjai-wasm/lists"}