Skip to content

Commit

Permalink
test
Browse files Browse the repository at this point in the history
  • Loading branch information
YO4 committed Feb 12, 2025
1 parent dd86371 commit 684d4aa
Show file tree
Hide file tree
Showing 21 changed files with 350 additions and 71 deletions.
173 changes: 173 additions & 0 deletions .github/workflows/rjit_mingw.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
name: RJIT MinGW
on:
push:
paths-ignore:
- 'doc/**'
- '**/man/*'
- '**.md'
- '**.rdoc'
- '**/.document'
- '.*.yml'
pull_request:
paths-ignore:
- 'doc/**'
- '**/man/*'
- '**.md'
- '**.rdoc'
- '**/.document'
- '.*.yml'
merge_group:

concurrency:
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}

permissions:
contents: read

# Notes:
# Actions console encoding causes issues, see test-all & test-spec steps
#
jobs:
make:
runs-on: windows-2022

name: ${{ github.workflow }} (${{ matrix.msystem }})

env:
MSYSTEM: ${{ matrix.msystem }}
MSYS2_ARCH: x86_64
CHOST: 'x86_64-w64-mingw32'
CFLAGS: '-march=x86-64 -mtune=generic -O3 -pipe'
CXXFLAGS: '-march=x86-64 -mtune=generic -O3 -pipe'
CPPFLAGS: '-D_FORTIFY_SOURCE=2 -D__USE_MINGW_ANSI_STDIO=1 -DFD_SETSIZE=2048'
LDFLAGS: '-pipe'
GITPULLOPTIONS: --no-tags origin ${{ github.ref }}

strategy:
matrix:
run_opts: ['--rjit-call-threshold=1']
include:
# To mitigate flakiness of MinGW CI, we test only one runtime that newer MSYS2 uses.
# Ruby 3.2 is the first Windows Ruby to use OpenSSL 3.x
- msystem: 'UCRT64'
baseruby: '3.2'
test_task: 'check'
test-all-opts: '--name=!/TestObjSpace#test_reachable_objects_during_iteration/'
fail-fast: false

if: >-
${{!(false
|| contains(github.event.head_commit.message, '[DOC]')
|| contains(github.event.head_commit.message, 'Document')
|| contains(github.event.pull_request.title, '[DOC]')
|| contains(github.event.pull_request.title, 'Document')
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
|| (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
)}}
steps:
- name: Set up Ruby & MSYS2
uses: ruby/setup-ruby@a6e6f86333f0a2523ece813039b8b4be04560854 # v1.190.0
with:
ruby-version: ${{ matrix.baseruby }}

- name: Misc system & package info
working-directory:
run: |
# show where
result=true
for e in gcc.exe ragel.exe make.exe libcrypto-3-x64.dll libssl-3-x64.dll; do
echo ::group::$'\033[93m'$e$'\033[m'
where $e || result=false
echo ::endgroup::
done
# show version
for e in gcc ragel make "openssl version"; do
case "$e" in *" "*) ;; *) e="$e --version";; esac
echo ::group::$'\033[93m'$e$'\033[m'
$e || result=false
echo ::endgroup::
done
# show packages
echo ::group::$'\033[93m'Packages$'\033[m'
pacman -Qs mingw-w64-ucrt-x86_64-* | sed -n "s,local/mingw-w64-ucrt-x86_64-,,p"
echo ::endgroup::
$result
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
with:
sparse-checkout-cone-mode: false
sparse-checkout: /.github

- uses: ./.github/actions/setup/directories
with:
srcdir: src
builddir: build
makeup: true
# Set fetch-depth: 10 so that Launchable can receive commits information.
fetch-depth: 10

- name: configure
run: >
../src/configure --disable-install-doc --prefix=/. --enable-rjit
--build=$CHOST --host=$CHOST --target=$CHOST
- name: make all
timeout-minutes: 30
run: make

- name: make install
run: make DESTDIR=../install install-nodoc

