Coverage Report

Created: 2026-06-13 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mruby/include/mruby/proc.h
Line
Count
Source
1
/**
2
** @file mruby/proc.h - Proc class
3
**
4
** See Copyright Notice in mruby.h
5
*/
6
7
#ifndef MRUBY_PROC_H
8
#define MRUBY_PROC_H
9
10
#include "common.h"
11
#include <mruby/irep.h>
12
#include <string.h>
13
14
/**
15
 * Proc class
16
 */
17
MRB_BEGIN_DECL
18
19
/*
20
 * env object (for internal used)
21
 *
22
 * - don't create multiple envs on one ci.
23
 * - don't share a env to different ci.
24
 * - don't attach a closed env to any ci.
25
 */
26
struct REnv {
27
  MRB_OBJECT_HEADER;
28
  mrb_value *stack;
29
  struct mrb_context *cxt; /* if not null, it means that the stack is shared with the call frame */
30
  mrb_sym mid;
31
};
32
33
/* flags (20bits): 1(ZERO):1(separate module):2(visibility):8(cioff/bidx):8(stack_len) */
34
933k
#define MRB_ENV_SET_LEN(e,len) ((e)->flags = (((e)->flags & ~0xff)|((unsigned int)(len) & 0xff)))
35
4.63M
#define MRB_ENV_LEN(e) ((mrb_int)((e)->flags & 0xff))
36
563k
#define MRB_ENV_CLOSE(e) ((e)->cxt = NULL)
37
731k
#define MRB_ENV_ONSTACK_P(e) ((e)->cxt != NULL)
38
290
#define MRB_ENV_BIDX(e) (((e)->flags >> 8) & 0xff)
39
731k
#define MRB_ENV_SET_BIDX(e,idx) ((e)->flags = (((e)->flags & ~(0xff<<8))|((unsigned int)(idx) & 0xff)<<8))
40
0
#define MRB_ENV_SET_VISIBILITY(e, vis) MRB_FLAGS_SET((e)->flags, 16, 2, vis)
41
#define MRB_ENV_VISIBILITY(e) MRB_FLAGS_GET((e)->flags, 16, 2)
42
0
#define MRB_ENV_VISIBILITY_BREAK_P(e) MRB_FLAG_CHECK((e)->flags, 18)
43
731k
#define MRB_ENV_COPY_FLAGS_FROM_CI(e, ci) MRB_FLAGS_SET((e)->flags, 16, 3, (ci)->vis)
44
45
/*
46
 * Returns TRUE on success.
47
 * If the function fails:
48
 * * Returns FALSE if noraise is TRUE.
49
 * * Raises a NoMemoryError exception if noraise is FALSE.
50
 */
