potion  0.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
vm.c File Reference

the vm execution loop, the "bytecode interpreter". More...

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <math.h>
#include "potion.h"
#include "internal.h"
#include "opcodes.h"
#include "asm.h"
#include "khash.h"
#include "table.h"
#include <udis86.h>
#include <dlfcn.h>
#include "vm-dis.c"
+ Include dependency graph for vm.c:

Go to the source code of this file.

Macros

#define DEBUG_IN_C
 
#define STRINGIFY(_obj)   ({PN str=potion_send(_obj,PN_string);str?PN_STR_PTR(str):"";})
 
#define STACK_MAX   4096
 
#define JUMPS_MAX   1024
 
#define CASE_OP(name, args)   case OP_##name: target->op[OP_##name]args; break;
 
#define PN_VM_MATH2(name, oper)
 
#define PN_VM_MATH3(name, oper, ov)   PN_VM_MATH2(name, oper)
 
#define PN_VM_NUMCMP(cmp)
 
#define PN_VM_CMP(cmp)
 
#define SWITCH_START(op)   switch (op.code) {
 
#define CASE(op, block)   case OP_##op: block; break;
 
#define SWITCH_END   }
 

Enumerations

enum  {
  DBG_STEP = 0, DBG_NEXT, DBG_RUN, DBG_QUIT,
  DBG_EXIT
}
 

Functions

void potion_vm_init (Potion *P)
 
PN potion_vm_proto (Potion *P, PN cl, PN self,...)
 entrypoint for all bytecode methods from the C api. More...
 
PN potion_vm_class (Potion *P, PN cl, PN self)
 implements the class op creates a class (or type) from a closure and parent class with obj ivars More...
 
PN potion_vm_eq (Potion *P, PN a, PN b)
 
PN potion_vm_neq (Potion *P, PN a, PN b)
 
static PN potion_sig_check (Potion *P, struct PNClosure *cl, int arity, int numargs)
 
PN potion_debug (Potion *P, struct PNProto *f, PN self, PN_OP op, PN *reg, PN *stack)
 
PN potion_vm (Potion *P, PN proto, PN self, PN vargs, PN_SIZE upc, PN *upargs)
 the bytecode run-loop More...
 

Variables

static PN(* pn_readline )(Potion *, PN, PN, PN)
 
struct {
   const char *   name
 
   const u8   args
 
potion_ops []
 
PNTarget potion_target_x86
 

Detailed Description

the vm execution loop, the "bytecode interpreter".

correct but slower than the jit.

usage: -B, -Dt or automatically when no jit is available for your architecture.

Potion uses a two-address register-based bytecode VM that is nearly a word-for-word copy of Lua's. The code is all different, but the bytecode is nearly identical. See http://luaforge.net/docman/83/98/ANoFrillsIntroToLua51VMInstructions.pdf or http://www.lua.org/doc/jucs05.pdf

It is even more space-efficient than a simple stack-based VM, and of course faster. Each 32-bit op word contains the op and its two arguments. I.e. the first address R(A) is always modified, as in a stack vm. A full non-destructive three-address scheme R(D) = OP R(A), R(B) is not needed.

