📄 vm_interpret.cpp
字号:
/*
*
* vm_interpret.cpp
*
* Copyright (c) 2001, 2002
* Andrew Fedoniouk - andrew@terra-informatica.org
* Portions: Serge Kuznetsov - kuznetsov@deeptown.org
*
* See the file "COPYING" for information on usage
* and redistribution of this file
*
*/
//|
//| bytecode interpreter
//|
#include <stdarg.h>
#include "c-smile.h"
#include "arithmetic.h"
#include "vm.h"
#include "tool.h"
#include "scanner.h"
#include "streams.h"
#if !defined ( _WIN32 )
#define _vsnprintf vsnprintf
#endif
namespace c_smile
{
#define iszero(x) ((x)->v_type == DT_INTEGER && (x)->v.v_integer == 0 )
inline bool
istrue ( VALUE& v )
{
return bool ( v );
}
//function frame description
#define FRAME_PCOFF 0
#define FRAME_FPOFF 1
#define FRAME_MSPOS 2
#define FRAME_EHPOS 3
#define FRAME_ARGC 4
#define FRAME_SIZE 5
#define PUSH_SYMBOL ( sym ) \
{ \
++sp; \
sp->v_type = DT_SYMBOL; \
sp->v.v_symbol = ( sym ); \
}
#define PUSH(v) *( ++sp ) = v
#define POP --sp
#define PUSHN(n) ( sp += ( n ) )
#define POPN(n) ( sp -= ( n ) )
#define SP(n) ( *( sp - ( n ) ) )
#define FP(n) ( *( fp - ( n ) ) )
#define CHECKSTACK(n) {if ( sp + ( n ) > stktop ) stackover (); }
#define CHECKTYPE(o,t) {if ( sp [-(o)].v_type != t ) badtype ( o, t ); }
#define ARG(n) (*( fp - (( fp - FRAME_ARGC )->v.v_integer - (n) + (FRAME_SIZE - 1))))
char *nameoftype ( int type );
bool VM::trace = false;
bool VM::decode = false;
VM::VM ( int smax, int eh_smax, int m_smax ) :
code ( NULL ),
package ( 0 ),
line_num ( -1 ),
eh_size ( eh_smax ),
eh_pos ( -1 ),
m_stack_size ( m_smax ),
m_stack_pos ( -1 ),
ready_for_gc ( true ),
thread ( 0 ),
native_code ( 0 ),
running ( true )
{
// allocate the stack
stkbase = new VALUE [ smax ];
stktop = stkbase + smax;
setup_stack ();
eh = new error_handler [ eh_size ];
m_stack = new MUTEX_PTR [ m_smax ];
sal::critical_section cs ( all_guard );
all.add_to_tail ( this );
}
VM::~VM ()
{
if ( running )
{
exit ( 1 );
}
sal::critical_section cs ( all_guard );
{
iterator<VM*> it ( all );
foreach ( it )
{
if ( it.current () == this )
{
it.remove_current ();
break;
}
}
}
delete [ ] stkbase;
delete [ ] eh;
delete [ ] m_stack;
}
// execute - execute a bytecode function
bool
VM::execute ( PACKAGE *package, const char *name, int argc, VALUE *argv )
{
symbol_t sym;
if ( !voc.find ( name, sym ) )
return false;
try
{
bool result = true;
if ( !result || !start_call ( package, sym, argc, argv ) )
return false;
return execute_call ();
}
catch ( VM_RTE& rte )
{
serr->put ( rte.report () );
serr->put ( stack_trace () );
}
return false;
}
// execute_init - execute a bytecode function
bool
VM::execute_init ( PACKAGE *package )
{
try
{
bool result = true;
if ( start_init ( package ) )
return execute_call ();
}
catch ( VM_RTE& rte )
{
serr->put ( rte.report () );
}
return false;
}
bool
VM::start_init ( PACKAGE *pkg )
{
package = pkg;
if ( package->init_code == 0 )
return false;
// setup the stack
sp = fp = stkbase;
PUSH ( package->init_code );
PUSH ( pkg );
PUSH ( 1 );
return true;
}
// start_call - start a function call
bool
VM::start_call ( PACKAGE *pkg, symbol_t sym, int argc, VALUE *argv )
{
package = pkg;
ENTRY e = package->find ( sym );
// lookup the symbol
if ( !e.is_valid () )
e = std->find ( sym );
if ( !e.is_valid () ) return false;
// setup the stack
setup_stack ();
PUSH ( *e.value () );
PUSH ( pkg );
for ( int i = 0; i < argc; i++ )
PUSH ( argv [ i ] );
PUSH ( argc + 1 );
return true;
}
// start_call - start a function call
bool
VM::start_call ( CODE *c, int argc, VALUE *argv )
{
PUSH ( c );
PUSH ( c->klass () );
for ( int i = 0; i < argc; i++ )
PUSH ( argv [ i ] );
PUSH ( argc + 1 );
return true;
}
// start_call - start a function call
bool
VM::start_call ( CODE *c, THING *obj, int argc, VALUE *argv )
{
PUSH ( c );
PUSH ( *obj );
for ( int i = 0; i < argc; i++ )
PUSH ( argv [ i ] );
PUSH ( argc + 1 );
return true;
}
// start_call - start method call
bool
VM::start_call ( CODE *c, VALUE& v_this, int argc, VALUE *argv )
{
PUSH ( c );
PUSH ( v_this );
for ( int i = 0; i < argc; i++ )
PUSH ( argv [ i ] );
PUSH ( argc + 1 );
return true;
}
// execute_call - execute a function call
bool
VM::execute_call ()
{
int n = SP ( 0 ) .v.v_integer;
POP;
if ( SP ( n ) .v_type == DT_CODE )
{
if ( SP ( n ) .v.v_code->is_native () )
{
VALUE v = invoke_native ( SP ( n ) .v.v_code, n - 1, &SP ( n - 2 ) );
POPN ( n );
SP ( 0 ) = v;
return true;
}
else
{
interpret ( n );
return true;
}
}
return false;
}
VALUE
VM::invoke_native ( CODE *c, int argc, VALUE* argv )
{
CODE *save = native_code;
native_code = c;
VALUE v = ( *native_code->native () ) ( argc, argv );
native_code = save;
return v;
}
// interpret - interpret bytecode instructions
void
VM::interpret ( int argc )
{
VALUE * return_fp = fp;
OBJECT *obj;
int n;
int woperand;
running = true;
// make a dummy call frame
CHECKSTACK ( FRAME_SIZE );
code = SP ( argc ) .v.v_code;
package = code->klass () ->get_package ();
PUSH ( ( int ) argc ); // argument count
PUSH ( eh_pos );
PUSH ( m_stack_pos );
PUSH ( int ( fp - stkbase ) ); // old fp
PUSH ( int ( pc - cbase ) ); // old pc
cbase = pc = ( unsigned char * ) code->bytecode ();
fp = sp;
// execute each instruction
start:
ready_for_gc = true;
try
{
for (;; )
{
if ( !ready_for_gc )
{
ready_for_gc = true;
if ( memory.gc_active )
memory.notification.signal ();
else if ( memory.allocated + other_allocs > memory.gc_threshold )
memory.gc ();
}
#ifdef DECODE_TRACE
decode_instruction ( code, pc - ( unsigned char * ) code->bytecode () );
#endif
switch ( *pc++ )
{
case OP_CALL:
opCALL ();
break;
case OP_RETURN:
if ( !opRETURN () || return_fp == fp )
goto STOP;
break;
case OP_SEND:
assert ( false );
break;
case OP_VREF:
opVREF ();
break;
case OP_VSET:
opVSET ();
break;
case OP_REF:
{
woperand = getwoperand ();
ARRAY &a = *package->literals;
VALUE *v1 = &a [ woperand ];
int t = v1->v_type;
VALUE *v = v1->v.v_var.value ();
SP ( 0 ) = *v;
}
break;
case OP_SET:
woperand = getwoperand ();
*( ( *package->literals ) [ woperand ] .v.v_var.value () ) = SP ( 0 );
break;
case OP_MREF:
n = FP ( FRAME_ARGC ) .v.v_integer + FRAME_ARGC;
obj = FP ( n ) .v.v_object;
SP ( 0 ) = obj->members [ *pc++ ];
break;
case OP_MSET:
n = FP ( FRAME_ARGC ) .v.v_integer + FRAME_ARGC;
obj = FP ( n ) .v.v_object;
obj->members [ *pc++ ] = SP ( 0 );
break;
case OP_AREF:
n = *pc++;
if ( n >= FP ( FRAME_ARGC ) .v.v_integer )
{
SP ( 0 ) = undefined;
}
else
{
SP ( 0 ) = ARG ( n );
}
break;
case OP_ASET:
n = *pc++;
if ( n >= FP ( FRAME_ARGC ) .v.v_integer )
{
error ( "argument %d does not exist", n );
}
ARG ( n ) = SP ( 0 );
break;
case OP_TREF:
n = *pc++;
SP ( 0 ) = FP ( -n-1 );
break;
case OP_TSET:
n = *pc++;
FP ( -n-1 ) = SP ( 0 );
break;
case OP_PMREF:
opPMREF ();
break;
case OP_PMSET:
opPMSET ();
break;
case OP_TSPACE:
n = *pc++;
CHECKSTACK ( n );
PUSHN ( n );
break;
case OP_BRT:
if ( istrue ( SP ( 0 ) ) )
{
pc = cbase + getwoperand ();
}
else
{
pc += 2;
}
break;
case OP_BRF:
if ( istrue ( SP ( 0 ) ) )
{
pc += 2;
}
else
{
pc = cbase + getwoperand ();
}
break;
case OP_BR:
pc = cbase + getwoperand ();
break;
case OP_NULL:
SP ( 0 ) = null;
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -