summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--yjit/src/codegen.rs67
-rw-r--r--yjit/src/core.rs17
2 files changed, 49 insertions, 35 deletions
diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs
index b319d81e2e..e522372093 100644
--- a/yjit/src/codegen.rs
+++ b/yjit/src/codegen.rs
@@ -1376,6 +1376,39 @@ fn guard_object_is_array(
}
}
+fn guard_object_is_string(
+ ctx: &mut Context,
+ asm: &mut Assembler,
+ object: Opnd,
+ object_opnd: YARVOpnd,
+ side_exit: Target,
+) {
+ let object_type = ctx.get_opnd_type(object_opnd);
+ if object_type.is_string() {
+ return;
+ }
+
+ let object_reg = match object {
+ Opnd::Reg(_) => object,
+ _ => asm.load(object),
+ };
+ guard_object_is_heap(ctx, asm, object_reg, object_opnd, side_exit);
+
+ asm.comment("guard object is string");
+
+ // Pull out the type mask
+ let flags_reg = asm.load(Opnd::mem(VALUE_BITS, object_reg, RUBY_OFFSET_RBASIC_FLAGS));
+ let flags_reg = asm.and(flags_reg, Opnd::UImm(RUBY_T_MASK as u64));
+
+ // Compare the result with T_STRING
+ asm.cmp(flags_reg, Opnd::UImm(RUBY_T_STRING as u64));
+ asm.jne(side_exit);
+
+ if object_type.diff(Type::TString) != TypeDiff::Incompatible {
+ ctx.upgrade_opnd_type(object_opnd, Type::TString);
+ }
+}
+
/// This guards that a special flag is not set on a hash.
/// By passing a hash with this flag set as the last argument
/// in a splat call, you can change the way keywords are handled
@@ -1410,22 +1443,6 @@ fn guard_object_is_not_ruby2_keyword_hash(
asm.write_label(not_ruby2_keyword);
}
-fn guard_object_is_string(
- asm: &mut Assembler,
- object_reg: Opnd,
- side_exit: Target,
-) {
- asm.comment("guard object is string");
-
- // Pull out the type mask
- let flags_reg = asm.load(Opnd::mem(VALUE_BITS, object_reg, RUBY_OFFSET_RBASIC_FLAGS));
- let flags_reg = asm.and(flags_reg, Opnd::UImm(RUBY_T_MASK as u64));
-
- // Compare the result with T_STRING
- asm.cmp(flags_reg, Opnd::UImm(RUBY_T_STRING as u64));
- asm.jne(side_exit);
-}
-
// push enough nils onto the stack to fill out an array
fn gen_expandarray(
jit: &mut JITState,
@@ -4322,8 +4339,8 @@ fn jit_rb_str_concat(
// Generate a side exit
let side_exit = get_side_exit(jit, ocb, ctx);
- // Guard that the argument is of class String at runtime.
- let arg_type = ctx.get_opnd_type(StackOpnd(0));
+ // Guard that the concat argument is a string
+ guard_object_is_string(ctx, asm, ctx.stack_opnd(0), StackOpnd(0), side_exit);
// Guard buffers from GC since rb_str_buf_append may allocate.
gen_save_sp(asm, ctx);
@@ -4331,19 +4348,6 @@ fn jit_rb_str_concat(
let concat_arg = ctx.stack_pop(1);
let recv = ctx.stack_pop(1);
- // If we're not compile-time certain that this will always be a string, guard at runtime
- if arg_type != Type::CString && arg_type != Type::TString {
- let arg_opnd = asm.load(concat_arg);
- if !arg_type.is_heap() {
- asm.comment("guard arg not immediate");
- asm.test(arg_opnd, (RUBY_IMMEDIATE_MASK as u64).into());
- asm.jnz(side_exit);
- asm.cmp(arg_opnd, Qfalse.into());
- asm.je(side_exit);
- }
- guard_object_is_string(asm, arg_opnd, side_exit);
- }
-
// Test if string encodings differ. If different, use rb_str_append. If the same,
// use rb_yjit_str_simple_append, which calls rb_str_cat.
asm.comment("<< on strings");
@@ -7048,6 +7052,7 @@ fn gen_objtostring(
SEND_MAX_DEPTH,
side_exit,
);
+
// No work needed. The string value is already on the top of the stack.
KeepCompiling
} else {
diff --git a/yjit/src/core.rs b/yjit/src/core.rs
index c67f797e82..0ddb875e65 100644
--- a/yjit/src/core.rs
+++ b/yjit/src/core.rs
@@ -154,6 +154,15 @@ impl Type {
}
}
+ /// Check if it's a T_STRING object (both TString and CString are T_STRING)
+ pub fn is_string(&self) -> bool {
+ match self {
+ Type::TString => true,
+ Type::CString => true,
+ _ => false,
+ }
+ }
+
/// Returns an Option with the T_ value type if it is known, otherwise None
pub fn known_value_type(&self) -> Option<ruby_value_type> {
match self {
@@ -258,10 +267,10 @@ impl Type {
/// Upgrade this type into a more specific compatible type
/// The new type must be compatible and at least as specific as the previously known type.
- fn upgrade(&mut self, src: Self) {
- // Here we're checking that src is more specific than self
- assert!(src.diff(*self) != TypeDiff::Incompatible);
- *self = src;
+ fn upgrade(&mut self, new_type: Self) {
+ // We can only upgrade to a type that is more specific
+ assert!(new_type.diff(*self) != TypeDiff::Incompatible);
+ *self = new_type;
}
}