  • MOVE (pos) copy value between registers R(A)=R(B)
  • LOADK (pos, need) load a constant into a register R(A)=value[B]
  • LOADPN (pos) load a PN value into a register R(A)=B
  • SELF (pos, need) prepare an object method for calling R(A+1) := R(B); R(A) := R(B)[RK(C)]
  • GETLOCAL (pos, regs) read a local into a register R(A)=local[B])
  • SETLOCAL (pos, regs) write a register value into a local local[A]=R(B)
  • GETUPVAL (pos, lregs) read an upvalue (upper scope) R(A)=upval[B]
  • SETUPVAL (pos, lregs) write to an upvalue upval[A]=R(B)
  • GLOBAL (pos, need) returns a global (for get or set) name R(A)= value R(B)
  • NEWTUPLE (pos, need) create tuple R(A)=()
  • GETTUPLE (pos, need) get tuple key R(A)=R(A)(B&1024?R(B):B)
  • SETTUPLE (pos, need) write register into tuple key R(A)=push(R(A), R(B)
  • GETTABLE (pos, need) get table entry R(A)=R(A){B}
  • SETTABLE (pos, need) write register into a table entry R(A) = R(A){R(A+1)} = R(B)
  • NEWLICK (pos, need) create lick. R(A) := {} (size = B,C)
  • GETPATH (pos, need) read obj field obj_get(R(A), R(B))
  • SETPATH (pos, need) write into obj field obj_set(R(A), R(A+1), R(B))
  • ADD (pos, need) R(A) = R(A) + R(B)
  • SUB (pos, need) R(A) = R(A) - R(B)
  • MULT (pos, need) -"-
  • DIV (pos, need)
  • REM (pos, need)
  • POW (pos, need)
  • NOT (pos) R(A) = !R(A)
  • CMP (pos) R(A) = int( R(B) - R(A) )
  • NEQ (pos) R(A) = R(A) != R(B)
  • EQ (pos) R(A) = R(A) == R(B)
  • LT (pos) R(A) = R(A) < R(B)
  • LTE (pos) R(A) = R(A) <= R(B)
  • GT (pos) R(A) = R(A) > R(B)
  • GTE (pos) R(A) = R(A) >= R(B)
  • BITN (pos, need) R(A) = ~R(B)
  • BITL (pos, need) R(A) = R(A) << R(B)
  • BITR (pos, need) R(A) = R(A) >> R(B)
  • DEF (pos, need) def_method(R(A), R(A+1), R(B)) define a method for an object
  • BIND (pos, need) bind(R(A), R(B)) method lookup for receiver A and message B http://piumarta.com/software/cola/colas-whitepaper.pdf
  • MSG (pos, need) message(R(A), R(B)) call a method of an object
  • JMP (pos, jmps, offs, &jmpc) pos += R(A)
  • TEST (pos) R(A) = bool R(A)
  • TESTJMP (pos, jmps, offs, &jmpc) if R(A) pos += R(B)
  • NOTJMP (pos, jmps, offs, &jmpc) if !R(A) pos += R(B)
  • NAMED (pos, need) assign named args before a CALL
  • CALL (pos, need) call a function. R(A),...:= R(A)(R(A+1),...,R(A+B-1)
  • CALLSET (pos, need) get default writer for R(B) R(A)=get_callset(R(B))
  • TAILCALL(pos, need) ? jumps back to the function entry (TODO)
  • RETURN (pos) return R(A), ... ,R(A+B-2)
  • PROTO (&pos, lregs, need, regs) define a method prototype
  • CLASS (pos, need) R(A) = vm_class(R(B), R(A)) creates class from closure B and parent A
  • DEBUG (pos) set ast to lineno

(c) 2008 why the lucky stiff, the freelance professor (c) 2013-2015 by perl11 org

Definition in file vm.c.

Macro Definition Documentation

#define DEBUG_IN_C

Definition at line 95 of file vm.c.

#define STRINGIFY (   _obj)    ({PN str=potion_send(_obj,PN_string);str?PN_STR_PTR(str):"";})

Definition at line 116 of file vm.c.

#define STACK_MAX   4096

Definition at line 216 of file vm.c.

#define JUMPS_MAX   1024

Definition at line 217 of file vm.c.

#define CASE_OP (   name,
  args 
)    case OP_##name: target->op[OP_##name]args; break;

Definition at line 219 of file vm.c.

#define PN_VM_MATH2 (   name,
  oper 
)
Value:
if (PN_IS_INT(reg[op.a]) && PN_IS_INT(reg[op.b])) \
reg[op.a] = PN_NUM(PN_INT(reg[op.a]) oper PN_INT(reg[op.b])); \
else { \
PN_CHECK_NUM(reg[op.a]); \
PN_CHECK_NUM(reg[op.b]); \
reg[op.a] = potion_obj_##name(P, reg[op.a], reg[op.b]); \
}
const char * name
Definition: vm.c:112
#define PN_INT(x)
Definition: potion.h:205
#define PN_NUM(i)
Definition: potion.h:204
#define PN_CHECK_NUM(obj)
Definition: potion.h:177
#define PN_IS_INT(v)
Definition: potion.h:162

