vm.c 60.3 KB
Newer Older
go kikuta's avatar
go kikuta committed
1
/*
2
** vm.c - virtual machine for mruby
roco's avatar
roco committed
3
**
mimaki's avatar
mimaki committed
4 5 6
** See Copyright Notice in mruby.h
*/

7 8
#include <stddef.h>
#include <stdarg.h>
9
#include <math.h>
mimaki's avatar
mimaki committed
10 11 12
#include "mruby.h"
#include "mruby/array.h"
#include "mruby/class.h"
13 14
#include "mruby/hash.h"
#include "mruby/irep.h"
15
#include "mruby/numeric.h"
16 17 18 19
#include "mruby/proc.h"
#include "mruby/range.h"
#include "mruby/string.h"
#include "mruby/variable.h"
20
#include "mruby/error.h"
21
#include "mruby/opcode.h"
22
#include "value_array.h"
take_cheeze's avatar
take_cheeze committed
23
#include "mrb_throw.h"
mimaki's avatar
mimaki committed
24

25 26 27 28 29 30 31 32 33
#ifndef ENABLE_STDIO
#if defined(__cplusplus)
extern "C" {
#endif
void abort(void);
#if defined(__cplusplus)
}  /* extern "C" { */
#endif
#endif
mimaki's avatar
mimaki committed
34 35 36 37

#define STACK_INIT_SIZE 128
#define CALLINFO_INIT_SIZE 32

38 39 40 41 42
/* Define amount of linear stack growth. */
#ifndef MRB_STACK_GROWTH
#define MRB_STACK_GROWTH 128
#endif

43
/* Maximum stack depth. Should be set lower on memory constrained systems.
44 45
The value below allows about 60000 recursive calls in the simplest case. */
#ifndef MRB_STACK_MAX
46
#define MRB_STACK_MAX (0x40000 - MRB_STACK_GROWTH)
47 48
#endif

49 50 51 52 53
#ifdef VM_DEBUG
# define DEBUG(x) (x)
#else
# define DEBUG(x)
#endif
54

55 56
#define ARENA_RESTORE(mrb,ai) (mrb)->arena_idx = (ai)

57 58 59
static inline void
stack_clear(mrb_value *from, size_t count)
{
60
#ifndef MRB_NAN_BOXING
61 62
  const mrb_value mrb_value_zero = { { 0 } };

63
  while (count-- > 0) {
64
    *from++ = mrb_value_zero;
65
  }
66
#else
67
  while (count-- > 0) {
68 69
    SET_NIL_VALUE(*from);
    from++;
70
  }
71
#endif
72 73
}

74 75 76
static inline void
stack_copy(mrb_value *dst, const mrb_value *src, size_t size)
{
77 78
  while (size-- > 0) {
    *dst++ = *src++;
79 80 81
  }
}

mimaki's avatar
mimaki committed
82 83 84
static void
stack_init(mrb_state *mrb)
{
85 86
  struct mrb_context *c = mrb->c;

fleuria's avatar
fleuria committed
87
  /* mrb_assert(mrb->stack == NULL); */
88 89 90 91
  c->stbase = (mrb_value *)mrb_calloc(mrb, STACK_INIT_SIZE, sizeof(mrb_value));
  c->stend = c->stbase + STACK_INIT_SIZE;
  c->stack = c->stbase;

fleuria's avatar
fleuria committed
92
  /* mrb_assert(ci == NULL); */
93 94 95 96
  c->cibase = (mrb_callinfo *)mrb_calloc(mrb, CALLINFO_INIT_SIZE, sizeof(mrb_callinfo));
  c->ciend = c->cibase + CALLINFO_INIT_SIZE;
  c->ci = c->cibase;
  c->ci->target_class = mrb->object_class;
97
  c->ci->stackent = c->stack;
mimaki's avatar
mimaki committed
98 99
}

100
static inline void
101 102
envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase)
{
103
  mrb_callinfo *ci = mrb->c->cibase;
104

105
  if (newbase == oldbase) return;
106
  while (ci <= mrb->c->ci) {
107
    struct REnv *e = ci->env;
108
    if (e && MRB_ENV_STACK_SHARED_P(e)) {
109
      ptrdiff_t off = e->stack - oldbase;
110 111 112

      e->stack = newbase + off;
    }
113
    ci->stackent = newbase + (ci->stackent - oldbase);
114 115 116 117
    ci++;
  }
}

118 119 120 121 122 123 124 125 126
static inline void
init_new_stack_space(mrb_state *mrb, int room, int keep)
{
  if (room > keep) {
    /* do not leave uninitialized malloc region */
    stack_clear(&(mrb->c->stack[keep]), room - keep);
  }
}

127 128
/** def rec ; $deep =+ 1 ; if $deep > 1000 ; return 0 ; end ; rec ; end  */

mimaki's avatar
mimaki committed
129
static void
130
stack_extend_alloc(mrb_state *mrb, int room, int keep)
131 132 133 134 135
{
  mrb_value *oldbase = mrb->c->stbase;
  int size = mrb->c->stend - mrb->c->stbase;
  int off = mrb->c->stack - mrb->c->stbase;

136 137 138 139 140 141
#ifdef MRB_STACK_EXTEND_DOUBLING
  if (room <= size)
    size *= 2;
  else
    size += room;
#else
142
  /* Use linear stack growth.
143
     It is slightly slower than doubling the stack space,
144
     but it saves memory on small devices. */
145
  if (room <= MRB_STACK_GROWTH)
146 147 148
    size += MRB_STACK_GROWTH;
  else
    size += room;
149
#endif
150 151 152 153 154

  mrb->c->stbase = (mrb_value *)mrb_realloc(mrb, mrb->c->stbase, sizeof(mrb_value) * size);
  mrb->c->stack = mrb->c->stbase + off;
  mrb->c->stend = mrb->c->stbase + size;
  envadjust(mrb, oldbase, mrb->c->stbase);
155

156 157 158
  /* Raise an exception if the new stack size will be too large,
     to prevent infinite recursion. However, do this only after resizing the stack, so mrb_raise has stack space to work with. */
  if (size > MRB_STACK_MAX) {
159
    init_new_stack_space(mrb, room, keep);
cremno's avatar
cremno committed
160
    mrb_raise(mrb, E_SYSSTACK_ERROR, "stack level too deep. (limit=" MRB_STRINGIZE(MRB_STACK_MAX) ")");
161 162 163 164
  }
}

static inline void
165
stack_extend(mrb_state *mrb, int room, int keep)
mimaki's avatar
mimaki committed
166
{
167
  if (mrb->c->stack + room >= mrb->c->stend) {
168
    stack_extend_alloc(mrb, room, keep);
mimaki's avatar
mimaki committed
169
  }
170
  init_new_stack_space(mrb, room, keep);
mimaki's avatar
mimaki committed
171 172
}

173
static inline struct REnv*
mimaki's avatar
mimaki committed
174 175
uvenv(mrb_state *mrb, int up)
{
176
  struct REnv *e = mrb->c->ci->proc->env;
mimaki's avatar
mimaki committed
177 178

  while (up--) {
179
    if (!e) return NULL;
mimaki's avatar
mimaki committed
180 181 182 183 184
    e = (struct REnv*)e->c;
  }
  return e;
}

185
static inline mrb_bool
186 187 188 189
is_strict(mrb_state *mrb, struct REnv *e)
{
  int cioff = e->cioff;

190
  if (MRB_ENV_STACK_SHARED_P(e) && mrb->c->cibase[cioff].proc &&
191
      MRB_PROC_STRICT_P(mrb->c->cibase[cioff].proc)) {
192
    return TRUE;
193
  }
194
  return FALSE;
195 196
}

197
static inline struct REnv*
198
top_env(mrb_state *mrb, struct RProc *proc)
199 200 201
{
  struct REnv *e = proc->env;

202
  if (is_strict(mrb, e)) return e;
203 204
  while (e->c) {
    e = (struct REnv*)e->c;
205
    if (is_strict(mrb, e)) return e;
206 207 208 209
  }
  return e;
}

210 211 212
#define CI_ACC_SKIP    -1
#define CI_ACC_DIRECT  -2

mimaki's avatar
mimaki committed
213 214 215
static mrb_callinfo*
cipush(mrb_state *mrb)
{
216 217 218 219 220
  struct mrb_context *c = mrb->c;
  mrb_callinfo *ci = c->ci;

  int eidx = ci->eidx;
  int ridx = ci->ridx;
mimaki's avatar
mimaki committed
221

222 223
  if (ci + 1 == c->ciend) {
    size_t size = ci - c->cibase;
mimaki's avatar
mimaki committed
224

225
    c->cibase = (mrb_callinfo *)mrb_realloc(mrb, c->cibase, sizeof(mrb_callinfo)*size*2);
226
    c->ci = c->cibase + size;
227
    c->ciend = c->cibase + size * 2;
mimaki's avatar
mimaki committed
228
  }
229 230 231 232
  ci = ++c->ci;
  ci->eidx = eidx;
  ci->ridx = ridx;
  ci->env = 0;
233
  ci->pc = 0;
234
  ci->err = 0;
235
  ci->proc = 0;
236

237
  return ci;
mimaki's avatar
mimaki committed
238 239 240 241 242
}

static void
cipop(mrb_state *mrb)
{
243 244 245 246
  struct mrb_context *c = mrb->c;

  if (c->ci->env) {
    struct REnv *e = c->ci->env;
247
    size_t len = (size_t)MRB_ENV_STACK_LEN(e);
248
    mrb_value *p = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value)*len);
249

250
    MRB_ENV_UNSHARE_STACK(e);
251 252 253
    if (len > 0) {
      stack_copy(p, e->stack, len);
    }
254
    e->stack = p;
255
    mrb_write_barrier(mrb, (struct RBasic *)e);
256 257
  }

258
  c->ci--;
mimaki's avatar
mimaki committed
259 260 261 262 263 264 265
}

static void
ecall(mrb_state *mrb, int i)
{
  struct RProc *p;
  mrb_callinfo *ci;
266
  mrb_value *self = mrb->c->stack;
267
  struct RObject *exc;
mimaki's avatar
mimaki committed
268

269
  p = mrb->c->ensure[i];
270
  if (!p) return;
271
  if (mrb->c->ci->eidx > i)
272
    mrb->c->ci->eidx = i;
mimaki's avatar
mimaki committed
273
  ci = cipush(mrb);
274
  ci->stackent = mrb->c->stack;
mimaki's avatar
mimaki committed
275
  ci->mid = ci[-1].mid;
276
  ci->acc = CI_ACC_SKIP;
mimaki's avatar
mimaki committed
277 278 279 280
  ci->argc = 0;
  ci->proc = p;
  ci->nregs = p->body.irep->nregs;
  ci->target_class = p->target_class;
281
  mrb->c->stack = mrb->c->stack + ci[-1].nregs;
282
  exc = mrb->exc; mrb->exc = 0;
mimaki's avatar
mimaki committed
283
  mrb_run(mrb, p, *self);
284
  mrb->c->ensure[i] = NULL;
285
  if (!mrb->exc) mrb->exc = exc;
mimaki's avatar
mimaki committed
286 287
}

288 289 290 291
#ifndef MRB_FUNCALL_ARGC_MAX
#define MRB_FUNCALL_ARGC_MAX 16
#endif

292
MRB_API mrb_value
293
mrb_funcall(mrb_state *mrb, mrb_value self, const char *name, mrb_int argc, ...)
294
{
295 296 297
  mrb_value argv[MRB_FUNCALL_ARGC_MAX];
  va_list ap;
  mrb_int i;
298
  mrb_sym mid = mrb_intern_cstr(mrb, name);
299

300
  if (argc > MRB_FUNCALL_ARGC_MAX) {
cremno's avatar
cremno committed
301
    mrb_raise(mrb, E_ARGUMENT_ERROR, "Too long arguments. (limit=" MRB_STRINGIZE(MRB_FUNCALL_ARGC_MAX) ")");
302 303
  }

304 305 306
  va_start(ap, argc);
  for (i = 0; i < argc; i++) {
    argv[i] = va_arg(ap, mrb_value);
307
  }
308 309
  va_end(ap);
  return mrb_funcall_argv(mrb, self, mid, argc, argv);
310 311
}

