Skip to content

Commit ea33b0a

Browse files
jhawthornXrXr
authored andcommitted
Add concatstrings to yjit codegen (#58)
* Add ETYPE_TRUE and ETYPE_FALSE * Implement checktype * Implement concatstrings * Update deps
1 parent eb6e5be commit ea33b0a

File tree

4 files changed

+139
-1
lines changed

4 files changed

+139
-1
lines changed

bootstraptest/test_yjit.rb

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -977,3 +977,47 @@ def build_hash(val)
977977
build_hash(:bar)
978978
build_hash(:bar)
979979
}
980+
981+
# test string interpolation with known types
982+
assert_equal 'foobar', %q{
983+
def make_str
984+
foo = -"foo"
985+
bar = -"bar"
986+
"#{foo}#{bar}"
987+
end
988+
989+
make_str
990+
make_str
991+
}
992+
993+
# test string interpolation with unknown types
994+
assert_equal 'foobar', %q{
995+
def make_str(foo, bar)
996+
"#{foo}#{bar}"
997+
end
998+
999+
make_str("foo", "bar")
1000+
make_str("foo", "bar")
1001+
}
1002+
1003+
# test string interpolation with known non-strings
1004+
assert_equal 'foo123', %q{
1005+
def make_str
1006+
foo = -"foo"
1007+
bar = 123
1008+
"#{foo}#{bar}"
1009+
end
1010+
1011+
make_str
1012+
make_str
1013+
}
1014+
1015+
# test string interpolation with unknown non-strings
1016+
assert_equal 'foo123', %q{
1017+
def make_str(foo, bar)
1018+
"#{foo}#{bar}"
1019+
end
1020+
1021+
make_str("foo", 123)
1022+
make_str("foo", 123)
1023+
}

common.mk

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16712,6 +16712,7 @@ yjit_codegen.$(OBJEXT): $(top_srcdir)/internal/imemo.h
1671216712
yjit_codegen.$(OBJEXT): $(top_srcdir)/internal/object.h
1671316713
yjit_codegen.$(OBJEXT): $(top_srcdir)/internal/serial.h
1671416714
yjit_codegen.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
16715+
yjit_codegen.$(OBJEXT): $(top_srcdir)/internal/string.h
1671516716
yjit_codegen.$(OBJEXT): $(top_srcdir)/internal/vm.h
1671616717
yjit_codegen.$(OBJEXT): $(top_srcdir)/internal/warnings.h
1671716718
yjit_codegen.$(OBJEXT): {$(VPATH)}assert.h
@@ -16730,6 +16731,7 @@ yjit_codegen.$(OBJEXT): {$(VPATH)}config.h
1673016731
yjit_codegen.$(OBJEXT): {$(VPATH)}darray.h
1673116732
yjit_codegen.$(OBJEXT): {$(VPATH)}debug_counter.h
1673216733
yjit_codegen.$(OBJEXT): {$(VPATH)}defines.h
16734+
yjit_codegen.$(OBJEXT): {$(VPATH)}encoding.h
1673316735
yjit_codegen.$(OBJEXT): {$(VPATH)}id.h
1673416736
yjit_codegen.$(OBJEXT): {$(VPATH)}id_table.h
1673516737
yjit_codegen.$(OBJEXT): {$(VPATH)}insns.def
@@ -16880,6 +16882,8 @@ yjit_codegen.$(OBJEXT): {$(VPATH)}iseq.h
1688016882
yjit_codegen.$(OBJEXT): {$(VPATH)}method.h
1688116883
yjit_codegen.$(OBJEXT): {$(VPATH)}missing.h
1688216884
yjit_codegen.$(OBJEXT): {$(VPATH)}node.h
16885+
yjit_codegen.$(OBJEXT): {$(VPATH)}onigmo.h
16886+
yjit_codegen.$(OBJEXT): {$(VPATH)}oniguruma.h
1688316887
yjit_codegen.$(OBJEXT): {$(VPATH)}ruby_assert.h
1688416888
yjit_codegen.$(OBJEXT): {$(VPATH)}ruby_atomic.h
1688516889
yjit_codegen.$(OBJEXT): {$(VPATH)}st.h