- name: Set up Launchable
uses: ./.github/actions/launchable/setup
with:
os: windows-2022
launchable-token: ${{ secrets.LAUNCHABLE_TOKEN }}
builddir: build
srcdir: src
test-tasks: '["test", "test-all", "test-spec"]'
continue-on-error: true

- name: test
timeout-minutes: 30
run: make test
shell: cmd
env:
GNUMAKEFLAGS: ''
RUBY_TESTOPTS: '-v --tty=no --rjit'
if: ${{ matrix.test_task == 'check' || matrix.test_task == 'test' }}

- name: test-all
timeout-minutes: 45
shell: cmd
run: |
make ${{ StartsWith(matrix.test_task, 'test/') && matrix.test_task || 'test-all' }}
env:
RUBY_TESTOPTS: >-
--retry --job-status=normal --show-skip --timeout-scale=1.5 --rjit
${{ matrix.test-all-opts }}
${{ env.TESTS }}
BUNDLER_VERSION:
if: ${{ matrix.test_task == 'check' || matrix.test_task == 'test-all' || StartsWith(matrix.test_task, 'test/') }}

- name: test-spec
timeout-minutes: 10
run: |
make ${{ StartsWith(matrix.test_task, 'spec/') && matrix.test_task || 'test-spec' }}
shell: cmd
env:
RUBY_TESTOPTS: '--rjit'
if: ${{ matrix.test_task == 'check' || matrix.test_task == 'test-spec' || StartsWith(matrix.test_task, 'spec/') }}

- uses: ./src/.github/actions/slack
with:
label: ${{ matrix.msystem }} / ${{ matrix.test_task }}
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
if: ${{ failure() }}

defaults:
run:
working-directory: build
shell: sh
8 changes: 0 additions & 8 deletions gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,11 +200,7 @@ rb_gc_worker_thread_set_vm_context(struct rb_gc_vm_context *context)

GC_ASSERT(rb_current_execution_context(false) == NULL);

#ifdef RB_THREAD_LOCAL_SPECIFIER
rb_current_ec_set(context->ec);
#else
native_tls_set(ruby_current_ec_key, context->ec);
#endif
}

void
Expand All @@ -214,11 +210,7 @@ rb_gc_worker_thread_unset_vm_context(struct rb_gc_vm_context *context)

GC_ASSERT(rb_current_execution_context(true) == context->ec);

#ifdef RB_THREAD_LOCAL_SPECIFIER
rb_current_ec_set(NULL);
#else
native_tls_set(ruby_current_ec_key, NULL);
#endif
}
#endif

Expand Down
1 change: 1 addition & 0 deletions include/ruby/win32.h
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ extern int rb_w32_ulink(const char *, const char *);
extern ssize_t rb_w32_ureadlink(const char *, char *, size_t);
extern int rb_w32_usymlink(const char *src, const char *link);
extern int gettimeofday(struct timeval *, struct timezone *);
#define _GETTIMEOFDAY_DEFINED
extern int clock_gettime(clockid_t, struct timespec *);
extern int clock_getres(clockid_t, struct timespec *);
extern rb_pid_t waitpid(rb_pid_t, int *, int);
Expand Down
11 changes: 10 additions & 1 deletion internal/vm.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,18 @@ void rb_check_stack_overflow(void);
VALUE rb_block_call2(VALUE obj, ID mid, int argc, const VALUE *argv, rb_block_call_func_t bl_proc, VALUE data2, long flags);
struct vm_ifunc *rb_current_ifunc(void);

#if USE_YJIT
#if USE_YJIT | USE_RJIT
/* vm_exec.c */
#ifdef RB_THREAD_LOCAL_SPECIFIER
extern RB_THREAD_LOCAL_SPECIFIER uint64_t rb_vm_insns_count;
#define rb_vm_insns_count_get() rb_vm_insns_count
#define rb_vm_insns_count_set(count) rb_vm_insns_count = (count)
#else
#define rb_vm_insns_count_get() \
(uint64_t)native_tls_get(rb_vm_insns_count_key)
#define rb_vm_insns_count_set(count) \
native_tls_set(rb_vm_insns_count_key, (void*)(count))
#endif
#endif