312
MRB_API mrb_value
313
mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, const mrb_value *argv, mrb_value blk)
mimaki's avatar
mimaki committed
314 315 316
{
  mrb_value val;

317
  if (!mrb->jmp) {
take_cheeze's avatar
take_cheeze committed
318
    struct mrb_jmpbuf c_jmp;
319
    size_t nth_ci = mrb->c->ci - mrb->c->cibase;
320

take_cheeze's avatar
take_cheeze committed
321 322 323 324 325 326 327
    MRB_TRY(&c_jmp) {
      mrb->jmp = &c_jmp;
      /* recursive call */
      val = mrb_funcall_with_block(mrb, self, mid, argc, argv, blk);
      mrb->jmp = 0;
    }
    MRB_CATCH(&c_jmp) { /* error */
328
      while (nth_ci < (mrb->c->ci - mrb->c->cibase)) {
329
        mrb->c->stack = mrb->c->ci->stackent;
330 331
        cipop(mrb);
      }
332
      mrb->jmp = 0;
333
      val = mrb_obj_value(mrb->exc);
334
    }
take_cheeze's avatar
take_cheeze committed
335
    MRB_END_EXC(&c_jmp);
mimaki's avatar
mimaki committed
336 337
  }
  else {
338 339 340 341 342
    struct RProc *p;
    struct RClass *c;
    mrb_sym undef = 0;
    mrb_callinfo *ci;
    int n;
343
    ptrdiff_t voff = -1;
344

345
    if (!mrb->c->stack) {
346 347
      stack_init(mrb);
    }
348
    n = mrb->c->ci->nregs;
349
    if (argc < 0) {
350
      mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative argc for funcall (%S)", mrb_fixnum_value(argc));
351 352 353 354 355
    }
    c = mrb_class(mrb, self);
    p = mrb_method_search_vm(mrb, &c, mid);
    if (!p) {
      undef = mid;
356
      mid = mrb_intern_lit(mrb, "method_missing");
357 358 359 360 361 362
      p = mrb_method_search_vm(mrb, &c, mid);
      n++; argc++;
    }
    ci = cipush(mrb);
    ci->mid = mid;
    ci->proc = p;
363
    ci->stackent = mrb->c->stack;
364
    ci->argc = argc;
365
    ci->target_class = c;
mirichi's avatar
mirichi committed
366
    mrb->c->stack = mrb->c->stack + n;
367 368 369
    if (mrb->c->stbase <= argv && argv < mrb->c->stend) {
      voff = argv - mrb->c->stbase;
    }
370 371
    if (MRB_PROC_CFUNC_P(p)) {
      ci->nregs = argc + 2;
372
      stack_extend(mrb, ci->nregs, 0);
373 374
    }
    else {
375
      ci->nregs = p->body.irep->nregs + n;
376
      stack_extend(mrb, ci->nregs, argc+2);
377
    }
378 379 380
    if (voff >= 0) {
      argv = mrb->c->stbase + voff;
    }
381
    mrb->c->stack[0] = self;
382
    if (undef) {
383
      mrb->c->stack[1] = mrb_symbol_value(undef);
384 385 386
      if (argc > 1) {
        stack_copy(mrb->c->stack+2, argv, argc-1);
      }
387 388
    }
    else if (argc > 0) {
389
      stack_copy(mrb->c->stack+1, argv, argc);
390
    }
391
    mrb->c->stack[argc+1] = blk;
392 393 394

    if (MRB_PROC_CFUNC_P(p)) {
      int ai = mrb_gc_arena_save(mrb);
395 396

      ci->acc = CI_ACC_DIRECT;
397
      val = p->body.func(mrb, self);
398
      mrb->c->stack = mrb->c->ci->stackent;
399
      cipop(mrb);
400
      mrb_gc_arena_restore(mrb, ai);
401 402
    }
    else {
403
      ci->acc = CI_ACC_SKIP;
404 405
      val = mrb_run(mrb, p, self);
    }
mimaki's avatar
mimaki committed
406
  }
407
  mrb_gc_protect(mrb, val);
mimaki's avatar
mimaki committed
408 409 410
  return val;
}

411
MRB_API mrb_value
412
mrb_funcall_argv(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, const mrb_value *argv)
mimaki's avatar
mimaki committed
413
{
414
  return mrb_funcall_with_block(mrb, self, mid, argc, argv, mrb_nil_value());
mimaki's avatar
mimaki committed
415 416
}

417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
/* 15.3.1.3.4  */
/* 15.3.1.3.44 */
/*
 *  call-seq:
 *     obj.send(symbol [, args...])        -> obj
 *     obj.__send__(symbol [, args...])      -> obj
 *
 *  Invokes the method identified by _symbol_, passing it any
 *  arguments specified. You can use <code>__send__</code> if the name
 *  +send+ clashes with an existing method in _obj_.
 *
 *     class Klass
 *       def hello(*args)
 *         "Hello " + args.join(' ')
 *       end
 *     end
 *     k = Klass.new
 *     k.send :hello, "gentle", "readers"   #=> "Hello gentle readers"
 */
436
MRB_API mrb_value
437 438 439 440
mrb_f_send(mrb_state *mrb, mrb_value self)
{
  mrb_sym name;
  mrb_value block, *argv, *regs;
441
  mrb_int argc, i, len;
442 443 444 445 446 447 448 449
  struct RProc *p;
  struct RClass *c;
  mrb_callinfo *ci;

  mrb_get_args(mrb, "n*&", &name, &argv, &argc, &block);

  c = mrb_class(mrb, self);
  p = mrb_method_search_vm(mrb, &c, name);
450 451

  if (!p) {                     /* call method_mising */
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
    return mrb_funcall_with_block(mrb, self, name, argc, argv, block);
  }

  ci = mrb->c->ci;
  ci->mid = name;
  ci->target_class = c;
  ci->proc = p;
  regs = mrb->c->stack+1;
  /* remove first symbol from arguments */
  if (ci->argc >= 0) {
    for (i=0,len=ci->argc; i<len; i++) {
      regs[i] = regs[i+1];
    }
    ci->argc--;
  }
  else {                     /* variable length arguments */
    mrb_ary_shift(mrb, regs[0]);
  }
470 471 472 473 474

  if (MRB_PROC_CFUNC_P(p)) {
    return p->body.func(mrb, self);
  }

475 476
  ci->nregs = p->body.irep->nregs;
  ci = cipush(mrb);
477
  ci->nregs = 0;
478 479 480 481 482 483 484 485
  ci->target_class = 0;
  ci->pc = p->body.irep->iseq;
  ci->stackent = mrb->c->stack;
  ci->acc = 0;

  return self;
}

486 487 488 489 490 491
static mrb_value
eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c)
{
  struct RProc *p;
  mrb_callinfo *ci;

492 493 494
  if (mrb_nil_p(blk)) {
    mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
  }
495 496 497 498 499 500 501 502 503 504 505 506
  ci = mrb->c->ci;
  if (ci->acc == CI_ACC_DIRECT) {
    return mrb_yield_with_class(mrb, blk, 0, 0, self, c);
  }
  ci->target_class = c;
  p = mrb_proc_ptr(blk);
  ci->proc = p;
  if (MRB_PROC_CFUNC_P(p)) {
    return p->body.func(mrb, self);
  }
  ci->nregs = p->body.irep->nregs;
  ci = cipush(mrb);
507
  ci->nregs = 0;
508 509 510 511 512 513 514 515
  ci->target_class = 0;
  ci->pc = p->body.irep->iseq;
  ci->stackent = mrb->c->stack;
  ci->acc = 0;

  return self;
}

516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
/* 15.2.2.4.35 */
/*
 *  call-seq:
 *     mod.class_eval {| | block }  -> obj
 *     mod.module_eval {| | block } -> obj
 *
 *  Evaluates block in the context of _mod_. This can
 *  be used to add methods to a class. <code>module_eval</code> returns
 *  the result of evaluating its argument.
 */
mrb_value
mrb_mod_module_eval(mrb_state *mrb, mrb_value mod)
{
  mrb_value a, b;

  if (mrb_get_args(mrb, "|S&", &a, &b) == 1) {
    mrb_raise(mrb, E_NOTIMP_ERROR, "module_eval/class_eval with string not implemented");
  }
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566
  return eval_under(mrb, mod, b, mrb_class_ptr(mod));
}

/* 15.3.1.3.18 */
/*
 *  call-seq:
 *     obj.instance_eval {| | block }                       -> obj
 *
 *  Evaluates the given block,within  the context of the receiver (_obj_).
 *  In order to set the context, the variable +self+ is set to _obj_ while
 *  the code is executing, giving the code access to _obj_'s
 *  instance variables. In the version of <code>instance_eval</code>
 *  that takes a +String+, the optional second and third
 *  parameters supply a filename and starting line number that are used
 *  when reporting compilation errors.
 *
 *     class KlassWithSecret
 *       def initialize
 *         @secret = 99
 *       end
 *     end
 *     k = KlassWithSecret.new
 *     k.instance_eval { @secret }   #=> 99
 */
mrb_value
mrb_obj_instance_eval(mrb_state *mrb, mrb_value self)
{
  mrb_value a, b;
  mrb_value cv;
  struct RClass *c;

  if (mrb_get_args(mrb, "|S&", &a, &b) == 1) {
    mrb_raise(mrb, E_NOTIMP_ERROR, "instance_eval with string not implemented");
567
  }
568 569 570 571 572 573 574 575 576 577
  switch (mrb_type(self)) {
  case MRB_TT_SYMBOL:
  case MRB_TT_FIXNUM:
  case MRB_TT_FLOAT:
    c = 0;
    break;
  default:
    cv = mrb_singleton_class(mrb, self);
    c = mrb_class_ptr(cv);
    break;
578
  }
579
  return eval_under(mrb, self, b, c);
580 581
}

582
MRB_API mrb_value
583
mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv, mrb_value self, struct RClass *c)
mimaki's avatar
mimaki committed
584 585
{
  struct RProc *p;
586
  mrb_sym mid = mrb->c->ci->mid;
mimaki's avatar
mimaki committed
587
  mrb_callinfo *ci;
588
  int n = mrb->c->ci->nregs;
mimaki's avatar
mimaki committed
589 590
  mrb_value val;

591 592 593
  if (mrb_nil_p(b)) {
    mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
  }
mimaki's avatar
mimaki committed
594 595 596 597
  p = mrb_proc_ptr(b);
  ci = cipush(mrb);
  ci->mid = mid;
  ci->proc = p;
598
  ci->stackent = mrb->c->stack;
mimaki's avatar
mimaki committed
599
  ci->argc = argc;
600
  ci->target_class = c;
mirichi's avatar
mirichi committed
601 602
  ci->acc = CI_ACC_SKIP;
  mrb->c->stack = mrb->c->stack + n;
603 604
  if (MRB_PROC_CFUNC_P(p)) {
    ci->nregs = argc + 2;
605
    stack_extend(mrb, ci->nregs, 0);
606 607
  }
  else {
608
    ci->nregs = p->body.irep->nregs;
609
    stack_extend(mrb, ci->nregs, argc+2);
610
  }
mimaki's avatar
mimaki committed
611

612
  mrb->c->stack[0] = self;
mimaki's avatar
mimaki committed
613
  if (argc > 0) {
614
    stack_copy(mrb->c->stack+1, argv, argc);
mimaki's avatar
mimaki committed
615
  }
616
  mrb->c->stack[argc+1] = mrb_nil_value();
mimaki's avatar
mimaki committed
617 618 619

  if (MRB_PROC_CFUNC_P(p)) {
    val = p->body.func(mrb, self);
620
    mrb->c->stack = mrb->c->ci->stackent;
mimaki's avatar
mimaki committed
621 622 623 624 625 626 627 628
    cipop(mrb);
  }
  else {
    val = mrb_run(mrb, p, self);
  }
  return val;
}

629
MRB_API mrb_value
630
mrb_yield_argv(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv)
mimaki's avatar
mimaki committed
631
{
632 633
  struct RProc *p = mrb_proc_ptr(b);

634
  return mrb_yield_with_class(mrb, b, argc, argv, p->env->stack[0], p->target_class);
mimaki's avatar
mimaki committed
635 636
}

637
MRB_API mrb_value
638
mrb_yield(mrb_state *mrb, mrb_value b, mrb_value arg)
mimaki's avatar
mimaki committed
639
{
640 641
  struct RProc *p = mrb_proc_ptr(b);

642
  return mrb_yield_with_class(mrb, b, 1, &arg, p->env->stack[0], p->target_class);
mimaki's avatar
mimaki committed
643 644
}

645 646 647 648 649 650
typedef enum {
  LOCALJUMP_ERROR_RETURN = 0,
  LOCALJUMP_ERROR_BREAK = 1,
  LOCALJUMP_ERROR_YIELD = 2
} localjump_error_kind;

651
static void
652
localjump_error(mrb_state *mrb, localjump_error_kind kind)
mimaki's avatar
mimaki committed
653
{
654 655 656 657
  char kind_str[3][7] = { "return", "break", "yield" };
  char kind_str_len[] = { 6, 5, 5 };
  static const char lead[] = "unexpected ";
  mrb_value msg;
mimaki's avatar
mimaki committed
658 659
  mrb_value exc;

660
  msg = mrb_str_buf_new(mrb, sizeof(lead) + 7);
cremno's avatar
cremno committed
661 662
  mrb_str_cat(mrb, msg, lead, sizeof(lead) - 1);
  mrb_str_cat(mrb, msg, kind_str[kind], kind_str_len[kind]);
663
  exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg);
664
  mrb->exc = mrb_obj_ptr(exc);
mimaki's avatar
mimaki committed
665 666
}

667
static void
668
argnum_error(mrb_state *mrb, mrb_int num)
669 670
{
  mrb_value exc;
671
  mrb_value str;
672

673
  if (mrb->c->ci->mid) {
674
    str = mrb_format(mrb, "'%S': wrong number of arguments (%S for %S)",
675 676
                  mrb_sym2str(mrb, mrb->c->ci->mid),
                  mrb_fixnum_value(mrb->c->ci->argc), mrb_fixnum_value(num));
677 678
  }
  else {
679
    str = mrb_format(mrb, "wrong number of arguments (%S for %S)",
680
                  mrb_fixnum_value(mrb->c->ci->argc), mrb_fixnum_value(num));
681
  }
682
  exc = mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str);
683
  mrb->exc = mrb_obj_ptr(exc);
684 685
}

686 687
#define ERR_PC_SET(mrb, pc) mrb->c->ci->err = pc;
#define ERR_PC_CLR(mrb)     mrb->c->ci->err = 0;
688
#ifdef ENABLE_DEBUG
689
#define CODE_FETCH_HOOK(mrb, irep, pc, regs) if ((mrb)->code_fetch_hook) (mrb)->code_fetch_hook((mrb), (irep), (pc), (regs));
690
#else
691
#define CODE_FETCH_HOOK(mrb, irep, pc, regs)
692 693
#endif

694
#if defined __GNUC__ || defined __clang__ || defined __INTEL_COMPILER
mimaki's avatar
mimaki committed
695
#define DIRECT_THREADED
696 697
#endif

mimaki's avatar
mimaki committed
698 699
#ifndef DIRECT_THREADED

700
#define INIT_DISPATCH for (;;) { i = *pc; CODE_FETCH_HOOK(mrb, irep, pc, regs); switch (GET_OPCODE(i)) {
mimaki's avatar
mimaki committed
701
#define CASE(op) case op:
702
#define NEXT pc++; break
mimaki's avatar
mimaki committed
703
#define JUMP break
704
#define END_DISPATCH }}
mimaki's avatar
mimaki committed
705 706 707

#else

