ruby-changes:43694
From: ko1 <ko1@a...>
Date: Thu, 28 Jul 2016 20:02:38 +0900 (JST)
Subject: [ruby-changes:43694] ko1:r55766 (trunk): * vm_core.h: revisit the structure of frame, block and env.
ko1 2016-07-28 20:02:30 +0900 (Thu, 28 Jul 2016) New Revision: 55766 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=55766 Log: * vm_core.h: revisit the structure of frame, block and env. [Bug #12628] This patch introduce many changes. * Introduce concept of "Block Handler (BH)" to represent passed blocks. * move rb_control_frame_t::flag to ep[0] (as a special local variable). This flags represents not only frame type, but also env flags such as escaped. * rename `rb_block_t` to `struct rb_block`. * Make Proc, Binding and RubyVM::Env objects wb-protected. Check [Bug #12628] for more details. Modified files: trunk/ChangeLog trunk/compile.c trunk/cont.c trunk/eval.c trunk/eval_intern.h trunk/gc.c trunk/insns.def trunk/internal.h trunk/iseq.c trunk/load.c trunk/parse.y trunk/proc.c trunk/process.c trunk/ruby.c trunk/string.c trunk/thread.c trunk/tool/mk_call_iseq_optimized.rb trunk/vm.c trunk/vm_args.c trunk/vm_core.h trunk/vm_dump.c trunk/vm_eval.c trunk/vm_insnhelper.c trunk/vm_insnhelper.h trunk/vm_method.c Index: string.c =================================================================== --- string.c (revision 55765) +++ string.c (revision 55766) @@ -9459,7 +9459,7 @@ sym_to_sym(VALUE sym) https://github.com/ruby/ruby/blob/trunk/string.c#L9459 } VALUE -rb_sym_proc_call(VALUE args, VALUE sym, int argc, const VALUE *argv, VALUE passed_proc) +rb_sym_proc_call(ID mid, int argc, const VALUE *argv, VALUE passed_proc) { VALUE obj; @@ -9467,7 +9467,7 @@ rb_sym_proc_call(VALUE args, VALUE sym, https://github.com/ruby/ruby/blob/trunk/string.c#L9467 rb_raise(rb_eArgError, "no receiver given"); } obj = argv[0]; - return rb_funcall_with_block(obj, (ID)sym, argc - 1, argv + 1, passed_proc); + return rb_funcall_with_block(obj, mid, argc - 1, argv + 1, passed_proc); } #if 0 Index: eval_intern.h =================================================================== --- eval_intern.h (revision 55765) +++ eval_intern.h (revision 55766) @@ -5,13 +5,23 @@ https://github.com/ruby/ruby/blob/trunk/eval_intern.h#L5 #include "vm_core.h" static inline void -pass_passed_block(rb_thread_t *th) +vm_passed_block_handler_set(rb_thread_t *th, VALUE block_handler) { - th->passed_block = rb_vm_control_frame_block_ptr(th->cfp); - th->cfp->flag |= VM_FRAME_FLAG_PASSED; + VM_ASSERT(vm_block_handler_verify(block_handler)); + th->passed_block_handler = block_handler; } -#define PASS_PASSED_BLOCK_TH(th) pass_passed_block(th) -#define PASS_PASSED_BLOCK() pass_passed_block(GET_THREAD()) + +static inline void +pass_passed_block_handler(rb_thread_t *th) +{ + VALUE block_handler = rb_vm_frame_block_handler(th->cfp); + VM_ASSERT(vm_block_handler_verify(block_handler)); + vm_passed_block_handler_set(th, block_handler); + VM_ENV_FLAGS_SET(th->cfp->ep, VM_FRAME_FLAG_PASSED); +} + +#define PASS_PASSED_BLOCK_HANDLER_TH(th) pass_passed_block_handler(th) +#define PASS_PASSED_BLOCK_HANDLER() pass_passed_block_handler(GET_THREAD()) #ifdef HAVE_STDLIB_H #include <stdlib.h> @@ -277,7 +287,7 @@ NORETURN(void rb_raise_method_missing(rb https://github.com/ruby/ruby/blob/trunk/eval_intern.h#L287 VALUE rb_vm_make_jump_tag_but_local_jump(int state, VALUE val); rb_cref_t *rb_vm_cref(void); rb_cref_t *rb_vm_cref_replace_with_duplicated_cref(void); -VALUE rb_vm_call_cfunc(VALUE recv, VALUE (*func)(VALUE), VALUE arg, const rb_block_t *blockptr, VALUE filename); +VALUE rb_vm_call_cfunc(VALUE recv, VALUE (*func)(VALUE), VALUE arg, VALUE block_handler, VALUE filename); void rb_vm_set_progname(VALUE filename); void rb_thread_terminate_all(void); VALUE rb_vm_cbase(void); Index: ruby.c =================================================================== --- ruby.c (revision 55765) +++ ruby.c (revision 55766) @@ -639,13 +639,10 @@ require_libraries(VALUE *req_list) https://github.com/ruby/ruby/blob/trunk/ruby.c#L639 *req_list = 0; } -static rb_block_t* +static const struct rb_block* toplevel_context(rb_binding_t *bind) { - rb_env_t *env; - - GetEnvPtr(bind->env, env); - return &env->block; + return &bind->block; } static void @@ -1447,7 +1444,7 @@ process_options(int argc, char **argv, s https://github.com/ruby/ruby/blob/trunk/ruby.c#L1444 char fbuf[MAXPATHLEN]; int i = (int)proc_options(argc, argv, opt, 0); rb_binding_t *toplevel_binding; - rb_block_t *base_block; + const struct rb_block *base_block; argc -= i; argv += i; @@ -1700,7 +1697,7 @@ process_options(int argc, char **argv, s https://github.com/ruby/ruby/blob/trunk/ruby.c#L1697 path = rb_realpath_internal(Qnil, opt->script_name, 1); } base_block = toplevel_context(toplevel_binding); - iseq = rb_iseq_new_main(tree, opt->script_name, path, base_block->iseq); + iseq = rb_iseq_new_main(tree, opt->script_name, path, vm_block_iseq(base_block)); } if (opt->dump & DUMP_BIT(insns)) { Index: insns.def =================================================================== --- insns.def (revision 55765) +++ insns.def (revision 55766) @@ -58,7 +58,7 @@ getlocal https://github.com/ruby/ruby/blob/trunk/insns.def#L58 (VALUE val) { int i, lev = (int)level; - VALUE *ep = GET_EP(); + const VALUE *ep = GET_EP(); /* optimized insns generated for level == (0|1) in defs/opt_operand.def */ for (i = 0; i < lev; i++) { @@ -81,13 +81,13 @@ setlocal https://github.com/ruby/ruby/blob/trunk/insns.def#L81 () { int i, lev = (int)level; - VALUE *ep = GET_EP(); + const VALUE *ep = GET_EP(); /* optimized insns generated for level == (0|1) in defs/opt_operand.def */ for (i = 0; i < lev; i++) { ep = GET_PREV_EP(ep); } - *(ep - idx) = val; + vm_env_write(ep, -(int)idx, val); } /** @@ -790,7 +790,7 @@ checkkeyword https://github.com/ruby/ruby/blob/trunk/insns.def#L790 ret = (bits & (0x01 << keyword_index)) ? Qfalse : Qtrue; } else { - assert(RB_TYPE_P(kw_bits, T_HASH)); + VM_ASSERT(RB_TYPE_P(kw_bits, T_HASH)); ret = rb_hash_has_key(kw_bits, INT2FIX(keyword_index)) ? Qfalse : Qtrue; } } @@ -932,11 +932,11 @@ defineclass https://github.com/ruby/ruby/blob/trunk/insns.def#L932 rb_iseq_check(class_iseq); /* enter scope */ - vm_push_frame(th, class_iseq, VM_FRAME_MAGIC_CLASS, klass, - VM_ENVVAL_BLOCK_PTR(GET_BLOCK_PTR()), + vm_push_frame(th, class_iseq, VM_FRAME_MAGIC_CLASS | VM_ENV_FLAG_LOCAL, klass, + GET_BLOCK_HANDLER(), (VALUE)vm_cref_push(th, klass, NULL, FALSE), class_iseq->body->iseq_encoded, GET_SP(), - class_iseq->body->local_size, + class_iseq->body->local_table_size, class_iseq->body->stack_max); RESTORE_REGS(); NEXT_INSN(); @@ -1059,7 +1059,7 @@ opt_send_without_block https://github.com/ruby/ruby/blob/trunk/insns.def#L1059 (VALUE val) // inc += -ci->orig_argc; { struct rb_calling_info calling; - calling.blockptr = NULL; + calling.block_handler = VM_BLOCK_HANDLER_NONE; vm_search_method(ci, cc, calling.recv = TOPN(calling.argc = ci->orig_argc)); CALL_METHOD(&calling, ci, cc); } @@ -1097,7 +1097,7 @@ invokeblock https://github.com/ruby/ruby/blob/trunk/insns.def#L1097 { struct rb_calling_info calling; calling.argc = ci->orig_argc; - calling.blockptr = NULL; + calling.block_handler = VM_BLOCK_HANDLER_NONE; calling.recv = GET_SELF(); val = vm_invoke_block(th, GET_CFP(), &calling, ci); Index: ChangeLog =================================================================== --- ChangeLog (revision 55765) +++ ChangeLog (revision 55766) @@ -1,3 +1,23 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Thu Jul 28 19:53:21 2016 Koichi Sasada <ko1@a...> + + * vm_core.h: revisit the structure of frame, block and env. + [Bug #12628] + + This patch introduce many changes. + + * Introduce concept of "Block Handler (BH)" to represent + passed blocks. + + * move rb_control_frame_t::flag to ep[0] (as a special local + variable). This flags represents not only frame type, but also + env flags such as escaped. + + * rename `rb_block_t` to `struct rb_block`. + + * Make Proc, Binding and RubyVM::Env objects wb-protected. + + Check [Bug #12628] for more details. + Thu Jul 28 15:05:12 2016 Nobuyoshi Nakada <nobu@r...> * include/ruby/ruby.h (ruby_fl_type): use __extension__ to get rid Index: thread.c =================================================================== --- thread.c (revision 55765) +++ thread.c (revision 55766) @@ -587,10 +587,12 @@ thread_start_func_2(rb_thread_t *th, VAL https://github.com/ruby/ruby/blob/trunk/thread.c#L587 if (!th->first_func) { GetProcPtr(th->first_proc, proc); th->errinfo = Qnil; - th->root_lep = rb_vm_ep_local_ep(proc->block.ep); + th->root_lep = rb_vm_ep_local_ep(vm_proc_ep(th->first_proc)); th->root_svar = Qfalse; EXEC_EVENT_HOOK(th, RUBY_EVENT_THREAD_BEGIN, th->self, 0, 0, Qundef); - th->value = rb_vm_invoke_proc(th, proc, (int)RARRAY_LEN(args), RARRAY_CONST_PTR(args), 0); + th->value = rb_vm_invoke_proc(th, proc, + (int)RARRAY_LEN(args), RARRAY_CONST_PTR(args), + VM_BLOCK_HANDLER_NONE); EXEC_EVENT_HOOK(th, RUBY_EVENT_THREAD_END, th->self, 0, 0, Qundef); } else { Index: gc.c =================================================================== --- gc.c (revision 55765) +++ gc.c (revision 55766) @@ -9158,19 +9158,6 @@ rb_raw_iseq_info(char *buff, const int b https://github.com/ruby/ruby/blob/trunk/gc.c#L9158 } } -static const rb_iseq_t * -vm_proc_iseq(VALUE procval) -{ - rb_proc_t *proc = RTYPEDDATA_DATA(procval); - - if (RUBY_VM_NORMAL_ISEQ_P(proc->block.iseq)) { - return proc->block.iseq; - } - else { - return NULL; - } -} - const char * rb_raw_obj_info(char *buff, const int buff_size, VALUE obj) { Index: vm_core.h =================================================================== --- vm_core.h (revision 55765) +++ vm_core.h (revision 55766) @@ -47,8 +47,12 @@ https://github.com/ruby/ruby/blob/trunk/vm_core.h#L47 #if VM_CHECK_MODE > 0 #define VM_ASSERT(expr) ( \ RUBY_ASSERT_WHEN(VM_CHECK_MODE > 0, expr)) + +#define VM_UNREACHABLE(func) rb_bug(#func ": unreachable") + #else #define VM_ASSERT(expr) ((void)0) +#define VM_UNREACHABLE(func) ((void)0) #endif #define RUBY_VM_THREAD_MODEL 2 @@ -225,7 +229,7 @@ struct rb_call_info_with_kwarg { https://github.com/ruby/ruby/blob/trunk/vm_core.h#L229 }; struct rb_calling_info { - struct rb_block_struct *blockptr; + VALUE block_handler; VALUE recv; int argc; }; @@ -278,10 +282,6 @@ struct rb_iseq_constant_body { https://github.com/ruby/ruby/blob/trunk/vm_core.h#L282 ISEQ_TYPE_DEFINED_GUARD } type; /* instruction sequence type */ - unsigned int stack_max; /* for stack overflow check */ - /* sizeof(vars) + 1 */ - unsigned int local_size; - unsigned int iseq_size; const VALUE *iseq_encoded; /* encoded iseq (insn addr and operands) */ @@ -384,6 +384,7 @@ struct rb_iseq_constant_body { https://github.com/ruby/ruby/blob/trunk/vm_core.h#L384 unsigned int ci_size; unsigned int ci_kw_size; unsigned int line_info_size; + unsigned int stack_max; /* for stack overflow check */ }; /* T_IMEMO/iseq */ @@ -593,28 +594,52 @@ typedef struct rb_vm_struct { https://github.com/ruby/ruby/blob/trunk/vm_core.h#L594 #define VM_DEBUG_VERIFY_METHOD_CACHE (VM_DEBUG_MODE != 0) #endif +struct rb_captured_block { + VALUE self; + const VALUE *ep; + union { + const rb_iseq_t *iseq; + const struct vm_ifunc *ifunc; + VALUE val; + } code; +}; + +enum rb_block_handler_type { + block_handler_type_iseq, + block_handler_type_ifunc, + block_handler_type_symbol, + block_handler_type_proc +}; + +enum rb_block_type { + block_type_iseq, + block_type_ifunc, + block_type_symbol, + block_type_proc +}; + +struct rb_block { + union { + struct rb_captured_block captured; + VALUE symbol; + VALUE proc; + } as; + enum rb_block_type type; +}; + typedef struct rb_control_frame_struct { const VALUE *pc; /* cfp[0] */ VALUE *sp; /* cfp[1] */ const rb_iseq_t *iseq; /* cfp[2] */ - VALUE flag; /* cfp[3] */ - VALUE self; /* cfp[4] / block[0] */ - VALUE *ep; /* cfp[5] / block[1] */ - const rb_iseq_t *block_iseq;/* cfp[6] / block[2] */ - VALUE proc; /* cfp[7] / block[3] */ + VALUE self; /* cfp[3] / block[0] */ + const VALUE *ep; /* cfp[4] / block[1] */ + const void *block_code; /* cfp[5] / block[2] */ /* iseq or ifunc */ #if VM_DEBUG_BP_CHECK - VALUE *bp_check; /* cfp[8] */ + VALUE *bp_check; /* cfp[6] */ #endif } rb_control_frame_t; -typedef struct rb_block_struct { - VALUE self; /* share with method frame if it's only block */ - VALUE *ep; /* share with method frame if it's only block */ - const rb_iseq_t *iseq; - VALUE proc; -} rb_block_t; - extern const rb_data_type_t ruby_threadptr_data_type; #define GetThreadPtr(obj, ptr) \ @@ -690,7 +715,7 @@ typedef struct rb_thread_struct { https://github.com/ruby/ruby/blob/trunk/vm_core.h#L715 int waiting_fd; /* for rb_iterate */ - const rb_block_t *passed_block; + VALUE passed_block_handler; /* for bmethod */ const rb_callable_method_entry_t *passed_bmethod_me; @@ -703,7 +728,7 @@ typedef struct rb_thread_struct { https://github.com/ruby/ruby/blob/trunk/vm_core.h#L728 VALUE top_wrapper; /* eval env */ - VALUE *root_lep; + const VALUE *root_lep; VALUE root_svar; /* thread control */ @@ -822,8 +847,8 @@ rb_iseq_t *rb_iseq_new_with_opt(NODE*, V https://github.com/ruby/ruby/blob/trunk/vm_core.h#L847 /* src -> iseq */ rb_iseq_t *rb_iseq_compile(VALUE src, VALUE file, VALUE line); -rb_iseq_t *rb_iseq_compile_on_base(VALUE src, VALUE file, VALUE line, rb_block_t *base_block); -rb_iseq_t *rb_iseq_compile_with_option(VALUE src, VALUE file, VALUE absolute_path, VALUE line, rb_block_t *base_block, VALUE opt); +rb_iseq_t *rb_iseq_compile_on_base(VALUE src, VALUE file, VALUE line, const struct rb_block *base_block); +rb_iseq_t *rb_iseq_compile_with_option(VALUE src, VALUE file, VALUE absolute_path, VALUE line, const struct rb_block *base_block, VALUE opt); VALUE rb_iseq_disasm(const rb_iseq_t *iseq); int rb_iseq_disasm_insn(VALUE str, const VALUE *iseqval, size_t pos, const rb_iseq_t *iseq, VALUE child); @@ -841,7 +866,7 @@ RUBY_SYMBOL_EXPORT_END https://github.com/ruby/ruby/blob/trunk/vm_core.h#L866 GetCoreDataFromValue((obj), rb_proc_t, (ptr)) typedef struct { - rb_block_t block; + const struct rb_block block; int8_t safe_level; /* 0..1 */ int8_t is_from_method; /* bool */ int8_t is_lambda; /* bool */ @@ -852,8 +877,9 @@ typedef struct { https://github.com/ruby/ruby/blob/trunk/vm_core.h#L877 typedef struct { int env_size; - rb_block_t block; - VALUE env[1]; /* flexible array */ + const VALUE *ep; + const rb_iseq_t *iseq; + const VALUE env[1]; /* flexible array */ } rb_env_t; extern const rb_data_type_t ruby_binding_data_type; @@ -862,7 +888,7 @@ extern const rb_data_type_t ruby_binding https://github.com/ruby/ruby/blob/trunk/vm_core.h#L888 GetCoreDataFromValue((obj), rb_binding_t, (ptr)) typedef struct { - VALUE env; + struct rb_block block; VALUE path; unsigned short first_lineno; } rb_binding_t; @@ -903,32 +929,6 @@ enum vm_svar_index { https://github.com/ruby/ruby/blob/trunk/vm_core.h#L929 VM_SVAR_FLIPFLOP_START = 2 /* flipflop */ }; -#define VM_FRAME_MAGIC_METHOD 0x11 -#define VM_FRAME_MAGIC_BLOCK 0x21 -#define VM_FRAME_MAGIC_CLASS 0x31 -#define VM_FRAME_MAGIC_TOP 0x41 -#define VM_FRAME_MAGIC_CFUNC 0x61 -#define VM_FRAME_MAGIC_PROC 0x71 -#define VM_FRAME_MAGIC_IFUNC 0x81 -#define VM_FRAME_MAGIC_EVAL 0x91 -#define VM_FRAME_MAGIC_LAMBDA 0xa1 -#define VM_FRAME_MAGIC_RESCUE 0xb1 -#define VM_FRAME_MAGIC_DUMMY 0xc1 -#define VM_FRAME_MAGIC_MASK_BITS 8 -#define VM_FRAME_MAGIC_MASK (~(~(VALUE)0<<VM_FRAME_MAGIC_MASK_BITS)) - -#define VM_FRAME_TYPE(cfp) ((cfp)->flag & VM_FRAME_MAGIC_MASK) - -/* other frame flag */ -#define VM_FRAME_FLAG_PASSED 0x0100 -#define VM_FRAME_FLAG_FINISH 0x0200 -#define VM_FRAME_FLAG_BMETHOD 0x0400 -#define VM_FRAME_TYPE_FINISH_P(cfp) (((cfp)->flag & VM_FRAME_FLAG_FINISH) != 0) -#define VM_FRAME_TYPE_BMETHOD_P(cfp) (((cfp)->flag & VM_FRAME_FLAG_BMETHOD) != 0) - -#define RUBYVM_CFUNC_FRAME_P(cfp) \ - (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CFUNC) - /* inline cache */ typedef struct iseq_inline_cache_entry *IC; typedef struct rb_call_info *CALL_INFO; @@ -945,31 +945,180 @@ typedef VALUE CDHASH; https://github.com/ruby/ruby/blob/trunk/vm_core.h#L945 typedef rb_control_frame_t * (FUNC_FASTCALL(*rb_insn_func_t))(rb_thread_t *, rb_control_frame_t *); -#define GC_GUARDED_PTR(p) ((VALUE)((VALUE)(p) | 0x01)) -#define GC_GUARDED_PTR_REF(p) ((void *)(((VALUE)(p)) & ~0x03)) +#define VM_TAGGED_PTR_SET(p, tag) ((VALUE)(p) | (tag)) +#define VM_TAGGED_PTR_REF(v, mask) ((void *)((v) & ~mask)) + +#define GC_GUARDED_PTR(p) VM_TAGGED_PTR_SET((p), 0x01) +#define GC_GUARDED_PTR_REF(p) VM_TAGGED_PTR_REF((p), 0x03) #define GC_GUARDED_PTR_P(p) (((VALUE)(p)) & 0x01) -/* - * block frame: - * ep[ 0]: prev frame - * ep[-1]: CREF (for *_eval) - * - * method frame: - * ep[ 0]: block pointer (ptr | VM_ENVVAL_BLOCK_PTR_FLAG) - */ +enum { + /* Frame/Environment flag bits: + * MMMM MMMM MMMM MMMM ____ ____ FFFF EEEX (LSB) + * + * X : tag for GC marking (It seems as Fixnum) + * EEE : 3 bits Env flags + * FFFF: 4 bits Frame flags + * MMMM: 16 bits frame magic (to check frame corruption) + */ + + /* frame types */ + VM_FRAME_MAGIC_METHOD = 0x11110001, + VM_FRAME_MAGIC_BLOCK = 0x22220001, + VM_FRAME_MAGIC_CLASS = 0x33330001, + VM_FRAME_MAGIC_TOP = 0x44440001, + VM_FRAME_MAGIC_CFUNC = 0x55550001, + VM_FRAME_MAGIC_PROC = 0x66660001, + VM_FRAME_MAGIC_IFUNC = 0x77770001, + VM_FRAME_MAGIC_EVAL = 0x88880001, + VM_FRAME_MAGIC_LAMBDA = 0x99990001, + VM_FRAME_MAGIC_RESCUE = 0xaaaa0001, + VM_FRAME_MAGIC_DUMMY = 0xbbbb0001, + + VM_FRAME_MAGIC_MASK = 0xffff0001, + + /* frame flag */ + VM_FRAME_FLAG_PASSED = 0x0010, + VM_FRAME_FLAG_FINISH = 0x0020, + VM_FRAME_FLAG_BMETHOD = 0x0040, + + /* env flag */ + VM_ENV_FLAG_LOCAL = 0x0002, + VM_ENV_FLAG_ESCAPED = 0x0004, + VM_ENV_FLAG_WB_REQUIRED = 0x0008 +}; + +static inline void VM_FORCE_WRITE_SPECIAL_CONST(const VALUE *ptr, VALUE special_const_value); + +#define VM_FRAME_TYPE_FINISH_P(cfp) (VM_ENV_FLAGS((cfp)->ep, VM_FRAME_FLAG_FINISH ) != 0) +#define VM_FRAME_TYPE_BMETHOD_P(cfp) (VM_ENV_FLAGS((cfp)->ep, VM_FRAME_FLAG_BMETHOD) != 0) + +#define VM_ENV_DATA_SIZE ( 3) + +#define VM_ENV_DATA_INDEX_ME_CREF (-2) /* ep[-2] */ +#define VM_ENV_DATA_INDEX_SPECVAL (-1) /* ep[-1] */ +#define VM_ENV_DATA_INDEX_FLAGS ( 0) /* ep[ 0] */ +#define VM_ENV_DATA_INDEX_ENV ( 1) /* ep[ 1] */ +#define VM_ENV_DATA_INDEX_ENV_PROC ( 2) /* ep[ 2] */ + +#define VM_ENV_INDEX_LAST_LVAR (-VM_ENV_DATA_SIZE) + +static inline void +VM_ENV_FLAGS_SET(const VALUE *ep, VALUE flag) +{ + VALUE flags = ep[VM_ENV_DATA_INDEX_FLAGS]; + VM_ASSERT(FIXNUM_P(flags)); + VM_FORCE_WRITE_SPECIAL_CONST(&ep[VM_ENV_DATA_INDEX_FLAGS], flags | flag); +} + +static inline void +VM_ENV_FLAGS_UNSET(const VALUE *ep, VALUE flag) +{ + VALUE flags = ep[VM_ENV_DATA_INDEX_FLAGS]; + VM_ASSERT(FIXNUM_P(flags)); + VM_FORCE_WRITE_SPECIAL_CONST(&ep[VM_ENV_DATA_INDEX_FLAGS], flags & ~flag); +} + +static inline long +VM_ENV_FLAGS(const VALUE *ep, long flag) +{ + VALUE flags = ep[VM_ENV_DATA_INDEX_FLAGS]; + VM_ASSERT(FIXNUM_P(flags)); + return flags & flag; +} + +static inline long +VM_FRAME_TYPE(const rb_control_frame_t *cfp) +{ + return VM_ENV_FLAGS(cfp->ep, VM_FRAME_MAGIC_MASK); +} + +#define RUBYVM_CFUNC_FRAME_P(cfp) \ + (VM_FRAME_TYPE(cfp) == VM_FRAME_MAGIC_CFUNC) -#define VM_ENVVAL_BLOCK_PTR_FLAG 0x02 -#define VM_ENVVAL_BLOCK_PTR(v) (GC_GUARDED_PTR(v) | VM_ENVVAL_BLOCK_PTR_FLAG) -#define VM_ENVVAL_BLOCK_PTR_P(v) ((v) & VM_ENVVAL_BLOCK_PTR_FLAG) -#define VM_ENVVAL_PREV_EP_PTR(v) ((VALUE)GC_GUARDED_PTR(v)) -#define VM_ENVVAL_PREV_EP_PTR_P(v) (!(VM_ENVVAL_BLOCK_PTR_P(v))) - -#define VM_EP_PREV_EP(ep) ((VALUE *)GC_GUARDED_PTR_REF((ep)[0])) -#define VM_EP_BLOCK_PTR(ep) ((rb_block_t *)GC_GUARDED_PTR_REF((ep)[0])) -#define VM_EP_LEP_P(ep) VM_ENVVAL_BLOCK_PTR_P((ep)[0]) +#define VM_GUARDED_PREV_EP(ep) GC_GUARDED_PTR(ep) +#define VM_BLOCK_HANDLER_NONE 0 -VALUE *rb_vm_ep_local_ep(VALUE *ep); -rb_block_t *rb_vm_control_frame_block_ptr(const rb_control_frame_t *cfp); +static inline int +VM_ENV_LOCAL_P(const VALUE *ep) +{ + return VM_ENV_FLAGS(ep, VM_ENV_FLAG_LOCAL) ? 1 : 0; +} + +static inline const VALUE * +VM_ENV_PREV_EP(const VALUE *e (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/