Skip to content

Commit 36fb0f4

Browse files
committed
keep virtual block in scope while its pointer is
1 parent 8ee0910 commit 36fb0f4

1 file changed

Lines changed: 50 additions & 64 deletions

File tree

jsrc/ar.c

Lines changed: 50 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,7 +1102,7 @@ DF2(jtfoldZ){F12IP;
11021102
#define STATEDYADX 29 // call is dyadic. Must be the MSB of the flags
11031103
#define STATEDYAD ((I)1<<STATEDYADX)
11041104
static DF2(jtfold12){F12IP;A z,vz;
1105-
struct foldstatus foldinfo={{0,0,0},0}; // fold status shared between F: and Z: zstatus: fold limit; abort; abort iteration; quiet iteration; halt after current
1105+
struct foldstatus foldinfo={{0,0,0},0}; // fold status shared between F: and Z: exestatus[3] followed by zstatus mask: fold limit; abort; abort iteration; quiet iteration; halt after current
11061106
ARGCHK2(a,w);
11071107
I dyad=EPDYAD; w=EPDYAD?w:a; A uself=FAV(self)->fgh[0]; A vself=FAV(self)->fgh[1];
11081108
if(unlikely(((UI)a^(UI)w)<(UI)dyad))jtfg=(J)((I)jtfg&~(JTINPLACEA|JTINPLACEW)); // can't inplace equal args
@@ -1115,7 +1115,9 @@ static DF2(jtfold12){F12IP;A z,vz;
11151115
I wr=AR(w); I wcr=wr-SGNTO0(-wr); // rank of w, rank of an item of w
11161116
UI wni; SETIC(w,wni); UI nitems=wni+(dmfr>>STATEDYADX); // #items of y; # items to process into u including x if given; number of turns through loop
11171117
UI zzalloc=64-(AKXR(1)>>LGSZI); zzalloc=MIN(nitems,zzalloc); zzalloc=dmfr&STATEFWD+STATEREV?zzalloc:16-(AKXR(1)>>LGSZI); zzalloc=dmfr&STATEMULT?zzalloc:1; // initial result allo. zzalloc is #boxes in zz; AN(zz) is # valid
1118-
A zz; GATV0E(zz,INT,zzalloc,dmfr&STATEMULT?1:0,goto exitpop;) AT(zz)=BOX; AFLAG(zz)=BOX&RECURSIBLE; AN(zz)=0; // alloc result area. avoid init of BOX area
1118+
A zz; GATV0E(zz,INT,zzalloc,dmfr&STATEMULT?1:0,goto exitpop;) AT(zz)=BOX; AFLAG(zz)=BOX&RECURSIBLE; AN(zz)=0; // alloc recursive result area. avoid init of BOX area
1119+
// Track the items of y (x arg into v) using a virtual arg
1120+
fauxblock(virtwfaux);
11191121
A virtw; // virtual block for items of y, if needed
11201122
I wstride; // dist between items of y, in bytes, pos/neg/0 based on fwd/rev
11211123
if(likely((dmfr&STATEFWD+STATEREV)!=0)){
@@ -1125,13 +1127,13 @@ static DF2(jtfold12){F12IP;A z,vz;
11251127
// Create the cell to run u on: one given argument or a cell of fills
11261128
if(nitems==1){
11271129
// 1 item. Could come from x (if y is empty) or y. Apply u to it, to give the final result
1128-
++foldinfo.exestats[0]; foldinfo.zstatus=0; dfv1(z,dmfr&STATEDYAD?a:head(w),uself);
1130+
++foldinfo.exestats[0]; foldinfo.zstatus=0; dfv1(z,dmfr&STATEDYAD?a:head(w),uself); // scaf* should be stats[1]
11291131
}else{
11301132
// 0 items (necessarily monadic). Error if fold multiple. Create a neutral for v from an item of y, and apply u to it
11311133
ASSERT(!(dmfr&STATEMULT),EVDOMAIN) // empty multiple fold is < 0 applications of v, error
11321134
A fillcell=jtred0(jt,w,vself); // a neutral with the shape of an item of y
11331135
ASSERTGOTO(fillcell!=0,EVDOMAIN,exitpop) // error if v has no neutral
1134-
++foldinfo.exestats[0]; foldinfo.zstatus=0; dfv1(z,fillcell,uself);
1136+
++foldinfo.exestats[0]; foldinfo.zstatus=0; dfv1(z,fillcell,uself); // scaf* should be stats[1]
11351137
}
11361138
// we have applied u to the single cell.
11371139
ASSERTGOTO(!(foldinfo.zstatus&0b01111),EVNORESULT,exitpop) // z stopped iteration and no result was created: that's a no result error
@@ -1142,8 +1144,6 @@ static DF2(jtfold12){F12IP;A z,vz;
11421144
zz=z; goto abortexit; // return z
11431145
}else{
11441146
// At least 2 items. Run the fold loop.
1145-
// Track the items of y (x arg into v) using a virtual arg
1146-
fauxblock(virtwfaux);
11471147
// if the original block was direct inplaceable, make the virtual block inplaceable. (We can't do this for indirect blocks because a virtual block is not marked recursive - rather it increments
11481148
// the usecount of the entire backing block - and modifying the virtual contents would leave the usecounts invalid since the backing block is always recursive (having been ra'd). Maybe could do this if it isn't?)
11491149
I wcn; PROD(wcn,wcr,AS(w)+1); // number of atoms in a cell
@@ -1174,87 +1174,73 @@ static DF2(jtfold12){F12IP;A z,vz;
11741174
jtfg = (J)((I)jtfg & ~(JTWILLBEOPENED+JTCOUNTITEMS+JTINPLACEA)); // never inplace x, which repeats if given; pass along original inplaceability of y
11751175
virtw=a; vz=w; // v starts on w and then reapplies to the result; save a reg by moving a to virtw
11761176
}
1177-
A *_old=jt->tnextpushp; // pop back to here to clear everything except the result & any early allocation
1177+
A *_old=jt->tnextpushp; // pop back to here to clear everything except the result & any early allocation. We make sure each new result allocation uses the same tstack location
11781178

11791179
I zstatus; // combined Z: results from this exec of v/u
11801180
// Loop executing u/v
11811181
do{
11821182
A tz; // will hold result from v while we are deciding whether to keep it
11831183
zstatus=0; // saved zstatus for this turn through the loop
1184-
++foldinfo.exestats[0]; foldinfo.zstatus=0; // incr stats for exec
1184+
++foldinfo.exestats[0]; foldinfo.zstatus=0; // incr v execct
11851185
// ************* run v
1186-
if(dmfr&STATEFWD+STATEREV){
1186+
if(dmfr&STATEFWD+STATEREV){ // not directionless
11871187
if(dmfr&ZZFLAGVIRTAINPLACE)ACRESET(virtw,ACUC1+ACINPLACE); // in case it was modified, restore inplaceability to the UNINCORPABLE block
11881188
tz=CALL2IP(FAV(vself)->valencefns[1],virtw,vz,vself); // fwd/rev. newitem v vz a is inplaceable if y was (set above). w is inplaceable first time based on initial-item status
11891189
if(unlikely(tz==virtw)){RZGOTO(tz=clonevirtual(tz),exitpop)}
11901190
AK(virtw)+=wstride; // advance item pointer to next/prev if there is one
11911191
}else tz=CALL21IP(dmfr>>STATEDYADX,FAV(vself)->valencefns[dmfr>>STATEDYADX],virtw,vz,vself); // directionless dyad/monad [x] v vz
1192+
11921193
jtfg=(J)((I)jtfg|JTINPLACEW); // w inplaceable on all iterations after the first
11931194
zstatus|=foldinfo.zstatus; // remember termination flags from zstatus
11941195
if(unlikely(zstatus&0b00011))goto errfinish; // z stopped iteration: finish up
11951196
vz=tz!=0?tz:vz; // if v ran to completion, use its result for the next iteration
1196-
if(likely(!(zstatus&0b00100))){ // is 'abort iteration'? (has z=0). If so, skip u & result store
1197-
if(unlikely(tz==0))goto errfinish; // error in v, exit
1198-
// ************** run u
1199-
++foldinfo.exestats[1]; foldinfo.zstatus=0; z=CALL1(FAV(uself)->valencefns[0],tz,uself); // never inplace
1200-
zstatus|=foldinfo.zstatus; // remember termination flags from zstatus
1201-
if(unlikely(zstatus&0b00011))goto errfinish; // z stopped iteration: finish up
1202-
if(likely(!(zstatus&0b00100))){ // is 'abort iteration'? (has z=0) if so, skip result store
1203-
if(unlikely(z==0))goto errfinish; // error in u, exit
1204-
if(!(zstatus&0b01000)){ // if store of result not suppressed... */
1205-
// ******************** the u result is to be added to the total (possibly replacing it)
1206-
// we install z into the result zz, which takes over its protection as long as that result survives. We would like to do this with ZAP
1207-
// if possible, because that way the usecount will never get to 2 and we can avoid RFO cycles.
1208-
// If zz is destroyed, its protection of z will be lost. That is OK unless somehow a value from up the stack, with protection ONLY on the stack.
1209-
// The only way such a value can get to us is through the arguments a/w - any named value is protected in its executing sentence, and any value in a box
1210-
// is protected in the box. Thus we ZAP unless the result is our a input
1211-
++foldinfo.exestats[2]; realizeifvirtual(z);
1212-
if(likely(z!=a)){razaptstackend(z);}else ra(z) // raise the block we are adding to the recursive result
1213-
if(dmfr&STATEMULT){ // is Fold Multiple?
1214-
// we are adding uz to a recursible block, with transfer of ownership. The new owner protects the block. If uz is abandoned it is safe to zap even if it is x. Sets new uz
1215-
// Fold Multiple. Add the new value to the result array
1216-
UI newslot=AN(zz); // where the new value will go
1217-
#if 1 // test version to try to eliminate crash
1218-
if(withprob(newslot==zzalloc,0.03)){ // current alloc full?
1219-
// current alloc is full. Double the allocation, swap it with zz (transferring ownership), and copy the data
1220-
zzalloc=2*zzalloc+(AKXR(1)>>LGSZI); // new allocation, cacheline multiple
1221-
// obsolete A zznew; GATV0E(zznew,INT,zzalloc,1,goto exitpop;) A *zznewzap=AZAPLOC(zznew); A *zzzap=AZAPLOC(zz); // allocate, & get pointers to tstack slots old & new
1222-
A zznew; GATV0E(zznew,INT,zzalloc,1,goto exitpop;) ACINITUNPUSH(zznew) // allocate & zap new block
1223-
// obsolete AT(zz)=INT; AFLAG(zz)=0;
1224-
JMC(AAV1(zznew),AAV1(zz),newslot<<LGSZI,0) AZAPLOC(zznew)=AZAPLOC(zz);
1225-
AT(zznew)=BOX; AFLAG(zznew)=BOX&RECURSIBLE; // new zz now has pointers to allocated blocks and to its dedicated zaploc
1226-
AN(zznew)=newslot+1; AAV(zznew)[newslot]=z; // AAV not AAV1
1227-
*AZAPLOC(zz)=zznew;
1228-
// obsolete mf(zz);
1229-
zz=zznew; // swap buffers, transferring ownership to zznew & protecting it; free zz using mf to avoid traversing boxes
1230-
// obsolete *zznewzap=zz;
1231-
}else{AAV1(zz)[newslot]=z; AN(zz)=newslot+1;} // install the new value & account for it in len
1232-
#else
1233-
if(withprob(newslot==zzalloc,0.03)){ // current alloc full?
1234-
// current alloc is full. Double the allocation, swap it with zz (transferring ownership), and copy the data
1235-
zzalloc=2*zzalloc+(AKXR(1)>>LGSZI); // new allocation, cacheline multiple
1197+
if(unlikely(zstatus&0b00100))goto abortiter; // is 'abort iteration'? (has z=0). If so, skip u & result store
1198+
if(unlikely(tz==0))goto errfinish; // error in v, exit
1199+
// ************** run u
1200+
++foldinfo.exestats[1]; foldinfo.zstatus=0; z=CALL1(FAV(uself)->valencefns[0],tz,uself); // never inplace. Increment count of executions of u
1201+
1202+
zstatus|=foldinfo.zstatus; // remember termination flags from zstatus
1203+
if(unlikely(zstatus&0b00011))goto errfinish; // z stopped iteration: finish up
1204+
if(unlikely(zstatus&0b00100))goto abortiter; // is 'abort iteration'? (has z=0) if so, skip result store
1205+
if(unlikely(z==0))goto errfinish; // error in u, exit
1206+
if(!(zstatus&0b01000)){ // if store of result not suppressed... */
1207+
// ******************** the u result is to be added to the total (possibly replacing it)
1208+
// we install z into the result zz, which takes over its protection as long as that result survives. We would like to do this with ZAP
1209+
// if possible, because that way the usecount will never get to 2 and we can avoid RFO cycles.
1210+
// If zz is destroyed, its protection of z will be lost. That is OK unless somehow z is a value from up the stack, with protection ONLY on the stack.
1211+
// The only way such a value can get to us is through the arguments a/w - any named value is protected in its executing sentence, and any value in a box
1212+
// is protected in the box. Thus we ZAP unless the result is our a input
1213+
++foldinfo.exestats[2]; realizeifvirtual(z); // Increment count of results added
1214+
if(likely(z!=a)){razaptstackend(z);}else ra(z) // raise the block we are adding to the recursive result
1215+
if(dmfr&STATEMULT){ // is Fold Multiple?
1216+
// we are adding uz to a recursible block, with transfer of ownership. The new owner protects the block. If uz is abandoned it is safe to zap even if it is x. Sets new uz
1217+
// Fold Multiple. Add the new value to the result array
1218+
UI newslot=AN(zz); // where the new value will go
1219+
if(withprob(newslot==zzalloc,0.03)){ // current alloc full?
1220+
// current alloc is full. Double the allocation, swap it with zz (transferring ownership), and copy the data
1221+
zzalloc=2*zzalloc+(AKXR(1)>>LGSZI); // new allocation, cacheline multiple
12361222
// obsolete A zznew; GATV0E(zznew,INT,zzalloc,1,goto exitpop;) A *zznewzap=AZAPLOC(zznew); A *zzzap=AZAPLOC(zz); // allocate, & get pointers to tstack slots old & new
1237-
A zznew; GATV0E(zznew,INT,zzalloc,1,goto exitpop;) ACINITUNPUSH(zznew) // allocate & zap new block
1223+
A zznew; GATV0E(zznew,INT,zzalloc,1,goto exitpop;) ACINITUNPUSH(zznew) // allocate & zap new block
12381224
// obsolete AT(zz)=INT; AFLAG(zz)=0;
1239-
JMC(AAV1(zznew),AAV1(zz),newslot<<LGSZI,0) AZAPLOC(zznew)=AZAPLOC(zz); *AZAPLOC(zz)=zznew; mf(zz); zz=zznew; // swap buffers, transferring ownership to zznew & protecting it; free zz using mf to avoid traversing boxes
1225+
JMC(AAV1(zznew),AAV1(zz),newslot<<LGSZI,0) AZAPLOC(zznew)=AZAPLOC(zz); *AZAPLOC(zz)=zznew; mf(zz); zz=zznew; // swap buffers, transferring ownership to zznew & protecting it; free zz using mf to avoid traversing boxes
12401226
// obsolete *zznewzap=zz;
1241-
AT(zz)=BOX; AFLAG(zz)=BOX&RECURSIBLE; // new zz now has pointers to allocated blocks and to its dedicated zaploc
1242-
}
1243-
AAV1(zz)[newslot]=z; AN(zz)=newslot+1; // install the new value & account for it in len
1244-
#endif
1245-
}else{
1246-
// Fold Single. Replace the value in zz
1247-
// obsolete ra(z) // uz is not guaranteed to stay in the result till the end; therefore we must not zap it for fold single since it might be w also.
1248-
if(AN(zz)!=0){A t=AAV0(zz)[0]; if(MEMAUDIT&0x3e)AAV0(zz)[0]=0; fa(t);} else{AN(zz)=1;} // free old value if any, mark value now valid (clear value in buffer before auditing)
1249-
AAV0(zz)[0]=z; // install new value
1250-
}
1227+
AT(zz)=BOX; AFLAG(zz)=BOX&RECURSIBLE; // new zz now has pointers to allocated blocks and to its dedicated zaploc
12511228
}
1252-
}else RESETERR // 'abort iteration' from u: clear error for next time
1253-
}else RESETERR // 'abort iteration' from v: clear error for next time
1229+
AAV1(zz)[newslot]=z; AN(zz)=newslot+1; // install the new value & account for it in len
1230+
}else{
1231+
// Fold Single. Replace the value in zz
1232+
// obsolete ra(z) // uz is not guaranteed to stay in the result till the end; therefore we must not zap it for fold single since it might be w also.
1233+
if(AN(zz)!=0){A t=AAV0(zz)[0]; if(MEMAUDIT&0x3e)AAV0(zz)[0]=0; fa(t);} else{AN(zz)=1;} // free old value if any, mark value now valid (clear value in buffer before auditing)
1234+
AAV0(zz)[0]=z; // install new value
1235+
}
1236+
}
1237+
1238+
if(0){abortiter: RESETERR} // 'abort iteration': clear error for next time
12541239
// ready for next iteration, whether the previous one completed or not
12551240
if(unlikely(zstatus&0b10000))break; // if early termination, exit loop
12561241
// it is possible that virtw has been passed through to vz. In that case, we have to copy it
12571242
// because we are about to relocate virtw. It is OK to keep vz virtual.
1243+
// ***************** free any result we aren't keeping
12581244
if(unlikely((vz=gc(vz,_old))==0))goto exitpop; // pop back everything but vz, result & virtuals (removing z at least)
12591245
}while(--nitems);
12601246
loopend:;
@@ -1298,7 +1284,7 @@ DF2(jtfoldZ2){F12IP;
12981284
ASSERT(BETWEENC(type,-3,1),EVINDEX) // requested action index must be in range
12991285
I y;
13001286
if(type==-3){y=rei0(w); y=jt->afoldinfo->exestats[0]>=y; // set y if current v count high enough
1301-
}else RE(y=b0(w)); // verify boolean
1287+
}else y=reb0(w); // verify boolean
13021288
if(y){
13031289
I ymask=1<<(type-(-3)); // convert type to one-hot
13041290
jt->afoldinfo->zstatus|=ymask; // accumulate zstatus

0 commit comments

Comments
 (0)