708
#define INIT_DISPATCH JUMP; return mrb_nil_value();
mimaki's avatar
mimaki committed
709
#define CASE(op) L_ ## op:
710 711
#define NEXT i=*++pc; CODE_FETCH_HOOK(mrb, irep, pc, regs); goto *optable[GET_OPCODE(i)]
#define JUMP i=*pc; CODE_FETCH_HOOK(mrb, irep, pc, regs); goto *optable[GET_OPCODE(i)]
mimaki's avatar
mimaki committed
712

713
#define END_DISPATCH
mimaki's avatar
mimaki committed
714 715 716 717 718

#endif

#define CALL_MAXARGS 127

719
MRB_API mrb_value
fleuria's avatar
fleuria committed
720
mrb_context_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep)
mimaki's avatar
mimaki committed
721
{
fleuria's avatar
fleuria committed
722
  /* mrb_assert(mrb_proc_cfunc_p(proc)) */
mimaki's avatar
mimaki committed
723 724
  mrb_irep *irep = proc->body.irep;
  mrb_code *pc = irep->iseq;
725
  mrb_value *pool = irep->pool;
mimaki's avatar
mimaki committed
726
  mrb_sym *syms = irep->syms;
727
  mrb_value *regs = NULL;
mimaki's avatar
mimaki committed
728
  mrb_code i;
729
  int ai = mrb_gc_arena_save(mrb);
take_cheeze's avatar
take_cheeze committed
730 731
  struct mrb_jmpbuf *prev_jmp = mrb->jmp;
  struct mrb_jmpbuf c_jmp;
mimaki's avatar
mimaki committed
732 733 734 735 736 737 738 739 740 741 742 743

#ifdef DIRECT_THREADED
  static void *optable[] = {
    &&L_OP_NOP, &&L_OP_MOVE,
    &&L_OP_LOADL, &&L_OP_LOADI, &&L_OP_LOADSYM, &&L_OP_LOADNIL,
    &&L_OP_LOADSELF, &&L_OP_LOADT, &&L_OP_LOADF,
    &&L_OP_GETGLOBAL, &&L_OP_SETGLOBAL, &&L_OP_GETSPECIAL, &&L_OP_SETSPECIAL,
    &&L_OP_GETIV, &&L_OP_SETIV, &&L_OP_GETCV, &&L_OP_SETCV,
    &&L_OP_GETCONST, &&L_OP_SETCONST, &&L_OP_GETMCNST, &&L_OP_SETMCNST,
    &&L_OP_GETUPVAR, &&L_OP_SETUPVAR,
    &&L_OP_JMP, &&L_OP_JMPIF, &&L_OP_JMPNOT,
    &&L_OP_ONERR, &&L_OP_RESCUE, &&L_OP_POPERR, &&L_OP_RAISE, &&L_OP_EPUSH, &&L_OP_EPOP,
744
    &&L_OP_SEND, &&L_OP_SENDB, &&L_OP_FSEND,
mimaki's avatar
mimaki committed
745 746 747 748 749 750 751 752 753 754 755 756 757
    &&L_OP_CALL, &&L_OP_SUPER, &&L_OP_ARGARY, &&L_OP_ENTER,
    &&L_OP_KARG, &&L_OP_KDICT, &&L_OP_RETURN, &&L_OP_TAILCALL, &&L_OP_BLKPUSH,
    &&L_OP_ADD, &&L_OP_ADDI, &&L_OP_SUB, &&L_OP_SUBI, &&L_OP_MUL, &&L_OP_DIV,
    &&L_OP_EQ, &&L_OP_LT, &&L_OP_LE, &&L_OP_GT, &&L_OP_GE,
    &&L_OP_ARRAY, &&L_OP_ARYCAT, &&L_OP_ARYPUSH, &&L_OP_AREF, &&L_OP_ASET, &&L_OP_APOST,
    &&L_OP_STRING, &&L_OP_STRCAT, &&L_OP_HASH,
    &&L_OP_LAMBDA, &&L_OP_RANGE, &&L_OP_OCLASS,
    &&L_OP_CLASS, &&L_OP_MODULE, &&L_OP_EXEC,
    &&L_OP_METHOD, &&L_OP_SCLASS, &&L_OP_TCLASS,
    &&L_OP_DEBUG, &&L_OP_STOP, &&L_OP_ERR,
  };
#endif

take_cheeze's avatar
take_cheeze committed
758 759
  mrb_bool exc_catched = FALSE;
RETRY_TRY_BLOCK:
mimaki's avatar
mimaki committed
760

take_cheeze's avatar
take_cheeze committed
761 762 763
  MRB_TRY(&c_jmp) {

  if (exc_catched) {
764
    exc_catched = FALSE;
mimaki's avatar
mimaki committed
765 766
    goto L_RAISE;
  }
take_cheeze's avatar
take_cheeze committed
767
  mrb->jmp = &c_jmp;
768
  if (!mrb->c->stack) {
mimaki's avatar
mimaki committed
769 770
    stack_init(mrb);
  }
771
  stack_extend(mrb, irep->nregs, stack_keep);
772
  mrb->c->ci->proc = proc;
773
  mrb->c->ci->nregs = irep->nregs;
774
  regs = mrb->c->stack;
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
775
  regs[0] = self;
mimaki's avatar
mimaki committed
776

777
  INIT_DISPATCH {
mimaki's avatar
mimaki committed
778 779 780 781 782 783
    CASE(OP_NOP) {
      /* do nothing */
      NEXT;
    }

    CASE(OP_MOVE) {
roco's avatar
roco committed
784
      /* A B    R(A) := R(B) */
mimaki's avatar
mimaki committed
785 786 787 788 789
      regs[GETARG_A(i)] = regs[GETARG_B(i)];
      NEXT;
    }

    CASE(OP_LOADL) {
roco's avatar
roco committed
790
      /* A Bx   R(A) := Pool(Bx) */
yui-knk's avatar
yui-knk committed
791
      regs[GETARG_A(i)] = pool[GETARG_Bx(i)];
mimaki's avatar
mimaki committed
792 793 794 795
      NEXT;
    }

    CASE(OP_LOADI) {
796
      /* A sBx  R(A) := sBx */
797
      SET_INT_VALUE(regs[GETARG_A(i)], GETARG_sBx(i));
mimaki's avatar
mimaki committed
798 799 800 801
      NEXT;
    }

    CASE(OP_LOADSYM) {
802
      /* A Bx   R(A) := Syms(Bx) */
mimaki's avatar
mimaki committed
803 804 805 806 807
      SET_SYM_VALUE(regs[GETARG_A(i)], syms[GETARG_Bx(i)]);
      NEXT;
    }

    CASE(OP_LOADSELF) {
roco's avatar
roco committed
808
      /* A      R(A) := self */
809
      regs[GETARG_A(i)] = regs[0];
mimaki's avatar
mimaki committed
810 811 812 813
      NEXT;
    }

    CASE(OP_LOADT) {
roco's avatar
roco committed
814
      /* A      R(A) := true */
815
      SET_TRUE_VALUE(regs[GETARG_A(i)]);
mimaki's avatar
mimaki committed
816 817 818 819
      NEXT;
    }

    CASE(OP_LOADF) {
roco's avatar
roco committed
820
      /* A      R(A) := false */
821
      SET_FALSE_VALUE(regs[GETARG_A(i)]);
mimaki's avatar
mimaki committed
822 823 824 825
      NEXT;
    }

    CASE(OP_GETGLOBAL) {
826
      /* A Bx   R(A) := getglobal(Syms(Bx)) */
mimaki's avatar
mimaki committed
827 828 829 830 831
      regs[GETARG_A(i)] = mrb_gv_get(mrb, syms[GETARG_Bx(i)]);
      NEXT;
    }

    CASE(OP_SETGLOBAL) {
832
      /* setglobal(Syms(Bx), R(A)) */
mimaki's avatar
mimaki committed
833 834 835 836 837
      mrb_gv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]);
      NEXT;
    }

    CASE(OP_GETSPECIAL) {
roco's avatar
roco committed
838
      /* A Bx   R(A) := Special[Bx] */
mimaki's avatar
mimaki committed
839 840 841 842 843
      regs[GETARG_A(i)] = mrb_vm_special_get(mrb, GETARG_Bx(i));
      NEXT;
    }

    CASE(OP_SETSPECIAL) {
roco's avatar
roco committed
844
      /* A Bx   Special[Bx] := R(A) */
mimaki's avatar
mimaki committed
845 846 847 848 849
      mrb_vm_special_set(mrb, GETARG_Bx(i), regs[GETARG_A(i)]);
      NEXT;
    }

    CASE(OP_GETIV) {
roco's avatar
roco committed
850
      /* A Bx   R(A) := ivget(Bx) */
mimaki's avatar
mimaki committed
851 852 853 854 855
      regs[GETARG_A(i)] = mrb_vm_iv_get(mrb, syms[GETARG_Bx(i)]);
      NEXT;
    }

    CASE(OP_SETIV) {
856
      /* ivset(Syms(Bx),R(A)) */
mimaki's avatar
mimaki committed
857 858 859 860 861
      mrb_vm_iv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]);
      NEXT;
    }

    CASE(OP_GETCV) {
862
      /* A Bx   R(A) := cvget(Syms(Bx)) */
863
      ERR_PC_SET(mrb, pc);
mimaki's avatar
mimaki committed
864
      regs[GETARG_A(i)] = mrb_vm_cv_get(mrb, syms[GETARG_Bx(i)]);
865
      ERR_PC_CLR(mrb);
mimaki's avatar
mimaki committed
866 867 868 869
      NEXT;
    }

    CASE(OP_SETCV) {
870
      /* cvset(Syms(Bx),R(A)) */
mimaki's avatar
mimaki committed
871 872 873 874 875
      mrb_vm_cv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]);
      NEXT;
    }

    CASE(OP_GETCONST) {
876
      /* A Bx    R(A) := constget(Syms(Bx)) */
877 878
      mrb_value val;

879
      ERR_PC_SET(mrb, pc);
880
      val = mrb_vm_const_get(mrb, syms[GETARG_Bx(i)]);
881
      ERR_PC_CLR(mrb);
882 883
      regs = mrb->c->stack;
      regs[GETARG_A(i)] = val;
mimaki's avatar
mimaki committed
884 885 886 887
      NEXT;
    }

    CASE(OP_SETCONST) {
888
      /* A Bx   constset(Syms(Bx),R(A)) */
mimaki's avatar
mimaki committed
889 890 891 892 893
      mrb_vm_const_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]);
      NEXT;
    }

    CASE(OP_GETMCNST) {
894
      /* A Bx   R(A) := R(A)::Syms(Bx) */
895
      mrb_value val;
mimaki's avatar
mimaki committed
896 897
      int a = GETARG_A(i);

898
      ERR_PC_SET(mrb, pc);
899
      val = mrb_const_get(mrb, regs[a], syms[GETARG_Bx(i)]);
900
      ERR_PC_CLR(mrb);
901 902
      regs = mrb->c->stack;
      regs[a] = val;
mimaki's avatar
mimaki committed
903 904 905 906
      NEXT;
    }

    CASE(OP_SETMCNST) {
907
      /* A Bx    R(A+1)::Syms(Bx) := R(A) */
mimaki's avatar
mimaki committed
908 909 910 911 912 913 914
      int a = GETARG_A(i);

      mrb_const_set(mrb, regs[a+1], syms[GETARG_Bx(i)], regs[a]);
      NEXT;
    }

    CASE(OP_GETUPVAR) {
roco's avatar
roco committed
915
      /* A B C  R(A) := uvget(B,C) */
916 917 918 919
      mrb_value *regs_a = regs + GETARG_A(i);
      int up = GETARG_C(i);

      struct REnv *e = uvenv(mrb, up);
920

921 922 923 924 925 926 927
      if (!e) {
        *regs_a = mrb_nil_value();
      }
      else {
        int idx = GETARG_B(i);
        *regs_a = e->stack[idx];
      }
mimaki's avatar
mimaki committed
928 929 930 931
      NEXT;
    }

    CASE(OP_SETUPVAR) {
roco's avatar
roco committed
932
      /* A B C  uvset(B,C,R(A)) */
933 934 935 936 937 938 939 940 941 942
      int up = GETARG_C(i);

      struct REnv *e = uvenv(mrb, up);

      if (e) {
        mrb_value *regs_a = regs + GETARG_A(i);
        int idx = GETARG_B(i);
        e->stack[idx] = *regs_a;
        mrb_write_barrier(mrb, (struct RBasic*)e);
      }
mimaki's avatar
mimaki committed
943 944 945 946
      NEXT;
    }

    CASE(OP_JMP) {
roco's avatar
roco committed
947
      /* sBx    pc+=sBx */
mimaki's avatar
mimaki committed
948 949 950 951 952
      pc += GETARG_sBx(i);
      JUMP;
    }

    CASE(OP_JMPIF) {
roco's avatar
roco committed
953
      /* A sBx  if R(A) pc+=sBx */
mimaki's avatar
mimaki committed
954
      if (mrb_test(regs[GETARG_A(i)])) {
roco's avatar
roco committed
955 956
        pc += GETARG_sBx(i);
        JUMP;
mimaki's avatar
mimaki committed
957 958 959 960 961
      }
      NEXT;
    }

    CASE(OP_JMPNOT) {
962
      /* A sBx  if !R(A) pc+=sBx */
mimaki's avatar
mimaki committed
963
      if (!mrb_test(regs[GETARG_A(i)])) {
roco's avatar
roco committed
964 965
        pc += GETARG_sBx(i);
        JUMP;
mimaki's avatar
mimaki committed
966 967 968 969 970
      }
      NEXT;
    }

    CASE(OP_ONERR) {
roco's avatar
roco committed
971
      /* sBx    pc+=sBx on exception */
972 973 974 975
      if (mrb->c->rsize <= mrb->c->ci->ridx) {
        if (mrb->c->rsize == 0) mrb->c->rsize = 16;
        else mrb->c->rsize *= 2;
        mrb->c->rescue = (mrb_code **)mrb_realloc(mrb, mrb->c->rescue, sizeof(mrb_code*) * mrb->c->rsize);
mimaki's avatar
mimaki committed
976
      }
977
      mrb->c->rescue[mrb->c->ci->ridx++] = pc + GETARG_sBx(i);
mimaki's avatar
mimaki committed
978 979 980 981
      NEXT;
    }

    CASE(OP_RESCUE) {
roco's avatar
roco committed
982
      /* A      R(A) := exc; clear(exc) */
983
      SET_OBJ_VALUE(regs[GETARG_A(i)], mrb->exc);
mimaki's avatar
mimaki committed
984 985 986 987 988
      mrb->exc = 0;
      NEXT;
    }

    CASE(OP_POPERR) {
989
      /* A      A.times{rescue_pop()} */
mimaki's avatar
mimaki committed
990 991 992
      int a = GETARG_A(i);

      while (a--) {
993
        mrb->c->ci->ridx--;
mimaki's avatar
mimaki committed
994 995 996 997 998
      }
      NEXT;
    }

    CASE(OP_RAISE) {
roco's avatar
roco committed
999
      /* A      raise(R(A)) */
1000
      mrb->exc = mrb_obj_ptr(regs[GETARG_A(i)]);
mimaki's avatar
mimaki committed
1001 1002 1003 1004
      goto L_RAISE;
    }

    CASE(OP_EPUSH) {
roco's avatar
roco committed
1005
      /* Bx     ensure_push(SEQ[Bx]) */
mimaki's avatar
mimaki committed
1006 1007
      struct RProc *p;

1008
      p = mrb_closure_new(mrb, irep->reps[GETARG_Bx(i)]);
mimaki's avatar
mimaki committed
1009
      /* push ensure_stack */
1010 1011 1012 1013
      if (mrb->c->esize <= mrb->c->ci->eidx) {
        if (mrb->c->esize == 0) mrb->c->esize = 16;
        else mrb->c->esize *= 2;
        mrb->c->ensure = (struct RProc **)mrb_realloc(mrb, mrb->c->ensure, sizeof(struct RProc*) * mrb->c->esize);
mimaki's avatar
mimaki committed
1014
      }
1015
      mrb->c->ensure[mrb->c->ci->eidx++] = p;
1016
      ARENA_RESTORE(mrb, ai);
mimaki's avatar
mimaki committed
1017 1018 1019 1020
      NEXT;
    }

    CASE(OP_EPOP) {
roco's avatar
roco committed
1021
      /* A      A.times{ensure_pop().call} */
mimaki's avatar
mimaki committed
1022
      int a = GETARG_A(i);
1023
      mrb_callinfo *ci = mrb->c->ci;
1024
      int n, eidx = ci->eidx;
mimaki's avatar
mimaki committed
1025

1026 1027
      for (n=0; n<a && eidx > ci[-1].eidx; n++) {
        ecall(mrb, --eidx);
1028
        ARENA_RESTORE(mrb, ai);
mimaki's avatar
mimaki committed
1029 1030 1031 1032
      }
      NEXT;
    }

