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
10 changes: 5 additions & 5 deletions .github/workflows/compilers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,11 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false }
- { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
# -Wno-strict-prototypes is necessary with current clang-15 since
# older autoconf generate functions without prototype and -pedantic
# now implies strict-prototypes. Disabling the error but leaving the
# warning generates a lot of noise from use of ANYARGS in
# rb_define_method() and friends.
# -Wno-strict-prototypes is necessary with clang-15 or newer, since
# older autoconf prior to 2.72 generate functions without prototype
# and -pedantic now implies strict-prototypes. Disabling the error
# but leaving the warning generates a lot of noise from use of
# ANYARGS in rb_define_method() and friends.
# See: https://github.com/llvm/llvm-project/commit/11da1b53d8cd3507959022cd790d5a7ad4573d94
- { uses: './.github/actions/compilers', name: 'C99', with: { CFLAGS: '-std=c99 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' }, timeout-minutes: 8 }
- { uses: './.github/actions/compilers', name: 'C11', with: { CFLAGS: '-std=c11 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' }, timeout-minutes: 8 }
Expand Down
4 changes: 4 additions & 0 deletions compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -15227,6 +15227,10 @@ rb_iseq_dup_with_independent_caches(const rb_iseq_t *src_root)
RB_OBJ_WRITE(copy, &cb->parent_iseq, sb->parent_iseq);
result = copy;
}

/* Shared across Ractors through the Proc#refined memo; the duplicated
* subtree is self-contained, so mark each copy shareable. */
RB_OBJ_SET_SHAREABLE((VALUE)copy);
}

if (ISEQ_PC2BRANCHINDEX(src_root) != Qnil) {
Expand Down
15 changes: 13 additions & 2 deletions ext/json/lib/json.rb
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,11 @@
# ====== Input Options
#
# Option +max_nesting+ (\Integer) specifies the maximum nesting depth allowed;
# defaults to +100+; specify +false+ to disable depth checking.
# defaults to +100+;
# You can set it to +false+ to disable depth checking entirely, but that is dangerous
# when parsing untrusted input.
#
# With the default, +false+:
# With the default, +100+:
# source = '[0, [1, [2, [3]]]]'
# ruby = JSON.parse(source)
# ruby # => [0, [1, [2, [3]]]]
Expand Down Expand Up @@ -384,6 +386,15 @@
# # Raises JSON::NestingError (nesting of 2 is too deep):
# JSON.generate(obj, max_nesting: 2)
#
# With +false+:
# obj = []
# obj[0] = obj
# # Raises SystemStackError: stack level too deep
# JSON.generate(obj, max_nesting: false)
#
# Setting +max_nesting+ to +false+ can lead to a stackoverflow and may leave the program
# in an unrecoverable state. It is discouraged.
#
# ====== Escaping Options
#
# Options +script_safe+ (boolean) specifies wether <tt>'\u2028'</tt>, <tt>'\u2029'</tt>
Expand Down
3 changes: 3 additions & 0 deletions proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,9 @@ refinement_memo_store(const rb_iseq_t *src_iseq, const rb_cref_t *base_cref,
rb_ary_push(memo, mods[i]);
}
OBJ_FREEZE(memo);
/* Every element is shareable, so mark the memo array shareable too for
* reuse from any Ractor. */
RB_OBJ_SET_SHAREABLE(memo);

/* create the map outside the lock; losing the race just discards it */
VALUE new_map = 0;
Expand Down
2 changes: 1 addition & 1 deletion ractor_sync.c
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,7 @@ static size_t
ractor_sync_memsize(const rb_ractor_t *r)
{
if (r->sync.ports) {
return st_table_size(r->sync.ports);
return st_memsize(r->sync.ports);
}
else {
return 0;
Expand Down
2 changes: 1 addition & 1 deletion test/mmtk/test_oom.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
module MMTk
class TestOOM < TestCase
def test_oom
assert_in_out_err([{ "MMTK_HEAP_MAX" => "64MiB" }], <<~RUBY, [], /failed to allocate memory/)
assert_in_out_err([{ "MMTK_HEAP_MAX" => "4MiB" }], <<~RUBY, [], /failed to allocate memory/)
10_000_000.times.map do
Object.new
end
Expand Down
5 changes: 3 additions & 2 deletions tool/sync_default_gems.rb
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,9 @@ def lib((upstream, branch), gemspec_in_subdir: false)
"ext/json/extconf.rb",
]),
mmtk: repo(["ruby/mmtk", "main"], [
["gc/mmtk", "gc/mmtk",
"test/.excludes-mmtk", "test/mmtk"],
["gc/mmtk", "gc/mmtk"],
["test/.excludes-mmtk", "test/.excludes-mmtk"],
["test/mmtk", "test/mmtk"],
]),
open3: lib("ruby/open3", gemspec_in_subdir: true).tap {
it.exclude << "lib/open3/jruby_windows.rb"
Expand Down
52 changes: 32 additions & 20 deletions zjit/src/backend/lir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ use crate::cast::IntoUsize;
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, PartialOrd, Ord)]
pub struct BlockId(pub usize);

