Example #1
0
static mrb_value
mrb_ary_aget(mrb_state *mrb, mrb_value self)
{
  struct RArray *a = mrb_ary_ptr(self);
  mrb_int i, len;
  mrb_value index;

  if (mrb_get_args(mrb, "o|i", &index, &len) == 1) {
    switch (mrb_type(index)) {
      /* a[n..m] */
    case MRB_TT_RANGE:
      if (mrb_range_beg_len(mrb, index, &i, &len, a->len)) {
        return ary_subseq(mrb, a, i, len);
      }
      else {
        return mrb_nil_value();
      }
    case MRB_TT_FIXNUM:
      return mrb_ary_ref(mrb, self, mrb_fixnum(index));
    default:
      return mrb_ary_ref(mrb, self, aget_index(mrb, index));
    }
  }

  i = aget_index(mrb, index);
  if (i < 0) i += a->len;
  if (i < 0 || a->len < i) return mrb_nil_value();
  if (len < 0) return mrb_nil_value();
  if (a->len == i) return mrb_ary_new(mrb);
  if (len > a->len - i) len = a->len - i;

  return ary_subseq(mrb, a, i, len);
}
bool rubyval_to_std_vector_string(mrb_state* mrb, mrb_value arg, std::vector<std::string>* ret, const char* funcName)
{
    if (! mrb_array_p(arg)) {
        return false;
    }
    
    mrb_int len = mrb_ary_len(mrb, arg);
    for (mrb_int i = 0; i < len; i++) {
        mrb_value v = mrb_ary_ref(mrb, arg, i);
        std::string str = "";
        if (mrb_fixnum_p(v)) {
            mrb_int val = mrb_fixnum(v);
            char *cstr = nullptr;
            sprintf(cstr, "%d", val);
            str = std::string(cstr);
        } else if (mrb_float_p(v)) {
            mrb_float val = mrb_float(v);
            char *cstr = nullptr;
            sprintf(cstr, "%f", val);
            str = std::string(cstr);
        }
        ret->push_back(str);
    }
    
    return true;
}
Example #3
0
mrb_value
mrb_ary_aget(mrb_state *mrb, mrb_value self)
{
  struct RArray *a = mrb_ary_ptr(self);
  mrb_int index, len;
  mrb_value *argv;
  int size;

  mrb_get_args(mrb, "i*", &index, &argv, &size);
  switch(size) {
  case 0:
    return mrb_ary_ref(mrb, self, index);

  case 1:
    if (mrb_type(argv[0]) != MRB_TT_FIXNUM) {
      mrb_raise(mrb, E_TYPE_ERROR, "expected Fixnum");
    }
    if (index < 0) index += a->len;
    if (index < 0 || a->len < (int)index) return mrb_nil_value();
    len = mrb_fixnum(argv[0]);
    if (len < 0) return mrb_nil_value();
    if (a->len == (int)index) return mrb_ary_new(mrb);
    if ((int)len > a->len - index) len = a->len - index;
    return ary_subseq(mrb, a, index, len);

  default:
    mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments");
  }

  return mrb_nil_value(); /* dummy to avoid warning : not reach here */
}
bool rubyval_to_dictionary(mrb_state* mrb, mrb_value arg, __Dictionary** outValue, const char* funcName)
{
    if (! mrb_hash_p(arg)) {
        return false;
    }
    
    mrb_value key_arr = mrb_hash_keys(mrb, arg);
    mrb_int len = mrb_ary_len(mrb, key_arr);
    __Dictionary* dic = __Dictionary::create();
    for (mrb_int i = 0; i < len; i++) {
        mrb_value hk = mrb_ary_ref(mrb, key_arr, i);
        mrb_value hv = mrb_hash_get(mrb, arg, hk);
        if (mrb_string_p(hk)) {
            char *kstr = mrb_str_to_cstr(mrb, hk);
            Ref* ref = to_ref_value(mrb, hv);
            dic->setObject(ref, std::string(kstr));
        } else if (mrb_symbol_p(hk)) {
            mrb_sym sym = mrb_symbol(hk);
            const char* kstr = mrb_sym2name(mrb, sym);
            Ref* ref = to_ref_value(mrb, hv);
            dic->setObject(ref, std::string(kstr));
        } else {
            CCASSERT(false, "not supported key value type");
        }
    }
    *outValue = dic;
    
    return true;
}
bool rubyval_to_ccvaluemapintkey(mrb_state* mrb, mrb_value arg, cocos2d::ValueMapIntKey* ret, const char* funcName)
{
    if (! mrb_hash_p(arg)) {
        return false;
    }
    
    mrb_value key_arr = mrb_hash_keys(mrb, arg);
    mrb_int len = mrb_ary_len(mrb, key_arr);
    ValueMapIntKey& dict = *ret;
    for (mrb_int i = 0; i < len; i++) {
        mrb_value hk = mrb_ary_ref(mrb, key_arr, i);
        mrb_value hv = mrb_hash_get(mrb, arg, hk);
        int int_key = 0;
        
        if (mrb_string_p(hk)) {
            char *kstr = mrb_str_to_cstr(mrb, hk);
            int_key = atoi(kstr);
        } else if (mrb_symbol_p(hk)) {
            mrb_sym sym = mrb_symbol(hk);
            const char* kstr = mrb_sym2name(mrb, sym);
            int_key = atoi(kstr);
        } else {
            return false;
        }
        Value val;
        if (! rubyval_to_ccvalue(mrb, hv, &val)) {
            return false;
        }
        
        dict[int_key] = val;
    }
    return true;
}
mrb_value ruby_global_require(mrb_state* mrb, mrb_value self)
{
    
    const char* filename_cstr = nullptr;
    mrb_get_args(mrb, "z", &filename_cstr);
    std::string filename(filename_cstr);
    
    auto engine = cocos2d::RubyEngine::getInstance();
    std::string realfile = engine->findFile(filename);
    
    mrb_value loaded_path_arr = mrb_gv_get(mrb, mrb_intern_cstr(mrb, "$LOADED_FEATURES"));
    if (mrb_array_p(loaded_path_arr)) {
        mrb_int len = mrb_ary_len(mrb, loaded_path_arr);
        for (mrb_int i = 0; i < len; i++) {
            mrb_value path = mrb_ary_ref(mrb, loaded_path_arr, i);
            const char* path_cstr = mrb_str_to_cstr(mrb, path);
            if (realfile.compare(path_cstr) == 0) {
                return mrb_nil_value();
            }
        }
    }
    
    if (! mrb_array_p(loaded_path_arr)) {
        loaded_path_arr = mrb_ary_new(mrb);
        mrb_value path = mrb_str_new_cstr(mrb, realfile.c_str());
        mrb_ary_push(mrb, loaded_path_arr, path);
        mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$LOADED_FEATURES"), loaded_path_arr);
    } else {
        mrb_value path = mrb_str_new_cstr(mrb, realfile.c_str());
        mrb_ary_push(mrb, loaded_path_arr, path);
    }
    engine->executeScriptFile(realfile.c_str());
    
    return mrb_nil_value();
}
Example #7
0
static mrb_value
mrb_sdl2_video_surface_fill_rects(mrb_state *mrb, mrb_value self)
{
    uint32_t color;
    mrb_value rects;
    mrb_get_args(mrb, "io", &color, &rects);
    if (!mrb_array_p(rects)) {
        mrb_raise(mrb, E_TYPE_ERROR, "given 2nd argument is unexpected type (expected Array).");
    }
    mrb_int const n = mrb_ary_len(mrb, rects);
    SDL_Surface *s = mrb_sdl2_video_surface_get_ptr(mrb, self);
    SDL_Rect r[n];
    mrb_int i;
    for (i = 0; i < n; ++i) {
        SDL_Rect const * const ptr = mrb_sdl2_rect_get_ptr(mrb, mrb_ary_ref(mrb, rects, i));
        if (NULL != ptr) {
            r[i] = *ptr;
        } else {
            r[i] = (SDL_Rect) {
                0, 0, 0, 0
            };
        }
    }
    if (0 != SDL_FillRects(s, r, n, color)) {
        mruby_sdl2_raise_error(mrb);
    }
    return self;
}
Example #8
0
mrb_value
mrb_mraa_i2c_write(mrb_state *mrb, mrb_value self){
    mraa_i2c_context i2c;
    mrb_value mrv_wbuf;
    mrb_int length;

    mraa_result_t result;
    uint8_t *wbuf;
    mrb_int argc;
    
    Data_Get_Struct(mrb, self, &mrb_mraa_i2c_ctx_type, i2c);

    argc = mrb_get_args(mrb, "o|i", &mrv_wbuf, &length);

    result = MRAA_ERROR_INVALID_PARAMETER;
    if (mrb_array_p(mrv_wbuf)){
        int i;
        if (argc == 1){
            length = RARRAY_LEN(mrv_wbuf);
        }

        wbuf = (uint8_t *)mrb_malloc(mrb, sizeof(uint8_t) * length);
        memset(wbuf, 0, sizeof(uint8_t) * length);
        for (i = 0; i < length; i++){
            wbuf[i] = mrb_fixnum(mrb_ary_ref(mrb, mrv_wbuf, i));
        }
        result = mraa_i2c_write(i2c, wbuf, length);
        mrb_free(mrb, wbuf);
    }

    return mrb_fixnum_value(result);
}
Example #9
0
static RETSIGTYPE
sighandler(int sig)
{
  mrb_state *mrb = global_mrb;
  struct RClass *mrb_mSignal = mrb_module_get(mrb, "Signal");
  mrb_value trap_list = mrb_iv_get(mrb, mrb_obj_value(mrb_mSignal), mrb_intern_lit(mrb, "trap_list"));
  mrb_value command = mrb_ary_ref(mrb, trap_list, sig);

  if (mrb_type(command) == MRB_TT_PROC) {
    mrb_funcall(mrb, command, "call", 1, mrb_fixnum_value(sig));
  } else {
    mrb_signal(mrb, sig, sighandler);

    /* default actions */
    switch (sig) {
      case SIGINT:
        mrb_exc_raise(mrb, mrb_funcall(
          mrb,
          mrb_obj_value(mrb_class_get(mrb, "Interrupt")),
          "new",
          1,
          mrb_str_new_cstr(mrb, "")
        ));
        break;
#ifdef SIGHUP
      case SIGHUP:
#endif
#ifdef SIGQUIT
      case SIGQUIT:
#endif
#ifdef SIGTERM
      case SIGTERM:
#endif
#ifdef SIGALRM
      case SIGALRM:
#endif
#ifdef SIGUSR1
      case SIGUSR1:
#endif
#ifdef SIGUSR2
      case SIGUSR2:
#endif
        mrb_exc_raise(mrb, mrb_funcall(
          mrb,
          mrb_obj_value(mrb_class_get(mrb, "SignalException")),
          "new",
          1,
          mrb_fixnum_value(sig)
        ));
        break;
      default:
        break;
    }
  }
}
Example #10
0
static ERL_NIF_TERM make_array(ErlNifEnv* env, mrb_state* mrb, mrb_value o) {
  size_t len = (int) RARRAY(o)->len;
  ERL_NIF_TERM list = enif_make_list_from_array(env, NULL, 0);

  for(int i = len; i>0; --i) {
    ERL_NIF_TERM term = mruby2erl(env, mrb, mrb_ary_ref(mrb, o, (mrb_int)i - 1));
    list = enif_make_list_cell(env, term, list);
  }

  return list;
}
Example #11
0
static void
mrb_trap_exit(mrb_state *mrb)
{
  struct RClass *mrb_mSignal = mrb_module_get(mrb, "Signal");
  mrb_value trap_list = mrb_iv_get(mrb, mrb_obj_value(mrb_mSignal), mrb_intern_lit(mrb, "trap_list"));
  mrb_value command = mrb_ary_ref(mrb, trap_list, 0);

  if (mrb_type(command) == MRB_TT_PROC) {
    mrb_ary_set(mrb, trap_list, 0, mrb_nil_value());
    mrb_funcall(mrb, command, "call", 1, mrb_fixnum_value(0));
  }
}
Example #12
0
static mrb_value
mrb_env_clear(mrb_state *mrb, mrb_value self)
{
  int i;
  mrb_value keys = mrb_env_keys(mrb, self);
  int ai = mrb_gc_arena_save(mrb);

  for (i = 0; i < RARRAY_LEN(keys); i++) {
    mrb_env_unsetenv(mrb, mrb_ary_ref(mrb, keys, i));
    mrb_gc_arena_restore(mrb, ai);
  }

  return self;
}
Example #13
0
mrb_value
cfunc_closure_initialize(mrb_state *mrb, mrb_value self)
{
    struct cfunc_closure_data *data;
    data = mrb_data_check_get_ptr(mrb, self, &cfunc_closure_data_type);
    if (!data) {
        data = mrb_malloc(mrb, sizeof(struct cfunc_closure_data));
    }
    data->refer = 0;
    data->autofree = 0;
    DATA_PTR(self) = data;
    DATA_TYPE(self) = &cfunc_closure_data_type;

    data->mrb = mrb;
    data->closure = NULL;
    data->arg_types = NULL;
    
    mrb_value rettype_mrb, block, args_mrb;
    mrb_get_args(mrb, "&oo", &block, &rettype_mrb, &args_mrb);
    data->argc = RARRAY_LEN(args_mrb);
    
    ffi_type *return_ffi_type = rclass_to_mrb_ffi_type(mrb, mrb_class_ptr(rettype_mrb))->ffi_type_value;
    data->return_type = rettype_mrb;

    data->arg_ffi_types = mrb_malloc(mrb, sizeof(ffi_type*) * data->argc);
    data->arg_types = mrb_malloc(mrb, sizeof(mrb_value) * data->argc);
    int i;
    for (i = 0; i < data->argc; ++i) {
        data->arg_types[i] = mrb_ary_ref(mrb, args_mrb, i);
        data->arg_ffi_types[i] = rclass_to_mrb_ffi_type(mrb, mrb_class_ptr(data->arg_types[i]))->ffi_type_value;
    }
    
    mrb_iv_set(mrb, self, mrb_intern_cstr(data->mrb, "@block"), block);

    void *closure_pointer = NULL;
    data->closure = ffi_closure_alloc(sizeof(ffi_closure) + sizeof(void*), &closure_pointer);
    data->cif = mrb_malloc(mrb, sizeof(ffi_cif));
    
    if (data->closure) {
        if (ffi_prep_cif(data->cif, FFI_DEFAULT_ABI, data->argc, return_ffi_type, data->arg_ffi_types) == FFI_OK) {
            if (ffi_prep_closure_loc(data->closure, data->cif, cfunc_closure_call_binding, mrb_object(self), closure_pointer) == FFI_OK) {
                set_cfunc_pointer_data((struct cfunc_type_data *)data, closure_pointer);
                return self;
            }
        }
    }

    mrb_raise(mrb, E_SCRIPT_ERROR, "Internal FFI call error");
    return mrb_nil_value();
}
Example #14
0
static ERL_NIF_TERM make_hash(ErlNifEnv* env, mrb_state* mrb, mrb_value o) {
  mrb_value keys = mrb_hash_keys(mrb, o);
  size_t len = (int) RARRAY(keys)->len;
  ERL_NIF_TERM list = enif_make_list_from_array(env, NULL, 0);

  for(int i = len; i>0; --i) {
    mrb_value k = mrb_ary_ref(mrb, keys, (mrb_int)i - 1);
    ERL_NIF_TERM key = mruby2erl(env, mrb, k);
    ERL_NIF_TERM value = mruby2erl(env, mrb, mrb_hash_get(mrb, o, k));
    list = enif_make_list_cell(env, enif_make_tuple2(env, key, value), list);
  }

  return enif_make_tuple1(env, list);
}
Example #15
0
static mrb_value
mrb_enc_from_encoding_index(mrb_state *mrb, int idx)
{
  mrb_value list, enc;

  if (mrb_nil_p(list = mrb_encoding_list)) {
    mrb_bug("mrb_enc_from_encoding_index(%d): no mrb_encoding_list", idx);
  }
  enc = mrb_ary_ref(mrb, list, idx);//mrb_ary_entry(list, idx);
  if (mrb_nil_p(enc)) {
    mrb_bug("mrb_enc_from_encoding_index(%d): not created yet", idx);
  }
  return enc;
}
Example #16
0
std::map<std::string, std::string> MRuby::invert(const std::map<std::string, std::string> &lis) const {
    std::map<std::string, std::string> res;

    mrb_value a = mrb_hash_new_capa(mMrb, lis.size());
    for (auto it = lis.begin(); it != lis.end(); ++it) {
        mrb_hash_set(mMrb, a, mrb_str_new_cstr(mMrb, it->first.c_str()), mrb_str_new_cstr(mMrb, it->second.c_str()));
    }
    mrb_value r = mrb_funcall(mMrb, mrb_top_self(mMrb), "invert", 1, a);
    mrb_value keys = mrb_hash_keys(mMrb, r);
    for (int i = 0; i < RARRAY_LEN(keys); ++i) {
        mrb_value k = mrb_ary_ref(mMrb, keys, i);
        mrb_value v = mrb_hash_get(mMrb, r, k);
        res[mrb_str_to_cstr(mMrb, k)] = mrb_str_to_cstr(mMrb, v);
    }
    return res;
}
bool rubyval_to_array(mrb_state* mrb, mrb_value arg, __Array** outValue, const char* funcName)
{
    if (! mrb_array_p(arg)) {
        return false;
    }
    
    mrb_int len = mrb_ary_len(mrb, arg);
    __Array* arr =  __Array::createWithCapacity(len);
    for (mrb_int i = 0; i < len; i++) {
        mrb_value val = mrb_ary_ref(mrb, arg, i);
        Ref* ref = to_ref_value(mrb, val);
        arr->addObject(ref);
    }
    *outValue = arr;
        
    return true;
}
bool rubyval_to_ccvaluevector(mrb_state* mrb, mrb_value arg, cocos2d::ValueVector* ret, const char* funcName)
{
    if (! mrb_array_p(arg)) {
        return false;
    }
    
    mrb_int len = mrb_ary_len(mrb, arg);
    for (mrb_int i = 0; i < len; i++) {
        mrb_value v = mrb_ary_ref(mrb, arg, i);
        Value val;
        if (! rubyval_to_ccvalue(mrb, v, &val)) {
            return false;
        }
        ret->push_back(val);
    }
    
    return true;
}
Example #19
0
static mrb_value
trap(mrb_state *mrb, mrb_value mod, int sig, sighandler_t func, mrb_value command)
{
  sighandler_t oldfunc;
  mrb_value oldcmd;
  mrb_value trap_list;
  mrb_sym id_trap_list;

  if (sig == 0) { /* EXIT */
    oldfunc = SIG_ERR;
  }
  else {
    oldfunc = mrb_signal(mrb, sig, func);
    if (oldfunc == SIG_ERR)
      mrb_sys_fail(mrb, signo2signm(sig));
  }
  id_trap_list = mrb_intern_lit(mrb, "trap_list");
  trap_list = mrb_iv_get(mrb, mod, id_trap_list);
  oldcmd = mrb_ary_ref(mrb, trap_list, (mrb_int)sig);

  if (mrb_nil_p(oldcmd)) {
    if (oldfunc == sighandler)
      oldcmd = mrb_str_new_cstr(mrb, "DEFAULT");
    else
      oldcmd = mrb_nil_value();
  }
  else if (mrb_type(oldcmd) == MRB_TT_TRUE) {
    if (oldfunc == SIG_IGN)
      oldcmd = mrb_str_new_cstr(mrb, "IGNORE");
    else if (oldfunc == SIG_DFL)
      oldcmd = mrb_str_new_cstr(mrb, "SYSTEM_DEFAULT");
    else if (oldfunc == sighandler)
      oldcmd = mrb_str_new_cstr(mrb, "DEFAULT");
    else
      oldcmd = mrb_nil_value();
  }
  else if (mrb_undef_p(oldcmd)) {
    oldcmd = mrb_str_new_cstr(mrb, "EXIT");
  }

  mrb_ary_set(mrb, trap_list, (mrb_int)sig, command);

  return oldcmd;
}
bool rubyval_to_carray_float(mrb_state* mrb, mrb_value arg, float** outValue, const char* funcName)
{
    if (! mrb_array_p(arg)) {
        return false;
    }
    
    mrb_int len = mrb_ary_len(mrb, arg);
    float arr[len];
    for (mrb_int i = 0; i < len; i++) {
        mrb_value val = mrb_ary_ref(mrb, arg, i);
        if (! mrb_float_p(val)) {
            return false;
        }
        arr[i] = mrb_float(val);
    }
    *outValue = arr;
    
    return true;
}
Example #21
0
static mrb_value
mrb_mrmagick_rm(mrb_state *mrb, mrb_value self)
{
  mrb_value ary, val;

  int num_files, i;
  char filepath[1024];

  mrb_get_args(mrb, "A", &ary);
  num_files = RARRAY_LEN(ary);
  
  for (i = 0; i < num_files; ++i) {
    val = mrb_ary_ref(mrb, ary, i);
    strncpy(filepath, RSTRING_PTR(val), RSTRING_LEN(val));
    filepath[RSTRING_LEN(val)] = '\0';

    remove(filepath);
  }
  return mrb_str_new_cstr(mrb, "hi!!");
}
Example #22
0
static int
enc_register_at(mrb_state *mrb, int index, const char *name, mrb_encoding *encoding)
{
    struct mrb_encoding_entry *ent = &enc_table.list[index];
    mrb_value list;
    mrb_value ref_ary;

    if (!valid_encoding_name_p(name)) return -1;
    if (!ent->name) {
    ent->name = name = strdup(name);
    }
    else if (STRCASECMP(name, ent->name)) {
    return -1;
    }
    if (!ent->enc) {
    ent->enc = xmalloc(sizeof(mrb_encoding));
    }
    if (encoding) {
    *ent->enc = *encoding;
    }
    else {
    memset(ent->enc, 0, sizeof(*ent->enc));
    }
    encoding = ent->enc;
    encoding->name = name;
    encoding->ruby_encoding_index = index;
    st_insert(enc_table.names, (st_data_t)name, (st_data_t)index);
    list = mrb_encoding_list;
    //if (list && mrb_nil_p((mrb_ary_ref(mrb, list, index)))) {
    if (list.tt) {
      ref_ary = mrb_ary_ref(mrb, list, index);
      if mrb_nil_p(ref_ary) {
        /* initialize encoding data */
        mrb_ary_set(mrb, list, index, enc_new(mrb, encoding));//rb_ary_store(list, index, enc_new(encoding));
      }
    }
Example #23
0
File: vm.c Project: kstephens/mruby
mrb_value
mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
{
  /* assert(mrb_proc_cfunc_p(proc)) */
  mrb_irep *irep = proc->body.irep;
  mrb_code *pc = irep->iseq;
  mrb_value *pool = irep->pool;
  mrb_sym *syms = irep->syms;
  mrb_value *regs;
  mrb_code i;
  int ai = mrb->arena_idx;
  jmp_buf c_jmp;
  jmp_buf *prev_jmp;

#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,
    &&L_OP_SEND, &&L_OP_FSEND, &&L_OP_VSEND,
    &&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


  if (setjmp(c_jmp) == 0) {
    prev_jmp = mrb->jmp;
    mrb->jmp = &c_jmp;
  }
  else {
    goto L_RAISE;
  }
  if (!mrb->stack) {
    stack_init(mrb);
  }
  mrb->ci->proc = proc;
  mrb->ci->nregs = irep->nregs + 2;
  regs = mrb->stack;

  INIT_DISPACTH {
    CASE(OP_NOP) {
      /* do nothing */
      NEXT;
    }

    CASE(OP_MOVE) {
      /* A B    R(A) := R(B) */
#if 0
      regs[GETARG_A(i)] = regs[GETARG_B(i)];
#elif 1
      int a = GETARG_A(i);
      int b = GETARG_B(i);

      regs[a].tt = regs[b].tt;
      regs[a].value = regs[b].value;
#else
      memcpy(regs+GETARG_A(i), regs+GETARG_B(i), sizeof(mrb_value));
#endif
      NEXT;
    }

    CASE(OP_LOADL) {
      /* A Bx   R(A) := Pool(Bx) */
      regs[GETARG_A(i)] = pool[GETARG_Bx(i)];
      NEXT;
    }

    CASE(OP_LOADI) {
      /* A Bx   R(A) := sBx */
      SET_INT_VALUE(regs[GETARG_A(i)], GETARG_sBx(i));
      NEXT;
    }

    CASE(OP_LOADSYM) {
      /* A B    R(A) := Sym(B) */
      SET_SYM_VALUE(regs[GETARG_A(i)], syms[GETARG_Bx(i)]);
      NEXT;
    }

    CASE(OP_LOADNIL) {
      /* A B    R(A) := nil */
      int a = GETARG_A(i);

      SET_NIL_VALUE(regs[a]);
      NEXT;
    }

    CASE(OP_LOADSELF) {
      /* A      R(A) := self */
      regs[GETARG_A(i)] = mrb->stack[0];
      NEXT;
    }

    CASE(OP_LOADT) {
      /* A      R(A) := true */
      regs[GETARG_A(i)] = mrb_true_value();
      NEXT;
    }

    CASE(OP_LOADF) {
      /* A      R(A) := false */
      regs[GETARG_A(i)] = mrb_false_value();
      NEXT;
    }

    CASE(OP_GETGLOBAL) {
      /* A B    R(A) := getglobal(Sym(B)) */
      regs[GETARG_A(i)] = mrb_gv_get(mrb, syms[GETARG_Bx(i)]);
      NEXT;
    }

    CASE(OP_SETGLOBAL) {
      /* setglobal(Sym(b), R(A)) */
      mrb_gv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]);
      NEXT;
    }

    CASE(OP_GETSPECIAL) {
      /* A Bx   R(A) := Special[Bx] */
      regs[GETARG_A(i)] = mrb_vm_special_get(mrb, GETARG_Bx(i));
      NEXT;
    }

    CASE(OP_SETSPECIAL) {
      /* A Bx   Special[Bx] := R(A) */
      mrb_vm_special_set(mrb, GETARG_Bx(i), regs[GETARG_A(i)]);
      NEXT;
    }

    CASE(OP_GETIV) {
      /* A Bx   R(A) := ivget(Bx) */
      regs[GETARG_A(i)] = mrb_vm_iv_get(mrb, syms[GETARG_Bx(i)]);
      NEXT;
    }

    CASE(OP_SETIV) {
      /* ivset(Sym(B),R(A)) */
      mrb_vm_iv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]);
      NEXT;
    }

    CASE(OP_GETCV) {
      /* A B    R(A) := ivget(Sym(B)) */
      regs[GETARG_A(i)] = mrb_vm_cv_get(mrb, syms[GETARG_Bx(i)]);
      NEXT;
    }

    CASE(OP_SETCV) {
      /* ivset(Sym(B),R(A)) */
      mrb_vm_cv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]);
      NEXT;
    }

    CASE(OP_GETCONST) {
      /* A B    R(A) := constget(Sym(B)) */
      regs[GETARG_A(i)] = mrb_vm_const_get(mrb, syms[GETARG_Bx(i)]);
      NEXT;
    }

    CASE(OP_SETCONST) {
      /* A B    constset(Sym(B),R(A)) */
      mrb_vm_const_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]);
      NEXT;
    }

    CASE(OP_GETMCNST) {
      /* A B C  R(A) := R(C)::Sym(B) */
      int a = GETARG_A(i);

      regs[a] = mrb_const_get(mrb, regs[a], syms[GETARG_Bx(i)]);
      NEXT;
    }

    CASE(OP_SETMCNST) {
      /* A B C  R(A+1)::Sym(B) := R(A) */
      int a = GETARG_A(i);

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

    CASE(OP_GETUPVAR) {
      /* A B C  R(A) := uvget(B,C) */
      regs[GETARG_A(i)] = uvget(mrb, GETARG_C(i), GETARG_B(i));
      NEXT;
    }

    CASE(OP_SETUPVAR) {
      /* A B C  uvset(B,C,R(A)) */
      uvset(mrb, GETARG_C(i), GETARG_B(i), regs[GETARG_A(i)]);
      NEXT;
    }

    CASE(OP_JMP) {
      /* sBx    pc+=sBx */
      pc += GETARG_sBx(i);
      JUMP;
    }

    CASE(OP_JMPIF) {
      /* A sBx  if R(A) pc+=sBx */
      if (mrb_test(regs[GETARG_A(i)])) {
        pc += GETARG_sBx(i);
        JUMP;
      }
      NEXT;
    }

    CASE(OP_JMPNOT) {
      /* A sBx  if R(A) pc+=sBx */
      if (!mrb_test(regs[GETARG_A(i)])) {
        pc += GETARG_sBx(i);
        JUMP;
      }
      NEXT;
    }

    CASE(OP_ONERR) {
      /* sBx    pc+=sBx on exception */
      if (mrb->rsize <= mrb->ci->ridx) {
        if (mrb->rsize == 0) mrb->rsize = 16;
        else mrb->rsize *= 2;
        mrb->rescue = mrb_realloc(mrb, mrb->rescue, sizeof(mrb_code*) * mrb->rsize);
      }
      mrb->rescue[mrb->ci->ridx++] = pc + GETARG_sBx(i);
      NEXT;
    }

    CASE(OP_RESCUE) {
      /* A      R(A) := exc; clear(exc) */
      SET_OBJ_VALUE(regs[GETARG_A(i)],mrb->exc);
      mrb->exc = 0;
      NEXT;
    }

    CASE(OP_POPERR) {
      int a = GETARG_A(i);

      while (a--) {
        mrb->ci->ridx--;
      }
      NEXT;
    }

    CASE(OP_RAISE) {
      /* A      raise(R(A)) */
      mrb->exc = mrb_object(regs[GETARG_A(i)]);
      goto L_RAISE;
    }

    CASE(OP_EPUSH) {
      /* Bx     ensure_push(SEQ[Bx]) */
      struct RProc *p;

      p = mrb_closure_new(mrb, mrb->irep[irep->idx+GETARG_Bx(i)]);
      /* push ensure_stack */
      if (mrb->esize <= mrb->ci->eidx) {
        if (mrb->esize == 0) mrb->esize = 16;
        else mrb->esize *= 2;
        mrb->ensure = mrb_realloc(mrb, mrb->ensure, sizeof(struct RProc*) * mrb->esize);
      }
      mrb->ensure[mrb->ci->eidx++] = p;
      NEXT;
    }

    CASE(OP_EPOP) {
      /* A      A.times{ensure_pop().call} */
      int n;
      int a = GETARG_A(i);

      for (n=0; n<a; n++) {
        ecall(mrb, --mrb->ci->eidx);
      }
      NEXT;
    }

  L_SEND:
    CASE(OP_SEND) {
      /* A B C  R(A) := call(R(A),Sym(B),R(A+1),... ,R(A+C-1)) */
      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) {
        mrb_value sym = mrb_symbol_value(mid);

        mid = mrb_intern(mrb, "method_missing");
        m = mrb_method_search_vm(mrb, &c, mid);
        if (n == CALL_MAXARGS) {
          mrb_ary_unshift(mrb, regs[a+1], sym);
        }
        else {
          memmove(regs+a+2, regs+a+1, sizeof(mrb_value)*(n+1));
          regs[a+1] = sym;
          n++;
        }
      }

      /* push callinfo */
      ci = cipush(mrb);
      ci->mid = mid;
      ci->proc = m;
      ci->stackidx = mrb->stack - mrb->stbase;
      ci->argc = n;
      if (ci->argc == CALL_MAXARGS) ci->argc = -1;
      ci->target_class = m->target_class;
      ci->pc = pc + 1;

      /* prepare stack */
      mrb->stack += a;

      if (MRB_PROC_CFUNC_P(m)) {
        mrb->stack[0] = m->body.func(mrb, recv);
        mrb->arena_idx = ai;
        if (mrb->exc) goto L_RAISE;
        /* pop stackpos */
        mrb->stack = mrb->stbase + ci->stackidx;
        cipop(mrb);
        NEXT;
      }
      else {
        /* fill callinfo */
        ci->acc = a;

        /* setup environment for calling method */
        proc = mrb->ci->proc = m;
        irep = m->body.irep;
        pool = irep->pool;
        syms = irep->syms;
        ci->nregs = irep->nregs;
        if (ci->argc < 0) {
          stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3);
        }
        else {
          stack_extend(mrb, irep->nregs,  ci->argc+2);
        }
        regs = mrb->stack;
        pc = irep->iseq;
        JUMP;
      }
    }

    CASE(OP_FSEND) {
      /* A B C  R(A) := fcall(R(A),Sym(B),R(A+1),... ,R(A+C)) */
      NEXT;
    }

    CASE(OP_VSEND) {
      /* A B    R(A) := vcall(R(A),Sym(B)) */
      NEXT;
    }

    CASE(OP_CALL) {
      /* A      R(A) := self.call(frame.argc, frame.argv) */
      mrb_callinfo *ci;
      mrb_value recv = mrb->stack[0];
      struct RProc *m = mrb_proc_ptr(recv);

      /* replace callinfo */
      ci = mrb->ci;
      ci->target_class = m->target_class;
      ci->proc = m;
      if (m->env) {
        ci->mid = m->env->mid;
        if (!m->env->stack) {
          m->env->stack = mrb->stack;
        }
      }

      /* prepare stack */
      if (MRB_PROC_CFUNC_P(m)) {
        mrb->stack[0] = m->body.func(mrb, recv);
        mrb->arena_idx = ai;
        if (mrb->exc) goto L_RAISE;
        /* pop stackpos */
        regs = mrb->stack = mrb->stbase + ci->stackidx;
        cipop(mrb);
        NEXT;
      }
      else {
        /* setup environment for calling method */
        proc = m;
        irep = m->body.irep;
        pool = irep->pool;
        syms = irep->syms;
        ci->nregs = irep->nregs;
        if (ci->argc < 0) {
          stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3);
        }
        else {
          stack_extend(mrb, irep->nregs,  ci->argc+2);
        }
        regs = mrb->stack;
        regs[0] = m->env->stack[0];
        pc = m->body.irep->iseq;
        JUMP;
      }
    }

    CASE(OP_SUPER) {
      /* A B C  R(A) := super(R(A+1),... ,R(A+C-1)) */
      mrb_value recv;
      mrb_callinfo *ci = mrb->ci;
      struct RProc *m;
      struct RClass *c;
      mrb_sym mid = ci->mid;
      int a = GETARG_A(i);
      int n = GETARG_C(i);

      recv = regs[0];
      c = mrb->ci->proc->target_class->super;
      m = mrb_method_search_vm(mrb, &c, mid);
      if (!m) {
        c = mrb->ci->proc->target_class;
        mid = mrb_intern(mrb, "method_missing");
        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 {
          memmove(regs+a+2, regs+a+1, sizeof(mrb_value)*(n+1));
          regs[a+1] = mrb_symbol_value(ci->mid);
          n++;
        }
      }

      /* push callinfo */
      ci = cipush(mrb);
      ci->mid = mid;
      ci->proc = m;
      ci->stackidx = mrb->stack - mrb->stbase;
      ci->argc = n;
      if (ci->argc == CALL_MAXARGS) ci->argc = -1;
      ci->target_class = m->target_class;
      ci->pc = pc + 1;

      /* prepare stack */
      mrb->stack += a;
      mrb->stack[0] = recv;

      if (MRB_PROC_CFUNC_P(m)) {
        mrb->stack[0] = m->body.func(mrb, recv);
        mrb->arena_idx = ai;
        if (mrb->exc) goto L_RAISE;
        /* pop stackpos */
        mrb->stack = mrb->stbase + ci->stackidx;
        cipop(mrb);
        NEXT;
      }
      else {
        /* 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;
        if (ci->argc < 0) {
          stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3);
        }
        else {
          stack_extend(mrb, irep->nregs,  ci->argc+2);
        }
        regs = mrb->stack;
        pc = irep->iseq;
        JUMP;
      }
    }

    CASE(OP_ARGARY) {
      /* A Bx   R(A) := argument array (16=6:1:5:4) */
      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 {
        struct REnv *e = uvenv(mrb, lv-1);
        stack = e->stack + 1;
      }
      if (r == 0) {
        regs[a] = mrb_ary_new_elts(mrb, m1+m2, stack);
      }
      else {
        mrb_value *pp;
        struct RArray *rest;
        int len = 0;

        if (stack[m1].tt == MRB_TT_ARRAY) {
          struct RArray *ary = mrb_ary_ptr(stack[m1]);

          pp = ary->buf;
          len = ary->len;
        }
        regs[a] = mrb_ary_new_capa(mrb, m1+len+m2);
        rest = mrb_ary_ptr(regs[a]);
        memcpy(rest->buf, stack, sizeof(mrb_value)*m1);
        if (len > 0) {
          memcpy(rest->buf+m1, pp, sizeof(mrb_value)*len);
        }
        if (m2 > 0) {
          memcpy(rest->buf+m1+len, stack+m1+1, sizeof(mrb_value)*m2);
        }
        rest->len = m1+len+m2;
      }
      regs[a+1] = stack[m1+r+m2];
      NEXT;
    }

    CASE(OP_ENTER) {
      /* Ax             arg setup according to flags (24=5:5:1:5:5:1:1) */
      /* number of optional arguments times OP_JMP should follow */
      int ax = GETARG_Ax(i);
      int m1 = (ax>>18)&0x1f;
      int o  = (ax>>13)&0x1f;
      int r  = (ax>>12)&0x1;
      int m2 = (ax>>7)&0x1f;
      /* unused
      int k  = (ax>>2)&0x1f;
      int kd = (ax>>1)&0x1;
      int b  = (ax>>0)& 0x1;
      */
      int argc = mrb->ci->argc;
      mrb_value *argv = regs+1;
      int len = m1 + o + r + m2;

      if (argc < 0) {
        struct RArray *ary = mrb_ary_ptr(regs[1]);
        argv = ary->buf;
        argc = ary->len;
        regs[len+2] = regs[1];  /* save argary in register */
      }
      if (mrb->ci->proc && MRB_PROC_STRICT_P(mrb->ci->proc)) {
        if (argc >= 0) {
          if (argc < m1 + m2 || (r == 0 && argc > len)) {
            fprintf(stderr, "'%s': wrong number of arguments (%d for %d)\n",
                    mrb_sym2name(mrb, mrb->ci->mid),
                    mrb->ci->argc, m1+m2);
            exit(1);
          }
        }
      }
      else if (len > 1 && argc == 1 && argv[0].tt == MRB_TT_ARRAY) {
        argc = mrb_ary_ptr(argv[0])->len;
        argv = mrb_ary_ptr(argv[0])->buf;
      }
      mrb->ci->argc = len;
      if (argc < len) {
        regs[len+1] = argv[argc]; /* move block */
        memmove(&regs[1], argv, sizeof(mrb_value)*(argc-m2)); /* m1 + o */
        memmove(&regs[len-m2+1], &argv[argc-m2], sizeof(mrb_value)*m2); /* m2 */
        if (r) {                  /* r */
          regs[m1+o+1] = mrb_ary_new_capa(mrb, 0);
        }
        pc += argc - m1 - m2 + 1;
      }
      else {
        memmove(&regs[1], argv, sizeof(mrb_value)*(m1+o)); /* m1 + o */
        if (r) {                  /* r */
          regs[m1+o+1] = mrb_ary_new_elts(mrb, argc-m1-o-m2, argv+m1+o);
        }
        memmove(&regs[m1+o+r+1], &argv[argc-m2], sizeof(mrb_value)*m2);
        regs[len+1] = argv[argc]; /* move block */
        pc += o + 1;
      }
      JUMP;
    }

    CASE(OP_KARG) {
      /* A B C          R(A) := kdict[Sym(B)]; if C kdict.rm(Sym(B)) */
      /* if C == 2; raise unless kdict.empty? */
      /* OP_JMP should follow to skip init code */
      NEXT;
    }

    CASE(OP_KDICT) {
      /* A C            R(A) := kdict */
      NEXT;
    }

    CASE(OP_RETURN) {
      /* A      return R(A) */
    L_RETURN:
      if (mrb->ci->env) {
        struct REnv *e = mrb->ci->env;
        int len = (int)e->flags;
        mrb_value *p = mrb_malloc(mrb, sizeof(mrb_value)*len);

        e->cioff = -1;
        memcpy(p, e->stack, sizeof(mrb_value)*len);
        e->stack = p;
      }

      if (mrb->exc) {
        mrb_callinfo *ci;

      L_RAISE:
        ci = mrb->ci;
        if (ci == mrb->cibase) goto L_STOP;
        while (ci[0].ridx == ci[-1].ridx) {
          cipop(mrb);
          ci = mrb->ci;
          if (ci == mrb->cibase) {
            if (ci->ridx == 0) goto L_STOP;
            break;
          }
        }
        irep = ci->proc->body.irep;
        pool = irep->pool;
        syms = irep->syms;
        regs = mrb->stack = mrb->stbase + ci->stackidx;
        pc = mrb->rescue[--ci->ridx];
      }
      else {
        mrb_callinfo *ci = mrb->ci;
        int acc, eidx = mrb->ci->eidx;
        mrb_value v = regs[GETARG_A(i)];

        switch (GETARG_B(i)) {
        case OP_R_NORMAL:
          ci = mrb->ci;
          break;
        case OP_R_BREAK:
          if (proc->env->cioff < 0) {
            localjump_error(mrb, "break");
            goto L_RAISE;
          }
          ci = mrb->ci = mrb->cibase + proc->env->cioff + 1;
          break;
        case OP_R_RETURN:
          if (proc->env->cioff < 0) {
            localjump_error(mrb, "return");
          }
          ci = mrb->ci = mrb->cibase + proc->env->cioff;
          break;
        default:
          /* cannot happen */
          break;
        }
        cipop(mrb);
        acc = ci->acc;
        pc = ci->pc;
        regs = mrb->stack = mrb->stbase + ci->stackidx;
        while (eidx > mrb->ci->eidx) {
          ecall(mrb, --eidx);
        }
        if (acc < 0) {
          mrb->jmp = prev_jmp;
          return v;
        }
        DEBUG(printf("from :%s\n", mrb_sym2name(mrb, ci->mid)));
        proc = mrb->ci->proc;
        irep = proc->body.irep;
        pool = irep->pool;
        syms = irep->syms;

        regs[acc] = v;
      }
      JUMP;
    }

    CASE(OP_TAILCALL) {
      /* A B C  return call(R(A),Sym(B),R(A+1),... ,R(A+C-1)) */
      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) {
        mrb_value sym = mrb_symbol_value(mid);

        mid = mrb_intern(mrb, "method_missing");
        m = mrb_method_search_vm(mrb, &c, mid);
        if (n == CALL_MAXARGS) {
          mrb_ary_unshift(mrb, regs[a+1], sym);
        }
        else {
          memmove(regs+a+2, regs+a+1, sizeof(mrb_value)*(n+1));
          regs[a+1] = sym;
          n++;
        }
      }


      /* replace callinfo */
      mrb->ci = ci = &mrb->ci[-1];
      ci->mid = mid;
      ci->target_class = m->target_class;
      ci->argc = n;
      if (ci->argc == CALL_MAXARGS) ci->argc = -1;

      /* move stack */
      memmove(mrb->stack, &regs[a], (ci->argc+1)*sizeof(mrb_value));

      if (MRB_PROC_CFUNC_P(m)) {
        mrb->stack[0] = m->body.func(mrb, recv);
        mrb->arena_idx = ai;
        goto L_RETURN;
      }
      else {
        /* setup environment for calling method */
        irep = m->body.irep;
        pool = irep->pool;
        syms = irep->syms;
        if (ci->argc < 0) {
          stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3);
        }
        else {
          stack_extend(mrb, irep->nregs,  ci->argc+2);
        }
        regs = mrb->stack;
        pc = irep->iseq;
      }
      JUMP;
    }

    CASE(OP_BLKPUSH) {
      /* A Bx   R(A) := block (16=6:1:5:4) */
      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 {
        struct REnv *e = uvenv(mrb, lv-1);
        stack = e->stack + 1;
      }
      regs[a] = stack[m1+r+m2];
      NEXT;
    }

