gc.c: extract mrb_obj_alloc_core() for internal allocation

split mrb_obj_alloc() into type-validation wrapper and allocation
core (mrb_obj_alloc_core). internal callers (mrb_proc_new,
mrb_env_new) use the core directly, skipping 15+ lines of type
validation per allocation.

most impactful for workloads with heavy Proc/Env allocation
(lambda calculus, block-intensive code).

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2026-03-20 17:44:23 +09:00
parent f7d7bbef43
commit 49dff412b5
3 changed files with 40 additions and 30 deletions
+3
View File
@@ -279,4 +279,7 @@ mrb_value mrb_bint_abs(mrb_state *mrb, mrb_value x);
void mrb_task_mark_all(mrb_state *mrb);
#endif
/* Internal object allocation without type validation (gc.c) */
struct RBasic* mrb_obj_alloc_core(mrb_state*, enum mrb_vtype, struct RClass*);
#endif /* MRUBY_INTERNAL_H */
+35 -28
View File
@@ -563,38 +563,14 @@ mrb_gc_unregister(mrb_state *mrb, mrb_value obj)
ARY_SET_LEN(a, w);
}
MRB_API struct RBasic*
mrb_obj_alloc(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls)
/* Core allocation without type validation.
Used internally by mrb_proc_new, mrb_env_new, etc. */
struct RBasic*
mrb_obj_alloc_core(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls)
{
static const RVALUE RVALUE_zero = { { { NULL, MRB_TT_FALSE } } };
mrb_gc *gc = &mrb->gc;
if (cls) {
enum mrb_vtype tt;
switch (cls->tt) {
case MRB_TT_CLASS:
case MRB_TT_SCLASS:
case MRB_TT_MODULE:
case MRB_TT_ENV:
break;
default:
mrb_raise(mrb, E_TYPE_ERROR, "allocation failure");
}
tt = MRB_INSTANCE_TT(cls);
if (ttype != MRB_TT_SCLASS &&
ttype != MRB_TT_ICLASS &&
ttype != MRB_TT_ENV &&
ttype != MRB_TT_BIGINT &&
ttype != tt &&
!(cls == mrb->object_class && (ttype == MRB_TT_CPTR || ttype == MRB_TT_CDATA || ttype == MRB_TT_ISTRUCT))) {
mrb_raisef(mrb, E_TYPE_ERROR, "allocation failure of %C", cls);
}
}
if (ttype <= MRB_TT_FREE) {
mrb_raisef(mrb, E_TYPE_ERROR, "allocation failure of %C (type %d)", cls, (int)ttype);
}
#ifdef MRB_GC_STRESS
mrb_full_gc(mrb);
#endif
@@ -625,6 +601,37 @@ mrb_obj_alloc(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls)
return &p->as.basic;
}
MRB_API struct RBasic*
mrb_obj_alloc(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls)
{
if (cls) {
enum mrb_vtype tt;
switch (cls->tt) {
case MRB_TT_CLASS:
case MRB_TT_SCLASS:
case MRB_TT_MODULE:
case MRB_TT_ENV:
break;
default:
mrb_raise(mrb, E_TYPE_ERROR, "allocation failure");
}
tt = MRB_INSTANCE_TT(cls);
if (ttype != MRB_TT_SCLASS &&
ttype != MRB_TT_ICLASS &&
ttype != MRB_TT_ENV &&
ttype != MRB_TT_BIGINT &&
ttype != tt &&
!(cls == mrb->object_class && (ttype == MRB_TT_CPTR || ttype == MRB_TT_CDATA || ttype == MRB_TT_ISTRUCT))) {
mrb_raisef(mrb, E_TYPE_ERROR, "allocation failure of %C", cls);
}
}
if (ttype <= MRB_TT_FREE) {
mrb_raisef(mrb, E_TYPE_ERROR, "allocation failure of %C (type %d)", cls, (int)ttype);
}
return mrb_obj_alloc_core(mrb, ttype, cls);
}
static inline void
add_gray_list(mrb_gc *gc, struct RBasic *obj)
{
+2 -2
View File
@@ -47,7 +47,7 @@ mrb_proc_new(mrb_state *mrb, const mrb_irep *irep)
struct RProc *p;
mrb_callinfo *ci = mrb->c->ci;
p = MRB_OBJ_ALLOC(mrb, MRB_TT_PROC, mrb->proc_class);
p = (struct RProc*)mrb_obj_alloc_core(mrb, MRB_TT_PROC, mrb->proc_class);
if (ci) {
struct RClass *tc = NULL;
@@ -76,7 +76,7 @@ mrb_env_new(mrb_state *mrb, struct mrb_context *c, mrb_callinfo *ci, int nstacks
int n = ci->n;
int nk = ci->nk;
e = MRB_OBJ_ALLOC(mrb, MRB_TT_ENV, NULL);
e = (struct REnv*)mrb_obj_alloc_core(mrb, MRB_TT_ENV, NULL);
e->c = tc;
MRB_ENV_SET_LEN(e, nstacks);
bidx += (n == 15) ? 1 : n;