Skip to content

Commit 183cbb7

Browse files
committed
YJIT: ZJIT: Allow both JITs in the same build
This commit allows building with both YJIT and ZJIT at the same time, a "combo build". Previously, `./configure --enable-yjit --enable-zjit` failed. At runtime, though, only one of the two can be enabled at a time. Add a root Cargo workspace that contains both the yjit and zjit crate. The common Rust build integration mechanisms are factored out into defs/jit.mk. Combo YJIT+ZJIT dev builds are supported; if either JIT uses `--enable-*=dev`, both of them are built in dev mode. The combo build requires Cargo, but building one JIT at a time with only rustc in release build remains supported.
1 parent 5b1a61e commit 183cbb7

19 files changed

Lines changed: 293 additions & 194 deletions

File tree

.github/auto_request_review.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ files:
1010
'zjit/src/cruby_bindings.inc.rs': []
1111
'doc/zjit*': [team:jit]
1212
'test/ruby/test_zjit*': [team:jit]
13+
'defs/jit.mk': [team:jit]
1314
options:
1415
ignore_draft: true
1516
# This currently doesn't work as intended. We want to skip reviews when only

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,9 @@ lcov*.info
246246
/yjit-bench
247247
/yjit_exit_locations.dump
248248

249+
# Rust
250+
/target
251+
249252
# /wasm/
250253
/wasm/tests/*.wasm
251254

Cargo.lock

Lines changed: 89 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Using Cargo's workspace feature to build all the Rust code in
2+
# into a single package.
3+
# TODO(alan) notes about rust version requirements. Undecided yet.
4+
5+
[workspace]
6+
members = ["zjit", "yjit"]
7+
8+
[package]
9+
name = "jit"
10+
version = "0.0.0"
11+
edition = "2024"
12+
rust-version = "1.85.0"
13+
publish = false # Don't publish to crates.io
14+
15+
[dependencies]
16+
yjit = { path = "yjit", optional = true }
17+
zjit = { path = "zjit", optional = true }
18+
19+
[lib]
20+
crate-type = ["staticlib"]
21+
path = "jit.rs"
22+
23+
[features]
24+
disasm = []
25+
runtime_checks = []
26+
yjit = [ "dep:yjit" ]
27+
zjit = [ "dep:zjit" ]
28+
29+
[profile.dev]
30+
opt-level = 0
31+
debug = true
32+
debug-assertions = true
33+
overflow-checks = true
34+
35+
[profile.dev_nodebug]
36+
inherits = "dev"
37+
38+
[profile.stats]
39+
inherits = "release"
40+
41+
[profile.release]
42+
# NOTE: --enable-yjit and zjit builds use `rustc` without going through Cargo. You
43+
# might want to update the `rustc` invocation if you change this profile.
44+
opt-level = 3
45+
# The extra robustness that comes from checking for arithmetic overflow is
46+
# worth the performance cost for the compiler.
47+
overflow-checks = true
48+
# Generate debug info
49+
debug = true
50+
# Use ThinLTO. Much smaller output for a small amount of build time increase.
51+
lto = "thin"

common.mk

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,9 @@ COMMONOBJS = array.$(OBJEXT) \
186186
weakmap.$(OBJEXT) \
187187
$(PRISM_FILES) \
188188
$(YJIT_OBJ) \
189-
$(YJIT_LIBOBJ) \
190189
$(ZJIT_OBJ) \
191-
$(ZJIT_LIBOBJ) \
192190
$(JIT_OBJ) \
191+
$(RUST_LIBOBJ) \
193192
$(COROUTINE_OBJ) \
194193
$(DTRACE_OBJ) \
195194
$(BUILTIN_ENCOBJS) \
@@ -345,7 +344,7 @@ YJIT_RUSTC_ARGS = --crate-name=yjit \
345344
-C opt-level=3 \
346345
-C overflow-checks=on \
347346
'--out-dir=$(CARGO_TARGET_DIR)/release/' \
348-
$(top_srcdir)/yjit/src/lib.rs
347+
'$(top_srcdir)/yjit/src/lib.rs'
349348

350349
ZJIT_RUSTC_ARGS = --crate-name=zjit \
351350
--crate-type=staticlib \
@@ -354,8 +353,8 @@ ZJIT_RUSTC_ARGS = --crate-name=zjit \
354353
-C lto=thin \
355354
-C opt-level=3 \
356355
-C overflow-checks=on \
357-
'--out-dir=$(ZJIT_CARGO_TARGET_DIR)/release/' \
358-
$(top_srcdir)/zjit/src/lib.rs
356+
'--out-dir=$(CARGO_TARGET_DIR)/release/' \
357+
'$(top_srcdir)/zjit/src/lib.rs'
359358

360359
all: $(SHOWFLAGS) main
361360

@@ -735,8 +734,8 @@ clean-local:: clean-runnable
735734
$(Q)$(RM) probes.h probes.$(OBJEXT) probes.stamp ruby-glommed.$(OBJEXT) ruby.imp ChangeLog $(STATIC_RUBY)$(EXEEXT)
736735
$(Q)$(RM) GNUmakefile.old Makefile.old $(arch)-fake.rb bisect.sh $(ENC_TRANS_D) builtin_binary.inc
737736
$(Q)$(RM) $(PRISM_BUILD_DIR)/.time $(PRISM_BUILD_DIR)/*/.time yjit_exit_locations.dump
738-
-$(Q)$(RMALL) yjit/target
739-
-$(Q) $(RMDIR) enc/jis enc/trans enc $(COROUTINE_H:/Context.h=) coroutine yjit \
737+
-$(Q)$(RMALL) target
738+
-$(Q) $(RMDIR) enc/jis enc/trans enc $(COROUTINE_H:/Context.h=) coroutine target \
740739
$(PRISM_BUILD_DIR)/*/ $(PRISM_BUILD_DIR) tmp \
741740
2> $(NULL) || $(NULLCMD)
742741

configure.ac

Lines changed: 54 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3926,46 +3926,33 @@ AC_ARG_ENABLE(yjit,
39263926
CARGO=
39273927
CARGO_BUILD_ARGS=
39283928
YJIT_LIBS=
3929+
RUST_JIT_SUPPORT=no
39293930
AS_CASE(["${YJIT_SUPPORT}"],
39303931
[yes|dev|stats|dev_nodebug], [
39313932
AS_IF([test x"$RUSTC" = "xno"],
39323933
AC_MSG_ERROR([rustc is required. Installation instructions available at https://www.rust-lang.org/tools/install])
39333934
)
3934-
AS_IF([test x"$ZJIT_SUPPORT" != "xno"],
3935-
AC_MSG_ERROR([YJIT cannot be enabled when ZJIT is enabled])
3936-
)
39373935
39383936
AS_CASE(["${YJIT_SUPPORT}"],
39393937
[yes], [
3940-
rb_rust_target_subdir=release
39413938
],
39423939
[dev], [
3943-
rb_rust_target_subdir=debug
3944-
CARGO_BUILD_ARGS='--features disasm,runtime_checks'
3940+
rb_cargo_features='disasm,runtime_checks'
3941+
RUST_JIT_SUPPORT=dev
39453942
AC_DEFINE(RUBY_DEBUG, 1)
39463943
],
39473944
[dev_nodebug], [
3948-
rb_rust_target_subdir=dev_nodebug
3949-
CARGO_BUILD_ARGS='--profile dev_nodebug --features disasm'
3945+
rb_cargo_features='disasm'
3946+
RUST_JIT_SUPPORT=dev_nodebug
39503947
AC_DEFINE(YJIT_STATS, 1)
39513948
],
39523949
[stats], [
3953-
rb_rust_target_subdir=stats
3954-
CARGO_BUILD_ARGS='--profile stats'
3950+
RUST_JIT_SUPPORT=stats
39553951
AC_DEFINE(YJIT_STATS, 1)
39563952
])
39573953
3958-
AS_IF([test -n "${CARGO_BUILD_ARGS}"], [
3959-
AC_CHECK_TOOL(CARGO, [cargo], [no])
3960-
AS_IF([test x"$CARGO" = "xno"],
3961-
AC_MSG_ERROR([cargo is required. Installation instructions available at https://www.rust-lang.org/tools/install])
3962-
]))
3963-
3964-
YJIT_LIBS="yjit/target/${rb_rust_target_subdir}/libyjit.a"
3965-
AS_CASE(["$target_os"],[openbsd*],[
3966-
# Link libc++abi (which requires libpthread) for _Unwind_* functions needed by yjit
3967-
LDFLAGS="$LDFLAGS -lpthread -lc++abi"
3968-
])
3954+
YJIT_LIBS="target/release/libyjit.a"
3955+
RUST_LIB='$(YJIT_LIBS)'
39693956
YJIT_OBJ='yjit.$(OBJEXT)'
39703957
JIT_OBJ='jit.$(OBJEXT)'
39713958
AS_IF([test x"$YJIT_SUPPORT" != "xyes" ], [
@@ -3976,38 +3963,23 @@ AS_CASE(["${YJIT_SUPPORT}"],
39763963
AC_DEFINE(USE_YJIT, 0)
39773964
])
39783965

3979-
ZJIT_CARGO_BUILD_ARGS=
39803966
ZJIT_LIBS=
39813967
AS_CASE(["${ZJIT_SUPPORT}"],
39823968
[yes|dev], [
39833969
AS_IF([test x"$RUSTC" = "xno"],
39843970
AC_MSG_ERROR([rustc is required. Installation instructions available at https://www.rust-lang.org/tools/install])
39853971
)
3986-
AS_IF([test x"$YJIT_SUPPORT" != "xno"],
3987-
AC_MSG_ERROR([ZJIT cannot be enabled when YJIT is enabled])
3988-
)
39893972
39903973
AS_CASE(["${ZJIT_SUPPORT}"],
39913974
[yes], [
3992-
rb_rust_target_subdir=release
39933975
],
39943976
[dev], [
3995-
rb_rust_target_subdir=debug
3996-
ZJIT_CARGO_BUILD_ARGS='--profile dev --features disasm'
3977+
RUST_JIT_SUPPORT=dev
39973978
AC_DEFINE(RUBY_DEBUG, 1)
39983979
])
39993980
4000-
AS_IF([test -n "${ZJIT_CARGO_BUILD_ARGS}"], [
4001-
AC_CHECK_TOOL(CARGO, [cargo], [no])
4002-
AS_IF([test x"$CARGO" = "xno"],
4003-
AC_MSG_ERROR([cargo is required. Installation instructions available at https://www.rust-lang.org/tools/install])
4004-
]))
4005-
4006-
ZJIT_LIBS="zjit/target/${rb_rust_target_subdir}/libzjit.a"
4007-
AS_CASE(["$target_os"],[openbsd*],[
4008-
# Link libc++abi (which requires libpthread) for _Unwind_* functions needed by yjit
4009-
LDFLAGS="$LDFLAGS -lpthread -lc++abi"
4010-
])
3981+
ZJIT_LIBS="target/release/libzjit.a"
3982+
RUST_LIB='$(ZJIT_LIBS)'
40113983
ZJIT_OBJ='zjit.$(OBJEXT)'
40123984
JIT_OBJ='jit.$(OBJEXT)'
40133985
AS_IF([test x"$ZJIT_SUPPORT" != "xyes" ], [
@@ -4018,18 +3990,57 @@ AS_CASE(["${ZJIT_SUPPORT}"],
40183990
AC_DEFINE(USE_ZJIT, 0)
40193991
])
40203992

3993+
# if YJIT+ZJIT release build, or any build that requires Cargo
3994+
AS_IF([test x"$RUST_JIT_SUPPORT" != "xno" -o \( x"$YJIT_SUPPORT" != "xno" -a x"$ZJIT_SUPPORT" != "xno" \)], [
3995+
AC_CHECK_TOOL(CARGO, [cargo], [no])
3996+
AS_IF([test x"$CARGO" = "xno"],
3997+
AC_MSG_ERROR([cargo is required. Installation instructions available at https://www.rust-lang.org/tools/install]))
3998+
3999+
YJIT_LIBS=
4000+
ZJIT_LIBS=
4001+
4002+
AS_IF([test x"${YJIT_SUPPORT}" != x"no"], [
4003+
rb_cargo_features="$rb_cargo_features,yjit"
4004+
])
4005+
AS_IF([test x"${ZJIT_SUPPORT}" != x"no"], [
4006+
rb_cargo_features="$rb_cargo_features,zjit"
4007+
])
4008+
# if YJIT and ZJIT release mode
4009+
AS_IF([test "${YJIT_SUPPORT}:${ZJIT_SUPPORT}" = "yes:yes"], [
4010+
RUST_JIT_SUPPORT=release
4011+
])
4012+
CARGO_BUILD_ARGS="--profile ${RUST_JIT_SUPPORT} --features ${rb_cargo_features}"
4013+
AS_IF([test "${RUST_JIT_SUPPORT}" = "dev"], [
4014+
RUST_LIB="target/debug/libjit.a"
4015+
], [
4016+
RUST_LIB="target/${RUST_JIT_SUPPORT}/libjit.a"
4017+
])
4018+
])
4019+
4020+
# In case either we're linking rust code
4021+
AS_IF([test -n "$RUST_LIB"], [
4022+
AS_CASE(["$target_os"],[openbsd*],[
4023+
# Link libc++abi (which requires libpthread) for _Unwind_* functions needed by rust stdlib
4024+
LDFLAGS="$LDFLAGS -lpthread -lc++abi"
4025+
])
4026+
4027+
# absolute path to stop the "target" dir in src dir from interfering through VPATH
4028+
RUST_LIB="$(pwd)/${RUST_LIB}"
4029+
])
4030+
40214031
dnl These variables end up in ::RbConfig::CONFIG
4022-
AC_SUBST(YJIT_SUPPORT)dnl what flavor of YJIT the Ruby build includes
40234032
AC_SUBST(RUSTC)dnl Rust compiler command
40244033
AC_SUBST(CARGO)dnl Cargo command for Rust builds
40254034
AC_SUBST(CARGO_BUILD_ARGS)dnl for selecting Rust build profiles
4026-
AC_SUBST(ZJIT_CARGO_BUILD_ARGS)dnl for selecting Rust build profiles
4027-
AC_SUBST(YJIT_LIBS)dnl for optionally building the Rust parts of YJIT
4035+
AC_SUBST(YJIT_SUPPORT)dnl what flavor of YJIT the Ruby build includes
4036+
AC_SUBST(YJIT_LIBS)dnl
40284037
AC_SUBST(YJIT_OBJ)dnl for optionally building the C parts of YJIT
40294038
AC_SUBST(ZJIT_SUPPORT)dnl what flavor of ZJIT the Ruby build includes
4030-
AC_SUBST(ZJIT_LIBS)dnl for optionally building the Rust parts of ZJIT
4039+
AC_SUBST(ZJIT_LIBS)dnl
40314040
AC_SUBST(ZJIT_OBJ)dnl for optionally building the C parts of ZJIT
40324041
AC_SUBST(JIT_OBJ)dnl for optionally building C glue code for Rust FFI
4042+
AC_SUBST(RUST_LIB)dnl for optionally building YJIT+ZJIT together
4043+
AC_SUBST(RUST_JIT_SUPPORT)dnl whether to use cargo to build all the rust code
40334044
}
40344045

40354046
[begin]_group "build section" && {

defs/gmake.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,7 @@ endif
443443

444444
include $(top_srcdir)/yjit/yjit.mk
445445
include $(top_srcdir)/zjit/zjit.mk
446+
include $(top_srcdir)/defs/jit.mk
446447

447448
# Query on the generated rdoc
448449
#

0 commit comments

Comments
 (0)