Skip to content

Commit 0ed53c6

Browse files
committed
parsing tweaks
1 parent 5405071 commit 0ed53c6

2 files changed

Lines changed: 10 additions & 8 deletions

File tree

jsrc/jtype.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ typedef I SI;
330330
#define SYMBX 24
331331
#define SYMB ((I)1L<<SYMBX) /* I locale (symbol table) */
332332
#define SYMBSIZE sizeof(LX)
333-
#define CONWX 25
333+
#define CONWX 25 // parsing uses the fact that CONWX is LASTNOUNX+5
334334
#define CONW ((I)1L<<CONWX) /* CW control word */
335335
#define CONWSIZE sizeof(CW)
336336
#define ADVX 26

jsrc/p.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,9 @@ static const UI4 ptcol[11] = { // there is a gap at SYMB. CONW is used to hold
142142
#define PTISNOTASGNNAME(s) (((s).pt&0x1))
143143
#define PTISRPAR(s) ((s).pt<0x100)
144144
// converting type field to pt, store in z
145-
#define PTFROMTYPE(z,t) {I pt=CTTZ(t); pt-=(LASTNOUNX+1); pt|=REPSGN(pt); z=ptcol[pt+1];}
145+
#define PTFROMTYPE(z,t) {I pt=CTTZ(t); pt-=(LASTNOUNX+1); pt|=REPSGN(pt); z=ptcol[pt+1];} // here when we know it's CAVN (not assignment)
146146
#define PTFROMTYPEASGN(z,t) {I pt=CTTZ(t); pt-=(LASTNOUNX+1); pt|=REPSGN(pt)|((t>>(CONWX-2))&(CONWX-(LASTNOUNX+1))); z=ptcol[pt+1];} // clear flag bit if ASGN to name, by fetching from unused CONW hole, which is 4 above ASGN
147+
// CONWX-2 moves CONW to its position in the table, which is at CONWX-(LASTNOUNX+1)
147148

148149
static PSTK* jtpfork(J jt,PSTK *stack){
149150
A y=folk(stack[1].a,stack[2].a,stack[3].a); // create the fork
@@ -512,7 +513,9 @@ A jtparsea(J jt, A *queue, I nwds){F1PREFIP;PSTK * RESTRICT stack;A z,*v;
512513
// Move in the new word and check its type. If it is a name that is not being assigned, resolve its
513514
// value. m has the index of the word we just moved
514515
// obsolete I at=AT(y = queue[mes>>2]); // fetch the next word from queue; pop the queue; extract the type, save as at
515-
I at=AT(nexty); y=nexty; // loop was unrolled once. We can't keep nexty and nextat in regs so we just unroll one
516+
I at=AT(nexty); // loop was unrolled once. We can't keep nexty and nextat in regs so we just unroll one
517+
L *sympv=JT(jt,sympv); // symbol root can change during parse, but not during stacking of a single execution. This is a quiet time to load. Loading outside the loop causes a spill.
518+
y=nexty;
516519
nexty = queue[(US)mes-1]; // fetch the next word from queue; pop the queue; extract the type, save as at.
517520
// The last fetch of nexty fetches from queue[-1]. This will not segfault, and we never come back to fetch from inside that bogus block.
518521
stack[0].t = (US)(mes+1); // install the original token number for the word
@@ -526,12 +529,11 @@ A jtparsea(J jt, A *queue, I nwds){F1PREFIP;PSTK * RESTRICT stack;A z,*v;
526529
// The important performance case is local names with bucket info. Pull that out & do it without the call overhead
527530
// This code is copied from s.c, except for the symx: since that occurs only in explicit definitions we can get to it only through here
528531
// obsolete I locstflags=AR(UNLXAV0(locbuckets)); // flags from local symbol table
529-
L *sympv=JT(jt,sympv); // symbol root can change during parse, but not during stacking of a single execution
530-
if(likely((SGNIF(locbuckets,ARLCLONEDX)|(NAV(y)->symx-1))>=0)){ // if we are using primary table and there is a symbol stored there...
532+
if((SGNIF(locbuckets,ARLCLONEDX)|(NAV(y)->symx-1))>=0){ // if we are using primary table and there is a symbol stored there...
531533
s=sympv+(I)NAV(y)->symx; // get address of symbol in primary table
532534
if(unlikely((sv=s->val)==0))goto rdglob; // if value has not been assigned, ignore it
533535
}else if(likely(NAV(y)->bucket!=0)){I bx;
534-
if(likely(0 <= (bx = ~NAV(y)->bucketx))){ // negative bucketx (now positive); skip that many items, and then you're at the right place. This is the path for almost all local symbols
536+
if(0 <= (bx = ~NAV(y)->bucketx)){ // negative bucketx (now positive); skip that many items, and then you're at the right place. This is the path for almost all local symbols
535537
s = ((LX *)((I)locbuckets&-8))[NAV(y)->bucket]+sympv; // fetch hashchain headptr, point to L for first symbol
536538
if(unlikely(bx>0)){NOUNROLL do{s = s->next+sympv;}while(--bx);} // skip the prescribed number, which is usually 1
537539
if(unlikely((sv=s->val)==0))goto rdglob; // if value has not been assigned, ignore it
@@ -551,12 +553,12 @@ A jtparsea(J jt, A *queue, I nwds){F1PREFIP;PSTK * RESTRICT stack;A z,*v;
551553
IFCMPNAME(NAV(s->name),nm,m,hsh,{if(unlikely((sv=s->val)==0))goto rdglob; break;}) // if match, we're done looking; could be not found, if no value
552554
lx = s->next;
553555
}
554-
// Here there was a value in the local symbol table
556+
// Here there was a value in the local symbol table. Skip to use it
555557
}
556558
}else{
557559
// No bucket info. Usually this is a locative/global, but it could be an explicit modifier, console level, or ".
558560
// If the name has a cached reference, use it
559-
if(likely(NAV(y)->cachedref!=0)){ // if the user doesn't care enough to turn on caching, performance must not be that important
561+
if(NAV(y)->cachedref!=0){ // if the user doesn't care enough to turn on caching, performance must not be that important
560562
// Note: this cannot be a NAMEABANDON, because such a name is never stacked where it can have the cachedref filled in
561563
A cachead=NAV(y)->cachedref; // use the cached address
562564
if(unlikely(NAV(y)->flag&NMCACHEDSYM)){cachead=(A)((sympv[(I)cachead]).val); if(unlikely(!cachead)){jsignal(EVVALUE);FP}} // if it's a symbol index, fetch that. value error only if cached symbol deleted

0 commit comments

Comments
 (0)