Optimize instructions when creating an array just to call include? (#12123)

* Add opt_duparray_send insn to skip the allocation on `#include?`

If the method isn't going to modify the array we don't need to copy it.
This avoids the allocation / array copy for things like `[:a, :b].include?(x)`.

This adds a BOP for include? and tracks redefinition for it on Array.

Co-authored-by: Andrew Novoselac <andrew.novoselac@shopify.com>

* YJIT: Implement opt_duparray_send include_p

Co-authored-by: Andrew Novoselac <andrew.novoselac@shopify.com>

* Update opt_newarray_send to support simple forms of include?(arg)

Similar to opt_duparray_send but for non-static arrays.

* YJIT: Implement opt_newarray_send include_p

---------

Co-authored-by: Andrew Novoselac <andrew.novoselac@shopify.com>
This commit is contained in:
Randy Stauner 2024-11-26 12:31:08 -07:00 committed by GitHub
parent c1dcd1d496
commit 1dd40ec18a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
Notes: git 2024-11-26 19:31:33 +00:00
Merged-By: maximecb <maximecb@ruby-lang.org>
14 changed files with 573 additions and 156 deletions

View File

@ -214,8 +214,21 @@ tests = [
'true'.freeze
},
[ 'opt_duparray_send', %q{ x = :a; [:a, :b].include?(x) }, ],
[ 'opt_duparray_send', <<-'},', ], # {
class Array
def include?(i)
i == 1
end
end
x = 1
[:a, :b].include?(x)
},
[ 'opt_newarray_send', %q{ ![ ].hash.nil? }, ],
[ 'opt_newarray_send', %q{ v=2; [1, Object.new, 2].include?(v) }, ],
[ 'opt_newarray_send', %q{ [ ].max.nil? }, ],
[ 'opt_newarray_send', %q{ [1, x = 2, 3].max == 3 }, ],
[ 'opt_newarray_send', <<-'},', ], # {

View File

@ -5228,6 +5228,7 @@ end
test
RUBY
# opt_newarray_send pack/buffer
assert_equal '[true, true]', <<~'RUBY'
def pack
v = 1.23
@ -5244,6 +5245,7 @@ assert_equal '[true, true]', <<~'RUBY'
[pack, with_buffer]
RUBY
# String#[] / String#slice
assert_equal 'ok', <<~'RUBY'
def error(klass)
yield
@ -5283,3 +5285,27 @@ assert_equal 'ok', <<~'RUBY'
test
RUBY
# opt_duparray_send :include?
assert_equal '[true, false]', <<~'RUBY'
def test(x)
[:a, :b].include?(x)
end
[
test(:b),
test(:c),
]
RUBY
# opt_newarray_send :include?
assert_equal '[true, false]', <<~'RUBY'
def test(x)
[Object.new, :a, :b].include?(x.to_sym)
end
[
test("b"),
test("c"),
]
RUBY

View File

@ -4170,8 +4170,87 @@ iseq_specialized_instruction(rb_iseq_t *iseq, INSN *iobj)
return COMPILE_OK;
}
}
// Break the "else if" chain since some prior checks abort after sub-ifs.
// We already found "newarray". To match `[...].include?(arg)` we look for
// the instruction(s) representing the argument followed by a "send".
if ((IS_INSN_ID(niobj, putstring) || IS_INSN_ID(niobj, putchilledstring) ||
IS_INSN_ID(niobj, putobject) ||
IS_INSN_ID(niobj, putself) ||
IS_INSN_ID(niobj, getlocal) ||
IS_INSN_ID(niobj, getinstancevariable)) &&
IS_NEXT_INSN_ID(&niobj->link, send)) {
LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
const struct rb_callinfo *ci;
// Allow any number (0 or more) of simple method calls on the argument
// (as in `[...].include?(arg.method1.method2)`.
do {
sendobj = sendobj->next;
ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
} while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
// If this send is for .include? with one arg we can do our opt.
if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
VALUE num = iobj->operands[0];
INSN *sendins = (INSN *)sendobj;
sendins->insn_id = BIN(opt_newarray_send);
sendins->operand_size = insn_len(sendins->insn_id) - 1;
sendins->operands = compile_data_calloc2(iseq, sendins->operand_size, sizeof(VALUE));
sendins->operands[0] = FIXNUM_INC(num, 1);
sendins->operands[1] = INT2FIX(VM_OPT_NEWARRAY_SEND_INCLUDE_P);
// Remove the original "newarray" insn.
ELEM_REMOVE(&iobj->link);
return COMPILE_OK;
}
}
}
/*
* duparray [...]
* some insn for the arg...
* send <calldata!mid:include?, argc:1, ARGS_SIMPLE>, nil
* =>
* arg insn...
* opt_duparray_send [...], :include?, 1
*/
if (IS_INSN_ID(iobj, duparray) && iobj->link.next && IS_INSN(iobj->link.next)) {
INSN *niobj = (INSN *)iobj->link.next;
if ((IS_INSN_ID(niobj, getlocal) ||
IS_INSN_ID(niobj, getinstancevariable) ||
IS_INSN_ID(niobj, putself)) &&
IS_NEXT_INSN_ID(&niobj->link, send)) {
LINK_ELEMENT *sendobj = &(niobj->link); // Below we call ->next;
const struct rb_callinfo *ci;
// Allow any number (0 or more) of simple method calls on the argument
// (as in `[...].include?(arg.method1.method2)`.
do {
sendobj = sendobj->next;
ci = (struct rb_callinfo *)OPERAND_AT(sendobj, 0);
} while (vm_ci_simple(ci) && vm_ci_argc(ci) == 0 && IS_NEXT_INSN_ID(sendobj, send));
if (vm_ci_simple(ci) && vm_ci_argc(ci) == 1 && vm_ci_mid(ci) == idIncludeP) {
// Move the array arg from duparray to opt_duparray_send.
VALUE ary = iobj->operands[0];
rb_obj_reveal(ary, rb_cArray);
INSN *sendins = (INSN *)sendobj;
sendins->insn_id = BIN(opt_duparray_send);
sendins->operand_size = insn_len(sendins->insn_id) - 1;;
sendins->operands = compile_data_calloc2(iseq, sendins->operand_size, sizeof(VALUE));
sendins->operands[0] = ary;
sendins->operands[1] = rb_id2sym(idIncludeP);
sendins->operands[2] = INT2FIX(1);
// Remove the duparray insn.
ELEM_REMOVE(&iobj->link);
return COMPILE_OK;
}
}
}
if (IS_INSN_ID(iobj, send)) {
const struct rb_callinfo *ci = (struct rb_callinfo *)OPERAND_AT(iobj, 0);
const rb_iseq_t *blockiseq = (rb_iseq_t *)OPERAND_AT(iobj, 1);

View File

@ -61,6 +61,7 @@ firstline, predefined = __LINE__+1, %[\
path
pack
buffer
include?
_ UScore

View File

@ -991,6 +991,28 @@ opt_str_uminus
}
}
DEFINE_INSN
opt_duparray_send
(VALUE ary, ID method, rb_num_t argc)
(...)
(VALUE val)
/* This instruction typically has no funcalls. But it may compare array
* contents to each other which may call methods when necessary.
* No way to detect such method calls beforehand.
* We must mark it as not leaf. */
// attr bool leaf = false; /* has rb_funcall() */
// attr rb_snum_t sp_inc = 1 - (rb_snum_t)argc;
// attr rb_snum_t comptime_sp_inc = 1 - (rb_snum_t)argc;
{
switch(method) {
case idIncludeP:
val = vm_opt_duparray_include_p(ec, ary, TOPN(0));
break;
default:
rb_bug("unreachable");
}
}
DEFINE_INSN
opt_newarray_send
(rb_num_t num, rb_num_t method)
@ -1014,6 +1036,9 @@ opt_newarray_send
case VM_OPT_NEWARRAY_SEND_MAX:
val = vm_opt_newarray_max(ec, num, STACK_ADDR_FROM_TOP(num));
break;
case VM_OPT_NEWARRAY_SEND_INCLUDE_P:
val = vm_opt_newarray_include_p(ec, (long)num-1, STACK_ADDR_FROM_TOP(num), TOPN(0));
break;
case VM_OPT_NEWARRAY_SEND_PACK:
val = vm_opt_newarray_pack_buffer(ec, (long)num-1, STACK_ADDR_FROM_TOP(num), TOPN(0), Qundef);
break;