#define TYPES2(a,b) (((((int)(a))<<8)|((int)(b)))&0xffff)
#define OP_MATH_BODY(op,v1,v2) do {\
  regs[a].value.v1 = regs[a].value.v1 op regs[a+1].value.v2;\
} while(0)

#define OP_MATH(op) do {\
  int a = GETARG_A(i);\
  /* 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):\
    OP_MATH_BODY(op,i,i);                  \
    break;\
  case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):\
    {\
      mrb_int x = regs[a].value.i;\
      mrb_float y = regs[a+1].value.f;\
      SET_FLOAT_VALUE(regs[a], (mrb_float)x op y);\
    }\
    break;\
  case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):\
    OP_MATH_BODY(op,f,i);\
    break;\
  case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):\
    OP_MATH_BODY(op,f,f);\
    break;\
  default:\
    i = MKOP_ABC(OP_SEND, a, GETARG_B(i), GETARG_C(i));\
    goto L_SEND;\
  }\
} while (0)

    CASE(OP_ADD) {
      /* A B C  R(A) := R(A)+R(A+1) (Syms[B]=:+,C=1)*/
      int a = GETARG_A(i);

      switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) {
      case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM):
        OP_MATH_BODY(+,i,i);
        break;
      case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):
        {
          mrb_int x = regs[a].value.i;
          mrb_float y = regs[a+1].value.f;
          SET_FLOAT_VALUE(regs[a], (mrb_float)x + y);
        }
        break;
      case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):
        OP_MATH_BODY(+,f,i);
        break;
      case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):
        OP_MATH_BODY(+,f,f);
        break;
      case TYPES2(MRB_TT_STRING,MRB_TT_STRING):
        regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]);
        break;
      default:
        i = MKOP_ABC(OP_SEND, a, GETARG_B(i), GETARG_C(i));
        goto L_SEND;
      }
      NEXT;
    }

    CASE(OP_SUB) {
      /* A B C  R(A) := R(A)-R(A+1) (Syms[B]=:-,C=1)*/
      OP_MATH(-);
      NEXT;
    }

    CASE(OP_MUL) {
      /* A B C  R(A) := R(A)*R(A+1) (Syms[B]=:*,C=1)*/
      OP_MATH(*);
      NEXT;
    }

    CASE(OP_DIV) {
      /* A B C  R(A) := R(A)/R(A+1) (Syms[B]=:/,C=1)*/
      OP_MATH(/);
      NEXT;
    }

    CASE(OP_ADDI) {
      /* A B C  R(A) := R(A)+C (Syms[B]=:+)*/
      int a = GETARG_A(i);

      /* need to check if + is overridden */
      switch (mrb_type(regs[a])) {
      case MRB_TT_FIXNUM:
        regs[a].value.i += GETARG_C(i);
        break;
      case MRB_TT_FLOAT:
        regs[a].value.f += GETARG_C(i);
        break;
      default:
        SET_INT_VALUE(regs[a+1], GETARG_C(i));
        i = MKOP_ABC(OP_SEND, a, GETARG_B(i), 1);
        goto L_SEND;
      }
      NEXT;
    }

    CASE(OP_SUBI) {
      /* A B C  R(A) := R(A)-C (Syms[B]=:+)*/
      int a = GETARG_A(i);

      /* need to check if + is overridden */
      switch (mrb_type(regs[a])) {
      case MRB_TT_FIXNUM:
        regs[a].value.i -= GETARG_C(i);
        break;
      case MRB_TT_FLOAT:
        regs[a].value.f -= GETARG_C(i);
        break;
      default:
        SET_INT_VALUE(regs[a+1], GETARG_C(i));
        i = MKOP_ABC(OP_SEND, a, GETARG_B(i), 1);
        goto L_SEND;
      }
      NEXT;
    }