51
mrb_bool mrb_env_unshare(mrb_state*, struct REnv*, mrb_bool noraise);
52
53
struct RProc {
54
  MRB_OBJECT_HEADER;
55
  union {
56
    const mrb_irep *irep;
57
    mrb_func_t func;
58
    mrb_sym mid;
59
  } body;
60
  const struct RProc *upper;
61
  union {
62
    struct RClass *target_class;
63
    struct REnv *env;
64
  } e;
65
};
66
67
/* aspec access */
68
13.0M
#define MRB_ASPEC_REQ(a)          (((a) >> 18) & 0x1f)
69
19.1M
#define MRB_ASPEC_OPT(a)          (((a) >> 13) & 0x1f)
70
11.8M
#define MRB_ASPEC_REST(a)         (((a) >> 12) & 0x1)
71
11.8M
#define MRB_ASPEC_POST(a)         (((a) >> 7) & 0x1f)
72
3.09M
#define MRB_ASPEC_KEY(a)          (((a) >> 2) & 0x1f)
73
3.09M
#define MRB_ASPEC_KDICT(a)        (((a) >> 1) & 0x1)
74
1.87k
#define MRB_ASPEC_BLOCK(a)        ((a) & 1)
75
5.41M
#define MRB_ASPEC_NOBLOCK(a)      (((a) >> 23) & 0x1)
76
77
26.9M
#define MRB_PROC_CFUNC_FL 128
78
49.3M
#define MRB_PROC_CFUNC_P(p) (((p)->flags & MRB_PROC_CFUNC_FL) != 0)
79
128
#define MRB_PROC_CFUNC(p) (p)->body.func
80
11.2M
#define MRB_PROC_STRICT 256
81
5.95M
#define MRB_PROC_STRICT_P(p) (((p)->flags & MRB_PROC_STRICT) != 0)
82
409k
#define MRB_PROC_ORPHAN 512
83
0
#define MRB_PROC_ORPHAN_P(p) (((p)->flags & MRB_PROC_ORPHAN) != 0)
84
38.7M
#define MRB_PROC_ENVSET 1024
85
38.5M
#define MRB_PROC_ENV_P(p) (((p)->flags & MRB_PROC_ENVSET) != 0)
86
7.63M
#define MRB_PROC_ENV(p) (MRB_PROC_ENV_P(p) ? (p)->e.env : NULL)
87
11.6M
#define MRB_PROC_TARGET_CLASS(p) (MRB_PROC_ENV_P(p) ? (p)->e.env->c : (p)->e.target_class)
88
7.92M
#define MRB_PROC_SET_TARGET_CLASS(p,tc) do {\
89
7.92M
  if (MRB_PROC_ENV_P(p)) {\
90
11.8k
    (p)->e.env->c = (tc);\
91
11.8k
    mrb_field_write_barrier(mrb, (struct RBasic*)(p)->e.env, (struct RBasic*)(tc));\
92
11.8k
  }\
93
7.92M
  else {\
94
7.90M
    (p)->e.target_class = (tc);\
95
7.90M
    mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)(tc));\
96
7.90M
  }\
97
7.92M
} while (0)
98
19.6M
#define MRB_PROC_SCOPE 2048
99
10.4M
#define MRB_PROC_SCOPE_P(p) (((p)->flags & MRB_PROC_SCOPE) != 0)
100
141k
#define MRB_PROC_NOARG 4096 /* for MRB_PROC_CFUNC_FL, aspec == MRB_ARGS_NONE() */
101
256
#define MRB_PROC_NOARG_P(p) (((p)->flags & MRB_PROC_NOARG) != 0)
102
14.4M
#define MRB_PROC_ALIAS 8192
103
22.5M
#define MRB_PROC_ALIAS_P(p) (((p)->flags & MRB_PROC_ALIAS) != 0)
104
105
/* Compressed aspec for cfunc procs (13 bits in RProc.flags).
106
 * Uses free bits 0-6 and 14-19 to store a compressed argument spec.
107
 * Layout: block(0) kdict(1) key(2-3) post(4-5) rest(6) opt(14-16) req(17-19)
108
 * Field widths are smaller than the full 24-bit aspec: req/opt max 7, post/key max 3.
109
 * Values exceeding the compressed range are clamped and rest is forced to 1. */
