summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS.md2
-rw-r--r--compile.c11
-rw-r--r--doc/language/packed_data.rdoc2
-rw-r--r--gems/bundled_gems2
-rw-r--r--iseq.c8
-rw-r--r--lib/prism/node_ext.rb8
-rw-r--r--parse.y9
-rw-r--r--prism/config.yml16
-rw-r--r--prism/prism.c71
-rw-r--r--prism_compile.c49
-rw-r--r--proc.c7
-rw-r--r--rubyparser.h1
-rw-r--r--spec/ruby/core/method/parameters_spec.rb13
-rw-r--r--spec/ruby/core/proc/parameters_spec.rb8
-rw-r--r--spec/ruby/language/block_spec.rb11
-rw-r--r--spec/ruby/language/method_spec.rb12
-rw-r--r--test/prism/errors/unterminated_heredoc_and_embexpr.txt11
-rw-r--r--test/prism/errors/unterminated_heredoc_and_embexpr_2.txt9
-rw-r--r--test/prism/errors_test.rb22
-rw-r--r--test/prism/lex_test.rb53
-rw-r--r--test/prism/result/source_location_test.rb4
-rw-r--r--test/prism/ruby/parameters_signature_test.rb4
-rw-r--r--test/ruby/test_iseq.rb11
-rw-r--r--test/ruby/test_method.rb6
-rw-r--r--test/ruby/test_syntax.rb43
-rw-r--r--vm_args.c23
-rw-r--r--vm_core.h1
-rw-r--r--vm_insnhelper.c9
-rw-r--r--zjit/src/codegen.rs4
-rw-r--r--zjit/src/cruby.rs16
-rw-r--r--zjit/src/cruby_bindings.inc.rs38
-rw-r--r--zjit/src/cruby_methods.rs2
-rw-r--r--zjit/src/hir.rs216
-rw-r--r--zjit/src/hir/opt_tests.rs119
-rw-r--r--zjit/src/hir/tests.rs112
35 files changed, 612 insertions, 321 deletions
diff --git a/NEWS.md b/NEWS.md
index b09eadeb05..8125a5c46b 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -69,7 +69,7 @@ releases.
* minitest 6.0.1
* test-unit 3.7.7
* rss 0.3.2
-* net-imap 0.6.2
+* net-imap 0.6.3
* rbs 3.10.3
* typeprof 0.31.1
* debug 1.11.1
diff --git a/compile.c b/compile.c
index 5d6cfb1e16..c9806947fd 100644
--- a/compile.c
+++ b/compile.c
@@ -2096,7 +2096,7 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *cons
if (node_args) {
struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
- struct rb_args_info *args = &RNODE_ARGS(node_args)->nd_ainfo;
+ const struct rb_args_info *const args = &RNODE_ARGS(node_args)->nd_ainfo;
ID rest_id = 0;
int last_comma = 0;
ID block_id = 0;
@@ -2193,7 +2193,10 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *cons
body->param.flags.accepts_no_kwarg = TRUE;
}
- if (block_id) {
+ if (args->no_blockarg) {
+ body->param.flags.accepts_no_block = TRUE;
+ }
+ else if (block_id) {
body->param.block_start = arg_size++;
body->param.flags.has_block = TRUE;
iseq_set_use_block(iseq);
@@ -13678,7 +13681,8 @@ ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
(body->param.flags.anon_rest << 10) |
(body->param.flags.anon_kwrest << 11) |
(body->param.flags.use_block << 12) |
- (body->param.flags.forwardable << 13) ;
+ (body->param.flags.forwardable << 13) |
+ (body->param.flags.accepts_no_block << 14);
#if IBF_ISEQ_ENABLE_LOCAL_BUFFER
# define IBF_BODY_OFFSET(x) (x)
@@ -13898,6 +13902,7 @@ ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
load_body->param.flags.anon_kwrest = (param_flags >> 11) & 1;
load_body->param.flags.use_block = (param_flags >> 12) & 1;
load_body->param.flags.forwardable = (param_flags >> 13) & 1;
+ load_body->param.flags.accepts_no_block = (param_flags >> 14) & 1;
load_body->param.size = param_size;
load_body->param.lead_num = param_lead_num;
load_body->param.opt_num = param_opt_num;
diff --git a/doc/language/packed_data.rdoc b/doc/language/packed_data.rdoc
index 1a6d80bd4e..0c84113643 100644
--- a/doc/language/packed_data.rdoc
+++ b/doc/language/packed_data.rdoc
@@ -726,4 +726,4 @@ for one byte in the input or output string.
- <tt>'^'</tt> - Only for unpacking; the current position:
- "foo\0\0\0".unpack("Z*C") # => ["foo", 6]
+ "foo\0\0\0".unpack("Z*^") # => ["foo", 4]
diff --git a/gems/bundled_gems b/gems/bundled_gems
index 6d79be7a97..6a0f626de9 100644
--- a/gems/bundled_gems
+++ b/gems/bundled_gems
@@ -12,7 +12,7 @@ rake 13.3.1 https://github.com/ruby/rake
test-unit 3.7.7 https://github.com/test-unit/test-unit
rexml 3.4.4 https://github.com/ruby/rexml
rss 0.3.2 https://github.com/ruby/rss
-net-imap 0.6.2 https://github.com/ruby/net-imap d9ae35ef913a45f83387b8444cdce4fb1cbf01af
+net-imap 0.6.3 https://github.com/ruby/net-imap
net-smtp 0.5.1 https://github.com/ruby/net-smtp
matrix 0.4.3 https://github.com/ruby/matrix
prime 0.1.4 https://github.com/ruby/prime
diff --git a/iseq.c b/iseq.c
index c418e17869..648f2c388f 100644
--- a/iseq.c
+++ b/iseq.c
@@ -3787,7 +3787,13 @@ rb_iseq_parameters(const rb_iseq_t *iseq, int is_proc)
}
rb_ary_push(args, a);
}
- if (body->param.flags.has_block) {
+ if (body->param.flags.accepts_no_block) {
+ ID noblock;
+ CONST_ID(noblock, "noblock");
+ PARAM_TYPE(noblock);
+ rb_ary_push(args, a);
+ }
+ else if (body->param.flags.has_block) {
CONST_ID(block, "block");
rb_ary_push(args, PARAM(body->param.block_start, block));
}
diff --git a/lib/prism/node_ext.rb b/lib/prism/node_ext.rb
index 469e54ca0c..1bb3ebcf5f 100644
--- a/lib/prism/node_ext.rb
+++ b/lib/prism/node_ext.rb
@@ -316,7 +316,13 @@ module Prism
names << [:nokey]
end
- names << [:block, block.name || :&] if block
+ case block
+ when BlockParameterNode
+ names << [:block, block.name || :&]
+ when NoBlockParameterNode
+ names << [:noblock]
+ end
+
names
end
end
diff --git a/parse.y b/parse.y
index b874e4f8dc..6e0c610a7c 100644
--- a/parse.y
+++ b/parse.y
@@ -6562,6 +6562,11 @@ f_block_arg : blkarg_mark tIDENTIFIER
$$ = $2;
/*% ripper: blockarg!($:2) %*/
}
+ | blkarg_mark keyword_nil
+ {
+ $$ = idNil;
+ /*% ripper: blockarg!(ID2VAL(idNil)) %*/
+ }
| blkarg_mark
{
arg_var(p, idFWD_BLOCK);
@@ -14474,6 +14479,10 @@ new_args_tail(struct parser_params *p, rb_node_kw_arg_t *kw_args, ID kw_rest_arg
struct rb_args_info *args = &node->nd_ainfo;
if (p->error_p) return node;
+ if (block == idNil) {
+ block = 0;
+ args->no_blockarg = TRUE;
+ }
args->block_arg = block;
args->kw_args = kw_args;
diff --git a/prism/config.yml b/prism/config.yml
index f6e99c66b1..0736f5a0bf 100644
--- a/prism/config.yml
+++ b/prism/config.yml
@@ -3920,6 +3920,18 @@ nodes:
nil
^^^
+ - name: NoBlockParameterNode
+ fields:
+ - name: operator_loc
+ type: location
+ - name: keyword_loc
+ type: location
+ comment: |
+ Represents the use of `&nil` inside method arguments.
+
+ def a(&nil)
+ ^^^^
+ end
- name: NoKeywordsParameterNode
fields:
- name: operator_loc
@@ -4066,7 +4078,9 @@ nodes:
- NoKeywordsParameterNode
- name: block
type: node?
- kind: BlockParameterNode
+ kind:
+ - BlockParameterNode
+ - NoBlockParameterNode
comment: |
Represents the list of parameters on a method, block, or lambda definition.
diff --git a/prism/prism.c b/prism/prism.c
index 34e5d38b0a..81768024f2 100644
--- a/prism/prism.c
+++ b/prism/prism.c
@@ -5561,6 +5561,24 @@ pm_nil_node_create(pm_parser_t *parser, const pm_token_t *token) {
/**
* Allocate and initialize a new NoKeywordsParameterNode node.
*/
+static pm_no_block_parameter_node_t *
+pm_no_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
+ assert(operator->type == PM_TOKEN_AMPERSAND || operator->type == PM_TOKEN_UAMPERSAND);
+ assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
+ pm_no_block_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_no_block_parameter_node_t);
+
+ *node = (pm_no_block_parameter_node_t) {
+ .base = PM_NODE_INIT(parser, PM_NO_BLOCK_PARAMETER_NODE, 0, PM_LOCATION_INIT_TOKENS(parser, operator, keyword)),
+ .operator_loc = TOK2LOC(parser, operator),
+ .keyword_loc = TOK2LOC(parser, keyword)
+ };
+
+ return node;
+}
+
+/**
+ * Allocate and initialize a new NoKeywordsParameterNode node.
+ */
static pm_no_keywords_parameter_node_t *
pm_no_keywords_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
assert(operator->type == PM_TOKEN_USTAR_STAR || operator->type == PM_TOKEN_STAR_STAR);
@@ -5787,9 +5805,9 @@ pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *par
* Set the block parameter on a ParametersNode node.
*/
static void
-pm_parameters_node_block_set(pm_parameters_node_t *params, pm_block_parameter_node_t *param) {
+pm_parameters_node_block_set(pm_parameters_node_t *params, pm_node_t *param) {
assert(params->block == NULL);
- pm_parameters_node_location_set(params, UP(param));
+ pm_parameters_node_location_set(params, param);
params->block = param;
}
@@ -9783,6 +9801,12 @@ parser_lex(pm_parser_t *parser) {
unsigned int semantic_token_seen = parser->semantic_token_seen;
parser->semantic_token_seen = true;
+ // We'll jump to this label when we are about to encounter an EOF.
+ // If we still have lex_modes on the stack, we pop them so that cleanup
+ // can happen. For example, we should still continue parsing after a heredoc
+ // identifier, even if the heredoc body was syntax invalid.
+ switch_lex_modes:
+
switch (parser->lex_modes.current->mode) {
case PM_LEX_DEFAULT:
case PM_LEX_EMBEXPR:
@@ -9856,6 +9880,14 @@ parser_lex(pm_parser_t *parser) {
// We'll check if we're at the end of the file. If we are, then we
// need to return the EOF token.
if (parser->current.end >= parser->end) {
+ // We may be missing closing tokens. We should pop modes one by one
+ // to do the appropriate cleanup like moving next_start for heredocs.
+ // Only when no mode is remaining will we actually emit the EOF token.
+ if (parser->lex_modes.current->mode != PM_LEX_DEFAULT) {
+ lex_mode_pop(parser);
+ goto switch_lex_modes;
+ }
+
// If we hit EOF, but the EOF came immediately after a newline,
// set the start of the token to the newline. This way any EOF
// errors will be reported as happening on that line rather than
@@ -13915,26 +13947,33 @@ parse_parameters(
parser_lex(parser);
pm_token_t operator = parser->previous;
- pm_token_t name = { 0 };
+ pm_node_t *param;
- bool repeated = false;
- if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
- name = parser->previous;
- repeated = pm_parser_parameter_name_check(parser, &name);
- pm_parser_local_add_token(parser, &name, 1);
+ if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
+ param = (pm_node_t *) pm_no_block_parameter_node_create(parser, &operator, &parser->previous);
} else {
- parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_BLOCK;
- }
+ pm_token_t name = {0};
- pm_block_parameter_node_t *param = pm_block_parameter_node_create(parser, NTOK2PTR(name), &operator);
- if (repeated) {
- pm_node_flag_set_repeated_parameter(UP(param));
+ bool repeated = false;
+ if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
+ name = parser->previous;
+ repeated = pm_parser_parameter_name_check(parser, &name);
+ pm_parser_local_add_token(parser, &name, 1);
+ } else {
+ parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_BLOCK;
+ }
+
+ param = (pm_node_t *) pm_block_parameter_node_create(parser, NTOK2PTR(name), &operator);
+ if (repeated) {
+ pm_node_flag_set_repeated_parameter(param);
+ }
}
+
if (params->block == NULL) {
pm_parameters_node_block_set(params, param);
} else {
- pm_parser_err_node(parser, UP(param), PM_ERR_PARAMETER_BLOCK_MULTI);
- pm_parameters_node_posts_append(params, UP(param));
+ pm_parser_err_node(parser, param, PM_ERR_PARAMETER_BLOCK_MULTI);
+ pm_parameters_node_posts_append(params, param);
}
break;
@@ -15433,7 +15472,7 @@ parse_string_part(pm_parser_t *parser, uint16_t depth) {
pm_token_t opening = parser->previous;
pm_statements_node_t *statements = NULL;
- if (!match1(parser, PM_TOKEN_EMBEXPR_END)) {
+ if (!match3(parser, PM_TOKEN_EMBEXPR_END, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
pm_accepts_block_stack_push(parser, true);
statements = parse_statements(parser, PM_CONTEXT_EMBEXPR, (uint16_t) (depth + 1));
pm_accepts_block_stack_pop(parser);
diff --git a/prism_compile.c b/prism_compile.c
index 5d83e55a77..c8b80e21ca 100644
--- a/prism_compile.c
+++ b/prism_compile.c
@@ -4524,6 +4524,7 @@ pm_compile_defined_expr0(rb_iseq_t *iseq, const pm_node_t *node, const pm_node_l
case PM_PARAMETERS_NODE:
case PM_KEYWORD_REST_PARAMETER_NODE:
case PM_NO_KEYWORDS_PARAMETER_NODE:
+ case PM_NO_BLOCK_PARAMETER_NODE:
case PM_NUMBERED_PARAMETERS_NODE:
case PM_OPTIONAL_KEYWORD_PARAMETER_NODE:
case PM_OPTIONAL_PARAMETER_NODE:
@@ -6340,7 +6341,7 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
}
}
- if (parameters_node && parameters_node->block) {
+ if (parameters_node && parameters_node->block && PM_NODE_TYPE_P(parameters_node->block, PM_BLOCK_PARAMETER_NODE)) {
const pm_block_parameter_node_t *block_node = (const pm_block_parameter_node_t *) parameters_node->block;
if (PM_NODE_FLAG_P(block_node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER) || !block_node->name) {
@@ -6686,26 +6687,38 @@ pm_compile_scope_node(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_nod
// def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
// ^^
if (parameters_node->block) {
- body->param.block_start = local_index;
- body->param.flags.has_block = true;
- iseq_set_use_block(iseq);
+ switch (PM_NODE_TYPE(parameters_node->block)) {
+ case PM_BLOCK_PARAMETER_NODE: {
+ body->param.block_start = local_index;
+ body->param.flags.has_block = true;
- pm_constant_id_t name = ((const pm_block_parameter_node_t *) parameters_node->block)->name;
+ iseq_set_use_block(iseq);
- if (name) {
- if (PM_NODE_FLAG_P(parameters_node->block, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
- ID local = pm_constant_id_lookup(scope_node, name);
- local_table_for_iseq->ids[local_index] = local;
+ pm_constant_id_t name = ((const pm_block_parameter_node_t *) parameters_node->block)->name;
+
+ if (name) {
+ if (PM_NODE_FLAG_P(parameters_node->block, PM_PARAMETER_FLAGS_REPEATED_PARAMETER)) {
+ ID local = pm_constant_id_lookup(scope_node, name);
+ local_table_for_iseq->ids[local_index] = local;
+ }
+ else {
+ pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
+ }
}
else {
- pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
+ pm_insert_local_special(idAnd, local_index, index_lookup_table, local_table_for_iseq);
}
- }
- else {
- pm_insert_local_special(idAnd, local_index, index_lookup_table, local_table_for_iseq);
- }
- local_index++;
+ local_index++;
+ break;
+ }
+ case PM_NO_BLOCK_PARAMETER_NODE: {
+ body->param.flags.accepts_no_block = true;
+ break;
+ }
+ default:
+ rb_bug("node type %s not expected as block parameter", pm_node_type_to_str(PM_NODE_TYPE(parameters_node->block)));
+ }
}
}
@@ -9955,6 +9968,12 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret,
return;
}
+ case PM_NO_BLOCK_PARAMETER_NODE: {
+ // def foo(&nil); end
+ // ^^^^
+ ISEQ_BODY(iseq)->param.flags.accepts_no_block = TRUE;
+ return;
+ }
case PM_NO_KEYWORDS_PARAMETER_NODE: {
// def foo(**nil); end
// ^^^^^
diff --git a/proc.c b/proc.c
index 67963a1b01..3e2afeab3c 100644
--- a/proc.c
+++ b/proc.c
@@ -3433,6 +3433,7 @@ method_inspect(VALUE method)
const VALUE keyrest = ID2SYM(rb_intern("keyrest"));
const VALUE block = ID2SYM(rb_intern("block"));
const VALUE nokey = ID2SYM(rb_intern("nokey"));
+ const VALUE noblock = ID2SYM(rb_intern("noblock"));
int forwarding = 0;
rb_str_buf_cat2(str, "(");
@@ -3467,6 +3468,9 @@ method_inspect(VALUE method)
else if (kind == nokey) {
name = rb_str_new2("nil");
}
+ else if (kind == noblock) {
+ name = rb_str_new2("nil");
+ }
else {
name = Qnil;
}
@@ -3519,6 +3523,9 @@ method_inspect(VALUE method)
else if (kind == nokey) {
rb_str_buf_cat2(str, "**nil");
}
+ else if (kind == noblock) {
+ rb_str_buf_cat2(str, "&nil");
+ }
if (i < RARRAY_LEN(params) - 1) {
rb_str_buf_cat2(str, ", ");
diff --git a/rubyparser.h b/rubyparser.h
index 36a2dc30a6..2ed93e9894 100644
--- a/rubyparser.h
+++ b/rubyparser.h
@@ -764,6 +764,7 @@ struct rb_args_info {
struct RNode_OPT_ARG *opt_args;
unsigned int no_kwarg: 1;
+ unsigned int no_blockarg: 1;
unsigned int forwarding: 1;
};
diff --git a/spec/ruby/core/method/parameters_spec.rb b/spec/ruby/core/method/parameters_spec.rb
index f1c2523cf0..41b9cd8d12 100644
--- a/spec/ruby/core/method/parameters_spec.rb
+++ b/spec/ruby/core/method/parameters_spec.rb
@@ -22,6 +22,12 @@ describe "Method#parameters" do
local_is_not_parameter = {}
end
+ ruby_version_is "4.1" do
+ eval <<-RUBY
+ def one_noblock(&nil); end
+ RUBY
+ end
+
def forward_parameters(...) end
def underscore_parameters(_, _, _ = 1, *_, _:, _: 2, **_, &_); end
@@ -187,6 +193,13 @@ describe "Method#parameters" do
m.parameters.should == [[:nokey]]
end
+ ruby_version_is "4.1" do
+ it "returns [[:noblock]] for a method with a single &nil parameter" do
+ m = MethodSpecs::Methods.instance_method(:one_noblock)
+ m.parameters.should == [[:noblock]]
+ end
+ end
+
it "works with ->(){} as the value of an optional argument" do
m = MethodSpecs::Methods.instance_method(:one_opt_with_stabby)
m.parameters.should == [[:opt,:a]]
diff --git a/spec/ruby/core/proc/parameters_spec.rb b/spec/ruby/core/proc/parameters_spec.rb
index cf8a8f5b12..0876ad0daf 100644
--- a/spec/ruby/core/proc/parameters_spec.rb
+++ b/spec/ruby/core/proc/parameters_spec.rb
@@ -172,4 +172,12 @@ describe "Proc#parameters" do
eval("lambda { it }").parameters.should == [[:req]]
end
end
+
+ ruby_version_is "4.1" do
+ it "returns :noblock for &nil parameter" do
+ eval <<~RUBY
+ proc { |&nil| }.parameters.should == [[:noblock]]
+ RUBY
+ end
+ end
end
diff --git a/spec/ruby/language/block_spec.rb b/spec/ruby/language/block_spec.rb
index 67aad76c57..ad6f7190b4 100644
--- a/spec/ruby/language/block_spec.rb
+++ b/spec/ruby/language/block_spec.rb
@@ -1110,6 +1110,17 @@ describe "`it` calls without arguments in a block" do
end
end
end
+
+ ruby_version_is "4.1" do
+ it "works alongside disallowed block argument" do
+ no_block = eval <<-EOF
+ proc {|arg1, &nil| arg1}
+ EOF
+
+ no_block.call(:a).should == :a
+ -> { no_block.call(:a) {} }.should raise_error(ArgumentError, 'no block accepted')
+ end
+ end
end
# Duplicates specs in language/it_parameter_spec.rb
diff --git a/spec/ruby/language/method_spec.rb b/spec/ruby/language/method_spec.rb
index 8f9f094fd8..dd93703d9f 100644
--- a/spec/ruby/language/method_spec.rb
+++ b/spec/ruby/language/method_spec.rb
@@ -1127,6 +1127,18 @@ describe "A method" do
result = m(1, {foo: :bar})
result.should == [1, nil, nil, {foo: :bar}, nil, {}]
end
+
+ ruby_version_is "4.1" do
+ evaluate <<-ruby do
+ def m(a, &nil); a end;
+ ruby
+
+ m(1).should == 1
+
+ -> { m(1) {} }.should raise_error(ArgumentError, 'no block accepted')
+ -> { m(1, &proc {}) }.should raise_error(ArgumentError, 'no block accepted')
+ end
+ end
end
context 'when passing an empty keyword splat to a method that does not accept keywords' do
diff --git a/test/prism/errors/unterminated_heredoc_and_embexpr.txt b/test/prism/errors/unterminated_heredoc_and_embexpr.txt
new file mode 100644
index 0000000000..bed7fcd24e
--- /dev/null
+++ b/test/prism/errors/unterminated_heredoc_and_embexpr.txt
@@ -0,0 +1,11 @@
+<<A+B
+ ^ unterminated heredoc; can't find string "A" anywhere before EOF
+ ^ unexpected '+', ignoring it
+ ^ unterminated heredoc; can't find string "A" anywhere before EOF
+#{C
+ ^ unexpected heredoc ending; expected an argument
+ ^ unexpected heredoc ending, expecting end-of-input
+ ^ unexpected heredoc ending, ignoring it
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+^ expected a `}` to close the embedded expression
+
diff --git a/test/prism/errors/unterminated_heredoc_and_embexpr_2.txt b/test/prism/errors/unterminated_heredoc_and_embexpr_2.txt
new file mode 100644
index 0000000000..a03ff1d212
--- /dev/null
+++ b/test/prism/errors/unterminated_heredoc_and_embexpr_2.txt
@@ -0,0 +1,9 @@
+<<A+B
+ ^ unterminated heredoc; can't find string "A" anywhere before EOF
+#{C + "#{"}
+ ^ unterminated string meets end of file
+ ^ unexpected end-of-input, assuming it is closing the parent top level context
+ ^ expected a `}` to close the embedded expression
+ ^ unterminated string; expected a closing delimiter for the interpolated string
+ ^ expected a `}` to close the embedded expression
+
diff --git a/test/prism/errors_test.rb b/test/prism/errors_test.rb
index b30a0f304d..27610e89d3 100644
--- a/test/prism/errors_test.rb
+++ b/test/prism/errors_test.rb
@@ -87,6 +87,28 @@ module Prism
assert_nil(statement.end_keyword)
end
+ def test_unclosed_interpolation
+ statement = Prism.parse_statement("\"\#{")
+ assert_equal('"', statement.opening)
+ assert_nil(statement.closing)
+
+ assert_equal(1, statement.parts.count)
+ assert_equal('#{', statement.parts[0].opening)
+ assert_equal("", statement.parts[0].closing)
+ assert_nil(statement.parts[0].statements)
+ end
+
+ def test_unclosed_heredoc_and_interpolation
+ statement = Prism.parse_statement("<<D\n\#{")
+ assert_equal("<<D", statement.opening)
+ assert_nil(statement.closing)
+
+ assert_equal(1, statement.parts.count)
+ assert_equal('#{', statement.parts[0].opening)
+ assert_equal("", statement.parts[0].closing)
+ assert_nil(statement.parts[0].statements)
+ end
+
private
def assert_errors(filepath, version)
diff --git a/test/prism/lex_test.rb b/test/prism/lex_test.rb
index 9a9f203c28..8ea7ce7e9b 100644
--- a/test/prism/lex_test.rb
+++ b/test/prism/lex_test.rb
@@ -48,11 +48,58 @@ module Prism
end
if RUBY_VERSION >= "3.3"
- def test_lex_compare
- prism = Prism.lex_compat(File.read(__FILE__), version: "current").value
- ripper = Ripper.lex(File.read(__FILE__))
+ def test_lex_compat
+ source = "foo bar"
+ prism = Prism.lex_compat(source, version: "current").value
+ ripper = Ripper.lex(source)
assert_equal(ripper, prism)
end
end
+
+ def test_lex_interpolation_unterminated
+ assert_equal(
+ %i[STRING_BEGIN EMBEXPR_BEGIN EOF],
+ token_types('"#{')
+ )
+
+ assert_equal(
+ %i[STRING_BEGIN EMBEXPR_BEGIN IGNORED_NEWLINE EOF],
+ token_types('"#{' + "\n")
+ )
+ end
+
+ def test_lex_interpolation_unterminated_with_content
+ # FIXME: Emits EOL twice.
+ assert_equal(
+ %i[STRING_BEGIN EMBEXPR_BEGIN CONSTANT EOF EOF],
+ token_types('"#{C')
+ )
+
+ assert_equal(
+ %i[STRING_BEGIN EMBEXPR_BEGIN CONSTANT NEWLINE EOF],
+ token_types('"#{C' + "\n")
+ )
+ end
+
+ def test_lex_heredoc_unterminated
+ code = <<~'RUBY'.strip
+ <<A+B
+ #{C
+ RUBY
+
+ assert_equal(
+ %i[HEREDOC_START EMBEXPR_BEGIN CONSTANT HEREDOC_END PLUS CONSTANT NEWLINE EOF],
+ token_types(code)
+ )
+
+ assert_equal(
+ %i[HEREDOC_START EMBEXPR_BEGIN CONSTANT NEWLINE HEREDOC_END PLUS CONSTANT NEWLINE EOF],
+ token_types(code + "\n")
+ )
+ end
+
+ def token_types(code)
+ Prism.lex(code).value.map { |token, _state| token.type }
+ end
end
end
diff --git a/test/prism/result/source_location_test.rb b/test/prism/result/source_location_test.rb
index 993150f581..dbda848211 100644
--- a/test/prism/result/source_location_test.rb
+++ b/test/prism/result/source_location_test.rb
@@ -650,6 +650,10 @@ module Prism
assert_location(NilNode, "nil")
end
+ def test_NoBlockParameterNode
+ assert_location(NoBlockParameterNode, "def foo(&nil); end", 8...12) { |node| node.parameters.block }
+ end
+
def test_NoKeywordsParameterNode
assert_location(NoKeywordsParameterNode, "def foo(**nil); end", 8...13) { |node| node.parameters.keyword_rest }
end
diff --git a/test/prism/ruby/parameters_signature_test.rb b/test/prism/ruby/parameters_signature_test.rb
index ea1eea106b..8ca4c565ac 100644
--- a/test/prism/ruby/parameters_signature_test.rb
+++ b/test/prism/ruby/parameters_signature_test.rb
@@ -50,6 +50,10 @@ module Prism
assert_parameters([[:nokey]], "**nil")
end
+ def test_noblock
+ assert_parameters([[:noblock]], "&nil")
+ end
+
def test_keyrest_anonymous
assert_parameters([[:keyrest, :**]], "**")
end
diff --git a/test/ruby/test_iseq.rb b/test/ruby/test_iseq.rb
index 6846f7958b..43b1f0f620 100644
--- a/test/ruby/test_iseq.rb
+++ b/test/ruby/test_iseq.rb
@@ -682,6 +682,17 @@ class TestISeq < Test::Unit::TestCase
assert_equal([[:nokey]], iseq.eval.singleton_method(:foo).parameters)
end
+ def test_to_binary_dumps_noblock
+ iseq = assert_iseq_to_binary(<<-RUBY)
+ o = Object.new
+ class << o
+ def foo(&nil); end
+ end
+ o
+ RUBY
+ assert_equal([[:noblock]], iseq.eval.singleton_method(:foo).parameters)
+ end
+
def test_to_binary_line_info
assert_iseq_to_binary("#{<<~"begin;"}\n#{<<~'end;'}", '[Bug #14660]').eval
begin;
diff --git a/test/ruby/test_method.rb b/test/ruby/test_method.rb
index c3819cdebf..7c3e8e03a7 100644
--- a/test/ruby/test_method.rb
+++ b/test/ruby/test_method.rb
@@ -32,6 +32,7 @@ class TestMethod < Test::Unit::TestCase
def mk7(a, b = nil, *c, d, **o) nil && o end
def mk8(a, b = nil, *c, d, e:, f: nil, **o) nil && o end
def mnk(**nil) end
+ def mnb(&nil) end
def mf(...) end
class Base
@@ -617,6 +618,7 @@ class TestMethod < Test::Unit::TestCase
define_method(:pmk7) {|a, b = nil, *c, d, **o|}
define_method(:pmk8) {|a, b = nil, *c, d, e:, f: nil, **o|}
define_method(:pmnk) {|**nil|}
+ define_method(:pmnb) {|&nil|}
def test_bound_parameters
assert_equal([], method(:m0).parameters)
@@ -640,6 +642,7 @@ class TestMethod < Test::Unit::TestCase
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyrest, :o]], method(:mk7).parameters)
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyreq, :e], [:key, :f], [:keyrest, :o]], method(:mk8).parameters)
assert_equal([[:nokey]], method(:mnk).parameters)
+ assert_equal([[:noblock]], method(:mnb).parameters)
# pending
assert_equal([[:rest, :*], [:keyrest, :**], [:block, :&]], method(:mf).parameters)
end
@@ -666,6 +669,7 @@ class TestMethod < Test::Unit::TestCase
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyrest, :o]], self.class.instance_method(:mk7).parameters)
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyreq, :e], [:key, :f], [:keyrest, :o]], self.class.instance_method(:mk8).parameters)
assert_equal([[:nokey]], self.class.instance_method(:mnk).parameters)
+ assert_equal([[:noblock]], self.class.instance_method(:mnb).parameters)
# pending
assert_equal([[:rest, :*], [:keyrest, :**], [:block, :&]], self.class.instance_method(:mf).parameters)
end
@@ -691,6 +695,7 @@ class TestMethod < Test::Unit::TestCase
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyrest, :o]], method(:pmk7).parameters)
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyreq, :e], [:key, :f], [:keyrest, :o]], method(:pmk8).parameters)
assert_equal([[:nokey]], method(:pmnk).parameters)
+ assert_equal([[:noblock]], method(:pmnb).parameters)
end
def test_bmethod_unbound_parameters
@@ -715,6 +720,7 @@ class TestMethod < Test::Unit::TestCase
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyrest, :o]], self.class.instance_method(:pmk7).parameters)
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:keyreq, :e], [:key, :f], [:keyrest, :o]], self.class.instance_method(:pmk8).parameters)
assert_equal([[:nokey]], self.class.instance_method(:pmnk).parameters)
+ assert_equal([[:noblock]], self.class.instance_method(:pmnb).parameters)
end
def test_hidden_parameters
diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb
index e868967e8b..70e1956816 100644
--- a/test/ruby/test_syntax.rb
+++ b/test/ruby/test_syntax.rb
@@ -202,6 +202,49 @@ class TestSyntax < Test::Unit::TestCase
assert_syntax_error("def f(...); g(&); end", /no anonymous block parameter/)
end
+ def test_no_block_argument_in_method
+ assert_valid_syntax("def f(&nil) end")
+ assert_valid_syntax("def f(a, &nil) end")
+ assert_valid_syntax("def f(*rest, &nil) end")
+ assert_valid_syntax("def f(*rest, p, &nil) end")
+ assert_valid_syntax("def f(a, *rest, &nil) end")
+ assert_valid_syntax("def f(a, *rest, p, &nil) end")
+ assert_valid_syntax("def f(a, k: nil, &nil) end")
+ assert_valid_syntax("def f(a, k: nil, **kw, &nil) end")
+ assert_valid_syntax("def f(a, *rest, k: nil, &nil) end")
+ assert_valid_syntax("def f(a, *rest, k: nil, **kw, &nil) end")
+ assert_valid_syntax("def f(a, *rest, p, k: nil, &nil) end")
+ assert_valid_syntax("def f(a, *rest, p, k: nil, **kw, &nil) end")
+
+ obj = Object.new
+ obj.instance_eval "def f(&nil) end"
+ assert_raise_with_message(ArgumentError, /block accepted/) {obj.f {}}
+ assert_raise_with_message(ArgumentError, /block accepted/) {obj.f(&proc {})}
+ end
+
+ def test_no_block_argument_in_block
+ assert_valid_syntax("proc do |&nil| end")
+ assert_valid_syntax("proc do |a, &nil| end")
+ assert_valid_syntax("proc do |*rest, &nil| end")
+ assert_valid_syntax("proc do |*rest, p, &nil| end")
+ assert_valid_syntax("proc do |a, *rest, &nil| end")
+ assert_valid_syntax("proc do |a, *rest, p, &nil| end")
+ assert_valid_syntax("proc do |a, k: nil, &nil| end")
+ assert_valid_syntax("proc do |a, k: nil, **kw, &nil| end")
+ assert_valid_syntax("proc do |a, *rest, k: nil, &nil| end")
+ assert_valid_syntax("proc do |a, *rest, k: nil, **kw, &nil| end")
+ assert_valid_syntax("proc do |a, *rest, p, k: nil, &nil| end")
+ assert_valid_syntax("proc do |a, *rest, p, k: nil, **kw, &nil| end")
+
+ pr = eval "proc {|&nil|}"
+ assert_nil(pr.call)
+ assert_raise_with_message(ArgumentError, /block accepted/) {pr.call {}}
+ pr = eval "proc {|a, &nil| a}"
+ assert_nil(pr.call)
+ assert_equal(1, pr.call(1))
+ assert_raise_with_message(ArgumentError, /block accepted/) {pr.call {}}
+ end
+
def test_newline_in_block_parameters
bug = '[ruby-dev:45292]'
["", "a", "a, b"].product(["", ";x", [";", "x"]]) do |params|
diff --git a/vm_args.c b/vm_args.c
index 90a18ee8df..62c63caa98 100644
--- a/vm_args.c
+++ b/vm_args.c
@@ -12,6 +12,8 @@ NORETURN(static void raise_argument_error(rb_execution_context_t *ec, const rb_i
NORETURN(static void argument_arity_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb_callable_method_entry_t *cme, const int miss_argc, const int min_argc, const int max_argc));
NORETURN(static void argument_kw_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb_callable_method_entry_t *cme, const char *error, const VALUE keys));
VALUE rb_keyword_error_new(const char *error, VALUE keys); /* class.c */
+static VALUE set_error_backtrace(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb_callable_method_entry_t *cme, const VALUE exc);
+
static VALUE method_missing(rb_execution_context_t *ec, VALUE obj, ID id, int argc, const VALUE *argv,
enum method_missing_reason call_status, int kw_splat);
const rb_callable_method_entry_t *rb_resolve_refined_method_callable(VALUE refinements, const rb_callable_method_entry_t *me);
@@ -959,7 +961,15 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
argument_kw_error(ec, iseq, cme, "unknown", rb_hash_keys(keyword_hash));
}
- if (ISEQ_BODY(iseq)->param.flags.has_block) {
+ if (ISEQ_BODY(iseq)->param.flags.accepts_no_block) {
+ VALUE given_block;
+ args_setup_block_parameter(ec, calling, &given_block);
+ if (!NIL_P(given_block)) {
+ VALUE exc = rb_exc_new_cstr(rb_eArgError, "no block accepted");
+ rb_exc_raise(set_error_backtrace(ec, iseq, cme, exc));
+ }
+ }
+ else if (ISEQ_BODY(iseq)->param.flags.has_block) {
if (ISEQ_BODY(iseq)->local_iseq == iseq) {
/* Do nothing */
}
@@ -981,8 +991,8 @@ setup_parameters_complex(rb_execution_context_t * const ec, const rb_iseq_t * co
return opt_pc;
}
-static void
-raise_argument_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb_callable_method_entry_t *cme, const VALUE exc)
+static VALUE
+set_error_backtrace(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb_callable_method_entry_t *cme, const VALUE exc)
{
VALUE at;
@@ -1000,6 +1010,13 @@ raise_argument_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb
rb_ivar_set(exc, idBt_locations, at);
rb_exc_set_backtrace(exc, at);
+ return exc;
+}
+
+static void
+raise_argument_error(rb_execution_context_t *ec, const rb_iseq_t *iseq, const rb_callable_method_entry_t *cme, const VALUE exc)
+{
+ set_error_backtrace(ec, iseq, cme, exc);
rb_exc_raise(exc);
}
diff --git a/vm_core.h b/vm_core.h
index 5f0266da1d..7fcf8ca5c1 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -456,6 +456,7 @@ struct rb_iseq_constant_body {
unsigned int anon_kwrest: 1;
unsigned int use_block: 1;
unsigned int forwardable: 1;
+ unsigned int accepts_no_block: 1;
} flags;
unsigned int size;
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index a27bf5f49b..95422caaa6 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -2732,7 +2732,8 @@ rb_simple_iseq_p(const rb_iseq_t *iseq)
ISEQ_BODY(iseq)->param.flags.has_kwrest == FALSE &&
ISEQ_BODY(iseq)->param.flags.accepts_no_kwarg == FALSE &&
ISEQ_BODY(iseq)->param.flags.forwardable == FALSE &&
- ISEQ_BODY(iseq)->param.flags.has_block == FALSE;
+ ISEQ_BODY(iseq)->param.flags.has_block == FALSE &&
+ ISEQ_BODY(iseq)->param.flags.accepts_no_block == FALSE;
}
bool
@@ -2745,7 +2746,8 @@ rb_iseq_only_optparam_p(const rb_iseq_t *iseq)
ISEQ_BODY(iseq)->param.flags.has_kwrest == FALSE &&
ISEQ_BODY(iseq)->param.flags.accepts_no_kwarg == FALSE &&
ISEQ_BODY(iseq)->param.flags.forwardable == FALSE &&
- ISEQ_BODY(iseq)->param.flags.has_block == FALSE;
+ ISEQ_BODY(iseq)->param.flags.has_block == FALSE &&
+ ISEQ_BODY(iseq)->param.flags.accepts_no_block == FALSE;
}
bool
@@ -2757,7 +2759,8 @@ rb_iseq_only_kwparam_p(const rb_iseq_t *iseq)
ISEQ_BODY(iseq)->param.flags.has_kw == TRUE &&
ISEQ_BODY(iseq)->param.flags.has_kwrest == FALSE &&
ISEQ_BODY(iseq)->param.flags.forwardable == FALSE &&
- ISEQ_BODY(iseq)->param.flags.has_block == FALSE;
+ ISEQ_BODY(iseq)->param.flags.has_block == FALSE &&
+ ISEQ_BODY(iseq)->param.flags.accepts_no_block == FALSE;
}
#define ALLOW_HEAP_ARGV (-2)
diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs
index c11610e26c..845f7e6eef 100644
--- a/zjit/src/codegen.rs
+++ b/zjit/src/codegen.rs
@@ -482,10 +482,10 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
Insn::ToRegexp { opt, values, state } => gen_toregexp(jit, asm, *opt, opnds!(values), &function.frame_state(*state)),
Insn::Param => unreachable!("block.insns should not have Insn::Param"),
Insn::Snapshot { .. } => return Ok(()), // we don't need to do anything for this instruction at the moment
- &Insn::Send { cd, blockiseq, state, reason, .. } => gen_send(jit, asm, cd, blockiseq, &function.frame_state(state), reason),
+ &Insn::Send { cd, blockiseq: None, state, reason, .. } => gen_send_without_block(jit, asm, cd, &function.frame_state(state), reason),
+ &Insn::Send { cd, blockiseq: Some(blockiseq), state, reason, .. } => gen_send(jit, asm, cd, blockiseq, &function.frame_state(state), reason),
&Insn::SendForward { cd, blockiseq, state, reason, .. } => gen_send_forward(jit, asm, cd, blockiseq, &function.frame_state(state), reason),
Insn::SendDirect { cme, iseq, recv, args, kw_bits, blockiseq, state, .. } => gen_send_iseq_direct(cb, jit, asm, *cme, *iseq, opnd!(recv), opnds!(args), *kw_bits, &function.frame_state(*state), *blockiseq),
- &Insn::SendWithoutBlock { cd, state, reason, .. } => gen_send_without_block(jit, asm, cd, &function.frame_state(state), reason),
&Insn::InvokeSuper { cd, blockiseq, state, reason, .. } => gen_invokesuper(jit, asm, cd, blockiseq, &function.frame_state(state), reason),
&Insn::InvokeSuperForward { cd, blockiseq, state, reason, .. } => gen_invokesuperforward(jit, asm, cd, blockiseq, &function.frame_state(state), reason),
&Insn::InvokeBlock { cd, state, reason, .. } => gen_invokeblock(jit, asm, cd, &function.frame_state(state), reason),
diff --git a/zjit/src/cruby.rs b/zjit/src/cruby.rs
index a47d9bf61f..0eb47062c9 100644
--- a/zjit/src/cruby.rs
+++ b/zjit/src/cruby.rs
@@ -1197,6 +1197,15 @@ pub mod test_utils {
})
}
+ /// Evaluate a given Ruby program with compile options
+ pub fn eval_with_options(program: &str, options_expr: &str) -> VALUE {
+ with_rubyvm(|| {
+ let options = eval(options_expr);
+ let wrapped_iseq = compile_to_wrapped_iseq_with_options(&unindent(program, false), options);
+ unsafe { rb_funcallv(wrapped_iseq, ID!(eval), 0, null()) }
+ })
+ }
+
/// Get the #inspect of a given Ruby program in Rust string
pub fn inspect(program: &str) -> String {
let inspect = format!("({program}).inspect");
@@ -1252,10 +1261,15 @@ pub mod test_utils {
/// Compile a program into a RubyVM::InstructionSequence object
fn compile_to_wrapped_iseq(program: &str) -> VALUE {
+ compile_to_wrapped_iseq_with_options(program, Qnil)
+ }
+
+ fn compile_to_wrapped_iseq_with_options(program: &str, options: VALUE) -> VALUE {
let bytes = program.as_bytes().as_ptr() as *const c_char;
unsafe {
let program_str = rb_utf8_str_new(bytes, program.len().try_into().unwrap());
- rb_funcallv(rb_cISeq, ID!(compile), 1, &program_str)
+ let args = [program_str, Qnil, Qnil, VALUE(1_usize.wrapping_shl(1) | 1), options];
+ rb_funcallv(rb_cISeq, ID!(compile), args.len() as c_int, args.as_ptr())
}
}
diff --git a/zjit/src/cruby_bindings.inc.rs b/zjit/src/cruby_bindings.inc.rs
index f178e76728..e1e162c0c2 100644
--- a/zjit/src/cruby_bindings.inc.rs
+++ b/zjit/src/cruby_bindings.inc.rs
@@ -1079,6 +1079,39 @@ impl rb_iseq_constant_body_rb_iseq_parameters__bindgen_ty_1 {
}
}
#[inline]
+ pub fn accepts_no_block(&self) -> ::std::os::raw::c_uint {
+ unsafe { ::std::mem::transmute(self._bitfield_1.get(14usize, 1u8) as u32) }
+ }
+ #[inline]
+ pub fn set_accepts_no_block(&mut self, val: ::std::os::raw::c_uint) {
+ unsafe {
+ let val: u32 = ::std::mem::transmute(val);
+ self._bitfield_1.set(14usize, 1u8, val as u64)
+ }
+ }
+ #[inline]
+ pub unsafe fn accepts_no_block_raw(this: *const Self) -> ::std::os::raw::c_uint {
+ unsafe {
+ ::std::mem::transmute(<__BindgenBitfieldUnit<[u8; 2usize]>>::raw_get(
+ ::std::ptr::addr_of!((*this)._bitfield_1),
+ 14usize,
+ 1u8,
+ ) as u32)
+ }
+ }
+ #[inline]
+ pub unsafe fn set_accepts_no_block_raw(this: *mut Self, val: ::std::os::raw::c_uint) {
+ unsafe {
+ let val: u32 = ::std::mem::transmute(val);
+ <__BindgenBitfieldUnit<[u8; 2usize]>>::raw_set(
+ ::std::ptr::addr_of_mut!((*this)._bitfield_1),
+ 14usize,
+ 1u8,
+ val as u64,
+ )
+ }
+ }
+ #[inline]
pub fn new_bitfield_1(
has_lead: ::std::os::raw::c_uint,
has_opt: ::std::os::raw::c_uint,
@@ -1094,6 +1127,7 @@ impl rb_iseq_constant_body_rb_iseq_parameters__bindgen_ty_1 {
anon_kwrest: ::std::os::raw::c_uint,
use_block: ::std::os::raw::c_uint,
forwardable: ::std::os::raw::c_uint,
+ accepts_no_block: ::std::os::raw::c_uint,
) -> __BindgenBitfieldUnit<[u8; 2usize]> {
let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 2usize]> = Default::default();
__bindgen_bitfield_unit.set(0usize, 1u8, {
@@ -1152,6 +1186,10 @@ impl rb_iseq_constant_body_rb_iseq_parameters__bindgen_ty_1 {
let forwardable: u32 = unsafe { ::std::mem::transmute(forwardable) };
forwardable as u64
});
+ __bindgen_bitfield_unit.set(14usize, 1u8, {
+ let accepts_no_block: u32 = unsafe { ::std::mem::transmute(accepts_no_block) };
+ accepts_no_block as u64
+ });
__bindgen_bitfield_unit
}
}
diff --git a/zjit/src/cruby_methods.rs b/zjit/src/cruby_methods.rs
index 56ff3ca1aa..f44c33845c 100644
--- a/zjit/src/cruby_methods.rs
+++ b/zjit/src/cruby_methods.rs
@@ -322,7 +322,7 @@ fn inline_thread_current(fun: &mut hir::Function, block: hir::BlockId, _recv: hi
fn inline_kernel_itself(_fun: &mut hir::Function, _block: hir::BlockId, recv: hir::InsnId, args: &[hir::InsnId], _state: hir::InsnId) -> Option<hir::InsnId> {
if args.is_empty() {
- // No need to coerce the receiver; that is done by the SendWithoutBlock rewriting.
+ // No need to coerce the receiver; that is done by the Send rewriting.
return Some(recv);
}
None
diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs
index 579c327d44..1888d00a98 100644
--- a/zjit/src/hir.rs
+++ b/zjit/src/hir.rs
@@ -884,7 +884,7 @@ pub enum Insn {
/// Call a C function that pushes a frame
CCallWithFrame {
- cd: *const rb_call_data, // cd for falling back to SendWithoutBlock
+ cd: *const rb_call_data, // cd for falling back to Send
cfunc: *const u8,
recv: InsnId,
args: Vec<InsnId>,
@@ -912,17 +912,10 @@ pub enum Insn {
/// Un-optimized fallback implementation (dynamic dispatch) for send-ish instructions
/// Ignoring keyword arguments etc for now
- SendWithoutBlock {
- recv: InsnId,
- cd: *const rb_call_data,
- args: Vec<InsnId>,
- state: InsnId,
- reason: SendFallbackReason,
- },
Send {
recv: InsnId,
cd: *const rb_call_data,
- blockiseq: IseqPtr,
+ blockiseq: Option<IseqPtr>,
args: Vec<InsnId>,
state: InsnId,
reason: SendFallbackReason,
@@ -1012,7 +1005,7 @@ pub enum Insn {
FixnumLShift { left: InsnId, right: InsnId, state: InsnId },
FixnumRShift { left: InsnId, right: InsnId },
- // Distinct from `SendWithoutBlock` with `mid:to_s` because does not have a patch point for String to_s being redefined
+ // Distinct from `Send` with `mid:to_s` because does not have a patch point for String to_s being redefined
ObjToString { val: InsnId, cd: *const rb_call_data, state: InsnId },
AnyToString { val: InsnId, str: InsnId, state: InsnId },
@@ -1187,7 +1180,6 @@ impl Insn {
}
},
Insn::CCallVariadic { .. } => effects::Any,
- Insn::SendWithoutBlock { .. } => effects::Any,
Insn::Send { .. } => effects::Any,
Insn::SendForward { .. } => effects::Any,
Insn::InvokeSuper { .. } => effects::Any,
@@ -1449,14 +1441,6 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
Insn::Jump(target) => { write!(f, "Jump {target}") }
Insn::IfTrue { val, target } => { write!(f, "IfTrue {val}, {target}") }
Insn::IfFalse { val, target } => { write!(f, "IfFalse {val}, {target}") }
- Insn::SendWithoutBlock { recv, cd, args, reason, .. } => {
- write!(f, "SendWithoutBlock {recv}, :{}", ruby_call_method_name(*cd))?;
- for arg in args {
- write!(f, ", {arg}")?;
- }
- write!(f, " # SendFallbackReason: {reason}")?;
- Ok(())
- }
Insn::SendDirect { recv, cd, iseq, args, blockiseq, .. } => {
write!(f, "SendDirect {recv}, {:p}, :{} ({:?})", self.ptr_map.map_ptr(blockiseq), ruby_call_method_name(*cd), self.ptr_map.map_ptr(iseq))?;
for arg in args {
@@ -1468,7 +1452,11 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
// For tests, we want to check HIR snippets textually. Addresses change
// between runs, making tests fail. Instead, pick an arbitrary hex value to
// use as a "pointer" so we can check the rest of the HIR.
- write!(f, "Send {recv}, {:p}, :{}", self.ptr_map.map_ptr(blockiseq), ruby_call_method_name(*cd))?;
+ if let Some(blockiseq) = *blockiseq {
+ write!(f, "Send {recv}, {:p}, :{}", self.ptr_map.map_ptr(blockiseq), ruby_call_method_name(*cd))?;
+ } else {
+ write!(f, "Send {recv}, :{}", ruby_call_method_name(*cd))?;
+ }
for arg in args {
write!(f, ", {arg}")?;
}
@@ -2275,13 +2263,6 @@ impl Function {
str: find!(str),
state,
},
- &SendWithoutBlock { recv, cd, ref args, state, reason } => SendWithoutBlock {
- recv: find!(recv),
- cd,
- args: find_vec!(args),
- state,
- reason,
- },
&SendDirect { recv, cd, cme, iseq, ref args, kw_bits, blockiseq, state } => SendDirect {
recv: find!(recv),
cd,
@@ -2402,7 +2383,6 @@ impl Function {
match self.insns.get_mut(insn_id.0).unwrap() {
Send { reason, .. }
| SendForward { reason, .. }
- | SendWithoutBlock { reason, .. }
| InvokeSuper { reason, .. }
| InvokeSuperForward { reason, .. }
| InvokeBlock { reason, .. }
@@ -2522,7 +2502,6 @@ impl Function {
Insn::FixnumLShift { .. } => types::Fixnum,
Insn::FixnumRShift { .. } => types::Fixnum,
Insn::PutSpecialObject { .. } => types::BasicObject,
- Insn::SendWithoutBlock { .. } => types::BasicObject,
Insn::SendDirect { .. } => types::BasicObject,
Insn::Send { .. } => types::BasicObject,
Insn::SendForward { .. } => types::BasicObject,
@@ -3034,7 +3013,7 @@ impl Function {
self.push_insn(block, Insn::GuardNoBitsSet { val: flags, mask: Const::CUInt64(RUBY_ELTS_SHARED as u64), mask_name: Some(ID!(RUBY_ELTS_SHARED)), reason: SideExitReason::GuardNotShared, state });
}
- /// Rewrite eligible Send/SendWithoutBlock opcodes into SendDirect
+ /// Rewrite eligible Send opcodes into SendDirect
/// opcodes if we know the target ISEQ statically. This removes run-time method lookups and
/// opens the door for inlining.
/// Also try and inline constant caches, specialize object allocations, and more.
@@ -3045,11 +3024,12 @@ impl Function {
assert!(self.blocks[block.0].insns.is_empty());
for insn_id in old_insns {
match self.find(insn_id) {
- Insn::SendWithoutBlock { recv, args, state, cd, .. } if ruby_call_method_id(cd) == ID!(freeze) && args.is_empty() =>
+ Insn::Send { recv, blockiseq: None, args, state, cd, .. } if ruby_call_method_id(cd) == ID!(freeze) && args.is_empty() =>
self.try_rewrite_freeze(block, insn_id, recv, state),
- Insn::SendWithoutBlock { recv, args, state, cd, .. } if ruby_call_method_id(cd) == ID!(minusat) && args.is_empty() =>
+ Insn::Send { recv, blockiseq: None, args, state, cd, .. } if ruby_call_method_id(cd) == ID!(minusat) && args.is_empty() =>
self.try_rewrite_uminus(block, insn_id, recv, state),
- Insn::SendWithoutBlock { mut recv, cd, args, state, .. } => {
+ Insn::Send { mut recv, cd, state, blockiseq, args, .. } => {
+ let has_block = blockiseq.is_some();
let frame_state = self.frame_state(state);
let (klass, profiled_type) = match self.resolve_receiver_type(recv, self.type_of(recv), frame_state.insn_idx) {
ReceiverTypeResolution::StaticallyKnown { class } => (class, None),
@@ -3058,21 +3038,24 @@ impl Function {
ReceiverTypeResolution::SkewedMegamorphic { .. }
| ReceiverTypeResolution::Megamorphic => {
if get_option!(stats) {
- self.set_dynamic_send_reason(insn_id, SendWithoutBlockMegamorphic);
+ let reason = if has_block { SendMegamorphic } else { SendWithoutBlockMegamorphic };
+ self.set_dynamic_send_reason(insn_id, reason);
}
self.push_insn_id(block, insn_id);
continue;
}
ReceiverTypeResolution::Polymorphic => {
if get_option!(stats) {
- self.set_dynamic_send_reason(insn_id, SendWithoutBlockPolymorphic);
+ let reason = if has_block { SendPolymorphic } else { SendWithoutBlockPolymorphic };
+ self.set_dynamic_send_reason(insn_id, reason);
}
self.push_insn_id(block, insn_id);
continue;
}
ReceiverTypeResolution::NoProfile => {
if get_option!(stats) {
- self.set_dynamic_send_reason(insn_id, SendWithoutBlockNoProfiles);
+ let reason = if has_block { SendNoProfiles } else { SendWithoutBlockNoProfiles };
+ self.set_dynamic_send_reason(insn_id, reason);
}
self.push_insn_id(block, insn_id);
continue;
@@ -3086,7 +3069,8 @@ impl Function {
// Do method lookup
let mut cme = unsafe { rb_callable_method_entry(klass, mid) };
if cme.is_null() {
- self.set_dynamic_send_reason(insn_id, SendWithoutBlockNotOptimizedMethodType(MethodType::Null));
+ let reason = if has_block { SendNotOptimizedMethodType(MethodType::Null) } else { SendWithoutBlockNotOptimizedMethodType(MethodType::Null) };
+ self.set_dynamic_send_reason(insn_id, reason);
self.push_insn_id(block, insn_id); continue;
}
// Load an overloaded cme if applicable. See vm_search_cc().
@@ -3098,7 +3082,8 @@ impl Function {
(METHOD_VISI_PRIVATE, true) => {}
(METHOD_VISI_PROTECTED, true) => {}
_ => {
- self.set_dynamic_send_reason(insn_id, SendWithoutBlockNotOptimizedNeedPermission);
+ let reason = if has_block { SendNotOptimizedNeedPermission } else { SendWithoutBlockNotOptimizedNeedPermission };
+ self.set_dynamic_send_reason(insn_id, reason);
self.push_insn_id(block, insn_id); continue;
}
}
@@ -3121,7 +3106,7 @@ impl Function {
// Only specialize positional-positional calls
// TODO(max): Handle other kinds of parameter passing
let iseq = unsafe { get_def_iseq_ptr((*cme).def) };
- if !can_direct_send(self, block, iseq, ci, insn_id, args.as_slice(), None) {
+ if !can_direct_send(self, block, iseq, ci, insn_id, args.as_slice(), blockiseq) {
self.push_insn_id(block, insn_id); continue;
}
@@ -3144,9 +3129,9 @@ impl Function {
self.push_insn_id(block, insn_id); continue;
};
- let send_direct = self.push_insn(block, Insn::SendDirect { recv, cd, cme, iseq, args: processed_args, kw_bits, state: send_state, blockiseq: None });
+ let send_direct = self.push_insn(block, Insn::SendDirect { recv, cd, cme, iseq, args: processed_args, kw_bits, state: send_state, blockiseq });
self.make_equal_to(insn_id, send_direct);
- } else if def_type == VM_METHOD_TYPE_BMETHOD {
+ } else if !has_block && def_type == VM_METHOD_TYPE_BMETHOD {
let procv = unsafe { rb_get_def_bmethod_proc((*cme).def) };
let proc = unsafe { rb_jit_get_proc_ptr(procv) };
let proc_block = unsafe { &(*proc).block };
@@ -3187,7 +3172,7 @@ impl Function {
let send_direct = self.push_insn(block, Insn::SendDirect { recv, cd, cme, iseq, args: processed_args, kw_bits, state: send_state, blockiseq: None });
self.make_equal_to(insn_id, send_direct);
- } else if def_type == VM_METHOD_TYPE_IVAR && args.is_empty() {
+ } else if !has_block && def_type == VM_METHOD_TYPE_IVAR && args.is_empty() {
// Check if we're accessing ivars of a Class or Module object as they require single-ractor mode.
// We omit gen_prepare_non_leaf_call on gen_getivar, so it's unsafe to raise for multi-ractor mode.
if self.is_metaclass(klass) && !self.assume_single_ractor_mode(block, state) {
@@ -3207,7 +3192,7 @@ impl Function {
let getivar = self.push_insn(block, Insn::GetIvar { self_val: recv, id, ic: std::ptr::null(), state });
self.make_equal_to(insn_id, getivar);
- } else if let (VM_METHOD_TYPE_ATTRSET, &[val]) = (def_type, args.as_slice()) {
+ } else if let (false, VM_METHOD_TYPE_ATTRSET, &[val]) = (has_block, def_type, args.as_slice()) {
// Check if we're accessing ivars of a Class or Module object as they require single-ractor mode.
// We omit gen_prepare_non_leaf_call on gen_getivar, so it's unsafe to raise for multi-ractor mode.
if self.is_metaclass(klass) && !self.assume_single_ractor_mode(block, state) {
@@ -3222,7 +3207,7 @@ impl Function {
self.push_insn(block, Insn::SetIvar { self_val: recv, id, ic: std::ptr::null(), val, state });
self.make_equal_to(insn_id, val);
- } else if def_type == VM_METHOD_TYPE_OPTIMIZED {
+ } else if !has_block && def_type == VM_METHOD_TYPE_OPTIMIZED {
let opt_type: OptimizedMethodType = unsafe { get_cme_def_body_optimized_type(cme) }.into();
match (opt_type, args.as_slice()) {
(OptimizedMethodType::Call, _) => {
@@ -3309,115 +3294,8 @@ impl Function {
},
};
} else {
- self.set_dynamic_send_reason(insn_id, SendWithoutBlockNotOptimizedMethodType(MethodType::from(def_type)));
- self.push_insn_id(block, insn_id); continue;
- }
- }
- Insn::Send { mut recv, cd, state, blockiseq, args, .. } => {
- let frame_state = self.frame_state(state);
- let (klass, profiled_type) = match self.resolve_receiver_type(recv, self.type_of(recv), frame_state.insn_idx) {
- ReceiverTypeResolution::StaticallyKnown { class } => (class, None),
- ReceiverTypeResolution::Monomorphic { profiled_type }
- | ReceiverTypeResolution::SkewedPolymorphic { profiled_type } => (profiled_type.class(), Some(profiled_type)),
- ReceiverTypeResolution::SkewedMegamorphic { .. }
- | ReceiverTypeResolution::Megamorphic => {
- if get_option!(stats) {
- self.set_dynamic_send_reason(insn_id, SendMegamorphic);
- }
- self.push_insn_id(block, insn_id);
- continue;
- }
- ReceiverTypeResolution::Polymorphic => {
- if get_option!(stats) {
- self.set_dynamic_send_reason(insn_id, SendPolymorphic);
- }
- self.push_insn_id(block, insn_id);
- continue;
- }
- ReceiverTypeResolution::NoProfile => {
- if get_option!(stats) {
- self.set_dynamic_send_reason(insn_id, SendNoProfiles);
- }
- self.push_insn_id(block, insn_id);
- continue;
- }
- };
- let ci = unsafe { get_call_data_ci(cd) }; // info about the call site
-
- let flags = unsafe { rb_vm_ci_flag(ci) };
-
- let mid = unsafe { vm_ci_mid(ci) };
- // Do method lookup
- let mut cme = unsafe { rb_callable_method_entry(klass, mid) };
- if cme.is_null() {
- self.set_dynamic_send_reason(insn_id, SendNotOptimizedMethodType(MethodType::Null));
- self.push_insn_id(block, insn_id); continue;
- }
- // Load an overloaded cme if applicable. See vm_search_cc().
- // It allows you to use a faster ISEQ if possible.
- cme = unsafe { rb_check_overloaded_cme(cme, ci) };
- let visibility = unsafe { METHOD_ENTRY_VISI(cme) };
- match (visibility, flags & VM_CALL_FCALL != 0) {
- (METHOD_VISI_PUBLIC, _) => {}
- (METHOD_VISI_PRIVATE, true) => {}
- (METHOD_VISI_PROTECTED, true) => {}
- _ => {
- self.set_dynamic_send_reason(insn_id, SendNotOptimizedNeedPermission);
- self.push_insn_id(block, insn_id); continue;
- }
- }
- let mut def_type = unsafe { get_cme_def_type(cme) };
- while def_type == VM_METHOD_TYPE_ALIAS {
- cme = unsafe { rb_aliased_callable_method_entry(cme) };
- def_type = unsafe { get_cme_def_type(cme) };
- }
-
- // If the call site info indicates that the `Function` has overly complex arguments, then do not optimize into a `SendDirect`.
- // Optimized methods(`VM_METHOD_TYPE_OPTIMIZED`) handle their own argument constraints (e.g., kw_splat for Proc call).
- if def_type != VM_METHOD_TYPE_OPTIMIZED && unspecializable_call_type(flags) {
- self.count_complex_call_features(block, flags);
- self.set_dynamic_send_reason(insn_id, ComplexArgPass);
- self.push_insn_id(block, insn_id); continue;
- }
-
- if def_type == VM_METHOD_TYPE_ISEQ {
- let iseq = unsafe { get_def_iseq_ptr((*cme).def) };
- if !can_direct_send(self, block, iseq, ci, insn_id, args.as_slice(), Some(blockiseq)) {
- self.push_insn_id(block, insn_id); continue;
- }
-
- // Check singleton class assumption first, before emitting other patchpoints
- if !self.assume_no_singleton_classes(block, klass, state) {
- self.set_dynamic_send_reason(insn_id, SingletonClassSeen);
- self.push_insn_id(block, insn_id); continue;
- }
-
- // Add PatchPoint for method redefinition
- self.push_insn(block, Insn::PatchPoint { invariant: Invariant::MethodRedefined { klass, method: mid, cme }, state });
-
- // Add GuardType for profiled receiver
- if let Some(profiled_type) = profiled_type {
- recv = self.push_insn(block, Insn::GuardType { val: recv, guard_type: Type::from_profiled_type(profiled_type), state });
- }
-
- let Ok((send_state, processed_args, kw_bits)) = self.prepare_direct_send_args(block, &args, ci, iseq, state)
- .inspect_err(|&reason| self.set_dynamic_send_reason(insn_id, reason)) else {
- self.push_insn_id(block, insn_id); continue;
- };
-
- let send_direct = self.push_insn(block, Insn::SendDirect {
- recv,
- cd,
- cme,
- iseq,
- args: processed_args,
- kw_bits,
- blockiseq: Some(blockiseq),
- state: send_state,
- });
- self.make_equal_to(insn_id, send_direct);
- } else {
- self.set_dynamic_send_reason(insn_id, SendNotOptimizedMethodType(MethodType::from(def_type)));
+ let reason = if has_block { SendNotOptimizedMethodType(MethodType::from(def_type)) } else { SendWithoutBlockNotOptimizedMethodType(MethodType::from(def_type)) };
+ self.set_dynamic_send_reason(insn_id, reason);
self.push_insn_id(block, insn_id); continue;
}
}
@@ -3440,7 +3318,7 @@ impl Function {
}
Insn::ObjToString { val, cd, state, .. } => {
if self.is_a(val, types::String) {
- // behaves differently from `SendWithoutBlock` with `mid:to_s` because ObjToString should not have a patch point for String to_s being redefined
+ // behaves differently from `Send` with `mid:to_s` because ObjToString should not have a patch point for String to_s being redefined
self.make_equal_to(insn_id, val); continue;
}
@@ -3457,7 +3335,7 @@ impl Function {
self.make_equal_to(insn_id, guard);
} else {
let recv = self.push_insn(block, Insn::GuardType { val, guard_type: Type::from_profiled_type(recv_type), state});
- let send_to_s = self.push_insn(block, Insn::SendWithoutBlock { recv, cd, args: vec![], state, reason: ObjToStringNotString });
+ let send_to_s = self.push_insn(block, Insn::Send { recv, cd, blockiseq: None, args: vec![], state, reason: ObjToStringNotString });
self.make_equal_to(insn_id, send_to_s);
}
}
@@ -4066,7 +3944,7 @@ impl Function {
self.push_insn(block, Insn::IncrCounterPtr { counter_ptr });
}
- /// Optimize Send/SendWithoutBlock that land in a C method to a direct CCall without
+ /// Optimize Send that land in a C method to a direct CCall without
/// runtime lookup.
fn optimize_c_calls(&mut self) {
if unsafe { rb_zjit_method_tracing_currently_enabled() } {
@@ -4139,7 +4017,11 @@ impl Function {
return Err(());
}
- let blockiseq = if blockiseq.is_null() { None } else { Some(blockiseq) };
+ let blockiseq = match blockiseq {
+ None => unreachable!("went to reduce_send_without_block_to_ccall"),
+ Some(p) if p.is_null() => None,
+ Some(blockiseq) => Some(blockiseq),
+ };
let cfunc = unsafe { get_cme_def_body_cfunc(cme) };
// Find the `argc` (arity) of the C method, which describes the parameters it expects
@@ -4236,7 +4118,7 @@ impl Function {
}
}
- // Try to reduce a SendWithoutBlock insn to a CCall/CCallWithFrame
+ // Try to reduce a Send insn with blockiseq: None to a CCall/CCallWithFrame
fn reduce_send_without_block_to_ccall(
fun: &mut Function,
block: BlockId,
@@ -4244,7 +4126,7 @@ impl Function {
send: Insn,
send_insn_id: InsnId,
) -> Result<(), ()> {
- let Insn::SendWithoutBlock { mut recv, cd, args, state, .. } = send else {
+ let Insn::Send { mut recv, cd, args, state, .. } = send else {
return Err(());
};
@@ -4474,7 +4356,7 @@ impl Function {
for insn_id in old_insns {
let send = self.find(insn_id);
match send {
- send @ Insn::SendWithoutBlock { recv, .. } => {
+ send @ Insn::Send { recv, blockiseq: None, .. } => {
let recv_type = self.type_of(recv);
if reduce_send_without_block_to_ccall(self, block, recv_type, send, insn_id).is_ok() {
continue;
@@ -4877,7 +4759,6 @@ impl Function {
}
&Insn::Send { recv, ref args, state, .. }
| &Insn::SendForward { recv, ref args, state, .. }
- | &Insn::SendWithoutBlock { recv, ref args, state, .. }
| &Insn::CCallVariadic { recv, ref args, state, .. }
| &Insn::CCallWithFrame { recv, ref args, state, .. }
| &Insn::SendDirect { recv, ref args, state, .. }
@@ -5537,8 +5418,7 @@ impl Function {
self.assert_subtype(insn_id, allow_nil, types::BoolExact)
}
// Instructions with recv and a Vec of Ruby objects
- Insn::SendWithoutBlock { recv, ref args, .. }
- | Insn::SendDirect { recv, ref args, .. }
+ Insn::SendDirect { recv, ref args, .. }
| Insn::Send { recv, ref args, .. }
| Insn::SendForward { recv, ref args, .. }
| Insn::InvokeSuper { recv, ref args, .. }
@@ -7030,7 +6910,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
let args = state.stack_pop_n(argc as usize)?;
let recv = state.stack_pop()?;
- let send = fun.push_insn(block, Insn::SendWithoutBlock { recv, cd, args, state: exit_id, reason: Uncategorized(opcode) });
+ let send = fun.push_insn(block, Insn::Send { recv, cd, blockiseq: None, args, state: exit_id, reason: Uncategorized(opcode) });
state.stack_push(send);
}
YARVINSN_opt_hash_freeze => {
@@ -7153,7 +7033,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
let recv = state.stack_pop().unwrap();
let refined_recv = fun.push_insn(block, Insn::RefineType { val: recv, new_type });
state.replace(recv, refined_recv);
- let send = fun.push_insn(block, Insn::SendWithoutBlock { recv: refined_recv, cd, args, state: snapshot, reason: Uncategorized(opcode) });
+ let send = fun.push_insn(block, Insn::Send { recv: refined_recv, cd, blockiseq: None, args, state: snapshot, reason: Uncategorized(opcode) });
state.stack_push(send);
fun.push_insn(block, Insn::Jump(BranchEdge { target: join_block, args: state.as_args(self_param) }));
block
@@ -7186,7 +7066,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
let args = state.stack_pop_n(argc as usize)?;
let recv = state.stack_pop()?;
let reason = SendWithoutBlockPolymorphicFallback;
- let send = fun.push_insn(block, Insn::SendWithoutBlock { recv, cd, args, state: exit_id, reason });
+ let send = fun.push_insn(block, Insn::Send { recv, cd, blockiseq: None, args, state: exit_id, reason });
state.stack_push(send);
fun.push_insn(block, Insn::Jump(BranchEdge { target: join_block, args: state.as_args(self_param) }));
break; // End the block
@@ -7195,7 +7075,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
let args = state.stack_pop_n(argc as usize)?;
let recv = state.stack_pop()?;
- let send = fun.push_insn(block, Insn::SendWithoutBlock { recv, cd, args, state: exit_id, reason: Uncategorized(opcode) });
+ let send = fun.push_insn(block, Insn::Send { recv, cd, blockiseq: None, args, state: exit_id, reason: Uncategorized(opcode) });
state.stack_push(send);
}
YARVINSN_send => {
@@ -7213,7 +7093,7 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
let args = state.stack_pop_n(argc as usize + usize::from(block_arg))?;
let recv = state.stack_pop()?;
- let send = fun.push_insn(block, Insn::Send { recv, cd, blockiseq, args, state: exit_id, reason: Uncategorized(opcode) });
+ let send = fun.push_insn(block, Insn::Send { recv, cd, blockiseq: Some(blockiseq), args, state: exit_id, reason: Uncategorized(opcode) });
state.stack_push(send);
if !blockiseq.is_null() {
diff --git a/zjit/src/hir/opt_tests.rs b/zjit/src/hir/opt_tests.rs
index d32de872d5..1315555694 100644
--- a/zjit/src/hir/opt_tests.rs
+++ b/zjit/src/hir/opt_tests.rs
@@ -863,6 +863,37 @@ mod hir_opt_tests {
");
}
+ // Regression test: when specialized_instruction is disabled, the compiler
+ // doesn't convert `send` to `opt_send_without_block`, so a no-block call
+ // reaches ZJIT as `YARVINSN_send` with a null blockiseq. This becomes
+ // `Send { blockiseq: Some(null_ptr) }` which must be normalized to None in
+ // reduce_send_to_ccall, otherwise CCallWithFrame gens wrong block handler.
+ #[test]
+ fn test_send_to_cfunc_without_specialized_instruction() {
+ eval_with_options("
+ def test(a) = a.length
+ test([1,2,3]); test([1,2,3])
+ ", "{ specialized_instruction: false }");
+ assert_snapshot!(hir_string("test"), @r"
+ fn test@<compiled>:2:
+ bb0():
+ EntryPoint interpreter
+ v1:BasicObject = LoadSelf
+ v2:BasicObject = GetLocal :a, l0, SP@4
+ Jump bb2(v1, v2)
+ bb1(v5:BasicObject, v6:BasicObject):
+ EntryPoint JIT(0)
+ Jump bb2(v5, v6)
+ bb2(v8:BasicObject, v9:BasicObject):
+ PatchPoint NoSingletonClass(Array@0x1000)
+ PatchPoint MethodRedefined(Array@0x1000, length@0x1008, cme:0x1010)
+ v22:ArrayExact = GuardType v9, ArrayExact
+ v23:BasicObject = CCallWithFrame v22, :Array#length@0x1038
+ CheckInterrupts
+ Return v23
+ ");
+ }
+
#[test]
fn test_optimize_nonexistent_top_level_call() {
eval("
@@ -884,7 +915,7 @@ mod hir_opt_tests {
EntryPoint JIT(0)
Jump bb2(v4)
bb2(v6:BasicObject):
- v11:BasicObject = SendWithoutBlock v6, :foo # SendFallbackReason: SendWithoutBlock: unsupported method type Null
+ v11:BasicObject = Send v6, :foo # SendFallbackReason: SendWithoutBlock: unsupported method type Null
CheckInterrupts
Return v11
");
@@ -1126,7 +1157,7 @@ mod hir_opt_tests {
v28:Fixnum[30] = Const Value(30)
v30:Fixnum[40] = Const Value(40)
v32:Fixnum[50] = Const Value(50)
- v34:BasicObject = SendWithoutBlock v6, :target, v24, v26, v28, v30, v32 # SendFallbackReason: Argument count does not match parameter count
+ v34:BasicObject = Send v6, :target, v24, v26, v28, v30, v32 # SendFallbackReason: Argument count does not match parameter count
v37:ArrayExact = NewArray v45, v49, v34
CheckInterrupts
Return v37
@@ -2689,7 +2720,7 @@ mod hir_opt_tests {
bb2(v6:BasicObject):
v10:Fixnum[1] = Const Value(1)
v12:Fixnum[0] = Const Value(0)
- v14:BasicObject = SendWithoutBlock v10, :itself, v12 # SendFallbackReason: SendWithoutBlock: unsupported method type Cfunc
+ v14:BasicObject = Send v10, :itself, v12 # SendFallbackReason: SendWithoutBlock: unsupported method type Cfunc
CheckInterrupts
Return v14
");
@@ -2984,7 +3015,7 @@ mod hir_opt_tests {
bb2(v6:BasicObject):
v11:Fixnum[1] = Const Value(1)
IncrCounter complex_arg_pass_param_rest
- v13:BasicObject = SendWithoutBlock v6, :foo, v11 # SendFallbackReason: Complex argument passing
+ v13:BasicObject = Send v6, :foo, v11 # SendFallbackReason: Complex argument passing
CheckInterrupts
Return v13
");
@@ -3009,7 +3040,7 @@ mod hir_opt_tests {
bb2(v6:BasicObject):
v11:Fixnum[10] = Const Value(10)
IncrCounter complex_arg_pass_param_post
- v13:BasicObject = SendWithoutBlock v6, :foo, v11 # SendFallbackReason: Complex argument passing
+ v13:BasicObject = Send v6, :foo, v11 # SendFallbackReason: Complex argument passing
CheckInterrupts
Return v13
");
@@ -3248,7 +3279,7 @@ mod hir_opt_tests {
v33:Fixnum[40] = Const Value(40)
v35:Fixnum[50] = Const Value(50)
v37:Fixnum[60] = Const Value(60)
- v39:BasicObject = SendWithoutBlock v6, :target, v27, v29, v31, v33, v35, v37 # SendFallbackReason: Too many arguments for LIR
+ v39:BasicObject = Send v6, :target, v27, v29, v31, v33, v35, v37 # SendFallbackReason: Too many arguments for LIR
v41:ArrayExact = NewArray v49, v53, v39
CheckInterrupts
Return v41
@@ -3303,7 +3334,7 @@ mod hir_opt_tests {
bb2(v6:BasicObject):
v11:Fixnum[1] = Const Value(1)
IncrCounter complex_arg_pass_param_kwrest
- v13:BasicObject = SendWithoutBlock v6, :foo, v11 # SendFallbackReason: Complex argument passing
+ v13:BasicObject = Send v6, :foo, v11 # SendFallbackReason: Complex argument passing
CheckInterrupts
Return v13
");
@@ -3358,7 +3389,7 @@ mod hir_opt_tests {
v11:HashExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
v12:HashExact = HashDup v11
IncrCounter complex_arg_pass_caller_kw_splat
- v14:BasicObject = SendWithoutBlock v6, :foo, v12 # SendFallbackReason: Complex argument passing
+ v14:BasicObject = Send v6, :foo, v12 # SendFallbackReason: Complex argument passing
CheckInterrupts
Return v14
");
@@ -3383,7 +3414,7 @@ mod hir_opt_tests {
Jump bb2(v4)
bb2(v6:BasicObject):
IncrCounter complex_arg_pass_param_kwrest
- v11:BasicObject = SendWithoutBlock v6, :foo # SendFallbackReason: Complex argument passing
+ v11:BasicObject = Send v6, :foo # SendFallbackReason: Complex argument passing
CheckInterrupts
Return v11
");
@@ -3410,7 +3441,7 @@ mod hir_opt_tests {
v12:StringExact = StringCopy v11
v14:Fixnum[1] = Const Value(1)
IncrCounter complex_arg_pass_caller_kwarg
- v16:BasicObject = SendWithoutBlock v6, :sprintf, v12, v14 # SendFallbackReason: Complex argument passing
+ v16:BasicObject = Send v6, :sprintf, v12, v14 # SendFallbackReason: Complex argument passing
CheckInterrupts
Return v16
");
@@ -3707,7 +3738,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Hash@0x1008, new@0x1009, cme:0x1010)
v46:HashExact = ObjectAllocClass Hash:VALUE(0x1008)
IncrCounter complex_arg_pass_param_block
- v20:BasicObject = SendWithoutBlock v46, :initialize # SendFallbackReason: Complex argument passing
+ v20:BasicObject = Send v46, :initialize # SendFallbackReason: Complex argument passing
CheckInterrupts
CheckInterrupts
Return v46
@@ -3917,7 +3948,7 @@ mod hir_opt_tests {
v17:CInt64 = LoadField v14, :_env_data_index_specval@0x1001
v18:CInt64 = GuardAnyBitSet v17, CUInt64(1)
v19:HeapObject[BlockParamProxy] = Const Value(VALUE(0x1008))
- v21:BasicObject = Send v8, 0x1010, :tap, v19 # SendFallbackReason: Uncategorized(send)
+ v21:BasicObject = Send v8, 0x1000, :tap, v19 # SendFallbackReason: Uncategorized(send)
CheckInterrupts
Return v21
");
@@ -4228,7 +4259,7 @@ mod hir_opt_tests {
v16:ArrayExact = NewArray
v22:ArrayExact = ToArray v16
IncrCounter complex_arg_pass_caller_splat
- v24:BasicObject = SendWithoutBlock v11, :call, v22 # SendFallbackReason: Complex argument passing
+ v24:BasicObject = Send v11, :call, v22 # SendFallbackReason: Complex argument passing
CheckInterrupts
Return v24
");
@@ -4256,7 +4287,7 @@ mod hir_opt_tests {
bb2(v8:BasicObject, v9:BasicObject):
v14:Fixnum[1] = Const Value(1)
IncrCounter complex_arg_pass_caller_kwarg
- v16:BasicObject = SendWithoutBlock v9, :call, v14 # SendFallbackReason: Complex argument passing
+ v16:BasicObject = Send v9, :call, v14 # SendFallbackReason: Complex argument passing
CheckInterrupts
Return v16
");
@@ -4673,7 +4704,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Hash@0x1000)
PatchPoint MethodRedefined(Hash@0x1000, dup@0x1008, cme:0x1010)
v22:BasicObject = CCallWithFrame v10, :Kernel#dup@0x1038
- v14:BasicObject = SendWithoutBlock v22, :freeze # SendFallbackReason: Uncategorized(opt_send_without_block)
+ v14:BasicObject = Send v22, :freeze # SendFallbackReason: Uncategorized(opt_send_without_block)
CheckInterrupts
Return v14
");
@@ -4696,7 +4727,7 @@ mod hir_opt_tests {
bb2(v6:BasicObject):
v10:HashExact = NewHash
v12:NilClass = Const Value(nil)
- v14:BasicObject = SendWithoutBlock v10, :freeze, v12 # SendFallbackReason: SendWithoutBlock: unsupported method type Cfunc
+ v14:BasicObject = Send v10, :freeze, v12 # SendFallbackReason: SendWithoutBlock: unsupported method type Cfunc
CheckInterrupts
Return v14
");
@@ -4766,7 +4797,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Array@0x1000)
PatchPoint MethodRedefined(Array@0x1000, dup@0x1008, cme:0x1010)
v22:BasicObject = CCallWithFrame v10, :Kernel#dup@0x1038
- v14:BasicObject = SendWithoutBlock v22, :freeze # SendFallbackReason: Uncategorized(opt_send_without_block)
+ v14:BasicObject = Send v22, :freeze # SendFallbackReason: Uncategorized(opt_send_without_block)
CheckInterrupts
Return v14
");
@@ -4789,7 +4820,7 @@ mod hir_opt_tests {
bb2(v6:BasicObject):
v10:ArrayExact = NewArray
v12:NilClass = Const Value(nil)
- v14:BasicObject = SendWithoutBlock v10, :freeze, v12 # SendFallbackReason: SendWithoutBlock: unsupported method type Cfunc
+ v14:BasicObject = Send v10, :freeze, v12 # SendFallbackReason: SendWithoutBlock: unsupported method type Cfunc
CheckInterrupts
Return v14
");
@@ -4860,7 +4891,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(String@0x1008)
PatchPoint MethodRedefined(String@0x1008, dup@0x1010, cme:0x1018)
v23:BasicObject = CCallWithFrame v11, :String#dup@0x1040
- v15:BasicObject = SendWithoutBlock v23, :freeze # SendFallbackReason: Uncategorized(opt_send_without_block)
+ v15:BasicObject = Send v23, :freeze # SendFallbackReason: Uncategorized(opt_send_without_block)
CheckInterrupts
Return v15
");
@@ -4884,7 +4915,7 @@ mod hir_opt_tests {
v10:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
v11:StringExact = StringCopy v10
v13:NilClass = Const Value(nil)
- v15:BasicObject = SendWithoutBlock v11, :freeze, v13 # SendFallbackReason: SendWithoutBlock: unsupported method type Cfunc
+ v15:BasicObject = Send v11, :freeze, v13 # SendFallbackReason: SendWithoutBlock: unsupported method type Cfunc
CheckInterrupts
Return v15
");
@@ -4955,7 +4986,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(String@0x1008)
PatchPoint MethodRedefined(String@0x1008, dup@0x1010, cme:0x1018)
v23:BasicObject = CCallWithFrame v11, :String#dup@0x1040
- v15:BasicObject = SendWithoutBlock v23, :-@ # SendFallbackReason: Uncategorized(opt_send_without_block)
+ v15:BasicObject = Send v23, :-@ # SendFallbackReason: Uncategorized(opt_send_without_block)
CheckInterrupts
Return v15
");
@@ -5381,7 +5412,7 @@ mod hir_opt_tests {
bb2(v8:BasicObject, v9:BasicObject):
v16:Fixnum[1] = Const Value(1)
v18:Fixnum[10] = Const Value(10)
- v22:BasicObject = SendWithoutBlock v9, :[]=, v16, v18 # SendFallbackReason: Uncategorized(opt_aset)
+ v22:BasicObject = Send v9, :[]=, v16, v18 # SendFallbackReason: Uncategorized(opt_aset)
CheckInterrupts
Return v18
");
@@ -5517,7 +5548,7 @@ mod hir_opt_tests {
Jump bb2(v4)
bb2(v6:BasicObject):
v11:Fixnum[100] = Const Value(100)
- v13:BasicObject = SendWithoutBlock v6, :identity, v11 # SendFallbackReason: Bmethod: Proc object is not defined by an ISEQ
+ v13:BasicObject = Send v6, :identity, v11 # SendFallbackReason: Bmethod: Proc object is not defined by an ISEQ
CheckInterrupts
Return v13
");
@@ -6389,7 +6420,7 @@ mod hir_opt_tests {
EntryPoint JIT(0)
Jump bb2(v4)
bb2(v6:BasicObject):
- v11:BasicObject = SendWithoutBlock v6, :foo # SendFallbackReason: Uncategorized(opt_send_without_block)
+ v11:BasicObject = Send v6, :foo # SendFallbackReason: Uncategorized(opt_send_without_block)
CheckInterrupts
Return v11
");
@@ -6436,7 +6467,7 @@ mod hir_opt_tests {
IfTrue v14, bb4(v8, v9, v9)
v23:CBool = HasType v9, HeapObject[class_exact:C]
IfTrue v23, bb5(v8, v9, v9)
- v32:BasicObject = SendWithoutBlock v9, :foo # SendFallbackReason: SendWithoutBlock: polymorphic fallback
+ v32:BasicObject = Send v9, :foo # SendFallbackReason: SendWithoutBlock: polymorphic fallback
Jump bb3(v8, v9, v32)
bb4(v15:BasicObject, v16:BasicObject, v17:BasicObject):
v19:HeapObject[class_exact:C] = RefineType v17, HeapObject[class_exact:C]
@@ -6589,7 +6620,7 @@ mod hir_opt_tests {
v19:CInt64 = GuardAnyBitSet v18, CUInt64(1)
v20:HeapObject[BlockParamProxy] = Const Value(VALUE(0x1008))
IncrCounter complex_arg_pass_caller_blockarg
- v22:BasicObject = Send v13, 0x1010, :map, v20 # SendFallbackReason: Complex argument passing
+ v22:BasicObject = Send v13, 0x1000, :map, v20 # SendFallbackReason: Complex argument passing
CheckInterrupts
Return v22
");
@@ -6620,7 +6651,7 @@ mod hir_opt_tests {
v19:CInt64[0] = GuardBitEquals v18, CInt64(0)
v20:NilClass = Const Value(nil)
IncrCounter complex_arg_pass_caller_blockarg
- v22:BasicObject = Send v13, 0x1008, :map, v20 # SendFallbackReason: Complex argument passing
+ v22:BasicObject = Send v13, 0x1000, :map, v20 # SendFallbackReason: Complex argument passing
CheckInterrupts
Return v22
");
@@ -6654,7 +6685,7 @@ mod hir_opt_tests {
v16:CInt64 = GuardAnyBitSet v15, CUInt64(1)
v17:HeapObject[BlockParamProxy] = Const Value(VALUE(0x1008))
IncrCounter complex_arg_pass_caller_blockarg
- v19:BasicObject = Send v10, 0x1010, :map, v17 # SendFallbackReason: Complex argument passing
+ v19:BasicObject = Send v10, 0x1000, :map, v17 # SendFallbackReason: Complex argument passing
CheckInterrupts
Return v19
");
@@ -8609,7 +8640,7 @@ mod hir_opt_tests {
v12:Fixnum[3] = Const Value(3)
v14:Fixnum[3] = Const Value(3)
v16:Fixnum[3] = Const Value(3)
- v18:BasicObject = SendWithoutBlock v10, :foo, v12, v14, v16 # SendFallbackReason: Argument count does not match parameter count
+ v18:BasicObject = Send v10, :foo, v12, v14, v16 # SendFallbackReason: Argument count does not match parameter count
CheckInterrupts
Return v18
");
@@ -8659,7 +8690,7 @@ mod hir_opt_tests {
Jump bb2(v4)
bb2(v6:BasicObject):
v10:Fixnum[0] = Const Value(0)
- v12:BasicObject = SendWithoutBlock v10, :foo # SendFallbackReason: Argument count does not match parameter count
+ v12:BasicObject = Send v10, :foo # SendFallbackReason: Argument count does not match parameter count
CheckInterrupts
Return v12
");
@@ -8682,7 +8713,7 @@ mod hir_opt_tests {
bb2(v6:BasicObject):
v10:Fixnum[4] = Const Value(4)
v12:Fixnum[1] = Const Value(1)
- v14:BasicObject = SendWithoutBlock v10, :succ, v12 # SendFallbackReason: SendWithoutBlock: unsupported method type Cfunc
+ v14:BasicObject = Send v10, :succ, v12 # SendFallbackReason: SendWithoutBlock: unsupported method type Cfunc
CheckInterrupts
Return v14
");
@@ -8836,7 +8867,7 @@ mod hir_opt_tests {
EntryPoint JIT(0)
Jump bb2(v6, v7, v8)
bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject):
- v17:BasicObject = SendWithoutBlock v11, :^ # SendFallbackReason: Uncategorized(opt_send_without_block)
+ v17:BasicObject = Send v11, :^ # SendFallbackReason: Uncategorized(opt_send_without_block)
CheckInterrupts
Return v17
");
@@ -9511,17 +9542,17 @@ mod hir_opt_tests {
v13:ArrayExact = NewArray
v19:ArrayExact = ToArray v13
IncrCounter complex_arg_pass_caller_splat
- v21:BasicObject = SendWithoutBlock v8, :foo, v19 # SendFallbackReason: Complex argument passing
+ v21:BasicObject = Send v8, :foo, v19 # SendFallbackReason: Complex argument passing
v25:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
v26:StringExact = StringCopy v25
PatchPoint NoEPEscape(test)
v31:ArrayExact = ToArray v13
IncrCounter complex_arg_pass_caller_splat
- v33:BasicObject = SendWithoutBlock v26, :display, v31 # SendFallbackReason: Complex argument passing
+ v33:BasicObject = Send v26, :display, v31 # SendFallbackReason: Complex argument passing
PatchPoint NoEPEscape(test)
v41:ArrayExact = ToArray v13
IncrCounter complex_arg_pass_caller_splat
- v43:BasicObject = SendWithoutBlock v8, :itself, v41 # SendFallbackReason: Complex argument passing
+ v43:BasicObject = Send v8, :itself, v41 # SendFallbackReason: Complex argument passing
CheckInterrupts
Return v43
");
@@ -10322,7 +10353,7 @@ mod hir_opt_tests {
IncrCounter complex_arg_pass_param_rest
IncrCounter complex_arg_pass_param_block
IncrCounter complex_arg_pass_param_kwrest
- v13:BasicObject = SendWithoutBlock v6, :fancy, v11 # SendFallbackReason: Complex argument passing
+ v13:BasicObject = Send v6, :fancy, v11 # SendFallbackReason: Complex argument passing
CheckInterrupts
Return v13
");
@@ -10346,7 +10377,7 @@ mod hir_opt_tests {
Jump bb2(v4)
bb2(v6:BasicObject):
IncrCounter complex_arg_pass_param_forwardable
- v11:BasicObject = SendWithoutBlock v6, :forwardable # SendFallbackReason: Complex argument passing
+ v11:BasicObject = Send v6, :forwardable # SendFallbackReason: Complex argument passing
CheckInterrupts
Return v11
");
@@ -11081,7 +11112,7 @@ mod hir_opt_tests {
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, Obj)
v21:HeapObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
- v13:BasicObject = SendWithoutBlock v21, :secret # SendFallbackReason: SendWithoutBlock: method private or protected and no FCALL
+ v13:BasicObject = Send v21, :secret # SendFallbackReason: SendWithoutBlock: method private or protected and no FCALL
CheckInterrupts
Return v13
");
@@ -11135,7 +11166,7 @@ mod hir_opt_tests {
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, Obj)
v21:BasicObjectExact[VALUE(0x1008)] = Const Value(VALUE(0x1008))
- v13:BasicObject = SendWithoutBlock v21, :initialize # SendFallbackReason: SendWithoutBlock: method private or protected and no FCALL
+ v13:BasicObject = Send v21, :initialize # SendFallbackReason: SendWithoutBlock: method private or protected and no FCALL
CheckInterrupts
Return v13
");
@@ -11162,7 +11193,7 @@ mod hir_opt_tests {
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, Obj)
v21:ObjectExact[VALUE(0x1008)] = Const Value(VALUE(0x1008))
- v13:BasicObject = SendWithoutBlock v21, :toplevel_method # SendFallbackReason: SendWithoutBlock: method private or protected and no FCALL
+ v13:BasicObject = Send v21, :toplevel_method # SendFallbackReason: SendWithoutBlock: method private or protected and no FCALL
CheckInterrupts
Return v13
");
@@ -11220,7 +11251,7 @@ mod hir_opt_tests {
PatchPoint SingleRactorMode
PatchPoint StableConstantNames(0x1000, Obj)
v21:HeapObject[VALUE(0x1008)] = Const Value(VALUE(0x1008))
- v13:BasicObject = SendWithoutBlock v21, :secret # SendFallbackReason: SendWithoutBlock: method private or protected and no FCALL
+ v13:BasicObject = Send v21, :secret # SendFallbackReason: SendWithoutBlock: method private or protected and no FCALL
CheckInterrupts
Return v13
");
@@ -11259,7 +11290,7 @@ mod hir_opt_tests {
EntryPoint JIT(0)
Jump bb2(v5, v6)
bb2(v8:BasicObject, v9:BasicObject):
- v15:BasicObject = SendWithoutBlock v9, :length # SendFallbackReason: Singleton class previously created for receiver class
+ v15:BasicObject = Send v9, :length # SendFallbackReason: Singleton class previously created for receiver class
CheckInterrupts
Return v15
");
@@ -11783,7 +11814,7 @@ mod hir_opt_tests {
IfTrue v14, bb4(v8, v9, v9)
v23:CBool = HasType v9, HeapObject[class_exact:D]
IfTrue v23, bb5(v8, v9, v9)
- v32:BasicObject = SendWithoutBlock v9, :foo # SendFallbackReason: SendWithoutBlock: polymorphic fallback
+ v32:BasicObject = Send v9, :foo # SendFallbackReason: SendWithoutBlock: polymorphic fallback
Jump bb3(v8, v9, v32)
bb4(v15:BasicObject, v16:BasicObject, v17:BasicObject):
PatchPoint NoSingletonClass(C@0x1000)
@@ -11835,7 +11866,7 @@ mod hir_opt_tests {
IfTrue v14, bb4(v8, v9, v9)
v23:CBool = HasType v9, Fixnum
IfTrue v23, bb5(v8, v9, v9)
- v32:BasicObject = SendWithoutBlock v9, :itself # SendFallbackReason: SendWithoutBlock: polymorphic fallback
+ v32:BasicObject = Send v9, :itself # SendFallbackReason: SendWithoutBlock: polymorphic fallback
Jump bb3(v8, v9, v32)
bb4(v15:BasicObject, v16:BasicObject, v17:BasicObject):
v19:HeapObject[class_exact:C] = RefineType v17, HeapObject[class_exact:C]
diff --git a/zjit/src/hir/tests.rs b/zjit/src/hir/tests.rs
index 0401ffcd7d..8b15d7d23f 100644
--- a/zjit/src/hir/tests.rs
+++ b/zjit/src/hir/tests.rs
@@ -151,7 +151,7 @@ mod snapshot_tests {
v23:Fixnum[7] = Const Value(7)
v25:Fixnum[8] = Const Value(8)
v26:Any = Snapshot FrameState { pc: 0x1008, stack: [v6, v11, v13, v15, v17, v19, v21, v23, v25], locals: [] }
- v27:BasicObject = SendWithoutBlock v6, :foo, v11, v13, v15, v17, v19, v21, v23, v25 # SendFallbackReason: Too many arguments for LIR
+ v27:BasicObject = Send v6, :foo, v11, v13, v15, v17, v19, v21, v23, v25 # SendFallbackReason: Too many arguments for LIR
v28:Any = Snapshot FrameState { pc: 0x1010, stack: [v27], locals: [] }
PatchPoint NoTracePoint
CheckInterrupts
@@ -641,7 +641,7 @@ pub mod hir_build_tests {
bb2(v6:BasicObject):
v10:Fixnum[1] = Const Value(1)
v12:Fixnum[2] = Const Value(2)
- v15:BasicObject = SendWithoutBlock v10, :+, v12 # SendFallbackReason: Uncategorized(opt_plus)
+ v15:BasicObject = Send v10, :+, v12 # SendFallbackReason: Uncategorized(opt_plus)
CheckInterrupts
Return v15
");
@@ -894,11 +894,11 @@ pub mod hir_build_tests {
SetLocal :l1, l1, EP@3, v10
v15:BasicObject = GetLocal :l1, l1, EP@3
v17:BasicObject = GetLocal :l2, l2, EP@4
- v20:BasicObject = SendWithoutBlock v15, :+, v17 # SendFallbackReason: Uncategorized(opt_plus)
+ v20:BasicObject = Send v15, :+, v17 # SendFallbackReason: Uncategorized(opt_plus)
SetLocal :l2, l2, EP@4, v20
v25:BasicObject = GetLocal :l2, l2, EP@4
v27:BasicObject = GetLocal :l3, l3, EP@5
- v30:BasicObject = SendWithoutBlock v25, :+, v27 # SendFallbackReason: Uncategorized(opt_plus)
+ v30:BasicObject = Send v25, :+, v27 # SendFallbackReason: Uncategorized(opt_plus)
SetLocal :l3, l3, EP@5, v30
CheckInterrupts
Return v30
@@ -1268,7 +1268,7 @@ pub mod hir_build_tests {
EntryPoint JIT(0)
Jump bb2(v6, v7, v8)
bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject):
- v19:BasicObject = SendWithoutBlock v11, :+, v12 # SendFallbackReason: Uncategorized(opt_plus)
+ v19:BasicObject = Send v11, :+, v12 # SendFallbackReason: Uncategorized(opt_plus)
CheckInterrupts
Return v19
");
@@ -1293,7 +1293,7 @@ pub mod hir_build_tests {
EntryPoint JIT(0)
Jump bb2(v6, v7, v8)
bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject):
- v19:BasicObject = SendWithoutBlock v11, :-, v12 # SendFallbackReason: Uncategorized(opt_minus)
+ v19:BasicObject = Send v11, :-, v12 # SendFallbackReason: Uncategorized(opt_minus)
CheckInterrupts
Return v19
");
@@ -1318,7 +1318,7 @@ pub mod hir_build_tests {
EntryPoint JIT(0)
Jump bb2(v6, v7, v8)
bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject):
- v19:BasicObject = SendWithoutBlock v11, :*, v12 # SendFallbackReason: Uncategorized(opt_mult)
+ v19:BasicObject = Send v11, :*, v12 # SendFallbackReason: Uncategorized(opt_mult)
CheckInterrupts
Return v19
");
@@ -1343,7 +1343,7 @@ pub mod hir_build_tests {
EntryPoint JIT(0)
Jump bb2(v6, v7, v8)
bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject):
- v19:BasicObject = SendWithoutBlock v11, :/, v12 # SendFallbackReason: Uncategorized(opt_div)
+ v19:BasicObject = Send v11, :/, v12 # SendFallbackReason: Uncategorized(opt_div)
CheckInterrupts
Return v19
");
@@ -1368,7 +1368,7 @@ pub mod hir_build_tests {
EntryPoint JIT(0)
Jump bb2(v6, v7, v8)
bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject):
- v19:BasicObject = SendWithoutBlock v11, :%, v12 # SendFallbackReason: Uncategorized(opt_mod)
+ v19:BasicObject = Send v11, :%, v12 # SendFallbackReason: Uncategorized(opt_mod)
CheckInterrupts
Return v19
");
@@ -1393,7 +1393,7 @@ pub mod hir_build_tests {
EntryPoint JIT(0)
Jump bb2(v6, v7, v8)
bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject):
- v19:BasicObject = SendWithoutBlock v11, :==, v12 # SendFallbackReason: Uncategorized(opt_eq)
+ v19:BasicObject = Send v11, :==, v12 # SendFallbackReason: Uncategorized(opt_eq)
CheckInterrupts
Return v19
");
@@ -1418,7 +1418,7 @@ pub mod hir_build_tests {
EntryPoint JIT(0)
Jump bb2(v6, v7, v8)
bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject):
- v19:BasicObject = SendWithoutBlock v11, :!=, v12 # SendFallbackReason: Uncategorized(opt_neq)
+ v19:BasicObject = Send v11, :!=, v12 # SendFallbackReason: Uncategorized(opt_neq)
CheckInterrupts
Return v19
");
@@ -1443,7 +1443,7 @@ pub mod hir_build_tests {
EntryPoint JIT(0)
Jump bb2(v6, v7, v8)
bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject):
- v19:BasicObject = SendWithoutBlock v11, :<, v12 # SendFallbackReason: Uncategorized(opt_lt)
+ v19:BasicObject = Send v11, :<, v12 # SendFallbackReason: Uncategorized(opt_lt)
CheckInterrupts
Return v19
");
@@ -1468,7 +1468,7 @@ pub mod hir_build_tests {
EntryPoint JIT(0)
Jump bb2(v6, v7, v8)
bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject):
- v19:BasicObject = SendWithoutBlock v11, :<=, v12 # SendFallbackReason: Uncategorized(opt_le)
+ v19:BasicObject = Send v11, :<=, v12 # SendFallbackReason: Uncategorized(opt_le)
CheckInterrupts
Return v19
");
@@ -1493,7 +1493,7 @@ pub mod hir_build_tests {
EntryPoint JIT(0)
Jump bb2(v6, v7, v8)
bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject):
- v19:BasicObject = SendWithoutBlock v11, :>, v12 # SendFallbackReason: Uncategorized(opt_gt)
+ v19:BasicObject = Send v11, :>, v12 # SendFallbackReason: Uncategorized(opt_gt)
CheckInterrupts
Return v19
");
@@ -1533,7 +1533,7 @@ pub mod hir_build_tests {
Jump bb4(v10, v16, v20)
bb4(v26:BasicObject, v27:BasicObject, v28:BasicObject):
v32:Fixnum[0] = Const Value(0)
- v35:BasicObject = SendWithoutBlock v28, :>, v32 # SendFallbackReason: Uncategorized(opt_gt)
+ v35:BasicObject = Send v28, :>, v32 # SendFallbackReason: Uncategorized(opt_gt)
CheckInterrupts
v38:CBool = Test v35
v39:Truthy = RefineType v35, Truthy
@@ -1544,9 +1544,9 @@ pub mod hir_build_tests {
Return v27
bb3(v51:BasicObject, v52:BasicObject, v53:BasicObject):
v58:Fixnum[1] = Const Value(1)
- v61:BasicObject = SendWithoutBlock v52, :+, v58 # SendFallbackReason: Uncategorized(opt_plus)
+ v61:BasicObject = Send v52, :+, v58 # SendFallbackReason: Uncategorized(opt_plus)
v66:Fixnum[1] = Const Value(1)
- v69:BasicObject = SendWithoutBlock v53, :-, v66 # SendFallbackReason: Uncategorized(opt_minus)
+ v69:BasicObject = Send v53, :-, v66 # SendFallbackReason: Uncategorized(opt_minus)
Jump bb4(v51, v61, v69)
");
}
@@ -1570,7 +1570,7 @@ pub mod hir_build_tests {
EntryPoint JIT(0)
Jump bb2(v6, v7, v8)
bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject):
- v19:BasicObject = SendWithoutBlock v11, :>=, v12 # SendFallbackReason: Uncategorized(opt_ge)
+ v19:BasicObject = Send v11, :>=, v12 # SendFallbackReason: Uncategorized(opt_ge)
CheckInterrupts
Return v19
");
@@ -1639,7 +1639,7 @@ pub mod hir_build_tests {
bb2(v6:BasicObject):
v11:Fixnum[2] = Const Value(2)
v13:Fixnum[3] = Const Value(3)
- v15:BasicObject = SendWithoutBlock v6, :bar, v11, v13 # SendFallbackReason: Uncategorized(opt_send_without_block)
+ v15:BasicObject = Send v6, :bar, v11, v13 # SendFallbackReason: Uncategorized(opt_send_without_block)
CheckInterrupts
Return v15
");
@@ -1726,7 +1726,7 @@ pub mod hir_build_tests {
v18:StringExact = StringCopy v17
v20:StringExact[VALUE(0x1010)] = Const Value(VALUE(0x1010))
v21:StringExact = StringCopy v20
- v23:BasicObject = SendWithoutBlock v6, :unknown_method, v12, v15, v18, v21 # SendFallbackReason: Uncategorized(opt_send_without_block)
+ v23:BasicObject = Send v6, :unknown_method, v12, v15, v18, v21 # SendFallbackReason: Uncategorized(opt_send_without_block)
CheckInterrupts
Return v23
");
@@ -1749,7 +1749,7 @@ pub mod hir_build_tests {
Jump bb2(v5, v6)
bb2(v8:BasicObject, v9:BasicObject):
v15:ArrayExact = ToArray v9
- v17:BasicObject = SendWithoutBlock v8, :foo, v15 # SendFallbackReason: Uncategorized(opt_send_without_block)
+ v17:BasicObject = Send v8, :foo, v15 # SendFallbackReason: Uncategorized(opt_send_without_block)
CheckInterrupts
Return v17
");
@@ -1794,7 +1794,7 @@ pub mod hir_build_tests {
Jump bb2(v5, v6)
bb2(v8:BasicObject, v9:BasicObject):
v14:Fixnum[1] = Const Value(1)
- v16:BasicObject = SendWithoutBlock v8, :foo, v14 # SendFallbackReason: Uncategorized(opt_send_without_block)
+ v16:BasicObject = Send v8, :foo, v14 # SendFallbackReason: Uncategorized(opt_send_without_block)
CheckInterrupts
Return v16
");
@@ -1816,7 +1816,7 @@ pub mod hir_build_tests {
EntryPoint JIT(0)
Jump bb2(v5, v6)
bb2(v8:BasicObject, v9:BasicObject):
- v15:BasicObject = SendWithoutBlock v8, :foo, v9 # SendFallbackReason: Uncategorized(opt_send_without_block)
+ v15:BasicObject = Send v8, :foo, v9 # SendFallbackReason: Uncategorized(opt_send_without_block)
CheckInterrupts
Return v15
");
@@ -1951,7 +1951,7 @@ pub mod hir_build_tests {
bb2(v8:BasicObject, v9:BasicObject):
v15:BasicObject = InvokeSuperForward v8, 0x1000, v9 # SendFallbackReason: Uncategorized(invokesuperforward)
v17:Fixnum[1] = Const Value(1)
- v20:BasicObject = SendWithoutBlock v15, :+, v17 # SendFallbackReason: Uncategorized(opt_plus)
+ v20:BasicObject = Send v15, :+, v17 # SendFallbackReason: Uncategorized(opt_plus)
CheckInterrupts
Return v20
");
@@ -2021,12 +2021,12 @@ pub mod hir_build_tests {
v14:Class[VMFrozenCore] = Const Value(VALUE(0x1000))
v16:HashExact = NewHash
PatchPoint NoEPEscape(test)
- v21:BasicObject = SendWithoutBlock v14, :core#hash_merge_kwd, v16, v9 # SendFallbackReason: Uncategorized(opt_send_without_block)
+ v21:BasicObject = Send v14, :core#hash_merge_kwd, v16, v9 # SendFallbackReason: Uncategorized(opt_send_without_block)
v23:Class[VMFrozenCore] = Const Value(VALUE(0x1000))
v26:StaticSymbol[:b] = Const Value(VALUE(0x1008))
v28:Fixnum[1] = Const Value(1)
- v30:BasicObject = SendWithoutBlock v23, :core#hash_merge_ptr, v21, v26, v28 # SendFallbackReason: Uncategorized(opt_send_without_block)
- v32:BasicObject = SendWithoutBlock v8, :foo, v30 # SendFallbackReason: Uncategorized(opt_send_without_block)
+ v30:BasicObject = Send v23, :core#hash_merge_ptr, v21, v26, v28 # SendFallbackReason: Uncategorized(opt_send_without_block)
+ v32:BasicObject = Send v8, :foo, v30 # SendFallbackReason: Uncategorized(opt_send_without_block)
CheckInterrupts
Return v32
");
@@ -2051,7 +2051,7 @@ pub mod hir_build_tests {
v15:ArrayExact = ToNewArray v9
v17:Fixnum[1] = Const Value(1)
ArrayPush v15, v17
- v21:BasicObject = SendWithoutBlock v8, :foo, v15 # SendFallbackReason: Uncategorized(opt_send_without_block)
+ v21:BasicObject = Send v8, :foo, v15 # SendFallbackReason: Uncategorized(opt_send_without_block)
CheckInterrupts
Return v21
");
@@ -2134,11 +2134,11 @@ pub mod hir_build_tests {
v16:CBool = IsMethodCFunc v11, :new
IfFalse v16, bb3(v6, v13, v11)
v18:HeapBasicObject = ObjectAlloc v11
- v20:BasicObject = SendWithoutBlock v18, :initialize # SendFallbackReason: Uncategorized(opt_send_without_block)
+ v20:BasicObject = Send v18, :initialize # SendFallbackReason: Uncategorized(opt_send_without_block)
CheckInterrupts
Jump bb4(v6, v18, v20)
bb3(v24:BasicObject, v25:NilClass, v26:BasicObject):
- v29:BasicObject = SendWithoutBlock v26, :new # SendFallbackReason: Uncategorized(opt_send_without_block)
+ v29:BasicObject = Send v26, :new # SendFallbackReason: Uncategorized(opt_send_without_block)
Jump bb4(v24, v29, v25)
bb4(v32:BasicObject, v33:BasicObject, v34:BasicObject):
CheckInterrupts
@@ -2251,7 +2251,7 @@ pub mod hir_build_tests {
v12:NilClass = Const Value(nil)
Jump bb2(v8, v9, v10, v11, v12)
bb2(v14:BasicObject, v15:BasicObject, v16:BasicObject, v17:NilClass, v18:NilClass):
- v25:BasicObject = SendWithoutBlock v15, :+, v16 # SendFallbackReason: Uncategorized(opt_plus)
+ v25:BasicObject = Send v15, :+, v16 # SendFallbackReason: Uncategorized(opt_plus)
SideExit UnhandledNewarraySend(MIN)
");
}
@@ -2283,13 +2283,13 @@ pub mod hir_build_tests {
v12:NilClass = Const Value(nil)
Jump bb2(v8, v9, v10, v11, v12)
bb2(v14:BasicObject, v15:BasicObject, v16:BasicObject, v17:NilClass, v18:NilClass):
- v25:BasicObject = SendWithoutBlock v15, :+, v16 # SendFallbackReason: Uncategorized(opt_plus)
+ v25:BasicObject = Send v15, :+, v16 # SendFallbackReason: Uncategorized(opt_plus)
PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_HASH)
v32:Fixnum = ArrayHash v15, v16
PatchPoint NoEPEscape(test)
v39:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
v40:ArrayExact = ArrayDup v39
- v42:BasicObject = SendWithoutBlock v14, :puts, v40 # SendFallbackReason: Uncategorized(opt_send_without_block)
+ v42:BasicObject = Send v14, :puts, v40 # SendFallbackReason: Uncategorized(opt_send_without_block)
PatchPoint NoEPEscape(test)
CheckInterrupts
Return v32
@@ -2325,7 +2325,7 @@ pub mod hir_build_tests {
v12:NilClass = Const Value(nil)
Jump bb2(v8, v9, v10, v11, v12)
bb2(v14:BasicObject, v15:BasicObject, v16:BasicObject, v17:NilClass, v18:NilClass):
- v25:BasicObject = SendWithoutBlock v15, :+, v16 # SendFallbackReason: Uncategorized(opt_plus)
+ v25:BasicObject = Send v15, :+, v16 # SendFallbackReason: Uncategorized(opt_plus)
SideExit PatchPoint(BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_HASH))
");
}
@@ -2357,7 +2357,7 @@ pub mod hir_build_tests {
v12:NilClass = Const Value(nil)
Jump bb2(v8, v9, v10, v11, v12)
bb2(v14:BasicObject, v15:BasicObject, v16:BasicObject, v17:NilClass, v18:NilClass):
- v25:BasicObject = SendWithoutBlock v15, :+, v16 # SendFallbackReason: Uncategorized(opt_plus)
+ v25:BasicObject = Send v15, :+, v16 # SendFallbackReason: Uncategorized(opt_plus)
v31:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
v32:StringExact = StringCopy v31
SideExit UnhandledNewarraySend(PACK)
@@ -2391,7 +2391,7 @@ pub mod hir_build_tests {
v12:NilClass = Const Value(nil)
Jump bb2(v8, v9, v10, v11, v12)
bb2(v14:BasicObject, v15:BasicObject, v16:BasicObject, v17:NilClass, v18:NilClass):
- v25:BasicObject = SendWithoutBlock v15, :+, v16 # SendFallbackReason: Uncategorized(opt_plus)
+ v25:BasicObject = Send v15, :+, v16 # SendFallbackReason: Uncategorized(opt_plus)
v29:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
v30:StringExact = StringCopy v29
v36:StringExact[VALUE(0x1008)] = Const Value(VALUE(0x1008))
@@ -2435,7 +2435,7 @@ pub mod hir_build_tests {
v12:NilClass = Const Value(nil)
Jump bb2(v8, v9, v10, v11, v12)
bb2(v14:BasicObject, v15:BasicObject, v16:BasicObject, v17:NilClass, v18:NilClass):
- v25:BasicObject = SendWithoutBlock v15, :+, v16 # SendFallbackReason: Uncategorized(opt_plus)
+ v25:BasicObject = Send v15, :+, v16 # SendFallbackReason: Uncategorized(opt_plus)
v29:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
v30:StringExact = StringCopy v29
v36:StringExact[VALUE(0x1008)] = Const Value(VALUE(0x1008))
@@ -2472,13 +2472,13 @@ pub mod hir_build_tests {
v12:NilClass = Const Value(nil)
Jump bb2(v8, v9, v10, v11, v12)
bb2(v14:BasicObject, v15:BasicObject, v16:BasicObject, v17:NilClass, v18:NilClass):
- v25:BasicObject = SendWithoutBlock v15, :+, v16 # SendFallbackReason: Uncategorized(opt_plus)
+ v25:BasicObject = Send v15, :+, v16 # SendFallbackReason: Uncategorized(opt_plus)
PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_INCLUDE_P)
v33:BoolExact = ArrayInclude v15, v16 | v16
PatchPoint NoEPEscape(test)
v40:ArrayExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
v41:ArrayExact = ArrayDup v40
- v43:BasicObject = SendWithoutBlock v14, :puts, v41 # SendFallbackReason: Uncategorized(opt_send_without_block)
+ v43:BasicObject = Send v14, :puts, v41 # SendFallbackReason: Uncategorized(opt_send_without_block)
PatchPoint NoEPEscape(test)
CheckInterrupts
Return v33
@@ -2519,7 +2519,7 @@ pub mod hir_build_tests {
v12:NilClass = Const Value(nil)
Jump bb2(v8, v9, v10, v11, v12)
bb2(v14:BasicObject, v15:BasicObject, v16:BasicObject, v17:NilClass, v18:NilClass):
- v25:BasicObject = SendWithoutBlock v15, :+, v16 # SendFallbackReason: Uncategorized(opt_plus)
+ v25:BasicObject = Send v15, :+, v16 # SendFallbackReason: Uncategorized(opt_plus)
SideExit PatchPoint(BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_INCLUDE_P))
");
}
@@ -2598,7 +2598,7 @@ pub mod hir_build_tests {
Jump bb2(v6, v7, v8)
bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject):
v18:ArrayExact = NewArray v11, v12
- v21:BasicObject = SendWithoutBlock v18, :length # SendFallbackReason: Uncategorized(opt_length)
+ v21:BasicObject = Send v18, :length # SendFallbackReason: Uncategorized(opt_length)
CheckInterrupts
Return v21
");
@@ -2623,7 +2623,7 @@ pub mod hir_build_tests {
Jump bb2(v6, v7, v8)
bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject):
v18:ArrayExact = NewArray v11, v12
- v21:BasicObject = SendWithoutBlock v18, :size # SendFallbackReason: Uncategorized(opt_size)
+ v21:BasicObject = Send v18, :size # SendFallbackReason: Uncategorized(opt_size)
CheckInterrupts
Return v21
");
@@ -3020,7 +3020,7 @@ pub mod hir_build_tests {
bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject):
v16:NilClass = Const Value(nil)
v20:Fixnum[1] = Const Value(1)
- v24:BasicObject = SendWithoutBlock v11, :[]=, v12, v20 # SendFallbackReason: Uncategorized(opt_aset)
+ v24:BasicObject = Send v11, :[]=, v12, v20 # SendFallbackReason: Uncategorized(opt_aset)
CheckInterrupts
Return v20
");
@@ -3044,7 +3044,7 @@ pub mod hir_build_tests {
EntryPoint JIT(0)
Jump bb2(v6, v7, v8)
bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject):
- v19:BasicObject = SendWithoutBlock v11, :[], v12 # SendFallbackReason: Uncategorized(opt_aref)
+ v19:BasicObject = Send v11, :[], v12 # SendFallbackReason: Uncategorized(opt_aref)
CheckInterrupts
Return v19
");
@@ -3067,7 +3067,7 @@ pub mod hir_build_tests {
EntryPoint JIT(0)
Jump bb2(v5, v6)
bb2(v8:BasicObject, v9:BasicObject):
- v15:BasicObject = SendWithoutBlock v9, :empty? # SendFallbackReason: Uncategorized(opt_empty_p)
+ v15:BasicObject = Send v9, :empty? # SendFallbackReason: Uncategorized(opt_empty_p)
CheckInterrupts
Return v15
");
@@ -3090,7 +3090,7 @@ pub mod hir_build_tests {
EntryPoint JIT(0)
Jump bb2(v5, v6)
bb2(v8:BasicObject, v9:BasicObject):
- v15:BasicObject = SendWithoutBlock v9, :succ # SendFallbackReason: Uncategorized(opt_succ)
+ v15:BasicObject = Send v9, :succ # SendFallbackReason: Uncategorized(opt_succ)
CheckInterrupts
Return v15
");
@@ -3114,7 +3114,7 @@ pub mod hir_build_tests {
EntryPoint JIT(0)
Jump bb2(v6, v7, v8)
bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject):
- v19:BasicObject = SendWithoutBlock v11, :&, v12 # SendFallbackReason: Uncategorized(opt_and)
+ v19:BasicObject = Send v11, :&, v12 # SendFallbackReason: Uncategorized(opt_and)
CheckInterrupts
Return v19
");
@@ -3138,7 +3138,7 @@ pub mod hir_build_tests {
EntryPoint JIT(0)
Jump bb2(v6, v7, v8)
bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject):
- v19:BasicObject = SendWithoutBlock v11, :|, v12 # SendFallbackReason: Uncategorized(opt_or)
+ v19:BasicObject = Send v11, :|, v12 # SendFallbackReason: Uncategorized(opt_or)
CheckInterrupts
Return v19
");
@@ -3161,7 +3161,7 @@ pub mod hir_build_tests {
EntryPoint JIT(0)
Jump bb2(v5, v6)
bb2(v8:BasicObject, v9:BasicObject):
- v15:BasicObject = SendWithoutBlock v9, :! # SendFallbackReason: Uncategorized(opt_not)
+ v15:BasicObject = Send v9, :! # SendFallbackReason: Uncategorized(opt_not)
CheckInterrupts
Return v15
");
@@ -3185,7 +3185,7 @@ pub mod hir_build_tests {
EntryPoint JIT(0)
Jump bb2(v6, v7, v8)
bb2(v10:BasicObject, v11:BasicObject, v12:BasicObject):
- v19:BasicObject = SendWithoutBlock v11, :=~, v12 # SendFallbackReason: Uncategorized(opt_regexpmatch2)
+ v19:BasicObject = Send v11, :=~, v12 # SendFallbackReason: Uncategorized(opt_regexpmatch2)
CheckInterrupts
Return v19
");
@@ -3215,7 +3215,7 @@ pub mod hir_build_tests {
v12:BasicObject = PutSpecialObject CBase
v14:StaticSymbol[:aliased] = Const Value(VALUE(0x1008))
v16:StaticSymbol[:__callee__] = Const Value(VALUE(0x1010))
- v18:BasicObject = SendWithoutBlock v10, :core#set_method_alias, v12, v14, v16 # SendFallbackReason: Uncategorized(opt_send_without_block)
+ v18:BasicObject = Send v10, :core#set_method_alias, v12, v14, v16 # SendFallbackReason: Uncategorized(opt_send_without_block)
CheckInterrupts
Return v18
");
@@ -3317,7 +3317,7 @@ pub mod hir_build_tests {
v17:NilClass = Const Value(nil)
IfTrue v16, bb3(v8, v17, v17)
v19:NotNil = RefineType v9, NotNil
- v21:BasicObject = SendWithoutBlock v19, :itself # SendFallbackReason: Uncategorized(opt_send_without_block)
+ v21:BasicObject = Send v19, :itself # SendFallbackReason: Uncategorized(opt_send_without_block)
Jump bb3(v8, v19, v21)
bb3(v23:BasicObject, v24:BasicObject, v25:BasicObject):
CheckInterrupts
@@ -3359,7 +3359,7 @@ pub mod hir_build_tests {
v25:NilClass = Const Value(nil)
IfTrue v24, bb4(v8, v25, v25)
v27:Truthy = RefineType v18, NotNil
- v29:BasicObject = SendWithoutBlock v27, :itself # SendFallbackReason: Uncategorized(opt_send_without_block)
+ v29:BasicObject = Send v27, :itself # SendFallbackReason: Uncategorized(opt_send_without_block)
CheckInterrupts
Return v29
bb3(v34:BasicObject, v35:Falsy):
@@ -3640,14 +3640,14 @@ pub mod hir_build_tests {
v13:NilClass = Const Value(nil)
v16:Fixnum[0] = Const Value(0)
v18:Fixnum[1] = Const Value(1)
- v21:BasicObject = SendWithoutBlock v9, :[], v16, v18 # SendFallbackReason: Uncategorized(opt_send_without_block)
+ v21:BasicObject = Send v9, :[], v16, v18 # SendFallbackReason: Uncategorized(opt_send_without_block)
CheckInterrupts
v25:CBool = Test v21
v26:Truthy = RefineType v21, Truthy
IfTrue v25, bb3(v8, v9, v13, v9, v16, v18, v26)
v28:Falsy = RefineType v21, Falsy
v31:Fixnum[2] = Const Value(2)
- v34:BasicObject = SendWithoutBlock v9, :[]=, v16, v18, v31 # SendFallbackReason: Uncategorized(opt_send_without_block)
+ v34:BasicObject = Send v9, :[]=, v16, v18, v31 # SendFallbackReason: Uncategorized(opt_send_without_block)
CheckInterrupts
Return v31
bb3(v40:BasicObject, v41:BasicObject, v42:NilClass, v43:BasicObject, v44:Fixnum[0], v45:Fixnum[1], v46:Truthy):
@@ -4001,7 +4001,7 @@ pub mod hir_build_tests {
v21:FalseClass = RefineType v15, Falsy
v23:Fixnum[1] = Const Value(1)
v25:Fixnum[1] = Const Value(1)
- v28:BasicObject = SendWithoutBlock v23, :+, v25 # SendFallbackReason: Uncategorized(opt_plus)
+ v28:BasicObject = Send v23, :+, v25 # SendFallbackReason: Uncategorized(opt_plus)
Jump bb3(v10, v28, v12)
bb3(v31:BasicObject, v32:BasicObject, v33:BasicObject):
CheckInterrupts