You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: jsrc/ar.c
+50-64Lines changed: 50 additions & 64 deletions
Original file line number
Diff line number
Diff line change
@@ -1102,7 +1102,7 @@ DF2(jtfoldZ){F12IP;
1102
1102
#defineSTATEDYADX 29 // call is dyadic. Must be the MSB of the flags
1103
1103
#defineSTATEDYAD ((I)1<<STATEDYADX)
1104
1104
staticDF2(jtfold12){F12IP;Az,vz;
1105
-
structfoldstatusfoldinfo={{0,0,0},0}; // fold status shared between F: and Z: zstatus: fold limit; abort; abort iteration; quiet iteration; halt after current
1105
+
structfoldstatusfoldinfo={{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
Iwr=AR(w); Iwcr=wr-SGNTO0(-wr); // rank of w, rank of an item of w
1116
1116
UIwni; SETIC(w,wni); UInitems=wni+(dmfr>>STATEDYADX); // #items of y; # items to process into u including x if given; number of turns through loop
1117
1117
UIzzalloc=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
-
Azz; GATV0E(zz,INT,zzalloc,dmfr&STATEMULT?1:0,gotoexitpop;) AT(zz)=BOX; AFLAG(zz)=BOX&RECURSIBLE; AN(zz)=0; // alloc result area. avoid init of BOX area
1118
+
Azz; GATV0E(zz,INT,zzalloc,dmfr&STATEMULT?1:0,gotoexitpop;) 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);
1119
1121
Avirtw; // virtual block for items of y, if needed
1120
1122
Iwstride; // dist between items of y, in bytes, pos/neg/0 based on fwd/rev
// Track the items of y (x arg into v) using a virtual arg
1146
-
fauxblock(virtwfaux);
1147
1147
// 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
1148
1148
// 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?)
1149
1149
Iwcn; PROD(wcn,wcr,AS(w)+1); // number of atoms in a cell
jtfg= (J)((I)jtfg& ~(JTWILLBEOPENED+JTCOUNTITEMS+JTINPLACEA)); // never inplace x, which repeats if given; pass along original inplaceability of y
1175
1175
virtw=a; vz=w; // v starts on w and then reapplies to the result; save a reg by moving a to virtw
1176
1176
}
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
1178
1178
1179
1179
Izstatus; // combined Z: results from this exec of v/u
1180
1180
// Loop executing u/v
1181
1181
do{
1182
1182
Atz; // will hold result from v while we are deciding whether to keep it
1183
1183
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
1185
1185
// ************* run v
1186
-
if(dmfr&STATEFWD+STATEREV){
1186
+
if(dmfr&STATEFWD+STATEREV){// not directionless
1187
1187
if(dmfr&ZZFLAGVIRTAINPLACE)ACRESET(virtw,ACUC1+ACINPLACE); // in case it was modified, restore inplaceability to the UNINCORPABLE block
1188
1188
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
AK(virtw)+=wstride; // advance item pointer to next/prev if there is one
1191
1191
}elsetz=CALL21IP(dmfr>>STATEDYADX,FAV(vself)->valencefns[dmfr>>STATEDYADX],virtw,vz,vself); // directionless dyad/monad [x] v vz
1192
+
1192
1193
jtfg=(J)((I)jtfg|JTINPLACEW); // w inplaceable on all iterations after the first
1193
1194
zstatus|=foldinfo.zstatus; // remember termination flags from zstatus
1194
1195
if(unlikely(zstatus&0b00011))goto errfinish; // z stopped iteration: finish up
1195
1196
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);}elsera(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
-
UInewslot=AN(zz); // where the new value will go
1217
-
#if1// 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
-
Azznew; GATV0E(zznew,INT,zzalloc,1,gotoexitpop;) ACINITUNPUSH(zznew) // allocate & zap new block
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);}elsera(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
+
UInewslot=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
1236
1222
// 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
-
Azznew; GATV0E(zznew,INT,zzalloc,1,gotoexitpop;) ACINITUNPUSH(zznew) // allocate & zap new block
1223
+
Azznew; GATV0E(zznew,INT,zzalloc,1,gotoexitpop;) ACINITUNPUSH(zznew) // allocate & zap new block
1238
1224
// 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
1240
1226
// 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){At=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
1251
1228
}
1252
-
}elseRESETERR// 'abort iteration' from u: clear error for next time
1253
-
}elseRESETERR// '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){At=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
1254
1239
// ready for next iteration, whether the previous one completed or not
1255
1240
if(unlikely(zstatus&0b10000))break; // if early termination, exit loop
1256
1241
// it is possible that virtw has been passed through to vz. In that case, we have to copy it
1257
1242
// because we are about to relocate virtw. It is OK to keep vz virtual.
1243
+
// ***************** free any result we aren't keeping
1258
1244
if(unlikely((vz=gc(vz,_old))==0))goto exitpop; // pop back everything but vz, result & virtuals (removing z at least)
1259
1245
}while(--nitems);
1260
1246
loopend:;
@@ -1298,7 +1284,7 @@ DF2(jtfoldZ2){F12IP;
1298
1284
ASSERT(BETWEENC(type,-3,1),EVINDEX) // requested action index must be in range
1299
1285
Iy;
1300
1286
if(type==-3){y=rei0(w); y=jt->afoldinfo->exestats[0]>=y; // set y if current v count high enough
0 commit comments