{"id":15060265,"url":"https://github.com/dibyendumajumdar/nanojit","last_synced_at":"2025-04-10T05:46:01.687Z","repository":{"id":82240384,"uuid":"83171046","full_name":"dibyendumajumdar/nanojit","owner":"dibyendumajumdar","description":"NanoJIT is a small, cross-platform C++ library that emits machine code.","archived":false,"fork":false,"pushed_at":"2017-09-15T01:10:44.000Z","size":600,"stargazers_count":155,"open_issues_count":6,"forks_count":16,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-03-07T16:48:48.958Z","etag":null,"topics":["assembler","compiler","jit","nanojit","nanojit-ir"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dibyendumajumdar.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-02-25T23:50:20.000Z","updated_at":"2024-12-28T07:54:22.000Z","dependencies_parsed_at":null,"dependency_job_id":"c40c0bc0-2a3f-4bf4-a5fa-3fc6456b2038","html_url":"https://github.com/dibyendumajumdar/nanojit","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dibyendumajumdar%2Fnanojit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dibyendumajumdar%2Fnanojit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dibyendumajumdar%2Fnanojit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dibyendumajumdar%2Fnanojit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dibyendumajumdar","download_url":"https://codeload.github.com/dibyendumajumdar/nanojit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248166881,"owners_count":21058479,"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","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":["assembler","compiler","jit","nanojit","nanojit-ir"],"created_at":"2024-09-24T22:55:20.913Z","updated_at":"2025-04-10T05:46:01.668Z","avatar_url":"https://github.com/dibyendumajumdar.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# NanoJIT\nNanoJIT is a small, cross-platform C++ library that emits machine code. It is part of [Adobe ActionScript](https://github.com/adobe/avmplus) \nand used to be part of [Mozilla SpiderMonkey](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Internals/Tracing_JIT) but is no longer used in SpiderMonkey.\n\n## High level overview\nNanoJIT defines its own linear IR called LIR. This is not an SSA IR as there are no phi nodes. Compared with LLVM IR, the NanoJIT IR is low level. There are only primitive types such as 32-bit and 64-bit integers, doubles and floats, and pointers. Users have to manage complex types on their own.\n\nThe NanoJIT IR is also restricted by platform, e.g. some instructions are only available on 64-bit platforms. \n\nThe main unit of compilation in NanoJIT is a Fragment - which can be thought of as a chunk of code. You can make a function out of a fragment by providing a start instruction and appropriate ret instructions. But Fragments need not be functions. I believe this flexibility stems from the fact that NanoJIT was designed to be used in a tracing JIT.\n\nThe documentation on NanoJIT is sparse or non-existent, making it hard to get started. The project aims to provide a [simpler, documented C API](https://github.com/dibyendumajumdar/nanojit/blob/master/nanojitextra/nanojitextra.h) to make it easier to use NanoJIT.\n\n## Project news\n\n* Sep-2017: First alpha release of NanoJITExtra C API\n* Currently I am concentrating on X86-64 architecture - in particular I have no ability to test the non X86 architectures\n* April-2017: Added support for 64-bit integer multiply, divide and modulus operators in X64 LIR. Not available on other architectures.\n\n## Playing with NanoJIT\n\nNanoJIT comes with a nice tool called lirasm. This is a command line tool that allows you to run a script containing NanoJIT IR instructions. For example, say you want a function that adds its two arguments. We can write this as follows:\n\n```\n; this is our add function\n; it takes two parameters\n; and returns the sum of the two\n; note that this script will only run on 64-bit platforms as q2i instruction is\n; not available on 32-bit platforms\n\n; the .begin and .end instructions tell lirasm to generate the function prologue and epilogue\n\n.begin add\np1 = paramp 0 0\t\t     ; the first '0' says that this is the 0th parameter \n                       ; the second argument '0' says this is a parameter\np2 = paramp 1 0\t\t     ; the second parameter\nx  = q2i p1            ; convert from int64 to int32\n                       ; this instruction will only work on 64-bit machines\n                       ; it ensures that the script will fail to compile on 32-bit arch\ny  = q2i p2            ; convert from int64 to int32\nsum = addi x y\t       ; add\nreti sum\n.end\n\n; this is our main function\n; we just call add with 200, 100\n.begin main\noneh = immi 100\t\t     ; constant 100\ntwoh = immi 200\t\t     ; constant 200\nres = calli add fastcall twoh oneh     ; call function add\nreti res\n.end\n```\n\nIf you save above script to a file named add.in, then you can run lirasm as follows:\n\n```\nlirasm add.in\n```\n\nYou can see the generated code by running:\n\n```\nlirasm -v add.in\n```\n\n## Example using NanoJITExtra API\nThis project is creating a simplified C API for NanoJIT - I call this NanoJITExtra. The API is defined in [nanojitextra.h](https://github.com/dibyendumajumdar/nanojit/blob/master/nanojitextra/nanojitextra.h). *Note* that this is work in progress.\n\n```c++\n\nNJXContextRef jit = NJX_create_context(true);\n\nconst char *name = \"add\";\ntypedef int (*functype)(NJXParamType, NJXParamType);\n\n// Create a function builder\nNJXValueKind args[2] = {NJXValueKind_I, NJXValueKind_I};\nNJXFunctionBuilderRef builder = NJX_create_function_builder(jit, name, NJXValueKind_I, args, 2, true);\n\nauto x = NJX_get_parameter(builder, 0); /* arg1 */\nauto y = NJX_get_parameter(builder, 1); /* arg2 */\nauto result = NJX_addi(builder, x, y);       /* result = x + y */\nauto ret = NJX_reti(builder, result);        /* return result */\n\nfunctype f = (functype)NJX_finalize(builder);\n\nNJX_destroy_function_builder(builder);\n\nassert(f);\nassert(f(100, 200) == 300);\n\nNJX_destroy_context(jit);\n\n```\n\n## More examples\nThere are bunch of [tests](https://github.com/dibyendumajumdar/nanojit/tree/master/utils/nanojit-lirasm/lirasm/tests) that come with the lirasm tool. These are examples of LIR scripts.\n\nThe samples folder contains an [example program](https://github.com/dibyendumajumdar/nanojit/blob/master/samples/example1.cpp) that illustrates using the NanoJITExtra C API.\n\nI am using NanoJIT as the backend for a C compiler - you can see more examples of [NanoJIT LIR here](https://github.com/dibyendumajumdar/dmr_c/tree/master/nanojit-backend).\n\n## Building NanoJIT\nWhile the goal of this project is to create a standalone build of NanoJIT, the original folder structure of avmplus is maintained so that merging upstream changes is easier.\n\nThe new build is work in progress. A very early version of CMakeLists.txt is available, this has been tested on Windows 10 with Visual Studio 2017, and with make on Linux and Mac OSX.  \n\nTo create Visual Studio project files do following:\n\n```\nmkdir build\ncd build\ncmake -DCMAKE_INSTALL_PREFIX=/path/to/install -G \"Visual Studio 15 2017 Win64\" -DCMAKE_BUILD_TYPE=Debug ..\n```\n\nOn Linux the command sequence is:\n\n```\nmkdir build\ncd build\ncmake -DCMAKE_INSTALL_PREFIX=/path/to/install -G \"Unix Makefiles\" -DCMAKE_BUILD_TYPE=Debug ..\n```\n\nBuilding the project will result in standalone NanoJIT and NanoJITExtra libraries, and the executable `lirasm` which can be used to assemble and run standalone code snippets as described above. Assuming you specified the `CMAKE_INSTALL_PREFIX` you can install the header files and the library using your build script.\n\n## Using NanoJIT\n\nOnce you have built the library all you need is to link the library, and include the `nanojitextra.h` header file. Note that the API is still being developed and is therefore not final yet. \n\nUsing NanoJIT on its own is a bit complicated mainly due to the requirement to provide variable liveness information as\ndescribed below. Addditionally the resolution of jumps to labels also requires some pre-processing.\n\nIt is therefore far easier to use a front-end to generate the NanoJIT LIR. A C front-end is being developed in the \nproject [dmr_C](https://github.com/dibyendumajumdar/dmr_c/tree/master/nanojit-backend). If you would still like to use \nNanoJIT directly then please read following carefully.\n\n### Insert Liveness information \nThe following information is based on information provided by Edwin Smith (original NanoJIT architect) and my own experience using it.\n\nThe register allocator computes virtual register liveness as it runs, while it\nis scanning LIR bottom-up. To prevent the allocator from thinking a\nregister or stack location (alloca) is available when it is not, following actions are needed:\n\na) Mark function parameters as live after all code is emitted for the function. Since NanoJIT only allows\nparameters in registers, not marking these live can cause the registers to be clobbered.\n\nb) If a virtual register is being defined before a loop entry\npoint, and used inside the loop, then its live range must cover the whole loop.\nThe front-end compiler must insert LIR_live at the loop jumps (back edges)\nto extend the live range. If the virtual registers are not marked as live\nthen the register allocator may incorrectly reuse the register.\n\nExample: Suppose you have a backward jump to block B. LIR_live for B's live-in\nregisters, should be added just before the jump (note: only needed for backwards\njumps). Note also that if the jump is in B1 and the target is B2, you\nneed LIR_live for B2's live-in registers.\n\nc) For stack allocations currently I recommend putting all allocation instructions \nat the start of the function body, and LIR_live instructions just before or after the\nfunction return. As the register allocator scans LIR instructions bottom up, it will see the LIR_live instructions\nfirst, and each LIR_live informs it about the stack allocation, until it hits the corresponding\nLIR_allocp instruction when the corresponding stack slot is marked as free. NanoJIT treats the stack as \na sequence of 4 byte slots, and the maximum number of slots is 4K on X86-64 I believe.\nUnless I am mistaken this means that the stack size of function cannot exceed 16K.\nIf the register allocator thinks a stack slot is free it might overwrite it when it needs\nto spill registers. My experience is that the register allocator can get confused if the \nLIR_allop instructions are interspersed with branch instructions, hence the recommendation\nto put all allocations at the beginning of the function.\n\n### Jumps and Labels\nThe instruction set requires setting labels as jump targets. There is no concept of basic blocks as in LLVM, but a basic block can be simulated by having a sequence of code with a label at the beginning and a jump at the end.\n\nThe code generator inserts the next instruction into the _current_ position within the LIR buffer. You may not yet have the target instruction defined yet as most jumps are forward jumps. Hence following procedure must be followed:\n\n* When you need to insert a jump, initially set jump target to NULL. This is okay. But keep track somewhere (e.g. in a memory structure) the logical target (e.g. the label name) for that jump target.  \n* Assign labels to the start of each basic block as you generate code for each basic block - these will become jump targets. Maintain a map of labels names to instructions. \n* After code generation is completed go back through the list of jumps you created in step 1, and set the targets to the labels which are now in place. You use the map created in step 2 to locate the label instructions.\n\n### NanoJIT does not handle complex types\nThe NanoJIT IR works at the level of integers, floats and pointers. Complex structures have to be managed by the front-end\nby generating appropriate load/store sequences.\n\n### JIT Functions can only take integer/pointer arguments\nAt least on X64 a limitation in NanoJIT is that JIT compiled functions can only take a limited number of arguments. On Win64 the limit is upto 4 integer or pointer arguments. On UNIX platforms it is 6 arguments, again only integer or pointer values. These\nlimitations arise as the current implementation only looks at the first 4/6 registers for arguments as per the X64 ABI.\n\nA JIT function should be able to return a double or float though - but this is something that is yet to be verified.\n\n### External C functions can only take upto 8 arguments\nExternal C functions called from JIT code can only take upto 8 arguments, although in this case it it possible to\nto pass double or float values. Return values can also be double or float.\n\n## Documentation\nA secondary goal of this project is to create some documentation of the standalone library, and document how it can be used. \n\n* [Main Components in NanoJIT](https://github.com/dibyendumajumdar/nanojit/blob/master/docs/overview.md)\n* [LIR Op Codes](https://github.com/dibyendumajumdar/nanojit/blob/master/docs/nanjit-opcodes.md)\n\n## Why NanoJIT?\nIt seems that NanoJIT is one of the rare examples of a small cross-platform standalone JIT library that can be used outside of the original project. It also matters that the license is not GPL. Finally it has been in production use in ActionScript and Adobe Flash for some time so one hopes that most bugs have been ironed out.\n\n## Why not NanoJIT?\nSupport is virtually non-existent. The original architect/developer Edwin Smith is no longer at Adobe, and works at [Facebook on HHVM](https://www.youtube.com/watch?v=GT4LxjJd2Ac). Although he is not involved with NanoJIT anymore, Edwin has graciously answered some of my questions. The Adobe team do not seem to respond to [issues](https://github.com/adobe/avmplus/issues).\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdibyendumajumdar%2Fnanojit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdibyendumajumdar%2Fnanojit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdibyendumajumdar%2Fnanojit/lists"}