展示 HN:Cj – 适用于 x86-64 和 ARM64 的微型无依赖 JIT,用 C 编写。
Show HN: Cj–tiny no-deps JIT in C for x86-64 and ARM64

原始链接: https://github.com/hellerve-pl-experiments/cj

## cj – 一个极简的即时编译框架 cj 是一个用 C 编写的、无依赖的即时编译 (JIT) 框架。它支持 x86-64 和 ARM64 架构,通过低级 API 直接生成本机代码——这意味着开发者直接发出指令,而没有高级抽象。 该框架拥有自动生成的后端(使用 `asmdb` 和 `mra_tools` 等工具)和手工编写的寄存器定义,从而使核心编译逻辑相对简单。它仅依赖于 C 标准库和 POSIX 进行内存映射。 示例代码演示了基本的 JIT 编译(NOP、RET),并利用可选的“构建器助手”进行更有结构的码生成,包括序言/尾声设置和循环。一个示例程序计算 5 的三角数。 cj 专为学习和实验而设计,旨在理解处理器指令集架构 (ISA)。它需要一个 C11 编译器和一个符合 POSIX 标准的操作系统。

一位开发者在Hacker News分享了“Cj”,一个用C语言编写的、无依赖的JIT(即时编译)编译器,支持x86-64和ARM64架构。该项目是对7年前想法的复兴,具有使用JavaScript脚本自动生成的后端和用于函数处理的基本抽象层。 目前Cj还处于非常早期的开发阶段,可以编译示例程序(包括一个极简语言实现——链接在帖子中),但缺乏寄存器分配器和完整的ABI支持等功能。开发者正在寻求反馈、错误报告和贡献,尤其是在代码生成辅助工具和更多示例方面。 他们不确定该项目的未来,正在考虑将其视为一个完成的实验还是继续开发。 还有一篇包含更多细节的博客文章,但GitHub仓库 ([https://github.com/hellerve-pl-experiments/cj](https://github.com/hellerve-pl-experiments/cj)) 包含最全面的信息。
相关文章

原文

is a small JIT framework written in C, with x86 and arm64 backends.

  • multi-architecture support: generates native code for:
    • x86-64
    • ARM64 (except for 26 SIMD different-size instructions)
  • low-level API: direct instruction emission, no high level constructs
  • no dependencies: pure C with clib, nothing else

the backends are autogenerated (check out codegen). x86 uses asmdb as a data source, arm64 uses a handgenerated file from mra_tools. register definitions are hand-crafted.

the rest is handwritten and basically trivial in the grand scheme of jit compilation. examples, tests, and codegen docs contain some llm-generation, so peruse at your own peril.

because i wanted to understand the isa for both processor architectures and it seemed like a fun project.

# dev build
make dev

# "prod" build
make all

# install (don't)
make install
#include "ctx.h"
#include "op.h"

int main(void) {
  // Create JIT context
  cj_ctx* cj = create_cj_ctx();

  // Emit instructions
  cj_nop(cj);  // NOP
  cj_ret(cj);  // RET

  // Create executable function
  cj_fn f = create_cj_fn(cj);

  // Execute JIT-compiled code!
  f();

  // Cleanup
  destroy_cj_fn(cj, f);
  destroy_cj_ctx(cj);

  return 0;
}

you can find some more examples in the examples directory.

For reusable building blocks, the optional builder helpers provide prologue/epilogue setup and structured loops:

#include <stdio.h>
#include "builder.h"

typedef int (*sum_fn)(int);

int main(void) {
  cj_ctx* cj = create_cj_ctx();
  cj_builder_frame frame;
  cj_builder_fn_prologue(cj, 0, &frame);

  cj_operand n = cj_builder_arg_int(cj, 0);
  cj_operand sum = cj_builder_scratch_reg(0);
  cj_operand i = cj_builder_scratch_reg(1);
  cj_operand one = cj_make_constant(1);

  cj_builder_assign(cj, sum, cj_builder_zero_operand());

  cj_builder_for_loop loop = cj_builder_for_begin(cj, i, one, n, one, CJ_COND_GE);
  cj_builder_add_assign(cj, sum, i);
  cj_builder_for_end(cj, &loop);

  cj_builder_return_value(cj, &frame, sum);

  sum_fn fn = (sum_fn)create_cj_fn(cj);
  printf("triangular(5) = %d\n", fn ? fn(5) : -1);

  destroy_cj_fn(cj, (cj_fn)fn);
  destroy_cj_ctx(cj);
  return 0;
}

see also docs/builder.md.

  • c11 compiler (gcc, clang)
  • POSIX-compliant OS (for mmap)
  • supported architecture (x86-64 or ARM64)

Have fun!

联系我们 contact @ memedata.com