vua: Remove vua =P
authorJack Miller <jack@codezen.org>
Sat, 17 Dec 2016 23:45:22 +0000 (17:45 -0600)
committerJack Miller <jack@codezen.org>
Sat, 17 Dec 2016 23:45:22 +0000 (17:45 -0600)
I imagine some of this code will return in some form, but for now I'm
wiping the slate clean to start with a torn up, assimilated TCC codebase
that can generate assembly in memory before I spend a lot of time
customizing it.

22 files changed:
include/vua/vua.h [deleted file]
kernel/main.c
kernel/string.c
vua/LUADIFF [deleted file]
vua/README [deleted file]
vua/ROADMAP [deleted file]
vua/vua.c [deleted file]
vua/vua_bc.c [deleted file]
vua/vua_bc.h [deleted file]
vua/vua_bc_dump.c [deleted file]
vua/vua_hash.c [deleted file]
vua/vua_hash.h [deleted file]
vua/vua_lex.c [deleted file]
vua/vua_lex.h [deleted file]
vua/vua_obj.h [deleted file]
vua/vua_parse.c [deleted file]
vua/vua_parse.h [deleted file]
vua/vua_str.c [deleted file]
vua/vua_tab.c [deleted file]
vua/vua_test.h [deleted file]
vua/vua_vm.asm [deleted file]
vua/vua_vm.h [deleted file]

diff --git a/include/vua/vua.h b/include/vua/vua.h
deleted file mode 100644 (file)
index 1a6b6ef..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#pragma once
-
-void vua_init(void);
-
-#include "../../vua/vua_obj.h"
-
-#define TEST_VUA
-
-#ifdef TEST_VUA
-void vua_test(void);
-#else
-#define vua_test(...)
-#endif
index 3a76866..1ff370d 100644 (file)
@@ -12,8 +12,6 @@
 
 #include <objcache.h>
 