1033
    CASE(OP_LOADNIL) {
1034
      /* A     R(A) := nil */
1035 1036 1037 1038 1039 1040
      int a = GETARG_A(i);

      SET_NIL_VALUE(regs[a]);
      NEXT;
    }

1041
    CASE(OP_SENDB) {
1042
      /* A B C  R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C),&R(A+C+1))*/
1043 1044 1045
      /* fall through */
    };

mimaki's avatar
mimaki committed
1046 1047
  L_SEND:
    CASE(OP_SEND) {
1048
      /* A B C  R(A) := call(R(A),Syms(B),R(A+1),...,R(A+C)) */
mimaki's avatar
mimaki committed
1049 1050 1051 1052 1053
      int a = GETARG_A(i);
      int n = GETARG_C(i);
      struct RProc *m;
      struct RClass *c;
      mrb_callinfo *ci;
1054
      mrb_value recv, result;
mimaki's avatar
mimaki committed
1055 1056 1057
      mrb_sym mid = syms[GETARG_B(i)];

      recv = regs[a];
1058
      if (GET_OPCODE(i) != OP_SENDB) {
skandhas's avatar
skandhas committed
1059 1060 1061 1062 1063 1064
        if (n == CALL_MAXARGS) {
          SET_NIL_VALUE(regs[a+2]);
        }
        else {
          SET_NIL_VALUE(regs[a+n+1]);
        }
1065
      }
mimaki's avatar
mimaki committed
1066 1067 1068
      c = mrb_class(mrb, recv);
      m = mrb_method_search_vm(mrb, &c, mid);
      if (!m) {
1069 1070
        mrb_value sym = mrb_symbol_value(mid);

1071
        mid = mrb_intern_lit(mrb, "method_missing");
roco's avatar
roco committed
1072 1073
        m = mrb_method_search_vm(mrb, &c, mid);
        if (n == CALL_MAXARGS) {
1074
          mrb_ary_unshift(mrb, regs[a+1], sym);
roco's avatar
roco committed
1075 1076
        }
        else {
1077
          value_move(regs+a+2, regs+a+1, ++n);
skandhas's avatar
skandhas committed
1078
          regs[a+1] = sym;
roco's avatar
roco committed
1079
        }
mimaki's avatar
mimaki committed
1080 1081 1082 1083 1084 1085
      }

      /* push callinfo */
      ci = cipush(mrb);
      ci->mid = mid;
      ci->proc = m;
1086
      ci->stackent = mrb->c->stack;
1087
      ci->target_class = c;
1088

mimaki's avatar
mimaki committed
1089
      ci->pc = pc + 1;
1090
      ci->acc = a;
mimaki's avatar
mimaki committed
1091 1092

      /* prepare stack */
1093
      mrb->c->stack += a;
mimaki's avatar
mimaki committed
1094 1095

      if (MRB_PROC_CFUNC_P(m)) {
Masamitsu MURASE's avatar
Masamitsu MURASE committed
1096
        if (n == CALL_MAXARGS) {
mirichi's avatar
mirichi committed
1097
          ci->argc = -1;
Masamitsu MURASE's avatar
Masamitsu MURASE committed
1098 1099 1100
          ci->nregs = 3;
        }
        else {
mirichi's avatar
mirichi committed
1101
          ci->argc = n;
Masamitsu MURASE's avatar
Masamitsu MURASE committed
1102 1103
          ci->nregs = n + 2;
        }
1104
        result = m->body.func(mrb, recv);
1105
        mrb->c->stack[0] = result;
1106
        mrb_gc_arena_restore(mrb, ai);
roco's avatar
roco committed
1107 1108
        if (mrb->exc) goto L_RAISE;
        /* pop stackpos */
1109
        ci = mrb->c->ci;
1110 1111
        if (!ci->target_class) { /* return from context modifying method (resume/yield) */
          if (!MRB_PROC_CFUNC_P(ci[-1].proc)) {
1112
            proc = ci[-1].proc;
1113
            irep = proc->body.irep;
1114 1115 1116
            pool = irep->pool;
            syms = irep->syms;
          }
1117
        }
1118
        regs = mrb->c->stack = ci->stackent;
1119
        pc = ci->pc;
roco's avatar
roco committed
1120
        cipop(mrb);
1121
        JUMP;
mimaki's avatar
mimaki committed
1122 1123
      }
      else {
roco's avatar
roco committed
1124
        /* setup environment for calling method */
1125
        proc = mrb->c->ci->proc = m;
roco's avatar
roco committed
1126 1127 1128 1129
        irep = m->body.irep;
        pool = irep->pool;
        syms = irep->syms;
        ci->nregs = irep->nregs;
mirichi's avatar
mirichi committed
1130 1131
        if (n == CALL_MAXARGS) {
          ci->argc = -1;
1132
          stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3);
roco's avatar
roco committed
1133 1134
        }
        else {
mirichi's avatar
mirichi committed
1135
          ci->argc = n;
1136
          stack_extend(mrb, irep->nregs,  n+2);
roco's avatar
roco committed
1137
        }
1138
        regs = mrb->c->stack;
roco's avatar
roco committed
1139 1140
        pc = irep->iseq;
        JUMP;
mimaki's avatar
mimaki committed
1141 1142 1143 1144
      }
    }

    CASE(OP_FSEND) {
1145
      /* A B C  R(A) := fcall(R(A),Syms(B),R(A+1),... ,R(A+C-1)) */
mimaki's avatar
mimaki committed
1146 1147 1148 1149
      NEXT;
    }

    CASE(OP_CALL) {
roco's avatar
roco committed
1150
      /* A      R(A) := self.call(frame.argc, frame.argv) */
mimaki's avatar
mimaki committed
1151
      mrb_callinfo *ci;
1152
      mrb_value recv = mrb->c->stack[0];
mimaki's avatar
mimaki committed
1153 1154 1155
      struct RProc *m = mrb_proc_ptr(recv);

      /* replace callinfo */
1156
      ci = mrb->c->ci;
mimaki's avatar
mimaki committed
1157 1158 1159
      ci->target_class = m->target_class;
      ci->proc = m;
      if (m->env) {
skandhas's avatar
skandhas committed
1160 1161 1162
        if (m->env->mid) {
          ci->mid = m->env->mid;
        }
roco's avatar
roco committed
1163
        if (!m->env->stack) {
1164
          m->env->stack = mrb->c->stack;
roco's avatar
roco committed
1165
        }
mimaki's avatar
mimaki committed
1166 1167 1168 1169
      }

      /* prepare stack */
      if (MRB_PROC_CFUNC_P(m)) {
skandhas's avatar
skandhas committed
1170
        recv = m->body.func(mrb, recv);
1171
        mrb_gc_arena_restore(mrb, ai);
roco's avatar
roco committed
1172 1173
        if (mrb->exc) goto L_RAISE;
        /* pop stackpos */
1174
        ci = mrb->c->ci;
1175
        regs = mrb->c->stack = ci->stackent;
skandhas's avatar
skandhas committed
1176 1177
        regs[ci->acc] = recv;
        pc = ci->pc;
roco's avatar
roco committed
1178
        cipop(mrb);
1179
        irep = mrb->c->ci->proc->body.irep;
1180 1181
        pool = irep->pool;
        syms = irep->syms;
1182
        JUMP;
mimaki's avatar
mimaki committed
1183 1184
      }
      else {
roco's avatar
roco committed
1185 1186 1187
        /* setup environment for calling method */
        proc = m;
        irep = m->body.irep;
skandhas's avatar
skandhas committed
1188
        if (!irep) {
1189
          mrb->c->stack[0] = mrb_nil_value();
skandhas's avatar
skandhas committed
1190 1191
          goto L_RETURN;
        }
roco's avatar
roco committed
1192 1193 1194 1195
        pool = irep->pool;
        syms = irep->syms;
        ci->nregs = irep->nregs;
        if (ci->argc < 0) {
1196
          stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3);
roco's avatar
roco committed
1197 1198
        }
        else {
1199
          stack_extend(mrb, irep->nregs, ci->argc+2);
roco's avatar
roco committed
1200
        }
1201
        regs = mrb->c->stack;
roco's avatar
roco committed
1202
        regs[0] = m->env->stack[0];
mirichi's avatar
mirichi committed
1203
        pc = irep->iseq;
roco's avatar
roco committed
1204
        JUMP;
mimaki's avatar
mimaki committed
1205 1206 1207 1208
      }
    }

    CASE(OP_SUPER) {
1209
      /* A C  R(A) := super(R(A+1),... ,R(A+C+1)) */
mimaki's avatar
mimaki committed
1210
      mrb_value recv;
1211
      mrb_callinfo *ci = mrb->c->ci;
mimaki's avatar
mimaki committed
1212 1213 1214 1215 1216 1217 1218
      struct RProc *m;
      struct RClass *c;
      mrb_sym mid = ci->mid;
      int a = GETARG_A(i);
      int n = GETARG_C(i);

      recv = regs[0];
1219
      c = mrb->c->ci->target_class->super;
mimaki's avatar
mimaki committed
1220 1221
      m = mrb_method_search_vm(mrb, &c, mid);
      if (!m) {
1222
        mid = mrb_intern_lit(mrb, "method_missing");
roco's avatar
roco committed
1223 1224 1225 1226 1227
        m = mrb_method_search_vm(mrb, &c, mid);
        if (n == CALL_MAXARGS) {
          mrb_ary_unshift(mrb, regs[a+1], mrb_symbol_value(ci->mid));
        }
        else {
1228
          value_move(regs+a+2, regs+a+1, ++n);
skandhas's avatar
skandhas committed
1229
          SET_SYM_VALUE(regs[a+1], ci->mid);
roco's avatar
roco committed
1230
        }
mimaki's avatar
mimaki committed
1231 1232 1233 1234 1235 1236
      }

      /* push callinfo */
      ci = cipush(mrb);
      ci->mid = mid;
      ci->proc = m;
1237
      ci->stackent = mrb->c->stack;
1238 1239 1240 1241 1242 1243
      if (n == CALL_MAXARGS) {
        ci->argc = -1;
      }
      else {
        ci->argc = n;
      }
1244
      ci->target_class = c;
mimaki's avatar
mimaki committed
1245 1246 1247
      ci->pc = pc + 1;

      /* prepare stack */
1248 1249
      mrb->c->stack += a;
      mrb->c->stack[0] = recv;
mimaki's avatar
mimaki committed
1250 1251

      if (MRB_PROC_CFUNC_P(m)) {
1252 1253 1254 1255 1256 1257
        if (n == CALL_MAXARGS) {
          ci->nregs = 3;
        }
        else {
          ci->nregs = n + 2;
        }
1258
        mrb->c->stack[0] = m->body.func(mrb, recv);
1259
        mrb_gc_arena_restore(mrb, ai);
roco's avatar
roco committed
1260 1261
        if (mrb->exc) goto L_RAISE;
        /* pop stackpos */
1262
        regs = mrb->c->stack = mrb->c->ci->stackent;
roco's avatar
roco committed
1263 1264
        cipop(mrb);
        NEXT;
mimaki's avatar
mimaki committed
1265 1266
      }
      else {
roco's avatar
roco committed
1267 1268 1269 1270 1271 1272 1273 1274 1275
        /* fill callinfo */
        ci->acc = a;

        /* setup environment for calling method */
        ci->proc = m;
        irep = m->body.irep;
        pool = irep->pool;
        syms = irep->syms;
        ci->nregs = irep->nregs;
1276
        if (n == CALL_MAXARGS) {
1277
          stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3);
roco's avatar
roco committed
1278 1279
        }
        else {
1280
          stack_extend(mrb, irep->nregs, ci->argc+2);
roco's avatar
roco committed
1281
        }
1282
        regs = mrb->c->stack;
roco's avatar
roco committed
1283 1284
        pc = irep->iseq;
        JUMP;
mimaki's avatar
mimaki committed
1285 1286 1287 1288
      }
    }

    CASE(OP_ARGARY) {
roco's avatar
roco committed
1289
      /* A Bx   R(A) := argument array (16=6:1:5:4) */
mimaki's avatar
mimaki committed
1290 1291 1292 1293 1294 1295 1296 1297 1298 1299
      int a = GETARG_A(i);
      int bx = GETARG_Bx(i);
      int m1 = (bx>>10)&0x3f;
      int r  = (bx>>9)&0x1;
      int m2 = (bx>>4)&0x1f;
      int lv = (bx>>0)&0xf;
      mrb_value *stack;

      if (lv == 0) stack = regs + 1;
      else {
roco's avatar
roco committed
1300
        struct REnv *e = uvenv(mrb, lv-1);
1301 1302
        if (!e) {
          mrb_value exc;
cubicdaiya's avatar
cubicdaiya committed
1303
          exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method");
1304
          mrb->exc = mrb_obj_ptr(exc);
1305 1306
          goto L_RAISE;
        }
roco's avatar
roco committed
1307
        stack = e->stack + 1;
mimaki's avatar
mimaki committed
1308 1309
      }
      if (r == 0) {
1310
        regs[a] = mrb_ary_new_from_values(mrb, m1+m2, stack);
mimaki's avatar
mimaki committed
1311 1312
      }
      else {
1313
        mrb_value *pp = NULL;
roco's avatar
roco committed
1314 1315 1316
        struct RArray *rest;
        int len = 0;

1317
        if (mrb_array_p(stack[m1])) {
roco's avatar
roco committed
1318 1319
          struct RArray *ary = mrb_ary_ptr(stack[m1]);

1320
          pp = ary->ptr;
roco's avatar
roco committed
1321 1322 1323 1324
          len = ary->len;
        }
        regs[a] = mrb_ary_new_capa(mrb, m1+len+m2);
        rest = mrb_ary_ptr(regs[a]);
1325 1326 1327
        if (m1 > 0) {
          stack_copy(rest->ptr, stack, m1);
        }
roco's avatar
roco committed
1328
        if (len > 0) {
1329
          stack_copy(rest->ptr+m1, pp, len);
roco's avatar
roco committed
1330 1331
        }
        if (m2 > 0) {
1332
          stack_copy(rest->ptr+m1+len, stack+m1+1, m2);
roco's avatar
roco committed
1333 1334
        }
        rest->len = m1+len+m2;
mimaki's avatar
mimaki committed
1335 1336
      }
      regs[a+1] = stack[m1+r+m2];
1337
      ARENA_RESTORE(mrb, ai);
mimaki's avatar
mimaki committed
1338 1339 1340 1341
      NEXT;
    }

    CASE(OP_ENTER) {
1342
      /* Ax             arg setup according to flags (23=5:5:1:5:5:1:1) */
mimaki's avatar
mimaki committed
1343
      /* number of optional arguments times OP_JMP should follow */
1344
      mrb_aspec ax = GETARG_Ax(i);
1345 1346 1347 1348
      int m1 = MRB_ASPEC_REQ(ax);
      int o  = MRB_ASPEC_OPT(ax);
      int r  = MRB_ASPEC_REST(ax);
      int m2 = MRB_ASPEC_POST(ax);
1349
      /* unused
1350 1351 1352
      int k  = MRB_ASPEC_KEY(ax);
      int kd = MRB_ASPEC_KDICT(ax);
      int b  = MRB_ASPEC_BLOCK(ax);
1353
      */
1354
      int argc = mrb->c->ci->argc;
mimaki's avatar
mimaki committed
1355
      mrb_value *argv = regs+1;
mirichi's avatar
mirichi committed
1356
      mrb_value *argv0 = argv;
mimaki's avatar
mimaki committed
1357
      int len = m1 + o + r + m2;
1358
      mrb_value *blk = &argv[argc < 0 ? 1 : argc];
mimaki's avatar
mimaki committed
1359

1360 1361 1362
      if (!mrb_nil_p(*blk) && mrb_type(*blk) != MRB_TT_PROC) {
        *blk = mrb_convert_type(mrb, *blk, MRB_TT_PROC, "Proc", "to_proc");
      }
mimaki's avatar
mimaki committed
1363
      if (argc < 0) {
roco's avatar
roco committed
1364
        struct RArray *ary = mrb_ary_ptr(regs[1]);
1365
        argv = ary->ptr;
roco's avatar
roco committed
1366
        argc = ary->len;
skandhas's avatar
skandhas committed
1367
        mrb_gc_protect(mrb, regs[1]);
mimaki's avatar
mimaki committed
1368
      }
1369
      if (mrb->c->ci->proc && MRB_PROC_STRICT_P(mrb->c->ci->proc)) {
roco's avatar
roco committed
1370 1371
        if (argc >= 0) {
          if (argc < m1 + m2 || (r == 0 && argc > len)) {
skandhas's avatar
skandhas committed
1372 1373
            argnum_error(mrb, m1+m2);
            goto L_RAISE;
roco's avatar
roco committed
1374 1375
          }
        }
mimaki's avatar
mimaki committed
1376
      }
1377
      else if (len > 1 && argc == 1 && mrb_array_p(argv[0])) {
1378
        mrb_gc_protect(mrb, argv[0]);
roco's avatar
roco committed
1379
        argc = mrb_ary_ptr(argv[0])->len;
1380
        argv = mrb_ary_ptr(argv[0])->ptr;
mimaki's avatar
mimaki committed
1381
      }
1382
      mrb->c->ci->argc = len;
mimaki's avatar
mimaki committed
1383
      if (argc < len) {
ksss's avatar
ksss committed
1384 1385 1386 1387 1388 1389 1390
        int mlen = m2;
        if (argc < m1+m2) {
          if (m1 < argc)
            mlen = argc - m1;
          else
            mlen = 0;
        }
1391
        regs[len+1] = *blk; /* move block */
1392
        SET_NIL_VALUE(regs[argc+1]);
mirichi's avatar
mirichi committed
1393
        if (argv0 != argv) {
ksss's avatar
ksss committed
1394
          value_move(&regs[1], argv, argc-mlen); /* m1 + o */
mirichi's avatar
mirichi committed
1395
        }
ksss's avatar
ksss committed
1396
        if (mlen) {
1397
          value_move(&regs[len-m2+1], &argv[argc-mlen], mlen);
mirichi's avatar
mirichi committed
1398
        }
1399
        if (r) {
roco's avatar
roco committed
1400 1401
          regs[m1+o+1] = mrb_ary_new_capa(mrb, 0);
        }
1402
        if (o == 0 || argc < m1+m2) pc++;
skandhas's avatar
skandhas committed
1403 1404
        else
          pc += argc - m1 - m2 + 1;
mimaki's avatar
mimaki committed
1405 1406
      }
      else {
ksss's avatar
ksss committed
1407
        int rnum = 0;
mirichi's avatar
mirichi committed
1408
        if (argv0 != argv) {
1409
          regs[len+1] = *blk; /* move block */
1410
          value_move(&regs[1], argv, m1+o);
mirichi's avatar
mirichi committed
1411
        }
1412
        if (r) {
ksss's avatar
ksss committed
1413 1414
          rnum = argc-m1-o-m2;
          regs[m1+o+1] = mrb_ary_new_from_values(mrb, rnum, argv+m1+o);
roco's avatar
roco committed
1415
        }
mirichi's avatar
mirichi committed
1416
        if (m2) {
1417
          if (argc-m2 > m1) {
ksss's avatar
ksss committed
1418
            value_move(&regs[m1+o+r+1], &argv[m1+o+rnum], m2);
1419
          }
mirichi's avatar
mirichi committed
1420
        }
1421 1422 1423
        if (argv0 == argv) {
          regs[len+1] = *blk; /* move block */
        }
roco's avatar
roco committed
1424
        pc += o + 1;
mimaki's avatar
mimaki committed
1425 1426 1427 1428 1429
      }
      JUMP;
    }

    CASE(OP_KARG) {
1430
      /* A B C          R(A) := kdict[Syms(B)]; if C kdict.rm(Syms(B)) */
mimaki's avatar
mimaki committed
1431 1432 1433 1434 1435 1436
      /* if C == 2; raise unless kdict.empty? */
      /* OP_JMP should follow to skip init code */
      NEXT;
    }

    CASE(OP_KDICT) {
roco's avatar
roco committed
1437
      /* A C            R(A) := kdict */
mimaki's avatar
mimaki committed
1438 1439 1440
      NEXT;
    }