#define OP_CMP_BODY(op,v1,v2) do {\
  if (regs[a].value.v1 op regs[a+1].value.v2) {\
    SET_TRUE_VALUE(regs[a]);\
  }\
  else {\
    SET_FALSE_VALUE(regs[a]);\
  }\
} while(0)

#define OP_CMP(op) do {\
  int a = GETARG_A(i);\
  /* 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):\
    OP_CMP_BODY(op,i,i);                   \
    break;\
  case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):\
    OP_CMP_BODY(op,i,f);\
    break;\
  case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):\
    OP_CMP_BODY(op,f,i);\
    break;\
  case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):\
    OP_CMP_BODY(op,f,f);\
    break;\
  default:\
    i = MKOP_ABC(OP_SEND, a, GETARG_B(i), GETARG_C(i));\
    goto L_SEND;\
  }\
} while (0)

    CASE(OP_EQ) {
      /* A B C  R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/
      OP_CMP(==);
      NEXT;
    }

    CASE(OP_LT) {
      /* A B C  R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/
      OP_CMP(<);
      NEXT;
    }

    CASE(OP_LE) {
      /* A B C  R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/
      OP_CMP(<=);
      NEXT;
    }

    CASE(OP_GT) {
      /* A B C  R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/
      OP_CMP(>);
      NEXT;
    }

    CASE(OP_GE) {
      /* A B C  R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/
      OP_CMP(>=);
      NEXT;
    }

    CASE(OP_ARRAY) {
      /* A B C          R(A) := ary_new(R(B),R(B+1)..R(B+C)) */
      int b = GETARG_B(i);
      int lim = b+GETARG_C(i);
      mrb_value ary = mrb_ary_new_capa(mrb, GETARG_C(i));

      while (b < lim) {
        mrb_ary_push(mrb, ary, regs[b++]);
      }
      regs[GETARG_A(i)] = ary;
      NEXT;
    }

    CASE(OP_ARYCAT) {
      /* A B            mrb_ary_concat(R(A),R(B)) */
      mrb_ary_concat(mrb, regs[GETARG_A(i)],
                     mrb_ary_splat(mrb, regs[GETARG_B(i)]));
      NEXT;
    }

    CASE(OP_ARYPUSH) {
      /* A B            R(A).push(R(B)) */
      mrb_ary_push(mrb, regs[GETARG_A(i)], regs[GETARG_B(i)]);
      NEXT;
    }

    CASE(OP_AREF) {
      /* A B C          R(A) := R(B)[C] */
      int a = GETARG_A(i);
      int c = GETARG_C(i);
      mrb_value v = regs[GETARG_B(i)];

      if (v.tt != MRB_TT_ARRAY) {
        if (c == 0) {
          regs[GETARG_A(i)] = v;
        }
        else {
          SET_NIL_VALUE(regs[a]);
        }
      }
      else {
        regs[GETARG_A(i)] = mrb_ary_ref(mrb, v, c);
      }
      NEXT;
    }

    CASE(OP_ASET) {
      /* A B C          R(B)[C] := R(A) */
      mrb_ary_set(mrb, regs[GETARG_B(i)], GETARG_C(i), regs[GETARG_A(i)]);
      NEXT;
    }

    CASE(OP_APOST) {
      /* A B C  *R(A),R(A+1)..R(A+C) := R(A) */
      int a = GETARG_A(i);
      mrb_value v = regs[a];
      int pre  = GETARG_B(i);
      int post = GETARG_C(i);

      if (v.tt != MRB_TT_ARRAY) {
        regs[a++] = mrb_ary_new_capa(mrb, 0);
        while (post--) {
          SET_NIL_VALUE(regs[a]);
          a++;
        }
      }
      else {
        struct RArray *ary = mrb_ary_ptr(v);
        size_t len = ary->len;
        int i;

        if (len > pre + post) {
          regs[a++] = mrb_ary_new_elts(mrb, len - pre - post, ary->buf+pre);
          while (post--) {
            regs[a++] = ary->buf[len-post-1];
          }
        }
        else {
          regs[a++] = mrb_ary_new_capa(mrb, 0);
          for (i=0; i+pre<len; i++) {
            regs[a+i] = ary->buf[pre+i];
          }
          while (i < post) {
            SET_NIL_VALUE(regs[a+i]);
            i++;
          }
        }
      }
      NEXT;
    }

    CASE(OP_STRING) {
      /* A Bx           R(A) := str_new(Lit(Bx)) */
      regs[GETARG_A(i)] = mrb_str_literal(mrb, pool[GETARG_Bx(i)]);
      NEXT;
    }

    CASE(OP_STRCAT) {
      /* A B    R(A).concat(R(B)) */
      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) {
        mrb_hash_set(mrb, hash, regs[b], regs[b+1]);
        b+=2;
      }
      regs[GETARG_A(i)] = hash;
      NEXT;
    }

    CASE(OP_LAMBDA) {
      /* A b c  R(A) := lambda(SEQ[b],c) (b:c = 14:2) */
      struct RProc *p;
      int c = GETARG_c(i);

      if (c & OP_L_CAPTURE) {
        p = mrb_closure_new(mrb, mrb->irep[irep->idx+GETARG_b(i)]);
      }
      else {
        p = mrb_proc_new(mrb, mrb->irep[irep->idx+GETARG_b(i)]);
      }
      if (c & OP_L_STRICT) p->flags |= MRB_PROC_STRICT;
      regs[GETARG_A(i)] = mrb_obj_value(p);
      NEXT;
    }

    CASE(OP_OCLASS) {
      /* A      R(A) := ::Object */
      regs[GETARG_A(i)] = mrb_obj_value(mrb->object_class);
      NEXT;
    }

    CASE(OP_CLASS) {
      /* A B    R(A) := newclass(R(A),Sym(B),R(A+1)) */
      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)) {
        base = mrb_obj_value(mrb->ci->target_class);
      }
      c = mrb_vm_define_class(mrb, base, super, id);
      regs[a] = mrb_obj_value(c);
      NEXT;
    }

    CASE(OP_MODULE) {
      /* A B            R(A) := newmodule(R(A),Sym(B)) */
      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)) {
        base = mrb_obj_value(mrb->ci->target_class);
      }
      c = mrb_vm_define_module(mrb, base, id);
      regs[a] = mrb_obj_value(c);
      NEXT;
    }

    CASE(OP_EXEC) {
      /* A Bx   R(A) := blockexec(R(A),SEQ[Bx]) */
      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;
      ci->stackidx = mrb->stack - mrb->stbase;
      ci->argc = 0;
      ci->target_class = mrb_class_ptr(regs[GETARG_A(i)]);

      p = mrb_proc_new(mrb, mrb->irep[irep->idx+GETARG_Bx(i)]);
      p->target_class = ci->target_class;
      ci->proc = p;

      if (MRB_PROC_CFUNC_P(p)) {
        mrb->stack[0] = p->body.func(mrb, recv);
        mrb->arena_idx = ai;
        if (mrb->exc) goto L_RAISE;
        /* pop stackpos */
        regs = mrb->stack = mrb->stbase + ci->stackidx;
        cipop(mrb);
        NEXT;
      }
      else {
        /* setup environment for calling method */
        irep = p->body.irep;
        pool = irep->pool;
        syms = irep->syms;
        mrb->stack += a;
        stack_extend(mrb, irep->nregs, 1);
        regs = mrb->stack;
        pc = irep->iseq;
        JUMP;
      }
    }

    CASE(OP_METHOD) {
      /* A B            R(A).newmethod(Sym(B),R(A+1)) */
      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]);
      NEXT;
    }

    CASE(OP_SCLASS) {
      /* A B    R(A) := R(B).singleton_class */
      regs[GETARG_A(i)] = mrb_singleton_class(mrb, regs[GETARG_B(i)]);
      NEXT;
    }

    CASE(OP_TCLASS) {
      /* A B    R(A) := target_class */
      regs[GETARG_A(i)] = mrb_obj_value(mrb->ci->target_class);
      NEXT;
    }

    CASE(OP_RANGE) {
      /* A B C  R(A) := range_new(R(B),R(B+1),C) */
      int b = GETARG_B(i);
      regs[GETARG_A(i)] = mrb_range_new(mrb, regs[b], regs[b+1], GETARG_C(i));
      NEXT;
    }

    CASE(OP_DEBUG) {
      /* A      debug print R(A),R(B),R(C) */
      printf("OP_DEBUG %d %d %d\n", GETARG_A(i), GETARG_B(i), GETARG_C(i));
      NEXT;
    }

    CASE(OP_STOP) {
      /*        stop VM */
    L_STOP:
      mrb->jmp = prev_jmp;
      return mrb_nil_value();
    }

    CASE(OP_ERR) {
      /* Bx     raise RuntimeError with message Lit(Bx) */
      mrb_value msg = pool[GETARG_Bx(i)];
      mrb_value exc = mrb_exc_new3(mrb, mrb->eRuntimeError_class, msg);

      mrb->exc = mrb_object(exc);
      goto L_RAISE;
    }
  }
  END_DISPACTH;
}
Example #24
0
mrb_value
mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self)
{
  /* assert(mrb_proc_cfunc_p(proc)) */
  mrb_irep *irep = proc->body.irep;
  mrb_code *pc = irep->iseq;
  mrb_value *pool = irep->pool;
  mrb_sym *syms = irep->syms;
  mrb_value *regs = NULL;
  mrb_code i;
  int ai = mrb_gc_arena_save(mrb);
  jmp_buf *prev_jmp = (jmp_buf *)mrb->jmp;
  jmp_buf c_jmp;

#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,
    &&L_OP_SEND, &&L_OP_SENDB, &&L_OP_FSEND,
    &&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


  if (setjmp(c_jmp) == 0) {
    mrb->jmp = &c_jmp;
  }
  else {
    goto L_RAISE;
  }
  if (!mrb->stack) {
    stack_init(mrb);
  }
  mrb->ci->proc = proc;
  mrb->ci->nregs = irep->nregs + 2;
  regs = mrb->stack;
  regs[0] = self;

  INIT_DISPATCH {
    CASE(OP_NOP) {
      /* do nothing */
      NEXT;
    }

    CASE(OP_MOVE) {
      /* A B    R(A) := R(B) */
      regs[GETARG_A(i)] = regs[GETARG_B(i)];
      NEXT;
    }

    CASE(OP_LOADL) {
      /* A Bx   R(A) := Pool(Bx) */
      regs[GETARG_A(i)] = pool[GETARG_Bx(i)];
      NEXT;
    }

    CASE(OP_LOADI) {
      /* A Bx   R(A) := sBx */
      SET_INT_VALUE(regs[GETARG_A(i)], GETARG_sBx(i));
      NEXT;
    }

    CASE(OP_LOADSYM) {
      /* A B    R(A) := Sym(B) */
      SET_SYM_VALUE(regs[GETARG_A(i)], syms[GETARG_Bx(i)]);
      NEXT;
    }

    CASE(OP_LOADSELF) {
      /* A      R(A) := self */
      regs[GETARG_A(i)] = regs[0];
      NEXT;
    }

    CASE(OP_LOADT) {
      /* A      R(A) := true */
      SET_TRUE_VALUE(regs[GETARG_A(i)]);
      NEXT;
    }

    CASE(OP_LOADF) {
      /* A      R(A) := false */
      SET_FALSE_VALUE(regs[GETARG_A(i)]);
      NEXT;
    }

    CASE(OP_GETGLOBAL) {
      /* A B    R(A) := getglobal(Sym(B)) */
      regs[GETARG_A(i)] = mrb_gv_get(mrb, syms[GETARG_Bx(i)]);
      NEXT;
    }

    CASE(OP_SETGLOBAL) {
      /* setglobal(Sym(b), R(A)) */
      mrb_gv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]);
      NEXT;
    }

    CASE(OP_GETSPECIAL) {
      /* A Bx   R(A) := Special[Bx] */
      regs[GETARG_A(i)] = mrb_vm_special_get(mrb, GETARG_Bx(i));
      NEXT;
    }

    CASE(OP_SETSPECIAL) {
      /* A Bx   Special[Bx] := R(A) */
      mrb_vm_special_set(mrb, GETARG_Bx(i), regs[GETARG_A(i)]);
      NEXT;
    }

    CASE(OP_GETIV) {
      /* A Bx   R(A) := ivget(Bx) */
      regs[GETARG_A(i)] = mrb_vm_iv_get(mrb, syms[GETARG_Bx(i)]);
      NEXT;
    }

    CASE(OP_SETIV) {
      /* ivset(Sym(B),R(A)) */
      mrb_vm_iv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]);
      NEXT;
    }

    CASE(OP_GETCV) {
      /* A B    R(A) := ivget(Sym(B)) */
      regs[GETARG_A(i)] = mrb_vm_cv_get(mrb, syms[GETARG_Bx(i)]);
      NEXT;
    }

    CASE(OP_SETCV) {
      /* ivset(Sym(B),R(A)) */
      mrb_vm_cv_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]);
      NEXT;
    }

    CASE(OP_GETCONST) {
      /* A B    R(A) := constget(Sym(B)) */
      regs[GETARG_A(i)] = mrb_vm_const_get(mrb, syms[GETARG_Bx(i)]);
      NEXT;
    }

    CASE(OP_SETCONST) {
      /* A B    constset(Sym(B),R(A)) */
      mrb_vm_const_set(mrb, syms[GETARG_Bx(i)], regs[GETARG_A(i)]);
      NEXT;
    }

    CASE(OP_GETMCNST) {
      /* A B C  R(A) := R(C)::Sym(B) */
      int a = GETARG_A(i);

      regs[a] = mrb_const_get(mrb, regs[a], syms[GETARG_Bx(i)]);
      NEXT;
    }

    CASE(OP_SETMCNST) {
      /* A B C  R(A+1)::Sym(B) := R(A) */
      int a = GETARG_A(i);

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

    CASE(OP_GETUPVAR) {
      /* A B C  R(A) := uvget(B,C) */

      regs[GETARG_A(i)] = uvget(mrb, GETARG_C(i), GETARG_B(i));
      NEXT;
    }

    CASE(OP_SETUPVAR) {
      /* A B C  uvset(B,C,R(A)) */
      uvset(mrb, GETARG_C(i), GETARG_B(i), regs[GETARG_A(i)]);
      NEXT;
    }

    CASE(OP_JMP) {
      /* sBx    pc+=sBx */
      pc += GETARG_sBx(i);
      JUMP;
    }

    CASE(OP_JMPIF) {
      /* A sBx  if R(A) pc+=sBx */
      if (mrb_test(regs[GETARG_A(i)])) {
        pc += GETARG_sBx(i);
        JUMP;
      }
      NEXT;
    }

    CASE(OP_JMPNOT) {
      /* A sBx  if R(A) pc+=sBx */
      if (!mrb_test(regs[GETARG_A(i)])) {
        pc += GETARG_sBx(i);
        JUMP;
      }
      NEXT;
    }

    CASE(OP_ONERR) {
      /* sBx    pc+=sBx on exception */
      if (mrb->rsize <= mrb->ci->ridx) {
        if (mrb->rsize == 0) mrb->rsize = 16;
        else mrb->rsize *= 2;
        mrb->rescue = (mrb_code **)mrb_realloc(mrb, mrb->rescue, sizeof(mrb_code*) * mrb->rsize);
      }
      mrb->rescue[mrb->ci->ridx++] = pc + GETARG_sBx(i);
      NEXT;
    }

    CASE(OP_RESCUE) {
      /* A      R(A) := exc; clear(exc) */
      SET_OBJ_VALUE(regs[GETARG_A(i)], mrb->exc);
      mrb->exc = 0;
      NEXT;
    }

    CASE(OP_POPERR) {
      int a = GETARG_A(i);

      while (a--) {
        mrb->ci->ridx--;
      }
      NEXT;
    }

    CASE(OP_RAISE) {
      /* A      raise(R(A)) */
      mrb->exc = (struct RObject*)mrb_object(regs[GETARG_A(i)]);
      goto L_RAISE;
    }

    CASE(OP_EPUSH) {
      /* Bx     ensure_push(SEQ[Bx]) */
      struct RProc *p;

      p = mrb_closure_new(mrb, mrb->irep[irep->idx+GETARG_Bx(i)]);
      /* push ensure_stack */
      if (mrb->esize <= mrb->ci->eidx) {
        if (mrb->esize == 0) mrb->esize = 16;
        else mrb->esize *= 2;
        mrb->ensure = (struct RProc **)mrb_realloc(mrb, mrb->ensure, sizeof(struct RProc*) * mrb->esize);
      }
      mrb->ensure[mrb->ci->eidx++] = p;
      mrb_gc_arena_restore(mrb, ai);
      NEXT;
    }

    CASE(OP_EPOP) {
      /* A      A.times{ensure_pop().call} */
      int n;
      int a = GETARG_A(i);

      for (n=0; n<a; n++) {
        ecall(mrb, --mrb->ci->eidx);
      }
      mrb_gc_arena_restore(mrb, ai);
      NEXT;
    }

    CASE(OP_LOADNIL) {
      /* A B    R(A) := nil */
      int a = GETARG_A(i);

      SET_NIL_VALUE(regs[a]);
      NEXT;
    }

    CASE(OP_SENDB) {
      /* fall through */
    };

  L_SEND:
    CASE(OP_SEND) {
      /* A B C  R(A) := call(R(A),Sym(B),R(A+1),... ,R(A+C-1)) */
      int a = GETARG_A(i);
      int n = GETARG_C(i);
      struct RProc *m;
      struct RClass *c;
      mrb_callinfo *ci;
      mrb_value recv, result;
      mrb_sym mid = syms[GETARG_B(i)];

      recv = regs[a];
      if (GET_OPCODE(i) != OP_SENDB) {
	if (n == CALL_MAXARGS) {
	  SET_NIL_VALUE(regs[a+2]);
	}
	else {
	  SET_NIL_VALUE(regs[a+n+1]);
	}
      }
      c = mrb_class(mrb, recv);
      m = mrb_method_search_vm(mrb, &c, mid);
      if (!m) {
        mrb_value sym = mrb_symbol_value(mid);

        mid = mrb_intern(mrb, "method_missing");
        m = mrb_method_search_vm(mrb, &c, mid);
        if (n == CALL_MAXARGS) {
          mrb_ary_unshift(mrb, regs[a+1], sym);
        }
        else {
          memmove(regs+a+2, regs+a+1, sizeof(mrb_value)*(n+1));
	  regs[a+1] = sym;
          n++;
        }
      }

      /* push callinfo */
      ci = cipush(mrb);
      ci->mid = mid;
      ci->proc = m;
      ci->stackidx = mrb->stack - mrb->stbase;
      ci->argc = n;
      if (ci->argc == CALL_MAXARGS) ci->argc = -1;
      ci->target_class = c;
      ci->pc = pc + 1;
      ci->acc = a;

      /* prepare stack */
      mrb->stack += a;

      if (MRB_PROC_CFUNC_P(m)) {
        if (n == CALL_MAXARGS) {
          ci->nregs = 3;
        }
        else {
          ci->nregs = n + 2;
        }
        result = m->body.func(mrb, recv);
        mrb->stack[0] = result;
        mrb_gc_arena_restore(mrb, ai);
        if (mrb->exc) goto L_RAISE;
        /* pop stackpos */
        regs = mrb->stack = mrb->stbase + mrb->ci->stackidx;
        cipop(mrb);
        NEXT;
      }
      else {
        /* setup environment for calling method */
        proc = mrb->ci->proc = m;
        irep = m->body.irep;
        pool = irep->pool;
        syms = irep->syms;
        ci->nregs = irep->nregs;
        if (ci->argc < 0) {
          stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3);
        }
        else {
          stack_extend(mrb, irep->nregs,  ci->argc+2);
        }
        regs = mrb->stack;
        pc = irep->iseq;
        JUMP;
      }
    }

    CASE(OP_FSEND) {
      /* A B C  R(A) := fcall(R(A),Sym(B),R(A+1),... ,R(A+C)) */
      NEXT;
    }

    CASE(OP_CALL) {
      /* A      R(A) := self.call(frame.argc, frame.argv) */
      mrb_callinfo *ci;
      mrb_value recv = mrb->stack[0];
      struct RProc *m = mrb_proc_ptr(recv);

      /* replace callinfo */
      ci = mrb->ci;
      ci->target_class = m->target_class;
      ci->proc = m;
      if (m->env) {
	if (m->env->mid) {
	  ci->mid = m->env->mid;
	}
        if (!m->env->stack) {
          m->env->stack = mrb->stack;
        }
      }

      /* prepare stack */
      if (MRB_PROC_CFUNC_P(m)) {
	recv = m->body.func(mrb, recv);
        mrb_gc_arena_restore(mrb, ai);
        if (mrb->exc) goto L_RAISE;
        /* pop stackpos */
	ci = mrb->ci;
        regs = mrb->stack = mrb->stbase + ci->stackidx;
	regs[ci->acc] = recv;
	pc = ci->pc;
        cipop(mrb);
        irep = mrb->ci->proc->body.irep;
        pool = irep->pool;
        syms = irep->syms;
        JUMP;
      }
      else {
        /* setup environment for calling method */
        proc = m;
        irep = m->body.irep;
	if (!irep) {
	  mrb->stack[0] = mrb_nil_value();
	  goto L_RETURN;
	}
        pool = irep->pool;
        syms = irep->syms;
        ci->nregs = irep->nregs;
        if (ci->argc < 0) {
          stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3);
        }
        else {
          stack_extend(mrb, irep->nregs,  ci->argc+2);
        }
        regs = mrb->stack;
        regs[0] = m->env->stack[0];
        pc = m->body.irep->iseq;
        JUMP;
      }
    }

    CASE(OP_SUPER) {
      /* A B C  R(A) := super(R(A+1),... ,R(A+C-1)) */
      mrb_value recv;
      mrb_callinfo *ci = mrb->ci;
      struct RProc *m;
      struct RClass *c;
      mrb_sym mid = ci->mid;
      int a = GETARG_A(i);
      int n = GETARG_C(i);

      recv = regs[0];
      c = mrb->ci->target_class->super;
      m = mrb_method_search_vm(mrb, &c, mid);
      if (!m) {
        mid = mrb_intern(mrb, "method_missing");
        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 {
          memmove(regs+a+2, regs+a+1, sizeof(mrb_value)*(n+1));
	  SET_SYM_VALUE(regs[a+1], ci->mid);
          n++;
        }
      }

      /* push callinfo */
      ci = cipush(mrb);
      ci->mid = mid;
      ci->proc = m;
      ci->stackidx = mrb->stack - mrb->stbase;
      ci->argc = n;
      if (ci->argc == CALL_MAXARGS) ci->argc = -1;
      ci->target_class = m->target_class;
      ci->pc = pc + 1;

      /* prepare stack */
      mrb->stack += a;
      mrb->stack[0] = recv;

      if (MRB_PROC_CFUNC_P(m)) {
        mrb->stack[0] = m->body.func(mrb, recv);
        mrb_gc_arena_restore(mrb, ai);
        if (mrb->exc) goto L_RAISE;
        /* pop stackpos */
        regs = mrb->stack = mrb->stbase + mrb->ci->stackidx;
        cipop(mrb);
        NEXT;
      }
      else {
        /* 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;
        if (ci->argc < 0) {
          stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3);
        }
        else {
          stack_extend(mrb, irep->nregs,  ci->argc+2);
        }
        regs = mrb->stack;
        pc = irep->iseq;
        JUMP;
      }
    }

    CASE(OP_ARGARY) {
      /* A Bx   R(A) := argument array (16=6:1:5:4) */
      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 {
        struct REnv *e = uvenv(mrb, lv-1);
        if (!e) {
          mrb_value exc;
          static const char m[] = "super called outside of method";
          exc = mrb_exc_new(mrb, E_NOMETHOD_ERROR, m, sizeof(m) - 1);
          mrb->exc = (struct RObject*)mrb_object(exc);
          goto L_RAISE;
        }
        stack = e->stack + 1;
      }
      if (r == 0) {
        regs[a] = mrb_ary_new_elts(mrb, m1+m2, stack);
      }
      else {
        mrb_value *pp = NULL;
        struct RArray *rest;
        int len = 0;

        if (mrb_array_p(stack[m1])) {
          struct RArray *ary = mrb_ary_ptr(stack[m1]);

          pp = ary->ptr;
          len = ary->len;
        }
        regs[a] = mrb_ary_new_capa(mrb, m1+len+m2);
        rest = mrb_ary_ptr(regs[a]);
        stack_copy(rest->ptr, stack, m1);
        if (len > 0) {
          stack_copy(rest->ptr+m1, pp, len);
        }
        if (m2 > 0) {
          stack_copy(rest->ptr+m1+len, stack+m1+1, m2);
        }
        rest->len = m1+len+m2;
      }
      regs[a+1] = stack[m1+r+m2];
      mrb_gc_arena_restore(mrb, ai);
      NEXT;
    }

    CASE(OP_ENTER) {
      /* Ax             arg setup according to flags (24=5:5:1:5:5:1:1) */
      /* number of optional arguments times OP_JMP should follow */
      int ax = GETARG_Ax(i);
      int m1 = (ax>>18)&0x1f;
      int o  = (ax>>13)&0x1f;
      int r  = (ax>>12)&0x1;
      int m2 = (ax>>7)&0x1f;
      /* unused
      int k  = (ax>>2)&0x1f;
      int kd = (ax>>1)&0x1;
      int b  = (ax>>0)& 0x1;
      */
      int argc = mrb->ci->argc;
      mrb_value *argv = regs+1;
      mrb_value *argv0 = argv;
      int len = m1 + o + r + m2;
      mrb_value *blk = &argv[argc < 0 ? 1 : argc];

      if (argc < 0) {
        struct RArray *ary = mrb_ary_ptr(regs[1]);
        argv = ary->ptr;
        argc = ary->len;
	mrb_gc_protect(mrb, regs[1]);
      }
      if (mrb->ci->proc && MRB_PROC_STRICT_P(mrb->ci->proc)) {
        if (argc >= 0) {
          if (argc < m1 + m2 || (r == 0 && argc > len)) {
	    argnum_error(mrb, m1+m2);
	    goto L_RAISE;
          }
        }
      }
      else if (len > 1 && argc == 1 && mrb_array_p(argv[0])) {
        argc = mrb_ary_ptr(argv[0])->len;
        argv = mrb_ary_ptr(argv[0])->ptr;
      }
      mrb->ci->argc = len;
      if (argc < len) {
        regs[len+1] = *blk; /* move block */
        if (argv0 != argv) {
          memmove(&regs[1], argv, sizeof(mrb_value)*(argc-m2)); /* m1 + o */
        }
        if (m2) {
          memmove(&regs[len-m2+1], &argv[argc-m2], sizeof(mrb_value)*m2); /* m2 */
        }
        if (r) {                  /* r */
          regs[m1+o+1] = mrb_ary_new_capa(mrb, 0);
        }
	if (o == 0) pc++;
	else
	  pc += argc - m1 - m2 + 1;
      }
      else {
        if (argv0 != argv) {
          regs[len+1] = *blk; /* move block */
          memmove(&regs[1], argv, sizeof(mrb_value)*(m1+o)); /* m1 + o */
        }
        if (r) {                  /* r */
          regs[m1+o+1] = mrb_ary_new_elts(mrb, argc-m1-o-m2, argv+m1+o);
        }
        if (m2) {
          memmove(&regs[m1+o+r+1], &argv[argc-m2], sizeof(mrb_value)*m2);
        }
        if (argv0 == argv) {
          regs[len+1] = *blk; /* move block */
        }
        pc += o + 1;
      }
      JUMP;
    }

    CASE(OP_KARG) {
      /* A B C          R(A) := kdict[Sym(B)]; if C kdict.rm(Sym(B)) */
      /* if C == 2; raise unless kdict.empty? */
      /* OP_JMP should follow to skip init code */
      NEXT;
    }

    CASE(OP_KDICT) {
      /* A C            R(A) := kdict */
      NEXT;
    }

    CASE(OP_RETURN) {
      /* A      return R(A) */
    L_RETURN:
      if (mrb->exc) {
        mrb_callinfo *ci;
        int eidx;

      L_RAISE:
	ci = mrb->ci;
	mrb_obj_iv_ifnone(mrb, mrb->exc, mrb_intern(mrb, "lastpc"), mrb_voidp_value(pc));
	mrb_obj_iv_set(mrb, mrb->exc, mrb_intern(mrb, "ciidx"), mrb_fixnum_value(ci - mrb->cibase));
	eidx = ci->eidx;
        if (ci == mrb->cibase) {
	  if (ci->ridx == 0) goto L_STOP;
	  goto L_RESCUE;
	}
        while (ci[0].ridx == ci[-1].ridx) {
          cipop(mrb);
          ci = mrb->ci;
	  if (ci[1].acc < 0 && prev_jmp) {
	    mrb->jmp = prev_jmp;
	    longjmp(*(jmp_buf*)mrb->jmp, 1);
	  }
	  while (eidx > mrb->ci->eidx) {
	    ecall(mrb, --eidx);
	  }
          if (ci == mrb->cibase) {
            if (ci->ridx == 0) {
	      regs = mrb->stack = mrb->stbase;
	      goto L_STOP;
	    }
            break;
          }
        }
      L_RESCUE:
        irep = ci->proc->body.irep;
        pool = irep->pool;
        syms = irep->syms;
        regs = mrb->stack = mrb->stbase + ci[1].stackidx;
        pc = mrb->rescue[--ci->ridx];
      }
      else {
        mrb_callinfo *ci = mrb->ci;
        int acc, eidx = mrb->ci->eidx;
        mrb_value v = regs[GETARG_A(i)];

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

            if (e->cioff < 0) {
              localjump_error(mrb, "return");
              goto L_RAISE;
            }
            ci = mrb->cibase + e->cioff;
	    if (ci == mrb->cibase) {
              localjump_error(mrb, "return");
              goto L_RAISE;
	    }
	    mrb->ci = ci;
            break;
          }
        case OP_R_NORMAL:
          if (ci == mrb->cibase) {
            localjump_error(mrb, "return");
            goto L_RAISE;
          }
          ci = mrb->ci;
          break;
        case OP_R_BREAK:
          if (proc->env->cioff < 0) {
            localjump_error(mrb, "break");
            goto L_RAISE;
          }
          ci = mrb->ci = mrb->cibase + proc->env->cioff + 1;
          break;
        default:
          /* cannot happen */
          break;
        }
        cipop(mrb);
        acc = ci->acc;
        pc = ci->pc;
        regs = mrb->stack = mrb->stbase + ci->stackidx;
        while (eidx > mrb->ci->eidx) {
          ecall(mrb, --eidx);
        }
        if (acc < 0) {
          mrb->jmp = prev_jmp;
          return v;
        }
        DEBUG(printf("from :%s\n", mrb_sym2name(mrb, ci->mid)));
        proc = mrb->ci->proc;
        irep = proc->body.irep;
        pool = irep->pool;
        syms = irep->syms;

        regs[acc] = v;
      }
      JUMP;
    }

    CASE(OP_TAILCALL) {
      /* A B C  return call(R(A),Sym(B),R(A+1),... ,R(A+C-1)) */
      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) {
        mrb_value sym = mrb_symbol_value(mid);

        mid = mrb_intern(mrb, "method_missing");
        m = mrb_method_search_vm(mrb, &c, mid);
        if (n == CALL_MAXARGS) {
          mrb_ary_unshift(mrb, regs[a+1], sym);
        }
        else {
          memmove(regs+a+2, regs+a+1, sizeof(mrb_value)*(n+1));
          regs[a+1] = sym;
          n++;
        }
      }


      /* replace callinfo */
      ci = mrb->ci;
      ci->mid = mid;
      ci->target_class = m->target_class;
      ci->argc = n;
      if (ci->argc == CALL_MAXARGS) ci->argc = -1;

      /* move stack */
      memmove(mrb->stack, &regs[a], (ci->argc+1)*sizeof(mrb_value));

      if (MRB_PROC_CFUNC_P(m)) {
        mrb->stack[0] = m->body.func(mrb, recv);
        mrb_gc_arena_restore(mrb, ai);
        goto L_RETURN;
      }
      else {
        /* setup environment for calling method */
        irep = m->body.irep;
        pool = irep->pool;
        syms = irep->syms;
        if (ci->argc < 0) {
          stack_extend(mrb, (irep->nregs < 3) ? 3 : irep->nregs, 3);
        }
        else {
          stack_extend(mrb, irep->nregs,  ci->argc+2);
        }
        regs = mrb->stack;
        pc = irep->iseq;
      }
      JUMP;
    }

    CASE(OP_BLKPUSH) {
      /* A Bx   R(A) := block (16=6:1:5:4) */
      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 {
        struct REnv *e = uvenv(mrb, lv-1);
	if (!e) {
	  localjump_error(mrb, "yield");
	  goto L_RAISE;
	}
        stack = e->stack + 1;
      }
      regs[a] = stack[m1+r+m2];
      NEXT;
    }

