зеркало из https://github.com/github/ruby.git
Introduce a specialize instruction for Array#pack
Instructions for this code: ```ruby # frozen_string_literal: true [a].pack("C") ``` Before this commit: ``` == disasm: #<ISeq:<main>@test.rb:1 (1,0)-(3,13)> 0000 putself ( 3)[Li] 0001 opt_send_without_block <calldata!mid:a, argc:0, FCALL|VCALL|ARGS_SIMPLE> 0003 newarray 1 0005 putobject "C" 0007 opt_send_without_block <calldata!mid:pack, argc:1, ARGS_SIMPLE> 0009 leave ``` After this commit: ``` == disasm: #<ISeq:<main>@test.rb:1 (1,0)-(3,13)> 0000 putself ( 3)[Li] 0001 opt_send_without_block <calldata!mid:a, argc:0, FCALL|VCALL|ARGS_SIMPLE> 0003 putobject "C" 0005 opt_newarray_send 2, :pack 0008 leave ``` Co-authored-by: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@shopify.com> Co-authored-by: Aaron Patterson <tenderlove@ruby-lang.org>
This commit is contained in:
Родитель
e5e079e70f
Коммит
49fcd33e13
13
array.c
13
array.c
|
@ -880,6 +880,19 @@ rb_ary_free(VALUE ary)
|
|||
}
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_setup_fake_ary(struct RArray *fake_ary, const VALUE *list, long len, bool freeze)
|
||||
{
|
||||
fake_ary->basic.flags = T_ARRAY;
|
||||
VALUE ary = (VALUE)fake_ary;
|
||||
RBASIC_CLEAR_CLASS(ary);
|
||||
ARY_SET_PTR(ary, list);
|
||||
ARY_SET_HEAP_LEN(ary, len);
|
||||
ARY_SET_CAPA(ary, len);
|
||||
if (freeze) OBJ_FREEZE(ary);
|
||||
return ary;
|
||||
}
|
||||
|
||||
size_t
|
||||
rb_ary_memsize(VALUE ary)
|
||||
{
|
||||
|
|
29
compile.c
29
compile.c
|
@ -4048,6 +4048,8 @@ insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
|
|||
return COMPILE_OK;
|
||||
}
|
||||
|
||||
#define vm_ci_simple(ci) (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE)
|
||||
|
||||
static int
|
||||
iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
|
||||
{
|
||||
|
@ -4059,24 +4061,43 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
|
|||
INSN *niobj = (INSN *)iobj->link.next;
|
||||
if (IS_INSN_ID(niobj, send)) {
|
||||
const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(niobj, 0);
|
||||
if ((vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE) && vm_ci_argc(ci) == 0) {
|
||||
if (vm_ci_simple(ci) && vm_ci_argc(ci) == 0) {
|
||||
switch (vm_ci_mid(ci)) {
|
||||
case idMax:
|
||||
case idMin:
|
||||
case idHash:
|
||||
{
|
||||
VALUE num = iobj->operands[0];
|
||||
int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
|
||||
iobj->insn_id = BIN(opt_newarray_send);
|
||||
iobj->operands = compile_data_calloc2(iseq, insn_len(iobj->insn_id) - 1, sizeof(VALUE));
|
||||
iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
|
||||
iobj->operands[0] = num;
|
||||
iobj->operands[1] = rb_id2sym(vm_ci_mid(ci));
|
||||
iobj->operand_size = insn_len(iobj->insn_id) - 1;
|
||||
iobj->operand_size = operand_len;
|
||||
ELEM_REMOVE(&niobj->link);
|
||||
return COMPILE_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((IS_INSN_ID(niobj, putstring) ||
|
||||
(IS_INSN_ID(niobj, putobject) && RB_TYPE_P(OPERAND_AT(niobj, 0), T_STRING))) &&
|
||||
IS_NEXT_INSN_ID(&niobj->link, send)) {
|
||||
const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT((INSN *)niobj->link.next, 0);
|
||||
if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idPack) {
|
||||
VALUE num = iobj->operands[0];
|
||||
int operand_len = insn_len(BIN(opt_newarray_send)) - 1;
|
||||
iobj->insn_id = BIN(opt_newarray_send);
|
||||
iobj->operands = compile_data_calloc2(iseq, operand_len, sizeof(VALUE));
|
||||
iobj->operands[0] = FIXNUM_INC(num, 1);
|
||||
iobj->operands[1] = rb_id2sym(vm_ci_mid(ci));
|
||||
iobj->operand_size = operand_len;
|
||||
ELEM_REMOVE(&iobj->link);
|
||||
ELEM_REMOVE(niobj->link.next);
|
||||
ELEM_INSERT_NEXT(&niobj->link, &iobj->link);
|
||||
return COMPILE_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_INSN_ID(iobj, send)) {
|
||||
|
@ -4084,7 +4105,7 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
|
|||
const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);
|
||||
|
||||
#define SP_INSN(opt) insn_set_specialized_instruction(iseq, iobj, BIN(opt_##opt))
|
||||
if (vm_ci_flag(ci) & VM_CALL_ARGS_SIMPLE) {
|
||||
if (vm_ci_simple(ci)) {
|
||||
switch (vm_ci_argc(ci)) {
|
||||
case 0:
|
||||
switch (vm_ci_mid(ci)) {
|
||||
|
|
|
@ -59,6 +59,7 @@ firstline, predefined = __LINE__+1, %[\
|
|||
name
|
||||
nil
|
||||
path
|
||||
pack
|
||||
|
||||
_ UScore
|
||||
|
||||
|
|
|
@ -977,6 +977,9 @@ opt_newarray_send
|
|||
case idMax:
|
||||
val = vm_opt_newarray_max(ec, num, STACK_ADDR_FROM_TOP(num));
|
||||
break;
|
||||
case idPack:
|
||||
val = rb_vm_opt_newarray_pack(ec, (long)num-1, STACK_ADDR_FROM_TOP(num), TOPN(0));
|
||||
break;
|
||||
default:
|
||||
rb_bug("unreachable");
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ enum ruby_basic_operators {
|
|||
BOP_OR,
|
||||
BOP_CMP,
|
||||
BOP_DEFAULT,
|
||||
BOP_PACK,
|
||||
|
||||
BOP_LAST_
|
||||
};
|
||||
|
|
6
pack.c
6
pack.c
|
@ -782,6 +782,12 @@ pack_pack(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
|
|||
return res;
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_ec_pack_ary(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer)
|
||||
{
|
||||
return pack_pack(ec, ary, fmt, buffer);
|
||||
}
|
||||
|
||||
static const char uu_table[] =
|
||||
"`!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_";
|
||||
static const char b64_table[] =
|
||||
|
|
1
rjit_c.c
1
rjit_c.c
|
@ -519,6 +519,7 @@ extern VALUE rb_vm_getclassvariable(const rb_iseq_t *iseq, const rb_control_fram
|
|||
extern VALUE rb_vm_opt_newarray_min(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr);
|
||||
extern VALUE rb_vm_opt_newarray_max(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr);
|
||||
extern VALUE rb_vm_opt_newarray_hash(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr);
|
||||
extern VALUE rb_vm_opt_newarray_pack(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr, VALUE fmt);
|
||||
extern VALUE rb_vm_splat_array(VALUE flag, VALUE array);
|
||||
extern bool rb_simple_iseq_p(const rb_iseq_t *iseq);
|
||||
extern bool rb_vm_defined(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, rb_num_t op_type, VALUE obj, VALUE v);
|
||||
|
|
|
@ -691,6 +691,10 @@ module RubyVM::RJIT # :nodoc: all
|
|||
Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_opt_newarray_min) }
|
||||
end
|
||||
|
||||
def C.rb_vm_opt_newarray_pack
|
||||
Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_opt_newarray_pack) }
|
||||
end
|
||||
|
||||
def C.rb_vm_set_ivar_id
|
||||
Primitive.cexpr! %q{ SIZET2NUM((size_t)rb_vm_set_ivar_id) }
|
||||
end
|
||||
|
|
|
@ -895,4 +895,22 @@ EXPECTED
|
|||
}
|
||||
assert_equal [nil], "a".unpack("C", offset: 1)
|
||||
end
|
||||
|
||||
def test_monkey_pack
|
||||
assert_separately([], <<-'end;')
|
||||
$-w = false
|
||||
class Array
|
||||
alias :old_pack :pack
|
||||
def pack _; "oh no"; end
|
||||
end
|
||||
|
||||
v = [2 ** 15].pack('n')
|
||||
|
||||
class Array
|
||||
alias :pack :old_pack
|
||||
end
|
||||
|
||||
assert_equal "oh no", v
|
||||
end;
|
||||
end
|
||||
end
|
||||
|
|
|
@ -540,6 +540,7 @@ generator = BindingGenerator.new(
|
|||
rb_vm_opt_newarray_min
|
||||
rb_vm_opt_newarray_max
|
||||
rb_vm_opt_newarray_hash
|
||||
rb_vm_opt_newarray_pack
|
||||
rb_vm_setinstancevariable
|
||||
rb_vm_splat_array
|
||||
rjit_full_cfunc_return
|
||||
|
|
1
vm.c
1
vm.c
|
@ -2278,6 +2278,7 @@ vm_redefinition_bop_for_id(ID mid)
|
|||
OP(NilP, NIL_P);
|
||||
OP(Cmp, CMP);
|
||||
OP(Default, DEFAULT);
|
||||
OP(Pack, PACK);
|
||||
#undef OP
|
||||
}
|
||||
return -1;
|
||||
|
|
|
@ -5932,6 +5932,22 @@ rb_vm_opt_newarray_hash(rb_execution_context_t *ec, rb_num_t num, const VALUE *p
|
|||
return vm_opt_newarray_hash(ec, num, ptr);
|
||||
}
|
||||
|
||||
VALUE rb_setup_fake_ary(struct RArray *fake_ary, const VALUE *list, long len, bool freeze);
|
||||
VALUE rb_ec_pack_ary(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer);
|
||||
|
||||
VALUE
|
||||
rb_vm_opt_newarray_pack(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr, VALUE fmt)
|
||||
{
|
||||
if (BASIC_OP_UNREDEFINED_P(BOP_PACK, ARRAY_REDEFINED_OP_FLAG)) {
|
||||
struct RArray fake_ary;
|
||||
VALUE ary = rb_setup_fake_ary(&fake_ary, ptr, num, true);
|
||||
return rb_ec_pack_ary(ec, ary, fmt, Qnil);
|
||||
}
|
||||
else {
|
||||
return rb_vm_call_with_refinements(ec, rb_ary_new4(num, ptr), idPack, 1, &fmt, RB_PASS_CALLED_KEYWORDS);
|
||||
}
|
||||
}
|
||||
|
||||
#undef id_cmp
|
||||
|
||||
#define IMEMO_CONST_CACHE_SHAREABLE IMEMO_FL_USER0
|
||||
|
|
|
@ -4235,11 +4235,50 @@ fn gen_opt_newarray_send(
|
|||
gen_opt_newarray_max(jit, asm, _ocb)
|
||||
} else if method == ID!(hash) {
|
||||
gen_opt_newarray_hash(jit, asm, _ocb)
|
||||
} else if method == ID!(pack) {
|
||||
gen_opt_newarray_pack(jit, asm, _ocb)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_opt_newarray_pack(
|
||||
jit: &mut JITState,
|
||||
asm: &mut Assembler,
|
||||
_ocb: &mut OutlinedCb,
|
||||
) -> Option<CodegenStatus> {
|
||||
// num == 4 ( for this code )
|
||||
let num = jit.get_arg(0).as_u32();
|
||||
|
||||
// Save the PC and SP because we may call #pack
|
||||
jit_prepare_non_leaf_call(jit, asm);
|
||||
|
||||
extern "C" {
|
||||
fn rb_vm_opt_newarray_pack(ec: EcPtr, num: u32, elts: *const VALUE, fmt: VALUE) -> VALUE;
|
||||
}
|
||||
|
||||
let values_opnd = asm.ctx.sp_opnd(-(num as i32));
|
||||
let values_ptr = asm.lea(values_opnd);
|
||||
|
||||
let fmt_string = asm.ctx.sp_opnd(-1);
|
||||
|
||||
let val_opnd = asm.ccall(
|
||||
rb_vm_opt_newarray_pack as *const u8,
|
||||
vec![
|
||||
EC,
|
||||
(num - 1).into(),
|
||||
values_ptr,
|
||||
fmt_string
|
||||
],
|
||||
);
|
||||
|
||||
asm.stack_pop(num.as_usize());
|
||||
let stack_ret = asm.stack_push(Type::CString);
|
||||
asm.mov(stack_ret, val_opnd);
|
||||
|
||||
Some(KeepCompiling)
|
||||
}
|
||||
|
||||
fn gen_opt_newarray_hash(
|
||||
jit: &mut JITState,
|
||||
asm: &mut Assembler,
|
||||
|
|
|
@ -802,6 +802,7 @@ pub(crate) mod ids {
|
|||
name: min content: b"min"
|
||||
name: max content: b"max"
|
||||
name: hash content: b"hash"
|
||||
name: pack content: b"pack"
|
||||
name: respond_to_missing content: b"respond_to_missing?"
|
||||
name: to_ary content: b"to_ary"
|
||||
name: eq content: b"=="
|
||||
|
|
|
@ -342,7 +342,8 @@ pub const BOP_AND: ruby_basic_operators = 28;
|
|||
pub const BOP_OR: ruby_basic_operators = 29;
|
||||
pub const BOP_CMP: ruby_basic_operators = 30;
|
||||
pub const BOP_DEFAULT: ruby_basic_operators = 31;
|
||||
pub const BOP_LAST_: ruby_basic_operators = 32;
|
||||
pub const BOP_PACK: ruby_basic_operators = 32;
|
||||
pub const BOP_LAST_: ruby_basic_operators = 33;
|
||||
pub type ruby_basic_operators = u32;
|
||||
pub type rb_serial_t = ::std::os::raw::c_ulonglong;
|
||||
pub const imemo_env: imemo_type = 0;
|
||||
|
|
Загрузка…
Ссылка в новой задаче