View File

@ -38,6 +38,7 @@ enum ruby_basic_operators {
BOP_CMP,
BOP_DEFAULT,
BOP_PACK,
BOP_INCLUDE_P,
BOP_LAST_
};

View File

@ -1114,6 +1114,33 @@ class TestArray < Test::Unit::TestCase
assert_not_include(a, [1,2])
end
def test_monkey_patch_include?
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}", timeout: 30)
begin;
$-w = false
class Array
alias :old_include? :include?
def include? x
return true if x == :always
old_include?(x)
end
end
def test
a, c, always = :a, :c, :always
[
[:a, :b].include?(a),
[:a, :b].include?(c),
[:a, :b].include?(always),
]
end
v = test
class Array
alias :include? :old_include?
end
assert_equal [true, false, true], v
end;
end
def test_intersect?
a = @cls[ 1, 2, 3]
assert_send([a, :intersect?, [3]])

View File

@ -1107,4 +1107,113 @@ class TestRubyOptimization < Test::Unit::TestCase
def o.to_s; 1; end
assert_match %r{\A#<Object:0x[0-9a-f]+>\z}, "#{o}"
end
def test_opt_duparray_send_include_p
[
'x = :b; [:a, :b].include?(x)',
'@c = :b; [:a, :b].include?(@c)',
'@c = "b"; %i[a b].include?(@c.to_sym)',
'[:a, :b].include?(self) == false',
].each do |code|
iseq = RubyVM::InstructionSequence.compile(code)
insn = iseq.disasm
assert_match(/opt_duparray_send/, insn)
assert_no_match(/\bduparray\b/, insn)
assert_equal(true, eval(code))
end
x, y = :b, :c
assert_equal(true, [:a, :b].include?(x))
assert_equal(false, [:a, :b].include?(y))
assert_in_out_err([], <<~RUBY, ["1,2", "3,3", "1,2", "4,4"])
class Array
prepend(Module.new do
def include?(i)
puts self.join(",")
# Modify self to prove that we are operating on a copy.
map! { i }
puts self.join(",")
end
end)
end
def x(i)
[1, 2].include?(i)
end
x(3)
x(4)
RUBY
# Ensure raises happen correctly.
assert_in_out_err([], <<~RUBY, ["will raise", "int 1 not 3"])
class Integer
undef_method :==
def == x
raise "int \#{self} not \#{x}"
end
end
x = 3
puts "will raise"
begin
p [1, 2].include?(x)
rescue
puts $!
end
RUBY
end
def test_opt_newarray_send_include_p
[
'b = :b; [:a, b].include?(:b)',
# Use Object.new to ensure that we get newarray rather than duparray.
'value = 1; [Object.new, true, "true", 1].include?(value)',
'value = 1; [Object.new, "1"].include?(value.to_s)',
'[Object.new, "1"].include?(self) == false',
].each do |code|
iseq = RubyVM::InstructionSequence.compile(code)
insn = iseq.disasm
assert_match(/opt_newarray_send/, insn)
assert_no_match(/\bnewarray\b/, insn)
assert_equal(true, eval(code))
end
x, y = :b, :c
assert_equal(true, [:a, x].include?(x))
assert_equal(false, [:a, x].include?(y))
assert_in_out_err([], <<~RUBY, ["1,3", "3,3", "1,4", "4,4"])
class Array
prepend(Module.new do
def include?(i)
puts self.join(",")
# Modify self to prove that we are operating on a copy.
map! { i }
puts self.join(",")
end
end)
end
def x(i)
[1, i].include?(i)
end
x(3)
x(4)
RUBY
# Ensure raises happen correctly.
assert_in_out_err([], <<~RUBY, ["will raise", "int 1 not 3"])
class Integer
undef_method :==
def == x
raise "int \#{self} not \#{x}"
end
end
x = 3
puts "will raise"
begin
p [1, x].include?(x)
rescue
puts $!
end
RUBY
end
end

1
vm.c
View File

@ -2263,6 +2263,7 @@ vm_init_redefined_flag(void)
OP(NilP, NIL_P), (C(NilClass));
OP(Cmp, CMP), (C(Integer), C(Float), C(String));
OP(Default, DEFAULT), (C(Hash));
OP(IncludeP, INCLUDE_P), (C(Array));
#undef C
#undef OP
}

