8000 YJIT: Replace Array#each only when YJIT is enabled · ruby/ruby@e045b6b · GitHub
[go: up one dir, main page]

Skip to content

Commit e045b6b

Browse files
committed
YJIT: Replace Array#each only when YJIT is enabled
1 parent 484ea00 commit e045b6b

File tree

15 files changed

+130
-56
lines changed

15 files changed

+130
-56
lines changed

array.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2604,6 +2604,39 @@ ary_fetch_next(VALUE self, VALUE *index, VALUE *value)
26042604
return Qtrue;
26052605
}
26062606

2607+
/*
2608+
* call-seq:
2609+
* each {|element| ... } -> self
2610+
* each -> new_enumerator
2611+
*
2612+
* With a block given, iterates over the elements of +self+,
2613+
* passing each element to the block;
2614+
* returns +self+:
2615+
*
2616+
* a = [:foo, 'bar', 2]
2617+
* a.each {|element| puts "#{element.class} #{element}" }
2618+
*
2619+
* Output:
2620+
*
2621+
* Symbol foo
2622+
* String bar
2623+
* Integer 2
2624+
*
2625+
* Allows the array to be modified during iteration:
2626+
*
2627+
* a = [:foo, 'bar', 2]
2628+
* a.each {|element| puts element; a.clear if element.to_s.start_with?('b') }
2629+
*
2630+
* Output:
2631+
*
2632+
* foo
2633+
* bar
2634+
*
2635+
* With no block given, returns a new Enumerator.
2636+
*
2637+
* Related: see {Methods for Iterating}[rdoc-ref:Array@Methods+for+Iterating].
2638+
*/
2639+
26072640
VALUE
26082641
rb_ary_each(VALUE ary)
26092642
{
@@ -8631,6 +8664,7 @@ Init_Array(void)
86318664
rb_define_method(rb_cArray, "unshift", rb_ary_unshift_m, -1);
86328665
rb_define_alias(rb_cArray, "prepend", "unshift");
86338666
rb_define_method(rb_cArray, "insert", rb_ary_insert, -1);
8667+
rb_define_method(rb_cArray, "each", rb_ary_each, 0);
86348668
rb_define_method(rb_cArray, "each_index", rb_ary_each_index, 0);
86358669
rb_define_method(rb_cArray, "reverse_each", rb_ary_reverse_each, 0);
86368670
rb_define_method(rb_cArray, "length", rb_ary_length, 0);

array.rb

Lines changed: 20 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,4 @@
11
class Array
2-
# call-seq:
3-
# each {|element| ... } -> self
4-
# each -> new_enumerator
5-
#
6-
# With a block given, iterates over the elements of +self+,
7-
# passing each element to the block;
8-
# returns +self+:
9-
#
10-
# a = [:foo, 'bar', 2]
11-
# a.each {|element| puts "#{element.class} #{element}" }
12-
#
13-
# Output:
14-
#
15-
# Symbol foo
16-
# String bar
17-
# Integer 2
18-
#
19-
# Allows the array to be modified during iteration:
20-
#
21-
# a = [:foo, 'bar', 2]
22-
# a.each {|element| puts element; a.clear if element.to_s.start_with?('b') }
23-
#
24-
# Output:
25-
#
26-
# foo
27-
# bar
28-
#
29-
# With no block given, returns a new Enumerator.
30-
#
31-
# Related: see {Methods for Iterating}[rdoc-ref:Array@Methods+for+Iterating].
32-
33-
def each
34-
Primitive.attr! :inline_block
35-
36-
unless defined?(yield)
37-
return Primitive.cexpr! 'SIZED_ENUMERATOR(self, 0, 0, ary_enum_length)'
38-
end
39-
_i = 0
40-
value = nil
41-
while Primitive.cexpr!(%q{ ary_fetch_next(self, LOCAL_PTR(_i), LOCAL_PTR(value)) })
42-
yield value
43-
end
44-
self
45-
end
46-
472
# call-seq:
483
# shuffle!(random: Random) -> self
494
#
@@ -258,4 +213,24 @@ def fetch_values(*indexes, &block)
258213
indexes.map! { |i| fetch(i, &block) }
259214
indexes
260215
end
216+
217+
with_yjit do
218+
if Array.instance_method(:each).source_location == nil # preserve monkey patches
219+
undef :each
220+
221+
def each # :nodoc:
222+
Primitive.attr! :inline_block, :c_trace
223+
224+
unless defined?(yield)
225+
return Primitive.cexpr! 'SIZED_ENUMERATOR(self, 0, 0, ary_enum_length)'
226+
end
227+
_i = 0
228+
value = nil
229+
while Primitive.cexpr!(%q{ ary_fetch_next(self, LOCAL_PTR(_i), LOCAL_PTR(value)) })
230+
yield value
231+
end
232+
self
233+
end
234+
end
235+
end
261236
end

bootstraptest/test_yjit.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2111,6 +2111,15 @@ def ccall = "".byteslice(nil, nil)
21112111
end
21122112
}
21132113