1441 1442 1443
    L_RETURN:
      i = MKOP_AB(OP_RETURN, GETARG_A(i), OP_R_NORMAL);
      /* fall through */
mimaki's avatar
mimaki committed
1444
    CASE(OP_RETURN) {
1445
      /* A B     return R(A) (B=normal,in-block return/break) */
mimaki's avatar
mimaki committed
1446
      if (mrb->exc) {
roco's avatar
roco committed
1447
        mrb_callinfo *ci;
1448
        int eidx;
mimaki's avatar
mimaki committed
1449 1450

      L_RAISE:
1451
        ci = mrb->c->ci;
1452 1453
        mrb_obj_iv_ifnone(mrb, mrb->exc, mrb_intern_lit(mrb, "lastpc"), mrb_cptr_value(mrb, pc));
        mrb_obj_iv_ifnone(mrb, mrb->exc, mrb_intern_lit(mrb, "ciidx"), mrb_fixnum_value(ci - mrb->c->cibase));
skandhas's avatar
skandhas committed
1454
        eidx = ci->eidx;
1455
        if (ci == mrb->c->cibase) {
skandhas's avatar
skandhas committed
1456 1457 1458
          if (ci->ridx == 0) goto L_STOP;
          goto L_RESCUE;
        }
1459 1460 1461
        while (eidx > ci[-1].eidx) {
          ecall(mrb, --eidx);
        }
roco's avatar
roco committed
1462 1463
        while (ci[0].ridx == ci[-1].ridx) {
          cipop(mrb);
1464
          ci = mrb->c->ci;
1465
          mrb->c->stack = ci[1].stackent;
1466
          if (ci[1].acc == CI_ACC_SKIP && prev_jmp) {
skandhas's avatar
skandhas committed
1467
            mrb->jmp = prev_jmp;
take_cheeze's avatar
take_cheeze committed
1468
            MRB_THROW(prev_jmp);
skandhas's avatar
skandhas committed
1469
          }
1470 1471 1472 1473
          if (ci > mrb->c->cibase) {
            while (eidx > ci[-1].eidx) {
              ecall(mrb, --eidx);
            }
skandhas's avatar
skandhas committed
1474
          }
1475
          else if (ci == mrb->c->cibase) {
1476
            if (ci->ridx == 0) {
1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487
              if (mrb->c == mrb->root_c) {
                regs = mrb->c->stack = mrb->c->stbase;
                goto L_STOP;
              }
              else {
                struct mrb_context *c = mrb->c;

                mrb->c = c->prev;
                c->prev = NULL;
                goto L_RAISE;
              }
skandhas's avatar
skandhas committed
1488
            }
roco's avatar
roco committed
1489 1490 1491
            break;
          }
        }
1492
      L_RESCUE:
sasaki takeru's avatar
sasaki takeru committed
1493
        if (ci->ridx == 0) goto L_STOP;
1494 1495
        proc = ci->proc;
        irep = proc->body.irep;
roco's avatar
roco committed
1496 1497
        pool = irep->pool;
        syms = irep->syms;
1498
        regs = mrb->c->stack = ci[1].stackent;
1499
        pc = mrb->c->rescue[--ci->ridx];
mimaki's avatar
mimaki committed
1500 1501
      }
      else {
1502 1503
        mrb_callinfo *ci = mrb->c->ci;
        int acc, eidx = mrb->c->ci->eidx;
roco's avatar
roco committed
1504 1505 1506
        mrb_value v = regs[GETARG_A(i)];

        switch (GETARG_B(i)) {
1507
        case OP_R_RETURN:
1508
          /* Fall through to OP_R_NORMAL otherwise */
1509 1510 1511
          if (proc->env && !MRB_PROC_STRICT_P(proc)) {
            struct REnv *e = top_env(mrb, proc);

1512
            if (!MRB_ENV_STACK_SHARED_P(e)) {
1513
              localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
1514 1515
              goto L_RAISE;
            }
1516 1517
            ci = mrb->c->cibase + e->cioff;
            if (ci == mrb->c->cibase) {
1518
              localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
1519
              goto L_RAISE;
skandhas's avatar
skandhas committed
1520
            }
1521
            mrb->c->stack = mrb->c->ci->stackent;
1522
            mrb->c->ci = ci;
1523 1524
            break;
          }
roco's avatar
roco committed
1525
        case OP_R_NORMAL:
1526 1527 1528 1529 1530
          if (ci == mrb->c->cibase) {
            if (!mrb->c->prev) { /* toplevel return */
              localjump_error(mrb, LOCALJUMP_ERROR_RETURN);
              goto L_RAISE;
            }
1531
            if (mrb->c->prev->ci == mrb->c->prev->cibase) {
take_cheeze's avatar
take_cheeze committed
1532
              mrb_value exc = mrb_exc_new_str_lit(mrb, E_FIBER_ERROR, "double resume");
1533 1534 1535 1536 1537 1538
              mrb->exc = mrb_obj_ptr(exc);
              goto L_RAISE;
            }
            /* automatic yield at the end */
            mrb->c->status = MRB_FIBER_TERMINATED;
            mrb->c = mrb->c->prev;
1539
            mrb->c->status = MRB_FIBER_RUNNING;
1540
          }
1541
          ci = mrb->c->ci;
roco's avatar
roco committed
1542 1543
          break;
        case OP_R_BREAK:
1544
          if (!proc->env || !MRB_ENV_STACK_SHARED_P(proc->env)) {
1545
            localjump_error(mrb, LOCALJUMP_ERROR_BREAK);
roco's avatar
roco committed
1546 1547
            goto L_RAISE;
          }
1548 1549 1550 1551 1552 1553 1554
          /* break from fiber block */
          if (mrb->c->ci == mrb->c->cibase && mrb->c->ci->pc) {
            struct mrb_context *c = mrb->c;

            mrb->c = c->prev;
            c->prev = NULL;
          }
1555
          ci = mrb->c->ci;
1556
          mrb->c->stack = ci->stackent;
1557 1558 1559 1560 1561 1562 1563 1564
          mrb->c->ci = mrb->c->cibase + proc->env->cioff + 1;
          while (ci > mrb->c->ci) {
            if (ci[-1].acc == CI_ACC_SKIP) {
              mrb->c->ci = ci;
              break;
            }
            ci--;
          }
roco's avatar
roco committed
1565 1566 1567 1568 1569
          break;
        default:
          /* cannot happen */
          break;
        }
1570
        while (eidx > mrb->c->ci[-1].eidx) {
1571 1572
          ecall(mrb, --eidx);
        }
roco's avatar
roco committed
1573 1574 1575
        cipop(mrb);
        acc = ci->acc;
        pc = ci->pc;
1576
        regs = mrb->c->stack = ci->stackent;
1577
        if (acc == CI_ACC_SKIP) {
roco's avatar
roco committed
1578 1579 1580 1581
          mrb->jmp = prev_jmp;
          return v;
        }
        DEBUG(printf("from :%s\n", mrb_sym2name(mrb, ci->mid)));
1582
        proc = mrb->c->ci->proc;
roco's avatar
roco committed
1583 1584 1585 1586 1587
        irep = proc->body.irep;
        pool = irep->pool;
        syms = irep->syms;

        regs[acc] = v;
mimaki's avatar
mimaki committed
1588 1589 1590 1591 1592
      }
      JUMP;
    }

    CASE(OP_TAILCALL) {
1593
      /* A B C  return call(R(A),Syms(B),R(A+1),... ,R(A+C+1)) */
mimaki's avatar
mimaki committed
1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605
      int a = GETARG_A(i);
      int n = GETARG_C(i);
      struct RProc *m;
      struct RClass *c;
      mrb_callinfo *ci;
      mrb_value recv;
      mrb_sym mid = syms[GETARG_B(i)];

      recv = regs[a];
      c = mrb_class(mrb, recv);
      m = mrb_method_search_vm(mrb, &c, mid);
      if (!m) {
roco's avatar
roco committed
1606 1607
        mrb_value sym = mrb_symbol_value(mid);

1608
        mid = mrb_intern_lit(mrb, "method_missing");
roco's avatar
roco committed
1609 1610 1611 1612 1613
        m = mrb_method_search_vm(mrb, &c, mid);
        if (n == CALL_MAXARGS) {
          mrb_ary_unshift(mrb, regs[a+1], sym);
        }
        else {
1614
          value_move(regs+a+2, regs+a+1, ++n);
roco's avatar
roco committed
1615 1616
          regs[a+1] = sym;
        }
mimaki's avatar
mimaki committed
1617 1618 1619
      }

      /* replace callinfo */
1620
      ci = mrb->c->ci;
mimaki's avatar
mimaki committed
1621
      ci->mid = mid;
1622
      ci->target_class = c;
1623 1624 1625 1626 1627 1628
      if (n == CALL_MAXARGS) {
        ci->argc = -1;
      }
      else {
        ci->argc = n;
      }
mimaki's avatar
mimaki committed
1629 1630

      /* move stack */
1631
      value_move(mrb->c->stack, &regs[a], ci->argc+1);
mimaki's avatar
mimaki committed
1632 1633

      if (MRB_PROC_CFUNC_P(m)) {
1634
        mrb->c->stack[0] = m->body.func(mrb, recv);
1635
        mrb_gc_arena_restore(mrb, ai);
roco's avatar
roco committed
1636
        goto L_RETURN;
mimaki's avatar
mimaki committed
1637 1638
      }
      else {
roco's avatar
roco committed
1639 1640 1641 1642 1643
        /* setup environment for calling method */
        irep = m->body.irep;
        pool = irep->pool;
        syms = irep->syms;
        if (ci->argc < 0) {
1644
          stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3);
roco's avatar
roco committed
1645 1646
        }
        else {
1647
          stack_extend(mrb, irep->nregs, ci->argc+2);
roco's avatar
roco committed
1648
        }
1649
        regs = mrb->c->stack;
roco's avatar
roco committed
1650
        pc = irep->iseq;
mimaki's avatar
mimaki committed
1651 1652 1653 1654 1655
      }
      JUMP;
    }

    CASE(OP_BLKPUSH) {
roco's avatar
roco committed
1656
      /* A Bx   R(A) := block (16=6:1:5:4) */
mimaki's avatar
mimaki committed
1657 1658 1659 1660 1661 1662 1663 1664 1665 1666
      int a = GETARG_A(i);
      int bx = GETARG_Bx(i);
      int m1 = (bx>>10)&0x3f;
      int r  = (bx>>9)&0x1;
      int m2 = (bx>>4)&0x1f;
      int lv = (bx>>0)&0xf;
      mrb_value *stack;

      if (lv == 0) stack = regs + 1;
      else {
roco's avatar
roco committed
1667
        struct REnv *e = uvenv(mrb, lv-1);
skandhas's avatar
skandhas committed
1668
        if (!e) {
1669
          localjump_error(mrb, LOCALJUMP_ERROR_YIELD);
skandhas's avatar
skandhas committed
1670 1671
          goto L_RAISE;
        }
roco's avatar
roco committed
1672
        stack = e->stack + 1;
mimaki's avatar
mimaki committed
1673 1674 1675 1676 1677
      }
      regs[a] = stack[m1+r+m2];
      NEXT;
    }

