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
7 changes: 7 additions & 0 deletions bootstraptest/test_method.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1427,3 +1427,10 @@ def test(*, kw: false)
test
RUBY

assert_equal '[1, 2, 3]', %q{
def target(*args) = args
def x = [1]
def forwarder(...) = target(*x, 2, ...)
forwarder(3).inspect
}, '[Bug #21832] post-splat args before forwarding'
29 changes: 25 additions & 4 deletions gc/mmtk/mmtk.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ RB_THREAD_LOCAL_SPECIFIER VALUE marking_parent_object;

#include <pthread.h>

static inline VALUE rb_mmtk_call_object_closure(VALUE obj, bool pin);

static void
rb_mmtk_init_gc_worker_thread(MMTk_VMWorkerThread gc_thread_tls)
{
Expand Down Expand Up @@ -361,15 +363,22 @@ make_final_job(struct objspace *objspace, VALUE obj, VALUE table)
}

static int
rb_mmtk_update_finalizer_table_i(st_data_t key, st_data_t value, st_data_t data)
rb_mmtk_update_finalizer_table_i(st_data_t key, st_data_t value, st_data_t data, int error)
{
RUBY_ASSERT(RB_FL_TEST(key, RUBY_FL_FINALIZE));
RUBY_ASSERT(mmtk_is_reachable((MMTk_ObjectReference)value));
RUBY_ASSERT(RB_BUILTIN_TYPE(value) == T_ARRAY);

struct objspace *objspace = (struct objspace *)data;

if (!mmtk_is_reachable((MMTk_ObjectReference)key)) {
if (mmtk_is_reachable((MMTk_ObjectReference)key)) {
VALUE new_key_location = rb_mmtk_call_object_closure((VALUE)key, false);

if (new_key_location != key) {
return ST_REPLACE;
}
}
else {
make_final_job(objspace, (VALUE)key, (VALUE)value);

rb_postponed_job_trigger(objspace->finalizer_postponed_job);
Expand All @@ -380,13 +389,25 @@ rb_mmtk_update_finalizer_table_i(st_data_t key, st_data_t value, st_data_t data)
return ST_CONTINUE;
}

static int
rb_mmtk_update_finalizer_table_replace_i(st_data_t *key, st_data_t *value, st_data_t data, int existing)
{
*key = rb_mmtk_call_object_closure((VALUE)*key, false);

return ST_CONTINUE;
}

static void
rb_mmtk_update_finalizer_table(void)
{
struct objspace *objspace = rb_gc_get_objspace();

// TODO: replace with st_foreach_with_replace when GC is moving
st_foreach(objspace->finalizer_table, rb_mmtk_update_finalizer_table_i, (st_data_t)objspace);
st_foreach_with_replace(
objspace->finalizer_table,
rb_mmtk_update_finalizer_table_i,
rb_mmtk_update_finalizer_table_replace_i,
(st_data_t)objspace
);
}

static int
Expand Down
4 changes: 4 additions & 0 deletions misc/.vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,8 @@
"disasm",
],
"rust-analyzer.cfg.setTest": false,
// rust-analyzer bundled in the VSCode extension may only support Rust newer than 1.85.0.
// To avoid warnings, install rust-analyzer with `rustup component add rust-analyzer` and
// use `~/.cargo/bin/rust-analyzer` with the following config.
"rust-analyzer.server.path": "rust-analyzer",
}
8 changes: 8 additions & 0 deletions prism_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -1833,6 +1833,10 @@ pm_setup_args_core(const pm_arguments_node_t *arguments_node, const pm_node_t *b
// foo(*a, b, c: :d)
// foo(*a, b, **c)
//
// If the next node is a forwarding argument:
//
// foo(*a, b, ...)
//
// If the next node is NULL (we have hit the end):
//
// foo(*a, b)
Expand All @@ -1855,6 +1859,10 @@ pm_setup_args_core(const pm_arguments_node_t *arguments_node, const pm_node_t *b
PUSH_INSN(ret, location, concatarray);
break;
}
case PM_FORWARDING_ARGUMENTS_NODE: {
PUSH_INSN1(ret, location, pushtoarray, INT2FIX(post_splat_counter));
break;
}
default:
break;
}
Expand Down
16 changes: 10 additions & 6 deletions zjit/src/backend/lir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1901,18 +1901,19 @@ impl Assembler
}
}

const BOLD_BEGIN: &str = "\x1b[1m";
const BOLD_END: &str = "\x1b[22m";

