diff --git a/jsrc/cx.c b/jsrc/cx.c index 64db68930..7f262f16c 100644 --- a/jsrc/cx.c +++ b/jsrc/cx.c @@ -125,9 +125,9 @@ static B jtforinit(J jt,CDATA*cv,A t){A x;C*s,*v;I k; // an incumbent value, we remove it. We also zap the value we install, just as in any normal assignment L *asym=&SYMORIGIN[cv->indexsym]; // pointer symbol-table entry, index then item ASSERT(!(asym->flag&LREADONLY),EVRO) // it had better not be readonly now - fa(asym->val); // if there is an incumbent value, discard it + fa(QCWORD(asym->fval)); // if there is an incumbent value, discard it A xx; GAT0(xx,INT,1,0); IAV0(xx)[0]=-1; AFLAGINIT(xx,AFRO) // -1 is the iteration number if there are no iterations; mark value RO to prevent xxx_index =: xxx_index + 1 from changing inplace - ACINITUNPUSH(xx); asym->val=xx; asym->valtype=SETNAMED(ATYPETOVALTYPE(INT)); // raise usecount, as local name; install as value of xyz_index + ACINITUNPUSH(xx); asym->fval=SETNAMED(MAKEFVAL(xx,ATYPETOVALTYPE(INT))); // raise usecount, as local name; install as value of xyz_index rifv(t); // it would be work to handle virtual t, because you can't just ra() a virtual, as virtuals are freed only from the tpop stack. So we wimp out & realize. note we can free from a boxed array now ra(t) cv->t=t; // if we need to save iteration array, do so, and protect from free asym->flag|=LREADONLY; // in the loop, the user may not modify xyz_index LREADONLY is set iff we have cv->t, and cleared then @@ -137,15 +137,15 @@ static B jtforinit(J jt,CDATA*cv,A t){A x;C*s,*v;I k; // We must keep ABACK in case we create a virtual block from xyz. // We store the block in 2 places: cv and symp.val. We ra() once for each place // If there is an incumbent value, discard it - asym=&SYMORIGIN[cv->itemsym]; A val=asym->val; // stored reference address; incumbent value there - fa(val); asym->val=0; asym->valtype=0; // free the incumbent if any, clear val in symbol in case of error + asym=&SYMORIGIN[cv->itemsym]; A val=QCWORD(asym->fval); // stored reference address; incumbent value there + fa(val); asym->fval=0; // free the incumbent if any, clear val in symbol in case of error // Calculate the item size and save it I isz; I r=AR(t)-((UI)AR(t)>0); PROD(isz,r,AS(t)+1); I tt=AT(t); cv->itemsiz=isz<tnextpushp; jt->tnextpushp=&asym->val; A svb=virtual(t,0,r); jt->tnextpushp=pushxsave; // since we can't ZAP a virtual, allocate this offstack to take ownership + A *pushxsave = jt->tnextpushp; jt->tnextpushp=&asym->fval; A svb=virtual(t,0,r); jt->tnextpushp=pushxsave; // since we can't ZAP a virtual, allocate this offstack to take ownership RZ(svb) AK(svb)=(CAV(t)-(C*)svb)-cv->itemsiz; ACINIT(svb,2); AN(svb)=isz; MCISH(AS(svb),AS(t)+1,r) // AC=2 since we store in symbol and cv // Install the virtual block as xyz, and remember its address - cv->item=svb; asym->valtype=SETNAMED(ATYPETOVALTYPE(tt)); // save in 2 places (already in asym->val), commensurate with AC of 2 + cv->item=svb; asym->fval=SETNAMED(MAKEFVAL(asym->fval,ATYPETOVALTYPE(tt))); // save in 2 places (already in asym->val), commensurate with AC of 2 } R 1; } /* for. do. end. initializations */ @@ -159,10 +159,10 @@ static CDATA* jtunstackcv(J jt,CDATA*cv,I assignvirt){ SYMORIGIN[cv->indexsym].flag&=~LREADONLY; // set xyz_index is no longer readonly. It is still available for inspection // If xyz still points to the virtual block, we must be exiting the loop early: the value must remain, so realize it if(likely((svb=cv->item)!=0)){ // if the svb was allocated... - if(unlikely(SYMORIGIN[cv->itemsym].val==svb)){A newb; // svb was allocated, loop did not complete, and xyz has not been reassigned - fa(svb); // remove svb from itemsym.val. Safe, because it can't be the last free - if(likely(assignvirt!=0)){RZ(newb=realize(svb)); ACINITZAP(newb); ra00(newb,AT(newb)); SYMORIGIN[cv->itemsym].val=newb; SYMORIGIN[cv->itemsym].valtype=SETNAMED(ATYPETOVALTYPE(AT(newb))); // realize stored value, raise, make recursive, store in symbol table - }else{SYMORIGIN[cv->itemsym].val=0; SYMORIGIN[cv->itemsym].valtype=0;} // after error, we needn't bother with a value + if(unlikely(QCWORD(SYMORIGIN[cv->itemsym].fval)==svb)){A newb; // svb was allocated, loop did not complete, and xyz has not been reassigned + fa(svb); // remove svb from itemsym.fval. Safe, because it can't be the last free + if(likely(assignvirt!=0)){RZ(newb=realize(svb)); ACINITZAP(newb); ra00(newb,AT(newb)); SYMORIGIN[cv->itemsym].fval=SETNAMED(MAKEFVAL(newb,ATYPETOVALTYPE(AT(newb)))); // realize stored value, raise, make recursive, store in symbol table + }else{SYMORIGIN[cv->itemsym].fval=0;} // after error, we needn't bother with a value } // Decrement the usecount to account for being removed from cv - this is the final free of the svb, unless it is a result. Since this is a virtual block, free the backer also if(AC(svb)<=1)fa(ABACK(svb)); fr(svb); // MUST NOT USE fa() for svb so that we don't recur and free svb's current contents in cv->t - svb is virtual @@ -175,10 +175,10 @@ static CDATA* jtunstackcv(J jt,CDATA*cv,I assignvirt){ } // call here when we find that xyz_index has been aliased. We remove it, free it, and replace it with a new block. Return 0 if error -// We do not have to change the valtype field, since it never changes +// valloc is a flagged value static A swapitervbl(J jt,A old,A *valloc){ fa(old); // discard the old value - GAT0(old,INT,1,0); ACINITUNPUSH(old); *valloc=old; // raise usecount, install as value of xyz_index + GAT0(old,INT,1,0); ACINITUNPUSH(old); *valloc=MAKEFVAL(old,QCTYPE(*valloc)); // raise usecount, install as value of xyz_index (with flags preserved) R old; } @@ -301,7 +301,7 @@ DF2(jtxdefn){ L *ybuckptr = &sympv[LXAV0(locsym)[(US)yxbucks]]; // pointer to sym block for y, known to exist if(likely(w!=0)){ // If y given, install it & incr usecount as in assignment. Include the script index of the modification I vtype=QCNAMED|(LOCALRA?QCRAREQD:REPSGN(AT(w))&QCRAREQD)|ATYPETOVALTYPE(AT(w)); // install QCSYMVAL flags - ybuckptr->val=w; ybuckptr->valtype=vtype; ybuckptr->sn=jt->currslistx; // finish the assignment, with QCSYMVAL semantics + ybuckptr->fval=MAKEFVAL(w,vtype); ybuckptr->sn=jt->currslistx; // finish the assignment, with QCSYMVAL semantics // If input is abandoned inplace and not the same as x, DO NOT increment usecount, but mark as abandoned and make not-inplace. Otherwise ra // We can handle an abandoned argument only if it is direct or recursive, since only those values can be assigned to a name if(likely(a!=w)&&(SGNTO0(AC(w)&(((AT(w)^AFLAG(w))&RECURSIBLE)-1))&((I)jtinplace>>JTINPLACEWX))){ @@ -320,7 +320,7 @@ DF2(jtxdefn){ L *xbuckptr = &sympv[LXAV0(locsym)[yxbucks>>16]]; // pointer to sym block for x if(!C_CRC32C&&xbuckptr==ybuckptr)xbuckptr=xbuckptr->next+sympv; I vtype=QCNAMED|(LOCALRA?QCRAREQD:REPSGN(AT(a))&QCRAREQD)|ATYPETOVALTYPE(AT(a)); // install QCSYMVAL flags - xbuckptr->val=a; xbuckptr->valtype=vtype; xbuckptr->sn=jt->currslistx; + xbuckptr->fval=MAKEFVAL(a,vtype); xbuckptr->sn=jt->currslistx; if(likely(a!=w)&(SGNTO0(AC(a)&(((AT(a)^AFLAG(a))&RECURSIBLE)-1))&((I)jtinplace>>JTINPLACEAX))){ AFLAGORLOCAL(a,AFKNOWNNAMED); xbuckptr->flag=LPERMANENT|LWASABANDONED; ACIPNOABAND(a); ramkrecursv(a); }else{ra(a);} @@ -573,8 +573,8 @@ nextlinedebug:; if(likely(cv->indexsym!=0)){ // for_xyz. Manage the loop variables L *sympv=SYMORIGIN; // base of symbol array - A *aval=&sympv[cv->indexsym].val; // address of iteration-count slot - A iterct=*aval; // A block for iteration count + A *aval=&sympv[cv->indexsym].fval; // address of iteration-count slot + A iterct=QCWORD(*aval); // A block for iteration count if(unlikely(AC(iterct)>1))BZ(iterct=swapitervbl(jt,iterct,aval)); // if value is now aliased, swap it out before we change it IAV0(iterct)[0]=cv->j; // Install iteration number into the readonly index L *itemsym=&sympv[cv->itemsym]; @@ -582,17 +582,15 @@ nextlinedebug:; if(likely(cv->jniter)){ // if there are more iterations to do... // if xyz has been reassigned, fa the incumbent and reinstate the virtual block, advanced to the next item AK(cv->item)+=cv->itemsiz; // advance to next item - if(unlikely(itemsym->val!=cv->item)){ + if(unlikely(QCWORD(itemsym->fval)!=cv->item)){ // discard & free incumbent, switch to virtual, raise it - A val=itemsym->val; fa(val) val=cv->item; ra(val) itemsym->val=val; - itemsym->valtype=SETNAMED(ATYPETOVALTYPE(INT)); // also have to set the value type in the symbol (as a local), in case it was changed. Any noun will do + A val=itemsym->fval; fa(QCWORD(val)) val=cv->item; ra(val) itemsym->fval=SETNAMED(MAKEFVAL(val,ATYPETOVALTYPE(INT))); // also have to set the value type in the symbol (as a local), in case it was changed. Any noun will do } --ic; goto elseifasdo; // advance to next line and process it; if flagged, we know it's bblock } // ending the iteration normally. set xyz to i.0 - {A val=itemsym->val; fa(val)} // discard & free incumbent, probably the virtual block. If the virtual block, this is never the final free, which comes in unstackcv - itemsym->val=mtv; // after last iteration, set xyz to mtv, which is permanent - itemsym->valtype=SETNAMED(ATYPETOVALTYPE(INT)); // also have to set the value type in the symbol (as a local), in case it was changed. Any noun will do + {A val=itemsym->fval; fa(QCWORD(val))} // discard & free incumbent, probably the virtual block. If the virtual block, this is never the final free, which comes in unstackcv + itemsym->fval=SETNAMED(MAKEFVAL(mtv,ATYPETOVALTYPE(INT))); // after last iteration, set xyz to mtv, which is permanent, and value type in the symbol (as a local), in case it was changed. Any noun will do }else if(likely(cv->jniter)){--ic; goto elseifasdo;} // (no for_xyz.) advance to next line and process it; if flagged is bblock // if there are no more iterations, fall through... tcesx&=~(32<val; if(yxv&&AFLAG(yxv)&AFUNINCORPABLE){ybuckptr->val=0; symbisdel(ybuckptr->name,yxv,locsym);}} yxbucks>>=16;} // clr val before assign in case of error (which must be on realize) + while(yxbucks){if((US)yxbucks){L *ybuckptr = &sympv[LXAV0(locsym)[(US)yxbucks]]; A yxv=QCWORD(ybuckptr->fval); if(yxv&&AFLAG(yxv)&AFUNINCORPABLE){ybuckptr->fval=0; symbisdel(ybuckptr->name,yxv,locsym);}} yxbucks>>=16;} // clr val before assign in case of error (which must be on realize) deba(DCPM+(~bic<<8)+(NPGpysfmtdl<<(7-6)&(~(I)jtinplace>>(JTXDEFMODIFIERX-7))&128),locsym,AAV1(sv->fgh[2])[HN*((NPGpysfmtdl>>6)&1)],self); // push a debug frame for this error. We know we didn't free locsym RETF(0) } diff --git a/jsrc/dc.c b/jsrc/dc.c index 0a5e0bbaf..055d150ab 100644 --- a/jsrc/dc.c +++ b/jsrc/dc.c @@ -9,7 +9,7 @@ static F1(jtdfrep){ARGCHK1(w); R NOUN&AT(w)?w:lrep(w);} -static SYMWALK(jtdloc,A,BOX,5,2,1,{RZ(*zv++=incorp(sfn(0,d->name))); RZ(*zv++=incorp(dfrep(d->val)));}) +static SYMWALK(jtdloc,A,BOX,5,2,1,{RZ(*zv++=incorp(sfn(0,d->name))); RZ(*zv++=incorp(dfrep(QCWORD(d->fval))));}) static B jtdrow(J jt,DC si,DC s0,A*zv,UI ncollist,I* collist){A fs,q,*qv,y,z;C c;UI col; fs=si->dcf; diff --git a/jsrc/j.h b/jsrc/j.h index e0ec8a4db..68108c2ed 100644 --- a/jsrc/j.h +++ b/jsrc/j.h @@ -2146,7 +2146,7 @@ if(likely(type _i<3)){z=(type _i<1)?1:(type _i==1)?_zzt[0]:_zzt[0]*_zzt[1];}else // split into two parts: the symbol-dependent and not, so we can move the expensive part outside of lock #define SYMVALFA1(l,faname) {if(faname!=0){if(unlikely(((l).flag&LWASABANDONED)!=0)){(l).flag&=~LWASABANDONED; AFLAGCLRKNOWN(faname); if(likely(AC(faname)<2))ACRESET(faname,ACINPLACE|ACUC1); faname=0;}}} #define SYMVALFA2(faname) if(faname!=0){faaction(jt,faname,AFLAGCLRKNOWN(faname));} -#define SYMVALFA(l) {A v=(l).val; SYMVALFA1(l,v) SYMVALFA2(v)} // l points to the symbol-table entry for the name +#define SYMVALFA(l) {A v=QCWORD((l).fval); SYMVALFA1(l,v) SYMVALFA2(v)} // l points to the symbol-table entry for the name #define SZA ((I)sizeof(A)) #define LGSZA LGSZI // we always require A and I to have same size #define SZD ((I)sizeof(D)) diff --git a/jsrc/jtype.h b/jsrc/jtype.h index 4df4e434c..d2fdeccac 100644 --- a/jsrc/jtype.h +++ b/jsrc/jtype.h @@ -889,7 +889,7 @@ typedef DST* DC; #define SETNAMED(w) (A)((I)(w)|QCNAMED) #define QCRAREQDX 5 // Value should be ra()d before stacking. This is any global name or any sparse value. #define QCRAREQD ((I)1<kchain.locpath // the path, allocated with rank 1 (so the path is in one cacheline). If 0, the locale has been deleted. The path runs from LOCPATH backwards // to end with the ending 0 at AAV1()[0] diff --git a/jsrc/m.c b/jsrc/m.c index b4d5504ef..5cce513e5 100644 --- a/jsrc/m.c +++ b/jsrc/m.c @@ -424,7 +424,7 @@ F1(jtspforloc){A*wv,x,y,z;C*s;D tot,*zv;I i,j,m,n;L*u;LX *yv,c; tot+=spfor1(LOCNAME(y)); // add in the size of the path and name m=AN(y); yv=LXAV0(y); for(j=SYMLINFOSIZE;jnext){tot+=sizeof(L); u=c+SYMORIGIN; tot+=spfor1(u->name); tot+=spfor1(u->val);} // add in the size of the name itself and the value, and the L block for the name + for(c=yv[j];c=SYMNEXT(c),c;c=u->next){tot+=sizeof(L); u=c+SYMORIGIN; tot+=spfor1(u->name); tot+=spfor1(QCWORD(u->fval));} // add in the size of the name itself and the value, and the L block for the name } zv[i]=tot; } @@ -684,7 +684,7 @@ void freesymb(J jt, A w){I j,wn=AN(w); LX k,* RESTRICT wv=LXAV0(w); LX nextk=jtsympv[k].next; // unroll loop 1 time fa(jtsympv[k].name);jtsympv[k].name=0; // always release name SYMVALFA(jtsympv[k]); // free value - jtsympv[k].val=0;jtsympv[k].valtype=0;jtsympv[k].sn=0;jtsympv[k].flag=0; // clear symbol fields for next time (that's Roger's way) + jtsympv[k].fval=0;jtsympv[k].sn=0;jtsympv[k].flag=0; // clear symbol fields for next time (that's Roger's way) lastk=k; // remember end-of-chain k=nextk; // advance to next block in chain }while(k); @@ -718,7 +718,7 @@ NOINLINE A jtfreesymtab(J jt,A w,I arw){ // don't make this static - it will be // Free the name fr(LOCNAME(w)); // clear the data fields in symbol SYMLINFO kludge but this is how it was done (should be done in symnew) - jtsympv[k].name=0;jtsympv[k].val=0;jtsympv[k].valtype=0;jtsympv[k].sn=0;jtsympv[k].flag=0; + jtsympv[k].name=0;jtsympv[k].fval=0;jtsympv[k].sn=0;jtsympv[k].flag=0; jtsymreturn(jt,k,k,1); // return symbol to free lists } } diff --git a/jsrc/p.c b/jsrc/p.c index bdb9d9825..76130ff99 100644 --- a/jsrc/p.c +++ b/jsrc/p.c @@ -281,7 +281,7 @@ void auditblock(J jt,A w, I nonrecurok, I virtok) { #endif #if 0 // for debugging -static SYMWALK(jtchkval0k, I,INT,1,1, AT(d->val)&NOUN&&AK(d->val)==0?SEGFAULT:0 , ;) +static SYMWALK(jtchkval0k, I,INT,1,1, AT(QCWORD(d->fval))&NOUN&&AK(QCWORD(d->fval))==0?SEGFAULT:0 , ;) #endif // Run parser, creating a new debug frame. Explicit defs, which make other tests first, go through jtparsea except during debug/pm @@ -584,9 +584,9 @@ A jtparsea(J jt, A *queue, I nwds){F1PREFIP;PSTK *stack;A z,*v; y=QCWORD(y); // back y up to the NAME block if((symx&~REPSGN4(SGNIF4(pt0ecam,LOCSYMFLGX+ARLCLONEDX)))!=0){ // if we are using primary table and there is a symbol stored there... L *s=sympv+(I)symx; // get address of symbol in primary table - if(unlikely(s->valtype==0))goto rdglob; // if value has not been assigned, ignore it. - y=(A)((I)s->val+s->valtype); // combine the type and value. type has QCSYMVAL semantics, as y does. scaf move this addition to the assignment - if(unlikely(ISRAREQD(s->valtype)))raposlocalqcgsv(s->val,QCPTYPE(s->valtype),y); // ra the block if needed - rare for locals (only sparse). Now we call it QCFAOWED semantics + if(unlikely((s->fval)==0))goto rdglob; // if value has not been assigned, ignore it. y has QCSYMVAL semantics +// obsolete y=(A)((I)s->val+s->valtype); // combine the type and value. type has QCSYMVAL semantics, as y does. + if(unlikely(ISRAREQD(y=s->fval)))raposlocalqcgsv(QCWORD(y),QCPTYPE(y),y); // ra the block if needed - rare for locals (only sparse). Now we call it QCFAOWED semantics }else if(likely((buck=NAV(QCWORD(y))->bucket)>0)){ // buckets but no symbol - must be global, or recursive symtab - but not synthetic new name I bx=NAVV(y)->bucketx; // get an early fetch in case we don't have a symbol but we do have buckets - globals, mainly if(likely((bx|(I)(I1)AR(jt->locsyms))>=0))goto rdglob; // if positive bucketx and no name has been added, skip the search - the usual case if not recursive symtab @@ -771,7 +771,7 @@ endname: ; if(likely(GETSTACK0PT&PTASGNLOCAL)){L *s; // only sentences from explicit defns have ASGNLOCAL set // local assignment. First check for primary symbol. We expect this to succeed. We fetch the unflagged address of the value if(likely((s=(L*)(I)(NAV(QCWORD(*(volatile A*)queue))->symx&~REPSGN4(SGNIF4(pt0ecam,LOCSYMFLGX+ARLCLONEDX))))!=0)){ - zval=(SYMORIGIN+(I)s)->val; // get value of symbol in primary table. There may be no value; that's OK + zval=QCWORD((SYMORIGIN+(I)s)->fval); // get value of symbol in primary table. There may be no value; that's OK }else{zval=QCWORD(jtprobelocal(jt,QCWORD(*(volatile A*)queue),jt->locsyms));} targc=LOCALRA?ACUC2:ACUC1; // since local values are not ra()d, they will have AC=1 if inplaceable. This will miss sparse values (which have been ra()d. which is OK }else{zval=QCWORD(probequiet(QCWORD(*(volatile A*)queue))); targc=ACUC2;} // global assignment, get slot address. Global names have been ra()d and have AC=2 @@ -1157,9 +1157,9 @@ rejectfrag:; if(likely((yflags&QCISLKPNAME))){ // y is a name to be looked up if(likely((((I)NAV(y)->symx-1)|SGNIF(AR(jt->locsyms),ARLCLONEDX))>=0)){ // if we are using primary table and there is a symbol stored there... L *s=SYMORIGIN+(I)NAV(y)->symx; // get address of symbol in primary table - if(likely((sv=s->val)!=0)){ // value has been assigned + if(likely((sv=s->fval)!=0)){ // value has been assigned // the very likely case of a local name. This value needs no protection because there is nothing more to happen in the sentence and the local symbol table is sufficient protection. Skip the ra and the tpush - I svt=s->valtype; // type of stored value + I svt=QCTYPE(sv); sv=QCWORD(sv); // type of stored value if(likely(svt&QCNOUN)||unlikely(yflags&QCNAMEBYVALUE)){ // if noun or special name, use value if(unlikely(yflags&QCNAMEABANDON))goto abandname; // if abandoned, it loses the symbol-table protection and we have to protect it with ra. Since rare (especially for a single word!), do so by re-looking up the name y=sv; // we will use the value we read diff --git a/jsrc/s.c b/jsrc/s.c index e8056c31f..7cf6acf4c 100644 --- a/jsrc/s.c +++ b/jsrc/s.c @@ -153,11 +153,11 @@ extern void jtsymfreeha(J jt, A w){I j,wn=AN(w); LX k,* RESTRICT wv=LXAV0(w); if(!SYMNEXTISPERM(k))break; // we are about to free k. exit if it is not permanent I nextk=jtsympv[k].next; // unroll loop 1 time aprev=&jtsympv[k].next; // save last item we processed here - if(jtsympv[k].val){ + if(jtsympv[k].fval){ // if the value was abandoned to an explicit definition, we took usecount 8..1 -> 1 ; revert that. Can't change an ACPERMANENT! // otherwise decrement the usecount SYMVALFA(jtsympv[k]); - jtsympv[k].val=0;jtsympv[k].valtype=0; // clear value - don't clear name + jtsympv[k].fval=0; // clear value - don't clear name } k=nextk; }while(k); @@ -170,7 +170,7 @@ extern void jtsymfreeha(J jt, A w){I j,wn=AN(w); LX k,* RESTRICT wv=LXAV0(w); NOUNROLL do{ k=SYMNEXT(k); // remove address flagging I nextk=jtsympv[k].next; // unroll loop once - fa(jtsympv[k].name);fa(jtsympv[k].val);jtsympv[k].name=0;jtsympv[k].valtype=0;jtsympv[k].val=0;jtsympv[k].sn=0;jtsympv[k].flag=0; + fa(jtsympv[k].name);fa(QCWORD(jtsympv[k].fval));jtsympv[k].name=0;jtsympv[k].fval=0;jtsympv[k].sn=0;jtsympv[k].flag=0; lastk=k; // remember index of last block ++nfreed; // ince count of block in chain-to-free k=nextk; @@ -196,8 +196,8 @@ F1(jtsympool){A aa,q,x,y,*yv,z,zz=0,*zv;I i,n,*u,*xv;L*pv;LX j,*v; GATV0E(y,BOX,n, 1,goto exit;); yv=AAV1(y); zv[1]=incorp(y); // box 1: for(i=0;iflag&LINFO)&&pv->val)?LOWESTBIT(AT(pv->val)):0; // type: only the lowest bit. In LINFO, val may be locale#. Must allow SYMB through - *xv++=pv->flag+(pv->name?LHASNAME:0)+(!(pv->flag&LINFO)&&pv->val?LHASVALUE:0); // flag + *xv++=(!(pv->flag&LINFO)&&pv->fval)?LOWESTBIT(AT(QCWORD(pv->fval))):0; // type: only the lowest bit. In LINFO, val may be locale#. Must allow SYMB through + *xv++=pv->flag+(pv->name?LHASNAME:0)+(!(pv->flag&LINFO)&&pv->fval?LHASVALUE:0); // flag *xv++=pv->sn; // script index *xv++=SYMNEXT(pv->next); // chain *xv++=0; // for debug, the thread# that allocated the symbol @@ -209,7 +209,7 @@ F1(jtsympool){A aa,q,x,y,*yv,z,zz=0,*zv;I i,n,*u,*xv;L*pv;LX j,*v; n=AN(JT(jt,stloc)); v=LXAV0(JT(jt,stloc)); // v->locale chains for(i=0;isymbol table for locale + x=SYMORIGIN[j].fval; // x->symbol table for locale RZGOTO(yv[j]=yv[LXAV0(x)[0]]=aa=incorp(sfn(SFNSIMPLEONLY,LOCNAME(x))),exit); // install name in the entry for the locale RZGOTO(q=sympoola(x),exit); u=AV(q); DO(AN(q), yv[u[i]]=aa;); } @@ -250,8 +250,8 @@ B jtprobedel(J jt,C*string,UI4 hash,A g){B ret; if(likely(!(AFLAG(sym->name)&AFRO))){ // ignore request to delete readonly name (cocurrent) IFCMPNAME(NAV(sym->name),string,(I)jtinplace&0xff,hash, // (1) exact match - if there is a value, use this slot, else say not found { - ret=sym->val==0?0:~(I)sym->valtype&QCNOUN; // return value: value was defined & not a noun - SYMVALFA(*sym); sym->val=0; sym->valtype=0; // decr usecount in value; remove value from symbol + ret=sym->fval==0?0:~(I)sym->fval&QCNOUN; // return value: value was defined & not a noun + SYMVALFA(*sym); sym->fval=0; // decr usecount in value; remove value from symbol if(!(sym->flag&LPERMANENT)){ // if PERMANENT, we delete only the value *asymx=sym->next; fa(sym->name); sym->name=0; sym->flag=0; sym->sn=0; // unhook symbol from hashchain, free the name, clear the symbol jtsymreturn(jt,delblockx,delblockx,1); // return symbol to free chains @@ -279,7 +279,7 @@ A jtprobe(J jt,C*string,UI4 hash,A g){ NOUNROLL while(symx){ // loop is unrolled 1 time // sym is the symbol to process, symx is its index. Start by reading next in chain. One overread is OK, will be symbol 0 (the root of the freequeue) symnext=sympv+(symx=SYMNEXT(sym->next)); - IFCMPNAME(NAV(sym->name),string,(I)jtinplace&0xff,hash,R (A)((I)sym->val+sym->valtype);) // (1) exact match - if there is a value, return it. valtype has QCSYMVAL semantics + IFCMPNAME(NAV(sym->name),string,(I)jtinplace&0xff,hash,R sym->fval;) // (1) exact match - if there is a value, return it. valtype has QCSYMVAL semantics sym=symnext; // advance to value we read } R 0; // not found @@ -299,7 +299,7 @@ A probelocalbuckets(L *sympv,A a,LX lx,I bx){NM*u; // lx is LXAV0(locsyms)[buc if(unlikely(++bx!=0)){NOUNROLL do{lx = sympv[lx].next;}while(++bx);} // rattle off the permanents, usually 1 // Now lx is the index of the first name that might match. Do the compares NOUNROLL while(lx=SYMNEXT(lx)) {L* l = lx+sympv; // symbol entry - IFCMPNAME(NAV(l->name),s,m,hsh, R (A)((I)l->val+l->valtype);) + IFCMPNAME(NAV(l->name),s,m,hsh, R l->fval;) lx = l->next; } R 0; // no match. @@ -307,7 +307,7 @@ A probelocalbuckets(L *sympv,A a,LX lx,I bx){NM*u; // lx is LXAV0(locsyms)[buc L* l = lx+sympv; // fetch hashchain headptr, point to L for first symbol // negative bucketx (now positive); skip that many items, and then you're at the right place if(unlikely(bx>0)){NOUNROLL do{l = l->next+sympv;}while(--bx);} // skip the prescribed number, which is usually 1 - R (A)((I)l->val+l->valtype); + R l->fval; } } @@ -555,7 +555,7 @@ static L *jtprobeforsym(J jt,C*string,UI4 hash,A g){ NOUNROLL while(symx){ // loop is unrolled 1 time // sym is the symbol to process, symx is its index. Start by reading next in chain. One overread is OK, will be symbol 0 (the root of the freequeue) symnext=sympv+SYMNEXT(symx=sym->next); - IFCMPNAME(NAV(sym->name),string,(I)jtinplace&0xff,hash,R sym->val!=0?sym:0;) // (1) exact match - if there is a value, return the symbol + IFCMPNAME(NAV(sym->name),string,(I)jtinplace&0xff,hash,R sym->fval!=0?sym:0;) // (1) exact match - if there is a value, return the symbol sym=symnext; // advance to value we read } R 0; // not found @@ -578,9 +578,9 @@ static I jtsyrdinternal(J jt, A a, I component){A g=0;L *l; gotval: ; // found: l points to the symbol. We hold a lock on g, if it is nonzero I res=0; - if(component==0){ASSERTGOTO(NOUN&AT(l->val),EVDOMAIN,exitlock) res=(I)l;} // 15!:6, symbol address - else if(component==1){ASSERTGOTO(NOUN&AT(l->val),EVDOMAIN,exitlock) res=(I)voidAV(l->val);} // 15!:14, data address - else if(component==2){ASSERTGOTO(NOUN&AT(l->val),EVDOMAIN,exitlock) res=(I)(l->val);} // 15!:12, header address + if(component==0){ASSERTGOTO(NOUN&AT(QCWORD(l->fval)),EVDOMAIN,exitlock) res=(I)l;} // 15!:6, symbol address + else if(component==1){ASSERTGOTO(NOUN&AT(QCWORD(l->fval)),EVDOMAIN,exitlock) res=(I)voidAV(QCWORD(l->fval));} // 15!:14, data address + else if(component==2){ASSERTGOTO(NOUN&AT(QCWORD(l->fval)),EVDOMAIN,exitlock) res=(I)(QCWORD(l->fval));} // 15!:12, header address else{res=l->sn+1;} // 4!:4, script index exitlock: if(g)READUNLOCK(g->lock) @@ -749,20 +749,20 @@ I jtsymbis(J jt,A a,A w,A g){F2PREFIP; } // ****** if g is a global table, we have a write lock on the locale, which we must release in any error paths. g=0 otherwise ******* - A x=e->val; // if x is 0, this name has not been assigned yet; if nonzero, x points to the incumbent value + A x=e->fval; // if x is 0, this name has not been assigned yet; if nonzero, x points to the incumbent value // If we are assigning the same data block that's already there, don't bother with changing use counts or anything else (assignment-in-place) - if(likely(x!=w)){ + if(likely(QCWORD(x)!=w)){ // if we are debugging, we have to make sure that the value being replaced is not in execution on the stack. Of course, it would have to have an executable type - if(unlikely(jt->uflags.trace&TRACEDB))if(x!=0&&((e->valtype&QCNOUN)==0))x=redef(w,x); // check for SI damage (handled later). could move outside of lock, but it's only for debug - + if(unlikely(jt->uflags.trace&TRACEDB))if(x!=0&&(((I)x&QCNOUN)==0))x=redef(w,x); // check for SI damage (handled later). could move outside of lock, but it's only for debug + x=QCWORD(x); // we have no further need for the type that has been reassigned + ASSERTGOTO(!(e->flag&LREADONLY),EVRO,exitlock) // if writing read-only name (xxx_index) with new value, fail I xaf; // holder for nvr/free flags {A aaf=AFLAG0; aaf=x?x:aaf; xaf=AFLAG(aaf);} // flags from x, or 0 if there is no x if(likely(!(AFNJA&xaf))){ // Normal case of non-memory-mapped assignment. - e->valtype=valtype; // set the value type of the new value - e->val=w; // store the new value to free w before ra() + e->fval=MAKEFVAL(w,valtype); // store the new flagged value to free w before ra() SYMVALFA1(*e,x); // fa the value unless it was never ra()d to begin with, and handle AC for the caller in that case; repurpose x to point to any residual value to be fa()d later // It is OK to do the first half of this operation early, since it doesn't change the usecount. But we must keep the lock until we have protected w // SYMVALFA1 does not call a subroutine diff --git a/jsrc/s.h b/jsrc/s.h index b621390e0..44ae82a16 100644 --- a/jsrc/s.h +++ b/jsrc/s.h @@ -28,7 +28,7 @@ while(j=k){ /* chase the chain */ \ d=j+SYMORIGIN; \ k=SYMNEXT(d->next); \ - if((d->name)&&(d->val)&&(SELECT)){ \ + if((d->name)&&(d->fval)&&(SELECT)){ \ if(m==AS(z)[0]){RZ(z=ext(0,z)); zv=(m*(COL))+(T*)AV(z);} \ {PROCESS;} \ ++m; \ diff --git a/jsrc/sl.c b/jsrc/sl.c index 1bf07750e..349703c01 100644 --- a/jsrc/sl.c +++ b/jsrc/sl.c @@ -212,7 +212,7 @@ A jtstcreate(J jt,I1 k,I p,I n,C*u){A g,x,xx;L*v; UI4 hsh=NAV(x)->hash; L *sympv=SYMORIGIN; // hash of name; origin of symbol tables LX *hv=LXAV0(JT(jt,stloc))+SYMHASH(hsh,AN(JT(jt,stloc))-SYMLINFOSIZE); // get hashchain base in stloc LX tx=SYMNEXT(*hv); if(tx!=0)NOUNROLL while(SYMNEXT(sympv[tx].next)!=0)tx=SYMNEXT(sympv[tx].next); // tx->last in chain, or 0 if chain empty - v=symnew(hv,tx); v->name=x; v->val=g; ACINITZAP(g); // install the new locale at end of chain; put name into block; save value; ZAP to match store of value + v=symnew(hv,tx); v->name=x; v->fval=g; ACINITZAP(g); // install the new locale at end of chain; put name into block; put locale pointer into fval; ZAP to match store of value LOCBLOOM(g)=0; // Init Bloom filter to 'nothing assigned' ACINITZAP(x); ACINIT(x,ACUC2) // now that we know we will succeed, transfer ownership to name to the locale and stloc, one each AR(g)=ARNAMED; // set rank to indicate named locale @@ -597,7 +597,7 @@ F1(jtlocname){A g=jt->global; } /* 18!:5 current locale name */ static SYMWALK(jtlocmap1,I,INT,18,3,1, - {I t=AT(d->val); + {I t=AT(QCWORD(d->fval)); *zv++=i; I zc; zc=(((1LL<<(ADVX-ADVX))|(2LL<<(CONJX-ADVX))|(3LL<<(VERBX-ADVX)))>>(CTTZ(((t&CONJ+ADV+VERB)|(1LL<<31))>>ADVX)))&3; // ADVX, CONJx, VERBX, and the implied NOUNX=31 must all be >+ 2 bits apart zc=t==SYMB?6:zc; zc=t&(NOUN|VERB|ADV|CONJ|SYMB)?zc:-2; @@ -655,7 +655,7 @@ F1(jtsetpermanent){A g; - SYMWALK(jtredefg,B,B01,100,1,1,RZ(redef((zv,mark),d->val))) + SYMWALK(jtredefg,B,B01,100,1,1,RZ(redef((zv,mark),QCWORD(d->fval)))) /* check for redefinition (erasure) of entire symbol table. */ // 18!:55 destroy locale(s) from user's point of view. This counts as one usecount; others are in execution and in paths. When all go to 0, delete the locale diff --git a/jsrc/sn.c b/jsrc/sn.c index 61288f970..06385f516 100644 --- a/jsrc/sn.c +++ b/jsrc/sn.c @@ -140,10 +140,10 @@ F1(jtnc){A*wv,x,y,z;I i,n,t,*zv; } /* 4!:0 name class */ // these functions are called with an a arg that is a 256-char rank-1 boolean map giving the initial characters wanted, and AS(a)[0] is a mask of allowed types -static SYMWALK(jtnlxxx, A,BOX,20,1, CAV1(a)[((UC*)NAV(d->name)->s)[0]]&&AS(a)[0]&AT(d->val), +static SYMWALK(jtnlxxx, A,BOX,20,1, CAV1(a)[((UC*)NAV(d->name)->s)[0]]&&AS(a)[0]&AT(QCWORD(d->fval)), RZ(*zv++=incorp(sfn(SFNSIMPLEONLY,d->name))) ) -static SYMWALK(jtnlsymlocked, A,BOX,20,1, LOCPATH(d->val)&&CAV1(a)[((UC*)NAV(d->name)->s)[0]], +static SYMWALK(jtnlsymlocked, A,BOX,20,1, LOCPATH(QCWORD(d->fval))&&CAV1(a)[((UC*)NAV(d->name)->s)[0]], RZ(*zv++=incorp(sfn(SFNSIMPLEONLY,d->name))) ) static SYMWALK(jtnlsymlockedz, A,BOX,20,1, CAV1(a)[((UC*)NAV(d->name)->s)[0]], @@ -186,7 +186,7 @@ static A jtnch1(J jt,B b,A w,I*pm,A ch){A*v,x,y;C*s,*yv;LX *e;I i,k,m,p,wn;L*d; for(i=SYMLINFOSIZE;iflag&&d->name&&d->val){ + if(LCH&d->flag&&d->name&&QCWORD(d->fval)){ d->flag^=LCH; if(b){ if(m==AN(ch)){RZ(ch=ext(0,ch)); v=m+AAV(ch);} @@ -213,7 +213,7 @@ static F1(jtnch2){A ch;B b;LX *e;I i,m,n;L*d; for(i=SYMLINFOSIZE;ival,&m,ch)); // go check each symbol in the locale + RZ(ch=nch1(b,d->fval,&m,ch)); // go check each symbol in the locale if(!d->next)break; d=SYMNEXT(d->next)+SYMORIGIN; }