interp.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 287 行
C
287 行
/* * Copyright (c) 1997 M.I.T. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by MIT. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#include <dpf-internal.h>#include <demand.h>#include <hash.h>/* * Load everything as 32 bit, and mask off the unneeded stuff. then * the remainder of the problems are aligned, checked, hash. The cost * here is the load of mask, with a possible cache miss. the benefit * is a much smaller interpreter: * orig: sizes x mask x aligned x checked x hash = 4 * 2 * 2 * 2 * 2 = 64 * new : aligned x checked x hash = 2 * 2 * 2 = 8 * * (should add all terms, all non-terms?) */#define op(op, aligned, unchecked, hash) \ ((aligned) << 3| (unchecked)<<2 | (hash)<<1 | (op == DPF_OP_EQ))#define eq_op(aligned, unchecked, hash) \ op(DPF_OP_EQ, aligned, unchecked, hash)#define s_op(aligned, unchecked) \ op(DPF_OP_SHIFT, aligned, unchecked, 0)typedef enum { /* aligned unchecked hash */ EQ = eq_op(0, 0, 0), EQ_UNCHECKED = eq_op(0, 1, 0), EQ_HASH = eq_op(0, 0, 1), EQ_UNCHECKED_HASH = eq_op(0, 1, 1), EQ_ALIGNED = eq_op(1, 0, 0), EQ_ALIGNED_UNCHECKED = eq_op(1, 1, 0), EQ_ALIGNED_HASH = eq_op(1, 0, 1), EQ_ALIGNED_UNCHECKED_HASH = eq_op(1, 1, 1), /* aligned unchecked */ SHIFT = s_op(0, 0), SHIFT_UNCHECKED = s_op(0, 1), SHIFT_ALIGNED = s_op(1, 0), SHIFT_ALIGNED_UNCHECKED = s_op(1, 1),} state_t;/* label with the right state. */void dpf_compile_atom(Atom a) { struct ir *ir; unsigned unchecked, aligned; ir = &a->ir; /* * If we have shifted on this path or the offset surpasses * the minimal amount of buffer space we are allocated, * emit a check to see if we have exceeded our memory. */ unchecked = !ir->shiftp && (ir->u.eq.offset <= DPF_MINMSG); aligned = ((ir->alignment + ir->u.eq.offset) % 4 == 0); a->code[0] = (isshift(ir)) ? s_op(aligned, unchecked) : eq_op(aligned, unchecked, (a->ht != 0));}static inline int load_lhs(unsigned *lhs, uint8 *msg, unsigned nbytes, struct ir *ir, int aligned, int unchecked) { unsigned off; off = ir->u.eq.offset; if(unchecked) demand(off < nbytes, bogus offset); else if(off >= nbytes) return 0; if(!aligned) memcpy(lhs, msg+off, 4); else { demand((unsigned long)(msg + off) % 4 == 0, bogus alignment); *lhs = *(unsigned *)(msg+off); } *lhs &= ir->u.eq.mask; return 1;}static inline Atom ht_lookup(Ht ht, uint32 val) { Atom hte; assert(ht); for(hte = ht->ht[hash(ht, val)]; hte; hte = hte->next) if(hte->ir.u.eq.val == val) return hte; return 0;}static int fast_interp(uint8 *msg, unsigned nbytes, Atom a, int fail_pid) { /* msg += (msg[off]:nbits & mask) << shift */# define do_shift(aligned, unchecked) do { \ if(!load_lhs(&off, msg, nbytes, ir, aligned, unchecked)) \ continue; \ off <<= ir->u.shift.shift; \ if(off >= nbytes) \ break; \ if((pid = fast_interp(msg+off, nbytes-off,a->kids.lh_first, a->pid)))\ return pid; \ } while(0) /* msg[off]:nbits & mask == val */# define do_eq(aligned, unchecked) do { \ assert(!a->ht); \ if(!load_lhs(&lhs, msg, nbytes, ir, aligned, unchecked)) \ break; \ if(lhs != ir->u.eq.val) \ break; \ if((pid = fast_interp(msg, nbytes, a->kids.lh_first, a->pid))) \ return pid; \ } while(0)# define do_deq(aligned, unchecked) do { \ Atom hte; \ \ assert(a->ht); \ if(!load_lhs(&lhs, msg, nbytes, ir, aligned, unchecked)) \ break; \ if(!(hte = ht_lookup(a->ht, lhs))) \ break; \ if((pid = fast_interp(msg, nbytes, hte->kids.lh_first, hte->pid)))\ return pid; \ } while(0) unsigned lhs, off, pid; struct ir *ir; for(; a; a = a->sibs.le_next) { ir = &a->ir; switch((state_t)a->code[0]) { case EQ: do_eq(0, 0); break; case EQ_UNCHECKED: do_eq(0, 1); break; case EQ_ALIGNED: do_eq(1, 0); break; case EQ_ALIGNED_UNCHECKED: do_eq(1, 1); break; case EQ_HASH: do_deq(0, 0); break; case EQ_ALIGNED_HASH: do_deq(1, 0); break; case EQ_UNCHECKED_HASH: do_deq(0, 1); break; case EQ_ALIGNED_UNCHECKED_HASH: do_deq(1, 1); break; case SHIFT: do_shift(0, 0); break; case SHIFT_UNCHECKED: do_shift(0, 1); break; case SHIFT_ALIGNED: do_shift(1, 0); break; case SHIFT_ALIGNED_UNCHECKED: do_shift(1, 1); break; default: fatal(Bogus op); } } return fail_pid;}static int interp(uint8 *msg, unsigned nbytes, Atom a, unsigned fail_pid) { struct ir *ir; unsigned lhs, off, pid; /* need to see if it ends. */ for(; a; a = a->sibs.le_next) { ir = &a->ir; if(isshift(ir)) { /* msg += (msg[off]:nbits & mask) << shift */ if(!load_lhs(&off, msg, nbytes, ir, 0, 0)) continue; off <<= ir->u.shift.shift; if(off >= nbytes) continue; else if((pid = interp(msg+off, nbytes-off, a->kids.lh_first, a->pid))) return pid; } else if(!a->ht) { /* msg[off]:nbits & mask == val */ if(!load_lhs(&lhs, msg, nbytes, ir, 0, 0)) continue; else if(lhs != ir->u.eq.val) continue; else if((pid = interp(msg, nbytes, a->kids.lh_first, a->pid))) return pid; } else { Atom hte; if(!load_lhs(&lhs, msg, nbytes, ir, 0, 0)) continue; if(!(hte = ht_lookup(a->ht, lhs))) continue; else if((pid = interp(msg, nbytes, hte->kids.lh_first, hte->pid))) return pid; } } return fail_pid;}static int dpf_interp(uint8 *msg, unsigned nbytes) {/* * OSKIT * Tried changing this to 0 to use fast_interp(); turns out * that fast_interp() doesn't work. Gave this error: * file ../../../oskit/dpf/src/dpf/interp.c, line 106: * (unsigned long)(msg + off) % 4 == 0 * bogus alignment */#if 1 return interp(msg, nbytes, dpf_base->kids.lh_first, 0);#else int pid; demand((unsigned long)msg % 4 == 0, bogus message alignment); pid = fast_interp(msg, nbytes, dpf_base->kids.lh_first, 0); assert(pid == interp(msg, nbytes, dpf_base->kids.lh_first, 0)); return pid;#endif}int (*dpf_compile(Atom trie))() { return dpf_interp;}/* * Compute what special-case optimizations we can do. Currently * optimize for: * 1. hash table has no collisions. * 2. hash table has only terminals. * 3. hash table has only non-terminals. */unsigned ht_state(Ht ht) { unsigned state; state = 0; /* no collisions means we can elide collision checks. */ if(!ht->coll) state |= DPF_NO_COLL; /* * note: when the hash table is empty, it will trigger ALL_NTERMS, * HOWEVER, the hash table will be set to REGEN, which will * make ht_regenp return 1. A bit sleazy. Weep. */ if(!ht->nterm) state |= DPF_ALL_TERMS; else if(!ht->term) state |= DPF_ALL_NTERMS; return state;}void dpf_dump(void *ptr) { if(ptr == dpf_interp) printf("<interpreter routine>\n");}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?