diff options
author | Daniel Gröber <dxld@darkboxed.org> | 2019-06-23 16:30:12 +0200 |
---|---|---|
committer | Daniel Gröber <dxld@darkboxed.org> | 2019-09-22 15:18:10 +0200 |
commit | b7e15d17a48286548f26f93594fb1b0b700dd422 (patch) | |
tree | c2059caee250b149549a1f559c05939f0c816c5c /rts/RetainerProfile.c | |
parent | ec1d76e29d517e9c3c37e0a481f0cbac79687776 (diff) | |
download | haskell-b7e15d17a48286548f26f93594fb1b0b700dd422.tar.gz |
rts: retainer: Rename heap traversal functions for extraction
This gets all remaining functions in-line with the new 'traverse' prefix
and module name.
Diffstat (limited to 'rts/RetainerProfile.c')
-rw-r--r-- | rts/RetainerProfile.c | 199 |
1 files changed, 99 insertions, 100 deletions
diff --git a/rts/RetainerProfile.c b/rts/RetainerProfile.c index d17a60a65b..e127afe5ae 100644 --- a/rts/RetainerProfile.c +++ b/rts/RetainerProfile.c @@ -108,7 +108,7 @@ static uint32_t timesAnyObjectVisited; // number of times any objects are * * There is one exception to this rule, namely: static objects. There we do just * go over the heap and reset the bit manually. See - * 'resetStaticObjectForRetainerProfiling'. + * 'resetStaticObjectForProfiling'. */ StgWord flip = 0; // flip bit // must be 0 if DEBUG_RETAINER is on (for static closures) @@ -246,10 +246,9 @@ typedef bool (*visitClosure_cb) ( traverseState g_retainerTraverseState; -static void retainStack(traverseState *, StgClosure *, stackData, StgPtr, StgPtr); -static void retainClosure(traverseState *, StgClosure *, StgClosure *, retainer); -static void retainPushClosure(traverseState *, StgClosure *, StgClosure *, stackData); -static void retainActualPush(traverseState *, stackElement *); +static void traverseStack(traverseState *, StgClosure *, stackData, StgPtr, StgPtr); +static void traverseClosure(traverseState *, StgClosure *, StgClosure *, retainer); +static void traversePushClosure(traverseState *, StgClosure *, StgClosure *, stackData); // number of blocks allocated for one stack @@ -318,7 +317,7 @@ closeTraverseStack( traverseState *ts ) * Returns true if the whole stack is empty. * -------------------------------------------------------------------------- */ static INLINE bool -isEmptyRetainerStack( traverseState *ts ) +isEmptyWorkStack( traverseState *ts ) { return (ts->firstStack == ts->currentStack) && ts->stackTop == ts->stackLimit; } @@ -327,11 +326,10 @@ isEmptyRetainerStack( traverseState *ts ) * Returns size of stack * -------------------------------------------------------------------------- */ W_ -retainerStackBlocks( void ) +traverseWorkStackBlocks(traverseState *ts) { bdescr* bd; W_ res = 0; - traverseState *ts = &g_retainerTraverseState; for (bd = ts->firstStack; bd != NULL; bd = bd->link) res += bd->blocks; @@ -339,6 +337,12 @@ retainerStackBlocks( void ) return res; } +W_ +retainerStackBlocks(void) +{ + return traverseWorkStackBlocks(&g_retainerTraverseState); +} + /* ----------------------------------------------------------------------------- * Returns true if stackTop is at the stack boundary of the current stack, * i.e., if the current stack chunk is empty. @@ -419,7 +423,8 @@ find_srt( stackPos *info ) * Pushes an element onto traverse stack * -------------------------------------------------------------------------- */ static void -retainActualPush(traverseState *ts, stackElement *se) { +pushStackElement(traverseState *ts, stackElement *se) +{ bdescr *nbd; // Next Block Descriptor if (ts->stackTop - 1 < ts->stackBottom) { #if defined(DEBUG_RETAINER) @@ -466,7 +471,7 @@ retainActualPush(traverseState *ts, stackElement *se) { * c_child_r - closure retainer. */ static INLINE void -retainPushClosure( traverseState *ts, StgClosure *c, StgClosure *cp, stackData data) { +traversePushClosure(traverseState *ts, StgClosure *c, StgClosure *cp, stackData data) { stackElement se; se.c = c; @@ -474,7 +479,7 @@ retainPushClosure( traverseState *ts, StgClosure *c, StgClosure *cp, stackData d se.data = data; se.info.type = posTypeFresh; - retainActualPush(ts, &se); + pushStackElement(ts, &se); }; /* ----------------------------------------------------------------------------- @@ -493,7 +498,7 @@ retainPushClosure( traverseState *ts, StgClosure *c, StgClosure *cp, stackData d * Note: SRTs are considered to be children as well. * -------------------------------------------------------------------------- */ static INLINE void -push( traverseState *ts, StgClosure *c, stackData data, StgClosure **first_child ) +traversePushChildren(traverseState *ts, StgClosure *c, stackData data, StgClosure **first_child) { stackElement se; bdescr *nbd; // Next Block Descriptor @@ -697,7 +702,7 @@ push( traverseState *ts, StgClosure *c, stackData data, StgClosure **first_child // here though. So type must be !=posTypeFresh. ASSERT(se.info.type != posTypeFresh); - retainActualPush(ts, &se); + pushStackElement(ts, &se); } /* ----------------------------------------------------------------------------- @@ -714,8 +719,26 @@ push( traverseState *ts, StgClosure *c, stackData data, StgClosure **first_child * is called only within popOff() and nowhere else. * -------------------------------------------------------------------------- */ static void -popOffReal(traverseState *ts) -{ +popStackElement(traverseState *ts) { +#if defined(DEBUG_RETAINER) + debugBelch("popStackElement(): stackTop = 0x%x, currentStackBoundary = 0x%x\n", ts->stackTop, ts->currentStackBoundary); +#endif + + ASSERT(ts->stackTop != ts->stackLimit); + ASSERT(!isEmptyWorkStack(ts)); + + // <= (instead of <) is wrong! + if (ts->stackTop + 1 < ts->stackLimit) { + ts->stackTop++; +#if defined(DEBUG_RETAINER) + ts->stackSize--; + if (ts->stackSize > ts->maxStackSize) ts->maxStackSize = ts->stackSize; + ASSERT(ts->stackSize >= 0); + debugBelch("stackSize = (--) %d\n", ts->stackSize); +#endif + return; + } + bdescr *pbd; // Previous Block Descriptor #if defined(DEBUG_RETAINER) @@ -756,30 +779,6 @@ popOffReal(traverseState *ts) #endif } -static INLINE void -popOff(traverseState *ts) { -#if defined(DEBUG_RETAINER) - debugBelch("\tpopOff(): stackTop = 0x%x, currentStackBoundary = 0x%x\n", ts->stackTop, ts->currentStackBoundary); -#endif - - ASSERT(ts->stackTop != ts->stackLimit); - ASSERT(!isEmptyRetainerStack(ts)); - - // <= (instead of <) is wrong! - if (ts->stackTop + 1 < ts->stackLimit) { - ts->stackTop++; -#if defined(DEBUG_RETAINER) - ts->stackSize--; - if (ts->stackSize > ts->maxStackSize) ts->maxStackSize = ts->stackSize; - ASSERT(ts->stackSize >= 0); - debugBelch("stackSize = %d\n", ts->stackSize); -#endif - return; - } - - popOffReal(ts); -} - /* ----------------------------------------------------------------------------- * Finds the next object to be considered for retainer profiling and store * its pointer to *c. @@ -799,7 +798,7 @@ popOff(traverseState *ts) { * is empty. * -------------------------------------------------------------------------- */ static INLINE void -pop( traverseState *ts, StgClosure **c, StgClosure **cp, stackData *data ) +traversePop(traverseState *ts, StgClosure **c, StgClosure **cp, stackData *data) { stackElement *se; @@ -826,7 +825,7 @@ pop( traverseState *ts, StgClosure **c, StgClosure **cp, stackData *data ) *cp = se->cp; *c = se->c; *data = se->data; - popOff(ts); + popStackElement(ts); return; } @@ -877,7 +876,7 @@ pop( traverseState *ts, StgClosure **c, StgClosure **cp, stackData *data ) uint32_t field_no = se->info.next.step & 3; if (entry_no == ((StgTRecChunk *)se->c)->next_entry_idx) { *c = NULL; - popOff(ts); + popStackElement(ts); break; // this breaks out of the switch not the loop } entry = &((StgTRecChunk *)se->c)->entries[entry_no]; @@ -908,7 +907,7 @@ pop( traverseState *ts, StgClosure **c, StgClosure **cp, stackData *data ) case SMALL_MUT_ARR_PTRS_FROZEN_DIRTY: *c = find_ptrs(&se->info); if (*c == NULL) { - popOff(ts); + popStackElement(ts); break; // this breaks out of the switch not the loop } goto out; @@ -950,7 +949,7 @@ pop( traverseState *ts, StgClosure **c, StgClosure **cp, stackData *data ) case THUNK_1_1: *c = find_srt(&se->info); if(*c == NULL) { - popOff(ts); + popStackElement(ts); break; // this breaks out of the switch not the loop } goto out; @@ -997,7 +996,7 @@ out: *data = se->data; if(last) - popOff(ts); + popStackElement(ts); return; @@ -1038,7 +1037,7 @@ endRetainerProfiling( void ) * The reason is that we do not know when a closure is visited last. * -------------------------------------------------------------------------- */ static INLINE void -maybeInitTravData( StgClosure *c ) +traverseMaybeInitClosureData(StgClosure *c) { if (!isTravDataValid(c)) { setTravDataToZero(c); @@ -1200,7 +1199,7 @@ associate( StgClosure *c, RetainerSet *s ) -------------------------------------------------------------------------- */ static void -retain_large_bitmap (traverseState *ts, StgPtr p, StgLargeBitmap *large_bitmap, +traverseLargeBitmap (traverseState *ts, StgPtr p, StgLargeBitmap *large_bitmap, uint32_t size, StgClosure *c, stackData data) { uint32_t i, b; @@ -1210,7 +1209,7 @@ retain_large_bitmap (traverseState *ts, StgPtr p, StgLargeBitmap *large_bitmap, bitmap = large_bitmap->bitmap[b]; for (i = 0; i < size; ) { if ((bitmap & 1) == 0) { - retainPushClosure(ts, (StgClosure *)*p, c, data); + traversePushClosure(ts, (StgClosure *)*p, c, data); } i++; p++; @@ -1224,12 +1223,12 @@ retain_large_bitmap (traverseState *ts, StgPtr p, StgLargeBitmap *large_bitmap, } static INLINE StgPtr -retain_small_bitmap (traverseState *ts, StgPtr p, uint32_t size, StgWord bitmap, +traverseSmallBitmap (traverseState *ts, StgPtr p, uint32_t size, StgWord bitmap, StgClosure *c, stackData data) { while (size > 0) { if ((bitmap & 1) == 0) { - retainPushClosure(ts, (StgClosure *)*p, c, data); + traversePushClosure(ts, (StgClosure *)*p, c, data); } p++; bitmap = bitmap >> 1; @@ -1257,8 +1256,8 @@ retain_small_bitmap (traverseState *ts, StgPtr p, uint32_t size, StgWord bitmap, * retainPushClosure() is invoked instead of evacuate(). * -------------------------------------------------------------------------- */ static void -retainStack( traverseState *ts, StgClosure *c, stackData data, - StgPtr stackStart, StgPtr stackEnd ) +traversePushStack(traverseState *ts, StgClosure *cp, stackData data, + StgPtr stackStart, StgPtr stackEnd) { stackElement *oldStackBoundary; StgPtr p; @@ -1280,7 +1279,7 @@ retainStack( traverseState *ts, StgClosure *c, stackData data, oldStackBoundary, ts->currentStackBoundary); #endif - ASSERT(get_itbl(c)->type == STACK); + ASSERT(get_itbl(cp)->type == STACK); p = stackStart; while (p < stackEnd) { @@ -1289,7 +1288,7 @@ retainStack( traverseState *ts, StgClosure *c, stackData data, switch(info->i.type) { case UPDATE_FRAME: - retainPushClosure(ts, ((StgUpdateFrame *)p)->updatee, c, data); + traversePushClosure(ts, ((StgUpdateFrame *)p)->updatee, cp, data); p += sizeofW(StgUpdateFrame); continue; @@ -1303,11 +1302,11 @@ retainStack( traverseState *ts, StgClosure *c, stackData data, bitmap = BITMAP_BITS(info->i.layout.bitmap); size = BITMAP_SIZE(info->i.layout.bitmap); p++; - p = retain_small_bitmap(ts, p, size, bitmap, c, data); + p = traverseSmallBitmap(ts, p, size, bitmap, cp, data); follow_srt: if (info->i.srt) { - retainPushClosure(ts, GET_SRT(info), c, data); + traversePushClosure(ts, GET_SRT(info), cp, data); } continue; @@ -1315,11 +1314,11 @@ retainStack( traverseState *ts, StgClosure *c, stackData data, StgBCO *bco; p++; - retainPushClosure(ts, (StgClosure*)*p, c, data); + traversePushClosure(ts, (StgClosure*)*p, cp, data); bco = (StgBCO *)*p; p++; size = BCO_BITMAP_SIZE(bco); - retain_large_bitmap(ts, p, BCO_BITMAP(bco), size, c, data); + traverseLargeBitmap(ts, p, BCO_BITMAP(bco), size, cp, data); p += size; continue; } @@ -1328,8 +1327,8 @@ retainStack( traverseState *ts, StgClosure *c, stackData data, case RET_BIG: size = GET_LARGE_BITMAP(&info->i)->size; p++; - retain_large_bitmap(ts, p, GET_LARGE_BITMAP(&info->i), - size, c, data); + traverseLargeBitmap(ts, p, GET_LARGE_BITMAP(&info->i), + size, cp, data); p += size; // and don't forget to follow the SRT goto follow_srt; @@ -1338,7 +1337,7 @@ retainStack( traverseState *ts, StgClosure *c, stackData data, StgRetFun *ret_fun = (StgRetFun *)p; const StgFunInfoTable *fun_info; - retainPushClosure(ts, ret_fun->fun, c, data); + traversePushClosure(ts, ret_fun->fun, cp, data); fun_info = get_fun_itbl(UNTAG_CONST_CLOSURE(ret_fun->fun)); p = (P_)&ret_fun->payload; @@ -1346,18 +1345,18 @@ retainStack( traverseState *ts, StgClosure *c, stackData data, case ARG_GEN: bitmap = BITMAP_BITS(fun_info->f.b.bitmap); size = BITMAP_SIZE(fun_info->f.b.bitmap); - p = retain_small_bitmap(ts, p, size, bitmap, c, data); + p = traverseSmallBitmap(ts, p, size, bitmap, cp, data); break; case ARG_GEN_BIG: size = GET_FUN_LARGE_BITMAP(fun_info)->size; - retain_large_bitmap(ts, p, GET_FUN_LARGE_BITMAP(fun_info), - size, c, data); + traverseLargeBitmap(ts, p, GET_FUN_LARGE_BITMAP(fun_info), + size, cp, data); p += size; break; default: bitmap = BITMAP_BITS(stg_arg_bitmaps[fun_info->f.fun_type]); size = BITMAP_SIZE(stg_arg_bitmaps[fun_info->f.fun_type]); - p = retain_small_bitmap(ts, p, size, bitmap, c, data); + p = traverseSmallBitmap(ts, p, size, bitmap, cp, data); break; } goto follow_srt; @@ -1382,7 +1381,7 @@ retainStack( traverseState *ts, StgClosure *c, stackData data, * ------------------------------------------------------------------------- */ static INLINE StgPtr -retain_PAP_payload (traverseState *ts, +traversePAP (traverseState *ts, StgClosure *pap, /* NOT tagged */ stackData data, StgClosure *fun, /* tagged */ @@ -1392,7 +1391,7 @@ retain_PAP_payload (traverseState *ts, StgWord bitmap; const StgFunInfoTable *fun_info; - retainPushClosure(ts, fun, pap, data); + traversePushClosure(ts, fun, pap, data); fun = UNTAG_CLOSURE(fun); fun_info = get_fun_itbl(fun); ASSERT(fun_info->i.type != PAP); @@ -1402,22 +1401,22 @@ retain_PAP_payload (traverseState *ts, switch (fun_info->f.fun_type) { case ARG_GEN: bitmap = BITMAP_BITS(fun_info->f.b.bitmap); - p = retain_small_bitmap(ts, p, n_args, bitmap, + p = traverseSmallBitmap(ts, p, n_args, bitmap, pap, data); break; case ARG_GEN_BIG: - retain_large_bitmap(ts, p, GET_FUN_LARGE_BITMAP(fun_info), + traverseLargeBitmap(ts, p, GET_FUN_LARGE_BITMAP(fun_info), n_args, pap, data); p += n_args; break; case ARG_BCO: - retain_large_bitmap(ts, (StgPtr)payload, BCO_BITMAP(fun), + traverseLargeBitmap(ts, (StgPtr)payload, BCO_BITMAP(fun), n_args, pap, data); p += n_args; break; default: bitmap = BITMAP_BITS(stg_arg_bitmaps[fun_info->f.fun_type]); - p = retain_small_bitmap(ts, p, n_args, bitmap, pap, data); + p = traverseSmallBitmap(ts, p, n_args, bitmap, pap, data); break; } return p; @@ -1531,7 +1530,7 @@ traverseWorkStack(traverseState *ts, visitClosure_cb visit_cb) // data_out = data to associate with current closure's children loop: - pop(ts, &c, &cp, &data); + traversePop(ts, &c, &cp, &data); if (c == NULL) { return; @@ -1589,7 +1588,7 @@ inner_loop: // But what about CONSTR? Surely these may be able // to appear, and they don't have SRTs, so we can't // check. So for now, we're calling - // resetStaticObjectForRetainerProfiling() from the + // resetStaticObjectForProfiling() from the // garbage collector to reset the retainer sets in all the // reachable static objects. goto loop; @@ -1609,7 +1608,7 @@ inner_loop: } // If this is the first visit to c, initialize its data. - maybeInitTravData(c); + traverseMaybeInitClosureData(c); if(visit_cb(c, cp, data, (stackData*)&child_data)) goto loop; @@ -1621,7 +1620,7 @@ inner_loop: // would be hard. switch (typeOfc) { case STACK: - retainStack(ts, c, child_data, + traversePushStack(ts, c, child_data, ((StgStack *)c)->sp, ((StgStack *)c)->stack + ((StgStack *)c)->stack_size); goto loop; @@ -1630,16 +1629,16 @@ inner_loop: { StgTSO *tso = (StgTSO *)c; - retainPushClosure(ts, (StgClosure *) tso->stackobj, c, child_data); - retainPushClosure(ts, (StgClosure *) tso->blocked_exceptions, c, child_data); - retainPushClosure(ts, (StgClosure *) tso->bq, c, child_data); - retainPushClosure(ts, (StgClosure *) tso->trec, c, child_data); + traversePushClosure(ts, (StgClosure *) tso->stackobj, c, child_data); + traversePushClosure(ts, (StgClosure *) tso->blocked_exceptions, c, child_data); + traversePushClosure(ts, (StgClosure *) tso->bq, c, child_data); + traversePushClosure(ts, (StgClosure *) tso->trec, c, child_data); if ( tso->why_blocked == BlockedOnMVar || tso->why_blocked == BlockedOnMVarRead || tso->why_blocked == BlockedOnBlackHole || tso->why_blocked == BlockedOnMsgThrowTo ) { - retainPushClosure(ts, tso->block_info.closure, c, child_data); + traversePushClosure(ts, tso->block_info.closure, c, child_data); } goto loop; } @@ -1647,36 +1646,36 @@ inner_loop: case BLOCKING_QUEUE: { StgBlockingQueue *bq = (StgBlockingQueue *)c; - retainPushClosure(ts, (StgClosure *) bq->link, c, child_data); - retainPushClosure(ts, (StgClosure *) bq->bh, c, child_data); - retainPushClosure(ts, (StgClosure *) bq->owner, c, child_data); + traversePushClosure(ts, (StgClosure *) bq->link, c, child_data); + traversePushClosure(ts, (StgClosure *) bq->bh, c, child_data); + traversePushClosure(ts, (StgClosure *) bq->owner, c, child_data); goto loop; } case PAP: { StgPAP *pap = (StgPAP *)c; - retain_PAP_payload(ts, c, child_data, pap->fun, pap->payload, pap->n_args); + traversePAP(ts, c, child_data, pap->fun, pap->payload, pap->n_args); goto loop; } case AP: { StgAP *ap = (StgAP *)c; - retain_PAP_payload(ts, c, child_data, ap->fun, ap->payload, ap->n_args); + traversePAP(ts, c, child_data, ap->fun, ap->payload, ap->n_args); goto loop; } case AP_STACK: - retainPushClosure(ts, ((StgAP_STACK *)c)->fun, c, child_data); - retainStack(ts, c, child_data, + traversePushClosure(ts, ((StgAP_STACK *)c)->fun, c, child_data); + traversePushStack(ts, c, child_data, (StgPtr)((StgAP_STACK *)c)->payload, (StgPtr)((StgAP_STACK *)c)->payload + ((StgAP_STACK *)c)->size); goto loop; } - push(ts, c, child_data, &first_child); + traversePushChildren(ts, c, child_data, &first_child); // If first_child is null, c has no child. // If first_child is not null, the top stack element points to the next @@ -1703,15 +1702,15 @@ retainRoot(void *user, StgClosure **tl) // We no longer assume that only TSOs and WEAKs are roots; any closure can // be a root. - ASSERT(isEmptyRetainerStack(ts)); + ASSERT(isEmptyWorkStack(ts)); ts->currentStackBoundary = ts->stackTop; c = UNTAG_CLOSURE(*tl); - maybeInitTravData(c); + traverseMaybeInitClosureData(c); if (c != &stg_END_TSO_QUEUE_closure && isRetainer(c)) { - retainPushClosure(ts, c, c, (stackData)getRetainerFrom(c)); + traversePushClosure(ts, c, c, (stackData)getRetainerFrom(c)); } else { - retainPushClosure(ts, c, c, (stackData)CCS_SYSTEM); + traversePushClosure(ts, c, c, (stackData)CCS_SYSTEM); } traverseWorkStack(ts, &retainVisitClosure); @@ -1769,7 +1768,7 @@ computeRetainerSet( traverseState *ts ) for (bd = capabilities[n]->mut_lists[g]; bd != NULL; bd = bd->link) { for (ml = bd->start; ml < bd->free; ml++) { - maybeInitTravData((StgClosure *)*ml); + traverseMaybeInitClosureData((StgClosure *)*ml); } } } @@ -1779,7 +1778,7 @@ computeRetainerSet( traverseState *ts ) /* ----------------------------------------------------------------------------- * Traverse all static objects for which we compute retainer sets, * and reset their rs fields to NULL, which is accomplished by - * invoking maybeInitTravData(). This function must be called + * invoking traverseMaybeInitClosureData(). This function must be called * before zeroing all objects reachable from scavenged_static_objects * in the case of major garbage collections. See GarbageCollect() in * GC.c. @@ -1795,14 +1794,14 @@ computeRetainerSet( traverseState *ts ) * SDM (20/7/2011): I don't think this is doing anything sensible, * because it happens before retainerProfile() and at the beginning of * retainerProfil() we change the sense of 'flip'. So all of the - * calls to maybeInitTravData() here are initialising retainer sets + * calls to traverseMaybeInitClosureData() here are initialising retainer sets * with the wrong flip. Also, I don't see why this is necessary. I - * added a maybeInitTravData() call to retainRoot(), and that seems + * added a traverseMaybeInitClosureData() call to retainRoot(), and that seems * to have fixed the assertion failure in retainerSetOf() I was * encountering. * -------------------------------------------------------------------------- */ void -resetStaticObjectForRetainerProfiling( StgClosure *static_objects ) +resetStaticObjectForProfiling( StgClosure *static_objects ) { #if defined(DEBUG_RETAINER) uint32_t count; @@ -1826,7 +1825,7 @@ resetStaticObjectForRetainerProfiling( StgClosure *static_objects ) p = (StgClosure*)*IND_STATIC_LINK(p); break; case THUNK_STATIC: - maybeInitTravData(p); + traverseMaybeInitClosureData(p); p = (StgClosure*)*THUNK_STATIC_LINK(p); break; case FUN_STATIC: @@ -1835,11 +1834,11 @@ resetStaticObjectForRetainerProfiling( StgClosure *static_objects ) case CONSTR_2_0: case CONSTR_1_1: case CONSTR_NOCAF: - maybeInitTravData(p); + traverseMaybeInitClosureData(p); p = (StgClosure*)*STATIC_LINK(get_itbl(p), p); break; default: - barf("resetStaticObjectForRetainerProfiling: %p (%s)", + barf("resetStaticObjectForProfiling: %p (%s)", p, get_itbl(p)->type); break; } |