]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libaml/aml.c
libaml: fix gc bug, need to amltake()/amldrop() temporary buffer
[plan9front.git] / sys / src / libaml / aml.c
1 #include <u.h>
2 #include <libc.h>
3 #include <aml.h>
4
5 typedef struct Interp Interp;
6 typedef struct Frame Frame;
7 typedef struct Heap Heap;
8
9 typedef struct Method Method;
10 typedef struct Region Region;
11 typedef struct Field Field;
12
13 typedef struct Name Name;
14 typedef struct Ref Ref;
15 typedef struct Env Env;
16 typedef struct Op Op;
17
18 struct Heap {
19         Heap    *link;
20         int     size;
21         uchar   mark;
22         char    tag;
23 };
24
25 #define H2D(h)  (((Heap*)(h))+1)
26 #define D2H(d)  (((Heap*)(d))-1)
27 #define TAG(d)  D2H(d)->tag
28 #define SIZE(d) D2H(d)->size
29
30 static char *spacename[] = {
31         "Mem", 
32         "Io",
33         "Pcicfg",
34         "Ebctl",
35         "Smbus",
36         "Cmos",
37         "Pcibar",
38         "Ipmi",
39 };
40
41 /* field flags */
42 enum {
43         AnyAcc          = 0x00,
44         ByteAcc         = 0x01,
45         WordAcc         = 0x02,
46         DWordAcc        = 0x03,
47         QWordAcc        = 0x04,
48         BufferAcc       = 0x05,
49         AccMask         = 0x07,
50
51         NoLock          = 0x10,
52
53         Preserve        = 0x00,
54         WriteAsOnes     = 0x20,
55         WriteAsZeros    = 0x40,
56         UpdateMask      = 0x60,
57 };
58
59 struct Method {
60         Name    *name;
61         int     narg;
62         void*   (*eval)(void);
63         uchar   *start;
64         uchar   *end;
65 };
66
67 struct Region {
68         Amlio;
69         char    mapped;
70 };
71
72 struct Field {
73         void    *reg;   /* Buffer or Region or data Field */
74         void    *bank;  /* bank value */
75         Field   *index; /* bank or index Field */
76         int     flags;
77         int     bitoff;
78         int     bitlen;
79 };
80
81 struct Name {
82         void    *v;
83
84         Name    *up;
85         Name    *next;
86         Name    *fork;
87         Name    *down;
88
89         char    seg[4];
90 };
91
92 struct Ref {
93         void    *ref;
94         void    **ptr;
95 };
96
97 struct Env {
98         void    *loc[8];
99         void    *arg[8];
100 };
101
102 struct Op {
103         char    *name;
104         char    *sequence;
105         void*   (*eval)(void);
106 };
107
108 struct Frame {
109         int     tag;
110         int     cond;
111         char    *phase;
112         uchar   *start;
113         uchar   *end;
114         Op      *op;
115         Env     *env;
116         Name    *dot;
117         void    *ref;
118         void    *aux;
119         int     narg;
120         void    *arg[8];
121 };
122
123 struct Interp {
124         uchar   *pc;
125         Frame   *fp;
126         Frame   *fb;
127 };
128
129 static Interp   interp;
130 static Frame    stack[32];
131
132 #define PC      interp.pc
133 #define FP      interp.fp
134 #define FB      interp.fb
135
136 #define F0      stack
137 #define FT      &stack[nelem(stack)]
138
139 static Heap *hp;
140
141 enum {
142         Obad, Onop, Odebug,
143         Ostr, Obyte, Oword, Odword, Oqword, Oconst,
144         Onamec, Oname, Oscope, Oalias,
145         Oreg, Ofld, Oxfld, Obfld, Opkg, Ovpkg, Oenv, Obuf, Omet, 
146         Odev, Ocpu, Othz, Oprc,
147         Oadd, Osub, Omod, Omul, Odiv, Oshl, Oshr, Oand, Onand, Oor,
148         Onor, Oxor, Onot, Olbit, Orbit, Oinc, Odec,
149         Oland, Olor, Olnot, Oleq, Olgt, Ollt,
150         Oindex, Omatch, Omutex, Oevent,
151         Ocfld, Ocfld0, Ocfld1, Ocfld2, Ocfld4, Ocfld8,
152         Oif, Oelse, Owhile, Obreak, Oret, Ocall, 
153         Ostore, Oderef, Osize, Oref, Ocref, Ocat,
154         Oacq, Osignal, Orel, Ostall, Osleep, Oload, Ounload,
155         Otodec, Otohex, Otoint,
156 };
157
158 static Op optab[];
159 static uchar octab1[];
160 static uchar octab2[];
161
162 static Name*
163 rootname(Name *dot)
164 {
165         while(dot != dot->up)
166                 dot = dot->up;
167         return dot;
168 }
169
170 static void
171 gcmark(void *p)
172 {
173         int i;
174         Env *e;
175         Field *f;
176         Heap *h;
177         Name *n, *d;
178
179         if(p == nil)
180                 return;
181         h = D2H(p);
182         if(h->mark & 1)
183                 return;
184         h->mark |= 1;
185         switch(h->tag){
186         case 'E':
187                 e = p;
188                 for(i=0; i<nelem(e->loc); i++)
189                         gcmark(e->loc[i]);
190                 for(i=0; i<nelem(e->arg); i++)
191                         gcmark(e->arg[i]);
192                 break;
193         case 'R':
194         case 'A':
195         case 'L':
196                 gcmark(((Ref*)p)->ref);
197                 break;
198         case 'N':
199                 n = p;
200                 gcmark(n->v);
201                 for(d = n->down; d; d = d->next)
202                         gcmark(d);
203                 gcmark(n->fork);
204                 gcmark(n->up);
205                 break;
206         case 'p':
207                 for(i=0; i<(SIZE(p)/sizeof(void*)); i++)
208                         gcmark(((void**)p)[i]);
209                 break;
210         case 'r':
211                 gcmark(((Region*)p)->name);
212                 break;
213         case 'm':
214                 gcmark(((Method*)p)->name);
215                 break;
216         case 'f':
217         case 'u':
218                 f = p;
219                 gcmark(f->reg);
220                 gcmark(f->bank);
221                 gcmark(f->index);
222                 break;
223         }
224 }
225
226 static int
227 gc(void)
228 {
229         int i;
230         Heap *h, **hh;
231         Frame *f;
232
233         for(h = hp; h; h = h->link)
234                 h->mark &= ~1;
235
236         for(h = hp; h; h = h->link)
237                 if(h->mark & 2)
238                         gcmark(H2D(h));
239
240         for(f = FP; f >= F0; f--){
241                 for(i=0; i<f->narg; i++)
242                         gcmark(f->arg[i]);
243                 gcmark(f->env);
244                 gcmark(f->dot);
245                 gcmark(f->ref);
246         }
247
248         gcmark(amlroot);
249
250         i = 0;
251         hh = &hp;
252         while(h = *hh){
253                 if(h->mark){
254                         hh = &h->link;
255                         continue;
256                 }
257                 *hh = h->link;
258                 if(h->tag == 'r'){
259                         Region *r = (void*)H2D(h);
260                         if(r->mapped > 0){
261                                 if(amldebug)
262                                         print("\namlunmapio(%N): %-8s %llux - %llux\n", 
263                                                 (Name*)r->name, spacename[r->space],
264                                                 r->off, r->off + r->len);
265                                 amlunmapio(r);
266                         }
267                         r->mapped = 0;
268                         r->write = nil;
269                         r->read = nil;
270                         r->aux = nil;
271                         r->va = nil;
272                 }
273                 memset(h, ~0, sizeof(Heap)+h->size);
274                 amlfree(h);
275                 i++;
276         }
277
278         return i;
279 }
280
281 static void*
282 mk(int tag, int size)
283 {
284         Heap *h;
285         int a;
286
287         a = sizeof(Heap) + size;
288         assert(a >= sizeof(Heap));
289         h = amlalloc(a);
290         h->size = size;
291         h->tag = tag;
292         h->link = hp;
293         hp = h;
294         return h+1;
295 }
296
297 static uvlong*
298 mki(uvlong i)
299 {
300         uvlong *v;
301
302         v = mk('i', sizeof(uvlong));
303         *v = i & amlintmask;
304         return v;
305 }
306
307 static char*
308 mks(char *s)
309 {
310         char *r = mk('s', strlen(s)+1);
311         strcpy(r, s);
312         return r;
313 }
314
315 static int
316 pkglen(uchar *p, uchar *e, uchar **np)
317 {
318         ulong n;
319         uchar b;
320
321         if(p >= e)
322                 return -1;
323         b = *p++;
324         if(b <= 0x3F)
325                 n = b;
326         else {
327                 n = b & 0xF;
328                 if(p >= e)
329                         return -1;
330                 n += *p++ << 4;
331                 if(b >= 0x80){
332                         if(p >= e)
333                                 return -1;
334                         n += *p++ << 12;
335                 }
336                 if(b >= 0xC0){
337                         if(p >= e)
338                                 return -1;
339                         n += *p++ << 20;
340                 }
341         }
342         if(np)
343                 *np = p;
344         return n;
345 }
346
347 static Name*
348 forkname(Name *dot)
349 {
350         Name *n;
351
352         n = mk('N', sizeof(Name));
353         *n = *dot;
354         n->fork = dot;
355         n->next = n->down = nil;
356         if(dot->v == dot)
357                 n->v = n;
358         if(dot->up == dot)
359                 n->up = n;
360         else {
361                 if(n->up = forkname(dot->up))
362                         n->up->down = n;
363         }
364         return n;
365 }
366
367 static Name*
368 getseg(Name *dot, void *seg, int new)
369 {
370         Name *n, *l;
371
372         for(n = l = nil; dot; dot = dot->fork){
373                 for(n = dot->down; n; n = n->next){
374                         if(memcmp(seg, n->seg, 4) == 0)
375                                 return n;
376                         l = n;
377                 }
378                 if(new){
379                         n = mk('N', sizeof(Name));
380                         memmove(n->seg, seg, sizeof(n->seg));
381                         n->up = dot;
382                         if(l == nil)
383                                 dot->down = n;
384                         else
385                                 l->next = n;
386                         n->v = n;
387                         break;
388                 }
389         }
390         return n;
391 }
392
393 Name*
394 getname(Name *dot, char *path, int new)
395 {
396         char seg[4];
397         int i, s;
398         Name *x;
399
400         if(dot == nil)
401                 return nil;
402
403         s = !new;
404         if(*path == '\\'){
405                 path++;
406                 dot = rootname(dot);
407                 s = 0;
408         }
409         while(*path == '^'){
410                 path++;
411                 dot = dot->up;
412                 s = 0;
413         }
414         do {
415                 for(i=0; i<4; i++){
416                         if(*path == 0 || *path == '.')
417                                 break;
418                         seg[i] = *path++;
419                 }
420                 if(i == 0)
421                         break;
422                 while(i < 4)
423                         seg[i++] = '_';
424                 if(s && *path == 0){
425                         for(;;){
426                                 if(x = getseg(dot, seg, 0))
427                                         break;
428                                 if(dot == dot->up)
429                                         break;
430                                 dot = dot->up;
431                         }
432                         return x;
433                 }
434                 s = 0;
435                 dot = getseg(dot, seg, new);
436         } while(*path++ == '.');
437
438         return dot;
439 }
440
441 static int
442 fixnames(void *dot, void *arg)
443 {
444         void **r, *v;
445         int i;
446
447         if(arg == nil)
448                 r = &((Name*)dot)->v;
449         else
450                 r = arg;
451         v = *r;
452         if(v == nil || v == dot)
453                 return 0;
454         if(TAG(v) == 'p'){
455                 r = (void**)v;
456                 for(i=0; i<(SIZE(r)/sizeof(void*)); i++)
457                         fixnames(dot, r+i);
458                 return 0;
459         }
460         if(TAG(v) == 'n' && (v = getname(dot, v, 0)) != nil)
461                 *r = v;
462         return 0;
463 }
464
465 static uvlong
466 getle(uchar *p, int len)
467 {
468         uvlong v;
469         int i;
470
471         v = 0ULL;
472         for(i=0; i<len; i++)
473                 v |= ((uvlong)p[i]) << i*8;
474         return v;
475 }
476
477 static void
478 putle(uchar *p, int len, uvlong v)
479 {
480         int i;
481
482         for(i=0; i<len; i++){
483                 p[i] = v;
484                 v >>= 8;
485         }
486 }
487
488 static uvlong
489 rwreg(void *reg, int off, int len, uvlong v, int write)
490 {
491         Interp save;
492         uchar buf[8], *p;
493         Region *r;
494
495         save = interp;  /* save, in case we reenter the interpreter */
496         FB = FP+1;      /* allocate new base */
497
498         switch(TAG(reg)){
499         case 'b':
500                 p = reg;
501                 if((off+len) > SIZE(p))
502                         break;
503                 p += off;
504                 if(write)
505                         putle(p, len, v);
506                 else
507                         v = getle(p, len);
508                 goto Out;
509
510         case 'r':
511                 r = reg;
512                 if((off+len) > r->len)
513                         break;
514                 if(r->mapped == 0){
515                         if(amldebug)
516                                 print("\namlmapio(%N): %-8s %llux - %llux\n", 
517                                         (Name*)r->name, spacename[r->space],
518                                         r->off, r->off + r->len);
519                         r->mapped = 1;
520                         if(amlmapio(r) < 0)
521                                 r->mapped = -1;
522                 }
523                 if(r->mapped <= 0)
524                         break;
525
526                 if(r->va != nil)
527                         p = r->va + off;
528                 else {
529                         if(len > sizeof(buf))
530                                 break;
531                         p = buf;
532                 }
533
534                 if(write){
535                         if(amldebug)
536                                 print("\nrwreg(%N): %-8s [%llux+%x]/%d <- %llux\n", 
537                                         (Name*)r->name, spacename[r->space],
538                                         r->off, off, len, v);
539                         putle(p, len, v);
540                         if(r->write != nil){
541                                 if((*r->write)(r, p, len, off) != len)
542                                         break;
543                         } else if(p == buf)
544                                 break;
545                 } else {
546                         if(r->read != nil){
547                                 if((*r->read)(r, p, len, off) != len)
548                                         break;
549                         } else if(p == buf)
550                                 break;
551                         v = getle(p, len);
552                         if(amldebug)
553                                 print("\nrwreg(%N): %-8s [%llux+%x]/%d -> %llux\n", 
554                                         (Name*)r->name, spacename[r->space],
555                                         r->off, off, len, v);
556                 }
557                 goto Out;
558         }
559
560         v = -1;
561 Out:
562         interp = save;  /* restore */
563         return v;
564 }
565
566 static uvlong
567 ival(void *p)
568 {
569         int n;
570
571         if(p != nil){
572                 switch(TAG(p)){
573                 case 'i':
574                         return *((uvlong*)p);
575                 case 's':
576                         if(*((char*)p) == 0)
577                                 break;
578                         return strtoull((char*)p, 0, 16);
579                 case 'b':
580                         n = SIZE(p);
581                         if(n > 0){
582                                 if(n > 8) n = 8;
583                                 return rwreg(p, 0, n, 0, 0);
584                         }
585                 }
586         }
587         return 0;
588 }
589
590 static void *deref(void *p);
591 static void *store(void *s, void *d);
592
593 static int
594 fieldalign(int flags)
595 {
596         switch(flags & AccMask){
597         default:
598         case AnyAcc:
599         case ByteAcc:
600         case BufferAcc:
601                 return 1;
602         case WordAcc:
603                 return 2;
604         case DWordAcc:
605                 return 4;
606         case QWordAcc:
607                 return 8;
608         }
609 }
610
611 static void *rwfield(Field *f, void *v, int write);
612
613 static uvlong
614 rwfieldunit(Field *f, int off, int len, uvlong v, int write)
615 {
616         if(f->index){
617                 if(TAG(f->reg) == 'f'){
618                         /* set index field */
619                         rwfield(f->index, mki(off), 1);
620
621                         /* set or get data field */
622                         if(write){
623                                 void *b = mk('b', len);
624                                 putle(b, len, v);
625                                 rwfield(f->reg, b, 1);
626                         }else{
627                                 v = ival(rwfield(f->reg, nil, 0));
628                         }
629                         return v;
630                 }
631
632                 /* set bank field */
633                 rwfield(f->index, f->bank, 1);
634         }
635         return rwreg(f->reg, off, len, v, write);
636 }
637
638 static void*
639 rwfield(Field *f, void *v, int write)
640 {
641         int boff, blen, wo, ws, wl, wa, wd, i;
642         uvlong w, m;
643         uchar *b;
644
645         if(f == nil)
646                 return nil;
647         blen = f->bitlen;
648         if(write){
649                 if(v && TAG(v) == 'b'){
650                         b = v;
651                         if(SIZE(b)*8 < blen)
652                                 blen = SIZE(b)*8;
653                 } else {
654                         w = ival(v);
655                         b = mk('b', (blen+7)/8);
656                         putle(b, SIZE(b), w);
657                 }
658         } else
659                 b = mk('b', (blen+7)/8);
660         /*
661          * don't free b while in rwfieldunit()/rwreg(),
662          * gc can't find this temporary object referenced.
663          */
664         amltake(b);
665         wa = fieldalign(f->flags);
666         wd = wa*8;
667         boff = 0;
668         while((wl = (blen-boff)) > 0){
669                 wo = (f->bitoff+boff) / wd;
670                 ws = (f->bitoff+boff) % wd;
671                 if(wl > (wd - ws))
672                         wl = wd - ws;
673                 if(write){
674                         w = 0;
675                         for(i = 0; i < wl; i++, boff++)
676                                 if(b[boff/8] & (1<<(boff%8)))
677                                         w |= 1ULL<<i;
678                         w <<= ws;
679                         if(wl != wd){
680                                 m = ((1ULL<<wl)-1) << ws;
681                                 w |= rwfieldunit(f, wo*wa, wa, 0, 0) & ~m;
682                         }
683                         rwfieldunit(f, wo*wa, wa, w, 1);
684                 } else {
685                         w = rwfieldunit(f, wo*wa, wa, 0, 0) >> ws;
686                         for(i = 0; i < wl; i++, boff++){
687                                 b[boff/8] |= (w&1)<<(boff%8);
688                                 w >>= 1;
689                         }
690                 }
691         }
692         amldrop(b);
693         if(write)
694                 return nil;
695         if(blen > 64)
696                 return b;
697         w = getle(b, SIZE(b));
698         return mki(w);
699 }
700
701 static void*
702 deref(void *p)
703 {
704         if(p) switch(TAG(p)){
705         case 'N':
706                 return ((Name*)p)->v;
707         case 'R': case 'A': case 'L':
708                 return *((Ref*)p)->ptr;
709         case 'f': case 'u':
710                 return rwfield(p, nil, 0);
711         }
712         return p;
713 }
714
715 static char*
716 todecstr(uchar *buf, int len, int sep)
717 {
718         char *r, *d;
719         int i, v;
720
721         r = d = mk('s', len*4 + 1);
722         if(len == 0){
723                 *d = 0;
724                 return r;
725         }
726         if(sep == 0)
727                 sep = ' ';
728         for(i=0; i<len; i++){
729                 v = buf[i];
730                 if((*d = '0' + ((v/100) % 10)) != '0')
731                         d++;
732                 if((*d = '0' + ((v/10) % 10)) != '0')
733                         d++;
734                 *d++ = '0' + (v % 10);
735                 *d++ = sep;
736         }
737         d[-1] = 0;
738         return r;
739 }
740
741 static char hex[] = "0123456789ABCDEF";
742
743 static char*
744 tohexstr(uchar *buf, int len, int sep)
745 {
746         char *r, *d;
747         int i;
748
749         r = d = mk('s', len*3 + 1);
750         if(len == 0){
751                 *d = 0;
752                 return r;
753         }
754         if(sep == 0)
755                 sep = ' ';
756         for(i=0; i<len; i++){
757                 *d++ = hex[buf[i] >> 4];
758                 *d++ = hex[buf[i] & 0xF];
759                 *d++ = sep;
760         }
761         d[-1] = 0;
762         return r;
763 }
764
765 static void*
766 copy(int tag, void *s)
767 {
768         uvlong v;
769         void *d;
770         int n;
771
772         if(tag == 0){
773                 if(s == nil)
774                         return nil;
775                 tag = TAG(s);
776         }
777         if(s == nil || TAG(s) == 'i'){
778                 n = 4;
779                 v = ival(s);
780                 if(v > 0xFFFFFFFFULL)
781                         n <<= 1;
782                 switch(tag){
783                 case 'b':
784                         d = mk(tag, n);
785                         rwreg(d, 0, n, v, 1);
786                         return d;
787                 case 's':
788                         n <<= 1;
789                         d = mk(tag, n+1);
790                         ((char*)d)[n] = 0;
791                         while(n > 0){
792                                 ((char*)d)[--n] = hex[v & 0xF];
793                                 v >>= 4;
794                         }
795                         return d;
796                 case 'i':
797                         if(v == 0ULL)
798                                 return nil;
799                         return mki(v);
800                 }
801         } else {
802                 n = SIZE(s);
803                 switch(tag){
804                 case 's':
805                         if(TAG(s) == 'b')
806                                 return tohexstr(s, n, ' ');
807                         /* no break */
808                 case 'b':
809                         if(TAG(s) == 's'){
810                                 n = strlen(s);
811                                 /* zero length string is converted to zero length buffer */
812                                 if(n > 0) n++;
813                         }
814                         d = mk(tag, n);
815                         memmove(d, s, n);
816                         return d;
817                 }
818         }
819         return s;
820 }
821
822 static void*
823 store(void *s, void *d)
824 {
825         void *p, **pp;
826
827         if(d == nil)
828                 return nil;
829         switch(TAG(d)){
830         default:
831                 return nil;
832         case 'A':
833                 s = deref(s);
834                 /* no break */
835         case 'R': case 'L':
836                 pp = ((Ref*)d)->ptr;
837                 while((p = *pp) != nil){
838                         switch(TAG(p)){
839                         case 'R': case 'A': case 'L':
840                                 pp = ((Ref*)p)->ptr;
841                                 break;
842                         case 'N':
843                                 pp = &((Name*)p)->v;
844                                 break;
845                         }
846                         if(*pp == p)
847                                 break;
848                 }
849                 break;
850         case 'N':
851                 pp = &((Name*)d)->v;
852                 break;
853         }
854         p = *pp;
855         if(p != nil && TAG(p) != 'N'){
856                 switch(TAG(p)){
857                 case 'f':
858                 case 'u':
859                         rwfield(p, s, 1);
860                         return d;
861                 }
862                 if(TAG(d) != 'A' && TAG(d) != 'L'){
863                         *pp = copy(TAG(p), s);
864                         return d;
865                 }
866         }
867         *pp = copy(0, s);
868         return d;
869 }
870
871 static int
872 Nfmt(Fmt *f)
873 {
874         char buf[5];
875         int i;
876         Name *n;
877
878         n = va_arg(f->args, Name*);
879         if(n == nil)
880                 return fmtprint(f, "?NIL");
881         if(n == n->up)
882                 return fmtprint(f, "\\");
883         strncpy(buf, n->seg, 4);
884         buf[4] = 0;
885         for(i=3; i>0; i--){
886                 if(buf[i] != '_')
887                         break;
888                 buf[i] = 0;
889         }
890         if(n->up == n->up->up)
891                 return fmtprint(f, "\\%s", buf);
892         return fmtprint(f, "%N.%s", n->up, buf);
893 }
894
895 static int
896 Vfmt(Fmt *f)
897 {
898         void *p;
899         int i, n, c;
900         Env *e;
901         Field *l;
902         Name *nm;
903         Method *m;
904         Region *g;
905         Ref *r;
906
907         p = va_arg(f->args, void*);
908         if(p == nil)
909                 return fmtprint(f, "nil");
910         c = TAG(p);
911         switch(c){
912         case 'N':
913                 nm = p;
914                 if(nm->v != nm)
915                         return fmtprint(f, "%N=%V", nm, nm->v);
916                 return fmtprint(f, "%N=*", nm);
917         case 'A':
918         case 'L':
919                 r = p;
920                 e = r->ref;
921                 if(c == 'A')
922                         return fmtprint(f, "Arg%zd=%V", r->ptr - e->arg, *r->ptr);
923                 if(c == 'L')
924                         return fmtprint(f, "Local%zd=%V", r->ptr - e->loc, *r->ptr);
925         case 'n':
926                 return fmtprint(f, "%s", (char*)p);
927         case 's':
928                 return fmtprint(f, "\"%s\"", (char*)p);
929         case 'i':
930                 return fmtprint(f, "%#llux", *((uvlong*)p));
931         case 'p':
932                 n = SIZE(p)/sizeof(void*);
933                 fmtprint(f, "Package(%d){", n);
934                 for(i=0; i<n; i++){
935                         if(i > 0)
936                                 fmtprint(f, ", ");
937                         fmtprint(f, "%V", ((void**)p)[i]);
938                 }
939                 fmtprint(f, "}");
940                 return 0;
941         case 'b':
942                 n = SIZE(p);
943                 fmtprint(f, "Buffer(%d){", n);
944                 for(i=0; i<n; i++){
945                         if(i > 0)
946                                 fmtprint(f, ", ");
947                         fmtprint(f, "%.2uX", ((uchar*)p)[i]);
948                 }
949                 fmtprint(f, "}");
950                 return 0;
951         case 'r':
952                 g = p;
953                 return fmtprint(f, "Region(%s, %#llux, %#llux)",
954                         spacename[g->space & 7], g->off, g->len);
955         case 'm':
956                 m = p;
957                 fmtprint(f, "%N(", m->name);
958                 for(i=0; i < m->narg; i++){
959                         if(i > 0)
960                                 fmtprint(f, ", ");
961                         fmtprint(f, "Arg%d", i);
962                 }
963                 fmtprint(f, ")");
964                 return 0;
965         case 'u':
966                 fmtprint(f, "Buffer");
967                 /* no break */
968         case 'f':
969                 l = p;
970                 if(l->index){
971                         if(TAG(l->reg) == 'f')
972                                 return fmtprint(f, "IndexField(%x, %x, %x) @ %V[%V]",
973                                         l->flags, l->bitoff, l->bitlen, l->reg, l->index);
974                         else
975                                 return fmtprint(f, "BankField(%x, %x, %x, %V=%V) @ %V",
976                                         l->flags, l->bitoff, l->bitlen, l->index, l->bank, l->reg);
977                 }
978                 return fmtprint(f, "Field(%x, %x, %x) @ %V",
979                         l->flags, l->bitoff, l->bitlen, l->reg);
980         default:
981                 return fmtprint(f, "%c:%p", c, p);
982         }
983 }
984
985 static void
986 dumpregs(void)
987 {
988         Frame *f;
989         Env *e;
990         int i;
991
992         print("\n*** dumpregs: PC=%p FP=%p\n", PC, FP);
993         e = nil;
994         for(f = FP; f >= FB; f--){
995                 print("%.8p.%.2zx: %-8s %N\t", f->start, f-FB, f->phase, f->dot);
996                 if(f->op)
997                         print("%s", f->op->name);
998                 print("(");
999                 for(i=0; i<f->narg; i++){
1000                         if(i > 0)
1001                                 print(", ");
1002                         print("%V", f->arg[i]);
1003                 }
1004                 print(")\n");
1005                 if(e == f->env)
1006                         continue;
1007                 if(e = f->env){
1008                         for(i=0; i<nelem(e->arg); i++)
1009                                 print("Arg%d=%V ", i, e->arg[i]);
1010                         print("\n");
1011                         for(i=0; i<nelem(e->loc); i++)
1012                                 print("Local%d=%V ", i, e->loc[i]);
1013                         print("\n");
1014                 }
1015         }
1016 }
1017
1018 static int
1019 xec(uchar *pc, uchar *end, Name *dot, Env *env, void **pret)
1020 {
1021         static int loop;
1022         int i, c;
1023         void *r;
1024
1025         PC = pc;
1026         if(FB < F0 || FB >= FT)
1027                 goto Out;
1028         FP = FB;
1029
1030         FP->tag = 0;
1031         FP->cond = 0;
1032         FP->narg = 0;
1033         FP->phase = "}";
1034         FP->start = PC;
1035         FP->end = end;
1036         FP->aux = end;
1037         FP->ref = nil;
1038         FP->dot = dot;
1039         FP->env = env;
1040         FP->op = nil;
1041
1042         for(;;){
1043                 if((++loop & 127) == 0)
1044                         gc();
1045                 if(amldebug)
1046                         print("\n%.8p.%.2zx %-8s\t%N\t", PC, FP - FB, FP->phase, FP->dot);
1047                 r = nil;
1048                 c = *FP->phase++;
1049                 switch(c){
1050                 default:
1051                         if(PC >= FP->end){
1052                         Overrun:
1053                                 print("aml: PC overrun frame end");
1054                                 goto Out;
1055                         }
1056                         FP++;
1057                         if(FP >= FT){
1058                                 print("aml: frame stack overflow");
1059                                 goto Out;
1060                         }
1061                         *FP = FP[-1];
1062                         FP->aux = nil;
1063                         FP->ref = nil;
1064                         FP->tag = c;
1065                         FP->start = PC;
1066                         c = *PC++;
1067                         if(amldebug) print("%.2X", c);
1068                         if(c == '['){
1069                                 if(PC >= FP->end)
1070                                         goto Overrun;
1071                                 c = *PC++;
1072                                 if(amldebug) print("%.2X", c);
1073                                 c = octab2[c];
1074                         }else
1075                                 c = octab1[c];
1076                         FP->op = &optab[c];
1077                         FP->narg = 0;
1078                         FP->phase = FP->op->sequence;
1079                         if(amldebug) print("\t%s %s", FP->op->name, FP->phase);
1080                         continue;
1081                 case '{':
1082                         end = PC;
1083                         c = pkglen(PC, FP->end, &PC);
1084                         end += c;
1085                         if(c < 0 || end > FP->end)
1086                                 goto Overrun;
1087                         FP->end = end;
1088                         continue;
1089                 case ',':
1090                         FP->start = PC;
1091                         continue;
1092                 case 's':
1093                         if(end = memchr(PC, 0, FP->end - PC))
1094                                 end++;
1095                         else
1096                                 end = FP->end;
1097                         c = end - PC;
1098                         r = mk('s', c+1);
1099                         memmove(r, PC, c);
1100                         ((uchar*)r)[c] = 0;
1101                         PC = end;
1102                         break;
1103                 case '1':
1104                 case '2':
1105                 case '4':
1106                 case '8':
1107                         end = PC+(c-'0');
1108                         if(end > FP->end)
1109                                 goto Overrun;
1110                         else {
1111                                 r = mki(*PC++);
1112                                 for(i = 8; PC < end; i += 8)
1113                                         *((uvlong*)r) |= ((uvlong)*PC++) << i;
1114                         }
1115                         break;
1116                 case '}':
1117                 case 0:
1118                         if(FP->op){
1119                                 if(amldebug){
1120                                         print("*%p,%V\t%s(", FP->aux, FP->ref, FP->op->name);
1121                                         for(i = 0; i < FP->narg; i++){
1122                                                 if(i > 0)
1123                                                         print(", ");
1124                                                 print("%V", FP->arg[i]);
1125                                         }
1126                                         print(")");
1127                                 }
1128                                 for(i = FP->narg; i < nelem(FP->arg); i++)
1129                                         FP->arg[i] = nil;
1130                                 r = FP->op->eval();
1131                                 if(amldebug)
1132                                         print(" -> %V", r);
1133                         }
1134
1135                         c = FP->phase[-1];
1136                         if(c == '}' && PC < FP->end){
1137                                 FP->narg = 0;
1138                                 FP->phase = "*}";
1139                                 continue;
1140                         }
1141
1142                         if(r) switch(FP->tag){
1143                         case '@':
1144                                 break;
1145                         case 'n':
1146                         case 'N':
1147                                 if(TAG(r) != 'N')
1148                                         r = nil;
1149                                 break;
1150                         default:
1151                                 if((r = deref(r)) == nil)
1152                                         break;
1153                                 switch(TAG(r)){
1154                                 case 'f': case 'u':
1155                                         r = rwfield(r, nil, 0);
1156                                         break;
1157                                 case 'm': {
1158                                         Method *m = r;
1159                                         FP->ref = m;
1160                                         FP->narg = 0;
1161                                         FP->phase = "********}" + (8 - m->narg);
1162                                         FP->op = &optab[Ocall];
1163                                         continue;
1164                                         }
1165                                 }
1166                         }
1167                         FP--;
1168                         break;
1169                 }
1170                 if(FP < FB){
1171                         if(pret){
1172                                 if(amldebug) print(" -> %V\n", r);
1173                                 *pret = r;
1174                         }
1175                         return 0;
1176                 }
1177                 FP->arg[FP->narg++] = r;
1178         }
1179 Out:
1180         if(amldebug)
1181                 dumpregs();
1182         return -1;
1183 }
1184
1185 static void*
1186 evalnamec(void)
1187 {
1188         static char name[1024];
1189         char *d;
1190         void *r;
1191         int c;
1192
1193         c = 1;
1194         d = name;
1195         PC = FP->start;
1196         if(*PC == '\\')
1197                 *d++ = *PC++;
1198         while(*PC == '^'){
1199                 if(d >= &name[sizeof(name)-1]){
1200                 Toolong:
1201                         *d = 0;
1202                         print("aml: name too long: %s\n", name);
1203                         PC = FP->end;
1204                         return nil;
1205                 }
1206                 *d++ = *PC++;
1207         }
1208         if(*PC == '.'){
1209                 PC++;
1210                 c = 2;
1211         } else if(*PC == '/'){
1212                 PC++;
1213                 c = *PC++;
1214         } else if(*PC == 0){
1215                 PC++;
1216                 c = 0;
1217         }
1218         while(c > 0){
1219                 if(d >= &name[sizeof(name)-5])
1220                         goto Toolong;
1221                 *d++ = *PC++;
1222                 *d++ = *PC++;
1223                 *d++ = *PC++;
1224                 *d++ = *PC++;
1225                 while((d > &name[0]) && (d[-1] == '_' || d[-1] == 0))
1226                         d--;
1227                 if(--c > 0)
1228                         *d++ = '.';
1229         }
1230         *d = 0;
1231         if((r = getname(FP->dot, name, FP->tag == 'N')) == nil){
1232                 r = mks(name);
1233                 D2H(r)->tag = 'n';      /* unresolved name */
1234         }
1235         return r;
1236 }
1237
1238 static void*
1239 evaliarg0(void)
1240 {
1241         return FP->arg[0];
1242 }
1243
1244 static void*
1245 evalconst(void)
1246 {
1247         switch(FP->start[0]){
1248         case 0x01:
1249                 return mki(1);
1250         case 0xFF:
1251                 return mki(~0ULL);
1252         }
1253         return nil;
1254 }
1255
1256 static void*
1257 evalbuf(void)
1258 {
1259         int n, m;
1260         uchar *p;
1261
1262         n = ival(FP->arg[0]);
1263         p = mk('b', n);
1264         m = FP->end - PC;
1265         if(m > n)
1266                 m = n;
1267         memmove(p, PC, m);
1268         PC = FP->end;
1269         return p;
1270 }
1271
1272 static void*
1273 evalpkg(void)
1274 {
1275         void **p, **x;
1276         int n;
1277
1278         if((p = FP->ref) != nil){
1279                 x = FP->aux;
1280                 if(x >= p && x < (p+(SIZE(p)/sizeof(void*)))){
1281                         *x++ = FP->arg[0];
1282                         FP->aux = x;
1283                 }
1284         }else {
1285                 n = ival(FP->arg[0]);
1286                 if(n < 0) n = 0;
1287                 p = mk('p', n*sizeof(void*));
1288                 FP->aux = p;
1289                 FP->ref = p;
1290         }
1291         return p;
1292 }
1293
1294 static void*
1295 evalname(void)
1296 {
1297         Name *n;
1298
1299         if(n = FP->arg[0])
1300                 n->v = FP->arg[1];
1301         else
1302                 PC = FP->end;
1303         return nil;
1304 }
1305
1306 static void*
1307 evalscope(void)
1308 {
1309         Name *n;
1310
1311         if(n = FP->arg[0])
1312                 FP->dot = n;
1313         else
1314                 PC = FP->end;
1315         FP->op = nil;
1316         return nil;
1317 }
1318
1319 static void*
1320 evalalias(void)
1321 {
1322         Name *n;
1323
1324         if(n = FP->arg[1])
1325                 n->v = deref(FP->arg[0]);
1326         return nil;
1327 }
1328
1329 static void*
1330 evalmet(void)
1331 {
1332         Name *n;
1333         Method *m;
1334
1335         if((n = FP->arg[0]) != nil){
1336                 m = mk('m', sizeof(Method));
1337                 m->narg = ival(FP->arg[1]) & 7;
1338                 m->start = PC;
1339                 m->end = FP->end;
1340                 m->name = n;
1341                 n->v = m;
1342         }
1343         PC = FP->end;
1344         return nil;
1345 }
1346
1347 static void*
1348 evalreg(void)
1349 {
1350         Name *n;
1351         Region *r;
1352
1353         if((n = FP->arg[0]) != nil){
1354                 r = mk('r', sizeof(Region));
1355                 r->space = ival(FP->arg[1]);
1356                 r->off = ival(FP->arg[2]);
1357                 r->len = ival(FP->arg[3]);
1358                 r->name = n;
1359                 r->va = nil;
1360                 n->v = r;
1361         }
1362         return nil;
1363 }
1364
1365 static void*
1366 evalcfield(void)
1367 {
1368         void *r;
1369         Field *f;
1370         Name *n;
1371         int c;
1372
1373         r = FP->arg[0];
1374         if(r == nil || (TAG(r) != 'b' && TAG(r) != 'r'))
1375                 return nil;
1376         c = FP->op - optab;
1377         if(c == Ocfld)
1378                 n = FP->arg[3];
1379         else
1380                 n = FP->arg[2];
1381         if(n == nil || TAG(n) != 'N')
1382                 return nil;
1383         if(TAG(r) == 'b')
1384                 f = mk('u', sizeof(Field));
1385         else
1386                 f = mk('f', sizeof(Field));
1387         switch(c){
1388         case Ocfld:
1389                 f->bitoff = ival(FP->arg[1]);
1390                 f->bitlen = ival(FP->arg[2]);
1391                 break;
1392         case Ocfld0:
1393                 f->bitoff = ival(FP->arg[1]);
1394                 f->bitlen = 1;
1395                 break;
1396         case Ocfld1:
1397         case Ocfld2:
1398         case Ocfld4:
1399         case Ocfld8:
1400                 f->bitoff = 8*ival(FP->arg[1]);
1401                 f->bitlen = 8*(c - Ocfld0);
1402                 break;
1403         }
1404         f->reg = r;
1405         n->v = f;
1406         return nil;
1407 }
1408
1409 static void*
1410 evalfield(void)
1411 {
1412         int flags, bitoff, n;
1413         Field *f, *index;
1414         void *reg, *bank;
1415         Name *d;
1416         uchar *p;
1417
1418         bank = nil;
1419         index = nil;
1420         bitoff = 0;
1421         switch(FP->op - optab){
1422         default:
1423                 goto Out;
1424         case Ofld:
1425                 if((reg = deref(FP->arg[0])) == nil || TAG(reg) != 'r')
1426                         goto Out;
1427                 flags = ival(FP->arg[1]);
1428                 break;
1429         case Oxfld:
1430                 if((index = deref(FP->arg[0])) == nil || TAG(index) != 'f')
1431                         goto Out;
1432                 if((reg = deref(FP->arg[1])) == nil || TAG(reg) != 'f') /* data field */
1433                         goto Out;
1434                 flags = ival(FP->arg[2]);
1435                 break;
1436         case Obfld:
1437                 if((reg = deref(FP->arg[0])) == nil || TAG(reg) != 'r')
1438                         goto Out;
1439                 if((index = deref(FP->arg[1])) == nil || TAG(index) != 'f')
1440                         goto Out;
1441                 bank = FP->arg[2];
1442                 flags = ival(FP->arg[3]);
1443                 break;
1444         }
1445         p = PC;
1446         if(p >= FP->end)
1447                 return nil;
1448         while(p < FP->end){
1449                 if(*p == 0x00){
1450                         p++;
1451                         if((n = pkglen(p, FP->end, &p)) < 0)
1452                                 break;
1453                         bitoff += n;
1454                         continue;
1455                 }
1456                 if(*p == 0x01){
1457                         p++;
1458                         flags = *p;
1459                         p += 2;
1460                         continue;
1461                 }
1462                 if(p+4 >= FP->end)
1463                         break;
1464                 if((d = getseg(FP->dot, p, 1)) == nil)
1465                         break;
1466                 if((n = pkglen(p+4, FP->end, &p)) < 0)
1467                         break;
1468                 f = mk('f', sizeof(Field));
1469                 f->flags = flags;
1470                 f->bitlen = n;
1471                 f->bitoff = bitoff;
1472                 f->reg = reg;
1473                 f->bank = bank;
1474                 f->index = index;
1475                 bitoff += n;
1476                 d->v = f;
1477         }
1478 Out:
1479         PC = FP->end;
1480         return nil;
1481 }
1482
1483 static void*
1484 evalnop(void)
1485 {
1486         return nil;
1487 }
1488
1489 static void*
1490 evalbad(void)
1491 {
1492         int i;
1493
1494         print("aml: bad opcode %p: ", PC);
1495         for(i=0; i < 8 && (FP->start+i) < FP->end; i++){
1496                 if(i > 0)
1497                         print(" ");
1498                 print("%.2X", FP->start[i]);
1499         }
1500         if((FP->start+i) < FP->end)
1501                 print("...");
1502         print("\n");
1503         PC = FP->end;
1504         return nil;
1505 }
1506
1507 static void*
1508 evalcond(void)
1509 {
1510         switch(FP->op - optab){
1511         case Oif:
1512                 if(FP <= FB)
1513                         break;
1514                 FP[-1].cond = ival(FP->arg[0]) != 0;
1515                 if(!FP[-1].cond)
1516                         PC = FP->end;
1517                 break;
1518         case Oelse:
1519                 if(FP <= FB)
1520                         break;
1521                 if(FP[-1].cond)
1522                         PC = FP->end;
1523                 break;
1524         case Owhile:
1525                 if(FP->aux){
1526                         if(PC >= FP->end){
1527                                 PC = FP->start;
1528                                 FP->aux = nil;
1529                         }
1530                         return nil;
1531                 }
1532                 FP->aux = FP->end;
1533                 if(ival(FP->arg[0]) == 0){
1534                         PC = FP->end;
1535                         break;
1536                 }
1537                 return nil;
1538         }
1539         FP->op = nil;
1540         return nil;
1541 }
1542
1543 static vlong
1544 cmp1(void *a, void *b)
1545 {
1546         vlong c;
1547         int tag;
1548
1549         if(a == nil || TAG(a) == 'i'){
1550                 c = ival(a) - ival(b);
1551         } else {
1552                 tag = TAG(a);
1553                 if(b == nil || TAG(b) != tag)
1554                         b = copy(tag, b);
1555                 if(b == nil || TAG(b) != tag)
1556                         return -1;      /* botch */
1557                 switch(tag){
1558                 default:
1559                         return -1;      /* botch */
1560                 case 's':
1561                         c = strcmp((char*)a, (char*)b);
1562                         break;
1563                 case 'b':
1564                         c = SIZE(a) - SIZE(b);
1565                         if(c == 0)
1566                                 c = memcmp(a, b, SIZE(a));
1567                         break;
1568                 }
1569         }
1570         return c;
1571 }
1572
1573 static void*
1574 evalcmp(void)
1575 {
1576         vlong c = cmp1(FP->arg[0], FP->arg[1]);
1577         switch(FP->op - optab){
1578         case Oleq:
1579                 if(c == 0) return mki(1);
1580                 break;
1581         case Olgt:
1582                 if(c > 0) return mki(1);
1583                 break;
1584         case Ollt:
1585                 if(c < 0) return mki(1);
1586                 break;
1587         }
1588         return nil;
1589 }
1590
1591 static void*
1592 evalcall(void)
1593 {
1594         Method *m;
1595         Env *e;
1596         int i;
1597
1598         if(FP->aux){
1599                 if(PC >= FP->end){
1600                         PC = FP->aux;
1601                         FP->end = PC;
1602                 }
1603                 return nil;
1604         }
1605         m = FP->ref;
1606         e = mk('E', sizeof(Env));
1607         for(i=0; i<FP->narg; i++)
1608                 e->arg[i] = deref(FP->arg[i]);
1609         FP->env = e;
1610         FP->narg = 0;
1611         FP->dot = m->name;
1612         if(m->eval != nil){
1613                 FP->op = nil;
1614                 FP->end = PC;
1615                 return (*m->eval)();
1616         }
1617         FP->dot = forkname(FP->dot);
1618         FP->aux = PC;
1619         FP->start = m->start;
1620         FP->end = m->end;
1621         PC = FP->start;
1622         return nil;
1623 }
1624
1625 static void*
1626 evalret(void)
1627 {
1628         void *r = FP->arg[0];
1629         int brk = (FP->op - optab) != Oret;
1630         while(--FP >= FB){
1631                 switch(FP->op - optab){
1632                 case Owhile:
1633                         if(!brk)
1634                                 continue;
1635                         PC = FP->end;
1636                         return nil;
1637                 case Ocall:
1638                         PC = FP->aux;
1639                         return r;
1640                 }
1641         }
1642         FP = FB;
1643         PC = FB->end;
1644         return r;
1645 }
1646
1647 static void*
1648 evalenv(void)
1649 {
1650         Ref *r;
1651         Env *e;
1652         int c;
1653
1654         if((e = FP->env) == nil)
1655                 return nil;
1656         c = FP->start[0];
1657         if(c >= 0x60 && c <= 0x67){
1658                 r = mk('L', sizeof(Ref));
1659                 r->ptr = &e->loc[c - 0x60];
1660         } else if(c >= 0x68 && c <= 0x6E){
1661                 r = mk('A', sizeof(Ref));
1662                 r->ptr = &e->arg[c - 0x68];
1663         } else
1664                 return nil;
1665         r->ref = e;
1666         return r;
1667 }
1668
1669 static void*
1670 evalstore(void)
1671 {
1672         return store(FP->arg[0], FP->arg[1]);
1673 }
1674
1675 static void*
1676 evalcat(void)
1677 {
1678         void *r, *a, *b;
1679         int tag, n, m;
1680
1681         a = FP->arg[0];
1682         b = FP->arg[1];
1683         if(a == nil || TAG(a) == 'i')
1684                 a = copy('b', a);       /* Concat(Int, ???) -> Buf */
1685         tag = TAG(a);
1686         if(b == nil || TAG(b) != tag)
1687                 b = copy(tag, b);
1688         if(TAG(b) != tag)
1689                 return nil;     /* botch */
1690         switch(tag){
1691         default:
1692                 return nil;     /* botch */
1693         case 'b':
1694                 n = SIZE(a);
1695                 m = SIZE(b);
1696                 r = mk('b', n + m);
1697                 memmove(r, a, n);
1698                 memmove((uchar*)r + n, b, m);
1699                 break;
1700         case 's':
1701                 n = strlen((char*)a);
1702                 m = strlen((char*)b);
1703                 r = mk('s', n + m + 1);
1704                 memmove(r, a, n);
1705                 memmove((char*)r + n, b, m);
1706                 ((char*)r)[n+m] = 0;
1707                 break;
1708         }
1709         store(r, FP->arg[2]);
1710         return r;
1711 }
1712
1713 static void*
1714 evalindex(void)
1715 {
1716         Field *f;
1717         void *p;
1718         Ref *r;
1719         uvlong x;
1720
1721         x = ival(FP->arg[1]);
1722         if(p = deref(FP->arg[0])) switch(TAG(p)){
1723         case 's':
1724                 if(x >= strlen((char*)p))
1725                         break;
1726                 /* no break */
1727         case 'b':
1728                 if(x >= SIZE(p))
1729                         break;
1730                 f = mk('u', sizeof(Field));
1731                 f->reg = p;
1732                 f->bitlen = 8;
1733                 f->bitoff = 8*x;
1734                 store(f, FP->arg[2]);
1735                 return f;
1736         case 'p':
1737                 if(x >= (SIZE(p)/sizeof(void*)))
1738                         break;
1739                 if(TAG(FP->arg[0]) == 'A' || TAG(FP->arg[0]) == 'L')
1740                         r = mk(TAG(FP->arg[0]), sizeof(Ref));
1741                 else
1742                         r = mk('R', sizeof(Ref));
1743                 r->ref = p;
1744                 r->ptr = ((void**)p) + x;
1745                 store(r, FP->arg[2]);
1746                 return r;
1747         }
1748         return nil;
1749 }
1750
1751 static int
1752 match1(int op, void *a, void *b)
1753 {
1754         vlong c = cmp1(a, b);
1755         switch(op){
1756         case 0: return 1;
1757         case 1: return c == 0;
1758         case 2: return c <= 0;
1759         case 3: return c < 0;
1760         case 4: return c >= 0;
1761         case 5: return c > 0;
1762         }
1763         return 0;
1764 }
1765
1766 static void*
1767 evalmatch(void)
1768 {
1769         void **p = FP->arg[0];
1770         if(p != nil && TAG(p) == 'p'){
1771                 uvlong i, n = SIZE(p)/sizeof(void*);
1772                 int o1 = ival(FP->arg[1]), o2 = ival(FP->arg[3]);
1773                 for(i=ival(FP->arg[5]); i<n; i++){
1774                         void *a = deref(p[i]);
1775                         if(match1(o1, a, FP->arg[2]) && match1(o2, a, FP->arg[4]))
1776                                 return mki(i);
1777                 }
1778         }
1779         return mki(~0ULL);
1780 }
1781
1782 static void*
1783 evalcondref(void)
1784 {
1785         void *s;
1786         if((s = FP->arg[0]) == nil)
1787                 return nil;
1788         store(s, FP->arg[1]);
1789         return mki(1);
1790 }
1791
1792 static void*
1793 evalsize(void)
1794 {
1795         return mki(amllen(FP->arg[0]));
1796 }
1797
1798 static void*
1799 evalderef(void)
1800 {
1801         void *p;
1802
1803         if(p = FP->arg[0]){
1804                 if(TAG(p) == 's' || TAG(p) == 'n')
1805                         p = getname(FP->dot, (char*)p, 0);
1806                 p = deref(p);
1807         }
1808         return p;
1809 }
1810
1811 static void*
1812 evalarith(void)
1813 {
1814         uvlong v, d;
1815         void *r;
1816         int i;
1817
1818         r = nil;
1819         switch(FP->op - optab){
1820         case Oadd:
1821                 r = mki(ival(FP->arg[0]) + ival(FP->arg[1]));
1822                 break;
1823         case Osub:
1824                 r = mki(ival(FP->arg[0]) - ival(FP->arg[1]));
1825                 break;
1826         case Omul:
1827                 r = mki(ival(FP->arg[0]) * ival(FP->arg[1]));
1828                 break;
1829         case Omod:
1830         case Odiv:
1831                 v = ival(FP->arg[0]);
1832                 d = ival(FP->arg[1]);
1833                 if(d == 0){
1834                         print("aml: division by zero: PC=%#p\n", PC);
1835                         return nil;
1836                 }
1837                 r = mki(v % d);
1838                 store(r, FP->arg[2]);
1839                 if((FP->op - optab) != Odiv)
1840                         return r;
1841                 r = mki(v / d);
1842                 store(r, FP->arg[3]); 
1843                 return r;
1844         case Oshl:
1845                 r = mki(ival(FP->arg[0]) << ival(FP->arg[1]));
1846                 break;
1847         case Oshr:
1848                 r = mki(ival(FP->arg[0]) >> ival(FP->arg[1]));
1849                 break;
1850         case Oand:
1851                 r = mki(ival(FP->arg[0]) & ival(FP->arg[1]));
1852                 break;
1853         case Onand:
1854                 r = mki(~(ival(FP->arg[0]) & ival(FP->arg[1])));
1855                 break;
1856         case Oor:
1857                 r = mki(ival(FP->arg[0]) | ival(FP->arg[1]));
1858                 break;
1859         case Onor:
1860                 r = mki(~(ival(FP->arg[0]) | ival(FP->arg[1])));
1861                 break;
1862         case Oxor:
1863                 r = mki(ival(FP->arg[0]) ^ ival(FP->arg[1]));
1864                 break;
1865         case Onot:
1866                 r = mki(~ival(FP->arg[0]));
1867                 store(r, FP->arg[1]);
1868                 return r;
1869         case Olbit:
1870                 v = ival(FP->arg[0]);
1871                 if(v == 0)
1872                         break;
1873                 for(i=0; (v & 1) == 0; i++)
1874                         v >>= 1;
1875                 r = mki(i+1);
1876                 break;
1877         case Orbit:
1878                 v = ival(FP->arg[0]);
1879                 if(v == 0)
1880                         break;
1881                 for(i=0; v != 0; i++)
1882                         v >>= 1;
1883                 r = mki(i);
1884                 break;
1885         case Oland:
1886                 return mki(ival(FP->arg[0]) && ival(FP->arg[1]));
1887         case Olor:
1888                 return mki(ival(FP->arg[0]) || ival(FP->arg[1]));
1889         case Olnot:
1890                 return mki(ival(FP->arg[0]) == 0);
1891
1892         case Oinc:
1893                 r = mki(ival(deref(FP->arg[0]))+1);
1894                 store(r, FP->arg[0]);
1895                 return r;
1896         case Odec:
1897                 r = mki(ival(deref(FP->arg[0]))-1);
1898                 store(r, FP->arg[0]);
1899                 return r;
1900         }
1901
1902         store(r, FP->arg[2]);
1903         return r;
1904 }
1905
1906 static void*
1907 evalload(void)
1908 {
1909         enum { LenOffset = 4, HdrLen = 36 };
1910         uvlong *tid;
1911         Region *r;
1912         int l;
1913
1914         tid = nil;
1915         if(FP->aux){
1916                 if(PC >= FP->end){
1917                         amlenum(amlroot, nil, fixnames, nil);
1918                         FP->aux = nil;
1919                         FP->end = PC;
1920                         tid = mki(1);   /* fake */
1921                 }
1922         } else {
1923                 store(nil, FP->arg[1]);
1924                 if(FP->arg[0] == nil)
1925                         return nil;
1926
1927                 l = rwreg(FP->arg[0], LenOffset, 4, 0, 0);
1928                 if(l <= HdrLen)
1929                         return nil;
1930
1931                 FP->aux = PC;   /* save */
1932                 FP->ref = FP->arg[0];
1933                 switch(TAG(FP->ref)){
1934                 case 'b':
1935                         if(SIZE(FP->ref) < l)
1936                                 return nil;
1937                         PC = (uchar*)FP->ref + HdrLen;
1938                         break;
1939                 case 'r':
1940                         r = FP->ref;
1941                         if(r->len < l || r->va == nil || r->mapped <= 0)
1942                                 return nil;
1943                         PC = (uchar*)r->va + HdrLen;
1944                         break;
1945                 default:
1946                         return nil;
1947                 }
1948                 FP->end = PC + (l - HdrLen);
1949                 FP->dot = amlroot;
1950                 FP->env = nil;
1951
1952                 tid = mki(1); /* fake */
1953                 store(tid, FP->arg[1]);
1954         }
1955         return tid;
1956 }
1957
1958 static void*
1959 evalstall(void)
1960 {
1961         amldelay(ival(FP->arg[0]));
1962         return nil;
1963 }
1964
1965 static void*
1966 evalsleep(void)
1967 {
1968         amldelay(ival(FP->arg[0])*1000);
1969         return nil;
1970 }
1971
1972 static void*
1973 evalconv(void)
1974 {
1975         void *r, *a;
1976
1977         r = nil;
1978         a = FP->arg[0];
1979         switch(FP->op - optab){
1980         case Otodec:
1981                 if(a == nil)
1982                         break;
1983                 if(TAG(a) == 's'){
1984                         r = a;
1985                         break;
1986                 }
1987                 if(TAG(a) == 'b'){
1988                         r = todecstr(a, SIZE(a), ',');
1989                         break;
1990                 }
1991                 break;
1992         case Otohex:
1993                 if(a == nil)
1994                         break;
1995                 if(TAG(a) == 's'){
1996                         r = a;
1997                         break;
1998                 }
1999                 if(TAG(a) == 'b'){
2000                         r = tohexstr(a, SIZE(a), ',');
2001                         break;
2002                 }
2003                 break;
2004         case Otoint:
2005                 if(a != nil && TAG(a) == 's')
2006                         r = mki(strtoull((char*)a, 0, 0));
2007                 else
2008                         r = mki(ival(a));
2009                 break;
2010         }
2011         store(r, FP->arg[1]);
2012         return r;
2013 }
2014
2015 static Op optab[] = {
2016         [Obad]          "",                     "",             evalbad,
2017         [Onop]          "Noop",                 "",             evalnop,
2018         [Odebug]        "Debug",                "",             evalnop,
2019
2020         [Ostr]          ".str",                 "s",            evaliarg0,
2021         [Obyte]         ".byte",                "1",            evaliarg0,
2022         [Oword]         ".word",                "2",            evaliarg0,
2023         [Odword]        ".dword",               "4",            evaliarg0,
2024         [Oqword]        ".qword",               "8",            evaliarg0,
2025         [Oconst]        ".const",               "",             evalconst,
2026         [Onamec]        ".name",                "",             evalnamec,
2027         [Oenv]          ".env",                 "",             evalenv,
2028
2029         [Oname]         "Name",                 "N*",           evalname,
2030         [Oscope]        "Scope",                "{n}",          evalscope,
2031         [Oalias]        "Alias",                "nN",           evalalias,
2032
2033         [Odev]          "Device",               "{N}",          evalscope,
2034         [Ocpu]          "Processor",            "{N141}",       evalscope,
2035         [Othz]          "ThermalZone",          "{N}",          evalscope,
2036         [Oprc]          "PowerResource",        "{N12}",        evalscope,
2037
2038         [Oreg]          "OperationRegion",      "N1ii",         evalreg,
2039         [Ofld]          "Field",                "{n1",          evalfield,
2040         [Oxfld]         "IndexField",           "{nn1",         evalfield,
2041         [Obfld]         "BankField",            "{nni1",        evalfield,
2042
2043         [Ocfld]         "CreateField",          "*iiN",         evalcfield,
2044         [Ocfld0]        "CreateBitField",       "*iN",          evalcfield,
2045         [Ocfld1]        "CreateByteField",      "*iN",          evalcfield,
2046         [Ocfld2]        "CreateWordField",      "*iN",          evalcfield,
2047         [Ocfld4]        "CreateDWordField",     "*iN",          evalcfield,
2048         [Ocfld8]        "CreateQWordField",     "*iN",          evalcfield,
2049
2050         [Opkg]          "Package",              "{1}",          evalpkg,
2051         [Ovpkg]         "VarPackage",           "{i}",          evalpkg,
2052         [Obuf]          "Buffer",               "{i",           evalbuf,
2053         [Omet]          "Method",               "{N1",          evalmet,
2054
2055         [Oadd]          "Add",                  "ii@",          evalarith,
2056         [Osub]          "Subtract",             "ii@",          evalarith,
2057         [Omod]          "Mod",                  "ii@",          evalarith,
2058         [Omul]          "Multiply",             "ii@",          evalarith,
2059         [Odiv]          "Divide",               "ii@@",         evalarith,
2060         [Oshl]          "ShiftLef",             "ii@",          evalarith,
2061         [Oshr]          "ShiftRight",           "ii@",          evalarith,
2062         [Oand]          "And",                  "ii@",          evalarith,
2063         [Onand]         "Nand",                 "ii@",          evalarith,
2064         [Oor]           "Or",                   "ii@",          evalarith,
2065         [Onor]          "Nor",                  "ii@",          evalarith,
2066         [Oxor]          "Xor",                  "ii@",          evalarith,
2067         [Onot]          "Not",                  "i@",           evalarith,
2068
2069         [Olbit]         "FindSetLeftBit",       "i@",           evalarith,
2070         [Orbit]         "FindSetRightBit",      "i@",           evalarith,
2071
2072         [Oinc]          "Increment",            "@",            evalarith,
2073         [Odec]          "Decrement",            "@",            evalarith,
2074
2075         [Oland]         "LAnd",                 "ii",           evalarith,
2076         [Olor]          "LOr",                  "ii",           evalarith,
2077         [Olnot]         "LNot",                 "i",            evalarith,
2078
2079         [Oleq]          "LEqual",               "**",           evalcmp,
2080         [Olgt]          "LGreater",             "**",           evalcmp,
2081         [Ollt]          "LLess",                "**",           evalcmp,
2082
2083         [Omutex]        "Mutex",                "N1",           evalnop,
2084         [Oevent]        "Event",                "N",            evalnop,
2085
2086         [Oif]           "If",                   "{i}",          evalcond,
2087         [Oelse]         "Else",                 "{}",           evalcond,
2088         [Owhile]        "While",                "{,i}",         evalcond,
2089         [Obreak]        "Break",                "",             evalret,
2090         [Oret]          "Return",               "*",            evalret,
2091         [Ocall]         "Call",                 "",             evalcall,
2092
2093         [Ostore]        "Store",                "*@",           evalstore,
2094         [Oindex]        "Index",                "@i@",          evalindex,
2095         [Omatch]        "Match",                "*1*1*i",       evalmatch,
2096         [Osize]         "SizeOf",               "*",            evalsize,
2097         [Oref]          "RefOf",                "@",            evaliarg0,
2098         [Ocref]         "CondRefOf",            "@@",           evalcondref,
2099         [Oderef]        "DerefOf",              "@",            evalderef,
2100         [Ocat]          "Concatenate",          "**@",          evalcat,
2101
2102         [Oacq]          "Acquire",              "@2",           evalnop,
2103         [Osignal]       "Signal",               "@",            evalnop,
2104         [Orel]          "Release",              "@",            evalnop,
2105         [Ostall]        "Stall",                "i",            evalstall,
2106         [Osleep]        "Sleep",                "i",            evalsleep,
2107         [Oload]         "Load",                 "*@}",          evalload,
2108         [Ounload]       "Unload",               "@",            evalnop,
2109
2110         [Otodec]        "ToDecimalString",      "*@",           evalconv,
2111         [Otohex]        "ToHexString",          "*@",           evalconv,
2112         [Otoint]        "ToInteger",            "*@",           evalconv,
2113 };
2114
2115 static uchar octab1[] = {
2116 /* 00 */        Oconst, Oconst, Obad,   Obad,   Obad,   Obad,   Oalias, Obad,
2117 /* 08 */        Oname,  Obad,   Obyte,  Oword,  Odword, Ostr,   Oqword, Obad,
2118 /* 10 */        Oscope, Obuf,   Opkg,   Ovpkg,  Omet,   Obad,   Obad,   Obad,
2119 /* 18 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2120 /* 20 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2121 /* 28 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Onamec, Onamec,
2122 /* 30 */        Onamec, Onamec, Onamec, Onamec, Onamec, Onamec, Onamec, Onamec,
2123 /* 38 */        Onamec, Onamec, Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2124 /* 40 */        Obad,   Onamec, Onamec, Onamec, Onamec, Onamec, Onamec, Onamec,
2125 /* 48 */        Onamec, Onamec, Onamec, Onamec, Onamec, Onamec, Onamec, Onamec,
2126 /* 50 */        Onamec, Onamec, Onamec, Onamec, Onamec, Onamec, Onamec, Onamec,
2127 /* 58 */        Onamec, Onamec, Onamec, Obad,   Onamec, Obad,   Onamec, Onamec,
2128 /* 60 */        Oenv,   Oenv,   Oenv,   Oenv,   Oenv,   Oenv,   Oenv,   Oenv,
2129 /* 68 */        Oenv,   Oenv,   Oenv,   Oenv,   Oenv,   Oenv,   Oenv,   Obad,
2130 /* 70 */        Ostore, Oref,   Oadd,   Ocat,   Osub,   Oinc,   Odec,   Omul,
2131 /* 78 */        Odiv,   Oshl,   Oshr,   Oand,   Onand,  Oor,    Onor,   Oxor,
2132 /* 80 */        Onot,   Olbit,  Orbit,  Oderef, Obad,   Omod,   Obad,   Osize,
2133 /* 88 */        Oindex, Omatch, Ocfld4, Ocfld2, Ocfld1, Ocfld0, Obad,   Ocfld8,
2134 /* 90 */        Oland,  Olor,   Olnot,  Oleq,   Olgt,   Ollt,   Obad,   Otodec,
2135 /* 98 */        Otohex, Otoint, Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2136 /* A0 */        Oif,    Oelse,  Owhile, Onop,   Oret,   Obreak, Obad,   Obad,
2137 /* A8 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2138 /* B0 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2139 /* B8 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2140 /* C0 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2141 /* C8 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2142 /* D0 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2143 /* D8 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2144 /* E0 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2145 /* E8 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2146 /* F0 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2147 /* F8 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Oconst,
2148 };
2149
2150 static uchar octab2[] = {
2151 /* 00 */        Obad,   Omutex, Oevent, Obad,   Obad,   Obad,   Obad,   Obad,
2152 /* 08 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2153 /* 10 */        Obad,   Obad,   Ocref,  Ocfld,  Obad,   Obad,   Obad,   Obad,
2154 /* 18 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2155 /* 20 */        Oload,  Ostall, Osleep, Oacq,   Osignal,Obad,   Obad,   Orel,
2156 /* 28 */        Obad,   Obad,   Ounload,Obad,   Obad,   Obad,   Obad,   Obad,
2157 /* 30 */        Obad,   Odebug, Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2158 /* 38 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2159 /* 40 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2160 /* 48 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2161 /* 50 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2162 /* 58 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2163 /* 60 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2164 /* 68 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2165 /* 70 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2166 /* 78 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2167 /* 80 */        Oreg,   Ofld,   Odev,   Ocpu,   Oprc,   Othz,   Oxfld,  Obfld,
2168 /* 88 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2169 /* 90 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2170 /* 98 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2171 /* A0 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2172 /* A8 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2173 /* B0 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2174 /* B8 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2175 /* C0 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2176 /* C8 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2177 /* D0 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2178 /* D8 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2179 /* E0 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2180 /* E8 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2181 /* F0 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2182 /* F8 */        Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,   Obad,
2183 };
2184
2185 int
2186 amltag(void *p)
2187 {
2188         return p ? TAG(p) : 0;
2189 }
2190
2191 void*
2192 amlval(void *p)
2193 {
2194         return deref(p);
2195 }
2196
2197 uvlong
2198 amlint(void *p)
2199 {
2200         return ival(p);
2201 }
2202
2203 int
2204 amllen(void *p)
2205 {
2206         while(p){
2207                 switch(TAG(p)){
2208                 case 'R':
2209                         p = *((Ref*)p)->ptr;
2210                         continue;
2211                 case 'n':
2212                 case 's':
2213                         return strlen((char*)p);
2214                 case 'p':
2215                         return SIZE(p)/sizeof(void*);
2216                 default:
2217                         return SIZE(p);
2218                 }
2219         }
2220         return 0;
2221 }
2222
2223 void*
2224 amlnew(char tag, int len)
2225 {
2226         switch(tag){
2227         case 'i':
2228                 return mki(0);
2229         case 'n':
2230         case 's':
2231                 return mk(tag, len + 1);
2232         case 'p':
2233                 return mk(tag, len * sizeof(void*));
2234         default:
2235                 return mk(tag, len);
2236         }
2237 }
2238
2239 static void*
2240 evalosi(void)
2241 {
2242         static char *w[] = { 
2243                 "Windows 2001",
2244                 "Windows 2001 SP1",
2245                 "Windows 2001 SP2",
2246                 "Windows 2006",
2247         };
2248         char *s;
2249         int i;
2250
2251         s = FP->env->arg[0];
2252         if(s == nil || TAG(s) != 's')
2253                 return nil;
2254         for(i = 0; i < nelem(w); i++)
2255                 if(strcmp(s, w[i]) == 0)
2256                         return mki(0xFFFFFFFF);
2257         return nil;
2258 }
2259
2260 void
2261 amlinit(void)
2262 {
2263         Name *n;
2264
2265         FB = F0;
2266         FP = F0-1;
2267
2268         fmtinstall('V', Vfmt);
2269         fmtinstall('N', Nfmt);
2270
2271         if(!amlintmask)
2272                 amlintmask = ~0ULL;
2273
2274         n = mk('N', sizeof(Name));
2275         n->up = n;
2276
2277         amlroot = n;
2278
2279         getname(amlroot, "_GPE", 1);
2280         getname(amlroot, "_PR", 1);
2281         getname(amlroot, "_SB", 1);
2282         getname(amlroot, "_TZ", 1);
2283         getname(amlroot, "_SI", 1);
2284         getname(amlroot, "_GL", 1);
2285
2286         if(n = getname(amlroot, "_REV", 1))
2287                 n->v = mki(2);
2288         if(n = getname(amlroot, "_OS", 1))
2289                 n->v = mks("Microsoft Windows");
2290         if(n = getname(amlroot, "_OSI", 1)){
2291                 Method *m;
2292
2293                 m = mk('m', sizeof(Method));
2294                 m->narg = 1;
2295                 m->eval = evalosi;
2296                 m->name = n;
2297                 n->v = m;
2298         }
2299 }
2300
2301 void
2302 amlexit(void)
2303 {
2304         amlroot = nil;
2305         FB = F0;
2306         FP = F0-1;
2307         gc();
2308 }
2309
2310 int
2311 amlload(uchar *data, int len)
2312 {
2313         int ret;
2314
2315         ret = xec(data, data+len, amlroot, nil, nil);
2316         amlenum(amlroot, nil, fixnames, nil);
2317         return ret;
2318 }
2319
2320 void*
2321 amlwalk(void *dot, char *name)
2322 {
2323         return getname(dot, name, 0);
2324 }
2325
2326 void
2327 amlenum(void *dot, char *seg, int (*proc)(void *, void *), void *arg)
2328 {
2329         Name *n, *d;
2330         int rec;
2331
2332         d = dot;
2333         if(d == nil || TAG(d) != 'N')
2334                 return;
2335         do {
2336                 rec = 1;
2337                 if(seg == nil || memcmp(seg, d->seg, sizeof(d->seg)) == 0)
2338                         rec = (*proc)(d, arg) == 0;
2339                 for(n = d->down; n && rec; n = n->next)
2340                         amlenum(n, seg, proc, arg);
2341                 d = d->fork;
2342         } while(d);
2343 }
2344
2345 int
2346 amleval(void *dot, char *fmt, ...)
2347 {
2348         va_list a;
2349         Method *m;
2350         void **r;
2351         Env *e;
2352         int i;
2353
2354         va_start(a, fmt);
2355         e = mk('E', sizeof(Env));
2356         for(i=0;*fmt;fmt++){
2357                 switch(*fmt){
2358                 default:
2359                         return -1;
2360                 case 's':
2361                         e->arg[i++] = mks(va_arg(a, char*));
2362                         break;
2363                 case 'i':
2364                         e->arg[i++] = mki(va_arg(a, int));
2365                         break;
2366                 case 'I':
2367                         e->arg[i++] = mki(va_arg(a, uvlong));
2368                         break;
2369                 case 'b':
2370                 case 'p':
2371                 case '*':
2372                         e->arg[i++] = va_arg(a, void*);
2373                         break;
2374                 }
2375         }
2376         r = va_arg(a, void**);
2377         va_end(a);
2378         if(dot = deref(dot))
2379         if(TAG(dot) == 'm'){
2380                 m = dot;
2381                 if(i != m->narg)
2382                         return -1;
2383                 if(m->eval == nil)
2384                         return xec(m->start, m->end, forkname(m->name), e, r);
2385                 if(FB < F0 || FB >= FT)
2386                         return -1;
2387                 FP = FB;
2388                 FP->op = nil;
2389                 FP->env = e;
2390                 FP->narg = 0;
2391                 FP->dot = m->name;
2392                 FP->ref = FP->aux = nil;
2393                 dot = (*m->eval)();
2394         }
2395         if(r != nil)
2396                 *r = dot;
2397         return 0;
2398 }
2399
2400 void
2401 amltake(void *p)
2402 {
2403         if(p != nil)
2404                 D2H(p)->mark |= 2;
2405 }
2406
2407 void
2408 amldrop(void *p)
2409 {
2410         if(p != nil)
2411                 D2H(p)->mark &= ~2;
2412 }