/// Return a result of fmt::Display for Assembler without escape sequence
pub fn lir_string(asm: &Assembler) -> String {
format!("{asm}").replace(BOLD_BEGIN, "").replace(BOLD_END, "")
use crate::ttycolors::TTY_TERMINAL_COLOR;
format!("{asm}").replace(TTY_TERMINAL_COLOR.bold_begin, "").replace(TTY_TERMINAL_COLOR.bold_end, "")
}

impl fmt::Display for Assembler {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Count the number of duplicated label names to disambiguate them if needed
let mut label_counts: HashMap<&String, usize> = HashMap::new();
let colors = crate::ttycolors::get_colors();
let bold_begin = colors.bold_begin;
let bold_end = colors.bold_end;
for label_name in self.label_names.iter() {
let counter = label_counts.entry(label_name).or_insert(0);
*counter += 1;
Expand All @@ -1932,7 +1933,7 @@ impl fmt::Display for Assembler {
for insn in self.insns.iter() {
match insn {
Insn::Comment(comment) => {
writeln!(f, " {BOLD_BEGIN}# {comment}{BOLD_END}")?;
writeln!(f, " {bold_begin}# {comment}{bold_end}")?;
}
Insn::Label(target) => {
let &Target::Label(Label(label_idx)) = target else {
Expand Down Expand Up @@ -2506,6 +2507,9 @@ impl AssemblerPanicHook {

/// Dump Assembler, highlighting the insn_idx line
fn dump_asm(asm: &Assembler, insn_idx: usize) {
let colors = crate::ttycolors::get_colors();
let bold_begin = colors.bold_begin;
let bold_end = colors.bold_end;
let lir_string = lir_string(asm);
let lines: Vec<&str> = lir_string.split('\n').collect();

Expand All @@ -2520,7 +2524,7 @@ impl AssemblerPanicHook {
eprintln!("Failed to compile LIR at insn_idx={insn_idx}:");
for (idx, line) in lines.iter().enumerate().filter(|(idx, _)| (min_idx..=max_idx).contains(idx)) {
if idx == insn_idx && line.starts_with(" ") {
eprintln!("{BOLD_BEGIN}=>{}{BOLD_END}", &line[" ".len()..]);
eprintln!("{bold_begin}=>{}{bold_end}", &line[" ".len()..]);
} else {
eprintln!("{line}");
}
Expand Down
9 changes: 5 additions & 4 deletions zjit/src/disasm.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use crate::asm::CodeBlock;

pub const BOLD_BEGIN: &str = "\x1b[1m";
pub const BOLD_END: &str = "\x1b[22m";

pub fn disasm_addr_range(cb: &CodeBlock, start_addr: usize, end_addr: usize) -> String {
use std::fmt::Write;

Expand Down Expand Up @@ -36,12 +33,16 @@ pub fn disasm_addr_range(cb: &CodeBlock, start_addr: usize, end_addr: usize) ->
let start_addr = 0;
let insns = cs.disasm_all(code_slice, start_addr as u64).unwrap();

let colors = crate::ttycolors::get_colors();
let bold_begin = colors.bold_begin;
let bold_end = colors.bold_end;

// For each instruction in this block
for insn in insns.as_ref() {
// Comments for this block
if let Some(comment_list) = cb.comments_at(insn.address() as usize) {
for comment in comment_list {
writeln!(&mut out, " {BOLD_BEGIN}# {comment}{BOLD_END}").unwrap();
writeln!(&mut out, " {bold_begin}# {comment}{bold_end}").unwrap();
}
}
writeln!(&mut out, " {}", format!("{insn}").trim()).unwrap();
Expand Down
1 change: 1 addition & 0 deletions zjit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ mod bitset;
mod gc;
mod payload;
mod json;
mod ttycolors;
31 changes: 31 additions & 0 deletions zjit/src/ttycolors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use std::io::IsTerminal;

pub fn stdout_supports_colors() -> bool {
std::io::stdout().is_terminal()
}

#[cfg_attr(not(feature = "disasm"), allow(dead_code))]
#[derive(Copy, Clone, Debug)]
pub struct TerminalColor {
pub bold_begin: &'static str,
pub bold_end: &'static str,
}

pub static TTY_TERMINAL_COLOR: TerminalColor = TerminalColor {
bold_begin: "\x1b[1m",
bold_end: "\x1b[22m",
};

pub static NON_TTY_TERMINAL_COLOR: TerminalColor = TerminalColor {
bold_begin: "",
bold_end: "",
};

/// Terminal escape codes for colors, font weight, etc. Only enabled if stdout is a TTY.
pub fn get_colors() -> &'static TerminalColor {
if stdout_supports_colors() {
&TTY_TERMINAL_COLOR
} else {
&NON_TTY_TERMINAL_COLOR
}
}