1678
#define TYPES2(a,b) ((((uint16_t)(a))<<8)|(((uint16_t)(b))&0xff))
mimaki's avatar
mimaki committed
1679
#define OP_MATH_BODY(op,v1,v2) do {\
1680
  v1(regs[a]) = v1(regs[a]) op v2(regs[a+1]);\
mimaki's avatar
mimaki committed
1681 1682 1683
} while(0)

    CASE(OP_ADD) {
roco's avatar
roco committed
1684
      /* A B C  R(A) := R(A)+R(A+1) (Syms[B]=:+,C=1)*/
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
1685 1686 1687 1688 1689
      int a = GETARG_A(i);

      /* need to check if op is overridden */
      switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {
      case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):
skandhas's avatar
skandhas committed
1690 1691
        {
          mrb_int x, y, z;
1692
          mrb_value *regs_a = regs + a;
skandhas's avatar
skandhas committed
1693

1694 1695
          x = mrb_fixnum(regs_a[0]);
          y = mrb_fixnum(regs_a[1]);
1696
          if (mrb_int_add_overflow(x, y, &z)) {
1697
            SET_FLOAT_VALUE(mrb, regs_a[0], (mrb_float)x + (mrb_float)y);
1698
            break;
skandhas's avatar
skandhas committed
1699
          }
1700
          SET_INT_VALUE(regs[a], z);
skandhas's avatar
skandhas committed
1701 1702
        }
        break;
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
1703
      case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):
skandhas's avatar
skandhas committed
1704 1705 1706
        {
          mrb_int x = mrb_fixnum(regs[a]);
          mrb_float y = mrb_float(regs[a+1]);
1707
          SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x + y);
skandhas's avatar
skandhas committed
1708 1709
        }
        break;
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
1710
      case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):
1711 1712 1713 1714
#ifdef MRB_WORD_BOXING
        {
          mrb_float x = mrb_float(regs[a]);
          mrb_int y = mrb_fixnum(regs[a+1]);
1715
          SET_FLOAT_VALUE(mrb, regs[a], x + y);
1716 1717
        }
#else
1718
        OP_MATH_BODY(+,mrb_float,mrb_fixnum);
1719
#endif
skandhas's avatar
skandhas committed
1720
        break;
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
1721
      case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):
1722 1723 1724 1725
#ifdef MRB_WORD_BOXING
        {
          mrb_float x = mrb_float(regs[a]);
          mrb_float y = mrb_float(regs[a+1]);
1726
          SET_FLOAT_VALUE(mrb, regs[a], x + y);
1727 1728
        }
#else
1729
        OP_MATH_BODY(+,mrb_float,mrb_float);
1730
#endif
skandhas's avatar
skandhas committed
1731
        break;
mimaki's avatar
mimaki committed
1732
      case TYPES2(MRB_TT_STRING,MRB_TT_STRING):
skandhas's avatar
skandhas committed
1733 1734
        regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]);
        break;
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
1735
      default:
skandhas's avatar
skandhas committed
1736
        goto L_SEND;
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
1737
      }
1738
      ARENA_RESTORE(mrb, ai);
mimaki's avatar
mimaki committed
1739 1740 1741 1742
      NEXT;
    }

    CASE(OP_SUB) {
roco's avatar
roco committed
1743
      /* A B C  R(A) := R(A)-R(A+1) (Syms[B]=:-,C=1)*/
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
1744 1745 1746 1747 1748
      int a = GETARG_A(i);

      /* need to check if op is overridden */
      switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {
      case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):
skandhas's avatar
skandhas committed
1749 1750 1751 1752 1753
        {
          mrb_int x, y, z;

          x = mrb_fixnum(regs[a]);
          y = mrb_fixnum(regs[a+1]);
1754
          if (mrb_int_sub_overflow(x, y, &z)) {
1755
            SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - (mrb_float)y);
skandhas's avatar
skandhas committed
1756 1757
            break;
          }
1758
          SET_INT_VALUE(regs[a], z);
skandhas's avatar
skandhas committed
1759 1760
        }
        break;
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
1761
      case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):
skandhas's avatar
skandhas committed
1762 1763 1764
        {
          mrb_int x = mrb_fixnum(regs[a]);
          mrb_float y = mrb_float(regs[a+1]);
1765
          SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x - y);
skandhas's avatar
skandhas committed
1766 1767
        }
        break;
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
1768
      case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):
1769 1770 1771 1772
#ifdef MRB_WORD_BOXING
        {
          mrb_float x = mrb_float(regs[a]);
          mrb_int y = mrb_fixnum(regs[a+1]);
1773
          SET_FLOAT_VALUE(mrb, regs[a], x - y);
1774 1775
        }
#else
1776
        OP_MATH_BODY(-,mrb_float,mrb_fixnum);
1777
#endif
skandhas's avatar
skandhas committed
1778
        break;
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
1779
      case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):
1780 1781 1782 1783
#ifdef MRB_WORD_BOXING
        {
          mrb_float x = mrb_float(regs[a]);
          mrb_float y = mrb_float(regs[a+1]);
1784
          SET_FLOAT_VALUE(mrb, regs[a], x - y);
1785 1786
        }
#else
1787
        OP_MATH_BODY(-,mrb_float,mrb_float);
1788
#endif
skandhas's avatar
skandhas committed
1789
        break;
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
1790
      default:
skandhas's avatar
skandhas committed
1791
        goto L_SEND;
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
1792
      }
mimaki's avatar
mimaki committed
1793 1794 1795 1796
      NEXT;
    }

    CASE(OP_MUL) {
roco's avatar
roco committed
1797
      /* A B C  R(A) := R(A)*R(A+1) (Syms[B]=:*,C=1)*/
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
1798 1799 1800 1801 1802
      int a = GETARG_A(i);

      /* need to check if op is overridden */
      switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {
      case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):
skandhas's avatar
skandhas committed
1803
        {
1804
          mrb_value z;
skandhas's avatar
skandhas committed
1805

1806 1807 1808 1809 1810
          z = mrb_fixnum_mul(mrb, regs[a], regs[a+1]);

          switch (mrb_type(z)) {
          case MRB_TT_FIXNUM:
            {
1811
              SET_INT_VALUE(regs[a], mrb_fixnum(z));
1812 1813 1814 1815
            }
            break;
          case MRB_TT_FLOAT:
            {
1816
              SET_FLOAT_VALUE(mrb, regs[a], mrb_float(z));
1817 1818 1819 1820 1821
            }
            break;
          default:
            /* cannot happen */
            break;
skandhas's avatar
skandhas committed
1822 1823 1824
          }
        }
        break;
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
1825
      case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):
skandhas's avatar
skandhas committed
1826 1827 1828
        {
          mrb_int x = mrb_fixnum(regs[a]);
          mrb_float y = mrb_float(regs[a+1]);
1829
          SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x * y);
skandhas's avatar
skandhas committed
1830 1831
        }
        break;
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
1832
      case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):
1833 1834 1835 1836
#ifdef MRB_WORD_BOXING
        {
          mrb_float x = mrb_float(regs[a]);
          mrb_int y = mrb_fixnum(regs[a+1]);
1837
          SET_FLOAT_VALUE(mrb, regs[a], x * y);
1838 1839
        }
#else
1840
        OP_MATH_BODY(*,mrb_float,mrb_fixnum);
1841
#endif
skandhas's avatar
skandhas committed
1842
        break;
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
1843
      case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):
1844 1845 1846 1847
#ifdef MRB_WORD_BOXING
        {
          mrb_float x = mrb_float(regs[a]);
          mrb_float y = mrb_float(regs[a+1]);
1848
          SET_FLOAT_VALUE(mrb, regs[a], x * y);
1849 1850
        }