extern bool rb_free_at_exit;
Expand Down
22 changes: 17 additions & 5 deletions lib/ruby_vm/rjit/assembler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,17 @@ class DwordPtr < Data.define(:reg, :disp); end
# 64-bit memory access
QwordPtr = Array

# SystemV x64 calling convention
C_ARGS = [:rdi, :rsi, :rdx, :rcx, :r8, :r9]
# Win64 stack allocation size
RSP_ALLOC_SIZE = 48 # 6 args shadow store
SHADOW_STORE_OFFSET = RSP_ALLOC_SIZE + 24 + 8

# Win64 x86_64 calling convention
C_ARGS = [:rcx, :rdx, :r8, :r9, [:rsp, 32], [:rsp, 40]]
C_ARGS32 = [:ecx, :edx, :r8d, :r9d] # for compile_branch_stub()
C_RET = :rax

MOV_SCRATCH = :r10

# https://cdrdv2.intel.com/v1/dl/getContent/671110
# Mostly an x86_64 assembler, but this also has some stuff that is useful for any architecture.
class Assembler
Expand Down Expand Up @@ -686,6 +693,9 @@ def mov(dst, src)
mod_rm: ModRM[mod: Mod01, reg: src_reg, rm: dst_reg],
disp: dst_disp,
)
else
mov(MOV_SCRATCH, src)
mov(dst, MOV_SCRATCH)
end
in QwordPtr[R64 => dst_reg, IMM32 => dst_disp]
case src
Expand Down Expand Up @@ -964,12 +974,12 @@ def insn(prefix: 0, opcode:, rd: nil, mod_rm: nil, disp: nil, imm: nil)
end
@bytes.push(*Array(opcode))
if mod_rm
mod_rm_byte = encode_mod_rm(
mod_rm_sib = encode_mod_rm(
mod: mod_rm.mod,
reg: mod_rm.reg.is_a?(Symbol) ? reg_code(mod_rm.reg) : mod_rm.reg,
rm: mod_rm.rm.is_a?(Symbol) ? reg_code(mod_rm.rm) : mod_rm.rm,
)
@bytes.push(mod_rm_byte)
@bytes.push(*mod_rm_sib)
end
if disp
@bytes.push(*Array(disp))
Expand Down Expand Up @@ -1006,7 +1016,9 @@ def encode_mod_rm(mod:, reg: 0, rm: 0)
if rm > 0b111
raise ArgumentError, "too large R/M: #{rm}"
end
(mod << 6) + (reg << 3) + rm
mod_rm_byte = (mod << 6) + (reg << 3) + rm
# put SIB when ModR/M is [rsp + disp] or [r12 + disp]
(rm == 0b100 && mod != 0b11) ? [mod_rm_byte, 0x24] : mod_rm_byte
end

# ib: 1 byte
Expand Down
1 change: 1 addition & 0 deletions lib/ruby_vm/rjit/code_block.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def initialize(mem_block:, mem_size:, outlined: false)

# @param asm [RubyVM::RJIT::Assembler]
def write(asm)
#pp [asm.comments, caller(1)[0,3]]
return 0 if @write_pos + asm.size >= @mem_size

start_addr = write_addr
Expand Down
10 changes: 7 additions & 3 deletions lib/ruby_vm/rjit/compiler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def self.decode_insn(encoded)
def initialize
mem_size = C.rjit_opts.exec_mem_size * 1024 * 1024
mem_block = C.mmap(mem_size)
#pp [:mem_block, mem_block.to_s(16)]
@cb = CodeBlock.new(mem_block: mem_block, mem_size: mem_size / 2)
@ocb = CodeBlock.new(mem_block: mem_block + mem_size / 2, mem_size: mem_size / 2, outlined: true)
@exit_compiler = ExitCompiler.new
Expand Down Expand Up @@ -242,9 +243,12 @@ def compile_prologue(asm, iseq, pc)
asm.push(EC)
asm.push(SP)

# Allocate shadow store for calling Win64 ABI functions
asm.sub(:rsp, RSP_ALLOC_SIZE)

# Move arguments EC and CFP to dedicated registers
asm.mov(EC, :rdi)
asm.mov(CFP, :rsi)
asm.mov(EC, C_ARGS[0])
asm.mov(CFP, C_ARGS[1])

# Load sp to a dedicated register
asm.mov(SP, [CFP, C.rb_control_frame_t.offsetof(:sp)]) # rbx = cfp->sp
Expand Down Expand Up @@ -510,7 +514,7 @@ def assert(cond)

def supported_platform?
return @supported_platform if defined?(@supported_platform)
@supported_platform = RUBY_PLATFORM.match?(/x86_64/).tap do |supported|
@supported_platform = RUBY_PLATFORM.match?(/x86_64|x64-/).tap do |supported|
warn "warning: RJIT does not support #{RUBY_PLATFORM} yet" unless supported
end
end
Expand Down
18 changes: 15 additions & 3 deletions lib/ruby_vm/rjit/exit_compiler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ def compile_entry_exit(pc, ctx, asm, cause:)
# Increment per-insn exit counter
count_insn_exit(pc, asm)

# Dellocate shadow store for calling Win64 ABI functions
asm.add(:rsp, RSP_ALLOC_SIZE)

# Restore callee-saved registers
asm.comment("#{cause}: entry exit")
asm.pop(SP)
Expand All @@ -27,6 +30,9 @@ def compile_entry_exit(pc, ctx, asm, cause:)
def compile_leave_exit(asm)
asm.comment('default cfp->jit_return')

# Dellocate shadow store for calling Win64 ABI functions
asm.add(:rsp, RSP_ALLOC_SIZE)

# Restore callee-saved registers
asm.pop(SP)
asm.pop(EC)
Expand All @@ -49,6 +55,9 @@ def compile_full_cfunc_return(asm)

# TODO: count the exit

# Dellocate shadow store for calling Win64 ABI functions
asm.add(:rsp, RSP_ALLOC_SIZE)

# Restore callee-saved registers
asm.pop(SP)
asm.pop(EC)
Expand All @@ -68,6 +77,9 @@ def compile_side_exit(pc, ctx, asm)
# Increment per-insn exit counter
count_insn_exit(pc, asm)

# Dellocate shadow store for calling Win64 ABI functions
asm.add(:rsp, RSP_ALLOC_SIZE)

# Restore callee-saved registers
asm.comment("exit to interpreter on #{pc_to_insn(pc).name}")
asm.pop(SP)
Expand Down Expand Up @@ -100,9 +112,9 @@ def compile_branch_stub(ctx, asm, branch_stub, target0_p)
if C.rjit_opts.dump_disasm && C.imemo_type_p(iseq, C.imemo_iseq) # Guard against ISEQ GC at random moments
asm.comment("branch stub hit: #{iseq.body.location.label}@#{C.rb_iseq_path(iseq)}:#{iseq_lineno(iseq, target0_p ? branch_stub.target0.pc : branch_stub.target1.pc)}")
end
asm.mov(:rdi, to_value(branch_stub))
asm.mov(:esi, ctx.sp_offset)
asm.mov(:edx, target0_p ? 1 : 0)
asm.mov(C_ARGS[0], to_value(branch_stub))
asm.mov(C_ARGS32[1], ctx.sp_offset)
asm.mov(C_ARGS32[2], target0_p ? 1 : 0)
asm.call(C.rb_rjit_branch_stub_hit)

# Jump to the address returned by rb_rjit_branch_stub_hit
Expand Down
Loading

0 comments on commit 684d4aa

Please sign in to comment.