Merge pull request #6289 from dearblue/orphan-block
[mruby.git] / src / state.c
blob35ea71e2d512714c8446503397e0e92dda7b7ee0
1 /*
2 ** state.c - mrb_state open/close functions
3 **
4 ** See Copyright Notice in mruby.h
5 */
7 #include <stdlib.h>
8 #include <string.h>
9 #include <mruby.h>
10 #include <mruby/irep.h>
11 #include <mruby/variable.h>
12 #include <mruby/debug.h>
13 #include <mruby/string.h>
14 #include <mruby/class.h>
15 #include <mruby/internal.h>
17 void mrb_init_core(mrb_state*);
18 void mrb_init_mrbgems(mrb_state*);
20 void mrb_gc_init(mrb_state*, mrb_gc *gc);
21 void mrb_gc_destroy(mrb_state*, mrb_gc *gc);
23 int mrb_core_init_protect(mrb_state *mrb, void (*body)(mrb_state*, void*), void *opaque);
25 static void
26 init_gc_and_core(mrb_state *mrb, void *opaque)
28 static const struct mrb_context mrb_context_zero = { 0 };
30 mrb_gc_init(mrb, &mrb->gc);
31 mrb->c = (struct mrb_context*)mrb_malloc(mrb, sizeof(struct mrb_context));
32 *mrb->c = mrb_context_zero;
33 mrb->root_c = mrb->c;
35 mrb_init_core(mrb);
38 MRB_API mrb_state*
39 mrb_open_core(mrb_allocf f, void *ud)
41 static const mrb_state mrb_state_zero = { 0 };
42 mrb_state *mrb;
44 if (f == NULL) f = mrb_default_allocf;
45 mrb = (mrb_state*)(f)(NULL, NULL, sizeof(mrb_state), ud);
46 if (mrb == NULL) return NULL;
48 *mrb = mrb_state_zero;
49 mrb->allocf_ud = ud;
50 mrb->allocf = f;
51 mrb->atexit_stack_len = 0;
53 if (mrb_core_init_protect(mrb, init_gc_and_core, NULL)) {
54 mrb_close(mrb);
55 return NULL;
58 return mrb;
61 MRB_API mrb_state*
62 mrb_open(void)
64 mrb_state *mrb = mrb_open_allocf(mrb_default_allocf, NULL);
66 return mrb;
69 #ifndef MRB_NO_GEMS
70 static void
71 init_mrbgems(mrb_state *mrb, void *opaque)
73 mrb_init_mrbgems(mrb);
75 #endif
77 MRB_API mrb_state*
78 mrb_open_allocf(mrb_allocf f, void *ud)
80 mrb_state *mrb = mrb_open_core(f, ud);
82 if (mrb == NULL) {
83 return NULL;
86 #ifndef MRB_NO_GEMS
87 if (mrb_core_init_protect(mrb, init_mrbgems, NULL)) {
88 mrb_close(mrb);
89 return NULL;
91 mrb_gc_arena_restore(mrb, 0);
92 #endif
93 return mrb;
96 void mrb_free_symtbl(mrb_state *mrb);
98 void
99 mrb_irep_incref(mrb_state *mrb, mrb_irep *irep)
101 if (irep->flags & MRB_IREP_NO_FREE) return;
102 if (irep->refcnt == UINT16_MAX) {
103 mrb_garbage_collect(mrb);
104 if (irep->refcnt == UINT16_MAX) {
105 mrb_raise(mrb, E_RUNTIME_ERROR, "too many irep references");
108 irep->refcnt++;
111 void
112 mrb_irep_decref(mrb_state *mrb, mrb_irep *irep)
114 if (irep->flags & MRB_IREP_NO_FREE) return;
115 irep->refcnt--;
116 if (irep->refcnt == 0) {
117 mrb_irep_free(mrb, irep);
121 void
122 mrb_irep_cutref(mrb_state *mrb, mrb_irep *irep)
124 mrb_irep **reps;
125 int i;
127 if (irep->flags & MRB_IREP_NO_FREE) return;
128 reps = (mrb_irep**)irep->reps;
129 if (!reps) return;
130 for (i=0; i<irep->rlen; i++) {
131 mrb_irep *tmp = reps[i];
132 reps[i] = NULL;
133 if (tmp) mrb_irep_decref(mrb, tmp);
137 void
138 mrb_irep_free(mrb_state *mrb, mrb_irep *irep)
140 int i;
142 if (irep->flags & MRB_IREP_NO_FREE) return;
143 if (!(irep->flags & MRB_ISEQ_NO_FREE))
144 mrb_free(mrb, (void*)irep->iseq);
145 if (irep->pool) {
146 for (i=0; i<irep->plen; i++) {
147 if ((irep->pool[i].tt & 3) == IREP_TT_STR ||
148 irep->pool[i].tt == IREP_TT_BIGINT) {
149 mrb_free(mrb, (void*)irep->pool[i].u.str);
152 mrb_free(mrb, (void*)irep->pool);
154 mrb_free(mrb, (void*)irep->syms);
155 if (irep->reps) {
156 for (i=0; i<irep->rlen; i++) {
157 if (irep->reps[i])
158 mrb_irep_decref(mrb, (mrb_irep*)irep->reps[i]);
160 mrb_free(mrb, (void*)irep->reps);
162 mrb_free(mrb, (void*)irep->lv);
163 mrb_debug_info_free(mrb, irep->debug_info);
164 #ifdef MRB_DEBUG
165 memset(irep, -1, sizeof(*irep));
166 #endif
167 mrb_free(mrb, irep);
170 MRB_API void
171 mrb_free_context(mrb_state *mrb, struct mrb_context *c)
173 if (!c) return;
174 mrb_free(mrb, c->stbase);
175 mrb_free(mrb, c->cibase);
176 mrb_free(mrb, c);
179 void mrb_protect_atexit(mrb_state *mrb);
181 MRB_API void
182 mrb_close(mrb_state *mrb)
184 if (!mrb) return;
185 mrb_protect_atexit(mrb);
187 /* free */
188 mrb_gc_destroy(mrb, &mrb->gc);
189 mrb_free_context(mrb, mrb->root_c);
190 mrb_gc_free_gv(mrb);
191 mrb_free_symtbl(mrb);
192 mrb_free(mrb, mrb);
195 MRB_API mrb_irep*
196 mrb_add_irep(mrb_state *mrb)
198 static const mrb_irep mrb_irep_zero = { 0 };
199 mrb_irep *irep;
201 irep = (mrb_irep*)mrb_malloc(mrb, sizeof(mrb_irep));
202 *irep = mrb_irep_zero;
203 irep->refcnt = 1;
205 return irep;
208 MRB_API mrb_value
209 mrb_top_self(mrb_state *mrb)
211 return mrb_obj_value(mrb->top_self);
214 MRB_API void
215 mrb_state_atexit(mrb_state *mrb, mrb_atexit_func f)
217 #ifdef MRB_FIXED_STATE_ATEXIT_STACK
218 if (mrb->atexit_stack_len + 1 > MRB_FIXED_STATE_ATEXIT_STACK_SIZE) {
219 mrb_raise(mrb, E_RUNTIME_ERROR, "exceeded fixed state atexit stack limit");
221 #else
222 size_t stack_size;
224 stack_size = sizeof(mrb_atexit_func) * (mrb->atexit_stack_len + 1);
225 if (mrb->atexit_stack_len == 0) {
226 mrb->atexit_stack = (mrb_atexit_func*)mrb_malloc(mrb, stack_size);
228 else {
229 mrb->atexit_stack = (mrb_atexit_func*)mrb_realloc(mrb, mrb->atexit_stack, stack_size);
231 #endif
233 mrb->atexit_stack[mrb->atexit_stack_len++] = f;