#define attr_i value.i
#ifdef MRB_NAN_BOXING
#define attr_f f
#else
#define attr_f value.f
#endif

#define TYPES2(a,b) (((((int)(a))<<8)|((int)(b)))&0xffff)
#define OP_MATH_BODY(op,v1,v2) do {\
  regs[a].v1 = regs[a].v1 op regs[a+1].v2;\
} while(0)

    CASE(OP_ADD) {
      /* A B C  R(A) := R(A)+R(A+1) (Syms[B]=:+,C=1)*/
      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):
	{
	  mrb_int x, y, z;

	  x = mrb_fixnum(regs[a]);
	  y = mrb_fixnum(regs[a+1]);
	  z = x + y;
	  if (((x < 0) ^ (y < 0)) == 0 && (x < 0) != (z < 0)) {
	    /* integer overflow */
	    SET_FLT_VALUE(regs[a], (mrb_float)x + (mrb_float)y);
	    break;
	  }
	  SET_INT_VALUE(regs[a], z);
	}
	break;
      case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):
	{
	  mrb_int x = mrb_fixnum(regs[a]);
	  mrb_float y = mrb_float(regs[a+1]);
	  SET_FLT_VALUE(regs[a], (mrb_float)x + y);
	}
	break;
      case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):
	OP_MATH_BODY(+,attr_f,attr_i);
	break;
      case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):
	OP_MATH_BODY(+,attr_f,attr_f);
	break;
      case TYPES2(MRB_TT_STRING,MRB_TT_STRING):
	regs[a] = mrb_str_plus(mrb, regs[a], regs[a+1]);
	break;
      default:
	goto L_SEND;
      }
      mrb_gc_arena_restore(mrb, ai);
      NEXT;
    }

    CASE(OP_SUB) {
      /* A B C  R(A) := R(A)-R(A+1) (Syms[B]=:-,C=1)*/
      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):
	{
	  mrb_int x, y, z;

	  x = mrb_fixnum(regs[a]);
	  y = mrb_fixnum(regs[a+1]);
	  z = x - y;
	  if (((x < 0) ^ (y < 0)) != 0 && (x < 0) != (z < 0)) {
	    /* integer overflow */
	    SET_FLT_VALUE(regs[a], (mrb_float)x - (mrb_float)y);
	    break;
	  }
	  SET_INT_VALUE(regs[a], z);
	}
	break;
      case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):
	{
	  mrb_int x = mrb_fixnum(regs[a]);
	  mrb_float y = mrb_float(regs[a+1]);
	  SET_FLT_VALUE(regs[a], (mrb_float)x - y);
	}
	break;
      case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):
	OP_MATH_BODY(-,attr_f,attr_i);
	break;
      case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):
	OP_MATH_BODY(-,attr_f,attr_f);
	break;
      default:
	goto L_SEND;
      }
      NEXT;
    }

    CASE(OP_MUL) {
      /* A B C  R(A) := R(A)*R(A+1) (Syms[B]=:*,C=1)*/
      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):
	{
	  mrb_int x, y, z;

	  x = mrb_fixnum(regs[a]);
	  y = mrb_fixnum(regs[a+1]);
	  z = x * y;
	  if (x != 0 && z/x != y) {
	    SET_FLT_VALUE(regs[a], (mrb_float)x * (mrb_float)y);
	  }
	  else {
	    SET_INT_VALUE(regs[a], z);
	  }
	}
	break;
      case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):
	{
	  mrb_int x = mrb_fixnum(regs[a]);
	  mrb_float y = mrb_float(regs[a+1]);
	  SET_FLT_VALUE(regs[a], (mrb_float)x * y);
	}
	break;
      case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):
	OP_MATH_BODY(*,attr_f,attr_i);
	break;
      case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):
	OP_MATH_BODY(*,attr_f,attr_f);
	break;
      default:
	goto L_SEND;
      }
      NEXT;
    }

    CASE(OP_DIV) {
      /* A B C  R(A) := R(A)/R(A+1) (Syms[B]=:/,C=1)*/
      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):
	{
	  mrb_int x = mrb_fixnum(regs[a]);
	  mrb_int y = mrb_fixnum(regs[a+1]);
	  SET_FLT_VALUE(regs[a], (mrb_float)x / (mrb_float)y);
	}
	break;
      case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):
	{
	  mrb_int x = mrb_fixnum(regs[a]);
	  mrb_float y = mrb_float(regs[a+1]);
	  SET_FLT_VALUE(regs[a], (mrb_float)x / y);
	}
	break;
      case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):
	OP_MATH_BODY(/,attr_f,attr_i);
	break;
      case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):
	OP_MATH_BODY(/,attr_f,attr_f);
	break;
      default:
	goto L_SEND;
      }
      NEXT;
    }

    CASE(OP_ADDI) {
      /* A B C  R(A) := R(A)+C (Syms[B]=:+)*/
      int a = GETARG_A(i);

      /* need to check if + is overridden */
      switch (mrb_type(regs[a])) {
      case MRB_TT_FIXNUM:
	{
	  mrb_int x = regs[a].attr_i;
	  mrb_int y = GETARG_C(i);
	  mrb_int z = x + y;

	  if (((x < 0) ^ (y < 0)) == 0 && (x < 0) != (z < 0)) {
	    /* integer overflow */
	    SET_FLT_VALUE(regs[a], (mrb_float)x + (mrb_float)y);
	    break;
	  }
	  regs[a].attr_i = z;
	}
        break;
      case MRB_TT_FLOAT:
        regs[a].attr_f += GETARG_C(i);
        break;
      default:
        SET_INT_VALUE(regs[a+1], GETARG_C(i));
        i = MKOP_ABC(OP_SEND, a, GETARG_B(i), 1);
        goto L_SEND;
      }
      NEXT;
    }

    CASE(OP_SUBI) {
      /* A B C  R(A) := R(A)-C (Syms[B]=:+)*/
      int a = GETARG_A(i);

      /* need to check if + is overridden */
      switch (mrb_type(regs[a])) {
      case MRB_TT_FIXNUM:
	{
	  mrb_int x = regs[a].attr_i;
	  mrb_int y = GETARG_C(i);
	  mrb_int z = x - y;

	  if (((x < 0) ^ (y < 0)) != 0 && (x < 0) != (z < 0)) {
	    /* integer overflow */
	    SET_FLT_VALUE(regs[a], (mrb_float)x - (mrb_float)y);
	    break;
	  }
	  regs[a].attr_i = z;
	}
        break;
      case MRB_TT_FLOAT:
        regs[a].attr_f -= GETARG_C(i);
        break;
      default:
        SET_INT_VALUE(regs[a+1], GETARG_C(i));
        i = MKOP_ABC(OP_SEND, a, GETARG_B(i), 1);
        goto L_SEND;
      }
      NEXT;
    }