View File

@ -1313,6 +1313,7 @@ enum vm_opt_newarray_send_type {
VM_OPT_NEWARRAY_SEND_HASH = 3,
VM_OPT_NEWARRAY_SEND_PACK = 4,
VM_OPT_NEWARRAY_SEND_PACK_BUFFER = 5,
VM_OPT_NEWARRAY_SEND_INCLUDE_P = 6,
};
enum vm_special_object_type {

View File

@ -6158,6 +6158,29 @@ vm_opt_str_freeze(VALUE str, int bop, ID id)
/* this macro is mandatory to use OPTIMIZED_CMP. What a design! */
#define id_cmp idCmp
static VALUE
vm_opt_duparray_include_p(rb_execution_context_t *ec, const VALUE ary, VALUE target)
{
if (BASIC_OP_UNREDEFINED_P(BOP_INCLUDE_P, ARRAY_REDEFINED_OP_FLAG)) {
return rb_ary_includes(ary, target);
}
else {
VALUE args[1] = {target};
// duparray
RUBY_DTRACE_CREATE_HOOK(ARRAY, RARRAY_LEN(ary));
VALUE dupary = rb_ary_resurrect(ary);
return rb_vm_call_with_refinements(ec, dupary, idIncludeP, 1, args, RB_NO_KEYWORDS);
}
}
VALUE
rb_vm_opt_duparray_include_p(rb_execution_context_t *ec, const VALUE ary, VALUE target)
{
return vm_opt_duparray_include_p(ec, ary, target);
}
static VALUE
vm_opt_newarray_max(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr)
{
@ -6239,6 +6262,26 @@ rb_vm_opt_newarray_hash(rb_execution_context_t *ec, rb_num_t num, const VALUE *p
VALUE rb_setup_fake_ary(struct RArray *fake_ary, const VALUE *list, long len);
VALUE rb_ec_pack_ary(rb_execution_context_t *ec, VALUE ary, VALUE fmt, VALUE buffer);
static VALUE
vm_opt_newarray_include_p(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr, VALUE target)
{
if (BASIC_OP_UNREDEFINED_P(BOP_INCLUDE_P, ARRAY_REDEFINED_OP_FLAG)) {
struct RArray fake_ary;
VALUE ary = rb_setup_fake_ary(&fake_ary, ptr, num);
return rb_ary_includes(ary, target);
}
else {
VALUE args[1] = {target};
return rb_vm_call_with_refinements(ec, rb_ary_new4(num, ptr), idIncludeP, 1, args, RB_NO_KEYWORDS);
}
}
VALUE
rb_vm_opt_newarray_include_p(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr, VALUE target)
{
return vm_opt_newarray_include_p(ec, num, ptr, target);
}
static VALUE
vm_opt_newarray_pack_buffer(rb_execution_context_t *ec, rb_num_t num, const VALUE *ptr, VALUE fmt, VALUE buffer)
{

View File

@ -4306,6 +4306,53 @@ fn gen_opt_newarray_max(
Some(KeepCompiling)
}
fn gen_opt_duparray_send(
jit: &mut JITState,
asm: &mut Assembler,
) -> Option<CodegenStatus> {
let method = jit.get_arg(1).as_u64();
if method == ID!(include_p) {
gen_opt_duparray_send_include_p(jit, asm)
} else {
None
}
}
fn gen_opt_duparray_send_include_p(
jit: &mut JITState,
asm: &mut Assembler,
) -> Option<CodegenStatus> {
asm_comment!(asm, "opt_duparray_send include_p");
let ary = jit.get_arg(0);
let argc = jit.get_arg(2).as_usize();
// Save the PC and SP because we may call #include?
jit_prepare_non_leaf_call(jit, asm);
extern "C" {
fn rb_vm_opt_duparray_include_p(ec: EcPtr, ary: VALUE, target: VALUE) -> VALUE;
}
let target = asm.ctx.sp_opnd(-1);
let val_opnd = asm.ccall(
rb_vm_opt_duparray_include_p as *const u8,
vec![
EC,
ary.into(),
target,
],
);
asm.stack_pop(argc);
let stack_ret = asm.stack_push(Type::Unknown);
asm.mov(stack_ret, val_opnd);
Some(KeepCompiling)
}
fn gen_opt_newarray_send(
jit: &mut JITState,
asm: &mut Assembler,
@ -4318,6 +4365,8 @@ fn gen_opt_newarray_send(
gen_opt_newarray_max(jit, asm)
} else if method == VM_OPT_NEWARRAY_SEND_HASH {
gen_opt_newarray_hash(jit, asm)
} else if method == VM_OPT_NEWARRAY_SEND_INCLUDE_P {
gen_opt_newarray_include_p(jit, asm)
} else if method == VM_OPT_NEWARRAY_SEND_PACK {
gen_opt_newarray_pack_buffer(jit, asm, 1, None)
} else if method == VM_OPT_NEWARRAY_SEND_PACK_BUFFER {
@ -4403,6 +4452,42 @@ fn gen_opt_newarray_hash(
Some(KeepCompiling)
}
fn gen_opt_newarray_include_p(
jit: &mut JITState,
asm: &mut Assembler,
) -> Option<CodegenStatus> {
asm_comment!(asm, "opt_newarray_send include?");
let num = jit.get_arg(0).as_u32();
// Save the PC and SP because we may call customized methods.
jit_prepare_non_leaf_call(jit, asm);
extern "C" {
fn rb_vm_opt_newarray_include_p(ec: EcPtr, num: u32, elts: *const VALUE, target: VALUE) -> VALUE;
}
let values_opnd = asm.ctx.sp_opnd(-(num as i32));
let values_ptr = asm.lea(values_opnd);
let target = asm.ctx.sp_opnd(-1);
let val_opnd = asm.ccall(
rb_vm_opt_newarray_include_p as *const u8,
vec![
EC,
(num - 1).into(),
values_ptr,
target
],
);
asm.stack_pop(num.as_usize());
let stack_ret = asm.stack_push(Type::Unknown);
asm.mov(stack_ret, val_opnd);
Some(KeepCompiling)
}
fn gen_opt_newarray_min(
jit: &mut JITState,
asm: &mut Assembler,
@ -10466,6 +10551,7 @@ fn get_gen_fn(opcode: VALUE) -> Option<InsnGenFn> {
YARVINSN_opt_hash_freeze => Some(gen_opt_hash_freeze),
YARVINSN_opt_str_freeze => Some(gen_opt_str_freeze),
YARVINSN_opt_str_uminus => Some(gen_opt_str_uminus),
YARVINSN_opt_duparray_send => Some(gen_opt_duparray_send),
YARVINSN_opt_newarray_send => Some(gen_opt_newarray_send),
YARVINSN_splatarray => Some(gen_splatarray),
YARVINSN_splatkw => Some(gen_splatkw),

View File

@ -824,6 +824,7 @@ pub(crate) mod ids {
name: respond_to_missing content: b"respond_to_missing?"
name: to_ary content: b"to_ary"
name: eq content: b"=="
name: include_p content: b"include?"
}
}

View File

@ -343,7 +343,8 @@ 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_PACK: ruby_basic_operators = 32;
pub const BOP_LAST_: ruby_basic_operators = 33;
pub const BOP_INCLUDE_P: ruby_basic_operators = 33;
pub const BOP_LAST_: ruby_basic_operators = 34;
pub type ruby_basic_operators = u32;
pub type rb_serial_t = ::std::os::raw::c_ulonglong;
pub const imemo_env: imemo_type = 0;
@ -607,6 +608,7 @@ pub const VM_OPT_NEWARRAY_SEND_MIN: vm_opt_newarray_send_type = 2;
pub const VM_OPT_NEWARRAY_SEND_HASH: vm_opt_newarray_send_type = 3;
pub const VM_OPT_NEWARRAY_SEND_PACK: vm_opt_newarray_send_type = 4;
pub const VM_OPT_NEWARRAY_SEND_PACK_BUFFER: vm_opt_newarray_send_type = 5;
pub const VM_OPT_NEWARRAY_SEND_INCLUDE_P: vm_opt_newarray_send_type = 6;
pub type vm_opt_newarray_send_type = u32;
pub const VM_SPECIAL_OBJECT_VMCORE: vm_special_object_type = 1;
pub const VM_SPECIAL_OBJECT_CBASE: vm_special_object_type = 2;
@ -789,161 +791,163 @@ pub const YARVINSN_opt_hash_freeze: ruby_vminsn_type = 60;
pub const YARVINSN_opt_str_freeze: ruby_vminsn_type = 61;
pub const YARVINSN_opt_nil_p: ruby_vminsn_type = 62;
pub const YARVINSN_opt_str_uminus: ruby_vminsn_type = 63;
pub const YARVINSN_opt_newarray_send: ruby_vminsn_type = 64;
pub const YARVINSN_invokesuper: ruby_vminsn_type = 65;
pub const YARVINSN_invokesuperforward: ruby_vminsn_type = 66;
pub const YARVINSN_invokeblock: ruby_vminsn_type = 67;
pub const YARVINSN_leave: ruby_vminsn_type = 68;
pub const YARVINSN_throw: ruby_vminsn_type = 69;
pub const YARVINSN_jump: ruby_vminsn_type = 70;
pub const YARVINSN_branchif: ruby_vminsn_type = 71;
pub const YARVINSN_branchunless: ruby_vminsn_type = 72;
pub const YARVINSN_branchnil: ruby_vminsn_type = 73;
pub const YARVINSN_once: ruby_vminsn_type = 74;
pub const YARVINSN_opt_case_dispatch: ruby_vminsn_type = 75;
pub const YARVINSN_opt_plus: ruby_vminsn_type = 76;
pub const YARVINSN_opt_minus: ruby_vminsn_type = 77;
pub const YARVINSN_opt_mult: ruby_vminsn_type = 78;
pub const YARVINSN_opt_div: ruby_vminsn_type = 79;
pub const YARVINSN_opt_mod: ruby_vminsn_type = 80;
pub const YARVINSN_opt_eq: ruby_vminsn_type = 81;
pub const YARVINSN_opt_neq: ruby_vminsn_type = 82;
pub const YARVINSN_opt_lt: ruby_vminsn_type = 83;
pub const YARVINSN_opt_le: ruby_vminsn_type = 84;
pub const YARVINSN_opt_gt: ruby_vminsn_type = 85;
pub const YARVINSN_opt_ge: ruby_vminsn_type = 86;
pub const YARVINSN_opt_ltlt: ruby_vminsn_type = 87;
pub const YARVINSN_opt_and: ruby_vminsn_type = 88;
pub const YARVINSN_opt_or: ruby_vminsn_type = 89;
pub const YARVINSN_opt_aref: ruby_vminsn_type = 90;
pub const YARVINSN_opt_aset: ruby_vminsn_type = 91;
pub const YARVINSN_opt_aset_with: ruby_vminsn_type = 92;
pub const YARVINSN_opt_aref_with: ruby_vminsn_type = 93;
pub const YARVINSN_opt_length: ruby_vminsn_type = 94;
pub const YARVINSN_opt_size: ruby_vminsn_type = 95;
pub const YARVINSN_opt_empty_p: ruby_vminsn_type = 96;
pub const YARVINSN_opt_succ: ruby_vminsn_type = 97;
pub const YARVINSN_opt_not: ruby_vminsn_type = 98;
pub const YARVINSN_opt_regexpmatch2: ruby_vminsn_type = 99;
pub const YARVINSN_invokebuiltin: ruby_vminsn_type = 100;
pub const YARVINSN_opt_invokebuiltin_delegate: ruby_vminsn_type = 101;
pub const YARVINSN_opt_invokebuiltin_delegate_leave: ruby_vminsn_type = 102;
pub const YARVINSN_getlocal_WC_0: ruby_vminsn_type = 103;
pub const YARVINSN_getlocal_WC_1: ruby_vminsn_type = 104;
pub const YARVINSN_setlocal_WC_0: ruby_vminsn_type = 105;
pub const YARVINSN_setlocal_WC_1: ruby_vminsn_type = 106;
pub const YARVINSN_putobject_INT2FIX_0_: ruby_vminsn_type = 107;
pub const YARVINSN_putobject_INT2FIX_1_: ruby_vminsn_type = 108;
pub const YARVINSN_trace_nop: ruby_vminsn_type = 109;
pub const YARVINSN_trace_getlocal: ruby_vminsn_type = 110;
pub const YARVINSN_trace_setlocal: ruby_vminsn_type = 111;
pub const YARVINSN_trace_getblockparam: ruby_vminsn_type = 112;
pub const YARVINSN_trace_setblockparam: ruby_vminsn_type = 113;
pub const YARVINSN_trace_getblockparamproxy: ruby_vminsn_type = 114;
pub const YARVINSN_trace_getspecial: ruby_vminsn_type = 115;
pub const YARVINSN_trace_setspecial: ruby_vminsn_type = 116;
pub const YARVINSN_trace_getinstancevariable: ruby_vminsn_type = 117;
pub const YARVINSN_trace_setinstancevariable: ruby_vminsn_type = 118;
pub const YARVINSN_trace_getclassvariable: ruby_vminsn_type = 119;
pub const YARVINSN_trace_setclassvariable: ruby_vminsn_type = 120;
pub const YARVINSN_trace_opt_getconstant_path: ruby_vminsn_type = 121;
pub const YARVINSN_trace_getconstant: ruby_vminsn_type = 122;
pub const YARVINSN_trace_setconstant: ruby_vminsn_type = 123;
pub const YARVINSN_trace_getglobal: ruby_vminsn_type = 124;
pub const YARVINSN_trace_setglobal: ruby_vminsn_type = 125;
pub const YARVINSN_trace_putnil: ruby_vminsn_type = 126;
pub const YARVINSN_trace_putself: ruby_vminsn_type = 127;
pub const YARVINSN_trace_putobject: ruby_vminsn_type = 128;
pub const YARVINSN_trace_putspecialobject: ruby_vminsn_type = 129;
pub const YARVINSN_trace_putstring: ruby_vminsn_type = 130;
pub const YARVINSN_trace_putchilledstring: ruby_vminsn_type = 131;
pub const YARVINSN_trace_concatstrings: ruby_vminsn_type = 132;
pub const YARVINSN_trace_anytostring: ruby_vminsn_type = 133;
pub const YARVINSN_trace_toregexp: ruby_vminsn_type = 134;
pub const YARVINSN_trace_intern: ruby_vminsn_type = 135;
pub const YARVINSN_trace_newarray: ruby_vminsn_type = 136;
pub const YARVINSN_trace_pushtoarraykwsplat: ruby_vminsn_type = 137;
pub const YARVINSN_trace_duparray: ruby_vminsn_type = 138;
pub const YARVINSN_trace_duphash: ruby_vminsn_type = 139;
pub const YARVINSN_trace_expandarray: ruby_vminsn_type = 140;
pub const YARVINSN_trace_concatarray: ruby_vminsn_type = 141;
pub const YARVINSN_trace_concattoarray: ruby_vminsn_type = 142;
pub const YARVINSN_trace_pushtoarray: ruby_vminsn_type = 143;
pub const YARVINSN_trace_splatarray: ruby_vminsn_type = 144;
pub const YARVINSN_trace_splatkw: ruby_vminsn_type = 145;
pub const YARVINSN_trace_newhash: ruby_vminsn_type = 146;
pub const YARVINSN_trace_newrange: ruby_vminsn_type = 147;
pub const YARVINSN_trace_pop: ruby_vminsn_type = 148;
pub const YARVINSN_trace_dup: ruby_vminsn_type = 149;
pub const YARVINSN_trace_dupn: ruby_vminsn_type = 150;
pub const YARVINSN_trace_swap: ruby_vminsn_type = 151;
pub const YARVINSN_trace_opt_reverse: ruby_vminsn_type = 152;
pub const YARVINSN_trace_topn: ruby_vminsn_type = 153;
pub const YARVINSN_trace_setn: ruby_vminsn_type = 154;
pub const YARVINSN_trace_adjuststack: ruby_vminsn_type = 155;
pub const YARVINSN_trace_defined: ruby_vminsn_type = 156;
pub const YARVINSN_trace_definedivar: ruby_vminsn_type = 157;
pub const YARVINSN_trace_checkmatch: ruby_vminsn_type = 158;
pub const YARVINSN_trace_checkkeyword: ruby_vminsn_type = 159;
pub const YARVINSN_trace_checktype: ruby_vminsn_type = 160;
pub const YARVINSN_trace_defineclass: ruby_vminsn_type = 161;
pub const YARVINSN_trace_definemethod: ruby_vminsn_type = 162;
pub const YARVINSN_trace_definesmethod: ruby_vminsn_type = 163;
pub const YARVINSN_trace_send: ruby_vminsn_type = 164;
pub const YARVINSN_trace_sendforward: ruby_vminsn_type = 165;
pub const YARVINSN_trace_opt_send_without_block: ruby_vminsn_type = 166;
pub const YARVINSN_trace_objtostring: ruby_vminsn_type = 167;
pub const YARVINSN_trace_opt_ary_freeze: ruby_vminsn_type = 168;
pub const YARVINSN_trace_opt_hash_freeze: ruby_vminsn_type = 169;
pub const YARVINSN_trace_opt_str_freeze: ruby_vminsn_type = 170;
pub const YARVINSN_trace_opt_nil_p: ruby_vminsn_type = 171;
pub const YARVINSN_trace_opt_str_uminus: ruby_vminsn_type = 172;
pub const YARVINSN_trace_opt_newarray_send: ruby_vminsn_type = 173;
pub const YARVINSN_trace_invokesuper: ruby_vminsn_type = 174;
pub const YARVINSN_trace_invokesuperforward: ruby_vminsn_type = 175;
pub const YARVINSN_trace_invokeblock: ruby_vminsn_type = 176;
pub const YARVINSN_trace_leave: ruby_vminsn_type = 177;
pub const YARVINSN_trace_throw: ruby_vminsn_type = 178;
pub const YARVINSN_trace_jump: ruby_vminsn_type = 179;
pub const YARVINSN_trace_branchif: ruby_vminsn_type = 180;
pub const YARVINSN_trace_branchunless: ruby_vminsn_type = 181;
pub const YARVINSN_trace_branchnil: ruby_vminsn_type = 182;
pub const YARVINSN_trace_once: ruby_vminsn_type = 183;
pub const YARVINSN_trace_opt_case_dispatch: ruby_vminsn_type = 184;
pub const YARVINSN_trace_opt_plus: ruby_vminsn_type = 185;
pub const YARVINSN_trace_opt_minus: ruby_vminsn_type = 186;
pub const YARVINSN_trace_opt_mult: ruby_vminsn_type = 187;
pub const YARVINSN_trace_opt_div: ruby_vminsn_type = 188;
pub const YARVINSN_trace_opt_mod: ruby_vminsn_type = 189;
pub const YARVINSN_trace_opt_eq: ruby_vminsn_type = 190;
pub const YARVINSN_trace_opt_neq: ruby_vminsn_type = 191;
pub const YARVINSN_trace_opt_lt: ruby_vminsn_type = 192;
pub const YARVINSN_trace_opt_le: ruby_vminsn_type = 193;
pub const YARVINSN_trace_opt_gt: ruby_vminsn_type = 194;
pub const YARVINSN_trace_opt_ge: ruby_vminsn_type = 195;
pub const YARVINSN_trace_opt_ltlt: ruby_vminsn_type = 196;
pub const YARVINSN_trace_opt_and: ruby_vminsn_type = 197;
pub const YARVINSN_trace_opt_or: ruby_vminsn_type = 198;
pub const YARVINSN_trace_opt_aref: ruby_vminsn_type = 199;
pub const YARVINSN_trace_opt_aset: ruby_vminsn_type = 200;
pub const YARVINSN_trace_opt_aset_with: ruby_vminsn_type = 201;
pub const YARVINSN_trace_opt_aref_with: ruby_vminsn_type = 202;
pub const YARVINSN_trace_opt_length: ruby_vminsn_type = 203;
pub const YARVINSN_trace_opt_size: ruby_vminsn_type = 204;
pub const YARVINSN_trace_opt_empty_p: ruby_vminsn_type = 205;
pub const YARVINSN_trace_opt_succ: ruby_vminsn_type = 206;
pub const YARVINSN_trace_opt_not: ruby_vminsn_type = 207;
pub const YARVINSN_trace_opt_regexpmatch2: ruby_vminsn_type = 208;
pub const YARVINSN_trace_invokebuiltin: ruby_vminsn_type = 209;
pub const YARVINSN_trace_opt_invokebuiltin_delegate: ruby_vminsn_type = 210;
pub const YARVINSN_trace_opt_invokebuiltin_delegate_leave: ruby_vminsn_type = 211;
pub const YARVINSN_trace_getlocal_WC_0: ruby_vminsn_type = 212;
pub const YARVINSN_trace_getlocal_WC_1: ruby_vminsn_type = 213;
pub const YARVINSN_trace_setlocal_WC_0: ruby_vminsn_type = 214;
pub const YARVINSN_trace_setlocal_WC_1: ruby_vminsn_type = 215;
pub const YARVINSN_trace_putobject_INT2FIX_0_: ruby_vminsn_type = 216;
pub const YARVINSN_trace_putobject_INT2FIX_1_: ruby_vminsn_type = 217;
pub const VM_INSTRUCTION_SIZE: ruby_vminsn_type = 218;
pub const YARVINSN_opt_duparray_send: ruby_vminsn_type = 64;
pub const YARVINSN_opt_newarray_send: ruby_vminsn_type = 65;
pub const YARVINSN_invokesuper: ruby_vminsn_type = 66;
pub const YARVINSN_invokesuperforward: ruby_vminsn_type = 67;
pub const YARVINSN_invokeblock: ruby_vminsn_type = 68;
pub const YARVINSN_leave: ruby_vminsn_type = 69;
pub const YARVINSN_throw: ruby_vminsn_type = 70;
pub const YARVINSN_jump: ruby_vminsn_type = 71;
pub const YARVINSN_branchif: ruby_vminsn_type = 72;
pub const YARVINSN_branchunless: ruby_vminsn_type = 73;
pub const YARVINSN_branchnil: ruby_vminsn_type = 74;
pub const YARVINSN_once: ruby_vminsn_type = 75;
pub const YARVINSN_opt_case_dispatch: ruby_vminsn_type = 76;
pub const YARVINSN_opt_plus: ruby_vminsn_type = 77;
pub const YARVINSN_opt_minus: ruby_vminsn_type = 78;
pub const YARVINSN_opt_mult: ruby_vminsn_type = 79;
pub const YARVINSN_opt_div: ruby_vminsn_type = 80;
pub const YARVINSN_opt_mod: ruby_vminsn_type = 81;
pub const YARVINSN_opt_eq: ruby_vminsn_type = 82;
pub const YARVINSN_opt_neq: ruby_vminsn_type = 83;
pub const YARVINSN_opt_lt: ruby_vminsn_type = 84;
pub const YARVINSN_opt_le: ruby_vminsn_type = 85;
pub const YARVINSN_opt_gt: ruby_vminsn_type = 86;
pub const YARVINSN_opt_ge: ruby_vminsn_type = 87;
pub const YARVINSN_opt_ltlt: ruby_vminsn_type = 88;
pub const YARVINSN_opt_and: ruby_vminsn_type = 89;
pub const YARVINSN_opt_or: ruby_vminsn_type = 90;
pub const YARVINSN_opt_aref: ruby_vminsn_type = 91;
pub const YARVINSN_opt_aset: ruby_vminsn_type = 92;
pub const YARVINSN_opt_aset_with: ruby_vminsn_type = 93;
pub const YARVINSN_opt_aref_with: ruby_vminsn_type = 94;
pub const YARVINSN_opt_length: ruby_vminsn_type = 95;
pub const YARVINSN_opt_size: ruby_vminsn_type = 96;
pub const YARVINSN_opt_empty_p: ruby_vminsn_type = 97;
pub const YARVINSN_opt_succ: ruby_vminsn_type = 98;
pub const YARVINSN_opt_not: ruby_vminsn_type = 99;
pub const YARVINSN_opt_regexpmatch2: ruby_vminsn_type = 100;
pub const YARVINSN_invokebuiltin: ruby_vminsn_type = 101;
pub const YARVINSN_opt_invokebuiltin_delegate: ruby_vminsn_type = 102;
pub const YARVINSN_opt_invokebuiltin_delegate_leave: ruby_vminsn_type = 103;
pub const YARVINSN_getlocal_WC_0: ruby_vminsn_type = 104;
pub const YARVINSN_getlocal_WC_1: ruby_vminsn_type = 105;
pub const YARVINSN_setlocal_WC_0: ruby_vminsn_type = 106;
pub const YARVINSN_setlocal_WC_1: ruby_vminsn_type = 107;
pub const YARVINSN_putobject_INT2FIX_0_: ruby_vminsn_type = 108;
pub const YARVINSN_putobject_INT2FIX_1_: ruby_vminsn_type = 109;
pub const YARVINSN_trace_nop: ruby_vminsn_type = 110;
pub const YARVINSN_trace_getlocal: ruby_vminsn_type = 111;
pub const YARVINSN_trace_setlocal: ruby_vminsn_type = 112;
pub const YARVINSN_trace_getblockparam: ruby_vminsn_type = 113;
pub const YARVINSN_trace_setblockparam: ruby_vminsn_type = 114;
pub const YARVINSN_trace_getblockparamproxy: ruby_vminsn_type = 115;
pub const YARVINSN_trace_getspecial: ruby_vminsn_type = 116;
pub const YARVINSN_trace_setspecial: ruby_vminsn_type = 117;
pub const YARVINSN_trace_getinstancevariable: ruby_vminsn_type = 118;
pub const YARVINSN_trace_setinstancevariable: ruby_vminsn_type = 119;
pub const YARVINSN_trace_getclassvariable: ruby_vminsn_type = 120;
pub const YARVINSN_trace_setclassvariable: ruby_vminsn_type = 121;
pub const YARVINSN_trace_opt_getconstant_path: ruby_vminsn_type = 122;
pub const YARVINSN_trace_getconstant: ruby_vminsn_type = 123;
pub const YARVINSN_trace_setconstant: ruby_vminsn_type = 124;
pub const YARVINSN_trace_getglobal: ruby_vminsn_type = 125;
pub const YARVINSN_trace_setglobal: ruby_vminsn_type = 126;
pub const YARVINSN_trace_putnil: ruby_vminsn_type = 127;
pub const YARVINSN_trace_putself: ruby_vminsn_type = 128;
pub const YARVINSN_trace_putobject: ruby_vminsn_type = 129;
pub const YARVINSN_trace_putspecialobject: ruby_vminsn_type = 130;
pub const YARVINSN_trace_putstring: ruby_vminsn_type = 131;
pub const YARVINSN_trace_putchilledstring: ruby_vminsn_type = 132;
pub const YARVINSN_trace_concatstrings: ruby_vminsn_type = 133;
pub const YARVINSN_trace_anytostring: ruby_vminsn_type = 134;
pub const YARVINSN_trace_toregexp: ruby_vminsn_type = 135;
pub const YARVINSN_trace_intern: ruby_vminsn_type = 136;
pub const YARVINSN_trace_newarray: ruby_vminsn_type = 137;
pub const YARVINSN_trace_pushtoarraykwsplat: ruby_vminsn_type = 138;
pub const YARVINSN_trace_duparray: ruby_vminsn_type = 139;
pub const YARVINSN_trace_duphash: ruby_vminsn_type = 140;
pub const YARVINSN_trace_expandarray: ruby_vminsn_type = 141;
pub const YARVINSN_trace_concatarray: ruby_vminsn_type = 142;
pub const YARVINSN_trace_concattoarray: ruby_vminsn_type = 143;
pub const YARVINSN_trace_pushtoarray: ruby_vminsn_type = 144;
pub const YARVINSN_trace_splatarray: ruby_vminsn_type = 145;
pub const YARVINSN_trace_splatkw: ruby_vminsn_type = 146;
pub const YARVINSN_trace_newhash: ruby_vminsn_type = 147;
pub const YARVINSN_trace_newrange: ruby_vminsn_type = 148;
pub const YARVINSN_trace_pop: ruby_vminsn_type = 149;
pub const YARVINSN_trace_dup: ruby_vminsn_type = 150;
pub const YARVINSN_trace_dupn: ruby_vminsn_type = 151;
pub const YARVINSN_trace_swap: ruby_vminsn_type = 152;
pub const YARVINSN_trace_opt_reverse: ruby_vminsn_type = 153;
pub const YARVINSN_trace_topn: ruby_vminsn_type = 154;
pub const YARVINSN_trace_setn: ruby_vminsn_type = 155;
pub const YARVINSN_trace_adjuststack: ruby_vminsn_type = 156;
pub const YARVINSN_trace_defined: ruby_vminsn_type = 157;
pub const YARVINSN_trace_definedivar: ruby_vminsn_type = 158;
pub const YARVINSN_trace_checkmatch: ruby_vminsn_type = 159;
pub const YARVINSN_trace_checkkeyword: ruby_vminsn_type = 160;
pub const YARVINSN_trace_checktype: ruby_vminsn_type = 161;
pub const YARVINSN_trace_defineclass: ruby_vminsn_type = 162;
pub const YARVINSN_trace_definemethod: ruby_vminsn_type = 163;
pub const YARVINSN_trace_definesmethod: ruby_vminsn_type = 164;
pub const YARVINSN_trace_send: ruby_vminsn_type = 165;
pub const YARVINSN_trace_sendforward: ruby_vminsn_type = 166;
pub const YARVINSN_trace_opt_send_without_block: ruby_vminsn_type = 167;
pub const YARVINSN_trace_objtostring: ruby_vminsn_type = 168;
pub const YARVINSN_trace_opt_ary_freeze: ruby_vminsn_type = 169;
pub const YARVINSN_trace_opt_hash_freeze: ruby_vminsn_type = 170;
pub const YARVINSN_trace_opt_str_freeze: ruby_vminsn_type = 171;
pub const YARVINSN_trace_opt_nil_p: ruby_vminsn_type = 172;
pub const YARVINSN_trace_opt_str_uminus: ruby_vminsn_type = 173;
pub const YARVINSN_trace_opt_duparray_send: ruby_vminsn_type = 174;
pub const YARVINSN_trace_opt_newarray_send: ruby_vminsn_type = 175;
pub const YARVINSN_trace_invokesuper: ruby_vminsn_type = 176;
pub const YARVINSN_trace_invokesuperforward: ruby_vminsn_type = 177;
pub const YARVINSN_trace_invokeblock: ruby_vminsn_type = 178;
pub const YARVINSN_trace_leave: ruby_vminsn_type = 179;
pub const YARVINSN_trace_throw: ruby_vminsn_type = 180;
pub const YARVINSN_trace_jump: ruby_vminsn_type = 181;
pub const YARVINSN_trace_branchif: ruby_vminsn_type = 182;
pub const YARVINSN_trace_branchunless: ruby_vminsn_type = 183;
pub const YARVINSN_trace_branchnil: ruby_vminsn_type = 184;
pub const YARVINSN_trace_once: ruby_vminsn_type = 185;
pub const YARVINSN_trace_opt_case_dispatch: ruby_vminsn_type = 186;
pub const YARVINSN_trace_opt_plus: ruby_vminsn_type = 187;
pub const YARVINSN_trace_opt_minus: ruby_vminsn_type = 188;
pub const YARVINSN_trace_opt_mult: ruby_vminsn_type = 189;
pub const YARVINSN_trace_opt_div: ruby_vminsn_type = 190;
pub const YARVINSN_trace_opt_mod: ruby_vminsn_type = 191;
pub const YARVINSN_trace_opt_eq: ruby_vminsn_type = 192;
pub const YARVINSN_trace_opt_neq: ruby_vminsn_type = 193;
pub const YARVINSN_trace_opt_lt: ruby_vminsn_type = 194;
pub const YARVINSN_trace_opt_le: ruby_vminsn_type = 195;
pub const YARVINSN_trace_opt_gt: ruby_vminsn_type = 196;
pub const YARVINSN_trace_opt_ge: ruby_vminsn_type = 197;
pub const YARVINSN_trace_opt_ltlt: ruby_vminsn_type = 198;
pub const YARVINSN_trace_opt_and: ruby_vminsn_type = 199;
pub const YARVINSN_trace_opt_or: ruby_vminsn_type = 200;
pub const YARVINSN_trace_opt_aref: ruby_vminsn_type = 201;
pub const YARVINSN_trace_opt_aset: ruby_vminsn_type = 202;
pub const YARVINSN_trace_opt_aset_with: ruby_vminsn_type = 203;
pub const YARVINSN_trace_opt_aref_with: ruby_vminsn_type = 204;
pub const YARVINSN_trace_opt_length: ruby_vminsn_type = 205;
pub const YARVINSN_trace_opt_size: ruby_vminsn_type = 206;
pub const YARVINSN_trace_opt_empty_p: ruby_vminsn_type = 207;
pub const YARVINSN_trace_opt_succ: ruby_vminsn_type = 208;
pub const YARVINSN_trace_opt_not: ruby_vminsn_type = 209;
pub const YARVINSN_trace_opt_regexpmatch2: ruby_vminsn_type = 210;
pub const YARVINSN_trace_invokebuiltin: ruby_vminsn_type = 211;
pub const YARVINSN_trace_opt_invokebuiltin_delegate: ruby_vminsn_type = 212;
pub const YARVINSN_trace_opt_invokebuiltin_delegate_leave: ruby_vminsn_type = 213;
pub const YARVINSN_trace_getlocal_WC_0: ruby_vminsn_type = 214;
pub const YARVINSN_trace_getlocal_WC_1: ruby_vminsn_type = 215;
pub const YARVINSN_trace_setlocal_WC_0: ruby_vminsn_type = 216;
pub const YARVINSN_trace_setlocal_WC_1: ruby_vminsn_type = 217;
pub const YARVINSN_trace_putobject_INT2FIX_0_: ruby_vminsn_type = 218;
pub const YARVINSN_trace_putobject_INT2FIX_1_: ruby_vminsn_type = 219;
pub const VM_INSTRUCTION_SIZE: ruby_vminsn_type = 220;
pub type ruby_vminsn_type = u32;
pub type rb_iseq_callback = ::std::option::Option<
unsafe extern "C" fn(arg1: *const rb_iseq_t, arg2: *mut ::std::os::raw::c_void),