Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 91 additions & 89 deletions .github/workflows/compilers.yml

Large diffs are not rendered by default.

30 changes: 18 additions & 12 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -1746,18 +1746,24 @@ AS_IF([test "$GCC" = yes], [
[rb_cv_gcc_atomic_builtins=no])])
AS_IF([test "$rb_cv_gcc_atomic_builtins" = yes], [
AC_DEFINE(HAVE_GCC_ATOMIC_BUILTINS)
AC_CACHE_CHECK([for 64bit __atomic builtins], [rb_cv_gcc_atomic_builtins_64], [
AC_LINK_IFELSE([AC_LANG_PROGRAM([[@%:@include <stdint.h>
uint64_t atomic_var;]],
[[
__atomic_load_n(&atomic_var, __ATOMIC_RELAXED);
__atomic_store_n(&atomic_var, 0, __ATOMIC_RELAXED);
]])],
[rb_cv_gcc_atomic_builtins_64=yes],
[rb_cv_gcc_atomic_builtins_64=no])])
AS_IF([test "$rb_cv_gcc_atomic_builtins_64" = yes], [
AC_DEFINE(HAVE_GCC_ATOMIC_BUILTINS_64)
])
for lib in "" atomic; do
AS_IF([test "$lib" != ""], [
AC_CHECK_LIB([atomic], [__atomic_fetch_add_8])
])
AC_CACHE_CHECK([for 64bit __atomic builtins], [rb_cv_gcc_atomic_builtins_64], [
AC_LINK_IFELSE([AC_LANG_PROGRAM([[@%:@include <stdint.h>
uint64_t atomic_var;]],
[[
__atomic_load_n(&atomic_var, __ATOMIC_RELAXED);
__atomic_store_n(&atomic_var, 0, __ATOMIC_RELAXED);
]])],
[rb_cv_gcc_atomic_builtins_64=yes],
[rb_cv_gcc_atomic_builtins_64=no])])
AS_IF([test "$rb_cv_gcc_atomic_builtins_64" = yes], [
AC_DEFINE(HAVE_GCC_ATOMIC_BUILTINS_64)
break
])
done
])