#define OP_CMP_BODY(op,v1,v2) do {\
  if (regs[a].v1 op regs[a+1].v2) {\
    SET_TRUE_VALUE(regs[a]);\
  }\
  else {\
    SET_FALSE_VALUE(regs[a]);\
  }\
} while(0)

#define OP_CMP(op) do {\
  int a = GETARG_A(i);\
  /* 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):\
    OP_CMP_BODY(op,attr_i,attr_i);\
    break;\
  case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT):\
    OP_CMP_BODY(op,attr_i,attr_f);\
    break;\
  case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM):\
    OP_CMP_BODY(op,attr_f,attr_i);\
    break;\
  case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT):\
    OP_CMP_BODY(op,attr_f,attr_f);\
    break;\
  default:\
    goto L_SEND;\
  }\
} while (0)

    CASE(OP_EQ) {
      /* A B C  R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/
      int a = GETARG_A(i);
      if (mrb_obj_eq(mrb, regs[a], regs[a+1])) {
	SET_TRUE_VALUE(regs[a]);
      }
      else {
	OP_CMP(==);
      }
      NEXT;
    }

    CASE(OP_LT) {
      /* A B C  R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/
      OP_CMP(<);
      NEXT;
    }

    CASE(OP_LE) {
      /* A B C  R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/
      OP_CMP(<=);
      NEXT;
    }

    CASE(OP_GT) {
      /* A B C  R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/
      OP_CMP(>);
      NEXT;
    }

    CASE(OP_GE) {
      /* A B C  R(A) := R(A)<R(A+1) (Syms[B]=:<,C=1)*/
      OP_CMP(>=);
      NEXT;
    }

    CASE(OP_ARRAY) {
      /* A B C          R(A) := ary_new(R(B),R(B+1)..R(B+C)) */
      regs[GETARG_A(i)] = mrb_ary_new_from_values(mrb, GETARG_C(i), &regs[GETARG_B(i)]);
      mrb_gc_arena_restore(mrb, ai);
      NEXT;
    }

    CASE(OP_ARYCAT) {
      /* A B            mrb_ary_concat(R(A),R(B)) */
      mrb_ary_concat(mrb, regs[GETARG_A(i)],
                     mrb_ary_splat(mrb, regs[GETARG_B(i)]));
      mrb_gc_arena_restore(mrb, ai);
      NEXT;
    }

    CASE(OP_ARYPUSH) {
      /* A B            R(A).push(R(B)) */
      mrb_ary_push(mrb, regs[GETARG_A(i)], regs[GETARG_B(i)]);
      NEXT;
    }

    CASE(OP_AREF) {
      /* A B C          R(A) := R(B)[C] */
      int a = GETARG_A(i);
      int c = GETARG_C(i);
      mrb_value v = regs[GETARG_B(i)];

      if (!mrb_array_p(v)) {
        if (c == 0) {
          regs[GETARG_A(i)] = v;
        }
        else {
          SET_NIL_VALUE(regs[a]);
        }
      }
      else {
	regs[GETARG_A(i)] = mrb_ary_ref(mrb, v, c);
      }
      NEXT;
    }

    CASE(OP_ASET) {
      /* A B C          R(B)[C] := R(A) */
      mrb_ary_set(mrb, regs[GETARG_B(i)], GETARG_C(i), regs[GETARG_A(i)]);
      NEXT;
    }

    CASE(OP_APOST) {
      /* A B C  *R(A),R(A+1)..R(A+C) := R(A) */
      int a = GETARG_A(i);
      mrb_value v = regs[a];
      int pre  = GETARG_B(i);
      int post = GETARG_C(i);

      if (!mrb_array_p(v)) {
        regs[a++] = mrb_ary_new_capa(mrb, 0);
        while (post--) {
          SET_NIL_VALUE(regs[a]);
          a++;
        }
      }
      else {
        struct RArray *ary = mrb_ary_ptr(v);
        int len = ary->len;
        int i;

        if (len > pre + post) {
          regs[a++] = mrb_ary_new_elts(mrb, len - pre - post, ary->ptr+pre);
          while (post--) {
	    regs[a++] = ary->ptr[len-post-1];
          }
        }
        else {
	  regs[a++] = mrb_ary_new_capa(mrb, 0);
          for (i=0; i+pre<len; i++) {
	    regs[a+i] = ary->ptr[pre+i];
          }
          while (i < post) {
            SET_NIL_VALUE(regs[a+i]);
            i++;
          }
        }
      }
      mrb_gc_arena_restore(mrb, ai);
      NEXT;
    }

    CASE(OP_STRING) {
      /* A Bx           R(A) := str_new(Lit(Bx)) */
      regs[GETARG_A(i)] = mrb_str_literal(mrb, pool[GETARG_Bx(i)]);
      mrb_gc_arena_restore(mrb, ai);
      NEXT;
    }

    CASE(OP_STRCAT) {
      /* A B    R(A).concat(R(B)) */
      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) {
        mrb_hash_set(mrb, hash, regs[b], regs[b+1]);
        b+=2;
      }
      regs[GETARG_A(i)] = hash;
      mrb_gc_arena_restore(mrb, ai);
      NEXT;
    }

    CASE(OP_LAMBDA) {
      /* A b c  R(A) := lambda(SEQ[b],c) (b:c = 14:2) */
      struct RProc *p;
      int c = GETARG_c(i);

      if (c & OP_L_CAPTURE) {
        p = mrb_closure_new(mrb, mrb->irep[irep->idx+GETARG_b(i)]);
      }
      else {
        p = mrb_proc_new(mrb, mrb->irep[irep->idx+GETARG_b(i)]);
      }
      if (c & OP_L_STRICT) p->flags |= MRB_PROC_STRICT;
      regs[GETARG_A(i)] = mrb_obj_value(p);
      mrb_gc_arena_restore(mrb, ai);
      NEXT;
    }

    CASE(OP_OCLASS) {
      /* A      R(A) := ::Object */
      regs[GETARG_A(i)] = mrb_obj_value(mrb->object_class);
      NEXT;
    }

    CASE(OP_CLASS) {
      /* A B    R(A) := newclass(R(A),Sym(B),R(A+1)) */
      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)) {
        base = mrb_obj_value(mrb->ci->target_class);
      }
      c = mrb_vm_define_class(mrb, base, super, id);
      regs[a] = mrb_obj_value(c);
      mrb_gc_arena_restore(mrb, ai);
      NEXT;
    }

    CASE(OP_MODULE) {
      /* A B            R(A) := newmodule(R(A),Sym(B)) */
      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)) {
	base = mrb_obj_value(mrb->ci->target_class);
      }
      c = mrb_vm_define_module(mrb, base, id);
      regs[a] = mrb_obj_value(c);
      mrb_gc_arena_restore(mrb, ai);
      NEXT;
    }

    CASE(OP_EXEC) {
      /* A Bx   R(A) := blockexec(R(A),SEQ[Bx]) */
      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;
      ci->stackidx = mrb->stack - mrb->stbase;
      ci->argc = 0;
      ci->target_class = mrb_class_ptr(recv);

      /* prepare stack */
      mrb->stack += a;

      p = mrb_proc_new(mrb, mrb->irep[irep->idx+GETARG_Bx(i)]);
      p->target_class = ci->target_class;
      ci->proc = p;

      if (MRB_PROC_CFUNC_P(p)) {
        mrb->stack[0] = p->body.func(mrb, recv);
        mrb_gc_arena_restore(mrb, ai);
        if (mrb->exc) goto L_RAISE;
        /* pop stackpos */
        regs = mrb->stack = mrb->stbase + mrb->ci->stackidx;
        cipop(mrb);
        NEXT;
      }
      else {
        irep = p->body.irep;
        pool = irep->pool;
        syms = irep->syms;
        stack_extend(mrb, irep->nregs, 1);
	ci->nregs = irep->nregs;
        regs = mrb->stack;
        pc = irep->iseq;
        JUMP;
      }
    }

    CASE(OP_METHOD) {
      /* A B            R(A).newmethod(Sym(B),R(A+1)) */
      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]);
      mrb_gc_arena_restore(mrb, ai);
      NEXT;
    }

    CASE(OP_SCLASS) {
      /* A B    R(A) := R(B).singleton_class */
      regs[GETARG_A(i)] = mrb_singleton_class(mrb, regs[GETARG_B(i)]);
      mrb_gc_arena_restore(mrb, ai);
      NEXT;
    }

    CASE(OP_TCLASS) {
      /* A B    R(A) := target_class */
      if (!mrb->ci->target_class) {
        static const char msg[] = "no target class or module";
        mrb_value exc = mrb_exc_new(mrb, E_TYPE_ERROR, msg, sizeof(msg) - 1);
        mrb->exc = (struct RObject*)mrb_object(exc);
        goto L_RAISE;
      }
      regs[GETARG_A(i)] = mrb_obj_value(mrb->ci->target_class);
      NEXT;
    }

    CASE(OP_RANGE) {
      /* A B C  R(A) := range_new(R(B),R(B+1),C) */
      int b = GETARG_B(i);
      regs[GETARG_A(i)] = mrb_range_new(mrb, regs[b], regs[b+1], GETARG_C(i));
      mrb_gc_arena_restore(mrb, ai);
      NEXT;
    }

    CASE(OP_DEBUG) {
      /* A      debug print R(A),R(B),R(C) */
#ifdef ENABLE_STDIO
      printf("OP_DEBUG %d %d %d\n", GETARG_A(i), GETARG_B(i), GETARG_C(i));
#else
      abort();
#endif
      NEXT;
    }

    CASE(OP_STOP) {
      /*        stop VM */
    L_STOP:
      {
	int n = mrb->ci->eidx;

	while (n--) {
	  ecall(mrb, n);
	}
      }
      mrb->jmp = prev_jmp;
      if (mrb->exc) {
	return mrb_obj_value(mrb->exc);
      }
      return regs[irep->nlocals];
    }

    CASE(OP_ERR) {
      /* Bx     raise RuntimeError with message Lit(Bx) */
      mrb_value msg = pool[GETARG_Bx(i)];
      mrb_value exc;

      if (GETARG_A(i) == 0) {
	exc = mrb_exc_new3(mrb, E_RUNTIME_ERROR, msg);
      }
      else {
	exc = mrb_exc_new3(mrb, E_LOCALJUMP_ERROR, msg);
      }
      mrb->exc = (struct RObject*)mrb_object(exc);
      goto L_RAISE;
    }
  }
  END_DISPATCH;
}
Example #25
0
static mrb_value
mrb_sdl2_misc_bytebuffer_initialize(mrb_state *mrb, mrb_value self)
{
  mrb_value arg;
  mrb_get_args(mrb, "o", &arg);

  mrb_sdl2_misc_buffer_data_t *data =
    (mrb_sdl2_misc_buffer_data_t*)DATA_PTR(self);

  if (NULL == data) {
    data = (mrb_sdl2_misc_buffer_data_t*)mrb_malloc(mrb, sizeof(mrb_sdl2_misc_buffer_data_t));
    if (NULL == data) {
      mrb_raise(mrb, E_RUNTIME_ERROR, "insufficient memory.");
    }
    data->buffer = NULL;
    data->size   = 0;
  }

  enum mrb_vtype const arg_type = mrb_type(arg);
  switch (arg_type) {
  case MRB_TT_FIXNUM:
    data->size = (size_t)mrb_fixnum(arg);
    break;
  case MRB_TT_FLOAT:
    data->size = (size_t)mrb_float(arg);
    break;
  case MRB_TT_STRING:
    data->size = (size_t)mrb_float(mrb_funcall(mrb, arg, "to_f", 0));
    break;
  case MRB_TT_ARRAY:
    {
      mrb_int const n = mrb_ary_len(mrb, arg);
      if (0 == n) {
        mrb_raise(mrb, E_ARGUMENT_ERROR, "cannot accept empty array.");
      }
      data->size = n * sizeof(uint8_t);
    }
    break;
  default:
    if (mrb_respond_to(mrb, arg, mrb_intern(mrb, "to_f", 4))) {
      data->size = (size_t)mrb_float(mrb_funcall(mrb, arg, "to_f", 0));
    } else if (mrb_respond_to(mrb, arg, mrb_intern(mrb, "to_i", 4))) {
      data->size = (size_t)mrb_fixnum(mrb_funcall(mrb, arg, "to_i", 0));
    } else {
      mrb_raise(mrb, E_TYPE_ERROR, "expected Fixnum/Float/String/Array or comvertible type");
    }
    break;
  }

  data->buffer = mrb_malloc(mrb, data->size);
  if (NULL == data->buffer) {
    mrb_free(mrb, data);
    mrb_raise(mrb, E_RUNTIME_ERROR, "insufficient memory.");
  }

  size_t i = 0;
  for (i = 0; i < data->size/sizeof(uint8_t); ++i) {
    ((uint8_t*)data->buffer)[i] = 0;
  }

  if (arg_type == MRB_TT_ARRAY) {
    mrb_int const n = mrb_ary_len(mrb, arg);
    mrb_int i;
    for (i = 0; i < n; ++i) {
      mrb_value const item = mrb_ary_ref(mrb, arg, i);
      switch (mrb_type(item)) {
      case MRB_TT_FIXNUM:
        ((uint8_t*)data->buffer)[i] = (uint8_t)(mrb_fixnum(item) & 0xffu);
        break;
      case MRB_TT_FLOAT:
        ((uint8_t*)data->buffer)[i] = (uint8_t)((uint32_t)mrb_float(item) & 0xffu);
        break;
      case MRB_TT_STRING:
        ((uint8_t*)data->buffer)[i] = (uint8_t)((uint32_t)mrb_float(mrb_funcall(mrb, item, "to_f", 0)) & 0xffu);
        break;
      default:
        if (mrb_respond_to(mrb, item, mrb_intern(mrb, "to_f", 4))) {
          ((uint8_t*)data->buffer)[i] = (uint8_t)((uint32_t)mrb_float(mrb_funcall(mrb, item, "to_f", 0)) & 0xffu);
        } else if (mrb_respond_to(mrb, item, mrb_intern(mrb, "to_i", 4))) {
          ((uint8_t*)data->buffer)[i] = (uint8_t)(mrb_fixnum(mrb_funcall(mrb, item, "to_i", 0)) & 0xffu);
        } else {
          mrb_free(mrb, data->buffer);
          mrb_free(mrb, data);
          mrb_raise(mrb, E_TYPE_ERROR, "expected Fixnum/Float/String or convertible type");
        }
        break;
      }
    }
  }

  DATA_PTR(self) = data;
  DATA_TYPE(self) = &mrb_sdl2_misc_buffer_data_type;

  return self;
}
Example #26
0
void
mrb_mruby_wslay_gem_init(mrb_state* mrb) {
  struct RClass *wslay_mod, *wslay_error_cl, *wslay_event_mod,
  *wslay_event_context_cl, *wslay_event_context_server_cl, *wslay_event_context_client_cl;

  wslay_mod = mrb_define_module(mrb, "Wslay");
  mrb_define_module_function(mrb, wslay_mod, "get_rsv1", mrb_wslay_get_rsv1, MRB_ARGS_REQ(1));
  mrb_define_module_function(mrb, wslay_mod, "get_rsv2", mrb_wslay_get_rsv2, MRB_ARGS_REQ(1));
  mrb_define_module_function(mrb, wslay_mod, "get_rsv3", mrb_wslay_get_rsv3, MRB_ARGS_REQ(1));
  wslay_error_cl = mrb_define_class_under(mrb, wslay_mod, "Err", E_RUNTIME_ERROR);
  mrb_value wslay_error_hash = mrb_hash_new_capa(mrb, 9 * 2);
  mrb_define_const(mrb, wslay_mod, "Error", wslay_error_hash);
  mrb_hash_set(mrb, wslay_error_hash, mrb_fixnum_value(WSLAY_ERR_WANT_READ), mrb_symbol_value(mrb_intern_lit(mrb, "want_read")));
  mrb_hash_set(mrb, wslay_error_hash, mrb_fixnum_value(WSLAY_ERR_WANT_WRITE), mrb_symbol_value(mrb_intern_lit(mrb, "want_write")));
  mrb_hash_set(mrb, wslay_error_hash, mrb_fixnum_value(WSLAY_ERR_PROTO), mrb_symbol_value(mrb_intern_lit(mrb, "proto")));
  mrb_hash_set(mrb, wslay_error_hash, mrb_fixnum_value(WSLAY_ERR_INVALID_ARGUMENT), mrb_symbol_value(mrb_intern_lit(mrb, "invalid_argument")));
  mrb_hash_set(mrb, wslay_error_hash, mrb_fixnum_value(WSLAY_ERR_INVALID_CALLBACK), mrb_symbol_value(mrb_intern_lit(mrb, "invalid_callback")));
  mrb_hash_set(mrb, wslay_error_hash, mrb_fixnum_value(WSLAY_ERR_NO_MORE_MSG), mrb_symbol_value(mrb_intern_lit(mrb, "no_more_msg")));
  mrb_hash_set(mrb, wslay_error_hash, mrb_fixnum_value(WSLAY_ERR_CALLBACK_FAILURE), mrb_symbol_value(mrb_intern_lit(mrb, "callback_failure")));
  mrb_hash_set(mrb, wslay_error_hash, mrb_fixnum_value(WSLAY_ERR_WOULDBLOCK), mrb_symbol_value(mrb_intern_lit(mrb, "wouldblock")));
  mrb_hash_set(mrb, wslay_error_hash, mrb_fixnum_value(WSLAY_ERR_NOMEM), mrb_symbol_value(mrb_intern_lit(mrb, "nomem")));
  mrb_value wslay_error_hash_keys = mrb_hash_keys(mrb, wslay_error_hash);
  for (mrb_int i = 0; i < RARRAY_LEN(wslay_error_hash_keys); i++) {
    mrb_value key = mrb_ary_ref(mrb, wslay_error_hash_keys, i);
    mrb_hash_set(mrb, wslay_error_hash,
      mrb_hash_get(mrb, wslay_error_hash, key), key);
  }

  mrb_value wslay_status_code_hash = mrb_hash_new_capa(mrb, 12 * 2);
  mrb_define_const(mrb, wslay_mod, "StatusCode", wslay_status_code_hash);
  mrb_hash_set(mrb, wslay_status_code_hash, mrb_fixnum_value(WSLAY_CODE_NORMAL_CLOSURE), mrb_symbol_value(mrb_intern_lit(mrb, "normal_closure")));
  mrb_hash_set(mrb, wslay_status_code_hash, mrb_fixnum_value(WSLAY_CODE_GOING_AWAY), mrb_symbol_value(mrb_intern_lit(mrb, "going_away")));
  mrb_hash_set(mrb, wslay_status_code_hash, mrb_fixnum_value(WSLAY_CODE_PROTOCOL_ERROR), mrb_symbol_value(mrb_intern_lit(mrb, "protocol_error")));
  mrb_hash_set(mrb, wslay_status_code_hash, mrb_fixnum_value(WSLAY_CODE_UNSUPPORTED_DATA), mrb_symbol_value(mrb_intern_lit(mrb, "unsupported_data")));
  mrb_hash_set(mrb, wslay_status_code_hash, mrb_fixnum_value(WSLAY_CODE_NO_STATUS_RCVD), mrb_symbol_value(mrb_intern_lit(mrb, "no_status_rcvd")));
  mrb_hash_set(mrb, wslay_status_code_hash, mrb_fixnum_value(WSLAY_CODE_ABNORMAL_CLOSURE), mrb_symbol_value(mrb_intern_lit(mrb, "abnormal_closure")));
  mrb_hash_set(mrb, wslay_status_code_hash, mrb_fixnum_value(WSLAY_CODE_INVALID_FRAME_PAYLOAD_DATA), mrb_symbol_value(mrb_intern_lit(mrb, "invalid_frame_payload_data")));
  mrb_hash_set(mrb, wslay_status_code_hash, mrb_fixnum_value(WSLAY_CODE_POLICY_VIOLATION), mrb_symbol_value(mrb_intern_lit(mrb, "policy_violation")));
  mrb_hash_set(mrb, wslay_status_code_hash, mrb_fixnum_value(WSLAY_CODE_MESSAGE_TOO_BIG), mrb_symbol_value(mrb_intern_lit(mrb, "message_too_big")));
  mrb_hash_set(mrb, wslay_status_code_hash, mrb_fixnum_value(WSLAY_CODE_MANDATORY_EXT), mrb_symbol_value(mrb_intern_lit(mrb, "mandatory_ext")));
  mrb_hash_set(mrb, wslay_status_code_hash, mrb_fixnum_value(WSLAY_CODE_INTERNAL_SERVER_ERROR), mrb_symbol_value(mrb_intern_lit(mrb, "internal_server_error")));
  mrb_hash_set(mrb, wslay_status_code_hash, mrb_fixnum_value(WSLAY_CODE_TLS_HANDSHAKE), mrb_symbol_value(mrb_intern_lit(mrb, "tls_handshake")));
  mrb_value wslay_status_code_hash_keys = mrb_hash_keys(mrb, wslay_status_code_hash);
  for (mrb_int i = 0; i < RARRAY_LEN(wslay_status_code_hash_keys); i++) {
    mrb_value key = mrb_ary_ref(mrb, wslay_status_code_hash_keys, i);
    mrb_hash_set(mrb, wslay_status_code_hash,
      mrb_hash_get(mrb, wslay_status_code_hash, key), key);
  }

  mrb_value io_flags_hash = mrb_hash_new_capa(mrb, 2);
  mrb_define_const(mrb, wslay_mod, "IoFlags", io_flags_hash);
  mrb_hash_set(mrb, io_flags_hash, mrb_fixnum_value(WSLAY_MSG_MORE), mrb_symbol_value(mrb_intern_lit(mrb, "msg_more")));
  mrb_hash_set(mrb, io_flags_hash, mrb_symbol_value(mrb_intern_lit(mrb, "msg_more")), mrb_fixnum_value(WSLAY_MSG_MORE));

  mrb_value wslay_opcode_hash = mrb_hash_new_capa(mrb, 6 * 2);
  mrb_define_const(mrb, wslay_mod, "OpCode", wslay_opcode_hash);
  mrb_hash_set(mrb, wslay_opcode_hash, mrb_fixnum_value(WSLAY_CONTINUATION_FRAME), mrb_symbol_value(mrb_intern_lit(mrb, "continuation_frame")));
  mrb_hash_set(mrb, wslay_opcode_hash, mrb_fixnum_value(WSLAY_TEXT_FRAME), mrb_symbol_value(mrb_intern_lit(mrb, "text_frame")));
  mrb_hash_set(mrb, wslay_opcode_hash, mrb_fixnum_value(WSLAY_BINARY_FRAME), mrb_symbol_value(mrb_intern_lit(mrb, "binary_frame")));
  mrb_hash_set(mrb, wslay_opcode_hash, mrb_fixnum_value(WSLAY_CONNECTION_CLOSE), mrb_symbol_value(mrb_intern_lit(mrb, "connection_close")));
  mrb_hash_set(mrb, wslay_opcode_hash, mrb_fixnum_value(WSLAY_PING), mrb_symbol_value(mrb_intern_lit(mrb, "ping")));
  mrb_hash_set(mrb, wslay_opcode_hash, mrb_fixnum_value(WSLAY_PONG), mrb_symbol_value(mrb_intern_lit(mrb, "pong")));
  mrb_value wslay_opcode_hash_keys = mrb_hash_keys(mrb, wslay_opcode_hash);
  for (mrb_int i = 0; i < RARRAY_LEN(wslay_opcode_hash_keys); i++) {
    mrb_value key = mrb_ary_ref(mrb, wslay_opcode_hash_keys, i);
    mrb_hash_set(mrb, wslay_opcode_hash,
      mrb_hash_get(mrb, wslay_opcode_hash, key), key);
  }

  wslay_event_mod = mrb_define_module_under(mrb, wslay_mod, "Event");
  wslay_event_context_cl = mrb_define_class_under(mrb, wslay_event_mod, "Context", mrb->object_class);
  MRB_SET_INSTANCE_TT(wslay_event_context_cl, MRB_TT_DATA);
  mrb_define_method(mrb, wslay_event_context_cl, "no_buffering=",         mrb_wslay_event_config_set_no_buffering,        MRB_ARGS_REQ(1));
  mrb_define_method(mrb, wslay_event_context_cl, "max_recv_msg_length=",  mrb_wslay_event_config_set_max_recv_msg_length, MRB_ARGS_REQ(1));
  mrb_define_method(mrb, wslay_event_context_cl, "recv",                  mrb_wslay_event_recv,                           MRB_ARGS_NONE());
  mrb_define_method(mrb, wslay_event_context_cl, "send",                  mrb_wslay_event_send,                           MRB_ARGS_NONE());
  mrb_define_method(mrb, wslay_event_context_cl, "queue_msg",             mrb_wslay_event_queue_msg,                      MRB_ARGS_REQ(2));
  mrb_define_method(mrb, wslay_event_context_cl, "queue_close",           mrb_wslay_event_queue_close,                    MRB_ARGS_ARG(1, 1));
  mrb_define_method(mrb, wslay_event_context_cl, "want_read?",            mrb_wslay_event_want_read,                      MRB_ARGS_NONE());
  mrb_define_method(mrb, wslay_event_context_cl, "want_write?",           mrb_wslay_event_want_write,                     MRB_ARGS_NONE());
  mrb_define_method(mrb, wslay_event_context_cl, "close_received?",       mrb_wslay_event_get_close_received,             MRB_ARGS_NONE());
  mrb_define_method(mrb, wslay_event_context_cl, "close_sent?",           mrb_wslay_event_get_close_sent,                 MRB_ARGS_NONE());
  mrb_define_method(mrb, wslay_event_context_cl, "status_code_received",  mrb_wslay_event_get_status_code_received,       MRB_ARGS_NONE());
  mrb_define_method(mrb, wslay_event_context_cl, "status_code_sent",      mrb_wslay_event_get_status_code_sent,           MRB_ARGS_NONE());
  mrb_define_method(mrb, wslay_event_context_cl, "queued_msg_count",      mrb_wslay_event_get_queued_msg_count,           MRB_ARGS_NONE());
  mrb_define_method(mrb, wslay_event_context_cl, "queued_msg_length",     mrb_wslay_event_get_queued_msg_length,          MRB_ARGS_NONE());

  wslay_event_context_server_cl = mrb_define_class_under(mrb, wslay_event_context_cl, "Server", wslay_event_context_cl);
  mrb_define_method(mrb, wslay_event_context_server_cl, "initialize", mrb_wslay_event_context_server_init, MRB_ARGS_REQ(1));

  wslay_event_context_client_cl = mrb_define_class_under(mrb, wslay_event_context_cl, "Client", wslay_event_context_cl);
  mrb_define_method(mrb, wslay_event_context_client_cl, "initialize", mrb_wslay_event_context_client_init, MRB_ARGS_REQ(1));
}
Example #27
0
int main(int argc, char const *argv[])
{
#ifdef _MEM_PROFILER
  uint8_t checkpoint_set = 0;
#endif
  fd_set rfds;
  char buffer[PIPE_BUFFER_SIZE];
  int i, n;
  Plugin plugins[MAX_PLUGINS];
  int plugins_count = 0;
  mrb_state *mrb;
  mrb_value r_output, r_plugins_list;
  mrb_sym output_gv_sym, plugins_to_load_gv_sym;
  
  printf("Version: %s\n", PROBE_VERSION);
  
  if( argc != 2 ){
    printf("Usage: %s <config_path>\n", argv[0]);
    exit(1);
  }
  
#ifdef _MEM_PROFILER
  init_profiler();
#endif
  
  config_path = argv[1];
  
  printf("Initializing core...\n");
  mrb = mrb_open_allocf(profiler_allocf, "main");
  output_gv_sym = mrb_intern_cstr(mrb, "$output");
  plugins_to_load_gv_sym = mrb_intern_cstr(mrb, "$plugins_to_load");
  setup_api(mrb);
  execute_file(mrb, "plugins/main.rb");
  execute_file(mrb, config_path);
  
  printf("Loading plugins...\n");
  r_plugins_list = mrb_gv_get(mrb, plugins_to_load_gv_sym);
  for(i = 0; i< mrb_ary_len(mrb, r_plugins_list); i++){
    char *path, tmp[100];
    int ssize;
    
    mrb_value r_plugin_name = mrb_ary_ref(mrb, r_plugins_list, i);
    const char *plugin_name = mrb_string_value_cstr(mrb, &r_plugin_name);
    
    snprintf(tmp, sizeof(tmp) - 1, "plugins/%s.rb", plugin_name);
    ssize = strlen(tmp);
    
    path = malloc(ssize + 1);
    strncpy(path, tmp, ssize);
    path[ssize] = '\0';
    
    if( access(path, F_OK) == -1 ){
      printf("cannot open plugin file \"%s\": %s\n", path, strerror(errno));
      exit(1);
    }
    
    init_plugin_from_file(&plugins[plugins_count], path, plugin_name); plugins_count++;
  }
  
  printf("Instanciating output class...\n");
  r_output = mrb_gv_get(mrb, output_gv_sym);
  interval = mrb_fixnum(mrb_funcall(mrb, r_output, "interval", 0));
  
  printf("Interval set to %dms\n", (int)interval);
  
  printf("Sending initial report...\n");
  mrb_funcall(mrb, r_output, "send_report", 0);
  
  if (mrb->exc) {
    mrb_print_error(mrb);
    
    exit(1);
  }

  
  // start all the threads
  for(i= 0; i< plugins_count; i++){
    // printf("== plugin %d\n", i);
    n = pthread_create(&plugins[i].thread, NULL, plugin_thread, (void *)&plugins[i]);
    if( n < 0 ){
      fprintf(stderr, "create failed\n");
    }
  }
  
  if( signal(SIGINT, clean_exit) == SIG_ERR){
    perror("signal");
    exit(1);
  }
  
  while(running){
    int fds[MAX_PLUGINS];
    int maxfd = 0, ai;
    struct timeval tv;
    mrb_value r_buffer;
    struct timeval cycle_started_at, cycle_completed_at;
    
    gettimeofday(&cycle_started_at, NULL);
    
    bzero(fds, sizeof(int) * MAX_PLUGINS);
    
    // ask every plugin to send their data
    for(i= 0; i< plugins_count; i++){
      strcpy(buffer, "request");
      if( send(plugins[i].host_pipe, buffer, strlen(buffer), 0) == -1 ){
        printf("send error when writing in pipe connected to plugin '%s'\n", plugins[i].name);
      }
      fds[i] = plugins[i].host_pipe;
      // printf("sent request to %d\n", i);
    }
    
    // printf("waiting answers...\n");
    // and now wait for each answer
    while(1){
      int left = 0;
      
      FD_ZERO(&rfds);
      
      for(i = 0; i< MAX_PLUGINS; i++){
        if( fds[i] != NOPLUGIN_VALUE ){
          FD_SET(fds[i], &rfds);
          left++;
          if( fds[i] > maxfd )
            maxfd = fds[i];
        }
      }
      
      // printf("left: %d %d\n", left, left <= 0);
      
      if( !running || (0 == left) )
        break;
      
      // substract 20ms to stay below the loop delay
      fill_timeout(&tv, cycle_started_at, interval - 20);
      // printf("before select\n");
      n = select(maxfd + 1, &rfds, NULL, NULL, &tv);
      // printf("after select: %d\n", n);
      if( n > 0 ){
        // find out which pipes have data
        for(i = 0; i< MAX_PLUGINS; i++){
          if( (fds[i] != NOPLUGIN_VALUE) && FD_ISSET(fds[i], &rfds) ){
            while (1){
              struct timeval answered_at;
              n = read(fds[i], buffer, sizeof(buffer));
              if( n == -1 ){
                if( errno != EAGAIN )
                  perror("read");
                break;
              }
              
              if( n == PIPE_BUFFER_SIZE ){
                printf("PIPE_BUFFER_SIZE is too small, increase it ! (value: %d)\n", PIPE_BUFFER_SIZE);
                continue;
              }
              
              gettimeofday(&answered_at, NULL);
              // printf("received answer from %s in %u ms\n", (const char *) plugins[i].mrb->ud,
              //     (uint32_t)((answered_at.tv_sec - cycle_started_at.tv_sec) * 1000 +
              //     (answered_at.tv_usec - cycle_started_at.tv_usec) / 1000)
              //   );
              
              buffer[n] = 0x00;
              
              ai = mrb_gc_arena_save(mrb);
              r_buffer = mrb_str_buf_new(mrb, n);
              mrb_str_buf_cat(mrb, r_buffer, buffer, n);
              
              // mrb_funcall(mrb, r_output, "tick", 0);
              mrb_funcall(mrb, r_output, "add", 1, r_buffer);
              check_exception("add", mrb);
              
              // pp(mrb, r_output, 0);
              
              mrb_gc_arena_restore(mrb, ai);
            }
            
            fds[i] = 0;
          }
        }
      }
      else if( n == 0 )  {
        printf("no responses received from %d plugins.\n", left);
        break;
        // timeout
      }
      else {
        perror("select");
      }
    }
    
    int idx = mrb_gc_arena_save(mrb);
    mrb_funcall(mrb, r_output, "flush", 0);
    check_exception("flush", mrb);
    mrb_gc_arena_restore(mrb, idx);
    
    // and now sleep until the next cycle
    gettimeofday(&cycle_completed_at, NULL);
    
  #ifdef _MEM_PROFILER
    if( checkpoint_set ){
      print_allocations();
    }
  #endif
    
    // force a gc run at the end of each cycle
    mrb_full_gc(mrb);
    // printf("[main] capa: %d / %d\n", mrb->arena_idx, mrb->arena_capa);
    // for(i= 0; i< plugins_count; i++){
    //   printf("[%s] capa: %d / %d\n", plugins[i].name, plugins[i].mrb->arena_idx, plugins[i].mrb->arena_capa);
    // }
  
  #ifdef _MEM_PROFILER
    checkpoint_set = 1;
    // and set starting point
    profiler_set_checkpoint();
  #endif

    
  #ifdef _MEM_PROFILER_RUBY
    // dump VMS state
    dump_state(mrb);
    for(i= 0; i< plugins_count; i++){
      dump_state(plugins[i].mrb);
    }
  #endif
    
    fflush(stdout);
    sleep_delay(&cycle_started_at, &cycle_completed_at, interval);
  }
  
  printf("Sending exit signal to all plugins...\n");
  strcpy(buffer, "exit");
  for(i= 0; i< plugins_count; i++){
    C_CHECK("send", send(plugins[i].host_pipe, buffer, strlen(buffer), 0) );
  }
  
  printf("Giving some time for threads to exit...\n\n");
  really_sleep(2000);
  
  
  for(i= 0; i< plugins_count; i++){
    int ret = pthread_kill(plugins[i].thread, 0);
    
    // if a success is returned then the thread is still alive
    // which means the thread did not acknoledged the exit message
    // kill it.
    if( ret == 0 ){
      printf("    - plugin \"%s\" failed to exit properly, killing it...\n", (const char *) plugins[i].mrb->ud);
      pthread_cancel(plugins[i].thread);
    }
    else {
      printf("    - plugin \"%s\" exited properly.\n", (const char *) plugins[i].mrb->allocf_ud);
    }
    
    if( pthread_join(plugins[i].thread, NULL) < 0){
      fprintf(stderr, "join failed\n");
    }
    
    mrb_close(plugins[i].mrb);
  }
  
  mrb_close(mrb);
  
  printf("Exited !\n");
  return 0;
}
Example #28
0
int value_to_node(mrb_state *mrb,
  yaml_document_t *document, mrb_value value)
{
  int node;

  switch (mrb_type(value))
  {
    case MRB_TT_ARRAY:
    {
      mrb_int len = mrb_ary_len(mrb, value);
      mrb_int i;
      int ai = mrb_gc_arena_save(mrb);

      node = yaml_document_add_sequence(document, NULL,
        YAML_ANY_SEQUENCE_STYLE);

      for (i = 0; i < len; i++)
      {
        mrb_value child = mrb_ary_ref(mrb, value, i);
        int child_node = value_to_node(mrb, document, child);

        /* Add the child to the sequence */
        yaml_document_append_sequence_item(document, node, child_node);
        mrb_gc_arena_restore(mrb, ai);
      }

      break;
    }

    case MRB_TT_HASH:
    {
      /* Iterating a list of keys is slow, but it only
       * requires use of the interface defined in `hash.h`.
       */

      mrb_value keys = mrb_hash_keys(mrb, value);
      mrb_int len = mrb_ary_len(mrb, keys);
      mrb_int i;
      int ai = mrb_gc_arena_save(mrb);

      node = yaml_document_add_mapping(document, NULL,
        YAML_ANY_MAPPING_STYLE);

      for (i = 0; i < len; i++)
      {
        mrb_value key = mrb_ary_ref(mrb, keys, i);
        mrb_value child = mrb_hash_get(mrb, value, key);

        int key_node = value_to_node(mrb, document, key);
        int child_node = value_to_node(mrb, document, child);

        /* Add the key/value pair to the mapping */
        yaml_document_append_mapping_pair(document, node,
          key_node, child_node);
        mrb_gc_arena_restore(mrb, ai);
      }

      break;
    }

    default:
    {
      if (mrb_nil_p(value)) {
        /* http://yaml.org/type/null.html
           Canonical form */
        value = mrb_str_new_lit(mrb, "~");
      } else {
        /* Equivalent to `obj = obj#to_s` */
        value = mrb_obj_as_string(mrb, value);
      }
      /* Fallthrough */
    }

    case MRB_TT_STRING:
    {
      yaml_scalar_style_t style = YAML_ANY_SCALAR_STYLE;
      if (RSTRING_LEN(value) == 0) {
        /* If the String is empty, it may be reloaded as a nil instead of an
         * empty string, to avoid that place a quoted string instead */
        style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
      }
      yaml_char_t *value_chars = (unsigned char *) RSTRING_PTR(value);
      node = yaml_document_add_scalar(document, NULL,
        value_chars, RSTRING_LEN(value), style);
      break;
    }
  }

  return node;
}