Skip to content

Commit 1e51c78

Browse files
committed
zjit implementation
1 parent f40f604 commit 1e51c78

10 files changed

Lines changed: 356 additions & 209 deletions

File tree

test/ruby/test_zjit.rb

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,44 @@ def test
187187
}, insns: [:opt_new], call_threshold: 2
188188
end
189189

190+
def test_opt_string_new
191+
assert_compiles '["", String, false]', %q{
192+
def test = String.new
193+
s = test; test
194+
[s, s.class, s.frozen?]
195+
}, insns: [:opt_string_new], call_threshold: 2
196+
end
197+
198+
def test_opt_string_new_with_capacity
199+
assert_compiles '["", "", ""]', %q{
200+
def test(cap) = String.new(capacity: cap)
201+
[test(100), test(-5), test(0)].tap { test(100) }
202+
}, insns: [:opt_string_new], call_threshold: 2
203+
end
204+
205+
def test_opt_string_new_allocates_mutable_string
206+
assert_compiles '"hello world"', %q{
207+
def test = String.new
208+
test; test
209+
s = test
210+
s << "hello" << " " << "world"
211+
s
212+
}, insns: [:opt_string_new], call_threshold: 2
213+
end
214+
215+
def test_opt_string_new_falls_back_when_initialize_redefined
216+
assert_compiles '[true, true]', %q{
217+
def test = String.new
218+
test; test
219+
class String
220+
def initialize(*) = (super; @marked = true)
221+
end
222+
a = test
223+
b = String.new
224+
[a.instance_variable_get(:@marked), b.instance_variable_get(:@marked)]
225+
}, insns: [:opt_string_new], call_threshold: 2
226+
end
227+
190228
def test_uncached_getconstant_path
191229
assert_compiles RUBY_COPYRIGHT.dump, %q{
192230
def test = RUBY_COPYRIGHT

yjit/bindgen/src/main.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ fn main() {
6767

6868
.allowlist_type("ruby_special_consts")
6969
.allowlist_function("rb_utf8_str_new")
70+
.allowlist_function("rb_str_buf_new")
71+
.allowlist_function("rb_str_new_capa_for_init")
7072
.allowlist_function("rb_str_buf_append")
7173
.allowlist_function("rb_str_dup")
7274
.allowlist_type("ruby_preserved_encindex")

yjit/src/codegen.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5004,11 +5004,6 @@ fn gen_opt_string_new(
50045004
if jit.assume_expected_cfunc(asm, comptime_recv_klass, mid, rb_class_new_instance_pass_kw as _)
50055005
&& assume_method_basic_definition(jit, asm, comptime_recv_klass, ID!(initialize)) {
50065006

5007-
extern "C" {
5008-
fn rb_str_buf_new(capa: std::os::raw::c_long) -> VALUE;
5009-
fn rb_str_new_capa_for_init(capa: std::os::raw::c_long) -> VALUE;
5010-
}
5011-
50125007
let str = if argc == 0 {
50135008
// bare String.new: an empty (embedded) string. rb_str_buf_new skips
50145009
// the encoding/coderange setup that rb_str_new would do.

yjit/src/cruby_bindings.inc.rs

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

zjit/bindgen/src/main.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ fn main() {
7474

7575
.allowlist_type("ruby_special_consts")
7676
.allowlist_function("rb_utf8_str_new")
77+
.allowlist_function("rb_str_buf_new")
78+
.allowlist_function("rb_str_new_capa_for_init")
7779
.allowlist_function("rb_str_buf_append")
7880
.allowlist_function("rb_str_dup")
7981
.allowlist_function("rb_str_getbyte")

zjit/src/codegen.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
625625
Insn::ArrayLength { array } => gen_array_length(asm, opnd!(array)),
626626
Insn::ObjectAlloc { val, state } => gen_object_alloc(jit, asm, opnd!(val), &function.frame_state(*state)),
627627
&Insn::ObjectAllocClass { class, state } => gen_object_alloc_class(asm, class, &function.frame_state(state)),
628+
&Insn::StringNew { capa, cfunc, state } => gen_string_new(asm, opnd!(capa), cfunc, &function.frame_state(state)),
628629
Insn::StringCopy { val, chilled, state } => gen_string_copy(asm, opnd!(val), *chilled, &function.frame_state(*state)),
629630
Insn::StringConcat { strings, state } => gen_string_concat(jit, asm, opnds!(strings), &function.frame_state(*state)),
630631
&Insn::StringGetbyte { string, index } => gen_string_getbyte(asm, opnd!(string), opnd!(index)),
@@ -2311,6 +2312,12 @@ fn gen_object_alloc(jit: &JITState, asm: &mut Assembler, val: lir::Opnd, state:
23112312
asm_ccall!(asm, rb_obj_alloc, val)
23122313
}
23132314

2315+
fn gen_string_new(asm: &mut Assembler, capa: lir::Opnd, cfunc: *const u8, state: &FrameState) -> lir::Opnd {
2316+
// rb_str_buf_new / rb_str_new_capa_for_init are leaf allocators that may trigger GC.
2317+
gen_prepare_leaf_call_with_gc(asm, state);
2318+
asm.ccall(cfunc, vec![capa])
2319+
}
2320+
23142321
fn gen_object_alloc_class(asm: &mut Assembler, class: VALUE, state: &FrameState) -> lir::Opnd {
23152322
// Allocating an object for a known class with default allocator is leaf; see doc for
23162323
// `ObjectAllocClass`.

zjit/src/cruby.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1634,6 +1634,7 @@ pub(crate) mod ids {
16341634
def_ids! {
16351635
name: NULL content: b""
16361636
name: respond_to_missing content: b"respond_to_missing?"
1637+
name: initialize
16371638
name: eq content: b"=="
16381639
name: string_eq content: b"String#=="
16391640
name: include_p content: b"include?"

0 commit comments

Comments
 (0)