Definition at line 369 of file vm.c.

#define PN_VM_MATH3 (   name,
  oper,
  ov 
)    PN_VM_MATH2(name, oper)

Definition at line 399 of file vm.c.

#define PN_VM_NUMCMP (   cmp)
Value:
if (PN_IS_INT(reg[op.a]) && PN_IS_INT(reg[op.b])) \
reg[op.a] = PN_BOOL(reg[op.a] cmp reg[op.b]); \
else { \
PN_CHECK_NUM(reg[op.a]); \
PN_CHECK_NUM(reg[op.b]); \
reg[op.a] = PN_BOOL(PN_DBL(reg[op.a]) cmp PN_DBL(reg[op.b])); \
}
#define PN_BOOL(v)
Definition: potion.h:158
#define PN_DBL(num)
Definition: potion.h:206
#define PN_CHECK_NUM(obj)
Definition: potion.h:177
#define PN_IS_INT(v)
Definition: potion.h:162

Definition at line 403 of file vm.c.

#define PN_VM_CMP (   cmp)
Value:
reg[op.a] = cmp ? potion_vm_eq(P, reg[op.a], reg[op.b]) \
: potion_vm_neq(P, reg[op.a], reg[op.b]);
PN potion_vm_neq(Potion *P, PN a, PN b)
Definition: vm.c:427
PN potion_vm_eq(Potion *P, PN a, PN b)
Definition: vm.c:416

Definition at line 412 of file vm.c.

#define SWITCH_START (   op)    switch (op.code) {
#define CASE (   op,
  block 
)    case OP_##op: block; break;
#define SWITCH_END   }

Enumeration Type Documentation

anonymous enum
Enumerator
DBG_STEP 
DBG_NEXT 
DBG_RUN 
DBG_QUIT 
DBG_EXIT 

Definition at line 98 of file vm.c.

Function Documentation

void potion_vm_init ( Potion P)

Definition at line 129 of file vm.c.

PN potion_vm_proto ( Potion P,
PN  cl,
PN  self,
  ... 
)

entrypoint for all bytecode methods from the C api.

See also
potion_test_eval()
Parameters
clPNClosure to be called
selfPN - sets self (ignored for most user defined functions). if self is a int < 10 it defines the number of args provided
...- arguments to the cl
  add = potion_eval(P, potion_str(P, "(x=N|y=N): x + y."));
  addfn = PN_CLOSURE_F(add); // i.e. potion_vm_proto
  num = addfn(P, add, 2, PN_NUM(3), PN_NUM(5));
  num = addfn(P, add, 1, PN_NUM(3)); // 1 arg provided, 2nd arg=0

Note that methods with optional arguments ... are not very safe to call. potion_vm_proto() does not know the number of arguments on the stack. So it checks for all optional args the matching type. You can help by providing numargs as self argument if numargs < 10.

Definition at line 159 of file vm.c.

PN potion_vm_class ( Potion P,
PN  cl,
PN  self 
)

implements the class op creates a class (or type) from a closure and parent class with obj ivars

Definition at line 203 of file vm.c.

PN potion_vm_eq ( Potion P,
PN  a,
PN  b 
)

Definition at line 416 of file vm.c.

PN potion_vm_neq ( Potion P,
PN  a,
PN  b 
)

Definition at line 427 of file vm.c.

static PN potion_sig_check ( Potion P,
struct PNClosure cl,
int  arity,
int  numargs 
)
static

Definition at line 438 of file vm.c.

PN potion_debug ( Potion P,
struct PNProto f,
PN  self,
PN_OP  op,
PN reg,
PN stack 
)

Definition at line 456 of file vm.c.

PN potion_vm ( Potion P,
PN  proto,
PN  self,
PN  vargs,
PN_SIZE  upc,
PN upargs 
)

the bytecode run-loop

Definition at line 594 of file vm.c.

Variable Documentation

PN(* pn_readline)(Potion *, PN, PN, PN)
static

Definition at line 105 of file vm.c.

const char* name

Definition at line 112 of file vm.c.

const u8 args

Definition at line 113 of file vm.c.

const { ... } potion_ops[]
PNTarget potion_target_x86