Apply PIE to nghttpx
[platform/upstream/nghttp2.git] / third-party / mruby / mrbgems / mruby-eval / src / eval.c
1 #include <mruby.h>
2 #include <mruby/class.h>
3 #include <mruby/compile.h>
4 #include <mruby/irep.h>
5 #include <mruby/proc.h>
6 #include <mruby/opcode.h>
7 #include <mruby/error.h>
8
9 mrb_value mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p);
10 mrb_value mrb_obj_instance_eval(mrb_state *mrb, mrb_value self);
11
12 static struct mrb_irep *
13 get_closure_irep(mrb_state *mrb, int level)
14 {
15   struct RProc *proc = mrb->c->ci[-1].proc;
16
17   while (level--) {
18     if (!proc) return NULL;
19     proc = proc->upper;
20   }
21   if (!proc) return NULL;
22   if (MRB_PROC_CFUNC_P(proc)) {
23     return NULL;
24   }
25   return proc->body.irep;
26 }
27
28 /* search for irep lev above the bottom */
29 static mrb_irep*
30 search_irep(mrb_irep *top, int bnest, int lev, mrb_irep *bottom)
31 {
32   int i;
33
34   for (i=0; i<top->rlen; i++) {
35     mrb_irep* tmp = top->reps[i];
36
37     if (tmp == bottom) return top;
38     tmp = search_irep(tmp, bnest-1, lev, bottom);
39     if (tmp) {
40       if (bnest == lev) return top;
41       return tmp;
42     }
43   }
44   return NULL;
45 }
46
47 static uint16_t
48 search_variable(mrb_state *mrb, mrb_sym vsym, int bnest)
49 {
50   mrb_irep *virep;
51   int level;
52   int pos;
53
54   for (level = 0; (virep = get_closure_irep(mrb, level)); level++) {
55     if (virep->lv == NULL) {
56       continue;
57     }
58     for (pos = 0; pos < virep->nlocals - 1; pos++) {
59       if (vsym == virep->lv[pos].name) {
60         return (pos+1)<<8 | (level+bnest);
61       }
62     }
63   }
64
65   return 0;
66 }
67
68 static int
69 irep_argc(mrb_irep *irep)
70 {
71   mrb_code c;
72
73   c = irep->iseq[0];
74   if (c == OP_ENTER) {
75     mrb_aspec ax = PEEK_W(irep->iseq+1);
76     /* extra 1 means a slot for block */
77     return MRB_ASPEC_REQ(ax)+MRB_ASPEC_OPT(ax)+MRB_ASPEC_REST(ax)+MRB_ASPEC_POST(ax)+1;
78   }
79   return 0;
80 }
81
82 static mrb_bool
83 potential_upvar_p(struct mrb_locals *lv, uint16_t v, int argc, uint16_t nlocals)
84 {
85   if (v >= nlocals) return FALSE;
86   /* skip arguments  */
87   if (v < argc+1) return FALSE;
88   return TRUE;
89 }
90
91 extern uint8_t mrb_insn_size[];
92 extern uint8_t mrb_insn_size1[];
93 extern uint8_t mrb_insn_size2[];
94 extern uint8_t mrb_insn_size3[];
95
96 static void
97 patch_irep(mrb_state *mrb, mrb_irep *irep, int bnest, mrb_irep *top)
98 {
99   int i;
100   uint32_t a;
101   uint16_t b;
102   uint8_t c;
103   mrb_code insn;
104   int argc = irep_argc(irep);
105
106   for (i = 0; i < irep->ilen; ) {
107     insn = irep->iseq[i];
108     switch(insn){
109     case OP_EPUSH:
110       b = PEEK_S(irep->iseq+i+1);
111       patch_irep(mrb, irep->reps[b], bnest + 1, top);
112       break;
113
114     case OP_LAMBDA:
115     case OP_BLOCK:
116       a = PEEK_B(irep->iseq+i+1);
117       b = PEEK_B(irep->iseq+i+2);
118       patch_irep(mrb, irep->reps[b], bnest + 1, top);
119       break;
120
121     case OP_SEND:
122       b = PEEK_B(irep->iseq+i+2);
123       c = PEEK_B(irep->iseq+i+3);
124       if (c != 0) {
125         break;
126       }
127       else {
128         uint16_t arg = search_variable(mrb, irep->syms[b], bnest);
129         if (arg != 0) {
130           /* must replace */
131           irep->iseq[i] = OP_GETUPVAR;
132           irep->iseq[i+2] = arg >> 8;
133           irep->iseq[i+3] = arg & 0xff;
134         }
135       }
136       break;
137
138     case OP_MOVE:
139       a = PEEK_B(irep->iseq+i+1);
140       b = PEEK_B(irep->iseq+i+2);
141       /* src part */
142       if (potential_upvar_p(irep->lv, b, argc, irep->nlocals)) {
143         uint16_t arg = search_variable(mrb, irep->lv[b - 1].name, bnest);
144         if (arg != 0) {
145           /* must replace */
146           irep->iseq[i] = insn = OP_GETUPVAR;
147           irep->iseq[i+2] = arg >> 8;
148           irep->iseq[i+3] = arg & 0xff;
149         }
150       }
151       /* dst part */
152       if (potential_upvar_p(irep->lv, a, argc, irep->nlocals)) {
153         uint16_t arg = search_variable(mrb, irep->lv[a - 1].name, bnest);
154         if (arg != 0) {
155           /* must replace */
156           irep->iseq[i] = insn = OP_SETUPVAR;
157           irep->iseq[i+1] = (mrb_code)b;
158           irep->iseq[i+2] = arg >> 8;
159           irep->iseq[i+3] = arg & 0xff;
160         }
161       }
162       break;
163
164     case OP_GETUPVAR:
165       a = PEEK_B(irep->iseq+i+1);
166       b = PEEK_B(irep->iseq+i+2);
167       c = PEEK_B(irep->iseq+i+3);
168       {
169         int lev = c+1;
170         mrb_irep *tmp = search_irep(top, bnest, lev, irep);
171         if (potential_upvar_p(tmp->lv, b, irep_argc(tmp), tmp->nlocals)) {
172           uint16_t arg = search_variable(mrb, tmp->lv[b-1].name, bnest);
173           if (arg != 0) {
174             /* must replace */
175             irep->iseq[i] = OP_GETUPVAR;
176             irep->iseq[i+2] = arg >> 8;
177             irep->iseq[i+3] = arg & 0xff;
178           }
179         }
180       }
181       break;
182
183     case OP_SETUPVAR:
184       a = PEEK_B(irep->iseq+i+1);
185       b = PEEK_B(irep->iseq+i+2);
186       c = PEEK_B(irep->iseq+i+3);
187       {
188         int lev = c+1;
189         mrb_irep *tmp = search_irep(top, bnest, lev, irep);
190         if (potential_upvar_p(tmp->lv, b, irep_argc(tmp), tmp->nlocals)) {
191           uint16_t arg = search_variable(mrb, tmp->lv[b-1].name, bnest);
192           if (arg != 0) {
193             /* must replace */
194             irep->iseq[i] = OP_SETUPVAR;
195             irep->iseq[i+1] = a;
196             irep->iseq[i+2] = arg >> 8;
197             irep->iseq[i+3] = arg & 0xff;
198           }
199         }
200       }
201       break;
202
203     case OP_EXT1:
204       insn = PEEK_B(irep->iseq+i+1);
205       i += mrb_insn_size1[insn]+1;
206       continue;
207     case OP_EXT2:
208       insn = PEEK_B(irep->iseq+i+1);
209       i += mrb_insn_size2[insn]+1;
210       continue;
211     case OP_EXT3:
212       insn = PEEK_B(irep->iseq+i+1);
213       i += mrb_insn_size3[insn]+1;
214       continue;
215     }
216     i+=mrb_insn_size[insn];
217   }
218 }
219
220 void mrb_codedump_all(mrb_state*, struct RProc*);
221
222 static struct RProc*
223 create_proc_from_string(mrb_state *mrb, char *s, mrb_int len, mrb_value binding, const char *file, mrb_int line)
224 {
225   mrbc_context *cxt;
226   struct mrb_parser_state *p;
227   struct RProc *proc;
228   struct REnv *e;
229   mrb_callinfo *ci; /* callinfo of eval caller */
230   struct RClass *target_class = NULL;
231   int bidx;
232
233   if (!mrb_nil_p(binding)) {
234     mrb_raise(mrb, E_ARGUMENT_ERROR, "Binding of eval must be nil.");
235   }
236
237   cxt = mrbc_context_new(mrb);
238   cxt->lineno = (short)line;
239
240   mrbc_filename(mrb, cxt, file ? file : "(eval)");
241   cxt->capture_errors = TRUE;
242   cxt->no_optimize = TRUE;
243   cxt->on_eval = TRUE;
244
245   p = mrb_parse_nstring(mrb, s, len, cxt);
246
247   /* only occur when memory ran out */
248   if (!p) {
249     mrb_raise(mrb, E_RUNTIME_ERROR, "Failed to create parser state.");
250   }
251
252   if (0 < p->nerr) {
253     /* parse error */
254     mrb_value str;
255
256     if (file) {
257       str = mrb_format(mrb, " file %S line %S: %S",
258                        mrb_str_new_cstr(mrb, file),
259                        mrb_fixnum_value(p->error_buffer[0].lineno),
260                        mrb_str_new_cstr(mrb, p->error_buffer[0].message));
261     }
262     else {
263       str = mrb_format(mrb, " line %S: %S",
264                        mrb_fixnum_value(p->error_buffer[0].lineno),
265                        mrb_str_new_cstr(mrb, p->error_buffer[0].message));
266     }
267     mrb_parser_free(p);
268     mrbc_context_free(mrb, cxt);
269     mrb_exc_raise(mrb, mrb_exc_new_str(mrb, E_SYNTAX_ERROR, str));
270   }
271
272   proc = mrb_generate_code(mrb, p);
273   if (proc == NULL) {
274     /* codegen error */
275     mrb_parser_free(p);
276     mrbc_context_free(mrb, cxt);
277     mrb_raise(mrb, E_SCRIPT_ERROR, "codegen error");
278   }
279   if (mrb->c->ci > mrb->c->cibase) {
280     ci = &mrb->c->ci[-1];
281   }
282   else {
283     ci = mrb->c->cibase;
284   }
285   if (ci->proc) {
286     target_class = MRB_PROC_TARGET_CLASS(ci->proc);
287   }
288   if (ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) {
289     if (ci->env) {
290       e = ci->env;
291     }
292     else {
293       e = (struct REnv*)mrb_obj_alloc(mrb, MRB_TT_ENV,
294                                       (struct RClass*)target_class);
295       e->mid = ci->mid;
296       e->stack = ci[1].stackent;
297       e->cxt = mrb->c;
298       MRB_ENV_SET_STACK_LEN(e, ci->proc->body.irep->nlocals);
299       bidx = ci->argc;
300       if (ci->argc < 0) bidx = 2;
301       else bidx += 1;
302       MRB_ENV_SET_BIDX(e, bidx);
303       ci->env = e;
304     }
305     proc->e.env = e;
306     proc->flags |= MRB_PROC_ENVSET;
307     mrb_field_write_barrier(mrb, (struct RBasic*)proc, (struct RBasic*)e);
308   }
309   proc->upper = ci->proc;
310   mrb->c->ci->target_class = target_class;
311   patch_irep(mrb, proc->body.irep, 0, proc->body.irep);
312   /* mrb_codedump_all(mrb, proc); */
313
314   mrb_parser_free(p);
315   mrbc_context_free(mrb, cxt);
316
317   return proc;
318 }
319
320 static mrb_value
321 exec_irep(mrb_state *mrb, mrb_value self, struct RProc *proc)
322 {
323   /* no argument passed from eval() */
324   mrb->c->ci->argc = 0;
325   if (mrb->c->ci->acc < 0) {
326     ptrdiff_t cioff = mrb->c->ci - mrb->c->cibase;
327     mrb_value ret = mrb_top_run(mrb, proc, self, 0);
328     if (mrb->exc) {
329       mrb_exc_raise(mrb, mrb_obj_value(mrb->exc));
330     }
331     mrb->c->ci = mrb->c->cibase + cioff;
332     return ret;
333   }
334   /* clear block */
335   mrb->c->stack[1] = mrb_nil_value();
336   return mrb_exec_irep(mrb, self, proc);
337 }
338
339 static mrb_value
340 f_eval(mrb_state *mrb, mrb_value self)
341 {
342   char *s;
343   mrb_int len;
344   mrb_value binding = mrb_nil_value();
345   char *file = NULL;
346   mrb_int line = 1;
347   struct RProc *proc;
348
349   mrb_get_args(mrb, "s|ozi", &s, &len, &binding, &file, &line);
350
351   proc = create_proc_from_string(mrb, s, len, binding, file, line);
352   mrb_assert(!MRB_PROC_CFUNC_P(proc));
353   return exec_irep(mrb, self, proc);
354 }
355
356 static mrb_value
357 f_instance_eval(mrb_state *mrb, mrb_value self)
358 {
359   mrb_value b;
360   mrb_int argc; mrb_value *argv;
361
362   mrb_get_args(mrb, "*!&", &argv, &argc, &b);
363
364   if (mrb_nil_p(b)) {
365     char *s;
366     mrb_int len;
367     char *file = NULL;
368     mrb_int line = 1;
369     mrb_value cv;
370     struct RProc *proc;
371
372     mrb_get_args(mrb, "s|zi", &s, &len, &file, &line);
373     cv = mrb_singleton_class(mrb, self);
374     proc = create_proc_from_string(mrb, s, len, mrb_nil_value(), file, line);
375     MRB_PROC_SET_TARGET_CLASS(proc, mrb_class_ptr(cv));
376     mrb_assert(!MRB_PROC_CFUNC_P(proc));
377     mrb->c->ci->target_class = mrb_class_ptr(cv);
378     return exec_irep(mrb, self, proc);
379   }
380   else {
381     mrb_get_args(mrb, "&", &b);
382     return mrb_obj_instance_eval(mrb, self);
383   }
384 }
385
386 void
387 mrb_mruby_eval_gem_init(mrb_state* mrb)
388 {
389   mrb_define_module_function(mrb, mrb->kernel_module, "eval", f_eval, MRB_ARGS_ARG(1, 3));
390   mrb_define_method(mrb, mrb->kernel_module, "instance_eval", f_instance_eval, MRB_ARGS_ARG(1, 2));
391 }
392
393 void
394 mrb_mruby_eval_gem_final(mrb_state* mrb)
395 {
396 }