type BlockSet = BitSet<BlockId>;

/// Underlying integer width of a virtual-register id. Narrow to keep `Opnd`/`Mem` small.
pub type VRegIdBase = u32;
/// Width of a stack-slot index inside `MemBase`. Separate id space from `VRegId`.
Expand Down Expand Up @@ -188,23 +190,37 @@ impl BasicBlock {
}
}

pub fn successors(&self) -> impl DoubleEndedIterator<Item = BlockId> + '_ {
// Stub blocks (from new_block_without_id) have no real CFG structure.
if self.rpo_index == DUMMY_RPO_INDEX {
return None.into_iter().chain(None.into_iter());
}
assert!(self.insns.last().unwrap().is_terminator());
let extract_target = |insn: &Insn| -> Option<BlockId> {
if let Some(Target::Block(edge)) = insn.target() {
Some(edge.target)
} else {
None
}
};

let (succ1, succ2) = match self.insns.as_slice() {
[] => panic!("empty block"),
[.., second_last, last] => {
(extract_target(second_last), extract_target(last))
},
[.., last] => {
(extract_target(last), None)
}
};
succ1.into_iter().chain(succ2.into_iter())
}

/// Sort key for scheduling blocks in code layout order
pub fn sort_key(&self) -> (usize, usize) {
(self.rpo_index, self.id.0)
}

pub fn successors(&self) -> Vec<BlockId> {
let EdgePair(edge1, edge2) = self.edges();
let mut succs = Vec::new();
if let Some(edge) = edge1 {
succs.push(edge.target);
}
if let Some(edge) = edge2 {
succs.push(edge.target);
}
succs
}

/// Get the output VRegs for this block.
/// These are VRegs referenced by operands passed to successor blocks via block edges.
/// This function is used for live range calculations and should _not_
Expand Down Expand Up @@ -3058,7 +3074,7 @@ impl Assembler
VisitSelf,
}
let mut result = vec![];
let mut seen = HashSet::with_capacity(self.basic_blocks.len());
let mut seen = BlockSet::with_capacity(self.basic_blocks.len());
let mut stack: Vec<_> = starts.iter().map(|&start| (start, Action::VisitEdges)).collect();
while let Some((block, action)) = stack.pop() {
if action == Action::VisitSelf {
Expand All @@ -3067,14 +3083,10 @@ impl Assembler
}
if !seen.insert(block) { continue; }
stack.push((block, Action::VisitSelf));
let EdgePair(edge1, edge2) = self.basic_blocks[block.0].edges();
// Push edge2 before edge1 so that edge1 is popped first from the
// Push block2 before block1 so that block1 is popped first from the
// LIFO stack, matching the visit order of a recursive DFS.
if let Some(edge) = edge2 {
stack.push((edge.target, Action::VisitEdges));
}
if let Some(edge) = edge1 {
stack.push((edge.target, Action::VisitEdges));
for block in self.basic_blocks[block.0].successors().rev() {
stack.push((block, Action::VisitEdges));
}
}
result
Expand Down
14 changes: 14 additions & 0 deletions zjit/src/codegen_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,20 @@ fn test_yield_inline_invocation_with_args() {
assert_snapshot!(assert_compiles("test"), @"7");
}

#[test]
fn test_yield_with_too_many_args_for_lir() {
// `self` + six yield args don't fit in C argument registers, so the direct
// block invocation must be rejected instead of emitting an uncompilable CCall.
set_call_threshold(2);
eval("
def foo = yield(1, 2, 3, 4, 5, 6)
def test = foo { |a, b, c, d, e, f| a + b + c + d + e + f }
test
test
");
assert_snapshot!(assert_compiles("test"), @"21");
}

#[test]
fn test_yield_inline_invocation_live_stack_below_args() {
// A live value sits on the stack below the yield args; the no-receiver-slot SP math
Expand Down
Loading