110
1.87k
#define MRB_PROC_CASPEC_MASK  0xfc07fu  /* bits 0-6 and 14-19 */
111
112
static inline uint32_t
113
mrb_proc_compress_aspec(mrb_aspec aspec)
114
1.87k
{
115
1.87k
  uint32_t req   = MRB_ASPEC_REQ(aspec);
116
1.87k
  uint32_t opt   = MRB_ASPEC_OPT(aspec);
117
1.87k
  uint32_t rest  = MRB_ASPEC_REST(aspec);
118
1.87k
  uint32_t post  = MRB_ASPEC_POST(aspec);
119
1.87k
  uint32_t key   = MRB_ASPEC_KEY(aspec);
120
1.87k
  uint32_t kdict = MRB_ASPEC_KDICT(aspec);
121
1.87k
  uint32_t block = MRB_ASPEC_BLOCK(aspec);
122
123
1.87k
  if (req > 7 || opt > 7 || post > 3 || key > 3) {
124
0
    if (req > 7) req = 7;
125
0
    if (opt > 7) opt = 7;
126
0
    if (post > 3) post = 3;
127
0
    if (key > 3) key = 3;
128
0
    rest = 1;
129
0
  }
130
131
1.87k
  return block | (kdict << 1) | (key << 2) | (post << 4) | (rest << 6)
132
1.87k
       | (opt << 14) | (req << 17);
133
1.87k
}
Unexecuted instantiation: class.c:mrb_proc_compress_aspec
Unexecuted instantiation: array.c:mrb_proc_compress_aspec
Unexecuted instantiation: y.tab.c:mrb_proc_compress_aspec
Unexecuted instantiation: mrblib.c:mrb_proc_compress_aspec
Unexecuted instantiation: gem_init.c:mrb_proc_compress_aspec
Unexecuted instantiation: variable.c:mrb_proc_compress_aspec
Unexecuted instantiation: symbol.c:mrb_proc_compress_aspec
Unexecuted instantiation: gc.c:mrb_proc_compress_aspec
Unexecuted instantiation: error.c:mrb_proc_compress_aspec
Unexecuted instantiation: load.c:mrb_proc_compress_aspec
Unexecuted instantiation: enum.c:mrb_proc_compress_aspec
Unexecuted instantiation: vm.c:mrb_proc_compress_aspec
Unexecuted instantiation: proc.c:mrb_proc_compress_aspec
Unexecuted instantiation: hash.c:mrb_proc_compress_aspec
Unexecuted instantiation: codedump.c:mrb_proc_compress_aspec
Unexecuted instantiation: kernel.c:mrb_proc_compress_aspec
Unexecuted instantiation: backtrace.c:mrb_proc_compress_aspec
Unexecuted instantiation: codegen.c:mrb_proc_compress_aspec
Unexecuted instantiation: set.c:mrb_proc_compress_aspec
Unexecuted instantiation: object.c:mrb_proc_compress_aspec
Unexecuted instantiation: mruby_objectspace.c:mrb_proc_compress_aspec
Unexecuted instantiation: fiber.c:mrb_proc_compress_aspec
Unexecuted instantiation: catch.c:mrb_proc_compress_aspec
Unexecuted instantiation: struct.c:mrb_proc_compress_aspec
Unexecuted instantiation: data.c:mrb_proc_compress_aspec
Unexecuted instantiation: metaprog.c:mrb_proc_compress_aspec
method.c:mrb_proc_compress_aspec
Line
Count
Source
114
1.87k
{
115
1.87k
  uint32_t req   = MRB_ASPEC_REQ(aspec);
116
1.87k
  uint32_t opt   = MRB_ASPEC_OPT(aspec);
117
1.87k
  uint32_t rest  = MRB_ASPEC_REST(aspec);
118
1.87k
  uint32_t post  = MRB_ASPEC_POST(aspec);
119
1.87k
  uint32_t key   = MRB_ASPEC_KEY(aspec);
120
1.87k
  uint32_t kdict = MRB_ASPEC_KDICT(aspec);
121
1.87k
  uint32_t block = MRB_ASPEC_BLOCK(aspec);
122
123
1.87k
  if (req > 7 || opt > 7 || post > 3 || key > 3) {
124
0
    if (req > 7) req = 7;
125
0
    if (opt > 7) opt = 7;
126
0
    if (post > 3) post = 3;
127
0
    if (key > 3) key = 3;
128
0
    rest = 1;
129
0
  }
130
131
1.87k
  return block | (kdict << 1) | (key << 2) | (post << 4) | (rest << 6)
132
1.87k
       | (opt << 14) | (req << 17);
133
1.87k
}
Unexecuted instantiation: eval.c:mrb_proc_compress_aspec
Unexecuted instantiation: binding.c:mrb_proc_compress_aspec
Unexecuted instantiation: proc_binding.c:mrb_proc_compress_aspec
134
135
static inline mrb_aspec
136
mrb_proc_decompress_caspec(uint32_t flags)
137
0
{
138
0
  return (((flags >> 17) & 0x7) << 18)  /* req */
139
0
       | (((flags >> 14) & 0x7) << 13)  /* opt */
140
0
       | (((flags >> 6) & 0x1) << 12)   /* rest */
141
0
       | (((flags >> 4) & 0x3) << 7)    /* post */
142
0
       | (((flags >> 2) & 0x3) << 2)    /* key */
143
0
       | (((flags >> 1) & 0x1) << 1)    /* kdict */
144
0
       | (flags & 0x1);                 /* block */
145
0
}
Unexecuted instantiation: class.c:mrb_proc_decompress_caspec
Unexecuted instantiation: array.c:mrb_proc_decompress_caspec
Unexecuted instantiation: y.tab.c:mrb_proc_decompress_caspec
Unexecuted instantiation: mrblib.c:mrb_proc_decompress_caspec
Unexecuted instantiation: gem_init.c:mrb_proc_decompress_caspec
Unexecuted instantiation: variable.c:mrb_proc_decompress_caspec
Unexecuted instantiation: symbol.c:mrb_proc_decompress_caspec
Unexecuted instantiation: gc.c:mrb_proc_decompress_caspec
Unexecuted instantiation: error.c:mrb_proc_decompress_caspec
Unexecuted instantiation: load.c:mrb_proc_decompress_caspec
Unexecuted instantiation: enum.c:mrb_proc_decompress_caspec
Unexecuted instantiation: vm.c:mrb_proc_decompress_caspec
Unexecuted instantiation: proc.c:mrb_proc_decompress_caspec
Unexecuted instantiation: hash.c:mrb_proc_decompress_caspec
Unexecuted instantiation: codedump.c:mrb_proc_decompress_caspec
Unexecuted instantiation: kernel.c:mrb_proc_decompress_caspec
Unexecuted instantiation: backtrace.c:mrb_proc_decompress_caspec
Unexecuted instantiation: codegen.c:mrb_proc_decompress_caspec
Unexecuted instantiation: set.c:mrb_proc_decompress_caspec
Unexecuted instantiation: object.c:mrb_proc_decompress_caspec
Unexecuted instantiation: mruby_objectspace.c:mrb_proc_decompress_caspec
Unexecuted instantiation: fiber.c:mrb_proc_decompress_caspec
Unexecuted instantiation: catch.c:mrb_proc_decompress_caspec
Unexecuted instantiation: struct.c:mrb_proc_decompress_caspec
Unexecuted instantiation: data.c:mrb_proc_decompress_caspec
Unexecuted instantiation: metaprog.c:mrb_proc_decompress_caspec
Unexecuted instantiation: method.c:mrb_proc_decompress_caspec
Unexecuted instantiation: eval.c:mrb_proc_decompress_caspec
Unexecuted instantiation: binding.c:mrb_proc_decompress_caspec
Unexecuted instantiation: proc_binding.c:mrb_proc_decompress_caspec
146
147
static inline void
148
mrb_proc_set_cfunc_aspec(struct RProc *p, mrb_aspec aspec)
149
1.87k
{
150
1.87k
  p->flags &= ~(MRB_PROC_NOARG | MRB_PROC_CASPEC_MASK);
151
1.87k
  if (aspec == 0) {
152
2
    p->flags |= MRB_PROC_NOARG;
153
2
  }
154
1.87k
  else {
155
1.87k
    p->flags |= mrb_proc_compress_aspec(aspec);
156
1.87k
  }
157
1.87k
}
Unexecuted instantiation: class.c:mrb_proc_set_cfunc_aspec
Unexecuted instantiation: array.c:mrb_proc_set_cfunc_aspec
Unexecuted instantiation: y.tab.c:mrb_proc_set_cfunc_aspec
Unexecuted instantiation: mrblib.c:mrb_proc_set_cfunc_aspec
Unexecuted instantiation: gem_init.c:mrb_proc_set_cfunc_aspec
Unexecuted instantiation: variable.c:mrb_proc_set_cfunc_aspec
Unexecuted instantiation: symbol.c:mrb_proc_set_cfunc_aspec
Unexecuted instantiation: gc.c:mrb_proc_set_cfunc_aspec
Unexecuted instantiation: error.c:mrb_proc_set_cfunc_aspec
Unexecuted instantiation: load.c:mrb_proc_set_cfunc_aspec
Unexecuted instantiation: enum.c:mrb_proc_set_cfunc_aspec
Unexecuted instantiation: vm.c:mrb_proc_set_cfunc_aspec
Unexecuted instantiation: proc.c:mrb_proc_set_cfunc_aspec
Unexecuted instantiation: hash.c:mrb_proc_set_cfunc_aspec
Unexecuted instantiation: codedump.c:mrb_proc_set_cfunc_aspec
Unexecuted instantiation: kernel.c:mrb_proc_set_cfunc_aspec
Unexecuted instantiation: backtrace.c:mrb_proc_set_cfunc_aspec
Unexecuted instantiation: codegen.c:mrb_proc_set_cfunc_aspec
Unexecuted instantiation: set.c:mrb_proc_set_cfunc_aspec
Unexecuted instantiation: object.c:mrb_proc_set_cfunc_aspec
Unexecuted instantiation: mruby_objectspace.c:mrb_proc_set_cfunc_aspec
Unexecuted instantiation: fiber.c:mrb_proc_set_cfunc_aspec
Unexecuted instantiation: catch.c:mrb_proc_set_cfunc_aspec
Unexecuted instantiation: struct.c:mrb_proc_set_cfunc_aspec
Unexecuted instantiation: data.c:mrb_proc_set_cfunc_aspec
Unexecuted instantiation: metaprog.c:mrb_proc_set_cfunc_aspec
method.c:mrb_proc_set_cfunc_aspec
Line
Count
Source
149
1.87k
{
150
1.87k
  p->flags &= ~(MRB_PROC_NOARG | MRB_PROC_CASPEC_MASK);
151
1.87k
  if (aspec == 0) {
152
2
    p->flags |= MRB_PROC_NOARG;
153
2
  }
154
1.87k
  else {
155
1.87k
    p->flags |= mrb_proc_compress_aspec(aspec);
156
1.87k
  }
157
1.87k
}
Unexecuted instantiation: eval.c:mrb_proc_set_cfunc_aspec
Unexecuted instantiation: binding.c:mrb_proc_set_cfunc_aspec
Unexecuted instantiation: proc_binding.c:mrb_proc_set_cfunc_aspec
158
159
2.58M
#define mrb_proc_ptr(v)    ((struct RProc*)(mrb_ptr(v)))
160
161
struct RProc *mrb_proc_new(mrb_state*, const mrb_irep*);
162
MRB_API struct RProc *mrb_proc_new_cfunc(mrb_state*, mrb_func_t);
163
MRB_API struct RProc *mrb_closure_new_cfunc(mrb_state *mrb, mrb_func_t func, int nlocals);
164
165
/* following functions are defined in mruby-proc-ext so please include it when using */
166
MRB_API struct RProc *mrb_proc_new_cfunc_with_env(mrb_state *mrb, mrb_func_t func, mrb_int argc, const mrb_value *argv);
167
MRB_API mrb_value mrb_proc_cfunc_env_get(mrb_state *mrb, mrb_int idx);
168
/* old name */
169
#define mrb_cfunc_env_get(mrb, idx) mrb_proc_cfunc_env_get(mrb, idx)
170
171
44.4M
#define MRB_METHOD_FUNC_FL    (1 << 24)
172
19.9M
#define MRB_METHOD_PUBLIC_FL  0
173
13.7M
#define MRB_METHOD_PRIVATE_FL (1 << 25)
174
10.1M
#define MRB_METHOD_PROTECTED_FL (1 << 26)
175
11.5M
#define MRB_METHOD_VDEFAULT_FL ((1 << 25) | (1 << 26))
176
32.5M
#define MRB_METHOD_VISIBILITY_MASK ((1 << 25) | (1 << 26))
177
178
43.7M
#define MRB_METHOD_FUNC_P(m) ((m).flags&MRB_METHOD_FUNC_FL)
179
24.3M
#define MRB_METHOD_FUNC(m) ((m).as.func)
180
4.19M
#define MRB_METHOD_FROM_FUNC(m,fn) do{(m).flags=MRB_METHOD_FUNC_FL;(m).as.func=(fn);}while(0)
181
7.31M
#define MRB_METHOD_FROM_PROC(m,pr) do{(m).flags=0;(m).as.proc=(pr);}while(0)
182
26.0M
#define MRB_METHOD_PROC_P(m) (!MRB_METHOD_FUNC_P(m))
183
11.5M
#define MRB_METHOD_PROC(m) ((m).as.proc)
184
14.5M
#define MRB_METHOD_UNDEF_P(m) ((m).as.proc==NULL)
185
630k
#define MRB_METHOD_VISIBILITY(m) ((m).flags & MRB_METHOD_VISIBILITY_MASK)
186
17.4M
#define MRB_SET_VISIBILITY_FLAGS(f,v) ((f)=(((f)&~MRB_METHOD_VISIBILITY_MASK)|(v)))
187
11.1M
#define MRB_METHOD_SET_VISIBILITY(m,v) MRB_SET_VISIBILITY_FLAGS((m).flags,(v))
188
189
3.51M
#define MRB_METHOD_CFUNC_P(m) (MRB_METHOD_FUNC_P(m) || (MRB_METHOD_PROC(m)?(MRB_PROC_CFUNC_P(MRB_METHOD_PROC(m))):FALSE))
190
/* use MRB_METHOD_CFUNC(m) only when MRB_METHOD_CFUNC_P(m) is true */
191
2.31M
#define MRB_METHOD_CFUNC(m) (MRB_METHOD_FUNC_P(m)?MRB_METHOD_FUNC(m):MRB_PROC_CFUNC(MRB_METHOD_PROC(m)))
192
193
MRB_API mrb_value mrb_load_proc(mrb_state *mrb, const struct RProc *proc);
194
195
/**
196
 *  It can be used to isolate top-level scopes referenced by blocks generated by
197
 *  `mrb_load_string_cxt()` or similar called before entering the mruby VM (e.g. from `main()`).
198
 *  In that case, the `ci` parameter should be `mrb->c->cibase`.
199
 *
200
 *      #include <mruby.h>
201
 *      #include <mruby/compile.h>
202
 *      #include <mruby/proc.h>
203
 *
204
 *      int
205
 *      main(int argc, char **argv)
206
 *      {
207
 *        mrb_state *mrb;
208
 *        mrb_ccontext *cxt;
209
 *        mrb_value blk, ret;
210
 *
211
 *        mrb = mrb_open();
212
 *        cxt = mrb_ccontext_new(mrb);
213
 *        blk = mrb_load_string_cxt(mrb, "x, y, z = 1, 2, 3; proc { [x, y, z] }", cxt);
214
 *        mrb_vm_ci_env_clear(mrb, mrb->c->cibase);
215
 *        mrb_load_string_cxt(mrb, "x, y, z = 4, 5, 6", cxt);
216
 *        ret = mrb_funcall(mrb, blk, "call", 0);
217
 *        mrb_p(mrb, ret);  // => [1, 2, 3]
218
 *                          // => [4, 5, 6] if `mrb_vm_ci_env_clear()` is commented out
219
 *        mrb_ccontext_free(mrb, cxt);
220
 *        mrb_close(mrb);
221
 *
222
 *        return 0;
223
 *      }
224
 *
225
 *  The top-level local variable names stored in `mrb_ccontext` are retained.
226
 *  Use also `mrb_ccontext_cleanup_local_variables()` at the same time, if necessary.
227
 */
228
MRB_API void mrb_vm_ci_env_clear(mrb_state *mrb, mrb_callinfo *ci);
229
230
void mrb_vm_ci_proc_set(mrb_callinfo *ci, const struct RProc *p);
231
struct RClass * mrb_vm_ci_target_class(const mrb_callinfo *ci);
232
void mrb_vm_ci_target_class_set(mrb_callinfo *ci, struct RClass *tc);
233
struct REnv * mrb_vm_ci_env(const mrb_callinfo *ci);
234
void mrb_vm_ci_env_set(mrb_callinfo *ci, struct REnv *e);
235
236
MRB_END_DECL
237
238
#endif  /* MRUBY_PROC_H */