AC_CACHE_CHECK([for __sync builtins], [rb_cv_gcc_sync_builtins], [
Expand Down
11 changes: 9 additions & 2 deletions gc/default/default.c
Original file line number Diff line number Diff line change
Expand Up @@ -9321,8 +9321,15 @@ gc_malloc_allocations(VALUE self)
}
#endif

void rb_gc_impl_before_fork(void *objspace_ptr) { /* no-op */ }
void rb_gc_impl_after_fork(void *objspace_ptr, rb_pid_t pid) {
void
rb_gc_impl_before_fork(void *objspace_ptr)
{
/* no-op */
}

void
rb_gc_impl_after_fork(void *objspace_ptr, rb_pid_t pid)
{
if (pid == 0) { /* child process */
rb_gc_ractor_newobj_cache_foreach(gc_ractor_newobj_cache_clear, NULL);
}
Expand Down
2 changes: 1 addition & 1 deletion lib/uri/generic.rb
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ def userinfo=(userinfo)
#
# uri = URI.parse("http://john:S3nsit1ve@my.example.com")
# uri.user = "sam"
# uri.to_s #=> "http://sam:V3ry_S3nsit1ve@my.example.com"
# uri.to_s #=> "http://sam@my.example.com"
#
def user=(user)
check_user(user)
Expand Down
9 changes: 6 additions & 3 deletions ruby_atomic.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
#define INTERNAL_ATOMIC_H

#include "ruby/atomic.h"
#ifdef HAVE_STDATOMIC_H
# include <stdatomic.h>
#endif

#define RUBY_ATOMIC_VALUE_LOAD(x) rbimpl_atomic_value_load(&(x), RBIMPL_ATOMIC_SEQ_CST)

Expand Down Expand Up @@ -76,11 +79,11 @@ rbimpl_atomic_u64_fetch_add(volatile rbimpl_atomic_uint64_t *ptr, uint64_t val)
return InterlockedExchangeAdd64((volatile LONG64 *)ptr, val);
#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
return atomic_add_64_nv(ptr, val) - val;
#elif defined(HAVE_STDATOMIC_H)
return atomic_fetch_add_explicit((_Atomic uint64_t *)ptr, val, memory_order_seq_cst);
#else
// TODO: stdatomic

// Fallback using mutex for platforms without 64-bit atomics
static rb_native_mutex_t lock = RB_NATIVE_MUTEX_INITIALIZER;
static rb_nativethread_mutex_t lock = RB_NATIVETHREAD_LOCK_INIT;
rb_native_mutex_lock(&lock);
uint64_t old = *ptr;
*ptr = old + val;
Expand Down
21 changes: 13 additions & 8 deletions zjit/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5230,19 +5230,24 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
}
YARVINSN_getlocal_WC_0 => {
let ep_offset = get_arg(pc, 0).as_u32();
if ep_escaped || has_blockiseq { // TODO: figure out how to drop has_blockiseq here
if !local_inval {
// The FrameState is the source of truth for locals until invalidated.
// In case of JIT-to-JIT send locals might never end up in EP memory.
let val = state.getlocal(ep_offset);
state.stack_push(val);
} else if ep_escaped || has_blockiseq { // TODO: figure out how to drop has_blockiseq here
// Read the local using EP
let val = fun.push_insn(block, Insn::GetLocal { ep_offset, level: 0, use_sp: false, rest_param: false });
state.setlocal(ep_offset, val); // remember the result to spill on side-exits
state.stack_push(val);
} else {
if local_inval {
// If there has been any non-leaf call since JIT entry or the last patch point,
// add a patch point to make sure locals have not been escaped.
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state.without_locals() }); // skip spilling locals
fun.push_insn(block, Insn::PatchPoint { invariant: Invariant::NoEPEscape(iseq), state: exit_id });
local_inval = false;
}
assert!(local_inval); // if check above
// There has been some non-leaf call since JIT entry or the last patch point,
// so add a patch point to make sure locals have not been escaped.
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state.without_locals() }); // skip spilling locals
fun.push_insn(block, Insn::PatchPoint { invariant: Invariant::NoEPEscape(iseq), state: exit_id });
local_inval = false;

// Read the local from FrameState
let val = state.getlocal(ep_offset);
state.stack_push(val);
Expand Down
62 changes: 57 additions & 5 deletions zjit/src/hir/opt_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -780,14 +780,13 @@ mod hir_opt_tests {
EntryPoint JIT(0)
Jump bb2(v5, v6)
bb2(v8:BasicObject, v9:BasicObject):
v13:BasicObject = GetLocal l0, EP@3
PatchPoint MethodRedefined(C@0x1000, fun_new_map@0x1008, cme:0x1010)
PatchPoint NoSingletonClass(C@0x1000)
v24:ArraySubclass[class_exact:C] = GuardType v13, ArraySubclass[class_exact:C]
v25:BasicObject = CCallWithFrame C#fun_new_map@0x1038, v24, block=0x1040
v16:BasicObject = GetLocal l0, EP@3
v23:ArraySubclass[class_exact:C] = GuardType v9, ArraySubclass[class_exact:C]
v24:BasicObject = CCallWithFrame C#fun_new_map@0x1038, v23, block=0x1040
v15:BasicObject = GetLocal l0, EP@3
CheckInterrupts
Return v25
Return v24
");
}

Expand Down Expand Up @@ -8425,4 +8424,57 @@ mod hir_opt_tests {
Return v32
");
}

#[test]
fn no_load_from_ep_right_after_entrypoint() {
let formatted = eval("
def read_nil_local(a, _b, _c)
formatted ||= a
@formatted = formatted
-> { formatted } # the environment escapes
end

def call
puts [], [], [], [] # fill VM stack with junk
read_nil_local(true, 1, 1) # expected direct send
end

call # profile
call # compile
@formatted
");
assert_eq!(Qtrue, formatted, "{}", formatted.obj_info());
assert_snapshot!(hir_string("read_nil_local"), @r"
fn read_nil_local@<compiled>:3:
bb0():
EntryPoint interpreter
v1:BasicObject = LoadSelf
v2:BasicObject = GetLocal l0, SP@7
v3:BasicObject = GetLocal l0, SP@6
v4:BasicObject = GetLocal l0, SP@5
v5:NilClass = Const Value(nil)
Jump bb2(v1, v2, v3, v4, v5)
bb1(v8:BasicObject, v9:BasicObject, v10:BasicObject, v11:BasicObject):
EntryPoint JIT(0)
v12:NilClass = Const Value(nil)
Jump bb2(v8, v9, v10, v11, v12)
bb2(v14:BasicObject, v15:BasicObject, v16:BasicObject, v17:BasicObject, v18:NilClass):
CheckInterrupts
v27:BasicObject = GetLocal l0, EP@6
SetLocal l0, EP@3, v27
v39:BasicObject = GetLocal l0, EP@3
PatchPoint SingleRactorMode
SetIvar v14, :@formatted, v39
v45:Class[VMFrozenCore] = Const Value(VALUE(0x1000))
PatchPoint MethodRedefined(Class@0x1008, lambda@0x1010, cme:0x1018)
PatchPoint NoSingletonClass(Class@0x1008)
v59:BasicObject = CCallWithFrame RubyVM::FrozenCore.lambda@0x1040, v45, block=0x1048
v48:BasicObject = GetLocal l0, EP@6
v49:BasicObject = GetLocal l0, EP@5
v50:BasicObject = GetLocal l0, EP@4
v51:BasicObject = GetLocal l0, EP@3
CheckInterrupts
Return v59
");
}
}
7 changes: 3 additions & 4 deletions zjit/src/hir/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1500,11 +1500,10 @@ pub mod hir_build_tests {
EntryPoint JIT(0)
Jump bb2(v5, v6)
bb2(v8:BasicObject, v9:BasicObject):
v13:BasicObject = GetLocal l0, EP@3
v15:BasicObject = Send v13, 0x1000, :each
v16:BasicObject = GetLocal l0, EP@3
v14:BasicObject = Send v9, 0x1000, :each
v15:BasicObject = GetLocal l0, EP@3
CheckInterrupts
Return v15
Return v14
");
}

Expand Down