static mrb_value mrb_sdl2_ttf_font_get_glyph_metric(mrb_state *mrb, mrb_value self) { int minx, maxx, miny, maxy, advance; mrb_value character; Uint16 ch; mrb_value result; mrb_get_args(mrb, "b", &character); if (mrb_obj_is_kind_of(mrb, character, mrb_class_get_under(mrb, mrb->object_class, "String"))) { ch = *RSTRING_PTR(character); } else if (mrb_obj_is_kind_of(mrb, character, mrb_class_get_under(mrb, mrb->object_class, "Integer"))) { ch = (Uint16) character.value.i; } result = mrb_hash_new_capa(mrb, 5); if (TTF_GlyphMetrics(mrb_sdl2_font_get_ptr(mrb, self), ch, &minx, &maxx, &miny, &maxy, &advance) == -1) { mruby_sdl2_raise_error(mrb); return mrb_false_value(); } mrb_hash_set(mrb, result, mrb_str_new_cstr(mrb, "minx"), mrb_fixnum_value(minx)); mrb_hash_set(mrb, result, mrb_str_new_cstr(mrb, "maxx"), mrb_fixnum_value(maxx)); mrb_hash_set(mrb, result, mrb_str_new_cstr(mrb, "miny"), mrb_fixnum_value(miny)); mrb_hash_set(mrb, result, mrb_str_new_cstr(mrb, "maxy"), mrb_fixnum_value(maxy)); mrb_hash_set(mrb, result, mrb_str_new_cstr(mrb, "advance"), mrb_fixnum_value(advance)); return result; }
bool convert_js_to_mrb_hash(NPP npp, const NPVariant &variant, mrb_state *mrb, mrb_value *result) { NPIdentifier *id_list = NULL; uint32_t count; NPN_Enumerate(npp, NPVARIANT_TO_OBJECT(variant), &id_list, &count); mrb_value ret_hash = mrb_hash_new_capa(mrb, count); for (uint32_t i=0; i<count; i++){ NPVariant item; NPN_GetProperty(npp, NPVARIANT_TO_OBJECT(variant), id_list[i], &item); mrb_value mrb_item; if (!convert_js_to_mrb(npp, item, mrb, &mrb_item)){ NPN_MemFree(id_list); NPN_ReleaseVariantValue(&item); return false; } NPN_ReleaseVariantValue(&item); NPUTF8 *key = NPN_UTF8FromIdentifier(id_list[i]); mrb_hash_set(mrb, ret_hash, mrb_str_new2(mrb, key), mrb_item); NPN_MemFree(key); } NPN_MemFree(id_list); *result = ret_hash; return true; }
static mrb_value mrb_ary_to_h(mrb_state *mrb, mrb_value ary) { mrb_int i; mrb_value v, hash; hash = mrb_hash_new_capa(mrb, 0); for (i = 0; i < RARRAY_LEN(ary); ++i) { v = mrb_check_array_type(mrb, RARRAY_PTR(ary)[i]); if (mrb_nil_p(v)) { mrb_raisef(mrb, E_TYPE_ERROR, "wrong element type %S at %S (expected array)", mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, RARRAY_PTR(ary)[i])), mrb_fixnum_value(i) ); } if (RARRAY_LEN(v) != 2) { mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong array length at %S (expected 2, was %S)", mrb_fixnum_value(i), mrb_fixnum_value(RARRAY_LEN(v)) ); } mrb_hash_set(mrb, hash, RARRAY_PTR(v)[0], RARRAY_PTR(v)[1]); } return hash; }
static void post_response(struct st_h2o_mruby_http_request_context_t *ctx, int status, const h2o_http1client_header_t *headers_sorted, size_t num_headers) { mrb_state *mrb = ctx->generator->ctx->shared->mrb; int gc_arena = mrb_gc_arena_save(mrb); size_t i; mrb_value resp = mrb_ary_new_capa(mrb, 3); /* set status */ mrb_ary_set(mrb, resp, 0, mrb_fixnum_value(status)); /* set headers */ mrb_value headers_hash = mrb_hash_new_capa(mrb, (int)num_headers); for (i = 0; i < num_headers; ++i) { /* skip the headers, we determine the eos! */ if (h2o_memis(headers_sorted[i].name, headers_sorted[i].name_len, H2O_STRLIT("content-length")) || h2o_memis(headers_sorted[i].name, headers_sorted[i].name_len, H2O_STRLIT("transfer-encoding"))) continue; /* build and set the hash entry */ mrb_value k = mrb_str_new(mrb, headers_sorted[i].name, headers_sorted[i].name_len); mrb_value v = mrb_str_new(mrb, headers_sorted[i].value, headers_sorted[i].value_len); while (i + 1 < num_headers && h2o_memis(headers_sorted[i].name, headers_sorted[i].name_len, headers_sorted[i + 1].name, headers_sorted[i + 1].name_len)) { ++i; v = mrb_str_cat_lit(mrb, v, "\n"); v = mrb_str_cat(mrb, v, headers_sorted[i].value, headers_sorted[i].value_len); } mrb_hash_set(mrb, headers_hash, k, v); } mrb_ary_set(mrb, resp, 1, headers_hash); /* set input stream */ assert(mrb_nil_p(ctx->refs.input_stream)); ctx->refs.input_stream = h2o_mruby_create_data_instance( mrb, mrb_ary_entry(ctx->generator->ctx->shared->constants, H2O_MRUBY_HTTP_INPUT_STREAM_CLASS), ctx, &input_stream_type); mrb_ary_set(mrb, resp, 2, ctx->refs.input_stream); if (mrb_nil_p(ctx->receiver)) { /* is async */ mrb_funcall(mrb, ctx->refs.request, "_set_response", 1, resp); if (mrb->exc != NULL) { fprintf(stderr, "_set_response failed\n"); abort(); } } else { /* send response to the waiting receiver */ h2o_mruby_run_fiber(ctx->generator, detach_receiver(ctx), resp, NULL); } mrb_gc_arena_restore(mrb, gc_arena); }
void inputBindingInit(mrb_state *mrb) { RClass *module = mrb_define_module(mrb, "Input"); mrb_define_module_function(mrb, module, "update", inputUpdate, MRB_ARGS_NONE()); mrb_define_module_function(mrb, module, "press?", inputPress, MRB_ARGS_REQ(1)); mrb_define_module_function(mrb, module, "trigger?", inputTrigger, MRB_ARGS_REQ(1)); mrb_define_module_function(mrb, module, "repeat?", inputRepeat, MRB_ARGS_REQ(1)); mrb_define_module_function(mrb, module, "dir4", inputDir4, MRB_ARGS_NONE()); mrb_define_module_function(mrb, module, "dir8", inputDir8, MRB_ARGS_NONE()); mrb_define_module_function(mrb, module, "mouse_x", inputMouseX, MRB_ARGS_NONE()); mrb_define_module_function(mrb, module, "mouse_y", inputMouseY, MRB_ARGS_NONE()); mrb_value modVal = mrb_obj_value(module); if (rgssVer >= 3) { mrb_value symHash = mrb_hash_new_capa(mrb, buttonCodesN); for (size_t i = 0; i < buttonCodesN; ++i) { const char *str = buttonCodes[i].str; mrb_sym sym = mrb_intern_static(mrb, str, strlen(str)); mrb_value symVal = mrb_symbol_value(sym); mrb_value val = mrb_fixnum_value(buttonCodes[i].val); /* In RGSS3 all Input::XYZ constants are equal to :XYZ symbols, * to be compatible with the previous convention */ mrb_const_set(mrb, modVal, sym, symVal); mrb_hash_set(mrb, symHash, symVal, val); } mrb_iv_set(mrb, modVal, mrb_intern_lit(mrb, "buttoncodes"), symHash); getMrbData(mrb)->buttoncodeHash = symHash; } else { for (size_t i = 0; i < buttonCodesN; ++i) { const char *str = buttonCodes[i].str; mrb_sym sym = mrb_intern_static(mrb, str, strlen(str)); mrb_value val = mrb_fixnum_value(buttonCodes[i].val); mrb_const_set(mrb, modVal, sym, val); } } }
/* * call-seq: * struct.to_h -> hash * * Create a hash from member names and struct values. */ static mrb_value mrb_struct_to_h(mrb_state *mrb, mrb_value self) { mrb_value members, ret; mrb_int i; members = struct_s_members(mrb, mrb_class(mrb, self)); ret = mrb_hash_new_capa(mrb, RARRAY_LEN(members)); for (i = 0; i < RARRAY_LEN(members); ++i) { mrb_hash_set(mrb, ret, RARRAY_PTR(members)[i], RSTRUCT_PTR(self)[i]); } return ret; }
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; }
static mrb_value read_hash(MarshalContext *ctx) { mrb_state *mrb = ctx->mrb; int len = read_fixnum(ctx); int i; mrb_value hash = mrb_hash_new_capa(mrb, len); ctx->objects.add(hash); for (i = 0; i < len; ++i) { mrb_value key = read_value(ctx); mrb_value val = read_value(ctx); mrb_hash_set(mrb, hash, key, val); } return hash; }
mrb_value mrb_hash_new(mrb_state *mrb) { return mrb_hash_new_capa(mrb, 0); }
mrb_value MR_ObjectJson (mrb_state* mrb, TRI_json_t const* json) { switch (json->_type) { case TRI_JSON_UNUSED: return mrb_nil_value(); case TRI_JSON_NULL: return mrb_nil_value(); case TRI_JSON_BOOLEAN: return json->_value._boolean ? mrb_true_value() : mrb_false_value(); case TRI_JSON_NUMBER: return mrb_float_value(mrb, json->_value._number); case TRI_JSON_STRING: case TRI_JSON_STRING_REFERENCE: // same for STRING and STRING_REFERENCE return mrb_str_new(mrb, json->_value._string.data, json->_value._string.length - 1); case TRI_JSON_ARRAY: { size_t n; size_t i; mrb_value a; TRI_json_t* sub; mrb_value key; mrb_value val; n = json->_value._objects._length; a = mrb_hash_new_capa(mrb, n); for (i = 0; i < n; i += 2) { sub = (TRI_json_t*) TRI_AtVector(&json->_value._objects, i); if (! TRI_IsStringJson(sub)) { continue; } key = mrb_str_new(mrb, sub->_value._string.data, sub->_value._string.length - 1); sub = (TRI_json_t*) TRI_AtVector(&json->_value._objects, i + 1); val = MR_ObjectJson(mrb, sub); mrb_hash_set(mrb, a, key, val); } return a; } case TRI_JSON_LIST: { size_t n; size_t i; mrb_value a; TRI_json_t* elm; mrb_value val; n = json->_value._objects._length; a = mrb_ary_new_capa(mrb, n); for (i = 0; i < n; ++i) { elm = (TRI_json_t*) TRI_AtVector(&json->_value._objects, i); val = MR_ObjectJson(mrb, elm); mrb_ary_set(mrb, a, i, val); } return a; } } return mrb_nil_value(); }
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(®s[1], argv, sizeof(mrb_value)*(argc-m2)); /* m1 + o */ memmove(®s[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(®s[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(®s[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, ®s[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; }
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)); }
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(®s[1], argv, sizeof(mrb_value)*(argc-m2)); /* m1 + o */ } if (m2) { memmove(®s[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(®s[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(®s[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, ®s[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), ®s[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; }
mrb_value mrb_hash_new(mrb_state *mrb, int capa) { return mrb_hash_new_capa(mrb, capa); }