java-topology/defects/ruby/patch/0001-kwarg-setup-hash-lookup.patch

86 lines
3.2 KiB
Diff

# UNDF: UNDF-2026-000000265
diff --git a/vm_args.c b/vm_args.c
--- a/vm_args.c
+++ b/vm_args.c
@@ -299,30 +299,50 @@ static inline int
-args_setup_kw_parameters_lookup(const ID key, VALUE *ptr,
- const VALUE *const passed_keywords, VALUE *passed_values,
- const int passed_keyword_len)
-{
- int i;
- const VALUE keyname = ID2SYM(key);
-
- for (i=0; i<passed_keyword_len; i++) { /* O(passed_keyword_len) */
- if (keyname == passed_keywords[i]) {
- *ptr = passed_values[i];
- passed_values[i] = Qundef;
- return TRUE;
- }
- }
-
- return FALSE;
-}
+/* Build a temporary st_table from passed keyword symbol -> value-slot index.
+ * Replaces O(K * P) double-loop with O(K + P): one pass to build the map,
+ * one O(1) lookup per accepted keyword.
+ */
+static st_table *
+build_passed_kw_table(const VALUE *const passed_keywords,
+ const int passed_keyword_len)
+{
+ st_table *tbl = st_init_numtable_with_size(passed_keyword_len);
+ for (int i = 0; i < passed_keyword_len; i++) {
+ st_insert(tbl, (st_data_t)passed_keywords[i], (st_data_t)i);
+ }
+ return tbl;
+}
static void
args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *const iseq, const rb_callable_method_entry_t *cme,
VALUE *const passed_values, const int passed_keyword_len, const VALUE *const passed_keywords,
VALUE *const locals)
{
const ID *acceptable_keywords = ISEQ_BODY(iseq)->param.keyword->table;
const int req_key_num = ISEQ_BODY(iseq)->param.keyword->required_num;
const int key_num = ISEQ_BODY(iseq)->param.keyword->num;
const VALUE * const default_values = ISEQ_BODY(iseq)->param.keyword->default_values;
VALUE missing = 0;
int i, di, found = 0;
int unspecified_bits = 0;
VALUE unspecified_bits_value = Qnil;
+ /* Build O(1) lookup map once — replaces O(K*P) nested loop */
+ st_table *kw_map = (passed_keyword_len > 0)
+ ? build_passed_kw_table(passed_keywords, passed_keyword_len)
+ : NULL;
+
for (i=0; i<req_key_num; i++) {
ID key = acceptable_keywords[i];
- if (args_setup_kw_parameters_lookup(key, &locals[i], passed_keywords, passed_values, passed_keyword_len)) {
+ VALUE keyname = ID2SYM(key);
+ st_data_t idx;
+ if (kw_map && st_lookup(kw_map, (st_data_t)keyname, &idx)) {
+ locals[i] = passed_values[idx];
+ passed_values[idx] = Qundef;
found++;
- }
- else {
+ } else {
if (!missing) missing = rb_ary_hidden_new(1);
rb_ary_push(missing, ID2SYM(key));
}
}
if (missing) argument_kw_error(ec, iseq, cme, "missing", missing);
for (di=0; i<key_num; i++, di++) {
- if (args_setup_kw_parameters_lookup(acceptable_keywords[i], &locals[i], passed_keywords, passed_values, passed_keyword_len)) {
+ VALUE keyname = ID2SYM(acceptable_keywords[i]);
+ st_data_t idx;
+ if (kw_map && st_lookup(kw_map, (st_data_t)keyname, &idx)) {
+ locals[i] = passed_values[idx];
+ passed_values[idx] = Qundef;
found++;
- }
- else {
+ } else {