Skip to content

Commit 0ca1da7

Browse files
committed
WIP
1 parent 75f25e5 commit 0ca1da7

4 files changed

Lines changed: 59 additions & 2 deletions

File tree

test/ruby/test_zjit.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,21 @@ def test = [1,2,3]
489489
}
490490
end
491491

492+
def test_array_splat
493+
assert_compiles '"foo"', %q{
494+
def foo(b) = b
495+
def test(a) = foo(*a)
496+
test("foo")
497+
}, insns: [:splatarray]
498+
end
499+
500+
def test_array_concat_implicit
501+
assert_compiles '[1, 2, 3]', %q{
502+
def test(a) = [1, *a]
503+
test([2, 3])
504+
}, insns: [:concattoarray]
505+
end
506+
492507
def test_new_range_inclusive
493508
assert_compiles '1..5', %q{
494509
def test(a, b) = a..b

zjit/bindgen/src/main.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,11 @@ fn main() {
149149
.allowlist_function("rb_ary_dup")
150150
.allowlist_function("rb_ary_push")
151151
.allowlist_function("rb_ary_unshift_m")
152+
.allowlist_function("rb_ary_concat")
153+
.allowlist_function("rb_check_to_array")
152154

153155
// From internal/array.h
156+
.allowlist_function("rb_to_array_type")
154157
.allowlist_function("rb_ec_ary_new_from_values")
155158
.allowlist_function("rb_ary_tmp_new_from_values")
156159

zjit/src/codegen.rs

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,8 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
367367
Insn::AnyToString { val, str, state } => gen_anytostring(asm, opnd!(val), opnd!(str), &function.frame_state(*state))?,
368368
Insn::Defined { op_type, obj, pushval, v } => gen_defined(jit, asm, *op_type, *obj, *pushval, opnd!(v))?,
369369
&Insn::IncrCounter(counter) => return Some(gen_incr_counter(asm, counter)),
370-
Insn::ArrayExtend { .. }
370+
Insn::ToArray { val, state } => gen_to_array(asm, opnd!(val), &function.frame_state(*state))?,
371+
Insn::ArrayExtend { left, right, state } => return gen_array_extend(asm, opnd!(left), opnd!(right), &function.frame_state(*state)),
371372
| Insn::ArrayMax { .. }
372373
| Insn::ArrayPush { .. }
373374
| Insn::DefinedIvar { .. }
@@ -379,7 +380,6 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
379380
| Insn::Send { .. }
380381
| Insn::StringIntern { .. }
381382
| Insn::Throw { .. }
382-
| Insn::ToArray { .. }
383383
| Insn::ToNewArray { .. }
384384
| Insn::Const { .. }
385385
=> {
@@ -1042,6 +1042,42 @@ fn gen_anytostring(asm: &mut Assembler, val: lir::Opnd, str: lir::Opnd, state: &
10421042
Some(asm_ccall!(asm, rb_obj_as_string_result, str, val))
10431043
}
10441044

1045+
fn gen_to_array(asm: &mut Assembler, val: lir::Opnd, state: &FrameState) -> Option<lir::Opnd> {
1046+
// Save PC
1047+
gen_save_pc(asm, state);
1048+
1049+
let klass = asm.ccall(rb_yarv_class_of as *const u8, vec![val]);
1050+
asm.cmp(klass, Opnd::Value(unsafe { rb_cArray }));
1051+
1052+
// Store whether val is an array (1 if array, 0 if not)
1053+
let is_array = asm.csel_e(Opnd::Imm(1), Opnd::Imm(0));
1054+
// Try to convert value to array using to_a
1055+
let converted = asm_ccall!(asm, rb_check_to_array, val);
1056+
1057+
// Create array with single element (for when conversion fails)
1058+
let wrapped = gen_new_array(asm, vec![val], state);
1059+
1060+
// Check if conversion succeeded (returned non-nil)
1061+
asm.cmp(converted, Qnil.into());
1062+
1063+
// If conversion failed (nil), use wrapped; otherwise use converted
1064+
let converted_or_wrapped = asm.csel_e(wrapped, converted);
1065+
1066+
// If val was already array, use it; otherwise use converted_or_wrapped
1067+
asm.cmp(is_array, Opnd::Imm(1));
1068+
let result = asm.csel_e(val, converted_or_wrapped);
1069+
1070+
Some(result)
1071+
}
1072+
1073+
fn gen_array_extend(asm: &mut Assembler, left: lir::Opnd, right: lir::Opnd, state: &FrameState) -> Option<()> {
1074+
// Save PC
1075+
gen_save_pc(asm, state);
1076+
1077+
asm_ccall!(asm, rb_ary_concat, left, right);
1078+
Some(())
1079+
}
1080+
10451081
/// Evaluate if a value is truthy
10461082
/// Produces a CBool type (0 or 1)
10471083
/// In Ruby, only nil and false are falsy

zjit/src/cruby_bindings.inc.rs

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)