#else
1851
        OP_MATH_BODY(*,mrb_float,mrb_float);
1852
#endif
skandhas's avatar
skandhas committed
1853
        break;
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
1854
      default:
skandhas's avatar
skandhas committed
1855
        goto L_SEND;
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
1856
      }
mimaki's avatar
mimaki committed
1857 1858 1859 1860
      NEXT;
    }

    CASE(OP_DIV) {
roco's avatar
roco committed
1861
      /* A B C  R(A) := R(A)/R(A+1) (Syms[B]=:/,C=1)*/
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
1862 1863 1864 1865 1866
      int a = GETARG_A(i);

      /* need to check if op is overridden */
      switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {
      case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):
skandhas's avatar
skandhas committed
1867 1868 1869
        {
          mrb_int x = mrb_fixnum(regs[a]);
          mrb_int y = mrb_fixnum(regs[a+1]);
1870
          SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x / (mrb_float)y);
skandhas's avatar
skandhas committed
1871 1872
        }
        break;
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
1873
      case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):
skandhas's avatar
skandhas committed
1874 1875 1876
        {
          mrb_int x = mrb_fixnum(regs[a]);
          mrb_float y = mrb_float(regs[a+1]);
1877
          SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x / y);
skandhas's avatar
skandhas committed
1878 1879
        }
        break;
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
1880
      case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):
1881 1882 1883 1884
#ifdef MRB_WORD_BOXING
        {
          mrb_float x = mrb_float(regs[a]);
          mrb_int y = mrb_fixnum(regs[a+1]);
1885
          SET_FLOAT_VALUE(mrb, regs[a], x / y);
1886 1887
        }
#else
1888
        OP_MATH_BODY(/,mrb_float,mrb_fixnum);
1889
#endif
skandhas's avatar
skandhas committed
1890
        break;
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
1891
      case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):
1892 1893 1894 1895
#ifdef MRB_WORD_BOXING
        {
          mrb_float x = mrb_float(regs[a]);
          mrb_float y = mrb_float(regs[a+1]);
1896
          SET_FLOAT_VALUE(mrb, regs[a], x / y);
1897 1898
        }
#else
1899
        OP_MATH_BODY(/,mrb_float,mrb_float);
1900
#endif
skandhas's avatar
skandhas committed
1901
        break;
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
1902
      default:
skandhas's avatar
skandhas committed
1903
        goto L_SEND;
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
1904
      }
1905
#ifdef MRB_NAN_BOXING
1906 1907
      if (isnan(mrb_float(regs[a]))) {
        regs[a] = mrb_float_value(mrb, mrb_float(regs[a]));
1908 1909
      }
#endif
mimaki's avatar
mimaki committed
1910 1911 1912 1913
      NEXT;
    }

    CASE(OP_ADDI) {
roco's avatar
roco committed
1914
      /* A B C  R(A) := R(A)+C (Syms[B]=:+)*/
mimaki's avatar
mimaki committed
1915 1916 1917 1918 1919
      int a = GETARG_A(i);

      /* need to check if + is overridden */
      switch (mrb_type(regs[a])) {
      case MRB_TT_FIXNUM:
skandhas's avatar
skandhas committed
1920
        {
1921
          mrb_int x = mrb_fixnum(regs[a]);
skandhas's avatar
skandhas committed
1922
          mrb_int y = GETARG_C(i);
1923
          mrb_int z;
skandhas's avatar
skandhas committed
1924

1925
          if (mrb_int_add_overflow(x, y, &z)) {
1926
            SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x + (mrb_float)y);
skandhas's avatar
skandhas committed
1927 1928
            break;
          }
1929
          SET_INT_VALUE(regs[a], z);
skandhas's avatar
skandhas committed
1930
        }
roco's avatar
roco committed
1931
        break;
mimaki's avatar
mimaki committed
1932
      case MRB_TT_FLOAT:
1933 1934 1935
#ifdef MRB_WORD_BOXING
        {
          mrb_float x = mrb_float(regs[a]);
1936
          SET_FLOAT_VALUE(mrb, regs[a], x + GETARG_C(i));
1937 1938
        }
#else
1939
        mrb_float(regs[a]) += GETARG_C(i);
1940
#endif
roco's avatar
roco committed
1941
        break;
mimaki's avatar
mimaki committed
1942
      default:
1943
        SET_INT_VALUE(regs[a+1], GETARG_C(i));
roco's avatar
roco committed
1944 1945
        i = MKOP_ABC(OP_SEND, a, GETARG_B(i), 1);
        goto L_SEND;
mimaki's avatar
mimaki committed
1946 1947 1948 1949 1950
      }
      NEXT;
    }

    CASE(OP_SUBI) {
tomykaira's avatar
tomykaira committed
1951
      /* A B C  R(A) := R(A)-C (Syms[B]=:-)*/
mimaki's avatar
mimaki committed
1952
      int a = GETARG_A(i);
Masaki Muranaka's avatar
Masaki Muranaka committed
1953
      mrb_value *regs_a = regs + a;
mimaki's avatar
mimaki committed
1954 1955

      /* need to check if + is overridden */
Masaki Muranaka's avatar
Masaki Muranaka committed
1956
      switch (mrb_type(regs_a[0])) {
mimaki's avatar
mimaki committed
1957
      case MRB_TT_FIXNUM:
skandhas's avatar
skandhas committed
1958
        {
1959
          mrb_int x = mrb_fixnum(regs_a[0]);
skandhas's avatar
skandhas committed
1960
          mrb_int y = GETARG_C(i);
1961
          mrb_int z;
skandhas's avatar
skandhas committed
1962

1963
          if (mrb_int_sub_overflow(x, y, &z)) {
1964
            SET_FLOAT_VALUE(mrb, regs_a[0], (mrb_float)x - (mrb_float)y);
Masaki Muranaka's avatar
Masaki Muranaka committed
1965 1966
          }
          else {
1967
            SET_INT_VALUE(regs_a[0], z);
skandhas's avatar
skandhas committed
1968 1969
          }
        }
roco's avatar
roco committed
1970
        break;
mimaki's avatar
mimaki committed
1971
      case MRB_TT_FLOAT:
1972 1973 1974
#ifdef MRB_WORD_BOXING
        {
          mrb_float x = mrb_float(regs[a]);
1975
          SET_FLOAT_VALUE(mrb, regs[a], x - GETARG_C(i));
1976 1977
        }
#else
1978
        mrb_float(regs_a[0]) -= GETARG_C(i);
1979
#endif
roco's avatar
roco committed
1980
        break;
mimaki's avatar
mimaki committed
1981
      default:
1982
        SET_INT_VALUE(regs_a[1], GETARG_C(i));
roco's avatar
roco committed
1983 1984
        i = MKOP_ABC(OP_SEND, a, GETARG_B(i), 1);
        goto L_SEND;
mimaki's avatar
mimaki committed
1985 1986 1987 1988
      }
      NEXT;
    }

1989
#define OP_CMP_BODY(op,v1,v2) (v1(regs[a]) op v2(regs[a+1]))
mimaki's avatar
mimaki committed
1990 1991

#define OP_CMP(op) do {\
mirichi's avatar
mirichi committed
1992
  int result;\
mimaki's avatar
mimaki committed
1993 1994 1995
  /* need to check if - is overridden */\
  switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {\
  case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):\
1996
    result = OP_CMP_BODY(op,mrb_fixnum,mrb_fixnum);\
mimaki's avatar
mimaki committed
1997 1998
    break;\
  case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):\
1999
    result = OP_CMP_BODY(op,mrb_fixnum,mrb_float);\
mimaki's avatar
mimaki committed
2000 2001
    break;\
  case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):\
2002
    result = OP_CMP_BODY(op,mrb_float,mrb_fixnum);\
mimaki's avatar
mimaki committed
2003 2004
    break;\
  case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):\
2005
    result = OP_CMP_BODY(op,mrb_float,mrb_float);\
mimaki's avatar
mimaki committed
2006 2007 2008 2009
    break;\
  default:\
    goto L_SEND;\
  }\
mirichi's avatar
mirichi committed
2010 2011 2012 2013 2014 2015
  if (result) {\
    SET_TRUE_VALUE(regs[a]);\
  }\
  else {\
    SET_FALSE_VALUE(regs[a]);\
  }\