2114+
# TODO: move this to test/ruby/test_yjit.rb
2115+
assert_equal "bootstraptest.test_yjit.rb:5:in 'Array#each'", %q{
2116+
begin
2117+
[nil].each { raise }
2118+
rescue => e
2119+
e.backtrace[1].sub(/test_yjit\.rb_\d+_\d+\.rb/, 'test_yjit.rb')
2120+
end
2121+
}
2122+
21142123
# Test << operator on string subclass
21152124
assert_equal 'abab', %q{
21162125
class MyString < String; end

common.mk

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,6 +1212,7 @@ BUILTIN_RB_SRCS = \
12121212
$(srcdir)/prelude.rb \
12131213
$(srcdir)/gem_prelude.rb \
12141214
$(srcdir)/yjit.rb \
1215+
$(srcdir)/yjit_hook.rb \
12151216
$(empty)
12161217
BUILTIN_RB_INCS = $(BUILTIN_RB_SRCS:.rb=.rbinc)
12171218

@@ -10642,6 +10643,7 @@ miniinit.$(OBJEXT): {$(VPATH)}vm_core.h
1064210643
miniinit.$(OBJEXT): {$(VPATH)}vm_opts.h
1064310644
miniinit.$(OBJEXT): {$(VPATH)}warning.rb
1064410645
miniinit.$(OBJEXT): {$(VPATH)}yjit.rb
10646+
miniinit.$(OBJEXT): {$(VPATH)}yjit_hook.rb
1064510647
node.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
1064610648
node.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
1064710649
node.$(OBJEXT): $(CCAN_DIR)/list/list.h
@@ -20002,6 +20004,7 @@ vm.$(OBJEXT): {$(VPATH)}vm_opts.h
2000220004
vm.$(OBJEXT): {$(VPATH)}vm_sync.h
2000320005
vm.$(OBJEXT): {$(VPATH)}vmtc.inc
2000420006
vm.$(OBJEXT): {$(VPATH)}yjit.h
20007+
vm.$(OBJEXT): {$(VPATH)}yjit_hook.rbinc
2000520008
vm_backtrace.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
2000620009
vm_backtrace.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
2000720010
vm_backtrace.$(OBJEXT): $(CCAN_DIR)/list/list.h

compile.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8960,6 +8960,9 @@ compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
89608960
else if (strcmp(RSTRING_PTR(string), "use_block") == 0) {
89618961
iseq_set_use_block(iseq);
89628962
}
8963+
else if (strcmp(RSTRING_PTR(string), "c_trace") == 0) {
8964+
ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
8965+
}
89638966
else {
89648967
goto unknown_arg;
89658968
}

inits.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ void
8484
rb_call_builtin_inits(void)
8585
{
8686
#define BUILTIN(n) CALL(builtin_##n)
87+
BUILTIN(kernel);
88+
BUILTIN(yjit);
8789
BUILTIN(gc);
8890
BUILTIN(ractor);
8991
BUILTIN(numeric);
@@ -95,15 +97,14 @@ rb_call_builtin_inits(void)
9597
BUILTIN(warning);
9698
BUILTIN(array);
9799
BUILTIN(hash);
98-
BUILTIN(kernel);
99100
BUILTIN(symbol);
100101
BUILTIN(timev);
101102
BUILTIN(thread_sync);
102-
BUILTIN(yjit);
103103
BUILTIN(nilclass);
104104
BUILTIN(marshal);
105105
BUILTIN(rjit_c);
106106
BUILTIN(rjit);
107+
BUILTIN(yjit_hook);
107108
Init_builtin_prelude();
108109
}
109110
#undef CALL

kernel.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,4 +290,12 @@ def Integer(arg, base = 0, exception: true)
290290
Primitive.rb_f_integer(arg, base, exception);
291291
end
292292
end
293+
294+
# Internal helper for builtin inits to define methods only when YJIT is enabled.
295+
# This method is removed in yjit_hook.rb.
296+
def with_yjit(&block) # :nodoc:
297+
if defined?(RubyVM::YJIT)
298+
RubyVM::YJIT.send(:add_yjit_hook, block)
299+
end
300+
end
293301
end

prism_compile.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3387,6 +3387,9 @@ pm_compile_builtin_attr(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, cons
33873387
else if (strcmp(RSTRING_PTR(string), "use_block") == 0) {
33883388
iseq_set_use_block(iseq);
33893389
}
3390+
else if (strcmp(RSTRING_PTR(string), "c_trace") == 0) {
3391+
ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_C_TRACE;
3392+
}
33903393
else {
33913394
COMPILE_ERROR(iseq, node_location->line, "unknown argument to attr!: %s", RSTRING_PTR(string));
33923395
return COMPILE_NG;

tool/mk_builtin_loader.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
SUBLIBS = {}
88
REQUIRED = {}
9-
BUILTIN_ATTRS = %w[leaf inline_block use_block]
9+
BUILTIN_ATTRS = %w[leaf inline_block use_block c_trace]
1010

1111
module CompileWarning
1212
@@warnings = 0

vm.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4425,6 +4425,9 @@ Init_vm_objects(void)
44254425
void Init_builtin_yjit(void) {}
44264426
#endif
44274427

4428+
// Whether YJIT is enabled or not, we load yjit_hook.rb to remove Kernel#with_yjit.
4429+
#include "yjit_hook.rbinc"
4430+
44284431
// Stub for builtin function when not building RJIT units
44294432
#if !USE_RJIT
44304433
void Init_builtin_rjit(void) {}

0 commit comments

Comments
 (0)
0