YJIT: ZJIT: Allow both JITs in the same build
This commit allows building YJIT and ZJIT simultaneously, 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.
This commit is contained in:
parent
b5575a80bc
commit
92b218fbc3
Notes:
git
2025-05-14 15:39:18 +00:00
1
.github/auto_request_review.yml
vendored
1
.github/auto_request_review.yml
vendored
@ -10,6 +10,7 @@ files:
|
||||
'zjit/src/cruby_bindings.inc.rs': []
|
||||
'doc/zjit*': [team:jit]
|
||||
'test/ruby/test_zjit*': [team:jit]
|
||||
'defs/jit.mk': [team:jit]
|
||||
options:
|
||||
ignore_draft: true
|
||||
# This currently doesn't work as intended. We want to skip reviews when only
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -246,6 +246,9 @@ lcov*.info
|
||||
/yjit-bench
|
||||
/yjit_exit_locations.dump
|
||||
|
||||
# Rust
|
||||
/target
|
||||
|
||||
# /wasm/
|
||||
/wasm/tests/*.wasm
|
||||
|
||||
|
89
Cargo.lock
generated
Normal file
89
Cargo.lock
generated
Normal file
@ -0,0 +1,89 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "capstone"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "015ef5d5ca1743e3f94af9509ba6bd2886523cfee46e48d15c2ef5216fd4ac9a"
|
||||
dependencies = [
|
||||
"capstone-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "capstone-sys"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2267cb8d16a1e4197863ec4284ffd1aec26fe7e57c58af46b02590a0235809a0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dissimilar"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8975ffdaa0ef3661bfe02dbdcc06c9f829dfafe6a3c474de366a8d5e44276921"
|
||||
|
||||
[[package]]
|
||||
name = "expect-test"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63af43ff4431e848fb47472a920f14fa71c24de13255a5692e93d4e90302acb0"
|
||||
dependencies = [
|
||||
"dissimilar",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jit"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"yjit",
|
||||
"zjit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.171"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "yjit"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"capstone",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zjit"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"capstone",
|
||||
"expect-test",
|
||||
]
|
51
Cargo.toml
Normal file
51
Cargo.toml
Normal file
@ -0,0 +1,51 @@
|
||||
# Using Cargo's workspace feature to build all the Rust code in
|
||||
# into a single package.
|
||||
# TODO(alan) notes about rust version requirements. Undecided yet.
|
||||
|
||||
[workspace]
|
||||
members = ["zjit", "yjit"]
|
||||
|
||||
[package]
|
||||
name = "jit"
|
||||
version = "0.0.0"
|
||||
edition = "2024"
|
||||
rust-version = "1.85.0"
|
||||
publish = false # Don't publish to crates.io
|
||||
|
||||
[dependencies]
|
||||
yjit = { path = "yjit", optional = true }
|
||||
zjit = { path = "zjit", optional = true }
|
||||
|
||||
[lib]
|
||||
crate-type = ["staticlib"]
|
||||
path = "jit.rs"
|
||||
|
||||
[features]
|
||||
disasm = []
|
||||
runtime_checks = []
|
||||
yjit = [ "dep:yjit" ]
|
||||
zjit = [ "dep:zjit" ]
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 0
|
||||
debug = true
|
||||
debug-assertions = true
|
||||
overflow-checks = true
|
||||
|
||||
[profile.dev_nodebug]
|
||||
inherits = "dev"
|
||||
|
||||
[profile.stats]
|
||||
inherits = "release"
|
||||
|
||||
[profile.release]
|
||||
# NOTE: --enable-yjit and zjit builds use `rustc` without going through Cargo. You
|
||||
# might want to update the `rustc` invocation if you change this profile.
|
||||
opt-level = 3
|
||||
# The extra robustness that comes from checking for arithmetic overflow is
|
||||
# worth the performance cost for the compiler.
|
||||
overflow-checks = true
|
||||
# Generate debug info
|
||||
debug = true
|
||||
# Use ThinLTO. Much smaller output for a small amount of build time increase.
|
||||
lto = "thin"
|
13
common.mk
13
common.mk
@ -187,10 +187,9 @@ COMMONOBJS = array.$(OBJEXT) \
|
||||
weakmap.$(OBJEXT) \
|
||||
$(PRISM_FILES) \
|
||||
$(YJIT_OBJ) \
|
||||
$(YJIT_LIBOBJ) \
|
||||
$(ZJIT_OBJ) \
|
||||
$(ZJIT_LIBOBJ) \
|
||||
$(JIT_OBJ) \
|
||||
$(RUST_LIBOBJ) \
|
||||
$(COROUTINE_OBJ) \
|
||||
$(DTRACE_OBJ) \
|
||||
$(BUILTIN_ENCOBJS) \
|
||||
@ -346,7 +345,7 @@ YJIT_RUSTC_ARGS = --crate-name=yjit \
|
||||
-C opt-level=3 \
|
||||
-C overflow-checks=on \
|
||||
'--out-dir=$(CARGO_TARGET_DIR)/release/' \
|
||||
$(top_srcdir)/yjit/src/lib.rs
|
||||
'$(top_srcdir)/yjit/src/lib.rs'
|
||||
|
||||
ZJIT_RUSTC_ARGS = --crate-name=zjit \
|
||||
--crate-type=staticlib \
|
||||
@ -355,8 +354,8 @@ ZJIT_RUSTC_ARGS = --crate-name=zjit \
|
||||
-C lto=thin \
|
||||
-C opt-level=3 \
|
||||
-C overflow-checks=on \
|
||||
'--out-dir=$(ZJIT_CARGO_TARGET_DIR)/release/' \
|
||||
$(top_srcdir)/zjit/src/lib.rs
|
||||
'--out-dir=$(CARGO_TARGET_DIR)/release/' \
|
||||
'$(top_srcdir)/zjit/src/lib.rs'
|
||||
|
||||
all: $(SHOWFLAGS) main
|
||||
|
||||
@ -736,8 +735,8 @@ clean-local:: clean-runnable
|
||||
$(Q)$(RM) probes.h probes.$(OBJEXT) probes.stamp ruby-glommed.$(OBJEXT) ruby.imp ChangeLog $(STATIC_RUBY)$(EXEEXT)
|
||||
$(Q)$(RM) GNUmakefile.old Makefile.old $(arch)-fake.rb bisect.sh $(ENC_TRANS_D) builtin_binary.inc
|
||||
$(Q)$(RM) $(PRISM_BUILD_DIR)/.time $(PRISM_BUILD_DIR)/*/.time yjit_exit_locations.dump
|
||||
-$(Q)$(RMALL) yjit/target
|
||||
-$(Q) $(RMDIR) enc/jis enc/trans enc $(COROUTINE_H:/Context.h=) coroutine yjit \
|
||||
-$(Q)$(RMALL) target
|
||||
-$(Q) $(RMDIR) enc/jis enc/trans enc $(COROUTINE_H:/Context.h=) coroutine target \
|
||||
$(PRISM_BUILD_DIR)/*/ $(PRISM_BUILD_DIR) tmp \
|
||||
2> $(NULL) || $(NULLCMD)
|
||||
|
||||
|
97
configure.ac
97
configure.ac
@ -3924,46 +3924,33 @@ AC_ARG_ENABLE(yjit,
|
||||
CARGO=
|
||||
CARGO_BUILD_ARGS=
|
||||
YJIT_LIBS=
|
||||
JIT_CARGO_SUPPORT=no
|
||||
AS_CASE(["${YJIT_SUPPORT}"],
|
||||
[yes|dev|stats|dev_nodebug], [
|
||||
AS_IF([test x"$RUSTC" = "xno"],
|
||||
AC_MSG_ERROR([rustc is required. Installation instructions available at https://www.rust-lang.org/tools/install])
|
||||
)
|
||||
AS_IF([test x"$ZJIT_SUPPORT" != "xno"],
|
||||
AC_MSG_ERROR([YJIT cannot be enabled when ZJIT is enabled])
|
||||
)
|
||||
|
||||
AS_CASE(["${YJIT_SUPPORT}"],
|
||||
[yes], [
|
||||
rb_rust_target_subdir=release
|
||||
],
|
||||
[dev], [
|
||||
rb_rust_target_subdir=debug
|
||||
CARGO_BUILD_ARGS='--features disasm,runtime_checks'
|
||||
rb_cargo_features='disasm,runtime_checks'
|
||||
JIT_CARGO_SUPPORT=dev
|
||||
AC_DEFINE(RUBY_DEBUG, 1)
|
||||
],
|
||||
[dev_nodebug], [
|
||||
rb_rust_target_subdir=dev_nodebug
|
||||
CARGO_BUILD_ARGS='--profile dev_nodebug --features disasm'
|
||||
rb_cargo_features='disasm'
|
||||
JIT_CARGO_SUPPORT=dev_nodebug
|
||||
AC_DEFINE(YJIT_STATS, 1)
|
||||
],
|
||||
[stats], [
|
||||
rb_rust_target_subdir=stats
|
||||
CARGO_BUILD_ARGS='--profile stats'
|
||||
JIT_CARGO_SUPPORT=stats
|
||||
AC_DEFINE(YJIT_STATS, 1)
|
||||
])
|
||||
|
||||
AS_IF([test -n "${CARGO_BUILD_ARGS}"], [
|
||||
AC_CHECK_TOOL(CARGO, [cargo], [no])
|
||||
AS_IF([test x"$CARGO" = "xno"],
|
||||
AC_MSG_ERROR([cargo is required. Installation instructions available at https://www.rust-lang.org/tools/install])
|
||||
]))
|
||||
|
||||
YJIT_LIBS="yjit/target/${rb_rust_target_subdir}/libyjit.a"
|
||||
AS_CASE(["$target_os"],[openbsd*],[
|
||||
# Link libc++abi (which requires libpthread) for _Unwind_* functions needed by yjit
|
||||
LDFLAGS="$LDFLAGS -lpthread -lc++abi"
|
||||
])
|
||||
YJIT_LIBS="target/release/libyjit.a"
|
||||
RUST_LIB='$(YJIT_LIBS)'
|
||||
YJIT_OBJ='yjit.$(OBJEXT)'
|
||||
JIT_OBJ='jit.$(OBJEXT)'
|
||||
AS_IF([test x"$YJIT_SUPPORT" != "xyes" ], [
|
||||
@ -3974,38 +3961,23 @@ AS_CASE(["${YJIT_SUPPORT}"],
|
||||
AC_DEFINE(USE_YJIT, 0)
|
||||
])
|
||||
|
||||
ZJIT_CARGO_BUILD_ARGS=
|
||||
ZJIT_LIBS=
|
||||
AS_CASE(["${ZJIT_SUPPORT}"],
|
||||
[yes|dev], [
|
||||
AS_IF([test x"$RUSTC" = "xno"],
|
||||
AC_MSG_ERROR([rustc is required. Installation instructions available at https://www.rust-lang.org/tools/install])
|
||||
)
|
||||
AS_IF([test x"$YJIT_SUPPORT" != "xno"],
|
||||
AC_MSG_ERROR([ZJIT cannot be enabled when YJIT is enabled])
|
||||
)
|
||||
|
||||
AS_CASE(["${ZJIT_SUPPORT}"],
|
||||
[yes], [
|
||||
rb_rust_target_subdir=release
|
||||
],
|
||||
[dev], [
|
||||
rb_rust_target_subdir=debug
|
||||
ZJIT_CARGO_BUILD_ARGS='--profile dev --features disasm'
|
||||
JIT_CARGO_SUPPORT=dev
|
||||
AC_DEFINE(RUBY_DEBUG, 1)
|
||||
])
|
||||
|
||||
AS_IF([test -n "${ZJIT_CARGO_BUILD_ARGS}"], [
|
||||
AC_CHECK_TOOL(CARGO, [cargo], [no])
|
||||
AS_IF([test x"$CARGO" = "xno"],
|
||||
AC_MSG_ERROR([cargo is required. Installation instructions available at https://www.rust-lang.org/tools/install])
|
||||
]))
|
||||
|
||||
ZJIT_LIBS="zjit/target/${rb_rust_target_subdir}/libzjit.a"
|
||||
AS_CASE(["$target_os"],[openbsd*],[
|
||||
# Link libc++abi (which requires libpthread) for _Unwind_* functions needed by yjit
|
||||
LDFLAGS="$LDFLAGS -lpthread -lc++abi"
|
||||
])
|
||||
ZJIT_LIBS="target/release/libzjit.a"
|
||||
RUST_LIB='$(ZJIT_LIBS)'
|
||||
ZJIT_OBJ='zjit.$(OBJEXT)'
|
||||
JIT_OBJ='jit.$(OBJEXT)'
|
||||
AS_IF([test x"$ZJIT_SUPPORT" != "xyes" ], [
|
||||
@ -4016,18 +3988,57 @@ AS_CASE(["${ZJIT_SUPPORT}"],
|
||||
AC_DEFINE(USE_ZJIT, 0)
|
||||
])
|
||||
|
||||
# if YJIT+ZJIT release build, or any build that requires Cargo
|
||||
AS_IF([test x"$JIT_CARGO_SUPPORT" != "xno" -o \( x"$YJIT_SUPPORT" != "xno" -a x"$ZJIT_SUPPORT" != "xno" \)], [
|
||||
AC_CHECK_TOOL(CARGO, [cargo], [no])
|
||||
AS_IF([test x"$CARGO" = "xno"],
|
||||
AC_MSG_ERROR([cargo is required. Installation instructions available at https://www.rust-lang.org/tools/install]))
|
||||
|
||||
YJIT_LIBS=
|
||||
ZJIT_LIBS=
|
||||
|
||||
AS_IF([test x"${YJIT_SUPPORT}" != x"no"], [
|
||||
rb_cargo_features="$rb_cargo_features,yjit"
|
||||
])
|
||||
AS_IF([test x"${ZJIT_SUPPORT}" != x"no"], [
|
||||
rb_cargo_features="$rb_cargo_features,zjit"
|
||||
])
|
||||
# if YJIT and ZJIT release mode
|
||||
AS_IF([test "${YJIT_SUPPORT}:${ZJIT_SUPPORT}" = "yes:yes"], [
|
||||
JIT_CARGO_SUPPORT=release
|
||||
])
|
||||
CARGO_BUILD_ARGS="--profile ${JIT_CARGO_SUPPORT} --features ${rb_cargo_features}"
|
||||
AS_IF([test "${JIT_CARGO_SUPPORT}" = "dev"], [
|
||||
RUST_LIB="target/debug/libjit.a"
|
||||
], [
|
||||
RUST_LIB="target/${JIT_CARGO_SUPPORT}/libjit.a"
|
||||
])
|
||||
])
|
||||
|
||||
# In case either we're linking rust code
|
||||
AS_IF([test -n "$RUST_LIB"], [
|
||||
AS_CASE(["$target_os"],[openbsd*],[
|
||||
# Link libc++abi (which requires libpthread) for _Unwind_* functions needed by rust stdlib
|
||||
LDFLAGS="$LDFLAGS -lpthread -lc++abi"
|
||||
])
|
||||
|
||||
# absolute path to stop the "target" dir in src dir from interfering through VPATH
|
||||
RUST_LIB="$(pwd)/${RUST_LIB}"
|
||||
])
|
||||
|
||||
dnl These variables end up in ::RbConfig::CONFIG
|
||||
AC_SUBST(YJIT_SUPPORT)dnl what flavor of YJIT the Ruby build includes
|
||||
AC_SUBST(RUSTC)dnl Rust compiler command
|
||||
AC_SUBST(CARGO)dnl Cargo command for Rust builds
|
||||
AC_SUBST(CARGO_BUILD_ARGS)dnl for selecting Rust build profiles
|
||||
AC_SUBST(ZJIT_CARGO_BUILD_ARGS)dnl for selecting Rust build profiles
|
||||
AC_SUBST(YJIT_LIBS)dnl for optionally building the Rust parts of YJIT
|
||||
AC_SUBST(YJIT_SUPPORT)dnl what flavor of YJIT the Ruby build includes
|
||||
AC_SUBST(YJIT_LIBS)dnl the .a library of YJIT
|
||||
AC_SUBST(YJIT_OBJ)dnl for optionally building the C parts of YJIT
|
||||
AC_SUBST(ZJIT_SUPPORT)dnl what flavor of ZJIT the Ruby build includes
|
||||
AC_SUBST(ZJIT_LIBS)dnl for optionally building the Rust parts of ZJIT
|
||||
AC_SUBST(ZJIT_LIBS)dnl path to the .a library of ZJIT
|
||||
AC_SUBST(ZJIT_OBJ)dnl for optionally building the C parts of ZJIT
|
||||
AC_SUBST(JIT_OBJ)dnl for optionally building C glue code for Rust FFI
|
||||
AC_SUBST(RUST_LIB)dnl path to the rust .a library that contains either or both JITs
|
||||
AC_SUBST(JIT_CARGO_SUPPORT)dnl "no" or the cargo profile of the rust code
|
||||
}
|
||||
|
||||
[begin]_group "build section" && {
|
||||
|
@ -443,6 +443,7 @@ endif
|
||||
|
||||
include $(top_srcdir)/yjit/yjit.mk
|
||||
include $(top_srcdir)/zjit/zjit.mk
|
||||
include $(top_srcdir)/defs/jit.mk
|
||||
|
||||
# Query on the generated rdoc
|
||||
#
|
||||
|
53
defs/jit.mk
Normal file
53
defs/jit.mk
Normal file
@ -0,0 +1,53 @@
|
||||
# Make recipes that deal with the rust code of YJIT and ZJIT.
|
||||
|
||||
# Because of Cargo cache, if the actual binary is not changed from the
|
||||
# previous build, the mtime is preserved as the cached file.
|
||||
# This means the target is not updated actually, and it will need to
|
||||
# rebuild at the next build.
|
||||
RUST_LIB_TOUCH = touch $@
|
||||
|
||||
ifneq ($(JIT_CARGO_SUPPORT),no)
|
||||
$(RUST_LIB):
|
||||
$(Q)if [ '$(ZJIT_SUPPORT)' != no -a '$(YJIT_SUPPORT)' != no ]; then \
|
||||
echo 'building YJIT and ZJIT ($(JIT_CARGO_SUPPORT:yes=release) mode)'; \
|
||||
elif [ '$(ZJIT_SUPPORT)' != no ]; then \
|
||||
echo 'building ZJIT ($(JIT_CARGO_SUPPORT) mode)'; \
|
||||
elif [ '$(YJIT_SUPPORT)' != no ]; then \
|
||||
echo 'building YJIT ($(JIT_CARGO_SUPPORT) mode)'; \
|
||||
fi
|
||||
+$(Q)CARGO_TARGET_DIR='$(CARGO_TARGET_DIR)' \
|
||||
CARGO_TERM_PROGRESS_WHEN='never' \
|
||||
$(CARGO) $(CARGO_VERBOSE) build --manifest-path '$(top_srcdir)/Cargo.toml' $(CARGO_BUILD_ARGS)
|
||||
$(RUST_LIB_TOUCH)
|
||||
endif
|
||||
|
||||
RUST_LIB_SYMBOLS = $(RUST_LIB:.a=).symbols
|
||||
$(RUST_LIBOBJ): $(RUST_LIB)
|
||||
$(ECHO) 'partial linking $(RUST_LIB) into $@'
|
||||
ifneq ($(findstring darwin,$(target_os)),)
|
||||
$(Q) $(CC) -nodefaultlibs -r -o $@ -exported_symbols_list $(RUST_LIB_SYMBOLS) $(RUST_LIB)
|
||||
else
|
||||
$(Q) $(LD) -r -o $@ --whole-archive $(RUST_LIB)
|
||||
-$(Q) $(OBJCOPY) --wildcard --keep-global-symbol='$(SYMBOL_PREFIX)rb_*' $(@)
|
||||
endif
|
||||
|
||||
rust-libobj: $(RUST_LIBOBJ)
|
||||
rust-lib: $(RUST_LIB)
|
||||
|
||||
# For Darwin only: a list of symbols that we want the glommed Rust static lib to export.
|
||||
# Unfortunately, using wildcard like '_rb_*' with -exported-symbol does not work, at least
|
||||
# not on version 820.1. Assume llvm-nm, so XCode 8.0 (from 2016) or newer.
|
||||
#
|
||||
# The -exported_symbols_list pulls out the right archive members. Symbols not listed
|
||||
# in the list are made private extern, which are in turn made local as we're using `ld -r`.
|
||||
# Note, section about -keep_private_externs in ld's man page hints at this behavior on which
|
||||
# we rely.
|
||||
ifneq ($(findstring darwin,$(target_os)),)
|
||||
$(RUST_LIB_SYMBOLS): $(RUST_LIB)
|
||||
$(Q) $(tooldir)/darwin-ar $(NM) --defined-only --extern-only $(RUST_LIB) | \
|
||||
sed -n -e 's/.* //' -e '/^$(SYMBOL_PREFIX)rb_/p' \
|
||||
-e '/^$(SYMBOL_PREFIX)rust_eh_personality/p' \
|
||||
> $@
|
||||
|
||||
$(RUST_LIBOBJ): $(RUST_LIB_SYMBOLS)
|
||||
endif
|
@ -35,3 +35,5 @@ default = []
|
||||
|
||||
# When moving an object, clear its original copy.
|
||||
clear_old_copy = []
|
||||
|
||||
[workspace]
|
||||
|
4
jit.rs
Normal file
4
jit.rs
Normal file
@ -0,0 +1,4 @@
|
||||
#[cfg(feature = "yjit")]
|
||||
pub use yjit::*;
|
||||
#[cfg(feature = "zjit")]
|
||||
pub use zjit::*;
|
@ -107,15 +107,14 @@ JIT_OBJ=@JIT_OBJ@
|
||||
YJIT_SUPPORT=@YJIT_SUPPORT@
|
||||
YJIT_LIBS=@YJIT_LIBS@
|
||||
YJIT_OBJ=@YJIT_OBJ@
|
||||
YJIT_LIBOBJ = $(YJIT_LIBS:.a=.@OBJEXT@)
|
||||
ZJIT_SUPPORT=@ZJIT_SUPPORT@
|
||||
ZJIT_LIBS=@ZJIT_LIBS@
|
||||
ZJIT_OBJ=@ZJIT_OBJ@
|
||||
ZJIT_LIBOBJ = $(ZJIT_LIBS:.a=.@OBJEXT@)
|
||||
CARGO_TARGET_DIR=@abs_top_builddir@/yjit/target
|
||||
JIT_CARGO_SUPPORT=@JIT_CARGO_SUPPORT@
|
||||
CARGO_TARGET_DIR=@abs_top_builddir@/target
|
||||
CARGO_BUILD_ARGS=@CARGO_BUILD_ARGS@
|
||||
ZJIT_CARGO_BUILD_ARGS=@ZJIT_CARGO_BUILD_ARGS@
|
||||
ZJIT_CARGO_TARGET_DIR=@abs_top_builddir@/zjit/target
|
||||
RUST_LIB=@RUST_LIB@
|
||||
RUST_LIBOBJ = $(RUST_LIB:.a=.@OBJEXT@)
|
||||
LDFLAGS = @STATIC@ $(CFLAGS) @LDFLAGS@
|
||||
EXE_LDFLAGS = $(LDFLAGS)
|
||||
EXTLDFLAGS = @EXTLDFLAGS@
|
||||
|
4
vm.c
4
vm.c
@ -452,7 +452,9 @@ jit_compile(rb_execution_context_t *ec)
|
||||
rb_zjit_compile_iseq(iseq, ec, false);
|
||||
}
|
||||
}
|
||||
#elif USE_YJIT
|
||||
#endif
|
||||
|
||||
#if USE_YJIT
|
||||
// Increment the ISEQ's call counter and trigger JIT compilation if not compiled
|
||||
if (body->jit_entry == NULL && rb_yjit_enabled_p) {
|
||||
body->jit_entry_calls++;
|
||||
|
@ -9,9 +9,6 @@ edition = "2021" # Rust 2021 edition to compile with
|
||||
rust-version = "1.58.0" # Minimally supported rust version
|
||||
publish = false # Don't publish to crates.io
|
||||
|
||||
[lib]
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[dependencies]
|
||||
# No required dependencies to simplify build process. TODO: Link to yet to be
|
||||
# written rationale. Optional For development and testing purposes
|
||||
@ -27,27 +24,3 @@ disasm = ["capstone"]
|
||||
# from cfg!(debug_assertions) so that we can see disasm of the code
|
||||
# that would run in the release mode.
|
||||
runtime_checks = []
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 0
|
||||
debug = true
|
||||
debug-assertions = true
|
||||
overflow-checks = true
|
||||
|
||||
[profile.dev_nodebug]
|
||||
inherits = "dev"
|
||||
|
||||
[profile.stats]
|
||||
inherits = "release"
|
||||
|
||||
[profile.release]
|
||||
# NOTE: --enable-yjit builds use `rustc` without going through Cargo. You
|
||||
# might want to update the `rustc` invocation if you change this profile.
|
||||
opt-level = 3
|
||||
# The extra robustness that comes from checking for arithmetic overflow is
|
||||
# worth the performance cost for the compiler.
|
||||
overflow-checks = true
|
||||
# Generate debug info
|
||||
debug = true
|
||||
# Use ThinLTO. Much smaller output for a small amount of build time increase.
|
||||
lto = "thin"
|
||||
|
@ -8,3 +8,5 @@ edition = "2021"
|
||||
[dependencies]
|
||||
bindgen = "0.70.1"
|
||||
env_logger = "0.11.5"
|
||||
|
||||
[workspace]
|
||||
|
57
yjit/yjit.mk
57
yjit/yjit.mk
@ -19,60 +19,21 @@ YJIT_SRC_FILES = $(wildcard \
|
||||
# rebuild at the next build.
|
||||
YJIT_LIB_TOUCH = touch $@
|
||||
|
||||
# Absolute path to match RUST_LIB rules to avoid picking
|
||||
# the "target" dir in the source directory through VPATH.
|
||||
BUILD_YJIT_LIBS = $(TOP_BUILD_DIR)/$(YJIT_LIBS)
|
||||
|
||||
# YJIT_SUPPORT=yes when `configure` gets `--enable-yjit`
|
||||
ifeq ($(YJIT_SUPPORT),yes)
|
||||
$(YJIT_LIBS): $(YJIT_SRC_FILES)
|
||||
yjit-libs: $(BUILD_YJIT_LIBS)
|
||||
$(BUILD_YJIT_LIBS): $(YJIT_SRC_FILES)
|
||||
$(ECHO) 'building Rust YJIT (release mode)'
|
||||
+$(Q) $(RUSTC) $(YJIT_RUSTC_ARGS)
|
||||
$(YJIT_LIB_TOUCH)
|
||||
else ifeq ($(YJIT_SUPPORT),no)
|
||||
$(YJIT_LIBS):
|
||||
$(ECHO) 'Error: Tried to build YJIT without configuring it first. Check `make showconfig`?'
|
||||
@false
|
||||
else ifeq ($(YJIT_SUPPORT),$(filter dev dev_nodebug stats,$(YJIT_SUPPORT)))
|
||||
# NOTE: MACOSX_DEPLOYMENT_TARGET to match `rustc --print deployment-target` to avoid the warning below.
|
||||
# ld: warning: object file (yjit/target/debug/libyjit.a(<libcapstone object>)) was built for
|
||||
# newer macOS version (15.2) than being linked (15.0)
|
||||
# We don't use newer macOS feature as of yet.
|
||||
$(YJIT_LIBS): $(YJIT_SRC_FILES)
|
||||
$(ECHO) 'building Rust YJIT ($(YJIT_SUPPORT) mode)'
|
||||
+$(Q)$(CHDIR) $(top_srcdir)/yjit && \
|
||||
CARGO_TARGET_DIR='$(CARGO_TARGET_DIR)' \
|
||||
CARGO_TERM_PROGRESS_WHEN='never' \
|
||||
MACOSX_DEPLOYMENT_TARGET=11.0 \
|
||||
$(CARGO) $(CARGO_VERBOSE) build $(CARGO_BUILD_ARGS)
|
||||
$(YJIT_LIB_TOUCH)
|
||||
else
|
||||
endif
|
||||
|
||||
yjit-libobj: $(YJIT_LIBOBJ)
|
||||
|
||||
YJIT_LIB_SYMBOLS = $(YJIT_LIBS:.a=).symbols
|
||||
$(YJIT_LIBOBJ): $(YJIT_LIBS)
|
||||
$(ECHO) 'partial linking $(YJIT_LIBS) into $@'
|
||||
ifneq ($(findstring darwin,$(target_os)),)
|
||||
$(Q) $(CC) -nodefaultlibs -r -o $@ -exported_symbols_list $(YJIT_LIB_SYMBOLS) $(YJIT_LIBS)
|
||||
else
|
||||
$(Q) $(LD) -r -o $@ --whole-archive $(YJIT_LIBS)
|
||||
-$(Q) $(OBJCOPY) --wildcard --keep-global-symbol='$(SYMBOL_PREFIX)rb_*' $(@)
|
||||
endif
|
||||
|
||||
# For Darwin only: a list of symbols that we want the glommed Rust static lib to export.
|
||||
# Unfortunately, using wildcard like '_rb_*' with -exported-symbol does not work, at least
|
||||
# not on version 820.1. Assume llvm-nm, so XCode 8.0 (from 2016) or newer.
|
||||
#
|
||||
# The -exported_symbols_list pulls out the right archive members. Symbols not listed
|
||||
# in the list are made private extern, which are in turn made local as we're using `ld -r`.
|
||||
# Note, section about -keep_private_externs in ld's man page hints at this behavior on which
|
||||
# we rely.
|
||||
ifneq ($(findstring darwin,$(target_os)),)
|
||||
$(YJIT_LIB_SYMBOLS): $(YJIT_LIBS)
|
||||
$(Q) $(tooldir)/darwin-ar $(NM) --defined-only --extern-only $(YJIT_LIBS) | \
|
||||
sed -n -e 's/.* //' -e '/^$(SYMBOL_PREFIX)rb_/p' \
|
||||
-e '/^$(SYMBOL_PREFIX)rust_eh_personality/p' \
|
||||
> $@
|
||||
|
||||
$(YJIT_LIBOBJ): $(YJIT_LIB_SYMBOLS)
|
||||
ifneq ($(YJIT_SUPPORT),no)
|
||||
$(RUST_LIB): $(YJIT_SRC_FILES)
|
||||
endif
|
||||
|
||||
# By using YJIT_BENCH_OPTS instead of RUN_OPTS, you can skip passing the options to `make install`
|
||||
@ -94,7 +55,7 @@ RUST_VERSION = +1.58.0
|
||||
.PHONY: yjit-smoke-test
|
||||
yjit-smoke-test:
|
||||
ifneq ($(strip $(CARGO)),)
|
||||
$(CARGO) $(RUST_VERSION) test --all-features -q --manifest-path='$(top_srcdir)/yjit/Cargo.toml'
|
||||
$(CARGO) test --all-features -q --manifest-path='$(top_srcdir)/yjit/Cargo.toml'
|
||||
endif
|
||||
$(MAKE) btest RUN_OPTS='--yjit-call-threshold=1' BTESTS=-j
|
||||
$(MAKE) test-all TESTS='$(top_srcdir)/test/ruby/test_yjit.rb'
|
||||
|
1
zjit.c
1
zjit.c
@ -9,6 +9,7 @@
|
||||
#include "internal/numeric.h"
|
||||
#include "internal/gc.h"
|
||||
#include "internal/vm.h"
|
||||
#include "yjit.h"
|
||||
#include "vm_core.h"
|
||||
#include "vm_callinfo.h"
|
||||
#include "builtin.h"
|
||||
|
@ -1,25 +1,10 @@
|
||||
[package]
|
||||
name = "zjit"
|
||||
version = "0.0.1"
|
||||
edition = "2024" # Rust 2021 edition to compile with
|
||||
edition = "2024"
|
||||
rust-version = "1.85.0" # Minimally supported rust version
|
||||
publish = false # Don't publish to crates.io
|
||||
|
||||
[lib]
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[profile.release]
|
||||
# NOTE: --enable-zjit builds use `rustc` without going through Cargo. You
|
||||
# might want to update the `rustc` invocation if you change this profile.
|
||||
opt-level = 3
|
||||
# The extra robustness that comes from checking for arithmetic overflow is
|
||||
# worth the performance cost for the compiler.
|
||||
overflow-checks = true
|
||||
# Generate debug info
|
||||
debug = true
|
||||
# Use ThinLTO. Much smaller output for a small amount of build time increase.
|
||||
lto = "thin"
|
||||
|
||||
[dependencies]
|
||||
# No required dependencies to simplify build process. TODO: Link to yet to be
|
||||
# written rationale. Optional For development and testing purposes
|
||||
|
@ -8,3 +8,5 @@ edition = "2024"
|
||||
[dependencies]
|
||||
bindgen = "0.71.1"
|
||||
env_logger = "0.11.5"
|
||||
|
||||
[workspace]
|
||||
|
@ -1,7 +1,8 @@
|
||||
fn main() {
|
||||
use std::env;
|
||||
|
||||
if let Ok(ruby_build_dir) = env::var("RUBY_BUILD_DIR") {
|
||||
// option_env! automatically registers a rerun-if-env-changed
|
||||
if let Some(ruby_build_dir) = option_env!("RUBY_BUILD_DIR") {
|
||||
// Link against libminiruby
|
||||
println!("cargo:rustc-link-search=native={ruby_build_dir}");
|
||||
println!("cargo:rustc-link-lib=static:-bundle=miniruby");
|
||||
|
58
zjit/zjit.mk
58
zjit/zjit.mk
@ -19,60 +19,20 @@ ZJIT_SRC_FILES = $(wildcard \
|
||||
# rebuild at the next build.
|
||||
ZJIT_LIB_TOUCH = touch $@
|
||||
|
||||
# Absolute path to match RUST_LIB rules to avoid picking
|
||||
# the "target" dir in the source directory through VPATH.
|
||||
BUILD_ZJIT_LIBS = $(TOP_BUILD_DIR)/$(ZJIT_LIBS)
|
||||
|
||||
# ZJIT_SUPPORT=yes when `configure` gets `--enable-zjit`
|
||||
ifeq ($(ZJIT_SUPPORT),yes)
|
||||
$(ZJIT_LIBS): $(ZJIT_SRC_FILES)
|
||||
$(BUILD_ZJIT_LIBS): $(ZJIT_SRC_FILES)
|
||||
$(ECHO) 'building Rust ZJIT (release mode)'
|
||||
+$(Q) $(RUSTC) $(ZJIT_RUSTC_ARGS)
|
||||
$(ZJIT_LIB_TOUCH)
|
||||
else ifeq ($(ZJIT_SUPPORT),no)
|
||||
$(ZJIT_LIBS):
|
||||
$(ECHO) 'Error: Tried to build ZJIT without configuring it first. Check `make showconfig`?'
|
||||
@false
|
||||
else ifeq ($(ZJIT_SUPPORT),$(filter dev dev_nodebug stats,$(ZJIT_SUPPORT)))
|
||||
# NOTE: MACOSX_DEPLOYMENT_TARGET to match `rustc --print deployment-target` to avoid the warning below.
|
||||
# ld: warning: object file (zjit/target/debug/libzjit.a(<libcapstone object>)) was built for
|
||||
# newer macOS version (15.2) than being linked (15.0)
|
||||
# We don't use newer macOS feature as of yet.
|
||||
$(ZJIT_LIBS): $(ZJIT_SRC_FILES)
|
||||
$(ECHO) 'building Rust ZJIT ($(ZJIT_SUPPORT) mode)'
|
||||
+$(Q)$(CHDIR) $(top_srcdir)/zjit && \
|
||||
CARGO_TARGET_DIR='$(ZJIT_CARGO_TARGET_DIR)' \
|
||||
CARGO_TERM_PROGRESS_WHEN='never' \
|
||||
MACOSX_DEPLOYMENT_TARGET=11.0 \
|
||||
$(CARGO) $(CARGO_VERBOSE) build $(ZJIT_CARGO_BUILD_ARGS)
|
||||
$(ZJIT_LIB_TOUCH)
|
||||
else
|
||||
endif
|
||||
|
||||
zjit-libobj: $(ZJIT_LIBOBJ)
|
||||
|
||||
ZJIT_LIB_SYMBOLS = $(ZJIT_LIBS:.a=).symbols
|
||||
$(ZJIT_LIBOBJ): $(ZJIT_LIBS)
|
||||
$(ECHO) 'partial linking $(ZJIT_LIBS) into $@'
|
||||
ifneq ($(findstring darwin,$(target_os)),)
|
||||
$(Q) $(CC) -nodefaultlibs -r -o $@ -exported_symbols_list $(ZJIT_LIB_SYMBOLS) $(ZJIT_LIBS)
|
||||
else
|
||||
$(Q) $(LD) -r -o $@ --whole-archive $(ZJIT_LIBS)
|
||||
-$(Q) $(OBJCOPY) --wildcard --keep-global-symbol='$(SYMBOL_PREFIX)rb_*' $(@)
|
||||
endif
|
||||
|
||||
# For Darwin only: a list of symbols that we want the glommed Rust static lib to export.
|
||||
# Unfortunately, using wildcard like '_rb_*' with -exported-symbol does not work, at least
|
||||
# not on version 820.1. Assume llvm-nm, so XCode 8.0 (from 2016) or newer.
|
||||
#
|
||||
# The -exported_symbols_list pulls out the right archive members. Symbols not listed
|
||||
# in the list are made private extern, which are in turn made local as we're using `ld -r`.
|
||||
# Note, section about -keep_private_externs in ld's man page hints at this behavior on which
|
||||
# we rely.
|
||||
ifneq ($(findstring darwin,$(target_os)),)
|
||||
$(ZJIT_LIB_SYMBOLS): $(ZJIT_LIBS)
|
||||
$(Q) $(tooldir)/darwin-ar $(NM) --defined-only --extern-only $(ZJIT_LIBS) | \
|
||||
sed -n -e 's/.* //' -e '/^$(SYMBOL_PREFIX)rb_/p' \
|
||||
-e '/^$(SYMBOL_PREFIX)rust_eh_personality/p' \
|
||||
> $@
|
||||
|
||||
$(ZJIT_LIBOBJ): $(ZJIT_LIB_SYMBOLS)
|
||||
ifneq ($(ZJIT_SUPPORT),no)
|
||||
$(RUST_LIB): $(ZJIT_SRC_FILES)
|
||||
endif
|
||||
|
||||
# By using ZJIT_BENCH_OPTS instead of RUN_OPTS, you can skip passing the options to `make install`
|
||||
@ -113,7 +73,7 @@ zjit-bindgen: zjit.$(OBJEXT)
|
||||
zjit-test: libminiruby.a
|
||||
RUBY_BUILD_DIR='$(TOP_BUILD_DIR)' \
|
||||
RUBY_LD_FLAGS='$(LDFLAGS) $(XLDFLAGS) $(MAINLIBS)' \
|
||||
CARGO_TARGET_DIR='$(ZJIT_CARGO_TARGET_DIR)' \
|
||||
CARGO_TARGET_DIR='$(CARGO_TARGET_DIR)' \
|
||||
$(CARGO) nextest run --manifest-path '$(top_srcdir)/zjit/Cargo.toml' $(ZJIT_TESTS)
|
||||
|
||||
# Run a ZJIT test written with Rust #[test] under LLDB
|
||||
@ -126,7 +86,7 @@ zjit-test-lldb: libminiruby.a
|
||||
fi; \
|
||||
exe_path=`RUBY_BUILD_DIR='$(TOP_BUILD_DIR)' \
|
||||
RUBY_LD_FLAGS='$(LDFLAGS) $(XLDFLAGS) $(MAINLIBS)' \
|
||||
CARGO_TARGET_DIR='$(ZJIT_CARGO_TARGET_DIR)' \
|
||||
CARGO_TARGET_DIR='$(CARGO_TARGET_DIR)' \
|
||||
$(CARGO) nextest list --manifest-path '$(top_srcdir)/zjit/Cargo.toml' --message-format json --list-type=binaries-only | \
|
||||
$(BASERUBY) -rjson -e 'puts JSON.load(STDIN.read).dig("rust-binaries", "zjit", "binary-path")'`; \
|
||||
exec lldb $$exe_path -- --test-threads=1 $(ZJIT_TESTS)
|
||||
|
Loading…
x
Reference in New Issue
Block a user