mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* eval.c, gc.c, iseq.c, node.h, vm_insnhelper.c, vm_insnhelper.h,
vm_method.c: rename omod and overlaid modules to refinements. * eval.c (hidden_identity_hash_new): renamed from identity_hash_new. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37117 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
7b6e6ede60
commit
e028d3d905
11 changed files with 84 additions and 71 deletions
|
@ -1,3 +1,10 @@
|
|||
Mon Oct 8 23:02:19 2012 Shugo Maeda <shugo@ruby-lang.org>
|
||||
|
||||
* eval.c, gc.c, iseq.c, node.h, vm_insnhelper.c, vm_insnhelper.h,
|
||||
vm_method.c: rename omod and overlaid modules to refinements.
|
||||
|
||||
* eval.c (hidden_identity_hash_new): renamed from identity_hash_new.
|
||||
|
||||
Sun Oct 7 04:50:00 2012 Zachary Scott <zzak@ruby-lang.org>
|
||||
|
||||
* lib/abbrev.rb: Documentation examples for Abbrev.
|
||||
|
|
58
eval.c
58
eval.c
|
@ -1041,35 +1041,35 @@ void check_class_or_module(VALUE obj)
|
|||
}
|
||||
|
||||
static VALUE
|
||||
identity_hash_new()
|
||||
hidden_identity_hash_new()
|
||||
{
|
||||
VALUE hash = rb_hash_new();
|
||||
|
||||
rb_funcall(hash, rb_intern("compare_by_identity"), 0);
|
||||
RBASIC(hash)->klass = 0;
|
||||
RBASIC(hash)->klass = 0; /* hide from ObjectSpace */
|
||||
return hash;
|
||||
}
|
||||
|
||||
void
|
||||
rb_overlay_module(NODE *cref, VALUE klass, VALUE module)
|
||||
rb_using_refinement(NODE *cref, VALUE klass, VALUE module)
|
||||
{
|
||||
VALUE iclass, c, superclass = klass;
|
||||
|
||||
check_class_or_module(klass);
|
||||
Check_Type(module, T_MODULE);
|
||||
if (NIL_P(cref->nd_omod)) {
|
||||
cref->nd_omod = identity_hash_new();
|
||||
if (NIL_P(cref->nd_refinements)) {
|
||||
cref->nd_refinements = hidden_identity_hash_new();
|
||||
}
|
||||
else {
|
||||
if (cref->flags & NODE_FL_CREF_OMOD_SHARED) {
|
||||
cref->nd_omod = rb_hash_dup(cref->nd_omod);
|
||||
cref->nd_refinements = rb_hash_dup(cref->nd_refinements);
|
||||
cref->flags &= ~NODE_FL_CREF_OMOD_SHARED;
|
||||
}
|
||||
if (!NIL_P(c = rb_hash_lookup(cref->nd_omod, klass))) {
|
||||
if (!NIL_P(c = rb_hash_lookup(cref->nd_refinements, klass))) {
|
||||
superclass = c;
|
||||
while (c && TYPE(c) == T_ICLASS) {
|
||||
if (RBASIC(c)->klass == module) {
|
||||
/* already overlaid module */
|
||||
/* already used refinement */
|
||||
return;
|
||||
}
|
||||
c = RCLASS_SUPER(c);
|
||||
|
@ -1086,7 +1086,7 @@ rb_overlay_module(NODE *cref, VALUE klass, VALUE module)
|
|||
RCLASS_REFINED_CLASS(c) = klass;
|
||||
module = RCLASS_SUPER(module);
|
||||
}
|
||||
rb_hash_aset(cref->nd_omod, klass, iclass);
|
||||
rb_hash_aset(cref->nd_refinements, klass, iclass);
|
||||
rb_clear_cache_by_class(klass);
|
||||
}
|
||||
|
||||
|
@ -1095,21 +1095,21 @@ using_module_i(VALUE klass, VALUE module, VALUE arg)
|
|||
{
|
||||
NODE *cref = (NODE *) arg;
|
||||
|
||||
rb_overlay_module(cref, klass, module);
|
||||
rb_using_refinement(cref, klass, module);
|
||||
return ST_CONTINUE;
|
||||
}
|
||||
|
||||
void
|
||||
rb_using_module(NODE *cref, VALUE module)
|
||||
{
|
||||
ID id_overlaid_modules;
|
||||
VALUE overlaid_modules;
|
||||
ID id_refinements;
|
||||
VALUE refinements;
|
||||
|
||||
check_class_or_module(module);
|
||||
CONST_ID(id_overlaid_modules, "__overlaid_modules__");
|
||||
overlaid_modules = rb_attr_get(module, id_overlaid_modules);
|
||||
if (NIL_P(overlaid_modules)) return;
|
||||
rb_hash_foreach(overlaid_modules, using_module_i, (VALUE) cref);
|
||||
CONST_ID(id_refinements, "__refinements__");
|
||||
refinements = rb_attr_get(module, id_refinements);
|
||||
if (NIL_P(refinements)) return;
|
||||
rb_hash_foreach(refinements, using_module_i, (VALUE) cref);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1130,7 +1130,7 @@ rb_mod_using(VALUE self, VALUE module)
|
|||
CONST_ID(id_using_modules, "__using_modules__");
|
||||
using_modules = rb_attr_get(self, id_using_modules);
|
||||
if (NIL_P(using_modules)) {
|
||||
using_modules = identity_hash_new();
|
||||
using_modules = hidden_identity_hash_new();
|
||||
rb_ivar_set(self, id_using_modules, using_modules);
|
||||
}
|
||||
rb_hash_aset(using_modules, module, Qtrue);
|
||||
|
@ -1170,8 +1170,8 @@ refinement_module_include(int argc, VALUE *argv, VALUE module)
|
|||
while (RUBY_VM_VALID_CONTROL_FRAME_P(cfp, end_cfp)) {
|
||||
if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq) &&
|
||||
(cref = rb_vm_get_cref(cfp->iseq, cfp->ep)) &&
|
||||
!NIL_P(cref->nd_omod) &&
|
||||
!NIL_P(c = rb_hash_lookup(cref->nd_omod, klass))) {
|
||||
!NIL_P(cref->nd_refinements) &&
|
||||
!NIL_P(c = rb_hash_lookup(cref->nd_refinements, klass))) {
|
||||
while (argc--) {
|
||||
VALUE mod = argv[argc];
|
||||
if (rb_class_inherited_p(module, mod)) {
|
||||
|
@ -1200,17 +1200,17 @@ rb_mod_refine(VALUE module, VALUE klass)
|
|||
{
|
||||
NODE *cref = rb_vm_cref();
|
||||
VALUE mod;
|
||||
ID id_overlaid_modules, id_refined_class;
|
||||
VALUE overlaid_modules;
|
||||
ID id_refinements, id_refined_class;
|
||||
VALUE refinements;
|
||||
|
||||
check_class_or_module(klass);
|
||||
CONST_ID(id_overlaid_modules, "__overlaid_modules__");
|
||||
overlaid_modules = rb_attr_get(module, id_overlaid_modules);
|
||||
if (NIL_P(overlaid_modules)) {
|
||||
overlaid_modules = identity_hash_new();
|
||||
rb_ivar_set(module, id_overlaid_modules, overlaid_modules);
|
||||
CONST_ID(id_refinements, "__refinements__");
|
||||
refinements = rb_attr_get(module, id_refinements);
|
||||
if (NIL_P(refinements)) {
|
||||
refinements = hidden_identity_hash_new();
|
||||
rb_ivar_set(module, id_refinements, refinements);
|
||||
}
|
||||
mod = rb_hash_lookup(overlaid_modules, klass);
|
||||
mod = rb_hash_lookup(refinements, klass);
|
||||
if (NIL_P(mod)) {
|
||||
mod = rb_module_new();
|
||||
CONST_ID(id_refined_class, "__refined_class__");
|
||||
|
@ -1219,8 +1219,8 @@ rb_mod_refine(VALUE module, VALUE klass)
|
|||
refinement_module_method_added, 1);
|
||||
rb_define_singleton_method(mod, "include",
|
||||
refinement_module_include, -1);
|
||||
rb_overlay_module(cref, klass, mod);
|
||||
rb_hash_aset(overlaid_modules, klass, mod);
|
||||
rb_using_refinement(cref, klass, mod);
|
||||
rb_hash_aset(refinements, klass, mod);
|
||||
}
|
||||
rb_mod_module_eval(0, NULL, mod);
|
||||
return mod;
|
||||
|
|
2
gc.c
2
gc.c
|
@ -2733,7 +2733,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE ptr)
|
|||
break;
|
||||
|
||||
case NODE_CREF:
|
||||
gc_mark(objspace, obj->as.node.nd_omod);
|
||||
gc_mark(objspace, obj->as.node.nd_refinements);
|
||||
gc_mark(objspace, (VALUE)obj->as.node.u1.node);
|
||||
ptr = (VALUE)obj->as.node.u3.node;
|
||||
goto again;
|
||||
|
|
|
@ -1027,7 +1027,7 @@ invokesuper
|
|||
if (me && me->def->type == VM_METHOD_TYPE_ISEQ &&
|
||||
me->def->body.iseq == ip) {
|
||||
klass = RCLASS_SUPER(klass);
|
||||
me = rb_method_entry_get_with_omod(Qnil, klass, id, &klass);
|
||||
me = rb_method_entry_get_with_refinements(Qnil, klass, id, &klass);
|
||||
}
|
||||
|
||||
CALL_METHOD(num, blockptr, flag, id, me, recv, klass);
|
||||
|
|
8
iseq.c
8
iseq.c
|
@ -202,11 +202,11 @@ set_relation(rb_iseq_t *iseq, const VALUE parent)
|
|||
if (type == ISEQ_TYPE_TOP) {
|
||||
/* toplevel is private */
|
||||
iseq->cref_stack = NEW_CREF(rb_cObject);
|
||||
iseq->cref_stack->nd_omod = Qnil;
|
||||
iseq->cref_stack->nd_refinements = Qnil;
|
||||
iseq->cref_stack->nd_visi = NOEX_PRIVATE;
|
||||
if (th->top_wrapper) {
|
||||
NODE *cref = NEW_CREF(th->top_wrapper);
|
||||
cref->nd_omod = Qnil;
|
||||
cref->nd_refinements = Qnil;
|
||||
cref->nd_visi = NOEX_PRIVATE;
|
||||
cref->nd_next = iseq->cref_stack;
|
||||
iseq->cref_stack = cref;
|
||||
|
@ -214,7 +214,7 @@ set_relation(rb_iseq_t *iseq, const VALUE parent)
|
|||
}
|
||||
else if (type == ISEQ_TYPE_METHOD || type == ISEQ_TYPE_CLASS) {
|
||||
iseq->cref_stack = NEW_CREF(0); /* place holder */
|
||||
iseq->cref_stack->nd_omod = Qnil;
|
||||
iseq->cref_stack->nd_refinements = Qnil;
|
||||
}
|
||||
else if (RTEST(parent)) {
|
||||
rb_iseq_t *piseq;
|
||||
|
@ -1657,7 +1657,7 @@ rb_iseq_clone(VALUE iseqval, VALUE newcbase)
|
|||
}
|
||||
if (newcbase) {
|
||||
iseq1->cref_stack = NEW_CREF(newcbase);
|
||||
iseq1->cref_stack->nd_omod = iseq0->cref_stack->nd_omod;
|
||||
iseq1->cref_stack->nd_refinements = iseq0->cref_stack->nd_refinements;
|
||||
iseq1->cref_stack->nd_visi = iseq0->cref_stack->nd_visi;
|
||||
if (iseq0->cref_stack->nd_next) {
|
||||
iseq1->cref_stack->nd_next = iseq0->cref_stack->nd_next;
|
||||
|
|
4
method.h
4
method.h
|
@ -91,8 +91,8 @@ void rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc,
|
|||
rb_method_entry_t *rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *option, rb_method_flag_t noex);
|
||||
rb_method_entry_t *rb_method_entry(VALUE klass, ID id, VALUE *define_class_ptr);
|
||||
|
||||
rb_method_entry_t *rb_method_entry_get_with_omod(VALUE omod, VALUE klass, ID id, VALUE *define_class_ptr);
|
||||
rb_method_entry_t *rb_method_entry_get_without_cache(VALUE klass, VALUE omod, ID id, VALUE *define_class_ptr);
|
||||
rb_method_entry_t *rb_method_entry_get_with_refinements(VALUE refinements, VALUE klass, ID id, VALUE *define_class_ptr);
|
||||
rb_method_entry_t *rb_method_entry_get_without_cache(VALUE klass, VALUE refinements, ID id, VALUE *define_class_ptr);
|
||||
rb_method_entry_t *rb_method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *, rb_method_flag_t noex);
|
||||
|
||||
int rb_method_entry_arity(const rb_method_entry_t *me);
|
||||
|
|
2
node.h
2
node.h
|
@ -281,7 +281,7 @@ typedef struct RNode {
|
|||
#define nd_set_line(n,l) \
|
||||
RNODE(n)->flags=((RNODE(n)->flags&~(-1<<NODE_LSHIFT))|(((l)&NODE_LMASK)<<NODE_LSHIFT))
|
||||
|
||||
#define nd_omod nd_reserved
|
||||
#define nd_refinements nd_reserved
|
||||
|
||||
#define nd_head u1.node
|
||||
#define nd_alen u2.argc
|
||||
|
|
|
@ -385,7 +385,8 @@ rb_search_method_entry(VALUE recv, ID mid, VALUE *defined_class_ptr)
|
|||
rb_id2name(mid), type, (void *)recv, flags, klass);
|
||||
}
|
||||
}
|
||||
return rb_method_entry_get_with_omod(Qnil, klass, mid, defined_class_ptr);
|
||||
return rb_method_entry_get_with_refinements(Qnil, klass, mid,
|
||||
defined_class_ptr);
|
||||
}
|
||||
|
||||
static inline int
|
||||
|
|
|
@ -1140,7 +1140,7 @@ vm_cref_push(rb_thread_t *th, VALUE klass, int noex, rb_block_t *blockptr)
|
|||
{
|
||||
rb_control_frame_t *cfp = vm_get_ruby_level_caller_cfp(th, th->cfp);
|
||||
NODE *cref = NEW_CREF(klass);
|
||||
cref->nd_omod = Qnil;
|
||||
cref->nd_refinements = Qnil;
|
||||
cref->nd_visi = noex;
|
||||
|
||||
if (blockptr) {
|
||||
|
@ -1151,7 +1151,7 @@ vm_cref_push(rb_thread_t *th, VALUE klass, int noex, rb_block_t *blockptr)
|
|||
}
|
||||
/* TODO: why cref->nd_next is 1? */
|
||||
if (cref->nd_next && cref->nd_next != (void *) 1 &&
|
||||
!NIL_P(cref->nd_next->nd_omod)) {
|
||||
!NIL_P(cref->nd_next->nd_refinements)) {
|
||||
COPY_CREF_OMOD(cref, cref->nd_next);
|
||||
}
|
||||
|
||||
|
|
|
@ -171,8 +171,8 @@ enum vm_regan_acttype {
|
|||
/**********************************************************/
|
||||
|
||||
#define COPY_CREF_OMOD(c1, c2) do { \
|
||||
(c1)->nd_omod = (c2)->nd_omod; \
|
||||
if (!NIL_P((c2)->nd_omod)) { \
|
||||
(c1)->nd_refinements = (c2)->nd_refinements; \
|
||||
if (!NIL_P((c2)->nd_refinements)) { \
|
||||
(c1)->flags |= NODE_FL_CREF_OMOD_SHARED; \
|
||||
(c2)->flags |= NODE_FL_CREF_OMOD_SHARED; \
|
||||
} \
|
||||
|
|
61
vm_method.c
61
vm_method.c
|
@ -21,7 +21,7 @@ struct cache_entry { /* method hash table. */
|
|||
VALUE filled_version; /* filled state version */
|
||||
ID mid; /* method's id */
|
||||
VALUE klass; /* receiver's class */
|
||||
VALUE omod; /* overlay modules */
|
||||
VALUE refinements; /* refinements */
|
||||
rb_method_entry_t *me;
|
||||
VALUE defined_class;
|
||||
};
|
||||
|
@ -405,16 +405,17 @@ lookup_method_table(VALUE klass, ID id, st_data_t *body)
|
|||
}
|
||||
|
||||
static inline rb_method_entry_t*
|
||||
search_method_with_omod(VALUE klass, ID id, VALUE omod, VALUE *defined_class_ptr)
|
||||
search_method_with_refinements(VALUE klass, ID id, VALUE refinements,
|
||||
VALUE *defined_class_ptr)
|
||||
{
|
||||
st_data_t body;
|
||||
VALUE iclass, skipped_class = Qnil;
|
||||
|
||||
for (body = 0; klass; klass = RCLASS_SUPER(klass)) {
|
||||
if (klass != skipped_class) {
|
||||
iclass = rb_hash_lookup(omod, klass);
|
||||
iclass = rb_hash_lookup(refinements, klass);
|
||||
if (NIL_P(iclass) && BUILTIN_TYPE(klass) == T_ICLASS) {
|
||||
iclass = rb_hash_lookup(omod, RBASIC(klass)->klass);
|
||||
iclass = rb_hash_lookup(refinements, RBASIC(klass)->klass);
|
||||
if (!NIL_P(iclass))
|
||||
iclass = copy_refinement_iclass(iclass, klass);
|
||||
}
|
||||
|
@ -432,7 +433,7 @@ search_method_with_omod(VALUE klass, ID id, VALUE omod, VALUE *defined_class_ptr
|
|||
}
|
||||
|
||||
static inline rb_method_entry_t*
|
||||
search_method_without_omod(VALUE klass, ID id, VALUE *defined_class_ptr)
|
||||
search_method_without_refinements(VALUE klass, ID id, VALUE *defined_class_ptr)
|
||||
{
|
||||
st_data_t body;
|
||||
|
||||
|
@ -446,13 +447,14 @@ search_method_without_omod(VALUE klass, ID id, VALUE *defined_class_ptr)
|
|||
}
|
||||
|
||||
static rb_method_entry_t*
|
||||
search_method(VALUE klass, ID id, VALUE omod, VALUE *defined_class_ptr)
|
||||
search_method(VALUE klass, ID id, VALUE refinements, VALUE *defined_class_ptr)
|
||||
{
|
||||
if (NIL_P(omod)) {
|
||||
return search_method_without_omod(klass, id, defined_class_ptr);
|
||||
if (NIL_P(refinements)) {
|
||||
return search_method_without_refinements(klass, id, defined_class_ptr);
|
||||
}
|
||||
else {
|
||||
return search_method_with_omod(klass, id, omod, defined_class_ptr);
|
||||
return search_method_with_refinements(klass, id, refinements,
|
||||
defined_class_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -463,18 +465,19 @@ search_method(VALUE klass, ID id, VALUE omod, VALUE *defined_class_ptr)
|
|||
* rb_method_entry() simply.
|
||||
*/
|
||||
rb_method_entry_t *
|
||||
rb_method_entry_get_without_cache(VALUE klass, VALUE omod, ID id,
|
||||
rb_method_entry_get_without_cache(VALUE klass, VALUE refinements, ID id,
|
||||
VALUE *defined_class_ptr)
|
||||
{
|
||||
VALUE defined_class;
|
||||
rb_method_entry_t *me = search_method(klass, id, omod, &defined_class);
|
||||
rb_method_entry_t *me = search_method(klass, id, refinements,
|
||||
&defined_class);
|
||||
|
||||
if (ruby_running) {
|
||||
struct cache_entry *ent;
|
||||
ent = cache + EXPR1(klass, omod, id);
|
||||
ent = cache + EXPR1(klass, refinements, id);
|
||||
ent->filled_version = GET_VM_STATE_VERSION();
|
||||
ent->klass = klass;
|
||||
ent->omod = omod;
|
||||
ent->refinements = refinements;
|
||||
ent->defined_class = defined_class;
|
||||
|
||||
if (UNDEFINED_METHOD_ENTRY_P(me)) {
|
||||
|
@ -494,22 +497,23 @@ rb_method_entry_get_without_cache(VALUE klass, VALUE omod, ID id,
|
|||
}
|
||||
|
||||
rb_method_entry_t *
|
||||
rb_method_entry_get_with_omod(VALUE omod, VALUE klass, ID id,
|
||||
VALUE *defined_class_ptr)
|
||||
rb_method_entry_get_with_refinements(VALUE refinements, VALUE klass, ID id,
|
||||
VALUE *defined_class_ptr)
|
||||
{
|
||||
#if OPT_GLOBAL_METHOD_CACHE
|
||||
struct cache_entry *ent;
|
||||
|
||||
ent = cache + EXPR1(klass, omod, id);
|
||||
ent = cache + EXPR1(klass, refinements, id);
|
||||
if (ent->filled_version == GET_VM_STATE_VERSION() &&
|
||||
ent->mid == id && ent->klass == klass && ent->omod == omod) {
|
||||
ent->mid == id && ent->klass == klass &&
|
||||
ent->refinements == refinements) {
|
||||
if (defined_class_ptr)
|
||||
*defined_class_ptr = ent->defined_class;
|
||||
return ent->me;
|
||||
}
|
||||
#endif
|
||||
|
||||
return rb_method_entry_get_without_cache(klass, omod, id,
|
||||
return rb_method_entry_get_without_cache(klass, refinements, id,
|
||||
defined_class_ptr);
|
||||
}
|
||||
|
||||
|
@ -517,12 +521,13 @@ rb_method_entry_t *
|
|||
rb_method_entry(VALUE klass, ID id, VALUE *defined_class_ptr)
|
||||
{
|
||||
NODE *cref = rb_vm_cref();
|
||||
VALUE omod = Qnil;
|
||||
VALUE refinements = Qnil;
|
||||
|
||||
if (cref && !NIL_P(cref->nd_omod)) {
|
||||
omod = cref->nd_omod;
|
||||
if (cref && !NIL_P(cref->nd_refinements)) {
|
||||
refinements = cref->nd_refinements;
|
||||
}
|
||||
return rb_method_entry_get_with_omod(omod, klass, id, defined_class_ptr);
|
||||
return rb_method_entry_get_with_refinements(refinements, klass, id,
|
||||
defined_class_ptr);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -712,8 +717,8 @@ rb_undef(VALUE klass, ID id)
|
|||
{
|
||||
rb_method_entry_t *me;
|
||||
NODE *cref = rb_vm_cref();
|
||||
VALUE omod = Qnil;
|
||||
void rb_overlay_module(NODE *cref, VALUE klass, VALUE module);
|
||||
VALUE refinements = Qnil;
|
||||
void rb_using_refinement(NODE *cref, VALUE klass, VALUE module);
|
||||
|
||||
if (NIL_P(klass)) {
|
||||
rb_raise(rb_eTypeError, "no class to undef method");
|
||||
|
@ -729,10 +734,10 @@ rb_undef(VALUE klass, ID id)
|
|||
rb_warn("undefining `%s' may cause serious problems", rb_id2name(id));
|
||||
}
|
||||
|
||||
if (cref && !NIL_P(cref->nd_omod)) {
|
||||
omod = cref->nd_omod;
|
||||
if (cref && !NIL_P(cref->nd_refinements)) {
|
||||
refinements = cref->nd_refinements;
|
||||
}
|
||||
me = search_method(klass, id, omod, 0);
|
||||
me = search_method(klass, id, refinements, 0);
|
||||
|
||||
if (UNDEFINED_METHOD_ENTRY_P(me)) {
|
||||
const char *s0 = " class";
|
||||
|
@ -755,7 +760,7 @@ rb_undef(VALUE klass, ID id)
|
|||
|
||||
if (!RTEST(rb_class_inherited_p(klass, me->klass))) {
|
||||
VALUE mod = rb_module_new();
|
||||
rb_overlay_module(cref, klass, mod);
|
||||
rb_using_refinement(cref, klass, mod);
|
||||
klass = mod;
|
||||
}
|
||||
rb_add_method(klass, id, VM_METHOD_TYPE_UNDEF, 0, NOEX_PUBLIC);
|
||||
|
|
Loading…
Reference in a new issue