Skip to content
This repository was archived by the owner on Jun 3, 2026. It is now read-only.

Commit de52fcf

Browse files
authored
Merge pull request #1 from kufu/with-patches
自前のパッチを適用できるようにする
2 parents b9dfa82 + 205bd1a commit de52fcf

5 files changed

Lines changed: 307 additions & 2 deletions

File tree

Dockerfile

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
ARG BASE_IMAGE_TAG
22
ARG RUBY_VERSION
33
ARG RUBY_SO_SUFFIX
4+
ARG RUBY_PATCH_DIR=/tmp/patches
45

56
### build ###
67
FROM ghcr.io/ruby/ubuntu:$BASE_IMAGE_TAG AS build
78

89
ARG BASE_IMAGE_TAG
910
ARG RUBY_VERSION
11+
ARG RUBY_PATCH_DIR
1012

1113
ENV LANG=C.UTF-8 \
1214
DEBIAN_FRONTEND=noninteractive
@@ -21,6 +23,7 @@ RUN set -ex && \
2123
gcc \
2224
git \
2325
g++ \
26+
patch \
2427
libffi-dev \
2528
libgdbm-dev \
2629
libgmp-dev \
@@ -42,10 +45,11 @@ RUN wget https://sh.rustup.rs -O /tmp/rustup.sh && \
4245
rm -f /tmp/rustup.sh
4346

4447
COPY tmp/ruby /usr/src/ruby
48+
COPY patches /tmp/patches
4549
COPY install_ruby.sh /tmp/
4650

4751
RUN set -ex && \
48-
RUBY_VERSION=3.2.3 PREFIX=/root /tmp/install_ruby.sh
52+
RUBY_VERSION=3.2.3 PREFIX=/root RUBY_PATCH_DIR= /tmp/install_ruby.sh
4953
RUN apt purge -y --auto-remove ruby
5054
COPY tmp/ruby /usr/src/ruby
5155

@@ -61,7 +65,7 @@ RUN set -ex && \
6165
echo 'update: --no-document'; \
6266
} >> /usr/local/etc/gemrc && \
6367
\
64-
PATH=/root/bin:$PATH /tmp/install_ruby.sh
68+
PATH=/root/bin:$PATH RUBY_PATCH_DIR=$RUBY_PATCH_DIR /tmp/install_ruby.sh
6569