2016
} while(0)
mimaki's avatar
mimaki committed
2017 2018

    CASE(OP_EQ) {
2019
      /* A B C  R(A) := R(A)==R(A+1) (Syms[B]=:==,C=1)*/
2020 2021
      int a = GETARG_A(i);
      if (mrb_obj_eq(mrb, regs[a], regs[a+1])) {
skandhas's avatar
skandhas committed
2022
        SET_TRUE_VALUE(regs[a]);
2023 2024
      }
      else {
skandhas's avatar
skandhas committed
2025
        OP_CMP(==);
2026
      }
mimaki's avatar
mimaki committed
2027 2028 2029 2030
      NEXT;
    }

    CASE(OP_LT) {
roco's avatar
roco committed
2031
      /* A B C  R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/
mirichi's avatar
mirichi committed
2032
      int a = GETARG_A(i);
mimaki's avatar
mimaki committed
2033 2034 2035 2036 2037
      OP_CMP(<);
      NEXT;
    }

    CASE(OP_LE) {
2038
      /* A B C  R(A) := R(A)<=R(A+1) (Syms[B]=:<=,C=1)*/
mirichi's avatar
mirichi committed
2039
      int a = GETARG_A(i);
mimaki's avatar
mimaki committed
2040 2041 2042 2043 2044
      OP_CMP(<=);
      NEXT;
    }

    CASE(OP_GT) {
2045
      /* A B C  R(A) := R(A)>R(A+1) (Syms[B]=:>,C=1)*/
mirichi's avatar
mirichi committed
2046
      int a = GETARG_A(i);
mimaki's avatar
mimaki committed
2047 2048 2049 2050 2051
      OP_CMP(>);
      NEXT;
    }

    CASE(OP_GE) {
2052
      /* A B C  R(A) := R(A)>=R(A+1) (Syms[B]=:>=,C=1)*/
mirichi's avatar
mirichi committed
2053
      int a = GETARG_A(i);
mimaki's avatar
mimaki committed
2054 2055 2056 2057 2058
      OP_CMP(>=);
      NEXT;
    }

    CASE(OP_ARRAY) {
roco's avatar
roco committed
2059
      /* A B C          R(A) := ary_new(R(B),R(B+1)..R(B+C)) */
2060
      regs[GETARG_A(i)] = mrb_ary_new_from_values(mrb, GETARG_C(i), &regs[GETARG_B(i)]);
2061
      ARENA_RESTORE(mrb, ai);
mimaki's avatar
mimaki committed
2062 2063 2064 2065
      NEXT;
    }

    CASE(OP_ARYCAT) {
roco's avatar
roco committed
2066
      /* A B            mrb_ary_concat(R(A),R(B)) */
mimaki's avatar
mimaki committed
2067
      mrb_ary_concat(mrb, regs[GETARG_A(i)],
roco's avatar
roco committed
2068
                     mrb_ary_splat(mrb, regs[GETARG_B(i)]));
2069
      ARENA_RESTORE(mrb, ai);
mimaki's avatar
mimaki committed
2070 2071 2072 2073
      NEXT;
    }

    CASE(OP_ARYPUSH) {
roco's avatar
roco committed
2074
      /* A B            R(A).push(R(B)) */
mimaki's avatar
mimaki committed
2075 2076 2077 2078 2079
      mrb_ary_push(mrb, regs[GETARG_A(i)], regs[GETARG_B(i)]);
      NEXT;
    }

    CASE(OP_AREF) {
roco's avatar
roco committed
2080
      /* A B C          R(A) := R(B)[C] */
mimaki's avatar
mimaki committed
2081 2082 2083 2084
      int a = GETARG_A(i);
      int c = GETARG_C(i);
      mrb_value v = regs[GETARG_B(i)];

2085
      if (!mrb_array_p(v)) {
roco's avatar
roco committed
2086 2087 2088 2089 2090 2091
        if (c == 0) {
          regs[GETARG_A(i)] = v;
        }
        else {
          SET_NIL_VALUE(regs[a]);
        }
mimaki's avatar
mimaki committed
2092 2093
      }
      else {
skandhas's avatar
skandhas committed
2094
        regs[GETARG_A(i)] = mrb_ary_ref(mrb, v, c);
mimaki's avatar
mimaki committed
2095 2096 2097 2098 2099
      }
      NEXT;
    }

    CASE(OP_ASET) {
roco's avatar
roco committed
2100
      /* A B C          R(B)[C] := R(A) */
mimaki's avatar
mimaki committed
2101 2102 2103 2104 2105
      mrb_ary_set(mrb, regs[GETARG_B(i)], GETARG_C(i), regs[GETARG_A(i)]);
      NEXT;
    }

    CASE(OP_APOST) {
roco's avatar
roco committed
2106
      /* A B C  *R(A),R(A+1)..R(A+C) := R(A) */
mimaki's avatar
mimaki committed
2107 2108 2109 2110 2111
      int a = GETARG_A(i);
      mrb_value v = regs[a];
      int pre  = GETARG_B(i);
      int post = GETARG_C(i);

2112
      if (!mrb_array_p(v)) {
roco's avatar
roco committed
2113 2114 2115 2116 2117
        regs[a++] = mrb_ary_new_capa(mrb, 0);
        while (post--) {
          SET_NIL_VALUE(regs[a]);
          a++;
        }
mimaki's avatar
mimaki committed
2118 2119
      }
      else {
roco's avatar
roco committed
2120
        struct RArray *ary = mrb_ary_ptr(v);
Yukihiro Matsumoto's avatar
Yukihiro Matsumoto committed
2121
        int len = ary->len;
cremno's avatar
cremno committed
2122
        int idx;
roco's avatar
roco committed
2123 2124

        if (len > pre + post) {
2125
          regs[a++] = mrb_ary_new_from_values(mrb, len - pre - post, ary->ptr+pre);
roco's avatar
roco committed
2126
          while (post--) {
skandhas's avatar
skandhas committed
2127
            regs[a++] = ary->ptr[len-post-1];
roco's avatar
roco committed
2128 2129 2130
          }
        }
        else {
skandhas's avatar
skandhas committed
2131
          regs[a++] = mrb_ary_new_capa(mrb, 0);
Jan Berdajs's avatar
Jan Berdajs committed
2132 2133
          for (idx=0; idx+pre<len; idx++) {
            regs[a+idx] = ary->ptr[pre+idx];
roco's avatar
roco committed
2134
          }
cremno's avatar
cremno committed
2135 2136
          while (idx < post) {
            SET_NIL_VALUE(regs[a+idx]);
Jan Berdajs's avatar
Jan Berdajs committed
2137
            idx++;
roco's avatar
roco committed
2138 2139
          }
        }
mimaki's avatar
mimaki committed
2140
      }
2141
      ARENA_RESTORE(mrb, ai);
mimaki's avatar
mimaki committed
2142 2143 2144 2145
      NEXT;
    }

    CASE(OP_STRING) {
roco's avatar
roco committed
2146
      /* A Bx           R(A) := str_new(Lit(Bx)) */
2147
      regs[GETARG_A(i)] = mrb_str_dup(mrb, pool[GETARG_Bx(i)]);
2148
      ARENA_RESTORE(mrb, ai);
mimaki's avatar
mimaki committed
2149 2150 2151 2152
      NEXT;
    }

    CASE(OP_STRCAT) {
roco's avatar
roco committed
2153
      /* A B    R(A).concat(R(B)) */
mimaki's avatar
mimaki committed
2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165
      mrb_str_concat(mrb, regs[GETARG_A(i)], regs[GETARG_B(i)]);
      NEXT;
    }

    CASE(OP_HASH) {
      /* A B C   R(A) := hash_new(R(B),R(B+1)..R(B+C)) */
      int b = GETARG_B(i);
      int c = GETARG_C(i);
      int lim = b+c*2;
      mrb_value hash = mrb_hash_new_capa(mrb, c);

      while (b < lim) {
roco's avatar
roco committed
2166 2167
        mrb_hash_set(mrb, hash, regs[b], regs[b+1]);
        b+=2;
mimaki's avatar
mimaki committed
2168 2169
      }
      regs[GETARG_A(i)] = hash;
2170
      ARENA_RESTORE(mrb, ai);
mimaki's avatar
mimaki committed
2171 2172 2173 2174
      NEXT;
    }

    CASE(OP_LAMBDA) {
roco's avatar
roco committed
2175
      /* A b c  R(A) := lambda(SEQ[b],c) (b:c = 14:2) */
mimaki's avatar
mimaki committed
2176 2177 2178 2179
      struct RProc *p;
      int c = GETARG_c(i);

      if (c & OP_L_CAPTURE) {
2180
        p = mrb_closure_new(mrb, irep->reps[GETARG_b(i)]);
mimaki's avatar
mimaki committed
2181 2182
      }
      else {
2183
        p = mrb_proc_new(mrb, irep->reps[GETARG_b(i)]);
2184 2185 2186 2187 2188 2189 2190 2191 2192
        if (c & OP_L_METHOD) {
          if (p->target_class->tt == MRB_TT_SCLASS) {
            mrb_value klass;
            klass = mrb_obj_iv_get(mrb,
                                   (struct RObject *)p->target_class,
                                   mrb_intern_lit(mrb, "__attached__"));
            p->target_class = mrb_class_ptr(klass);
          }
        }
mimaki's avatar
mimaki committed
2193 2194 2195
      }
      if (c & OP_L_STRICT) p->flags |= MRB_PROC_STRICT;
      regs[GETARG_A(i)] = mrb_obj_value(p);
2196
      ARENA_RESTORE(mrb, ai);
mimaki's avatar
mimaki committed
2197 2198 2199 2200
      NEXT;
    }

    CASE(OP_OCLASS) {
roco's avatar
roco committed
2201
      /* A      R(A) := ::Object */
mimaki's avatar
mimaki committed
2202 2203 2204 2205 2206
      regs[GETARG_A(i)] = mrb_obj_value(mrb->object_class);
      NEXT;
    }

    CASE(OP_CLASS) {
2207
      /* A B    R(A) := newclass(R(A),Syms(B),R(A+1)) */
mimaki's avatar
mimaki committed
2208 2209 2210 2211 2212 2213 2214 2215
      struct RClass *c = 0;
      int a = GETARG_A(i);
      mrb_value base, super;
      mrb_sym id = syms[GETARG_B(i)];

      base = regs[a];
      super = regs[a+1];
      if (mrb_nil_p(base)) {
2216
        base = mrb_obj_value(mrb->c->ci->target_class);
mimaki's avatar
mimaki committed
2217 2218 2219
      }
      c = mrb_vm_define_class(mrb, base, super, id);
      regs[a] = mrb_obj_value(c);
2220
      ARENA_RESTORE(mrb, ai);
mimaki's avatar
mimaki committed
2221 2222 2223 2224
      NEXT;
    }

    CASE(OP_MODULE) {
2225
      /* A B            R(A) := newmodule(R(A),Syms(B)) */
mimaki's avatar
mimaki committed
2226 2227 2228 2229 2230 2231 2232
      struct RClass *c = 0;
      int a = GETARG_A(i);
      mrb_value base;
      mrb_sym id = syms[GETARG_B(i)];

      base = regs[a];
      if (mrb_nil_p(base)) {
2233
        base = mrb_obj_value(mrb->c->ci->target_class);
mimaki's avatar
mimaki committed
2234 2235 2236
      }
      c = mrb_vm_define_module(mrb, base, id);
      regs[a] = mrb_obj_value(c);
2237
      ARENA_RESTORE(mrb, ai);
mimaki's avatar
mimaki committed
2238 2239 2240 2241
      NEXT;
    }

    CASE(OP_EXEC) {
roco's avatar
roco committed
2242
      /* A Bx   R(A) := blockexec(R(A),SEQ[Bx]) */
mimaki's avatar
mimaki committed
2243 2244 2245 2246 2247 2248 2249 2250 2251 2252
      int a = GETARG_A(i);
      mrb_callinfo *ci;
      mrb_value recv = regs[a];
      struct RProc *p;

      /* prepare stack */
      ci = cipush(mrb);
      ci->pc = pc + 1;
      ci->acc = a;
      ci->mid = 0;
2253
      ci->stackent = mrb->c->stack;
mimaki's avatar
mimaki committed
2254
      ci->argc = 0;
2255
      ci->target_class = mrb_class_ptr(recv);
mimaki's avatar
mimaki committed
2256

2257
      /* prepare stack */
2258
      mrb->c->stack += a;
2259

2260
      p = mrb_proc_new(mrb, irep->reps[GETARG_Bx(i)]);
mimaki's avatar
mimaki committed
2261 2262 2263 2264
      p->target_class = ci->target_class;
      ci->proc = p;

      if (MRB_PROC_CFUNC_P(p)) {
2265
        ci->nregs = 0;
2266
        mrb->c->stack[0] = p->body.func(mrb, recv);
2267
        mrb_gc_arena_restore(mrb, ai);
roco's avatar
roco committed
2268 2269
        if (mrb->exc) goto L_RAISE;
        /* pop stackpos */
2270
        regs = mrb->c->stack = mrb->c->ci->stackent;
roco's avatar
roco committed
2271 2272
        cipop(mrb);
        NEXT;
mimaki's avatar
mimaki committed
2273 2274
      }
      else {
roco's avatar
roco committed
2275 2276 2277
        irep = p->body.irep;
        pool = irep->pool;
        syms = irep->syms;
2278
        stack_extend(mrb, irep->nregs, 1);
skandhas's avatar
skandhas committed
2279
        ci->nregs = irep->nregs;
2280
        regs = mrb->c->stack;
roco's avatar
roco committed
2281 2282
        pc = irep->iseq;
        JUMP;
mimaki's avatar
mimaki committed
2283 2284 2285 2286
      }
    }

    CASE(OP_METHOD) {
2287
      /* A B            R(A).newmethod(Syms(B),R(A+1)) */
mimaki's avatar
mimaki committed
2288 2289 2290 2291
      int a = GETARG_A(i);
      struct RClass *c = mrb_class_ptr(regs[a]);

      mrb_define_method_vm(mrb, c, syms[GETARG_B(i)], regs[a+1]);
2292
      ARENA_RESTORE(mrb, ai);
mimaki's avatar
mimaki committed
2293 2294 2295 2296
      NEXT;
    }

    CASE(OP_SCLASS) {
roco's avatar
roco committed
2297
      /* A B    R(A) := R(B).singleton_class */
mimaki's avatar
mimaki committed
2298
      regs[GETARG_A(i)] = mrb_singleton_class(mrb, regs[GETARG_B(i)]);
2299
      ARENA_RESTORE(mrb, ai);
mimaki's avatar
mimaki committed
2300 2301 2302 2303
      NEXT;
    }

    CASE(OP_TCLASS) {
2304
      /* A      R(A) := target_class */
2305
      if (!mrb->c->ci->target_class) {
cubicdaiya's avatar
cubicdaiya committed
2306
        mrb_value exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR, "no target class or module");
2307
        mrb->exc = mrb_obj_ptr(exc);
2308
        goto L_RAISE;
2309
      }
2310
      regs[GETARG_A(i)] = mrb_obj_value(mrb->c->ci->target_class);
mimaki's avatar
mimaki committed
2311 2312 2313 2314
      NEXT;
    }

    CASE(OP_RANGE) {
roco's avatar
roco committed
2315
      /* A B C  R(A) := range_new(R(B),R(B+1),C) */
mimaki's avatar
mimaki committed
2316 2317
      int b = GETARG_B(i);
      regs[GETARG_A(i)] = mrb_range_new(mrb, regs[b], regs[b+1], GETARG_C(i));
2318
      ARENA_RESTORE(mrb, ai);
mimaki's avatar
mimaki committed
2319 2320 2321 2322
      NEXT;
    }

    CASE(OP_DEBUG) {
2323
      /* A B C    debug print R(A),R(B),R(C) */
2324 2325 2326
#ifdef ENABLE_DEBUG
      mrb->debug_op_hook(mrb, irep, pc, regs);
#else
2327
#ifdef ENABLE_STDIO
mimaki's avatar
mimaki committed
2328
      printf("OP_DEBUG %d %d %d\n", GETARG_A(i), GETARG_B(i), GETARG_C(i));
2329 2330 2331
#else
      abort();
#endif
2332
#endif
mimaki's avatar
mimaki committed
2333 2334 2335 2336
      NEXT;
    }

    CASE(OP_STOP) {
roco's avatar
roco committed
2337
      /*        stop VM */
mimaki's avatar
mimaki committed
2338
    L_STOP:
2339
      {
2340 2341 2342 2343
        int eidx_stop = mrb->c->ci == mrb->c->cibase ? 0 : mrb->c->ci[-1].eidx;
        int eidx = mrb->c->ci->eidx;
        while (eidx > eidx_stop) {
          ecall(mrb, --eidx);
skandhas's avatar
skandhas committed
2344
        }
2345
      }
2346
      ERR_PC_CLR(mrb);
mimaki's avatar
mimaki committed
2347
      mrb->jmp = prev_jmp;
2348
      if (mrb->exc) {
skandhas's avatar
skandhas committed
2349
        return mrb_obj_value(mrb->exc);
2350
      }
2351
      return regs[irep->nlocals];
mimaki's avatar
mimaki committed
2352 2353 2354
    }

    CASE(OP_ERR) {
roco's avatar
roco committed
2355
      /* Bx     raise RuntimeError with message Lit(Bx) */
2356
      mrb_value msg = mrb_str_dup(mrb, pool[GETARG_Bx(i)]);
2357
      mrb_value exc;
mimaki's avatar
mimaki committed
2358

2359
      if (GETARG_A(i) == 0) {
2360
        exc = mrb_exc_new_str(mrb, E_RUNTIME_ERROR, msg);
2361 2362
      }
      else {
2363
        exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg);
2364
      }
2365
      mrb->exc = mrb_obj_ptr(exc);
mimaki's avatar
mimaki committed
2366 2367 2368
      goto L_RAISE;
    }
  }
2369
  END_DISPATCH;
take_cheeze's avatar
take_cheeze committed
2370 2371 2372 2373 2374 2375 2376

  }
  MRB_CATCH(&c_jmp) {
    exc_catched = TRUE;
    goto RETRY_TRY_BLOCK;
  }
  MRB_END_EXC(&c_jmp);
mimaki's avatar
mimaki committed
2377
}
2378

2379
MRB_API mrb_value
fleuria's avatar
fleuria committed
2380 2381
mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
{
Yukihiro "Matz" Matsumoto's avatar
Yukihiro "Matz" Matsumoto committed
2382
  return mrb_context_run(mrb, proc, self, mrb->c->ci->argc + 2); /* argc + 2 (receiver and block) */
fleuria's avatar
fleuria committed
2383
}
2384

2385
MRB_API mrb_value
2386
mrb_toplevel_run_keep(mrb_state *mrb, struct RProc *proc, unsigned int stack_keep)
2387 2388 2389 2390 2391
{
  mrb_callinfo *ci;
  mrb_value v;

  if (!mrb->c->cibase || mrb->c->ci == mrb->c->cibase) {
2392
    return mrb_context_run(mrb, proc, mrb_top_self(mrb), stack_keep);
2393 2394
  }
  ci = cipush(mrb);
2395
  ci->nregs = 1;   /* protect the receiver */
2396
  ci->acc = CI_ACC_SKIP;
2397
  ci->target_class = mrb->object_class;
2398
  v = mrb_context_run(mrb, proc, mrb_top_self(mrb), stack_keep);
2399 2400 2401 2402
  cipop(mrb);

  return v;
}
2403

2404
MRB_API mrb_value
2405 2406 2407 2408
mrb_toplevel_run(mrb_state *mrb, struct RProc *proc)
{
  return mrb_toplevel_run_keep(mrb, proc, 0);
}