Skip to content

Commit 6662568

Browse files
committed
ZJIT: Inline String#to_sym to StringIntern
Closes #1061. Also add a test to make sure `String#intern` generates the same HIR.
1 parent d74c656 commit 6662568

3 files changed

Lines changed: 86 additions & 0 deletions

File tree

‎zjit/src/codegen_tests.rs‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,25 @@ fn test_string_intern() {
369369
assert_snapshot!(assert_compiles(r#"test"#), @":foo123");
370370
}
371371

372+
#[test]
373+
fn test_string_to_sym_invalid_encoding_unused() {
374+
eval(r#"
375+
def test(str)
376+
str.to_sym
377+
:converted
378+
end
379+
"#);
380+
assert_snapshot!(assert_compiles(r#"
381+
test("warmup")
382+
test("warmup")
383+
begin
384+
test("\xFF".force_encoding(Encoding::UTF_8))
385+
rescue EncodingError
386+
:encoding_error
387+
end
388+
"#), @":encoding_error");
389+
}
390+
372391
#[test]
373392
fn test_duphash() {
374393
eval("

‎zjit/src/cruby_methods.rs‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ pub fn init() -> Annotations {
277277
annotate!(rb_cFloat, "to_i", inline_float_to_i);
278278
annotate!(rb_cFloat, "to_int", inline_float_to_i);
279279
annotate!(rb_cString, "to_s", inline_string_to_s, types::StringExact);
280+
annotate!(rb_cString, "to_sym", inline_string_to_sym, types::Symbol);
280281
annotate!(rb_cFloat, "nan?", types::BoolExact, no_gc, leaf, elidable);
281282
annotate!(rb_cFloat, "finite?", types::BoolExact, no_gc, leaf, elidable);
282283
annotate!(rb_cFloat, "infinite?", types::Fixnum.union(types::NilClass), no_gc, leaf, elidable);
@@ -324,6 +325,14 @@ fn inline_string_to_s(fun: &mut hir::Function, block: hir::BlockId, recv: hir::I
324325
None
325326
}
326327

328+
fn inline_string_to_sym(fun: &mut hir::Function, block: hir::BlockId, recv: hir::InsnId, args: &[hir::InsnId], state: hir::InsnId) -> Option<hir::InsnId> {
329+
if args.is_empty() && fun.likely_a(recv, types::StringExact, state) {
330+
let recv = fun.coerce_to(block, recv, types::StringExact, state);
331+
return Some(fun.push_insn(block, hir::Insn::StringIntern { val: recv, state }));
332+
}
333+
None
334+
}
335+
327336
fn inline_falseclass_and(fun: &mut hir::Function, block: hir::BlockId, _recv: hir::InsnId, args: &[hir::InsnId], _state: hir::InsnId) -> Option<hir::InsnId> {
328337
// FalseClass#& just returns Qfalse and ignores its argument.
329338
let &[_] = args else { return None; };

‎zjit/src/hir/opt_tests.rs‎

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12840,6 +12840,64 @@ mod hir_opt_tests {
1284012840
");
1284112841
}
1284212842

12843+
#[test]
12844+
fn test_inline_string_to_sym() {
12845+
eval(r#"
12846+
def test(str) = str.to_sym
12847+
test("warmup")
12848+
"#);
12849+
assert_snapshot!(hir_string("test"), @"
12850+
fn test@<compiled>:2:
12851+
bb1():
12852+
EntryPoint interpreter
12853+
v1:BasicObject = LoadSelf
12854+
v2:CPtr = LoadSP
12855+
v3:BasicObject = LoadField v2, :str@0x1000
12856+
Jump bb3(v1, v3)
12857+
bb2():
12858+
EntryPoint JIT(0)
12859+
v6:BasicObject = LoadArg :self@0
12860+
v7:BasicObject = LoadArg :str@1
12861+
Jump bb3(v6, v7)
12862+
bb3(v9:BasicObject, v10:BasicObject):
12863+
PatchPoint NoSingletonClass(String@0x1008)
12864+
PatchPoint MethodRedefined(String@0x1008, to_sym@0x1010, cme:0x1018)
12865+
v24:StringExact = GuardType v10, StringExact recompile
12866+
v25:Symbol = StringIntern v24
12867+
CheckInterrupts
12868+
Return v25
12869+
");
12870+
}
12871+
12872+
#[test]
12873+
fn test_inline_string_intern() {
12874+
eval(r#"
12875+
def test(str) = str.intern
12876+
test("warmup")
12877+
"#);
12878+
assert_snapshot!(hir_string("test"), @"
12879+
fn test@<compiled>:2:
12880+
bb1():
12881+
EntryPoint interpreter
12882+
v1:BasicObject = LoadSelf
12883+
v2:CPtr = LoadSP
12884+
v3:BasicObject = LoadField v2, :str@0x1000
12885+
Jump bb3(v1, v3)
12886+
bb2():
12887+
EntryPoint JIT(0)
12888+
v6:BasicObject = LoadArg :self@0
12889+
v7:BasicObject = LoadArg :str@1
12890+
Jump bb3(v6, v7)
12891+
bb3(v9:BasicObject, v10:BasicObject):
12892+
PatchPoint NoSingletonClass(String@0x1008)
12893+
PatchPoint MethodRedefined(String@0x1008, intern@0x1010, cme:0x1018)
12894+
v24:StringExact = GuardType v10, StringExact recompile
12895+
v25:Symbol = StringIntern v24
12896+
CheckInterrupts
12897+
Return v25
12898+
");
12899+
}
12900+
1284312901
#[test]
1284412902
fn test_fixnum_to_s_returns_string() {
1284512903
eval(r#"

0 commit comments

Comments
 (0)