6670
### ruby ###
6771
FROM ghcr.io/ruby/ubuntu:$BASE_IMAGE_TAG AS ruby

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@ You can specify the specific revision in the master branch like:
8787
rake docker:build ruby_version=master:ce798d08de
8888
```
8989

90+
## Applying custom Ruby patches
91+
92+
- Drop one or more `*.patch` files under `patches/` (they are applied with `patch -p1` in filename order before `./configure` runs).
93+
- By default the build stage uses that directory via the `RUBY_PATCH_DIR` build arg. To disable, pass `--build-arg RUBY_PATCH_DIR=` (empty). To use another location, point the arg at your directory.
94+
9095
## Build and push for the specific ruby and ubuntu versions
9196

9297
Trigger CircleCI workflow with `ruby_version` and `ubuntu_version` pipeline parameters.

install_ruby.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ RUBY_VERSION=${RUBY_VERSION-2.6.0}
66
RUBY_MAJOR=$(echo $RUBY_VERSION | sed -E 's/\.[0-9]+(-.*)?$//g')
77
RUBYGEMS_VERSION=${RUBYGEMS_VERSION-3.2.3}
88
PREFIX=${PREFIX-/usr/local}
9+
RUBY_PATCH_DIR=${RUBY_PATCH_DIR-}
910

1011
. "$HOME/.cargo/env"
1112

@@ -117,6 +118,14 @@ fi
117118
unset debugflags
118119
fi
119120

121+
if [ -n "$RUBY_PATCH_DIR" ] && [ -d "$RUBY_PATCH_DIR" ]; then
122+
for patch_file in "$RUBY_PATCH_DIR"/*.patch; do
123+
[ -e "$patch_file" ] || continue
124+
echo "Applying patch: $(basename "$patch_file")"
125+
patch -d /usr/src/ruby -p1 < "$patch_file"
126+
done
127+
fi
128+
120129
/usr/src/ruby/configure "${configure_args[@]}" || {
121130
cat config.log | grep flags=
122131
exit 1

patches/.gitkeep

Whitespace-only changes.

patches/diff.patch

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
diff --git a/gc.c b/gc.c
2+
index 68304d26c50e0d..ff99c52c8fa8fd 100644
3+
--- a/gc.c
4+
+++ b/gc.c
5+
@@ -1246,6 +1246,15 @@ rb_gc_obj_free_vm_weak_references(VALUE obj)
6+
break;
7+
case T_IMEMO:
8+
switch (imemo_type(obj)) {
9+
+ case imemo_callcache: {
10+
+ const struct rb_callcache *cc = (const struct rb_callcache *)obj;
11+
+
12+
+ if (vm_cc_refinement_p(cc)) {
13+
+ rb_vm_delete_cc_refinement(cc);
14+
+ }
15+
+
16+
+ break;
17+
+ }
18+
case imemo_callinfo:
19+
rb_vm_ci_free((const struct rb_callinfo *)obj);
20+
break;
21+
@@ -3436,6 +3445,64 @@ vm_weak_table_frozen_strings_foreach(st_data_t key, st_data_t value, st_data_t d
22+
23+
struct st_table *rb_generic_ivtbl_get(void);
24+
25+
+struct global_vm_cc_refinement_foreach_data {
26+
+ struct global_vm_table_foreach_data *iter_data;
27+
+ st_table *new_tbl;
28+
+};
29+
+
30+
+static int
31+
+vm_weak_table_cc_refinement_foreach_i(st_data_t key, st_data_t value, st_data_t data)
32+
+{
33+
+ struct global_vm_cc_refinement_foreach_data *cc_refinement_foreach_data = (struct global_vm_cc_refinement_foreach_data *)data;
34+
+ struct global_vm_table_foreach_data *iter_data = cc_refinement_foreach_data->iter_data;
35+
+ struct st_table *new_tbl = cc_refinement_foreach_data->new_tbl;
36+
+
37+
+ int ret = iter_data->callback((VALUE)key, iter_data->data);
38+
+
39+
+ const struct rb_callcache *cc = (struct rb_callcache *)key;
40+
+ switch (ret) {
41+
+ case ST_CONTINUE:
42+
+ break;
43+
+ case ST_DELETE:
44+
+ return ret;
45+
+ case ST_REPLACE: {
46+
+ VALUE new_key = (VALUE)key;
47+
+ iter_data->update_callback(&new_key, iter_data->data);
48+
+ cc = (struct rb_callcache *)new_key;
49+
+ break;
50+
+ }
51+
+ default:
52+
+ rb_bug("vm_weak_table_cc_refinement_foreach_i: return value %d not supported", ret);
53+
+ }
54+
+
55+
+ DURING_GC_COULD_MALLOC_REGION_START();
56+
+ {
57+
+ rb_vm_insert_cc_refinement(new_tbl, cc);
58+
+ }
59+
+ DURING_GC_COULD_MALLOC_REGION_END();
60+
+
61+
+ return ret;
62+
+}
63+
+
64+
+static st_table *
65+
+vm_weak_table_cc_refinement_rebuild(st_table *cc_refinement_table, struct global_vm_table_foreach_data *iter_data)
66+
+{
67+
+ st_table *new_tbl = NULL;
68+
+ DURING_GC_COULD_MALLOC_REGION_START();
69+
+ {
70+
+ new_tbl = st_init_numtable_with_size(st_table_size(cc_refinement_table));
71+
+ }
72+
+ DURING_GC_COULD_MALLOC_REGION_END();
73+
+
74+
+ struct global_vm_cc_refinement_foreach_data cc_refinement_foreach_data = {
75+
+ .iter_data = iter_data,
76+
+ .new_tbl = new_tbl,
77+
+ };
78+
+
79+
+ st_foreach(cc_refinement_table, vm_weak_table_cc_refinement_foreach_i, (st_data_t)&cc_refinement_foreach_data);
80+
+ return new_tbl;
81+
+}
82+
+
83+
void
84+
rb_gc_vm_weak_table_foreach(vm_table_foreach_callback_func callback,
85+
vm_table_update_callback_func update_callback,
86+
@@ -3498,6 +3565,17 @@ rb_gc_vm_weak_table_foreach(vm_table_foreach_callback_func callback,
87+
);
88+
break;
89+
}
90+
+ case RB_GC_VM_CC_REFINEMENT_TABLE: {
91+
+ st_table_size(vm->cc_refinement_table);
92+
+ if (vm->cc_refinement_table && st_table_size(vm->cc_refinement_table) > 0) {
93+
+ st_table *old_tbl = vm->cc_refinement_table;
94+
+ st_table *new_tbl = vm_weak_table_cc_refinement_rebuild(vm->cc_refinement_table, &foreach_data);
95+
+
96+
+ vm->cc_refinement_table = new_tbl;
97+
+ st_free_table(old_tbl);
98+
+ }
99+
+ break;
100+
+ }
101+
default:
102+
rb_bug("rb_gc_vm_weak_table_foreach: unknown table %d", table);
103+
}
104+
diff --git a/gc/gc.h b/gc/gc.h
105+
index 5b380df1f45cc8..a096bb184a0d74 100644
106+
--- a/gc/gc.h
107+
+++ b/gc/gc.h
108+
@@ -30,6 +30,7 @@ enum rb_gc_vm_weak_tables {
109+
RB_GC_VM_GLOBAL_SYMBOLS_TABLE,
110+
RB_GC_VM_GENERIC_IV_TABLE,
111+
RB_GC_VM_FROZEN_STRINGS_TABLE,
112+
+ RB_GC_VM_CC_REFINEMENT_TABLE,
113+
RB_GC_VM_WEAK_TABLE_COUNT
114+
};
115+
#endif
116+
diff --git a/method.h b/method.h
117+
index 030c3cc3d18be9..5c5d19cabe6223 100644
118+
--- a/method.h
119+
+++ b/method.h
120+
@@ -250,6 +250,9 @@ void rb_scope_visibility_set(rb_method_visibility_t);
121+
122+
VALUE rb_unnamed_parameters(int arity);
123+
124+
+void rb_vm_insert_cc_refinement(st_table *cc_refinement_table, const struct rb_callcache *cc);
125+
+void rb_vm_delete_cc_refinement(const struct rb_callcache *cc);
126+
+
127+
void rb_clear_method_cache(VALUE klass_or_module, ID mid);
128+
void rb_clear_all_refinement_method_cache(void);
129+
130+
diff --git a/vm.c b/vm.c
131+
index 9a0008ea070ccd..7aa9739fba67c6 100644
132+
--- a/vm.c
133+
+++ b/vm.c
134+
@@ -3143,6 +3143,10 @@ ruby_vm_destruct(rb_vm_t *vm)
135+
st_free_table(vm->frozen_strings);
136+
vm->frozen_strings = 0;
137+
}
138+
+ if (vm->cc_refinement_table) {
139+
+ st_free_table(vm->cc_refinement_table);
140+
+ vm->cc_refinement_table = NULL;
141+
+ }
142+
RB_ALTSTACK_FREE(vm->main_altstack);
143+
144+
struct global_object_list *next;
145+
@@ -3245,6 +3249,7 @@ vm_memsize(const void *ptr)
146+
vm_memsize_builtin_function_table(vm->builtin_function_table) +
147+
rb_id_table_memsize(vm->negative_cme_table) +
148+
rb_st_memsize(vm->overloaded_cme_table) +
149+
+ rb_st_memsize(vm->cc_refinement_table) +
150+
vm_memsize_constant_cache() +
151+
GET_SHAPE_TREE()->cache_size * sizeof(redblack_node_t)
152+
);
153+
@@ -4447,6 +4452,7 @@ Init_vm_objects(void)
154+
vm->loading_table = st_init_strtable();
155+
vm->ci_table = st_init_table(&vm_ci_hashtype);
156+
vm->frozen_strings = st_init_table_with_size(&rb_fstring_hash_type, 10000);
157+
+ vm->cc_refinement_table = st_init_numtable();
158+
}
159+
160+
// Stub for builtin function when not building YJIT units
161+
diff --git a/vm_callinfo.h b/vm_callinfo.h
162+
index d85261aaf900cd..5e0fcc5465cf8a 100644
163+
--- a/vm_callinfo.h
164+
+++ b/vm_callinfo.h
165+
@@ -345,6 +345,7 @@ vm_cc_new(VALUE klass,
166+
break;
167+
case cc_type_refinement:
168+
*(VALUE *)&cc->flags |= VM_CALLCACHE_REFINEMENT;
169+
+ rb_vm_insert_cc_refinement(NULL, cc);
170+
break;
171+
}
172+
173+
diff --git a/vm_core.h b/vm_core.h
174+
index 961cc3967c3a6d..ccca31a768c34c 100644
175+
--- a/vm_core.h
176+
+++ b/vm_core.h
177+
@@ -799,6 +799,7 @@ typedef struct rb_vm_struct {
178+
struct rb_id_table *negative_cme_table;
179+
st_table *overloaded_cme_table; // cme -> overloaded_cme
180+
st_table *unused_block_warning_table;
181+
+ st_table *cc_refinement_table;
182+
183+
// This id table contains a mapping from ID to ICs. It does this with ID
184+
// keys and nested st_tables as values. The nested tables have ICs as keys
185+
diff --git a/vm_method.c b/vm_method.c
186+
index e4f71648acb3aa..177723fd423d28 100644
187+
--- a/vm_method.c
188+
+++ b/vm_method.c
189+
@@ -310,27 +310,29 @@ rb_clear_method_cache(VALUE klass_or_module, ID mid)
190+
}
191+
192+
static int
193+
-invalidate_all_refinement_cc(void *vstart, void *vend, size_t stride, void *data)
194+
-{
195+
- VALUE v = (VALUE)vstart;
196+
- for (; v != (VALUE)vend; v += stride) {
197+
- void *ptr = rb_asan_poisoned_object_p(v);
198+
- rb_asan_unpoison_object(v, false);
199+
-
200+
- if (RBASIC(v)->flags) { // liveness check
201+
- if (imemo_type_p(v, imemo_callcache)) {
202+
- const struct rb_callcache *cc = (const struct rb_callcache *)v;
203+
- if (vm_cc_refinement_p(cc) && cc->klass) {
204+
- vm_cc_invalidate(cc);
205+
- }
206+
- }
207+
- }
208+
+invalidate_cc_refinement(st_data_t key, st_data_t value, st_data_t data)
209+
+{
210+
+ VALUE v = (VALUE)key;
211+
+ void *ptr = rb_asan_poisoned_object_p(v);
212+
+ rb_asan_unpoison_object(v, false);
213+
+
214+
+ if (rb_gc_pointer_to_heap_p(v) &&
215+
+ !rb_objspace_garbage_object_p(v) &&
216+
+ RBASIC(v)->flags) { // liveness check
217+
+ const struct rb_callcache *cc = (const struct rb_callcache *)v;
218+
219+
- if (ptr) {
220+
- rb_asan_poison_object(v);
221+
+ VM_ASSERT(vm_cc_refinement_p(cc));
222+
+
223+
+ if (cc->klass) {
224+
+ vm_cc_invalidate(cc);
225+
}
226+
}
227+
- return 0; // continue to iteration
228+
+
229+
+ if (ptr) {
230+
+ rb_asan_poison_object(v);
231+
+ }
232+
+
233+
+ return ST_CONTINUE;
234+
}
235+
236+
static st_index_t
237+
@@ -442,10 +444,49 @@ rb_vm_ci_free(const struct rb_callinfo *ci)
238+
st_delete(vm->ci_table, &key, NULL);
239+
}
240+
241+
+void
242+
+rb_vm_insert_cc_refinement(st_table *cc_refinement_table, const struct rb_callcache *cc)
243+
+{
244+
+ st_data_t key = (st_data_t)cc;
245+
+
246+
+ if (cc_refinement_table) {
247+
+ st_insert(cc_refinement_table, key, 1);
248+
+ } else {
249+
+ rb_vm_t *vm = GET_VM();
250+
+ RB_VM_LOCK_ENTER();
251+
+ {
252+
+ st_insert(vm->cc_refinement_table, key, 1);
253+
+ }
254+
+ RB_VM_LOCK_LEAVE();
255+
+ }
256+
+}
257+
+
258+
+void rb_st_compact_table(st_table *tab);
259+
+
260+
+void
261+
+rb_vm_delete_cc_refinement(const struct rb_callcache *cc)
262+
+{
263+
+ ASSERT_vm_locking();
264+
+
265+
+ rb_vm_t *vm = GET_VM();
266+
+ st_data_t key = (st_data_t)cc;
267+
+
268+
+ st_delete(vm->cc_refinement_table, &key, NULL);
269+
+}
270+
+
271+
void
272+
rb_clear_all_refinement_method_cache(void)
273+
{
274+
- rb_objspace_each_objects(invalidate_all_refinement_cc, NULL);
275+
+ rb_vm_t *vm = GET_VM();
276+
+
277+
+ RB_VM_LOCK_ENTER();
278+
+ {
279+
+ st_foreach(vm->cc_refinement_table, invalidate_cc_refinement, (st_data_t)NULL);
280+
+ st_clear(vm->cc_refinement_table);
281+
+ rb_st_compact_table(vm->cc_refinement_table);
282+
+ }
283+
+ RB_VM_LOCK_LEAVE();
284+
+
285+
rb_yjit_invalidate_all_method_lookup_assumptions();
286+
}
287+

0 commit comments

Comments
 (0)