yjit_codegen.c

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "internal/compile.h"
99
#include "internal/class.h"
1010
#include "internal/object.h"
11+
#include "internal/string.h"
1112
#include "insns_info.inc"
1213
#include "yjit.h"
1314
#include "yjit_iface.h"
@@ -1317,6 +1318,89 @@ gen_defined(jitstate_t* jit, ctx_t* ctx)
13171318
return YJIT_KEEP_COMPILING;
13181319
}
13191320

1321+
static codegen_status_t
1322+
gen_checktype(jitstate_t* jit, ctx_t* ctx)
1323+
{
1324+
// TODO: could we specialize on the type we detect
1325+
uint8_t* side_exit = yjit_side_exit(jit, ctx);
1326+
1327+
enum ruby_value_type type_val = (enum ruby_value_type)jit_get_arg(jit, 0);
1328+
// Only three types are emitted by compile.c
1329+
if (type_val == T_STRING || type_val == T_ARRAY || type_val == T_HASH) {
1330+
val_type_t val_type = ctx_get_opnd_type(ctx, OPND_STACK(0));
1331+
x86opnd_t val = ctx_stack_pop(ctx, 1);
1332+
1333+
x86opnd_t stack_ret;
1334+
1335+
// Check if we know from type information
1336+
if ((type_val == T_STRING && val_type.type == ETYPE_STRING) ||
1337+
(type_val == T_ARRAY && val_type.type == ETYPE_ARRAY) ||
1338+
(type_val == T_HASH && val_type.type == ETYPE_HASH)) {
1339+
// guaranteed type match
1340+
stack_ret = ctx_stack_push(ctx, TYPE_TRUE);
1341+
mov(cb, stack_ret, imm_opnd(Qtrue));
1342+
return YJIT_KEEP_COMPILING;
1343+
} else if (val_type.is_imm || val_type.type != ETYPE_UNKNOWN) {
1344+
// guaranteed not to match T_STRING/T_ARRAY/T_HASH
1345+
stack_ret = ctx_stack_push(ctx, TYPE_FALSE);
1346+
mov(cb, stack_ret, imm_opnd(Qfalse));
1347+
return YJIT_KEEP_COMPILING;
1348+
}
1349+
1350+
mov(cb, REG0, val);
1351+
1352+
if (!val_type.is_heap) {
1353+
// if (SPECIAL_CONST_P(val)) {
1354+
// Bail if receiver is not a heap object
1355+
test(cb, REG0, imm_opnd(RUBY_IMMEDIATE_MASK));
1356+
jnz_ptr(cb, side_exit);
1357+
cmp(cb, REG0, imm_opnd(Qfalse));
1358+
je_ptr(cb, side_exit);
1359+
cmp(cb, REG0, imm_opnd(Qnil));
1360+
je_ptr(cb, side_exit);
1361+
}
1362+
1363+
// Check type on object
1364+
mov(cb, REG0, mem_opnd(64, REG0, offsetof(struct RBasic, flags)));
1365+
and(cb, REG0, imm_opnd(RUBY_T_MASK));
1366+
cmp(cb, REG0, imm_opnd(type_val));
1367+
mov(cb, REG1, imm_opnd(Qfalse));
1368+
cmovne(cb, REG0, REG1);
1369+
1370+
stack_ret = ctx_stack_push(ctx, TYPE_IMM);
1371+
mov(cb, stack_ret, REG0);
1372+
1373+
return YJIT_KEEP_COMPILING;
1374+
} else {
1375+
return YJIT_CANT_COMPILE;
1376+
}
1377+
}
1378+
1379+
static codegen_status_t
1380+
gen_concatstrings(jitstate_t* jit, ctx_t* ctx)
1381+
{
1382+
rb_num_t n = (rb_num_t)jit_get_arg(jit, 0);
1383+
1384+
// Save the PC and SP because we are allocating
1385+
jit_save_pc(jit, REG0);
1386+
jit_save_sp(jit, ctx);
1387+
1388+
x86opnd_t values_ptr = ctx_sp_opnd(ctx, -(sizeof(VALUE) * (uint32_t)n));
1389+
1390+
// call rb_str_concat_literals(long n, const VALUE *strings);
1391+
yjit_save_regs(cb);
1392+
mov(cb, C_ARG_REGS[0], imm_opnd(n));
1393+
lea(cb, C_ARG_REGS[1], values_ptr);
1394+
call_ptr(cb, REG0, (void *)rb_str_concat_literals);
1395+
yjit_load_regs(cb);
1396+
1397+
ctx_stack_pop(ctx, n);
1398+
x86opnd_t stack_ret = ctx_stack_push(ctx, TYPE_STRING);
1399+
mov(cb, stack_ret, RAX);
1400+
1401+
return YJIT_KEEP_COMPILING;
1402+
}
1403+
13201404
static void
13211405
guard_two_fixnums(ctx_t* ctx, uint8_t* side_exit)
13221406
{
@@ -2902,6 +2986,7 @@ yjit_init_codegen(void)
29022986
yjit_reg_op(BIN(adjuststack), gen_adjuststack);
29032987
yjit_reg_op(BIN(newarray), gen_newarray);
29042988
yjit_reg_op(BIN(newhash), gen_newhash);
2989+
yjit_reg_op(BIN(concatstrings), gen_concatstrings);
29052990
yjit_reg_op(BIN(putnil), gen_putnil);
29062991
yjit_reg_op(BIN(putobject), gen_putobject);
29072992
yjit_reg_op(BIN(putobject_INT2FIX_0_), gen_putobject_int2fix);
@@ -2913,6 +2998,7 @@ yjit_init_codegen(void)
29132998
yjit_reg_op(BIN(getinstancevariable), gen_getinstancevariable);
29142999
yjit_reg_op(BIN(setinstancevariable), gen_setinstancevariable);
29153000
yjit_reg_op(BIN(defined), gen_defined);
3001+
yjit_reg_op(BIN(checktype), gen_checktype);
29163002
yjit_reg_op(BIN(opt_lt), gen_opt_lt);
29173003
yjit_reg_op(BIN(opt_le), gen_opt_le);
29183004
yjit_reg_op(BIN(opt_ge), gen_opt_ge);

yjit_core.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ enum yjit_type_enum
3232
{
3333
ETYPE_UNKNOWN = 0,
3434
ETYPE_NIL,
35+
ETYPE_TRUE,
36+
ETYPE_FALSE,
3537
ETYPE_FIXNUM,
3638
ETYPE_ARRAY,
3739
ETYPE_HASH,
@@ -49,7 +51,7 @@ typedef struct yjit_type_struct
4951
uint8_t is_imm : 1;
5052

5153
// Specific value type, if known
52-
uint8_t type : 3;
54+
uint8_t type : 4;
5355

5456
} val_type_t;
5557
STATIC_ASSERT(val_type_size, sizeof(val_type_t) == 1);
@@ -64,6 +66,8 @@ STATIC_ASSERT(val_type_size, sizeof(val_type_t) == 1);
6466
#define TYPE_IMM ( (val_type_t){ .is_imm = 1 } )
6567

6668
#define TYPE_NIL ( (val_type_t){ .is_imm = 1, .type = ETYPE_NIL } )
69+
#define TYPE_TRUE ( (val_type_t){ .is_imm = 1, .type = ETYPE_TRUE } )
70+
#define TYPE_FALSE ( (val_type_t){ .is_imm = 1, .type = ETYPE_FALSE } )
6771
#define TYPE_FIXNUM ( (val_type_t){ .is_imm = 1, .type = ETYPE_FIXNUM } )
6872
#define TYPE_ARRAY ( (val_type_t){ .is_heap = 1, .type = ETYPE_ARRAY } )
6973
#define TYPE_HASH ( (val_type_t){ .is_heap = 1, .type = ETYPE_HASH } )

0 commit comments

Comments
 (0)