-#include <vua/vua.h>
-
 void main(struct boot_header *boot_header)
 {
     /* Figure out which platform we're on */
@@ -47,8 +45,6 @@ void main(struct boot_header *boot_header)
     test_objcache();
     test_fullmem();
 
-    vua_init();
-
  asm("sti": :);
 
  asm("hlt": :);
index 7e404d2..ed8fcae 100644 (file)
@@ -1,7 +1,6 @@
 /* vim: set ts=4 sw=4 sts=4 et : */
 
 #include <kernel.h>
-#include <vua/vua.h>    // printing native objects
 
 #include <stdarg.h>
 
@@ -97,7 +96,6 @@ void vsnprintf(char *buf, u32 size, char *format, va_list ap)
     char fill;
     char *s;
     char c;
-    vua_str_t *vs;
 
     unsigned long long val;
     s32 fieldwidth = -1;
@@ -134,19 +132,6 @@ void vsnprintf(char *buf, u32 size, char *format, va_list ap)
                 escaped = 0;
                 size++;
                 break;
-            case 'S':
-                vs = tv_str(va_arg(ap, vua_tv_t));
-
-                if (vs) {
-                    for (tmp = 0; tmp < min(vs->len, size); tmp++) {
-                        *str++ = vs->data[tmp];
-                        size--;
-                    }
-                }
-
-                escaped = 0;
-                size++;
-                break;
             case 'l':
                 if (qualifier[0] == 'l')
                     qualifier[1] = 'l';
diff --git a/vua/LUADIFF b/vua/LUADIFF
deleted file mode 100644 (file)
index c773dfd..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-=== Collection of implemented or planned deviations from Lua(JIT) ===
-
-- Tables are indexed from 0. Partially this is because I hate starting lists
-  at 1 even though table access isn't pointer math, but it will also align
-  with using the memory buffer primitive.
-
-- NO implicit casting of variables. e.g. "1" + "2" is an error, not 3.
-
-- NO syntactic sugar for single table or string args to functions. i.e. f
-  "string" or f { whatever } is invalid and should be converted to f("string") or
-  f({whatever})
-
-- 64 bits of address space. This is a kernel level VM and I don't want any
-  restrictions on how much address space is accessible natively. This is
-  going to entail more than a handful of changes to any jmp/call bytecode.
-
-- Memory buffer primitive object similar to a C struct, and accessed like a
-  table. These can only be created with explicit addresses by kernel
-  privileged code, but buffers with implicit addresses can be created by
-  anyone for the purpose of intializing registers, or working with a binary
-  format.
-
-  Buffs can be sliced by any program to hand off to other programs with broad
-  RW or RO access conveyed at type level.
-
-  Buffs support field definitions in byte sizes at compile time so that reads
-  and writes to constant offsets specified by name can be resolved without a
-  runtime lookup. These definitions can be shared formally (in a header file)
-  or written ad hoc, but they are just for convenience. Accesses are still
-  bounds checked at runtime, and since they convey no type information, it's
-  impossible to abuse this system to dereference arbitrary pointers.
-
-- Integer math for everything. No FPU by default. This isn't a performance
-  decision, but a predictability one. With a kernel usecase, I don't want to
-  have to worry about rounding errors, or introduce implicit conversions to
-  integer types to support bit level ops.
-
-  HOWEVER. This is probably the deviation I'm least rigid on. Mostly
-  because we introduce the need to pack and unpack TV_INT values to do math,
-  where LJ's double values can be operated on in place because the FPU won't
-  touch NaN values LJ uses to store type info. We can somewhat mitigate this by
-  being smart with KREGs, but it's hard to beat hardware supported
-  passthrough. Taking this performance difference into account, if we get
-  preliminary benchmarks that show we're generating slower assembly with
-  integer math anyway, I may be persuaded.
-
-- Bitops are part of the default language (like Lua, unlike LuaJIT) and will
-  have bytecode.
-
-- Conditionals are slightly different. Like C, numeric conditions will be
-  considered false if they're exactly equal to 0. Like Lua though, nil
-  is equivalent to false, and strings are true regardless of value.
-
-- 64 bit math. In particular, instead of having KSHORT/KNUM like LJ, we'll
-  have KNUM (which is a 60 bit integer instead of a 52 bit precision double in
-  LJ) and KREG which is an untouched full 64 bit integer. KREGs have their own
-  constant pool and bytecode forms, but can only be loaded from memory buffers
-  and stored into memory buffers.
-
-  KREGs may not be mixed with any other variable type, although two specific
-  and manual cast operations KREG<=>KNUM will exist at the cost of a shift
-  (and possibly or) instruction, with no built-in overflow contingency.
-
-  I'm not sure if these KREGs will be directly passable to functions, or if
-  they'll have to be written into a memory buffer object and passed like
-  any other tracked value. If they are passable, this significantly changes
-  the structure of CALL bytecodes.
-
-  The main idea of KREG though, is that kernel level code will still be able
-  to take advantage of full register reads and writes, but more importantly
-  all applications will be able to do complex chunks of math without constantly
-  packing and unpacking TV_INTs.
diff --git a/vua/README b/vua/README
deleted file mode 100644 (file)
index c43b492..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-Vua - Viridis Lua
-
-A Lua VM tightly bound to kernel level memory management.
-
-This must eventually be JIT'd for which I will crib LuaJIT at every possible
-point. At the moment, my plan is to get a working parser/lexer together and
-after that probably put together an interpreter because it should be
-relatively easy to do a naive implementation that will knock out some basic
-topics like the sort of memory management facilities the kernel should
-provide. However, the long run solution is to have this generating verified
-assembly that can be run directly on the CPU shared in a single processor
-context to virtually eliminate context switches and (hopefully) get some
-really great performance out of our caches.
-
-= A dynamic language base system ?! =
-
-The crazy idea here is that processes can safely exist in the same memory
-context. With binaries running arbitrary machine code this is impossible. You
-can analyze the assembly but since you have no information about range of
-inputs, or results of IO, as soon as you read or write to an unpredictable
-address, or by an unpredictable offset, your verification code can only do so
-much to verify the code is safe.
-
-Once you abandon the idea of running binaries, you have only one option
-because in the end, after all, everything still boils down to instructions.
-
-So you need to write a compiler of some sort, but the basic paradigms of some
-languages are impossible to verify even with source. How can you implement
-even something as basic as strlen() in C *without* passing a pointer to
-arbitrary memory that you decide is a string?
-
-Instead, you can use an interpreted dynamic language and AOT/JIT compile into
-assembly. That way you can verify that the process has access to everything
-it needs (which essentially amounts to ensuring everything it's using is in
-scope) and generate your own assembly that you know is correct.
-
-The performance hit taken (compared to native binaries) from resorting to
-this strategy (regardless of chosen language or compiler tactics) depends on
-how well we leverage the shared context, but it also give us the ability to
-almost fully insulate the user from the hardware and experiment liberally
-with assembly generation and optimization.
-
-= Lua? =
-
-I chose Lua because I find the syntax to be readable, and most importantly
-there isn't much of it. There's literally a single data structure and a
-handful of operations and grammar. It's also been proved that Lua can be fast
-as hell which is clearly going to be important when your entire base system
-is tied to a language.
-
-I also considered Lisp/Scheme but while I like the idea, the implementations
-are fractured and the communities can't converge because the languages are
-*too expressive* if that's possible. Lua reminds me much more of a bare bones
-hybrid of Python and C.
-
-There are some statically compiled languages that look interesting too, like
-Rust which has some neat properties especially with containing pointers that
-piqued my interest, but our memory model is lethal to pre-compiled binaries
-so I'd still have to write (or port with great effort considering our
-environment) a compiler and linker to generate in memory instructions on the
-fly, and that is a *far* more complex task with a featureful, statically
-compiled language versus an austere, duck typing language like Lua.
-
-Lua is already memory safe and I believe it can be expanded to do native
-memory access and register math relatively easily by adapting the parser to
-accept hints about untracked values, and generate specialized bytecode (and
-then specialized native instructions) to deal with it, being loaded from and
-stored to memory buffer objects.
-
-For the sort of reactive programming I'm going to implement in userspace, it
-might seem like functional programming or logic programming would be more
-appropriate paradigm, however I believe that imperative programming is more
-attuned to how people think and computers operate. Considering this will be
-used for low level micro-kernel daemons, fundamentally altering the
-programming paradigm might be a bridge too far. However, the organization of
-the operating system is conducive to lazy, functional behavior, even if all
-of the units of code are written imperatively.
-
-More pragmatically, Lua is just a starting point to be built upon and
-fundamentally I don't need a lot of knobs on a language just to test this
-theory, but I do have to assume the overhead of some sort of radical security
-abstraction and a JIT compiler is a good step in that direction. Lightweight
-and capable of responding to trace input, as well as using a bytecode
-abstraction.
-
-= Why not just use LuaJIT? =
-
-I am cribbing from LuaJIT as much as I possibly can, but this interpreter
-needs to be modularized to run multiple *totally separate processes* at once,
-and to *verify* the assembly it outputs which is far more complicated than
-just having a couple of userspace threads running around in the same context.
-
-More concretely, I am unwilling to involve the FPU in general programs
-(LuaJIT uses doubles or u32s for math), and want full u64 register math,
-bitwise operations as well as 64 bit addressability, where LuaJIT compresses
-memory references into 32 bits.
-
-= Vua? =
-
-Which brings me to why this is Vua and not VLua or something. I fully expect
-that this will end up being a dialect of Lua. Dynamically typed, interpreted
-programming languages are generally not designed to run as system level
-software and so I'm betting it will take some non-standard extensions to get
-there.
diff --git a/vua/ROADMAP b/vua/ROADMAP
deleted file mode 100644 (file)
index 46215a5..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-This is a loose document to describe the rough order in which I'll approach
-Vua dev. It's really easy to get overwhelmed, despite the fact that we're
-cribbing from LuaJIT, so just having a milestone to focus on is good. That
-said, this order isn't final.
-
-- Assigning constant values to variables, and doing simple operations (math,
-  unary ops, comparisons). This will get the expression parser up to snuff.
-
-- Basic conditionals. Most likely just "if", but possibly others if they fall
-  out easily. The important part is to exercise jump lists.
-
-- Dealing with "local", so upvalues, visibility rules, etc. Up to here, every
-  variable is assumed global, but after conditionals we have scoped blocks
-  that we can use to test. This will also further establish our function local
-  stack which is going to be important for prototyping.
-
-- Finalizing a function prototype. This will take a function and prep it to
-  run. This includes creating constant lookup tables and any else that would
-  be required to interpret the bytecode quickly.
-
-- Dispatch a thread to run a simple function. Effectively at this point we'd
-  be an operational bytecode interpreter for a trivial language, but the
-  important thing is that we can start testing actual execution of the bytecode
-  instead of just examining it.
-
-- Function calls. This includes everything that we didn't have to tackle for
-  the function prototype. Multiple arguments, multiple returns, tail calls,
-  and call assignment. At this point it should be possible to write and execute
-  a tail call optimized factorial function (for example).
-
-- Table manipulation. Both defining / duping constant table initializers and
-  dereference / field assignment, len, etc. Likely also metatables.
-
-- A round-up pass. This will include implementing any remaining operators
-  that Vua doesn't support already like bitwise operations, potentially any
-  boolean operations we didn't get to, and lower priority stuff like string
-  manipulation. Basically, clean up the TODOs for any more fundamental
-  expression stuff before we start tackling advanced features.
-
-- Garbage collection. At this point we'll have most of the core objects in
-  place and should be able to garbage collect a running thread from another
-  thread.
-
-- More advanced flow control, most likely iterators will still need
-  attention.
-
-- Dealing with regs and structs. This is going to be the first really
-  significant deviation from Lua proper. Specialized bytecode to deal with
-  full register integer math without packing and unpacking TV_INTs. This will
-  go hand in hand with a kernel object (only available to privileged code) that
-  can create arbitrary memory buffers (structs), which only accept native
-  register input and ouput and provide byte accurate mediated access to raw
-  memory.
-
-- Rounding up higher level requirements. Stuff like "require" that don't
-  get reflected in bytecode necessarily, but need to be used to
-
-At this point we'll have a pretty useful and full featured interpreter and I
-haven't yet decided if I'm going to immediately look at the JIT, or if it
-makes more sense to start implementing drivers and look at JIT'ing once we
-have a firmer grasp on the sort of memory barrier primitives and locking
-we're going to provide.
diff --git a/vua/vua.c b/vua/vua.c
deleted file mode 100644 (file)
index 5d98496..0000000
--- a/vua/vua.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/* vim: set ts=4 sw=4 sts=4 et : */
-
-#include <kernel.h>
-
-#include <vua/vua.h>
-
-#include "vua_obj.h"
-#include "vua_hash.h"
-#include "vua_parse.h"
-#include "vua_vm.h"
-#include "vua_test.h"
-
-char *test_prog = "function a() local a = 2; local x = 1; function b() y = 0; x = a; end end\na()";
-
-void vua_init(void)
-{
-    vua_state_t *state = NULL;
-    vua_proto_t *program;
-
-    vua_test();
-
-    vua_parse((u8 *) test_prog, strlen(test_prog), &program);
-
-    vm_entry(state, program);
-}
-
-#ifdef TEST_VUA
-
-#include <page_alloc.h>
-
-char *test_char_longstring = NULL;
-
-u64 test_long = 0x1234567890abcdef;
-
-void vua_test(void)
-{
-    vua_str_t *str;
-    char *tmp = "abc";
-    u32 inthash;
-    u32 strhash;
-    int i;
-
-    /* Big string, crossing multiple allocation sizes, with all byte values */
-    test_char_longstring = page_alloc(0);
-    for(i = 0; i < PAGE_SIZE; i++)
-        test_char_longstring[i] = (i % 256);
-
-    str = vua_str_create(test_char_longstring, PAGE_SIZE);
-
-    page_alloc_free(test_char_longstring);
-
-    inthash = vua_hash_data(&test_long, sizeof(u64), 0);
-    assert(inthash == 0x877f1449);
-
-    strhash = vua_hash_str(str, 0);
-    assert(strhash == 0xec6dd2a8);
-
-    vua_str_free(str);
-
-    str = vua_str_create(NULL, 0);
-
-    vua_str_append(str, 'a');
-    vua_str_append(str, 'b');
-    vua_str_append(str, 'c');
-
-    assert(strncmp(str->data, tmp, str->len) == 0);
-
-    test_vua_tab();
-}
-#endif
diff --git a/vua/vua_bc.c b/vua/vua_bc.c
deleted file mode 100644 (file)
index d01493c..0000000
+++ /dev/null
@@ -1,1091 +0,0 @@
-/* vim: set ts=4 sw=4 sts=4 et : */
-
-#include <kernel.h>
-
-#include <objcache.h>
-
-#include "vua_bc.h"
-#include "vua_parse.h"
-
-DEFINE_OBJCACHE(bc_cache);
-
-static void __jmp_patchval(parser_t *parser, BCPos list, BCPos vtarget,
-        BCReg reg, BCPos dtarget);
-static void __jmp_dropval(parser_t *parser, BCPos list);
-static BCPos __emit_jmp(parser_t *parser);
-static int __jmp_novalue(parser_t *parser, BCPos list);
-
-/* Handle standard function level constants, table maps TV to a constant number
- * to be embedded into an instruction.
- */
-
-u32 vua_bc_newconst(parser_t *parser, vua_tv_t val)
-{
-    vua_tv_t *ret;
-
-    if (parser->func->constants == NULL) {
-        parser->func->constants = vua_tab_new(0, 0);
-        if (!parser->func->constants) {
-            printk("Couldn't create function constant table\n");
-            return BCBAD_CONST;
-        }
-    }
-
-    ret = vua_tab_set(parser->func->constants, val);
-
-    if (!ret)
-        return BCBAD_CONST;
-
-    if (*ret != nil_tv)
-        return tv_int(*ret);
-
-    if (tvis_int(val)) {
-        *ret = int_tv(parser->func->num_consts++);
-        return parser->func->num_consts - 1;
-    } else {
-        *ret = int_tv(parser->func->obj_consts++);
-        return parser->func->obj_consts - 1;
-    }
-}
-
-#if 0
-/* Handle u64 register constants. The rest of the runtime doesn't
- * have any support yet, but this is a good first step.
- *
- * This function abuses the fact that the table doesn't touch
- * the value TV, only the key.
- */
-
-static u32 vua_bc_newconst_reg(parser_t *parser, u64 reg)
-{
-    vua_tv_t *ret;
-    int i;
-
-    if (parser->func->kregs == NULL) {
-        parser->func->kregs = vua_tab_new(0, 0);
-        if (!parser->func->kregs) {
-            printk("Couldn't create function register constant table\n");
-            return BCBAD_CONST;
-        }
-    }
-
-    for (i = 0; i < parser->func->reg_consts; i++) {
-        ret = vua_tab_get(parser->func->kregs, int_tv(i));
-
-        if (*ret == reg)
-            return i;
-    }
-
-    ret = vua_tab_set(parser->func->kregs, tv_int(parser->func->reg_consts++));
-
-    if (!ret)
-        return BCBAD_CONST;
-
-    *ret = reg;
-    return i;
-}
-#endif
-
-static void __reg_free(parser_t *parser, BCReg reg)
-{
-    func_t *func = parser->func;
-
-    if (reg >= func->nactvar) {
-        func->freereg--;
-        assert(reg == func->freereg);
-    }
-}
-
-void vua_bc_reg_reserve(parser_t *parser, int num)
-{
-    parser->func->freereg += num;
-
-    if (parser->func->framesize < parser->func->freereg)
-        parser->func->framesize = parser->func->freereg;
-}
-
-static void __expr_free(parser_t *parser, expr_t *expr)
-{
-    if (expr->type == VNONRELOC)
-        __reg_free(parser, expr->v.r.info);
-}
-
-/* Free two exprs, without asserting that they're freed in order, so we
- * can easily free both sides of a binop
- */
-
-static void __expr_free2(parser_t *parser, expr_t *expr, expr_t *expr2)
-{
-    func_t *func = parser->func;
-
-    if ((expr->type == VNONRELOC)&&(expr->v.r.info >= func->nactvar))
-        func->freereg--;
-    if ((expr2->type == VNONRELOC)&&(expr2->v.r.info >= func->nactvar))
-        func->freereg--;
-}
-
-/* Actually insert an instruction, advance PC etc. */
-
-#define BC_STRIDE   32
-
-static BCPos __emit(parser_t *parser, BCIns ins)
-{
-    BCInsLine *new;
-    func_t *func = parser->func;
-    BCPos pc = func->pc;
-    ptrdiff_t delta = func->bcbase - parser->bcstack;
-    int rem = func->max_pc - func->pc;
-
-    /* Resolve pending jumps */
-
-    __jmp_patchval(parser, func->jpc, pc, NO_REG, pc);
-    func->jpc = NO_JMP;
-
-    if (rem == 0) {
-        new = objcache_get(&bc_cache, (parser->bclim + BC_STRIDE) * sizeof(BCInsLine));
-        assert(new);
-
-        if (parser->bcstack) {
-            memcpy(new, parser->bcstack, parser->bclim * sizeof(BCInsLine));
-            objcache_free(&bc_cache, parser->bcstack);
-        }
-
-        parser->bcstack = new;
-        parser->bclim += BC_STRIDE;
-
-        func->bcbase = new + delta;
-        func->max_pc += BC_STRIDE;
-    }
-
-    func->bcbase[pc].ins = ins;
-    func->bcbase[pc].line = parser->lexer.line;
-    func->pc++;
-
-    return pc;
-}
-
-/* Resolve an non-constant expression into a RELOCABLE or NONRELOC value, based
- * on whether it must be committed to a register right now.
- *
- * GETs to non-local variables (upvalues, globals) can be easily changed in
- * isolation to take any registers as inputs and outputs later because these
- * calls don't use or touch the local stack.
- *
- * INDEX operations can easily be changed too, because the table involved has
- * to already be in a register so the result can be easily re-directed to any
- * available register.
- *
- * CALLS and references to LOCAL variables, however, need registers now. CALLS
- * because it uses a range of input and output registers that have to be
- * contiguous and thus should be reserved as soon as possible. LOCAL because
- * their use might affect the local stack.
- *
- * After this function, expr->type is RELOCABLE or NONRELOC or it's a constant
- * type that's passed through.
- *
- * If it's RELOCABLE, v.uval is the BCPos of emitted instruction, so later it
- * can be committed to a register and the instruction modified.
- *
- * If it's NONRELOC, info is the register it's been committed to.
- */
-
-void vua_bc_discharge(parser_t *parser, expr_t *expr)
-{
-    BCIns ins;
-    int c;
-
-    if (expr->type == VGLOBAL) {
-        c = vua_bc_newconst(parser, expr->v.val);
-        if (c > BCMAX_D)
-            return;
-        ins = BCINS_AD(BC_GGET, 0, c);
-    } else if (expr->type == VUPVAL) {
-        ins = BCINS_AD(BC_UGET, 0, expr->v.r.info);
-    } else if (expr->type == VLOCAL) {
-        expr->type = VNONRELOC;
-        return;
-    } else
-        return;
-
-    expr->v.r.info = __emit(parser, ins);
-    expr->type = VRELOCABLE;
-}
-
-/* Emit an expression to a specific register. Ignore branches, for use when
- * we're actually processing branches. Expression is either resolved into a
- * NONRELOC, with v.r.info set to reg, or it's type VJMP. True/false list are
- * not touched.
- */
-
-#define bcptr(parser, expr) (&(parser)->func->bcbase[(expr)->v.r.info].ins)
-
-static void __toreg_nobranch(parser_t *parser, expr_t *expr, BCReg reg)
-{
-    BCIns ins;
-    int c;
-
-    if (expr->type == VKSTR) {
-        c = vua_bc_newconst(parser, expr->v.val);
-        if (c > BCMAX_D)
-            return;
-        ins = BCINS_AD(BC_KSTR, reg, c);
-    } else if (expr->type == VKNUM) {
-        c = vua_bc_newconst(parser, int_tv(expr->v.uval));
-        if (c > BCMAX_D)
-            return;
-        ins = BCINS_AD(BC_KNUM, reg, c);
-    } else if (expr->type == VRELOCABLE) {
-        setbc_a(bcptr(parser, expr), reg);
-        goto noins;
-    } else if (expr->type == VNONRELOC) {
-        if (reg == expr->v.r.info)
-            goto noins;
-        ins = BCINS_AD(BC_MOV, reg, expr->v.r.info);
-    } else if (expr->type <= VKTRUE)
-        ins = BCINS_AD(BC_KPRI, reg, expr->type);
-    else
-        return;
-
-    __emit(parser, ins);
-
-noins:
-    expr->v.r.info = reg;
-    expr->type = VNONRELOC;
-}
-
-/* Emit an expression to a specific register. */
-
-static void __toreg(parser_t *parser, expr_t *expr, BCReg reg)
-{
-    BCPos jval, jfalse, jtrue;
-
-    __toreg_nobranch(parser, expr, reg);
-
-    /* VJMP expressions, which are comparisons that have had their test/jmp
-     * instructions emitted, need to be fixed up after the statement is parsed,
-     * just like and/or branches.
-     */
-
-    if (expr->type == VJMP)
-        vua_bc_jmp_append(parser, &expr->true_list, expr->v.r.info);
-
-    /* If this expression has jump lists, they need to be patched to place
-     * return values into reg.
-     *
-     * If either of the true/false lists include tests that aren't copies
-     * (jmp_novalue) then we're going to need to substitute a value. This
-     * happens, for example, when NOTs cause values to be discarded (dropval)
-     * or comparisons are being placed in a register and thus need to be made
-     * into explicit values instead of implied by the results of a comparison
-     * op.
-     */
-
-    if (expr->true_list != expr->false_list) {
-
-        jfalse = NO_JMP;
-        jtrue = NO_JMP;
-
-        if (__jmp_novalue(parser, expr->true_list)||
-               __jmp_novalue(parser, expr->false_list)) {
-
-            if (expr->type == VJMP)
-                jval = NO_JMP;
-            else
-                jval = __emit_jmp(parser);
-
-            jfalse = __emit(parser, BCINS_AD(BC_KPRI, reg, VKFALSE));
-
-            __emit(parser, BCINS_AJ(BC_JMP, parser->func->freereg, 1));
-
-            jtrue = __emit(parser, BCINS_AD(BC_KPRI, reg, VKTRUE));
-
-            vua_bc_jmp_here(parser, jval);
-        }
-
-        parser->func->last_target = parser->func->pc;
-        __jmp_patchval(parser, expr->false_list, parser->func->pc, reg, jfalse);
-        __jmp_patchval(parser, expr->true_list, parser->func->pc, reg, jtrue);
-    }
-
-    expr->v.r.info = reg;
-    expr->type = VNONRELOC;
-    expr->true_list = NO_JMP;
-    expr->false_list = NO_JMP;
-}
-
-/* Grab a register, and emit expression to it */
-
-/* NOTE: This expects the expression has already been discharged */
-
-BCReg vua_bc_tonextreg(parser_t *parser, expr_t *expr)
-{
-    __expr_free(parser, expr);
-
-    vua_bc_reg_reserve(parser, 1);
-
-    __toreg(parser, expr, parser->func->freereg - 1);
-
-    return parser->func->freereg - 1;
-}
-
-/* Determine if this expression is already in a reg, if not emit it to the next
- * available register
- */
-
-static BCReg __toanyreg(parser_t *parser, expr_t *expr)
-{
-    vua_bc_discharge(parser, expr);
-
-    if (expr->type == VNONRELOC) {
-        return expr->v.r.info;
-    }
-
-    return vua_bc_tonextreg(parser, expr);
-}
-
-/* To value discharges all expressions, whether simple or complex (jump) */
-
-static void __toval(parser_t *parser, expr_t *expr)
-{
-    if (expr->true_list != expr->false_list)
-        __toanyreg(parser, expr);
-    else
-        vua_bc_discharge(parser, expr);
-}
-
-void vua_bc_emit_store(parser_t *parser, expr_t *var, expr_t *expr)
-{
-    BCIns ins;
-    BCReg a;
-    int c;
-
-    if (var->type == VLOCAL) {
-        parser->vstack[var->v.r.aux].flags |= VSTACK_VAR_RW;
-        __expr_free(parser, expr);
-        __toreg(parser, expr, var->v.r.info);
-        return;
-    } else if (var->type == VUPVAL) {
-        parser->vstack[var->v.r.aux].flags |= VSTACK_VAR_RW;
-        __toval(parser, expr);
-        if (expr->type <= VKPRI) {
-            c = expr->type;
-            ins = BCINS_AD(BC_USETP, var->v.r.info, c);
-        } else if (expr->type == VKSTR) {
-            c = vua_bc_newconst(parser, str_tv(expr->v.val));
-            ins = BCINS_AD(BC_USETS, var->v.r.info, c);
-        } else if (expr->type == VKNUM) {
-            c = vua_bc_newconst(parser, int_tv(expr->v.uval));
-            ins = BCINS_AD(BC_USETN, var->v.r.info, c);
-        } else {
-            c = __toanyreg(parser, expr);
-            ins = BCINS_AD(BC_USETV, var->v.r.info, c);
-        }
-        assert(c <= BCMAX_D);
-    } else if (var->type == VGLOBAL) {
-        a = __toanyreg(parser, expr);
-
-        c = vua_bc_newconst(parser, var->v.val);
-        if (c > BCMAX_D)
-            return;
-
-        ins = BCINS_AD(BC_GSET, a, c);
-    }
-
-    __emit(parser, ins);
-    __expr_free(parser, expr);
-}
-
-/* Emit the LHS of a binary operation */
-
-void vua_bc_emit_binop_left(parser_t *parser, binop op, expr_t *expr)
-{
-    /* The emit branch looks backwards here if you're thinking about how flow
-     * control branches are emitted, but the branch here is to the next
-     * conditional expression, not to an associated block.
-     */
-
-    if (op == OPR_AND)
-        vua_bc_emit_branch_t(parser, expr);
-    else if (op == OPR_OR)
-        vua_bc_emit_branch_f(parser, expr);
-
-    /* Concat doesn't take any constants, and operates on a range of input
-     * registers that must be contiguous, so emit to a new reg that will fall
-     * in that range.
-     */
-
-    else if (op == OPR_CONCAT) {
-        vua_bc_discharge(parser, expr);
-        vua_bc_tonextreg(parser, expr);
-
-    /* Equality is defined for all basic types, but constants are embedded into
-     * the instructions.
-     */
-
-    } else if (op == OPR_EQ || op == OPR_NE) {
-        if ((expr->true_list != expr->false_list) || expr->type > VKLAST)
-            __toanyreg(parser, expr);
-
-    /* Remaining binops are defined at the instruction level only for integer
-     * constants which can be embedded into *VN *NV instructions.
-     */
-
-    } else {
-        if ((expr->true_list != expr->false_list) || expr->type != VKNUM)
-            __toanyreg(parser, expr);
-    }
-}
-
-/* Potentially pre-compute constant expressions */
-
-static int __fold_arith(parser_t *parser, binop op, expr_t *left, expr_t *right)
-{
-    u64 i, pow;
-
-    if ((left->type != VKNUM)||(right->type != VKNUM))
-        return 0;
-
-    /* TODO: Overflow? Signed values? */
-
-    if (op == OPR_ADD)
-        left->v.uval += right->v.uval;
-    else if (op == OPR_MUL)
-        left->v.uval *= right->v.uval;
-    else if (op == OPR_SUB)
-        left->v.uval -= right->v.uval;
-    else if (op == OPR_DIV) {
-        if (right->v.uval != 0)
-            left->v.uval /= right->v.uval;
-        else
-            printk("ERROR: Div by 0\n");
-    } else if (op == OPR_DIV) {
-        if (right->v.uval != 0)
-            left->v.uval %= right->v.uval;
-        else
-            printk("ERROR: Mod by 0\n");
-    } else if (op == OPR_POW) {
-        pow = 1;
-        for (i = 0; i < right->v.uval; i++)
-            pow *= left->v.uval;
-        left->v.uval = pow;
-    }
-
-    return 1;
-}
-
-/* Operation is basic math */
-
-static void __emit_arith(parser_t *parser, binop op, expr_t *left, expr_t *right)
-{
-    BCIns ins;
-    int b = -1;
-    int rc, rb;
-
-    if (__fold_arith(parser, op, left, right))
-        return;
-
-    if (op != OPR_POW) {
-        /* set ins to VV instruction by default */
-        ins = op - OPR_ADD + BC_ADDVV;
-
-        /* discharge rhs, so it may release registers */
-        __toval(parser, right);
-
-        /* If RHS is constant, register it and convert ins into VN form */
-
-        if ((right->type == VKNUM)&&
-                ((rc = vua_bc_newconst(parser, int_tv(right->v.uval))) <= BCMAX_C)) {
-            ins -= (BC_ADDVV - BC_ADDVN);
-
-        /* Otherwise (non constant, or no more C slots) put it into a register
-         * that is now our C part for the VV instruction.
-         */
-
-        } else
-            rc = __toanyreg(parser, right);
-
-        __toval(parser, left);
-
-        /* If LHS is constant, RHS isn't, then reverse the instruction
-         * arguments because ADDVN and ADDNV both have B = var, C = num despite
-         * the differing op
-         */
-
-        if ((left->type == VKNUM) && (right->type != VKNUM) &&
-            ((b = vua_bc_newconst(parser, int_tv(left->v.uval))) <= BCMAX_B)) {
-            rb = rc;
-            rc = b;
-            ins -= (BC_ADDVV - BC_ADDNV);
-        } else
-            rb = __toanyreg(parser, left);
-    }
-
-    __expr_free2(parser, left, right);
-
-    left->v.r.info = __emit(parser, BCINS_ABC(ins, 0, rb, rc));
-    left->type = VRELOCABLE;
-}
-
-static void __emit_comparison(parser_t *parser, binop op, expr_t *left, expr_t *right)
-{
-    BCIns ins;
-    expr_t *tmp;
-    BCReg reg, d;
-
-    __toval(parser, left);
-
-    /* Equality is defined for all basic types */
-    if (op == OPR_EQ || op == OPR_NE) {
-        /* Similar to arith, default to value equivalence */
-        if (op == OPR_EQ)
-            ins = BC_ISEQV;
-        else
-            ins = BC_ISNEV;
-
-        /* Similar to arith, constants must be second argument */
-        if (left->type <= VKLAST) {
-            tmp = left;
-            left = right;
-            right = tmp;
-        }
-
-        /* Get LHS into a register */
-        reg = __toanyreg(parser, left);
-
-        d = BCBAD_CONST;
-        if (right->type <= VKPRI) {
-            d = vua_bc_newconst(parser, right->type);
-            ins = BCINS_AD(ins + (BC_ISEQP-BC_ISEQV), reg, d);
-        } else if (right->type == VKSTR) {
-            d = vua_bc_newconst(parser, right->v.val);
-            ins = BCINS_AD(ins + (BC_ISEQS-BC_ISEQV), reg, d);
-        } else if (right->type == VKNUM) {
-            d = vua_bc_newconst(parser, int_tv(right->v.uval));
-            ins = BCINS_AD(ins + (BC_ISEQN-BC_ISEQV), reg, d);
-        }
-
-        /* If we ran out of slots, or right is not an immediate value */
-
-        if (d >= BCMAX_D) {
-            d = __toanyreg(parser, right);
-            ins = BCINS_AD(bc_op(ins), reg, d);
-        }
-
-    /* Other comparisons only for numbers */
-    } else {
-        ins = op - (OPR_LT + BC_ISLT);
-        d = __toanyreg(parser, right);
-        reg = __toanyreg(parser, left);
-        ins  = BCINS_AD(ins, reg, d);
-
-        /* TODO: LJ converts from GT/GE to LT/LE phrasing here not sure why if
-         * we have to have separate ops anyway. Could potentially remove ops
-         * and handle re-phrasing here, since we're not doing float comparison.
-         */
-    }
-
-    __expr_free2(parser, left, right);
-
-    __emit(parser, ins);
-    left->v.r.info = __emit_jmp(parser);
-    left->type = VJMP;
-}
-
-/* Emit the RHS of a binary operation */
-
-void vua_bc_emit_binop(parser_t *parser, binop op, expr_t *left, expr_t *right)
-{
-    BCIns ins;
-
-    if (op <= OPR_POW)
-        __emit_arith(parser, op, left, right);
-    else if (op == OPR_AND) {
-        vua_bc_discharge(parser, right);
-        vua_bc_jmp_append(parser, &right->false_list, left->false_list);
-        *left = *right;
-    } else if (op == OPR_OR) {
-        vua_bc_discharge(parser, right);
-        vua_bc_jmp_append(parser, &right->true_list, left->true_list);
-        *left = *right;
-    } else if (op == OPR_CONCAT) {
-        __toval(parser, right);
-
-        /* Concat is right associative, so detect if right is a relocable CAT
-         * instruction and attempt to expand it, instead of emitting a new one
-         *
-         * right->v.r.info is guaranteed to be left->v.r.info - 1 because in
-         * emit_binop_left we emit to next reg, instead of any reg.
-         */
-
-        if (right->type == VRELOCABLE && bc_op(*bcptr(parser, right)) == BC_CAT) {
-            __expr_free(parser, left);
-            setbc_b(bcptr(parser, right), left->v.r.info);
-            left->v.r.info = right->v.r.info;
-        } else {
-            vua_bc_tonextreg(parser, right);
-            __expr_free(parser, right);
-            __expr_free(parser, left);
-            ins = BCINS_ABC(BC_CAT, 0, left->v.r.info, right->v.r.info);
-            left->v.r.info = __emit(parser, ins);
-        }
-
-        left->type = VRELOCABLE;
-
-    } else
-        __emit_comparison(parser, op, left, right);
-}
-
-/* Invert a test instruction. */
-
-static void __invertcond(parser_t *parser, expr_t *expr)
-{
-    BCIns *ip = &parser->func->bcbase[expr->v.r.info - 1].ins;
-    setbc_op(ip, bc_op(*ip)^1);
-}
-
-void vua_bc_emit_unop(parser_t *parser, BCIns op, expr_t *expr)
-{
-    BCPos tmp;
-
-    if (op == BC_NOT) {
-        /* Invert the jump lists */
-        tmp = expr->true_list;
-        expr->true_list = expr->false_list;
-        expr->false_list = tmp;
-
-        /* Any value return by jumps here are now unreachable. */
-
-        __jmp_dropval(parser, expr->true_list);
-        __jmp_dropval(parser, expr->false_list);
-
-        vua_bc_discharge(parser, expr);
-
-        /* Constants can be resolved immediately */
-
-        if ((expr->type == VKNIL) || (expr->type == VKFALSE)) {
-            expr->type = VKTRUE;
-            return;
-        } else if (expr->type <= VKLAST) {
-            expr->type = VKFALSE;
-            return;
-        }
-
-        /* Conditionals can be inverted in place */
-
-        if (expr->type == VJMP) {
-            __invertcond(parser, expr);
-            return;
-        }
-
-        /* We can't NOT something that isn't in a register, so go ahead and
-         * discharge the value to a register.
-         */
-
-        if (expr->type == VRELOCABLE) {
-            vua_bc_reg_reserve(parser, 1);
-            setbc_a(bcptr(parser, expr), parser->func->freereg - 1);
-            expr->v.r.info = parser->func->freereg - 1;
-            expr->type = VNONRELOC;
-        }
-
-    /* TODO: UNM, LEN case */
-    } else {
-
-    }
-
-    __expr_free(parser, expr);
-
-    expr->v.r.info = __emit(parser, BCINS_AD(op, 0, expr->v.r.info));
-    expr->type = VRELOCABLE;
-}
-
-/* JUMPS
- *
- * Conditional expressions produce chains of jmp instructions
- *
- * The trick is that we start the conditional, we don't know if there's a
- * forthcoming elseif/else or where the end of the block is going to be
- * so we track the locations of all of the jump instructions in a chain
- * and then actually set their targets later.
- *
- * Since we don't actually keep the expression information around after we've
- * emitted the relevant bytecode, LuaJIT cleverly encodes the list directly
- * into the instructions, taking advantage of the fact that jumps are meant to
- * point to other bytecode instructions anyway.
- *
- * So, for a conditional like
- *
- * if a then                <-- jmp if not a to elseif b
- *  ...                     <-- jmp to end
- * elseif b then            <-- jmp if not b to else
- *  ...                     <-- jmp to end
- * else
- *  ...
- * end
- *
- * For simple conditionals, parsing then outputs a jmp with no target to be
- * executed if the conditional is false. Then with elseif/else a jump is
- * emitted with no target to skip to the end of the whole structure, and
- * another jump is emitted after the conditional to be resolved on else / end.
- *
- * If we were only going to accept simple conditions, that would be fine.
- * However, things get more complex when you're chaining conditionals with and,
- * or, or not. For example
- *
- * if (a and b) or (c and d) then ...  end
- *
- * The expression is parsed piecemeal. The first expression (a and b) resolves
- * into multiple jumps. If not a, then jump to the second conditional, if b,
- * then jump to the block. So the overall expression has two types of jump:
- * false jumps, which need to be updated to point to the beginning of the next
- * conditional, and true jumps, which need to be updated to skip all remaining
- * conditionals and get to the actual block of code.
- *
- * All of these jump list jumps are resolved to actually point to bytecode
- * locations after those locations are actually emitted.
- *
- * This split is also useful when parsing "not" in conditionals because we can
- * just switch the true and false lists and everything will work out.
- *
- * VALUE JUMPS
- *
- * Another Lua-ism is that boolean operations return values, instead of being
- * resolved into 0 or 1 like C. I'm not particularly a fan of this behavior and
- * at first glance it appears that it complicates the bytecode by necessitating
- * test and copy operations that can later be resolved to just test operations if
- * the return value isn't used after the conditional.
- *
- * However, this ends up being more efficient because the value is already in a
- * register after the test instruction, and we don't need to end up doing any
- * extra work before returning the value.
- *
- * We still end up having to deal with true / false resolution, but only in the
- * cases like "not (a and b)" where the value gets explicitly converted into a
- * boolean.
- */
-
-/* Iterate from one jmp to the next in bytecode */
-
-static BCPos __jmp_next(parser_t *parser, BCPos pc)
-{
-    BCPos delta = bc_j(parser->func->bcbase[pc].ins);
-
-    if (delta == NO_JMP)
-        return NO_JMP;
-
-    return (pc + 1) + delta;
-}
-
-/* Update a single jmp instruction */
-
-static void __jmp_patchins(parser_t *parser, BCPos pos, BCPos dest)
-{
-    BCIns *ins = &parser->func->bcbase[pos].ins;
-    BCPos offset = dest - (pos + 1) + BCBIAS_J;
-
-    assert(offset <= BCMAX_D);
-
-    setbc_d(ins, offset);
-}
-
-/* Update a single test instruction to copy to reg, or convert it into just a
- * test instruction.
- */
-
-static int __jmp_patchtest(parser_t *parser, BCPos pos, BCReg reg)
-{
-   BCIns *ins;
-   BCOp op;
-
-   if (pos)
-       pos--;
-
-   ins = &parser->func->bcbase[pos].ins;
-   op = bc_op(*ins);
-
-   if ((op == BC_ISTC) || (op == BC_ISFC)) {
-       if (reg != NO_REG && reg != bc_d(*ins))
-           setbc_a(ins, reg);
-       else {
-           setbc_op(ins, op + (BC_IST-BC_ISTC));
-           setbc_a(ins, 0);
-       }
-
-       return 1;
-   }
-
-   return 0;
-}
-
-/* Update a series of jmps and their previous test instructions based on
- * copying the value out to reg and jumping to vtarget if there's a value, and
- * dtarget if not.
- */
-
-static void __jmp_patchval(parser_t *parser, BCPos list, BCPos vtarget,
-        BCReg reg, BCPos dtarget)
-{
-    BCPos next;
-
-    while (list != NO_JMP) {
-        next = __jmp_next(parser, list);
-
-        if (__jmp_patchtest(parser, list, reg))
-            __jmp_patchins(parser, list, vtarget);
-        else
-            __jmp_patchins(parser, list, dtarget);
-
-        list = next;
-    }
-}
-
-/* Convert a series of jmp test copies into tests because their
- * value is no longer accessible as ouput
- */
-
-static void __jmp_dropval(parser_t *parser, BCPos list)
-{
-    while (list != NO_JMP) {
-        __jmp_patchtest(parser, list, NO_REG);
-        list = __jmp_next(parser, list);
-    }
-}
-
-/* Return whether a jump list includes any no-value tests */
-
-static int __jmp_novalue(parser_t *parser, BCPos list)
-{
-    BCIns ins;
-
-    while (list != NO_JMP) {
-        if (list)
-            ins = parser->func->bcbase[list - 1].ins;
-        else
-            ins = parser->func->bcbase[list].ins;
-
-        if (!(bc_op(ins) == BC_ISTC || bc_op(ins) == BC_ISFC || bc_a(ins) == NO_REG))
-            return 1;
-
-        list = __jmp_next(parser, list);
-    }
-
-    return 0;
-}
-
-void vua_bc_jmp_append(parser_t *parser, BCPos *list, BCPos pc)
-{
-    BCPos cur, next;
-
-    if (pc == NO_JMP)
-        return;
-
-    if (*list == NO_JMP) {
-        *list = pc;
-        return;
-    }
-
-    for (cur = *list; (next = __jmp_next(parser, cur)) != NO_JMP; cur = next);
-
-    __jmp_patchins(parser, cur, pc);
-}
-
-void vua_bc_jmp_here(parser_t *parser, BCPos pos)
-{
-    parser->func->last_target = parser->func->pc;
-    vua_bc_jmp_append(parser, &parser->func->jpc, pos);
-}
-
-BCPos __emit_jmp(parser_t *parser)
-{
-    BCIns ins = BCINS_AJ(BC_JMP, parser->func->freereg, NO_JMP);
-    BCPos pc = __emit(parser, ins);
-
-    parser->func->jpc = NO_JMP;
-
-    vua_bc_jmp_append(parser, &pc, parser->func->jpc);
-
-    return pc;
-}
-
-BCPos vua_bc_emit_branch(parser_t *parser, expr_t *expr, int cond)
-{
-    BCIns ins;
-    BCPos ret;
-
-    /* TODO if branching on NOT'd expression, replace NOT with inverted
-     * conditional (i.e. NOT 0 IST 0 -> ISF 0) if it's relocable.
-     */
-
-    if (expr->type != VNONRELOC) {
-        vua_bc_reg_reserve(parser, 1);
-        __toreg_nobranch(parser, expr, parser->func->freereg - 1);
-    }
-
-    ins = BCINS_AD(cond ? BC_ISTC : BC_ISFC, NO_REG, expr->v.r.info);
-
-    __emit(parser, ins);
-
-    ret = __emit_jmp(parser);
-
-    __expr_free(parser, expr);
-
-    return ret;
-}
-
-void vua_bc_emit_branch_t(parser_t *parser, expr_t *expr)
-{
-    BCPos pc;
-
-    vua_bc_discharge(parser, expr);
-
-    if (expr->type == VKSTR || expr->type == VKTRUE ||
-            (expr->type == VKNUM && expr->v.uval != 0))
-        pc = NO_JMP;
-    else if (expr->type == VJMP) {
-        /* Comparison jumps if true by default, for a conditional we want the
-         * exact opposite.*/
-
-        __invertcond(parser, expr);
-        pc = expr->v.r.info;
-    } else
-        pc = vua_bc_emit_branch(parser, expr, 0);
-
-    vua_bc_jmp_append(parser, &expr->false_list, pc);
-    vua_bc_jmp_here(parser, expr->true_list);
-    expr->true_list = NO_JMP;
-}
-
-void vua_bc_emit_branch_f(parser_t *parser, expr_t *expr)
-{
-    BCPos pc;
-
-    vua_bc_discharge(parser, expr);
-
-    if (expr->type == VKNIL || expr->type == VKFALSE ||
-            (expr->type == VKNUM && expr->v.uval == 0))
-        pc = NO_JMP;
-    else if (expr->type == VJMP)
-        pc = expr->v.r.info;
-    else
-        pc = vua_bc_emit_branch(parser, expr, 1);
-
-    vua_bc_jmp_append(parser, &expr->true_list, pc);
-    vua_bc_jmp_here(parser, expr->false_list);
-    expr->false_list = NO_JMP;
-}
-
-BCPos vua_bc_emit_proto(parser_t *parser, vua_proto_t *proto)
-{
-    return __emit(parser, BCINS_AD(BC_FNEW, 0,
-                vua_bc_newconst(parser, proto_tv(proto))));
-}
-
-BCPos vua_bc_emit_func(parser_t *parser)
-{
-    return __emit(parser, BCINS_AD(BC_FUNCV, 0, 0));
-}
-
-void vua_bc_emit_ret(parser_t *parser, int rets, expr_t *list)
-{
-    BCIns ins;
-
-    if (rets == 0)
-        ins = BCINS_AD(BC_RET0, 0, 1);
-    else if (rets == 1)
-        ins = BCINS_AD(BC_RET1, __toanyreg(parser, list), 2);
-    else {
-        vua_bc_tonextreg(parser, list);
-        ins = BCINS_AD(BC_RET, parser->func->nactvar, rets + 1);
-    }
-
-    __emit(parser, ins);
-}
-
-void vua_bc_emit_uclo(parser_t *parser, int nactvar)
-{
-    __emit(parser, BCINS_AJ(BC_UCLO, nactvar, 0));
-}
-
-void vua_bc_fix_ret(parser_t *parser)
-{
-    func_t *func = parser->func;
-    BCIns ins;
-    BCPos offset;
-    int i;
-
-    if ((func->pc <= func->last_target)||
-            (!bc_isret(func->bcbase[func->pc - 1].ins))) {
-        if (func->scope->flags & SCOPE_UPVAL)
-            vua_bc_emit_uclo(parser, 0);
-        vua_bc_emit_ret(parser, 0, NULL);
-    }
-
-    /* If returns were emitted before there was a child prototype, they need to
-     * be fixed. RET ops are replaced by UCLO jumps to equivalent RET
-     * instructions that are appended after the last explicit return.
-     */
-
-    if (!(func->flags & PROTO_FIXUP_RETURN))
-        return;
-
-    for (i = 1; i < func->pc; i++) {
-        ins = func->bcbase[i].ins;
-        switch (bc_op(ins)) {
-            case BC_CALLMT:
-            case BC_CALLT:
-            case BC_RETM:
-            case BC_RET:
-            case BC_RET0:
-            case BC_RET1:
-                /* Copy original ret to end of function */
-                offset = __emit(parser, ins);
-                func->bcbase[offset].line = func->bcbase[i].line;
-
-                /* Convert offset to jmp from UCLO to new ret instruction */
-                offset = ((offset - i) + 1) + BCBIAS_J;
-                assert(offset <= BCMAX_D);
-
-                func->bcbase[i].ins = BCINS_AD(BC_UCLO, 0, offset);
-                break;
-
-            /* If we encounter a UCLO, we're done because it's either in a
-             * child function, or it's after a child function, so subsequent
-             * returns were handled by PROTO_CHILD
-             */
-
-            case BC_UCLO:
-                return;
-            default:
-                break;
-        }
-    }
-}
-
-void vua_bc_emit_call(parser_t *parser, expr_t *f, expr_t *args)
-{
-    BCIns ins;
-    BCPos base = f->v.r.info;
-
-    /* Args = f(a, b, c()) or f (a, b, ...) */
-    if (args->type == VCALL) {
-
-        /* Final arg needs to be adjusted to be multiple return to set MULTRES
-         * correctly so args can be passed on to this call. Multi-return
-         * functions earlier in the arg list potentially have all but their
-         * first return overwritten by subsequent args.
-         */
-
-        setbc_b(bcptr(parser, args), 0);
-
-        ins = BCINS_ABC(BC_CALLM, base, 2, args->v.r.aux - base - 1);
-    } else {
-        if (args->type != VVOID)
-            vua_bc_tonextreg(parser, args);
-        ins = BCINS_ABC(BC_CALL, base, 2, parser->func->freereg - base);
-    }
-
-    f->type = VCALL;
-    f->v.r.info = __emit(parser, ins);
-    f->v.r.aux = base;
-    parser->func->freereg = base + 1;
-}
diff --git a/vua/vua_bc.h b/vua/vua_bc.h
deleted file mode 100644 (file)
index 041175a..0000000
+++ /dev/null
@@ -1,301 +0,0 @@
-/* This was taken directly from LuaJIT's lj_bc.h and modified to suit */
-
-#pragma once
-
-#include "vua_obj.h"
-#include "vua_parse.h"
-
-/* No big endian support as of yet */
-#define ENDIAN_SELECT(le, be) (le)
-
-/*
-** Bytecode instruction format.
-** Copyright (C) 2005-2016 Mike Pall. See Copyright Notice in luajit.h
-*/
-
-/* Bytecode instruction format, 32 bit wide, fields of 8 or 16 bit:
-**
-** +----+----+----+----+
-** | B  | C  | A  | OP | Format ABC
-** +----+----+----+----+
-** |    D    | A  | OP | Format AD
-** +--------------------
-** MSB               LSB
-**
-** In-memory instructions are always stored in host byte order.
-*/
-
-/* Operand ranges and related constants. */
-#define BCMAX_A                0xff
-#define BCMAX_B                0xff
-#define BCMAX_C                0xff
-#define BCMAX_D                0xffff
-#define BCBAD_CONST    0x10000
-#define BCBIAS_J       0x8000
-#define NO_REG         BCMAX_A
-#define NO_JMP         (~(BCPos)0)
-
-/* Macros to get instruction fields. */
-#define bc_op(i)       ((BCOp)((i)&0xff))
-#define bc_a(i)                ((BCReg)(((i)>>8)&0xff))
-#define bc_b(i)                ((BCReg)((i)>>24))
-#define bc_c(i)                ((BCReg)(((i)>>16)&0xff))
-#define bc_d(i)                ((BCReg)((i)>>16))
-#define bc_j(i)                (bc_d(i)-BCBIAS_J)
-
-/* Macros to set instruction fields. */
-#define setbc_byte(p, x, ofs) \
-  ((u8 *)(p))[ENDIAN_SELECT(ofs, 3-ofs)] = (u8)(x)
-#define setbc_op(p, x) setbc_byte(p, (x), 0)
-#define setbc_a(p, x)  setbc_byte(p, (x), 1)
-#define setbc_b(p, x)  setbc_byte(p, (x), 3)
-#define setbc_c(p, x)  setbc_byte(p, (x), 2)
-#define setbc_d(p, x) \
-  ((u16 *)(p))[ENDIAN_SELECT(1, 0)] = (u16)(x)
-#define setbc_j(p, x)  setbc_d(p, (BCPos)((s32)(x)+BCBIAS_J))
-
-/* Macros to compose instructions. */
-#define BCINS_ABC(o, a, b, c) \
-  (((BCIns)(o))|((BCIns)(a)<<8)|((BCIns)(b)<<24)|((BCIns)(c)<<16))
-#define BCINS_AD(o, a, d) \
-  (((BCIns)(o))|((BCIns)(a)<<8)|((BCIns)(d)<<16))
-#define BCINS_AJ(o, a, j)      BCINS_AD(o, a, (BCPos)((s32)(j)+BCBIAS_J))
-
-/* Bytecode instruction definition. Order matters, see below.
-**
-** (name, filler, Amode, Bmode, Cmode or Dmode, metamethod)
-**
-** The opcode name suffixes specify the type for RB/RC or RD:
-** V = variable slot
-** S = string const
-** N = number const
-** P = primitive type (~itype)
-** B = unsigned byte literal
-** M = multiple args/results
-*/
-#define BCDEF(_) \
-  /* Comparison ops. ORDER OPR. */ \
-  _(ISLT,      var,    ___,    var,    lt) \
-  _(ISGE,      var,    ___,    var,    lt) \
-  _(ISLE,      var,    ___,    var,    le) \
-  _(ISGT,      var,    ___,    var,    le) \
-  \
-  _(ISEQV,     var,    ___,    var,    eq) \
-  _(ISNEV,     var,    ___,    var,    eq) \
-  _(ISEQS,     var,    ___,    str,    eq) \
-  _(ISNES,     var,    ___,    str,    eq) \
-  _(ISEQN,     var,    ___,    num,    eq) \
-  _(ISNEN,     var,    ___,    num,    eq) \
-  _(ISEQP,     var,    ___,    pri,    eq) \
-  _(ISNEP,     var,    ___,    pri,    eq) \
-  \
-  /* Unary test and copy ops. */ \
-  _(ISTC,      dst,    ___,    var,    ___) \
-  _(ISFC,      dst,    ___,    var,    ___) \
-  _(IST,       ___,    ___,    var,    ___) \
-  _(ISF,       ___,    ___,    var,    ___) \
-  \
-  /* Unary ops. */ \
-  _(MOV,       dst,    ___,    var,    ___) \
-  _(NOT,       dst,    ___,    var,    ___) \
-  _(UNM,       dst,    ___,    var,    unm) \
-  _(LEN,       dst,    ___,    var,    len) \
-  \
-  /* Binary ops. ORDER OPR. VV last, POW must be next. */ \
-  _(ADDVN,     dst,    var,    num,    add) \
-  _(SUBVN,     dst,    var,    num,    sub) \
-  _(MULVN,     dst,    var,    num,    mul) \
-  _(DIVVN,     dst,    var,    num,    div) \
-  _(MODVN,     dst,    var,    num,    mod) \
-  \
-  _(ADDNV,     dst,    var,    num,    add) \
-  _(SUBNV,     dst,    var,    num,    sub) \
-  _(MULNV,     dst,    var,    num,    mul) \
-  _(DIVNV,     dst,    var,    num,    div) \
-  _(MODNV,     dst,    var,    num,    mod) \
-  \
-  _(ADDVV,     dst,    var,    var,    add) \
-  _(SUBVV,     dst,    var,    var,    sub) \
-  _(MULVV,     dst,    var,    var,    mul) \
-  _(DIVVV,     dst,    var,    var,    div) \
-  _(MODVV,     dst,    var,    var,    mod) \
-  \
-  _(POW,       dst,    var,    var,    pow) \
-  _(CAT,       dst,    rbase,  rbase,  concat) \
-  \
-  /* Constant ops. */ \
-  _(KSTR,      dst,    ___,    str,    ___) \
-  _(KCDATA,    dst,    ___,    cdata,  ___) \
-  _(KSHORT,    dst,    ___,    lits,   ___) \
-  _(KNUM,      dst,    ___,    num,    ___) \
-  _(KPRI,      dst,    ___,    pri,    ___) \
-  _(KNIL,      base,   ___,    base,   ___) \
-  \
-  /* Upvalue and function ops. */ \
-  _(UGET,      dst,    ___,    uv,     ___) \
-  _(USETV,     uv,     ___,    var,    ___) \
-  _(USETS,     uv,     ___,    str,    ___) \
-  _(USETN,     uv,     ___,    num,    ___) \
-  _(USETP,     uv,     ___,    pri,    ___) \
-  _(UCLO,      rbase,  ___,    jump,   ___) \
-  _(FNEW,      dst,    ___,    func,   gc) \
-  \
-  /* Table ops. */ \
-  _(TNEW,      dst,    ___,    lit,    gc) \
-  _(TDUP,      dst,    ___,    tab,    gc) \
-  _(GGET,      dst,    ___,    str,    index) \
-  _(GSET,      var,    ___,    str,    newindex) \
-  _(TGETV,     dst,    var,    var,    index) \
-  _(TGETS,     dst,    var,    str,    index) \
-  _(TGETB,     dst,    var,    lit,    index) \
-  _(TSETV,     var,    var,    var,    newindex) \
-  _(TSETS,     var,    var,    str,    newindex) \
-  _(TSETB,     var,    var,    lit,    newindex) \
-  _(TSETM,     base,   ___,    num,    newindex) \
-  \
-  /* Calls and vararg handling. T = tail call. */ \
-  _(CALLM,     base,   lit,    lit,    call) \
-  _(CALL,      base,   lit,    lit,    call) \
-  _(CALLMT,    base,   ___,    lit,    call) \
-  _(CALLT,     base,   ___,    lit,    call) \
-  _(ITERC,     base,   lit,    lit,    call) \
-  _(ITERN,     base,   lit,    lit,    call) \
-  _(VARG,      base,   lit,    lit,    ___) \
-  _(ISNEXT,    base,   ___,    jump,   ___) \
-  \
-  /* Returns. */ \
-  _(RETM,      base,   ___,    lit,    ___) \
-  _(RET,       rbase,  ___,    lit,    ___) \
-  _(RET0,      rbase,  ___,    lit,    ___) \
-  _(RET1,      rbase,  ___,    lit,    ___) \
-  \
-  /* Loops and branches. I/J = interp/JIT, I/C/L = init/call/loop. */ \
-  _(FORI,      base,   ___,    jump,   ___) \
-  _(JFORI,     base,   ___,    jump,   ___) \
-  \
-  _(FORL,      base,   ___,    jump,   ___) \
-  _(IFORL,     base,   ___,    jump,   ___) \
-  _(JFORL,     base,   ___,    lit,    ___) \
-  \
-  _(ITERL,     base,   ___,    jump,   ___) \
-  _(IITERL,    base,   ___,    jump,   ___) \
-  _(JITERL,    base,   ___,    lit,    ___) \
-  \
-  _(LOOP,      rbase,  ___,    jump,   ___) \
-  _(ILOOP,     rbase,  ___,    jump,   ___) \
-  _(JLOOP,     rbase,  ___,    lit,    ___) \
-  \
-  _(JMP,       rbase,  ___,    jump,   ___) \
-  \
-  /* Function headers. I/J = interp/JIT, F/V/C = fixarg/vararg/C func. */ \
-  _(FUNCF,     rbase,  ___,    ___,    ___) \
-  _(IFUNCF,    rbase,  ___,    ___,    ___) \
-  _(JFUNCF,    rbase,  ___,    lit,    ___) \
-  _(FUNCV,     rbase,  ___,    ___,    ___) \
-  _(IFUNCV,    rbase,  ___,    ___,    ___) \
-  _(JFUNCV,    rbase,  ___,    lit,    ___) \
-  _(FUNCC,     rbase,  ___,    ___,    ___) \
-  _(FUNCCW,    rbase,  ___,    ___,    ___)
-
-/* Bytecode opcode numbers. */
-typedef enum {
-#define BCENUM(name, ma, mb, mc, mt)   BC_##name,
-BCDEF(BCENUM)
-#undef BCENUM
-  BC__MAX
-} BCOp;
-
-/* Ensure that we can't build if we violate any of the relationships we rely on
- * in the bytecode generator to quickly output instructions
- */
-
-STATIC_ASSERT((int)BC_ISEQV+1 == (int)BC_ISNEV);
-STATIC_ASSERT(((int)BC_ISEQV^1) == (int)BC_ISNEV);
-STATIC_ASSERT(((int)BC_ISEQS^1) == (int)BC_ISNES);
-STATIC_ASSERT(((int)BC_ISEQN^1) == (int)BC_ISNEN);
-STATIC_ASSERT(((int)BC_ISEQP^1) == (int)BC_ISNEP);
-STATIC_ASSERT(((int)BC_ISLT^1) == (int)BC_ISGE);
-STATIC_ASSERT(((int)BC_ISLE^1) == (int)BC_ISGT);
-STATIC_ASSERT(((int)BC_ISLT^3) == (int)BC_ISGT);
-STATIC_ASSERT((int)BC_IST-(int)BC_ISTC == (int)BC_ISF-(int)BC_ISFC);
-STATIC_ASSERT((int)BC_CALLT-(int)BC_CALL == (int)BC_CALLMT-(int)BC_CALLM);
-STATIC_ASSERT((int)BC_CALLMT + 1 == (int)BC_CALLT);
-STATIC_ASSERT((int)BC_RETM + 1 == (int)BC_RET);
-STATIC_ASSERT((int)BC_FORL + 1 == (int)BC_IFORL);
-STATIC_ASSERT((int)BC_FORL + 2 == (int)BC_JFORL);
-STATIC_ASSERT((int)BC_ITERL + 1 == (int)BC_IITERL);
-STATIC_ASSERT((int)BC_ITERL + 2 == (int)BC_JITERL);
-STATIC_ASSERT((int)BC_LOOP + 1 == (int)BC_ILOOP);
-STATIC_ASSERT((int)BC_LOOP + 2 == (int)BC_JLOOP);
-STATIC_ASSERT((int)BC_FUNCF + 1 == (int)BC_IFUNCF);
-STATIC_ASSERT((int)BC_FUNCF + 2 == (int)BC_JFUNCF);
-STATIC_ASSERT((int)BC_FUNCV + 1 == (int)BC_IFUNCV);
-STATIC_ASSERT((int)BC_FUNCV + 2 == (int)BC_JFUNCV);
-
-STATIC_ASSERT((int)BC_ISGE-(int)BC_ISLT == (int)OPR_GE-(int)OPR_LT);
-STATIC_ASSERT((int)BC_ISLE-(int)BC_ISLT == (int)OPR_LE-(int)OPR_LT);
-STATIC_ASSERT((int)BC_ISGT-(int)BC_ISLT == (int)OPR_GT-(int)OPR_LT);
-STATIC_ASSERT((int)BC_SUBVV-(int)BC_ADDVV == (int)OPR_SUB-(int)OPR_ADD);
-STATIC_ASSERT((int)BC_MULVV-(int)BC_ADDVV == (int)OPR_MUL-(int)OPR_ADD);
-STATIC_ASSERT((int)BC_DIVVV-(int)BC_ADDVV == (int)OPR_DIV-(int)OPR_ADD);
-STATIC_ASSERT((int)BC_MODVV-(int)BC_ADDVV == (int)OPR_MOD-(int)OPR_ADD);
-
-/* Stack slots used by FORI/FORL, relative to operand A. */
-enum {
-  FORL_IDX, FORL_STOP, FORL_STEP, FORL_EXT
-};
-
-/* Bytecode operand modes. ORDER BCMode */
-typedef enum {
-  BCMnone, BCMdst, BCMbase, BCMvar, BCMrbase, BCMuv,  /* Mode A must be <= 7 */
-  BCMlit, BCMlits, BCMpri, BCMnum, BCMstr, BCMtab, BCMfunc, BCMjump, BCMcdata,
-  BCM_max
-} BCMode;
-#define BCM___         BCMnone
-
-#define bcmode_a(op)   ((BCMode)(vua_bc_mode[op] & 7))
-#define bcmode_b(op)   ((BCMode)((vua_bc_mode[op]>>3) & 15))
-#define bcmode_c(op)   ((BCMode)((vua_bc_mode[op]>>7) & 15))
-#define bcmode_d(op)   bcmode_c(op)
-#define bcmode_hasd(op)        ((vua_bc_mode[op] & (15<<3)) == (BCMnone<<3))
-#define bcmode_mm(op)  ((MMS)(vua_bc_mode[op]>>11))
-
-#define BCMODE(name, ma, mb, mc, mm) \
-  (BCM##ma|(BCM##mb<<3)|(BCM##mc<<7)|(MM_##mm<<11)),
-
-static const u16 vua_bc_mode[] = {
-BCDEF(BCMODE)
-};
-
-#define BCMODE_FF      0
-
-static inline int bc_isret(BCOp op)
-{
-  return (op == BC_RETM || op == BC_RET || op == BC_RET0 || op == BC_RET1);
-}
-
-void vua_bc_discharge(parser_t *parser, expr_t *expr);
-BCReg vua_bc_tonextreg(parser_t *parser, expr_t *expr);
-
-void vua_bc_reg_reserve(parser_t *parser, int num);
-u32 vua_bc_newconst(parser_t *parser, vua_tv_t val);
-
-void vua_bc_emit_store(parser_t *parser, expr_t *var, expr_t *expr);
-void vua_bc_emit_binop_left(parser_t *parser, binop op, expr_t *expr);
-void vua_bc_emit_binop(parser_t *parser, binop op, expr_t *left, expr_t *right);
-void vua_bc_emit_unop(parser_t *parser, BCIns op, expr_t *expr);
-void vua_bc_emit_branch_t(parser_t *parser, expr_t *expr);
-void vua_bc_emit_branch_f(parser_t *parser, expr_t *expr);
-
-BCPos vua_bc_emit_proto(parser_t *parser, vua_proto_t *proto);
-BCPos vua_bc_emit_func(parser_t *parser);
-void vua_bc_emit_ret(parser_t *parser, int rets, expr_t *list);
-void vua_bc_emit_uclo(parser_t *parser, int nactvar);
-void vua_bc_emit_call(parser_t *parser, expr_t *f, expr_t *args);
-
-void vua_bc_fix_ret(parser_t *parser);
-
-void vua_bc_jmp_append(parser_t *parser, BCPos *list, BCPos pc);
-void vua_bc_jmp_here(parser_t *parser, BCPos pos);
-
-void vua_bc_dump(vua_proto_t *proto);
diff --git a/vua/vua_bc_dump.c b/vua/vua_bc_dump.c
deleted file mode 100644 (file)
index e0d2c87..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/* vim: set ts=4 sw=4 sts=4 et : */
-
-#include <kernel.h>
-
-#include "vua_bc.h"
-
-#define BCNAME(name, a, b, c, t)    #name,
-
-const char *bc_names[] = {
-BCDEF(BCNAME)
-};
-
-static void __print_hint(vua_proto_t *proto, s32 part, BCMode mode)
-{
-    s32 jmp;
-    u16 uv;
-
-    if (mode == BCMnum) {
-        printk("%lx ", tv_int(proto->k[part]));
-    } else if (mode == BCMstr) {
-        printk("%S ", tv_str(proto->k[~part]));
-    } else if (mode == BCMpri) {
-        if (part == VKNIL)
-            printk("nil ");
-        else if (part == VKFALSE)
-            printk("false ");
-        else if (part == VKTRUE)
-            printk("true ");
-    } else if (mode == BCMjump) {
-        jmp = part - BCBIAS_J;
-        if (jmp < 0)
-            printk("=> -%d ", (-1 * jmp));
-        else
-            printk("=> +%d ", jmp);
-    } else if (mode == BCMuv) {
-        uv = proto->uv[part];
-        printk("%d ", uv & 0xF);
-        if (uv & UV_LOCAL)
-            printk("local ");
-        if (uv & UV_IMMUTABLE)
-            printk("immutable ");
-    }
-}
-
-void vua_bc_dump(vua_proto_t *proto)
-{
-    BCIns *bc = (BCIns *) (((u64) proto) + sizeof(vua_proto_t));
-    int i, op, a, b, c, d;
-
-    for (i = 0; i < proto->size_bc; i++) {
-        op = bc_op(bc[i]);
-
-        if (op == BC_FNEW) {
-            printk("\n");
-            d = ~bc_d(bc[i]);
-            vua_bc_dump(tv_proto(proto->k[d]));
-            printk("\n");
-        }
-
-        printk("%3d : %s\t", i, bc_names[op]);
-
-        a = bc_a(bc[i]);
-        printk("%d\t", a);
-
-        if (bcmode_hasd(op)) {
-            d = bc_d(bc[i]);
-            printk("%d\t\t", d);
-
-            __print_hint(proto, a, bcmode_a(op));
-            __print_hint(proto, d, bcmode_d(op));
-        } else {
-            b = bc_b(bc[i]);
-            c = bc_c(bc[i]);
-            printk("%d\t%d\t", b, c);
-
-            __print_hint(proto, a, bcmode_a(op));
-            __print_hint(proto, b, bcmode_b(op));
-            __print_hint(proto, c, bcmode_c(op));
-        }
-
-        printk("\n");
-    }
-}
diff --git a/vua/vua_hash.c b/vua/vua_hash.c
deleted file mode 100644 (file)
index 61ca809..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/* vim: set ts=4 sw=4 sts=4 et : */
-
-#include <kernel.h>
-
-#include "vua_obj.h"
-
-/* This is an implementation of Murmur3 by Austin Appleby, which is public
- * domain. This has been modified to use our types and conform to our style, as
- * well as eliminating some unnecessary macros and deal with our objects.
- *
- * Original Github: https://github.com/aappleby/smhasher
- */
-
-/* LuaJIT uses lookup3, but Murmur3 is fast and has good distribution */
-
-#define        FORCE_INLINE inline __attribute__((always_inline))
-
-/* This could be done in inline assembly with rol, but for now this is CPU
- * agnostic */
-
-static inline u32 __rotl32 ( u32 x, s32 r )
-{
-    return (x << r) | (x >> (32 - r));
-}
-
-static FORCE_INLINE u32 __fmix32 ( u32 h )
-{
-    h ^= h >> 16;
-    h *= 0x85ebca6b;
-    h ^= h >> 13;
-    h *= 0xc2b2ae35;
-    h ^= h >> 16;
-
-    return h;
-}
-
-/* I've broken these up into chunks because at some point it may be necessary
- * to hash non-contiguous data and a custom iterator would be written to feed
- * data to the hash function in the correct order.
- */
-
-#define HASH_FUNC_HEADER(x)                     \
-    const u32 nblocks = x / sizeof(u32);        \
-    const u32 c1 = 0xcc9e2d51;                  \
-    const u32 c2 = 0x1b873593;                  \
-    const u8 *tail;                             \
-    u32 h1 = seed;                              \
-    u32 k1;
-
-#define HASH_K1                 \
-        k1 *= c1;               \
-        k1 = __rotl32(k1,15);   \
-        k1 *= c2;               \
-        h1 ^= k1;               \
-        h1 = __rotl32(h1,13);   \
-        h1 = h1*5+0xe6546b64;
-
-#define HASH_FUNC_FOOTER(x)                                         \
-    k1 = 0;                                                         \
-    switch(x & 3)                                                   \
-    {                                                               \
-        case 3: k1 ^= tail[2] << 16;                                \
-        case 2: k1 ^= tail[1] << 8;                                 \
-        case 1: k1 ^= tail[0];                                      \
-                k1 *= c1; k1 = __rotl32(k1,15); k1 *= c2; h1 ^= k1; \
-    };                                                              \
-    h1 ^= x ;                                                       \
-    h1 = __fmix32(h1);                                              \
-    return h1;
-
-u32 vua_hash_data(void *key, u32 len, u32 seed)
-{
-    HASH_FUNC_HEADER(len);
-
-    const u8 *data = (const u8 *)key;
-    const u32 * blocks = (const u32 *)(data + nblocks*sizeof(u32));
-    tail = (u8 *) blocks;
-
-    for(int i = -nblocks; i; i++)
-    {
-        k1 = blocks[i];
-
-        HASH_K1;
-    }
-
-    HASH_FUNC_FOOTER(len);
-}
-
-u32 vua_hash_int(u64 val, u32 seed)
-{
-    return vua_hash_data(&val, sizeof(u64) / sizeof(u32), seed);
-}
-
-u32 vua_hash_str(vua_str_t *string, u32 seed)
-{
-    return vua_hash_data(string->data, string->len, seed);
-}
diff --git a/vua/vua_hash.h b/vua/vua_hash.h
deleted file mode 100644 (file)
index b17ae4b..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/* vim: set ts=4 sw=4 sts=4 et : */
-
-#pragma once
-
-#include "vua_obj.h"
-
-u32 vua_hash_data(void *key, u32 len, u32 seed);
-u32 vua_hash_int(u64 val, u32 seed);
-u32 vua_hash_str(vua_str_t *string, u32 seed);
diff --git a/vua/vua_lex.c b/vua/vua_lex.c
deleted file mode 100644 (file)
index ad63b46..0000000
+++ /dev/null
@@ -1,442 +0,0 @@
-/* vim: set ts=4 sw=4 sts=4 et : */
-
-#include <kernel.h>
-#include <objcache.h>
-
-#include "vua_obj.h"
-#include "vua_hash.h"
-#include "vua_lex.h"
-#include "vua_bc.h"
-
-#define TOK_NAME(a)  #a,
-
-static const char *tok_names[] = {
-    TOK_DEF(TOK_NAME)
-};
-
-static void __save(lexer_state_t *lexer)
-{
-    vua_str_append(lexer->stringbuf, lexer->current);
-}
-
-static void __next(lexer_state_t *lexer)
-{
-    if (lexer->len) {
-        lexer->current = lexer->data[0];
-        lexer->len--;
-        lexer->col++;
-        lexer->data++;
-    } else
-        lexer->current = EOF;
-}
-
-#define save(l) __save(l)
-#define next(l) __next(l)
-#define save_next(l) (__save(l), __next(l))
-
-#define cond_save_next(c, l)\
-{\
-    if (c)\
-        save(l);\
-    next(l);\
-}
-#define lex_error(l, e)\
-{\
-    l->error = e;\
-    return;\
-}
-
-static void __nextline(lexer_state_t *lexer)
-{
-    lexer->nl_pending = 1;
-}
-
-static void __lex_string(lexer_state_t *lexer, int comment)
-{
-    char delimiter = lexer->current;
-
-    /* Discard the opening delimiter */
-    next(lexer);
-
-    while (comment || lexer->current != delimiter) {
-        switch (lexer->current) {
-            case EOF:
-            case '\n':
-            case '\r':
-                if (comment)
-                    return;
-                lex_error(lexer, "Expected end of string, not end of line");
-            case '\\':
-                /* Condense escapes into single char values */
-                next(lexer);
-                switch(lexer->current) {
-                    case 'a':
-                        lexer->current = '\a';
-                        break;
-                    case 'b':
-                        lexer->current = '\b';
-                        break;
-                    case 'f':
-                        lexer->current = '\f';
-                        break;
-                    case 'n':
-                        lexer->current = '\n';
-                        break;
-                    case 'r':
-                        lexer->current = '\r';
-                        break;
-                    case 't':
-                        lexer->current = '\t';
-                        break;
-                    case 'v':
-                        lexer->current = '\v';
-                        break;
-                    case 'x':
-                        /* TODO: Hex escapes */
-                        break;
-                    case 'z':
-                        /* Absorb following whitespace */
-                        next(lexer);
-                        while (vua_char_isspace(lexer->current)) {
-                            if (lexer->current == '\n' || lexer->current == '\r')
-                                __nextline(lexer);
-                            next(lexer);
-                        }
-                        continue; //Nothing to add to current buffer
-                    case '\n':
-                    case '\r':
-                        lexer->current = '\n';
-                        __nextline(lexer);
-                        break;
-                    case EOF:
-                        lex_error(lexer, "Expected end of string, not end of stream");
-                    /* TODO: Decimal escapes */
-                }
-
-                /* End of escape case */
-                break;
-        }
-
-        /* End of loop - either we're saving an unescaped character,
-         * or the escape case has set lexer->current to a resolved
-         * character and broken out of the switch
-         */
-
-        cond_save_next(!comment, lexer);
-    }
-
-    /* Discard the final delimiter */
-    next(lexer);
-}
-
-static void __lex_longstring(lexer_state_t *lexer, int sep, int comment)
-{
-    int i;
-
-    /* For convenience leading newlines are ignored */
-    if (lexer->current == '\n' || lexer->current == '\r')
-        next(lexer);
-
-    while (1) {
-        if (lexer->current == ']') {
-            if (lexer->len < (sep + 1))
-                lex_error(lexer, "Long string ran out of space to terminate");
-            for (i = 0; i < sep; i++) {
-                if (lexer->data[i] != '=')
-                    break;
-            }
-            if ((sep != i)||(lexer->data[i] != ']')) {
-                cond_save_next(!comment, lexer);
-                continue;
-            }
-            for (i = 0; i < sep + 2; i++)
-                next(lexer);
-            return;
-        } else if (lexer->current == EOF)
-            lex_error(lexer, "Expected end of long string, not end of stream");
-
-        cond_save_next(!comment, lexer);
-    }
-}
-
-static void __lex_number(lexer_state_t *lexer)
-{
-    u64 val = 0;
-    u64 old_val;
-    int base = 10;
-
-    if (lexer->current == '0') {
-        save_next(lexer);
-        if (lexer->current == 'x') {
-            save_next(lexer);
-            base = 16;
-        } else
-            base = 8;
-    }
-
-    while (vua_char_isident(lexer->current)) {
-        int digit_val;
-
-        /* Some ASCII tricks, '1' - '0' = 1, letter | 0x20 = lowercase */
-        if (vua_char_isdigit(lexer->current))
-            digit_val = lexer->current - '0';
-        else if (vua_char_isxdigit(lexer->current))
-            digit_val = 10 + ((lexer->current | 0x20) - 'a');
-        else
-            lex_error(lexer, "Invalid digit in numeric constant");
-
-        if (digit_val >= base)
-            lex_error(lexer, "Invalid digit for base in numeric constant");
-
-        old_val = val;
-        val *= base;
-
-        if (val / base != old_val)
-            lex_error(lexer, "Numeric constant overflow");
-
-        old_val = val;
-        val += digit_val;
-
-        if (val < old_val)
-            lex_error(lexer, "Numeric constant overflow");
-
-        save_next(lexer);
-    }
-
-    lexer->num_ret = val;
-}
-
-static enum vua_token __lex(lexer_state_t *lexer)
-{
-    vua_tv_t *got;
-    int i, c;
-
-    while(1) {
-        if (vua_char_isident(lexer->current)) {
-            if (vua_char_isdigit(lexer->current)) {
-                __lex_number(lexer);
-                return TOK_NUMBER;
-            }
-
-            do {
-                save_next(lexer);
-            } while (vua_char_isident(lexer->current));
-
-            /* HACK: we need to figure out how to indicate a stale hash so this can be done
-             * lazily, but for now just manually hash the final string
-             */
-
-            lexer->stringbuf->hash = vua_hash_str(lexer->stringbuf, 0);
-
-            got = vua_tab_get(lexer->global->constants, str_tv(lexer->stringbuf));
-
-            if ((got)&&(tvis_int(*got))&&(tv_int(*got) >= BCMAX_D))
-                return tv_int(*got) - BCMAX_D;
-
-            return TOK_NAME;
-        }
-
-        switch(lexer->current) {
-            /* Ignore whitespace, but potentially inc line number */
-            case '\n':
-            case '\r':
-                __nextline(lexer);
-            case ' ':
-            case '\t':
-            case '\v':
-            case '\f':
-                next(lexer);
-                continue;
-            case '-':
-                next(lexer);
-                if (lexer->current != '-')
-                    return '-';
-                next(lexer);
-                if (lexer->current == '[') {
-                    int sep = 0;
-                    next(lexer);
-                    while (lexer->current == '=') {
-                        next(lexer);
-                        sep++;
-                    }
-                    if (lexer->current == '[') {
-                        next(lexer);
-                        __lex_longstring(lexer, sep, 1);
-                        continue;
-                    }
-
-                    /* If somehow lexer->current isn't [ then it wasn't a long
-                     * form comment, but it's still a short comment thanks to
-                     * the known -- prefix
-                     */
-                }
-
-                __lex_string(lexer, 1);
-                continue;
-            case '=':
-                next(lexer);
-                if (lexer->current == '=') {
-                    next(lexer);
-                    return TOK_EQUALITY;
-                } else
-                    return '=';
-            case '<':
-                next(lexer);
-                if (lexer->current == '=') {
-                    next(lexer);
-                    return TOK_LTE;
-                } else
-                    return '<';
-            case '>':
-                next(lexer);
-                if (lexer->current == '=') {
-                    next(lexer);
-                    return TOK_GTE;
-                } else
-                    return '>';
-            case '~':
-                next(lexer);
-                if (lexer->current == '=') {
-                    next(lexer);
-                    return TOK_INEQUALITY;
-                } else
-                    return '~';
-            case ':':
-                next(lexer);
-                if (lexer->current == ':') {
-                    next(lexer);
-                    return TOK_LABEL;
-                } else
-                    return ':';
-            case '"':
-            case '\'':
-                __lex_string(lexer, 0);
-                return TOK_STRING;
-            case '[':
-                /* Look ahead to ensure we're starting a string */
-                for (i = 0; i < lexer->len; i++) {
-                    if (lexer->data[i] != '=')
-                        break;
-                }
-                if ((i < lexer->len)&&(lexer->data[i] == '[')) {
-                    for (c = i + 2; c; c--) // +2 for both opening brackets
-                        next(lexer);
-                    __lex_longstring(lexer, i, 0);
-                    return TOK_STRING;
-                }
-                return '[';
-            case '.':
-                next(lexer);
-                if (lexer->current == '.') {
-                    next(lexer);
-                    if (lexer->current == '.') {
-                        next(lexer);
-                        return TOK_ARGLIST;
-                    }
-                    return TOK_CONCAT;
-                } else
-                    return '.';
-
-                // TODO: Bare floats? .1 For example?
-            case EOF:
-                return TOK_EOF;
-            default:
-                c = lexer->current;
-                next(lexer);
-                return c;
-        }
-    }
-
-    return 0;
-}
-
-static void __lex_debug(lexer_state_t *lexer)
-{
-    if (lexer->nl_pending)
-        printk("\n");
-
-    if (lexer->token > TOK_OFS)
-        printk("%s", tok_names[lexer->token - (TOK_OFS + 1)]);
-    else
-        printk("%c", lexer->token);
-
-    switch(lexer->token) {
-        case TOK_STRING:
-        case TOK_NAME:
-        case TOK_NUMBER:
-            printk("(%S) ", str_tv(lexer->stringbuf));
-            break;
-        default:
-            printk(" ");
-    }
-}
-
-enum vua_token vua_lexer_lex(lexer_state_t *lexer)
-{
-    if (!lexer->stringbuf)
-        lexer->stringbuf = vua_str_create(NULL, 0);
-    else
-        vua_str_reset(lexer->stringbuf);
-
-    if (lexer->nl_pending) {
-        lexer->line++;
-        lexer->col = 0;
-        lexer->nl_pending = 0;
-    }
-
-    lexer->token = __lex(lexer);
-
-    __lex_debug(lexer);
-
-    return lexer->token;
-}
-
-#define ADD_RESW(a, tok)\
-    ret = vua_tab_set(lexer->global->constants, str_tv(vua_str_create(a, strlen(a))));\
-    *ret = int_tv(tok + BCMAX_D);
-
-void vua_lexer_init(lexer_state_t *lexer, func_t *global, u8 *data, u64 len)
-{
-    vua_tv_t *ret;
-
-    lexer->data = data;
-    lexer->len = len;
-    lexer->line = 0;
-    lexer->col = 0;
-    lexer->nl_pending = 0;
-
-    /* Prime the lexer */
-    next(lexer);
-
-    /* Global scope */
-    lexer->global = global;
-    lexer->global->constants = vua_tab_new(0, 8);
-
-    if (!lexer->global->constants) {
-        printk("Failed to allocate global constant table\n");
-        return;
-    }
-
-    ADD_RESW("and", TOK_AND);
-    ADD_RESW("break", TOK_BREAK);
-    ADD_RESW("do", TOK_DO);
-    ADD_RESW("else", TOK_ELSE);
-    ADD_RESW("elseif", TOK_ELSEIF);
-    ADD_RESW("end", TOK_END);
-    ADD_RESW("false", TOK_FALSE);
-    ADD_RESW("for", TOK_FOR);
-    ADD_RESW("function", TOK_FUNCTION);
-    ADD_RESW("goto", TOK_GOTO);
-    ADD_RESW("if", TOK_IF);
-    ADD_RESW("in", TOK_IN);
-    ADD_RESW("local", TOK_LOCAL);
-    ADD_RESW("nil", TOK_NIL);
-    ADD_RESW("not", TOK_NOT);
-    ADD_RESW("or", TOK_OR);
-    ADD_RESW("repeat", TOK_REPEAT);
-    ADD_RESW("return", TOK_RETURN);
-    ADD_RESW("then", TOK_THEN);
-    ADD_RESW("true", TOK_TRUE);
-    ADD_RESW("until", TOK_UNTIL);
-    ADD_RESW("while", TOK_WHILE);
-}
diff --git a/vua/vua_lex.h b/vua/vua_lex.h
deleted file mode 100644 (file)
index 721759c..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/* vim: set ts=4 sw=4 sts=4 et : */
-#pragma once
-
-#include "vua_obj.h"
-
-
-/* Lua Manual Section 3.1 */
-
-#define TOK_DEF(_)   \
-    /* Terminals */ \
-    _(TOK_NUMBER)   \
-    _(TOK_NAME)     \
-                    \
-    /* Reserved Words */\
-    _(TOK_AND)      \
-    _(TOK_BREAK)    \
-    _(TOK_DO)       \
-    _(TOK_ELSE)     \
-    _(TOK_ELSEIF)   \
-    _(TOK_END)      \
-    _(TOK_FALSE)    \
-    _(TOK_FOR)      \
-    _(TOK_FUNCTION) \
-    _(TOK_GOTO)     \
-    _(TOK_IF)       \
-    _(TOK_IN)       \
-    _(TOK_LOCAL)    \
-    _(TOK_NIL)      \
-    _(TOK_NOT)      \
-    _(TOK_OR)       \
-    _(TOK_REPEAT)   \
-    _(TOK_RETURN)   \
-    _(TOK_THEN)     \
-    _(TOK_TRUE)     \
-    _(TOK_UNTIL)    \
-    _(TOK_WHILE)    \
-                    \
-    /* Multi-character Symbols */\
-    _(TOK_STRING)   \
-    _(TOK_EQUALITY) \
-    _(TOK_INEQUALITY)\
-    _(TOK_LTE)      \
-    _(TOK_GTE)      \
-    _(TOK_LABEL)    \
-    _(TOK_CONCAT)   \
-    _(TOK_ARGLIST)  \
-                    \
-    _(TOK_EOF)\
-
-#define TOK_ENUM(a) a,
-enum vua_token {
-    TOK_OFS = 256,  // Offset the enum so we can return raw
-                    // characters without conflicting.
-    TOK_DEF(TOK_ENUM)
-};
-
-void vua_lexer_init(lexer_state_t *lexer, func_t *global, u8 *data, u64 len);
-enum vua_token vua_lexer_lex(lexer_state_t *lexer);
-
-/* Identifying types of specific characters */
-/* Public domain, taken from LuaJIT lj_char.{c,h} */
-
-#define VUA_CHAR_CNTRL   0x01
-#define VUA_CHAR_SPACE   0x02
-#define VUA_CHAR_PUNCT   0x04
-#define VUA_CHAR_DIGIT   0x08
-#define VUA_CHAR_XDIGIT  0x10
-#define VUA_CHAR_UPPER   0x20
-#define VUA_CHAR_LOWER   0x40
-#define VUA_CHAR_IDENT   0x80
-#define VUA_CHAR_ALPHA   (VUA_CHAR_LOWER|VUA_CHAR_UPPER)
-#define VUA_CHAR_ALNUM   (VUA_CHAR_ALPHA|VUA_CHAR_DIGIT)
-#define VUA_CHAR_GRAPH   (VUA_CHAR_ALNUM|VUA_CHAR_PUNCT)
-
-#define vua_char_isa(c, t)       (vua_char_bits[c] & t)
-#define vua_char_iscntrl(c)      vua_char_isa((c), VUA_CHAR_CNTRL)
-#define vua_char_isspace(c)      vua_char_isa((c), VUA_CHAR_SPACE)
-#define vua_char_ispunct(c)      vua_char_isa((c), VUA_CHAR_PUNCT)
-#define vua_char_isdigit(c)      vua_char_isa((c), VUA_CHAR_DIGIT)
-#define vua_char_isxdigit(c)     vua_char_isa((c), VUA_CHAR_XDIGIT)
-#define vua_char_isupper(c)      vua_char_isa((c), VUA_CHAR_UPPER)
-#define vua_char_islower(c)      vua_char_isa((c), VUA_CHAR_LOWER)
-#define vua_char_isident(c)      vua_char_isa((c), VUA_CHAR_IDENT)
-#define vua_char_isalpha(c)      vua_char_isa((c), VUA_CHAR_ALPHA)
-#define vua_char_isalnum(c)      vua_char_isa((c), VUA_CHAR_ALNUM)
-#define vua_char_isgraph(c)      vua_char_isa((c), VUA_CHAR_GRAPH)
-
-#define vua_char_toupper(c)      ((c) - (vua_char_islower(c) >> 1))
-#define vua_char_tolower(c)      ((c) + vua_char_isupper(c))
-
-#define EOF 256
-
-static const u8 vua_char_bits[257] = {
-   0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x3, 0x3, 0x3, 0x3, 0x3, 0x1, 0x1,
-   0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
-   0x2, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4,
-  0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98,0x98, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4,
-   0x4,0xb0,0xb0,0xb0,0xb0,0xb0,0xb0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,
-  0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0,0xa0, 0x4, 0x4, 0x4, 0x4,0x84,
-   0x4,0xd0,0xd0,0xd0,0xd0,0xd0,0xd0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,
-  0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0, 0x4, 0x4, 0x4, 0x4, 0x1,
-  0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
-  0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
-  0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
-  0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
-  0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
-  0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
-  0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
-  0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,
-  0x0
-};
diff --git a/vua/vua_obj.h b/vua/vua_obj.h
deleted file mode 100644 (file)
index d405f0e..0000000
+++ /dev/null
@@ -1,339 +0,0 @@
-/* vim: set ts=4 sw=4 sts=4 et : */
-
-#pragma once
-
-/* This defines the basic types of Vua */
-
-/* Similar to all implicit memory management schemes we need to encapsulate all
- * sorts of data in a generic data structure so we can track it in a uniform
- * fashion.
- *
- * While typically you'd want to split up the object definitions to maintain
- * good separation of code, we're going to have to enforce some standardization
- * so it makes sense to gather their definitions.
- */
-
-/* Things to keep in mind:
- *
- *  - Objects will be in an objcache, which means they have an increment of 16
- *  bytes for their allocations, so you might as well use it.
- *
- *  - The GC information must obviously be first because we'll be casting
- *  generic pointers.
- */
-
-/* GC header
- *
- * This needs to be as small as possible because even one byte difference is
- * multiplied by every object in the world.
- *
- * LuaJIT keeps this to 6 bytes, 4 for next, 2 bytes for type / mark.
- *
- * Using the objcache, I don't think we need to chain GC objects together.
- * Instead, we can start at the thread root use the GC type information to
- * figure out how to traverse the objects and push them onto the gray stack,
- * meanwhile the white/black bits stored in the objcache can be derived based
- * on the object's address.
- *
- * Fortunately this means we can side-step the need to either use 8 bytes of
- * pointer, or shrink a pointer and thus put restrictions on our addresses.
- */
-
-typedef struct vua_gc_header {
-    u8  type;
-    u8  mark;
-} vua_gc_header_t;
-
-/* Another aspect to consider is that we don't need this amount of overhead for
- * simple values that don't need to collected. Stuff like NIL and TRUE and
- * FALSE don't need 16 bytes of overhead in an allocation to express. Neither
- * do simple numeric values.
- *
- * The problem on a 64 bit machine is that you obviously want to be able to
- * take advantage of the big registers and yet you obviously can't express the
- * entire 64 bit range *and* have independent control bits in the same 8 bytes.
- *
- * LuaJIT works around this problem in the TValue struct and by defaulting
- * numbers to doubles. Since a double is floating point, you can detect when
- * it's a special NaN value and use the remaining bits for whatever you want.
- *
- * I, however, am not so ready to rely on the FPU and would prefer to default
- * to integer types, but this is moot anyway because I also want to keep full
- * 64 bit pointers, where LuaJIT condenses GC refs into 32 bits, which allows
- * them to pack a full reference _and_ extra info into the TValue.
- *
- * So if we're going to fit pointers in here, we have a couple of options. The
- * top two bytes of a current 64 bit pointer are sign extended from the 48th
- * bit, so that's two full bytes we can derive. We could also rely on our 16
- * byte alignment, which leaves 4 bits at the low end of a pointer which we'd
- * have even without the sign extension.
- *
- * I've chosen to use the 4 bits approach with the following encoding.
- */
-
-#define TV_NIL      0
-#define TV_FALSE    1
-#define TV_TRUE     2
-#define TV_STR      3
-#define TV_TABLE    4
-#define TV_INT      5
-#define TV_PROTO    6
-
-/*
- * The reason I chose to use the bottom half byte is that even though those top
- * bits can be derived in a pointer, you still have to correct those bits
- * before you dereference it (i.e. the CPU won't automatically sign extend over
- * your bits). That means you either have to test the 48th bit and set/clear as
- * necessary, or you have to shrink your addressable space (to say objects are
- * only in kernel or user space considering our memory separation) and just do
- * the set/clear. Using the alignment bits, we keep the address space open
- * _and_ just peform a clear to get a usable pointer.
- *
- * This method also provides us with enough expressivity (4 bits) to encode
- * every one of the basic types from LuaJIT even though some of them we won't
- * use (like C data), so the extra two bytes afforded by using the top bytes
- * isn't an issue.
- *
- * Lastly, while unfortunately we can't do something like LuaJIT and have our
- * flags in place and still be a valid floating point double, shifting 4 bits
- * to convert to/from a TValue to a 60-bit integer is about as cheap as you
- * get.
- *
- * So what about floats? We can either build in a single precision float to the
- * top 32 bits, or we could assume double precision and make it cost 16 bytes
- * and a dereference to store it.
- */
-
-typedef u64 vua_tv_t;
-
-#define tvis_(x, y)     (((x) & 0xf) == y)
-#define tvis_nil(x)     tvis_(x, TV_NIL)
-#define tvis_true(x)    tvis_(x, TV_TRUE)
-#define tvis_false(x)   tvis_(x, TV_FALSE)
-#define tvis_str(x)     tvis_(x, TV_STR)
-#define tvis_table(x)   tvis_(x, TV_TABLE)
-#define tvis_int(x)     tvis_(x, TV_INT)
-#define tvis_proto(x)   tvis_(x, TV_PROTO)
-
-#define tv_int(x)       ((x) >> 4)
-#define tv_ptr(x)       ((void *) ((x) & ~(0xful)))
-#define tv_str(x)       ((vua_str_t *) tv_ptr(x))
-#define tv_proto(x)     ((vua_proto_t *) tv_ptr(x))
-
-#define int_tv(x)       (((x) << 4) | TV_INT)
-#define nil_tv          (0UL | TV_NIL)
-#define str_tv(s)       (((u64) (s)) | TV_STR)
-#define proto_tv(p)     (((u64) (p)) | TV_PROTO)
-
-/* Definitions for metatables */
-
-/* Split out from enum so we can easily redefine and use as a string list */
-
-#define MMDEF(_) \
-  _(index) _(newindex) _(gc) _(mode) _(eq) _(len) \
-  /* Only the above (fast) metamethods are negative cached (max. 8). */ \
-  _(lt) _(le) _(concat) _(call) \
-  /* The following must be in ORDER ARITH. */ \
-  _(add) _(sub) _(mul) _(div) _(mod) _(pow) _(unm)
-
-typedef enum {
-#define MMENUM(name)    MM_##name,
-MMDEF(MMENUM)
-#undef MMENUM
-  MM__MAX,
-  MM____ = MM__MAX,
-  MM_FAST = MM_len
-} MMS;
-
-/* Bytecode Types */
-
-typedef u32 BCIns;  /* Bytecode instruction. */
-typedef u32 BCPos;  /* Bytecode position. */
-typedef u32 BCReg;  /* Bytecode register. */
-typedef s32 BCLine;  /* Bytecode line number. */
-
-typedef struct BCInsLine {
-  BCIns ins;            /* Bytecode instruction. */
-  BCLine line;          /* Line number for this bytecode. */
-} BCInsLine;
-
-/* String */
-
-typedef struct vua_str {
-    vua_gc_header_t gc;
-    u16 len;
-
-    char *data;
-    u32 hash;
-
-} __attribute__((packed)) vua_str_t;
-
-vua_str_t *vua_str_create(char *init_val, u64 starting_len);
-void vua_str_reset(vua_str_t *str);
-void vua_str_free(vua_str_t *str);
-int vua_str_eq(vua_str_t *a, vua_str_t *b);
-int vua_str_append(vua_str_t *a, char c);
-
-/* Hash Table */
-
-typedef struct vua_tab_node {
-    struct vua_tab_node *next;
-    vua_tv_t key;
-    vua_tv_t val;
-
-    char _extra[8];
-} vua_tab_node_t;
-
-typedef struct vua_tab {
-    vua_gc_header_t gc;
-
-    vua_tab_node_t *nodes;
-    vua_tv_t *array;
-
-    u32 asize;
-    u32 hmask;
-} vua_tab_t;
-
-#define TAB_MAX_HBITS   26 /* 67 million hash slots (2GB) */
-#define TAB_MAX_HSIZE   (1 << TAB_MAX_HBITS)
-#define TAB_MAX_ABITS   28 /* 268 million keys (2GB) */
-#define TAB_MAX_ASIZE   (1 << TAB_MAX_ABITS)
-
-vua_tab_t *vua_tab_new(u32 asize, u32 hbits);
-vua_tv_t *vua_tab_get(vua_tab_t *tab, vua_tv_t key);
-vua_tv_t *vua_tab_set(vua_tab_t *tab, vua_tv_t key);
-void vua_tab_free(vua_tab_t *tab);
-
-typedef struct vua_var_info {
-    vua_str_t *name;
-    BCPos start_pc;
-    BCPos end_pc;
-    u8 slot;
-    u8 flags;
-} var_info_t;
-
-#define VSTACK_VAR_RW   (1 << 0)
-#define VSTACK_GOTO     (1 << 1)
-#define VSTACK_LABEL    (1 << 2)
-
-/* Flags for resolved upvalues, fit in var_idx_t (u16), but avoid slot data
- * (u8)
- */
-
-#define UV_IMMUTABLE    (1 << 14)
-#define UV_LOCAL        (1 << 15)
-
-typedef u16 var_idx_t;
-
-typedef struct vua_scope {
-    struct vua_scope *prev;
-    var_idx_t vstart;
-    u8 nactvar;
-    u8 flags;
-} scope_t;
-
-#define SCOPE_LOOP      (1 << 0)
-#define SCOPE_BREAK     (1 << 1)
-#define SCOPE_GOLA      (1 << 2)
-#define SCOPE_UPVAL     (1 << 3)
-#define SCOPE_NOCLOSE   (1 << 4)
-
-/* Taken from LJ */
-#define MAX_LOCVAR  200
-#define MAX_UPVAL   60
-
-/* upidx + MAX_VSTACK should never overflow, otherwise all var_idx_t usable. */
-#define MAX_VSTACK  (0xFFFF - MAX_UPVAL)
-
-typedef struct vua_func {
-    struct vua_func *prev;
-
-    scope_t *scope;
-
-    vua_tab_t *constants;
-    u32 obj_consts;
-    u32 num_consts;
-
-    vua_tab_t *kregs;
-    u32 reg_consts;
-
-    u8 params;          // Number of parameters
-
-    BCReg freereg;      // Next free register
-    BCReg nactvar;      // Number of active variables
-    BCReg nuv;          // Number of upvalues
-    u8 framesize;       // Stack frame size
-
-    BCInsLine *bcbase;  // Bytecode holster
-    BCPos max_pc;       // Size of bcbase window
-    BCPos pc;           // Next bytecode position
-
-    BCPos jpc;          // Pending jump list
-    BCPos last_target;  // final target loc, for ret fixup
-
-    u8 flags;           // PROTO flags
-
-    /* Indices into the variable stack */
-    var_idx_t varmap[MAX_LOCVAR];
-    var_idx_t uvmap[MAX_UPVAL];
-    var_idx_t uvtmp[MAX_UPVAL];
-} func_t;
-
-typedef struct vua_lexer_state {
-    /* Current state of the lexer data */
-    u8 *data;
-    u64 len;
-    int current;
-
-    /* Return data from lex() */
-    int token;
-    char *error;
-    vua_str_t *stringbuf;
-    u64 num_ret;
-    u8 nl_pending;
-    int line;
-    int col;
-
-    func_t *global;
-
-} lexer_state_t;
-
-typedef struct vua_parser {
-    lexer_state_t lexer;
-    func_t *func;
-
-    var_info_t *vstack;
-    u32 vstack_size;
-    u32 vtop;
-
-    BCInsLine *bcstack;
-    BCPos bclim;
-} parser_t;
-
-/* Prototype represents a function that has been fully parsed and processed,
- * ready to actually be used, but also potentially garbage collected.
- */
-
-typedef struct vua_proto {
-    vua_gc_header_t gc;
-
-    u8 params;
-    u8 framesize;
-
-    u32 size_bc;
-    u32 size_kgc;
-    u32 size_kn;
-    u32 size_kr;
-    u32 size_proto;
-
-    vua_tv_t *k;
-    var_idx_t *uv;
-
-    u8 nuv;
-    u8 flags;
-} vua_proto_t;
-
-#define PROTO_CHILD         (1 << 0)
-#define PROTO_VARARG        (1 << 1)
-#define PROTO_HAS_RETURN    (1 << 2)
-#define PROTO_FIXUP_RETURN  (1 << 3)
diff --git a/vua/vua_parse.c b/vua/vua_parse.c
deleted file mode 100644 (file)
index 949c2fc..0000000
+++ /dev/null
@@ -1,1002 +0,0 @@
-/* vim: set ts=4 sw=4 sts=4 et : */
-
-#include <kernel.h>
-
-#include <objcache.h>
-
-#include "vua_bc.h"
-#include "vua_parse.h"
-#include "vua_lex.h"
-#include "vua_obj.h"
-
-static DEFINE_OBJCACHE(parser_cache);
-
-static u32 __parse_expr_binop(parser_t *parser, expr_t *expr, u32 prio);
-static int __parse_block(parser_t *parser);
-static int __parse_expr_list(parser_t *parser, expr_t *expr);
-
-#define __parse_expr(p, e) __parse_expr_binop(p, e, 0)
-#define next()  vua_lexer_lex(&parser->lexer)
-
-static int __lex_opt(parser_t *parser, enum vua_token token)
-{
-    if (parser->lexer.token == token) {
-        next();
-        return 1;
-    }
-
-    return 0;
-}
-#define lex_opt(x) __lex_opt(parser, x)
-
-static int __lex_check(parser_t *parser, enum vua_token token)
-{
-    assert(parser->lexer.token == token);
-    next();
-    return 1;
-}
-
-#define lex_check(x) __lex_check(parser, x)
-
-static int __new_scope(parser_t *parser, int flags)
-{
-    scope_t *new = objcache_get(&parser_cache, sizeof(scope_t));
-
-    assert(new);
-
-    new->flags = flags;
-    new->vstart = parser->vtop;
-    new->nactvar = parser->func->nactvar;
-
-    new->prev = parser->func->scope;
-    parser->func->scope = new;
-
-    return 0;
-}
-
-static void __remove_var(parser_t *parser, BCReg tolevel);
-
-static void __end_scope(parser_t *parser)
-{
-    func_t *func = parser->func;
-    scope_t *scope = func->scope;
-
-    /* Record ending pc */
-    __remove_var(parser, scope->nactvar);
-
-    func->freereg = func->nactvar;
-
-    /* Close any upvalues here when they fall out of scope */
-    if ((scope->flags & (SCOPE_UPVAL|SCOPE_NOCLOSE)) == SCOPE_UPVAL)
-        vua_bc_emit_uclo(parser, scope->nactvar);
-
-    func->scope = scope->prev;
-
-    objcache_free(&parser_cache, scope);
-}
-
-static int __new_func(parser_t *parser)
-{
-    func_t *new = objcache_get(&parser_cache, sizeof(func_t));
-
-    assert(new);
-
-    memset(new, 0, sizeof(func_t));
-
-    new->prev = parser->func;
-    new->jpc = NO_JMP;
-
-    parser->func = new;
-
-    return 0;
-}
-
-/* Convert token to binary operator.
- *
- * Note that EQ is equality test, assignment seems like a binary operator, but
- * it's handled separately.
- */
-
-static binop token2binop(u32 tok)
-{
-    switch (tok) {
-        case '+':
-            return OPR_ADD;
-        case '-':
-            return OPR_SUB;
-        case '*':
-            return OPR_MUL;
-        case '/':
-            return OPR_DIV;
-        case '%':
-            return OPR_MOD;
-        case '^':
-            return OPR_POW;
-        case TOK_CONCAT:
-            return OPR_CONCAT;
-        case TOK_INEQUALITY:
-            return OPR_NE;
-        case TOK_EQUALITY:
-            return OPR_EQ;
-        case '<':
-            return OPR_LT;
-        case TOK_LTE:
-            return OPR_LE;
-        case '>':
-            return OPR_GT;
-        case TOK_GTE:
-            return OPR_GE;
-        case TOK_AND:
-            return OPR_AND;
-        case TOK_OR:
-            return OPR_OR;
-        default:
-            return OPR_NOBINOPR;
-    }
-}
-
-static void __expr_init(expr_t *expr, expr_type type)
-{
-    expr->type = type;
-    expr->v.uval = 0;
-    expr->true_list = NO_JMP;
-    expr->false_list = NO_JMP;
-}
-
-/* Add a new local variable, offset n from the current last variable */
-
-#define VSTACK_STRIDE 32
-
-static void __new_var(parser_t *parser, BCReg n, vua_str_t *name)
-{
-    var_info_t *new;
-
-    if (parser->vstack_size % VSTACK_STRIDE == 0) {
-        new = objcache_get(&parser_cache, (parser->vstack_size + VSTACK_STRIDE) * sizeof(var_info_t));
-        assert(new);
-
-        if (parser->vstack) {
-            memcpy(new, parser->vstack, (parser->vstack_size * sizeof(var_info_t)));
-            objcache_free(&parser_cache, parser->vstack);
-        }
-
-        parser->vstack = new;
-        parser->vstack_size += VSTACK_STRIDE;
-    }
-
-    parser->func->varmap[parser->func->nactvar + n] = parser->vtop;
-    parser->vstack[parser->vtop].name = name;
-    parser->vtop++;
-}
-
-/* Create all upvalues from parser->func to given func/vidx */
-
-static int __handle_uv(parser_t *parser, func_t *owner, BCReg reg, var_idx_t vidx)
-{
-    func_t *cur = parser->func;
-    scope_t *scope = owner->scope;
-    int idx = cur->nuv++;
-
-    cur->uvmap[idx] = vidx;
-    cur->uvtmp[idx] = vidx;
-    cur = cur->prev;
-
-    while (cur != owner) {
-        cur->uvmap[cur->nuv] = vidx;
-        cur->uvtmp[cur->nuv] = MAX_VSTACK + idx;
-        cur->nuv++;
-        cur = cur->prev;
-    }
-
-    /* Mark the scope with the definition of this upvalue as having an upvalue.
-     */
-
-    while ((scope) && (scope->nactvar > reg))
-        scope = scope->prev;
-
-    if (scope)
-        scope->flags |= SCOPE_UPVAL;
-
-    return idx;
-}
-
-/* Given a variable name, look it up determine whether it's a global, local
- * or an upvalue and set expr_t to suit
- */
-
-static void __lookup_var(parser_t *parser, expr_t *expr, vua_str_t *name)
-{
-    func_t *func = parser->func;
-    var_info_t *var;
-    int i, level = 0;
-
-    __expr_init(expr, VVOID);
-
-    while (func) {
-        /* Iterate backwards so later local defs override earlier ones */
-
-        /* Check locals */
-        for (i = func->nactvar - 1; i >= 0; i--) {
-            var = &parser->vstack[func->varmap[i]];
-
-            if (!vua_str_eq(name, var->name))
-                continue;
-
-            expr->v.r.aux = func->varmap[i];
-
-            /* Lookup local to first function, no upvalues */
-            if (level == 0) {
-                expr->type = VLOCAL;
-                expr->v.r.info = i;
-            } else {
-                expr->type = VUPVAL;
-                expr->v.r.info = __handle_uv(parser, func, i, expr->v.r.aux);
-            }
-            return;
-        }
-
-        /* Check already existing upvalues */
-
-        for (i = func->nuv - 1; i >= 0; i--) {
-            var = &parser->vstack[func->uvmap[i]];
-
-            if (!vua_str_eq(name, var->name))
-                continue;
-
-            expr->type = VUPVAL;
-            expr->v.r.aux = func->uvmap[i];
-
-            if (level == 0)
-                expr->v.r.info = i;
-            else
-                expr->v.r.info = __handle_uv(parser, func, i, expr->v.r.aux);
-            return;
-        }
-
-        func = func->prev;
-        level++;
-    }
-
-    expr->type = VGLOBAL;
-    expr->v.val = str_tv(name);
-    return;
-}
-
-/* Add and remove update slots / nactvar, and maintains start and end PCs in
- * variable info for ranges of variable info on the vstack as scopes open and
- * close.
- */
-
-static void __add_var(parser_t *parser, BCReg num)
-{
-    var_info_t *var;
-    func_t *func = parser->func;
-
-    while(num) {
-        var = &parser->vstack[func->varmap[num]];
-        var->start_pc = func->pc;
-        var->slot = func->nactvar++;
-        var->flags = 0;
-        num--;
-    }
-}
-
-static void __remove_var(parser_t *parser, BCReg tolevel)
-{
-    var_info_t *var;
-    func_t *func = parser->func;
-
-    while (func->nactvar > tolevel) {
-        var = &parser->vstack[func->varmap[func->nactvar]];
-        var->end_pc = func->pc;
-        func->nactvar--;
-    }
-}
-
-static void __parse_args(parser_t *parser, expr_t *expr)
-{
-    expr_t args;
-
-    next();
-
-    if (parser->lexer.token == ')')
-        __expr_init(&args, VVOID);
-    else {
-        __parse_expr_list(parser, &args);
-    }
-
-    lex_check(')');
-
-    vua_bc_emit_call(parser, expr, &args);
-}
-
-/* Parse a standalone expression, like (), a function call or variable name,
- * these are allowed to be valid left hand sides for assignment
- */
-
-static void __parse_expr_primary(parser_t *parser, expr_t *expr)
-{
-    int token = parser->lexer.token;
-
-    if (token == '(') {
-        next();
-        __parse_expr(parser, expr);
-        vua_bc_discharge(parser, expr);
-    } else if (token == TOK_NAME) {
-        __lookup_var(parser, expr, parser->lexer.stringbuf);
-        if (expr->type == VGLOBAL)
-            parser->lexer.stringbuf = NULL;
-    }
-
-    next();
-
-    while (1) {
-        token = parser->lexer.token;
-
-        if (token == '(') {
-            vua_bc_tonextreg(parser, expr);
-            __parse_args(parser, expr);
-        } else
-            break;
-
-    }
-}
-
-/* Parse a constant expression */
-
-static void __parse_expr_simple(parser_t *parser, expr_t *expr)
-{
-    int token = parser->lexer.token;
-
-    /* Unary values */
-    if (token == TOK_NUMBER) {
-        __expr_init(expr, VKNUM);
-        expr->v.uval = parser->lexer.num_ret;
-    } else if (token == TOK_STRING) {
-        __expr_init(expr, VKSTR);
-        expr->v.val = str_tv(parser->lexer.stringbuf);
-        parser->lexer.stringbuf = NULL;
-    } else if (token == TOK_NIL)
-        __expr_init(expr, VKNIL);
-    else if (token == TOK_TRUE)
-        __expr_init(expr, VKTRUE);
-    else if (token == TOK_FALSE)
-        __expr_init(expr, VKFALSE);
-    else {
-        __parse_expr_primary(parser, expr);
-        return;
-    }
-
-    next();
-}
-
-/* Parse a unary operation (not, ~, #, -), or continue on to look for a simple
- * expression, or a function call
- */
-
-static void __parse_expr_unop(parser_t *parser, expr_t *expr)
-{
-    int token = parser->lexer.token;
-    int op;
-
-    /* Unary operations */
-    if (token == TOK_NOT)
-        op = BC_NOT;
-    else if (token == '-')
-        op = BC_UNM;
-    else if (token == '#')
-        op = BC_LEN;
-    else {
-        /* Other options aren't operations */
-        __parse_expr_simple(parser, expr);
-        return;
-    }
-
-    /* If we got an unary operation, then attempt to resolve what
-     * it's operating on
-     */
-
-    next();
-
-    __parse_expr_binop(parser, expr, UNARY_PRIORITY);
-
-    vua_bc_emit_unop(parser, op, expr);
-}
-
-/* Parse a potential binary operation expression. Most of the work is done by
- * unop to get both the LHS and RHS of the binary operation, however the
- * important work here is enforcing the mathematical order of operations.
- *
- * The higher the priority, the greater the precedence. So, for example a
- * conditional (which is constant, so it would actually be optimized out, but
- * it's just an example)
- *
- * 1 + 3 * 4 and 2 + 5
- *
- * 1 is a unary expression, so it will be parsed by unop, leaving
- *
- * + 3 * 4 and 2 + 5
- *
- * + is a binary operation with priority 6/6, so it's RHS is parsed, but only
- * operations with a higher priority are considered.
- *
- * 3 * 4 and 2 + 5 (prio 6)
- *
- * 3 is unary, leaving
- *
- * * 4 and 2 + 5 (prio 6)
- *
- * * is a binary operation with a higher priority (7/7) so just like +, it's
- * RHS is parsed, but only operations with higher priority
- *
- * 4 and 2 + 5 (prio 7)
- *
- * 4 is unary, so it gets parsed, leaving
- *
- * and 2 + 5 (prio 7)
- *
- * and is a binary option with a lower priority (2/2) so parsing for the *
- * stops and generates the bytecode for 3 * 4, and returns to where we were
- * parsing +, which generates the bytecode to add 1, properly putting 13 into
- * whatever register instead of stupidly going in order and arriving at 16.
- */
-
-static u32 __parse_expr_binop(parser_t *parser, expr_t *expr, u32 prio)
-{
-    u32 op, next_op;
-    expr_t expr2;
-
-    /* Parse the LHS */
-    __parse_expr_unop(parser, expr);
-
-    op = token2binop(parser->lexer.token);
-
-    while (op != OPR_NOBINOPR && priority[op].left > prio) {
-        vua_bc_emit_binop_left(parser, op, expr);
-        next();
-
-        next_op = __parse_expr_binop(parser, &expr2, priority[op].right);
-        vua_bc_emit_binop(parser, op, expr, &expr2);
-
-        op = next_op;
-    }
-
-    return op;
-}
-
-/* Parse an expression list and immediately discharge all but the last
- * register. This is used for function calls as well as multi assignment.
- */
-
-static int __parse_expr_list(parser_t *parser, expr_t *expr)
-{
-    int nexps = 1;
-
-    __parse_expr(parser, expr);
-
-    while (lex_opt(',')) {
-        vua_bc_tonextreg(parser, expr);
-        __parse_expr(parser, expr);
-        nexps++;
-    }
-
-    return nexps;
-}
-
-typedef struct lhs_list {
-    expr_t expr;
-    struct lhs_list *prev;
-} lhs_list_t;
-
-/* Handle assignment to one or more variables */
-
-static int __parse_assignment(parser_t *parser, lhs_list_t *head)
-{
-    lhs_list_t *new, *tail = head;
-    expr_t expr;
-    int nvars = 1;
-    int nexps;
-
-    while (lex_opt(',')) {
-        new = objcache_get(&parser_cache, sizeof(lhs_list_t));
-        assert(new);
-
-        __parse_expr_primary(parser, &new->expr);
-
-        new->prev = tail;
-        tail = new;
-        nvars++;
-    }
-
-    lex_check('=');
-
-    nexps = __parse_expr_list(parser, &expr);
-
-    assert(nexps == nvars);
-
-    while (nexps) {
-        vua_bc_emit_store(parser, &tail->expr, &expr);
-
-        new = tail->prev;
-        objcache_free(&parser_cache, tail);
-        tail = new;
-
-        __expr_init(&expr, VNONRELOC);
-        expr.v.r.info = parser->func->freereg - (nvars - nexps);
-
-        nexps--;
-    }
-
-    return 0;
-}
-
-/* Handle assignment with possible function call LHS */
-
-static int __parse_call_assignment(parser_t *parser)
-{
-    lhs_list_t *head = objcache_get(&parser_cache, sizeof(lhs_list_t));
-
-    assert(head);
-
-    head->prev = NULL;
-
-    __parse_expr_primary(parser, &head->expr);
-
-    if(head->expr.type == VCALL) {
-
-    } else {
-        /* Will free head list */
-        __parse_assignment(parser, head);
-    }
-
-    return 0;
-}
-
-/* Parse a conditional expression, which is just an expression followed by an
- * appropriate jump
- */
-
-static BCPos __parse_cond_expr(parser_t *parser)
-{
-    expr_t cond;
-
-    __parse_expr(parser, &cond);
-
-    if (cond.type == VKNIL)
-        cond.type = VKFALSE;
-
-    vua_bc_emit_branch_t(parser, &cond);
-    return cond.false_list;
-}
-
-static BCPos __parse_then(parser_t *parser)
-{
-    BCPos exit;
-
-    exit = __parse_cond_expr(parser);
-
-    lex_check(TOK_THEN);
-
-    __parse_block(parser);
-
-    return exit;
-}
-
-static int __parse_if(parser_t *parser)
-{
-    BCPos escapes = NO_JMP;
-    BCPos flist;
-
-    flist = __parse_then(parser);
-
-    vua_bc_jmp_append(parser, &escapes, flist);
-    vua_bc_jmp_here(parser, escapes);
-
-    lex_check(TOK_END);
-    return 0;
-}
-
-/* Parse a local definition and possibly assignment. */
-
-static int __parse_local(parser_t *parser)
-{
-    expr_t expr;
-    int exps, vars = 0;
-
-    while (parser->lexer.token == TOK_NAME) {
-        __new_var(parser, vars++, parser->lexer.stringbuf);
-        parser->lexer.stringbuf = NULL;
-
-        next();
-        lex_opt(',');
-    }
-
-    if (lex_opt('=')) {
-        exps = __parse_expr_list(parser, &expr);
-        assert(exps == vars);
-        vua_bc_tonextreg(parser, &expr);
-    }
-
-    __add_var(parser, vars);
-    return 0;
-}
-
-static int __parse_params(parser_t *parser, int needself)
-{
-    vua_str_t *self;
-    int params = 0;
-    int c;
-
-    lex_check('(');
-
-    if (needself) {
-        self = vua_str_create("self", 4);
-
-        c = vua_bc_newconst(parser, str_tv(self));
-        assert(c <= BCMAX_D);
-
-        __new_var(parser, params++, self);
-    }
-
-    if (parser->lexer.token != ')') {
-        do {
-            if (parser->lexer.token == TOK_NAME) {
-                __new_var(parser, params++, parser->lexer.stringbuf);
-                parser->lexer.stringbuf = NULL;
-                next();
-            } else if (parser->lexer.token == TOK_ARGLIST) {
-                parser->func->flags |= PROTO_VARARG;
-                next();
-                break;
-            } else
-                assert(0);
-        } while (lex_opt(','));
-    }
-
-    __add_var(parser, params);
-
-    vua_bc_reg_reserve(parser, params);
-
-    lex_check(')');
-    return params;
-}
-
-static int __parse_body(parser_t *parser, expr_t *expr, int needself);
-
-static int __parse_function(parser_t *parser)
-{
-   expr_t var, expr;
-
-   __lookup_var(parser, &var, parser->lexer.stringbuf);
-   parser->lexer.stringbuf = NULL;
-   next();
-
-   __parse_body(parser, &expr, 0);
-
-   vua_bc_emit_store(parser, &var, &expr);
-
-   return 0;
-}
-
-static int __end_block(enum vua_token tok)
-{
-    if ((tok == TOK_ELSE)||
-            (tok == TOK_ELSEIF)||
-            (tok == TOK_END)||
-            (tok == TOK_UNTIL)||
-            (tok == TOK_EOF))
-        return 1;
-    return 0;
-}
-
-static int __parse_return(parser_t *parser)
-{
-    expr_t expr;
-    int rets = 0;
-
-    parser->func->flags |= PROTO_HAS_RETURN;
-
-    if (parser->func->flags & PROTO_CHILD)
-        vua_bc_emit_uclo(parser, 0);
-
-    if (__end_block(parser->lexer.token) || parser->lexer.token == ';')
-        vua_bc_emit_ret(parser, 0, NULL);
-    else {
-        rets = __parse_expr_list(parser, &expr);
-        vua_bc_emit_ret(parser, rets, &expr);
-    }
-
-    return 0;
-}
-
-/* Statement is a workhorse rule, encompassing all of our fundamental
- * operations like assignment, math, flow control etc.
- *
- * Most statements are easy to detect because they begin with an easy signifier
- * like 'if' or 'for', but two types of statement, the varlist and the function
- * call start with names, so we need to lex more tokens to figure out what
- * exactly we're looking at.
- */
-
-static int __parse_statement(parser_t *parser)
-{
-    switch (parser->lexer.token) {
-        case TOK_IF:
-            next();
-            __parse_if(parser);
-            break;
-        case TOK_LOCAL:
-            next();
-            __parse_local(parser);
-            break;
-        case TOK_FUNCTION:
-            next();
-            __parse_function(parser);
-            break;
-        case TOK_RETURN:
-            next();
-            __parse_return(parser);
-            break;
-        default:
-            __parse_call_assignment(parser);
-            break;
-    }
-
-    return 0;
-}
-
-/* A block is a list of zero or more statements, so most of the work is on the
- * statement parser. However, the important part of a block is that it opens a
- * new scope.
- */
-
-static int __parse_chunk(parser_t *parser)
-{
-    do {
-        __parse_statement(parser);
-        lex_opt(';');
-    } while (!__end_block(parser->lexer.token));
-
-    return 0;
-}
-
-/* Parse an arbitrary new scope, like one built into a conditional */
-
-static int __parse_block(parser_t *parser)
-{
-    __new_scope(parser, 0);
-
-    __parse_chunk(parser);
-
-    __end_scope(parser);
-
-    return 0;
-}
-
-/* Convert a prototype's upvalue section into registers + flags */
-
-static void __child_proto(parser_t *parser, vua_proto_t *proto)
-{
-    var_idx_t *uv = proto->uv;
-    var_info_t *vstack = parser->vstack;
-    int i;
-
-    for (i = 0; i < proto->nuv; i++)  {
-
-        /* MAX_VSTACK used to denote that this is an upvalue from a a lower
-         * scope, but the value is already the register in the target scope
-         */
-
-        if (uv[i] >= MAX_VSTACK)
-            uv[i] -= MAX_VSTACK;
-
-        /* Otherwise, it's a variable index, so update uv[i] to the register,
-         * and set flags in the varinfo
-         */
-
-        else if (vstack[uv[i]].flags & VSTACK_VAR_RW)
-            uv[i] = vstack[uv[i]].slot | UV_LOCAL;
-        else
-            uv[i] = vstack[uv[i]].slot | UV_LOCAL | UV_IMMUTABLE;
-    }
-}
-
-/* Convert a fully parsed function into a prototype ready to run */
-
-static vua_proto_t *__prototype(parser_t *parser)
-{
-    func_t *func = parser->func;
-    vua_proto_t *proto;
-    int k_off;
-    int uv_off;
-    vua_tab_node_t *node;
-    BCIns *bc;
-
-    u64 size_proto;
-    int i, idx;
-
-    /* Ensure there's a return, and fix any returns that were potentially
-     * emitted before a child function was parsed
-     */
-
-    vua_bc_fix_ret(parser);
-
-    /* When closing this function level scope, we don't need any further UCLO
-     * instructions because we have returns that dealt with that already,
-     * unlike dropping out of lesser scopes
-     */
-
-    func->scope->flags |= SCOPE_NOCLOSE;
-    __end_scope(parser);
-
-    size_proto = sizeof(vua_proto_t);
-    size_proto += func->pc * sizeof(BCIns);
-
-    size_proto += func->obj_consts * sizeof(vua_tv_t);
-    k_off = size_proto;
-    size_proto += func->num_consts * sizeof(vua_tv_t);
-
-    uv_off = size_proto;
-    size_proto += ((func->nuv + 1) & ~1) << 1; // maintain 4 byte align
-
-    proto = objcache_get(&parser_cache, size_proto);
-    assert(proto);
-
-    proto->params = func->params;
-    proto->framesize = func->framesize;
-    proto->size_kgc = func->obj_consts;
-    proto->size_kn = func->num_consts;
-    proto->size_kr = func->reg_consts;
-    proto->size_bc = func->pc;
-    proto->nuv = func->nuv;
-    proto->flags = func->flags;
-
-    bc = (BCIns *) (((u64) proto) + sizeof(vua_proto_t));
-    proto->k = (vua_tv_t *) (((u64) proto) + k_off);
-    proto->uv = (var_idx_t *) (((u64) proto) + uv_off);
-
-    /* Replace placeholder FUNCV with proper definition */
-    bc[0] = BCINS_AD(func->flags & PROTO_VARARG ? BC_FUNCV : BC_FUNCF, func->framesize, 0);
-
-    /* Move over the instruction part of parsed bytecode */
-    for (i = 1; i < func->pc; i++)
-        bc[i] = func->bcbase[i].ins;
-
-    /* Copy constants into lookup table */
-
-    if (func->constants) {
-        for (i = 0; i < func->constants->asize; i++)
-            proto->k[tv_int(func->constants->array[i])] = i;
-
-        for (i = 0; i <= func->constants->hmask; i++) {
-            node = &func->constants->nodes[i];
-
-            if (tvis_nil(node->key))
-                continue;
-
-            while (node) {
-                idx = tv_int(node->val);
-
-                if (tvis_int(node->key))
-                    proto->k[idx] = node->key;
-                else if (tvis_proto(node->key)) {
-                    __child_proto(parser, tv_proto(node->key));
-                    proto->k[~idx] = node->key;
-                } else if (idx <= BCMAX_D)
-                    proto->k[~idx] = node->key;
-                node = node->next;
-            }
-        }
-    }
-
-    /* Copy upvalues, to be fixed up by parent function */
-
-    memcpy(proto->uv, func->uvtmp, func->nuv * sizeof(var_idx_t));
-
-    parser->func = parser->func->prev;
-
-    /* Cleanup the dead parser function */
-
-    if (func->constants)
-        vua_tab_free(func->constants);
-    if (func->kregs)
-        vua_tab_free(func->kregs);
-
-    objcache_free(&parser_cache, func);
-
-    return proto;
-}
-
-/* Parse a new function body, different from block because it needs to parse
- * function parameters and then have various fixups applied before generating a
- * prototype that can actually be assigned to a value
- */
-
-static int __parse_body(parser_t *parser, expr_t *expr, int needself)
-{
-    func_t *parent = parser->func;
-    func_t *child;
-    vua_proto_t *proto;
-
-    ptrdiff_t oldbase = parent->bcbase - parser->bcstack;
-
-    __new_func(parser);
-    child = parser->func;
-
-    __new_scope(parser, 0);
-
-    child->bcbase = &parent->bcbase[parent->pc];
-    child->max_pc = parent->max_pc - parent->pc;
-
-    child->params = __parse_params(parser, needself);
-
-    /* Emit opening FUNCV as a place holder */
-    vua_bc_emit_func(parser);
-
-    __parse_chunk(parser);
-
-    /* Get prototype and destroy child func_t in the process */
-    proto = __prototype(parser);
-
-    /* Re-ref in case parsing chunk realloc'd the parser bcstack */
-    parent->bcbase = parser->bcstack + oldbase;
-    parent->max_pc = parser->bclim - (oldbase / sizeof(BCInsLine));
-
-    __expr_init(expr, VRELOCABLE);
-    expr->v.r.info = vua_bc_emit_proto(parser, proto);
-
-    /* If this is the first child, and a return has already been emitted, then
-     * they may need to be fixed to close upvalues.  For subsequent returns,
-     * just having PROTO_CHILD already set will cause upvalues to be closed.
-     */
-
-    if (!(parent->flags & PROTO_CHILD)) {
-        parent->flags |= PROTO_CHILD;
-        if (parent->flags & PROTO_HAS_RETURN)
-            parent->flags |= PROTO_FIXUP_RETURN;
-    }
-
-    /* Advance beyond whatever ended our body */
-    next();
-
-    return 0;
-}
-
-/* The top level parse function is similar to __parse_body, except that
- * it does some parse/lex init and assumes that the content is in a
- * vararg function with no defined params.
- */
-
-int vua_parse(u8 *input_data, u64 len, vua_proto_t **proto)
-{
-    parser_t *state = objcache_get(&parser_cache, sizeof(parser_t));
-
-    if(!state)
-        return -1;
-
-    state->func = NULL;
-
-    if (__new_func(state) < 0)
-        return -1;
-
-    vua_lexer_init(&state->lexer, state->func, input_data, len);
-
-    printk("\n");
-
-    vua_lexer_lex(&state->lexer);
-
-    __new_scope(state, 0);
-
-    /* Placeholder FUNCV */
-    vua_bc_emit_func(state);
-
-    __parse_chunk(state);
-
-    *proto = __prototype(state);
-
-    printk("\n\n");
-
-    vua_bc_dump(*proto);
-
-    return 0;
-}
diff --git a/vua/vua_parse.h b/vua/vua_parse.h
deleted file mode 100644 (file)
index d850216..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/* vim: set ts=4 sw=4 sts=4 et : */
-#pragma once
-
-#include "vua_lex.h"
-
-/* Dealing with Expressions
- *
- * Expressions form the bedrock of any language, being the most fundamental
- * parts of statements. The condition in a conditional, either side of an
- * assignment, basic math operations, etc. etc.
- *
- * Because we're going to be generating bytecode, like LuaJIT, we never
- * actually need to have a full parse tree in memory, like we would if we were
- * going to interpret Vua directly. Instead, expression bytecode can be emitted
- * immediately into the function's instruction buffer, and most of the
- * expression comes from register context.
- */
-
-typedef enum {
-  /* Constant expressions must be first and in this order for KPRI */
-  VKNIL,
-  VKFALSE,
-  VKTRUE,
-  VKPRI = VKTRUE,
-  VKSTR,
-  VKNUM,
-  VKLAST = VKNUM,
-  VLOCAL,       /* info = local register, aux = vstack index */
-  VUPVAL,       /* info = upvalue index, aux = vstack index */
-  VGLOBAL,      /* val = string value */
-  VINDEXED,     /* info = table register, aux = index reg/byte/string const */
-  VJMP,         /* info = instruction PC */
-  VRELOCABLE,   /* info = instruction PC */
-  VNONRELOC,    /* info = result register */
-  VCALL,        /* info = instruction PC, aux = base */
-  VVOID
-} expr_type;
-
-/* Expression descriptor. */
-
-typedef struct vua_expression {
-    expr_type type;
-    union {
-        struct {
-            u32 info;
-            u32 aux;
-        } r;
-        vua_tv_t val;
-        u64 uval;
-    } v;
-
-    BCPos true_list;
-    BCPos false_list;
-} expr_t;
-
-/* Order TOK -> BIN_OP and priority struct taken from lj_parse.c */
-
-typedef enum binop {
-       OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW,  /* ORDER ARITH */
-       OPR_CONCAT,
-       OPR_NE, OPR_EQ,
-       OPR_LT, OPR_GE, OPR_LE, OPR_GT,
-       OPR_AND, OPR_OR,
-       OPR_NOBINOPR
-} binop;
-
-typedef struct vua_op_prio {
-    u8 left;
-    u8 right;
-} prio_t;
-
-static const prio_t priority[] = {
-  {6,6}, {6,6}, {7,7}, {7,7}, {7,7},    /* ADD SUB MUL DIV MOD */
-  {10,9}, {5,4},                        /* POW CONCAT (right associative) */
-  {3,3}, {3,3},                         /* EQ NE */
-  {3,3}, {3,3}, {3,3}, {3,3},           /* LT GE GT LE */
-  {2,2}, {1,1}                          /* AND OR */
-};
-
-#define UNARY_PRIORITY 8
-
-u32 vua_parse_expr_binop(parser_t *parser, expr_t *expr, u32 prio);
-int vua_parse_expr(parser_t *parser, expr_t *expr);
-int vua_parse(u8 *input_data, u64 len, vua_proto_t **proto);
diff --git a/vua/vua_str.c b/vua/vua_str.c
deleted file mode 100644 (file)
index a339285..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/* vim: set ts=4 sw=4 sts=4 et : */
-
-#include <kernel.h>
-
-#include <objcache.h>
-
-#include "vua_obj.h"
-#include "vua_hash.h"
-
-DEFINE_OBJCACHE(string_cache);
-
-void vua_str_reset(vua_str_t *str)
-{
-    if (str->len)
-        objcache_free(&string_cache, str->data);
-    str->data = NULL;
-    str->len = 0;
-}
-
-void vua_str_free(vua_str_t *str)
-{
-    objcache_free(&string_cache, str->data);
-    objcache_free(&string_cache, str);
-}
-
-vua_str_t *vua_str_create(char *init_val, u64 starting_len)
-{
-    vua_str_t *ret = objcache_get(&string_cache, sizeof(vua_str_t));
-
-    if(!ret)
-        return NULL;
-
-    if((!init_val) || (starting_len == 0)) {
-        ret->len = 0;
-        return ret;
-    }
-
-    ret->data = objcache_get(&string_cache, starting_len);
-
-    if (!ret->data) {
-        // TODO: Page allocator > 63k strings
-        objcache_free(&string_cache, ret);
-        return NULL;
-    }
-
-    memcpy(ret->data, init_val, starting_len);
-
-    ret->len = starting_len;
-    ret->hash = vua_hash_str(ret, 0);
-
-    return ret;
-}
-
-int vua_str_eq(vua_str_t *a, vua_str_t *b)
-{
-    int i;
-
-    if (a->hash != b->hash)
-        return 0;
-    if (a->len != b->len)
-        return 0;
-
-    for (i = 0; i < a->len; i++) {
-        if (a->data[i] != b->data[i])
-            return 0;
-    }
-
-    return 1;
-}
-
-int vua_str_append(vua_str_t *a, char c)
-{
-    char *new;
-
-    if (a->len % OC_CELL_SIZE == 0) {
-        new = objcache_get(&string_cache, a->len + 1);
-        if (!new)
-            return 0;
-
-        if (a->len) {
-            memcpy(new, a->data, a->len);
-            objcache_free(&string_cache, a->data);
-        }
-
-        a->data = new;
-    }
-
-    a->data[a->len] = c;
-    a->len++;
-
-    return 1;
-}
diff --git a/vua/vua_tab.c b/vua/vua_tab.c
deleted file mode 100644 (file)
index 16cd152..0000000
+++ /dev/null
@@ -1,738 +0,0 @@
-/* vim: set ts=4 sw=4 sts=4 et : */
-
-/*
- * I had to convince myself that combining the hash table and array into a
- * single type, like Lua and LuaJIT do. Fundamentally, I dislike the
- * combination because a hash table and a simple iterative list seem like
- * separate use cases to me.
- *
- * However, after reflection, I think about how often in data structures you
- * want to attach some attributes to a list (i.e. look at almost every struct
- * in this file) and really is
- *
- * { 1, 2, 3, "source" = "src" }
- *
- * worse than
- *
- * { "source" = "src", data = [ 1, 2, 3 ] }
- *
- * ?
- *
- * But past syntax, it seems better to have dedicated list and dict types, like
- * Python because you can have clear definition of concatenation (for example)
- * and a clear definition of iteration.
- *
- * And yet LuaJIT does a pretty good job of determining what exactly should be
- * in the array and what should be hashed. The best asize is essentially the
- * biggest asize that would both have an item in it and that you could
- * currently more than half fill.
- *
- * This means that the basic append case expands, e.g. adding the 4097th item
- * to a list, the asize of 8192 would be chosen because there's an item > 4096,
- * and 2*4097 > 8192.
- *
- * Meanwhile, if you're doing something like { 0 = x, 4096 = y, 8192 = z }, it
- * will choose an asize of 0 because there's no possible asize that you can
- * more than half fill.
- *
- * The iteration case is also handled pretty well here. In the first case, the
- * array part includes every item and they'll be generated in order by
- * iteration.
- *
- * The other weird caveat of Lua tables is that if you remove more than half of
- * the items by setting them to the special value nil, iteration breaks and
- * higher indices can (possibly) be turned into hash keys. I'm not a fan of
- * this behavior, but the fact remains that nil is a special value and
- * inserting it shouldn't really be considered any different than, say, calling
- * "del list[x]" in Python. In short, don't do that. If your algorithm requires
- * you to "delete" items, just mark them with some other not language special
- * value (like 0, or false, or "empty" etc.)
- */
-
-#include <kernel.h>
-#include <objcache.h>
-
-#include "vua_obj.h"
-#include "vua_hash.h"
-#include "vua_test.h"
-
-/* General memory cache for tab structures and small a/h allocs */
-
-DEFINE_OBJCACHE(tab_cache);
-
-/* Define the sizes (in bytes) after which the page allocator should just be
- * used directly instead of the tab cache, right now it's PAGE_SIZE, but we
- * could want to after half a page or some other ratio
- */
-
-#define ASIZE_PAGE_THRESHOLD    PAGE_SIZE
-#define HSIZE_PAGE_THRESHOLD    PAGE_SIZE
-
-/* Default hash table size if not specified on tab creation 64 entries * 16 =
- * 1024 bytes by default
- *
- * Chosen because currently we don't do anything smart with picking a hash
- * table size, or implicitly resize the hash part, but we do create a hash part
- * if there isn't one.
- */
-
-#define DEF_HSIZE               64
-
-/* __cmp functions assume a is of the correct type, but check b and their
- * values match;
- */
-
-static int __cmp_str(vua_tv_t a, vua_tv_t b)
-{
-    if (!tvis_str(b))
-        return 0;
-    return vua_str_eq(tv_str(a), tv_str(b));
-}
-
-static int __cmp_int(vua_tv_t a, vua_tv_t b)
-{
-    /* For right now, all ints are 60 bits packed into the tvalue
-     * Later, this will have to potentially pull all 64 or more
-     * bits out of a pointer to  compare larger values
-     */
-
-    return (a == b);
-}
-
-/* cmp_tv works for any other basic type, nil, true, false, and object pointers
- * (where objects are the same if their pointers are the same)
- */
-
-static int __cmp_tv(vua_tv_t a, vua_tv_t b)
-{
-    return (a == b);
-}
-
-/* Isolated logic of taking a key and finding its place in the table */
-
-/* If it returns non-NULL, then key was present and the return value points to
- * either an array value tv, or a node value tv. (i.e. it works like you'd
- * expect get to work).
- *
- * If the return is NULL and node non-NULL, node is either the head node (and
- * thus will have key == nil) or it's the preceding node that can be appended
- * to.
- *
- * If the return is NULL and node is NULL, then the key wouldn't fit anywhere.
- * If the key was an integer, that means array and hash were too small.  If the
- * key was anything else, the hash was too small.
- */
-
-static inline vua_tv_t *__get(vua_tab_t *tab, vua_tv_t key,
-        vua_tab_node_t **node)
-{
-    int (*cmp)(vua_tv_t a, vua_tv_t b) = __cmp_tv;
-    u64 int_val;
-    u32 hash;
-
-    *node = NULL;
-
-    if (tvis_int(key)) {
-        int_val = tv_int(key);
-        if (int_val < tab->asize)
-            return &tab->array[int_val];
-        hash = vua_hash_int(int_val, 0);
-        cmp = __cmp_int;
-    } else if (tvis_str(key)) {
-        hash = tv_str(key)->hash;
-        cmp = __cmp_str;
-    } else if (tvis_true(key))
-        hash = 1;
-    else if (tvis_false(key))
-        hash = 0;
-    else
-        hash = vua_hash_int((u64) key, 0) ;
-
-    /* If we get here, we're doing a hash lookup */
-
-    if (tab->hmask == 0)
-        return NULL;
-
-    *node = &tab->nodes[hash & tab->hmask];
-
-    /* If the head node is nil, don't bother iterating */
-
-    if (tvis_nil((*node)->key))
-        return NULL;
-
-    while (1) {
-        if (cmp(key, (*node)->key))
-            return &(*node)->val;
-
-        if ((*node)->next == NULL)
-            return NULL;
-
-        *node = (*node)->next;
-    };
-
-    return NULL;
-}
-
-/* Just get existing keys. Returns NULL if you access outside the existing
- * array/hash. Returns a pointer otherwise that may point to a tv_nil value.
- */
-
-vua_tv_t *vua_tab_get(vua_tab_t *tab, vua_tv_t key)
-{
-    vua_tab_node_t *node;
-    return __get(tab, key, &node);
-}
-
-/* Set, but without implicit resize. Either the key already fits or not */
-
-vua_tv_t *__set(vua_tab_t *tab, vua_tv_t key)
-{
-    vua_tab_node_t *node, *new_node;
-    vua_tv_t *ret;
-
-    ret = __get(tab, key, &node);
-
-    if (ret)
-        return ret;
-
-    if (node) {
-        /* Returned nil head node */
-        if (tvis_nil(node->key)) {
-            node->key = key;
-            return &node->val;
-        /* Returned preceding node */
-        } else {
-            new_node = objcache_get(&tab_cache, sizeof(vua_tab_node_t));
-            if (!new_node)
-                return NULL;
-
-            node->next = new_node;
-
-            new_node->key = key;
-            new_node->next = NULL;
-            new_node->val = nil_tv;
-            return &new_node->val;
-        }
-    }
-
-    return NULL;
-}
-
-void __free_array_part(vua_tv_t *array, u32 asize)
-{
-    if (asize >= ASIZE_PAGE_THRESHOLD)
-        page_vmalloc_free(array, asize >> PAGE_SHIFT);
-    else
-        objcache_free(&tab_cache, array);
-}
-
-void __free_hash_part(vua_tab_node_t *nodes, u32 hsize)
-{
-    vua_tab_node_t *node, *tmp;
-    u32 i;
-
-    for (i = 0; i < hsize; i++) {
-        node = &nodes[i];
-
-        if (tvis_nil(node->key))
-            continue;
-
-        node = node->next;
-
-        while (node) {
-            tmp = node->next;
-            objcache_free(&tab_cache, node);
-            node = tmp;
-        }
-    }
-
-    if (hsize >= HSIZE_PAGE_THRESHOLD)
-        page_vmalloc_free(nodes, (hsize >> PAGE_SHIFT));
-    else
-        objcache_free(&tab_cache, nodes);
-}
-
-/* Allocate a new array part. Intelligently deal with either vmalloc or
- * objcache based on the sizes of the relevant parts.
- *
- * Returns 0 if everything worked, -1 otherwise with old data intact.
- */
-
-static int __new_array_part(vua_tab_t *tab, u32 new_size)
-{
-    vua_tv_t *part;
-    int old_bytes = (tab->asize * sizeof(vua_tv_t));
-    int new_bytes = (new_size * sizeof(vua_tv_t));
-
-    vua_tab_node_t *cur, *prev;
-    u32 hsize, i;
-
-    if (new_size >= ASIZE_PAGE_THRESHOLD) {
-        if (tab->asize >= ASIZE_PAGE_THRESHOLD) {
-            /* If both are vmallocs, vrealloc handles the (zero) copy */
-            part = page_vrealloc(tab->array, (old_bytes >> PAGE_SHIFT), (new_bytes >> PAGE_SHIFT));
-            if (!part)
-                return -1;
-
-            page_vmalloc_free(tab->array, (old_bytes >> PAGE_SHIFT));
-
-        } else {
-            /* New size is big, old size is small */
-            part = page_vmalloc(new_size / PAGE_SIZE);
-
-            if (!part)
-                return -1;
-
-            if (tab->array) {
-                memcpy(part, tab->array, old_bytes);
-                objcache_free(&tab_cache, tab->array);
-            }
-        }
-    } else {
-        part = objcache_get(&tab_cache, new_size * sizeof(vua_tv_t));
-
-        if (!part)
-            return -1;
-
-        if (tab->array) {
-            if (old_bytes >= ASIZE_PAGE_THRESHOLD) {
-                /* Old size is big, new size is small */
-                memcpy(part, tab->array, new_bytes);
-                page_vmalloc_free(tab->array, old_bytes / PAGE_SIZE);
-            } else {
-                /* Both are small */
-                memcpy(part, tab->array, min(new_bytes, old_bytes));
-                objcache_free(&tab_cache, tab->array);
-            }
-        }
-    }
-
-    /* memset 0, thankfully equivalent to setting to NIL */
-    if (new_bytes > old_bytes)
-        memset(&part[tab->asize], 0, (new_bytes - old_bytes));
-
-    tab->array = part;
-    tab->asize = new_size;
-
-    /* Now we have to search the hash part and move any integer keys that will
-     * fit into our new array
-     */
-
-    hsize = tab->hmask ? tab->hmask + 1 : 0;
-    for (i = 0; i < hsize; i++) {
-        cur = &tab->nodes[i];
-        prev = NULL;
-
-        if (tvis_nil(cur->key))
-            continue;
-
-        do {
-            if ((tvis_int(cur->key))&&(tv_int(cur->key) < tab->asize))
-                tab->array[tv_int(cur->key)] = cur->val;
-
-            if (prev)
-                prev->next = cur->next;
-
-            prev = cur;
-            cur = cur->next;
-        } while(cur);
-    }
-
-    return 0;
-}
-
-/* Allocate new hash part, similar to the above. The only difference being that
- * we can't use zero copy / memcpy to move over data because each item has to
- * be re-hashed to take advantage of the new bits
- */
-
-static int __new_hash_part(vua_tab_t *tab, u32 new_hsize)
-{
-    vua_tab_node_t *new_nodes, *cur;
-    vua_tab_node_t *old_nodes = tab->nodes;
-    vua_tv_t *val;
-
-    u32 old_hsize = tab->hmask ? tab->hmask + 1 : 0;
-
-    u32 new_bytes = new_hsize * sizeof(vua_tab_node_t);
-
-    u32 i;
-
-    if (new_hsize > HSIZE_PAGE_THRESHOLD)
-        new_nodes = page_vmalloc(new_bytes >> PAGE_SHIFT);
-    else
-        new_nodes = objcache_get(&tab_cache, new_bytes);
-
-    if (!new_nodes)
-        return -1;
-
-    memset(new_nodes, 0, new_bytes);
-
-    tab->nodes = new_nodes;
-    tab->hmask = new_hsize - 1;
-
-    for (i = 0; i < old_hsize; i++) {
-        cur = &old_nodes[i];
-
-        if (tvis_nil(cur->key))
-            continue;
-
-        while (cur) {
-
-            /* Should only fail because we're out of memory, but we can't free
-             * as we go without significantly complicating the free on error
-             * path to restore already moved items.
-             */
-
-            val = __set(tab, cur->key);
-
-            if (!val)
-                goto cleanup;
-
-            *val = cur->val;
-            cur = cur->next;
-        }
-    }
-
-    if (old_nodes)
-        __free_hash_part(old_nodes, old_hsize);
-
-    return 0;
-
-cleanup:
-    __free_hash_part(new_nodes, new_hsize);
-
-    tab->nodes = old_nodes;
-    tab->hmask = old_hsize - 1;
-
-    return -1;
-}
-
-vua_tab_t *vua_tab_resize(vua_tab_t *tab, u32 asize, u32 hsize)
-{
-    u32 old_hsize;
-
-    if (tab->asize != asize) {
-        if (__new_array_part(tab, asize) < 0)
-            return NULL;
-    }
-
-    old_hsize = tab->hmask ? tab->hmask + 1 : 0;
-
-    if (hsize != old_hsize) {
-        if (__new_hash_part(tab, hsize) < 0)
-            return NULL;
-    }
-
-    return tab;
-}
-
-static void __count_int(u32 *bins, u32 val)
-{
-    u32 b;
-
-    if (val == 0)
-        b = 0;
-    else
-        b = 32 - __builtin_clz(val);
-
-    if (b < TAB_MAX_ABITS)
-        bins[b]++;
-}
-
-/* Given the distribution of integer keys and the total number of them, pick an
- * asize
- */
-
-static u32 __best_asize(u32 *bins, u32 total)
-{
-    u32 b, bmax, sum, best_asize = 0;
-
-    bmax = 1;
-    sum = 0;
-
-    for (b = 0; b < TAB_MAX_ABITS; b++) {
-        sum += bins[b];
-
-        /* If there's an item in the bin and we could fill the an array this
-         * size at least half full, then this is a good asize choice
-         */
-
-        if ((bins[b])&&((sum * 2) > bmax))
-            best_asize = bmax;
-
-        bmax <<= 1;
-
-        /* If we've covered every item, or we couldn't half fill the next
-         * largest total size, then we're done looking
-         */
-
-        if ((sum == total)||(total * 2) < bmax)
-            break;
-    }
-
-    return best_asize;
-}
-
-/* Given an existing table, and a new integer key, pick an asize
- *
- * LuaJIT does this by iterating through every key and sorting them into bins
- * based on what asize they would need to fit into the array part. It seems a
- * bit exhaustive to me, but it's impossible to avoid looking at every key in
- * the table without making further restrictions on the table like you can only
- * add items in order, or that you have specify the max asize on creation and
- * those restrictions aren't particularly attractive. After you make peace with
- * the fact that this is going to be linear over all keys, using a hundred+
- * bytes of stack doesn't seem too bad.
- */
-
-static u32 __asize(vua_tab_t *tab, vua_tv_t key)
-{
-    vua_tab_node_t *node;
-    u32 bins[TAB_MAX_ABITS] = { 0 };
-    u32 i, b, bmax, total;
-
-    b = 0;
-    bmax = 1;
-    total = 0;
-
-    /* Fill in bins for current array part */
-
-    for (i = 0; i < tab->asize; i++) {
-        if (i == bmax) {
-            bmax <<= 1;
-            b++;
-        }
-
-        if (tvis_nil(tab->array[i]))
-            continue;
-
-        bins[b]++;
-        total++;
-    }
-
-    /* Fill in bins for current hash part */
-
-    if (tab->hmask) {
-        for (i = 0; i < (tab->hmask + 1); i++) {
-            node = &tab->nodes[i];
-
-            if (tvis_nil(node->key))
-                continue;
-
-            do {
-                if (tvis_int(node->key)) {
-                    __count_int(bins, tv_int(node->key));
-                    total++;
-                }
-
-                node = node->next;
-            } while (node);
-        }
-    }
-
-    /* Lastly, add our new key */
-
-    __count_int(bins, tv_int(key));
-    total++;
-
-    /* At this point, bins has been fully fleshed out and total is the number
-     * of actual int keys in the entire table.
-     */
-
-    return  __best_asize(bins, total);
-}
-
-/* Setting keys. Unlike __set, this will implicitly try to resize
- * the table to fit integers into the array part, and create a
- * hash part if none exists.
- */
-
-vua_tv_t *vua_tab_set(vua_tab_t *tab, vua_tv_t key)
-{
-    u32 asize;
-
-    /* If this key is an integer, see if we should resize
-     * the array part to fit it in.
-     */
-
-    if (tvis_int(key)) {
-        if (int_tv(key) >= tab->asize) {
-            asize = __asize(tab, key);
-            if (asize != tab->asize) {
-                vua_tab_resize(tab, asize, tab->hmask ? tab->hmask + 1 : 0);
-                return __set(tab, key);
-            }
-        } else
-            return __set(tab, key);
-    }
-
-    /* If it's not an int, or is an int that didn't fit into the array part
-     * then it needs to go into the hash part
-     */
-
-    if (!tab->hmask)
-        vua_tab_resize(tab, tab->asize, DEF_HSIZE);
-
-    return __set(tab, key);
-}
-
-vua_tab_t *vua_tab_new(u32 asize, u32 hsize)
-{
-    vua_tab_t *ret;
-
-    if (asize > TAB_MAX_ASIZE)
-        return NULL;
-
-    if (hsize > TAB_MAX_HSIZE)
-        return NULL;
-
-    ret = objcache_get(&tab_cache, sizeof(vua_tab_t));
-
-    if (!ret)
-        return NULL;
-
-    memset(ret, 0, sizeof(vua_tab_t));
-
-    return vua_tab_resize(ret, asize, hsize);
-}
-
-void vua_tab_free(vua_tab_t *tab)
-{
-    if (tab->array)
-        __free_array_part(tab->array, tab->asize);
-
-    if (tab->nodes)
-        __free_hash_part(tab->nodes, tab->hmask + 1);
-
-    objcache_free(&tab_cache, tab);
-}
-
-#ifdef TEST_VUA_TAB
-
-int __alen(vua_tab_t *tab)
-{
-    int len = 0;
-    int i;
-
-    for( i = 0; i < tab->asize; i++) {
-        if (!tvis_nil(tab->array[i]))
-            len++;
-    }
-
-    return len;
-}
-
-int __hlen(vua_tab_t *tab)
-{
-    vua_tab_node_t *node;
-    int len = 0;
-    int i;
-
-    for (i = 0; i < (tab->hmask ? tab->hmask + 1: 0); i++) {
-        node = &tab->nodes[i];
-
-        if(tvis_nil(node->key))
-            continue;
-
-        do {
-            len++;
-            node = node->next;
-        } while(node);
-    }
-
-    return len;
-}
-
-void test_vua_tab(void)
-{
-    vua_tab_t *tab = vua_tab_new(0, 0);
-    vua_str_t *keystr = vua_str_create("Key", 3);
-    vua_str_t *valstr = vua_str_create("Value", 5);
-    vua_tab_node_t *node;
-    vua_tv_t *ret;
-    int i;
-
-    if(!tab) {
-        printk("Failed to alloc\n");
-        return;
-    }
-
-    ret = vua_tab_set(tab, int_tv(0));
-    *ret = int_tv(0x1000);
-
-    ret = __get(tab, int_tv(0), &node); 
-
-    assert(tv_int(*ret) == 0x1000);
-    assert(__alen(tab) == 1);
-    assert(__hlen(tab) == 0);
-    assert(tab->asize == 1);
-
-    ret = vua_tab_set(tab, int_tv(0));
-    *ret = int_tv(0x2000);
-
-    ret = __get(tab, int_tv(0), &node);
-
-    assert(tv_int(*ret) == 0x2000);
-    assert(__alen(tab) == 1);
-    assert(__hlen(tab) == 0);
-    assert(tab->asize == 1);
-
-    ret = vua_tab_set(tab, str_tv(keystr));
-    *ret = str_tv(valstr);
-
-    ret = __get(tab, str_tv(keystr), &node);
-
-    assert(vua_str_eq(tv_str(*ret), valstr));
-    assert(__alen(tab) == 1);
-    assert(__hlen(tab) == 1);
-    assert(tab->asize == 1);
-
-    ret = vua_tab_set(tab, int_tv(1));
-    *ret = int_tv(1);
-
-    assert(tab->asize == 2);
-
-    ret = vua_tab_set(tab, int_tv(2));
-    *ret = int_tv(1);
-
-    ret = vua_tab_set(tab, int_tv(3));
-    *ret = int_tv(1);
-
-    assert(__alen(tab) == 4);
-    assert(tab->asize == 4);
-
-    /* Adding 16 is too far out for expanding asize */
-    ret = vua_tab_set(tab, int_tv(16));
-    *ret = int_tv(1);
-
-    assert(__alen(tab) == 4);
-    assert(tab->asize == 4);
-
-    /* But getting 16 should still work */
-    ret = __get(tab, int_tv(16), &node);
-    assert(tv_int(*ret) == 1);
-
-    /* And adding 17-31, asize should expand */
-    for (i = 17; i < 32; i++) {
-        ret = vua_tab_set(tab, int_tv(i));
-        *ret = int_tv(i);
-    }
-
-    assert(tab->asize == 32);
-    assert(__alen(tab) == 20);
-
-    vua_tab_resize(tab, tab->asize, tab->hmask ? (tab->hmask + 1) << 1: 1);
-
-    /* Repeat above to make sure resize retained values */
-    ret = __get(tab, str_tv(keystr), &node);
-
-    assert(vua_str_eq(tv_str(*ret), valstr));
-    assert(__alen(tab) == 20);
-    assert(__hlen(tab) == 1);
-
-    vua_tab_free(tab);
-    vua_str_free(keystr);
-    vua_str_free(valstr);
-}
-#endif
diff --git a/vua/vua_test.h b/vua/vua_test.h
deleted file mode 100644 (file)
index f7e2dd4..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/* vim: set ts=4 sw=4 sts=4 et : */
-
-#define TEST_VUA_TAB
-
-#ifdef TEST_VUA_TAB
-void test_vua_tab(void);
-#else
-#define test_vua_tab(...)
-#endif
diff --git a/vua/vua_vm.asm b/vua/vua_vm.asm
deleted file mode 100644 (file)
index 6795c78..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/* vim: set ts=4 sw=4 sts=4 et : */
-/* VuaVM - basic bytecode interpreter for Vua */
-
-/* Obviously inspired by LuaJIT, but since we can count on never encountering
- * a C function that isn't under control we have much more freedom about ABI
- * conventions and can potentially use every register as we please.
- */
-
-/* Some lessons learned from reading LuaJIT:
- *
- * - Branch predictability is paramount, which is why instruction dispatch is
- * done in place rather than at the top of a big unpredictable loop.
- */
-
-.macro next_ins
-    
-.endm
-
-.global vm_entry
-vm_entry:
-    jmp .
diff --git a/vua/vua_vm.h b/vua/vua_vm.h
deleted file mode 100644 (file)
index 3eee47c..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/* vim: set ts=4 sw=4 sts=4 et : */
-
-#pragma once
-
-#include "vua_obj.h"
-
-/* Encapsulate a stopped interpreter thread */
-
-typedef struct vua_thread {
-    BCIns *pc;
-    void *stack;
-} vua_thread_t;
-
-/* Encapsulate a running interpreter context */
-
-typedef struct vua_state {
-    vua_thread_t thread;
-} vua_state_t;
-
-extern u64 vm_entry(vua_state_t *state, vua_proto_t *proto);