mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-14 17:50:22 +02:00
1258 lines
30 KiB
C
1258 lines
30 KiB
C
/* Copyright (C) 2000 Free Software Foundation, Inc.
|
||
*
|
||
* This program is free software; you can redistribute it and/or modify
|
||
* it under the terms of the GNU General Public License as published by
|
||
* the Free Software Foundation; either version 2, or (at your option)
|
||
* any later version.
|
||
*
|
||
* This program is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
* GNU General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU General Public License
|
||
* along with this software; see the file COPYING. If not, write to
|
||
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
||
* Boston, MA 02111-1307 USA
|
||
*
|
||
* As a special exception, the Free Software Foundation gives permission
|
||
* for additional uses of the text contained in its release of GUILE.
|
||
*
|
||
* The exception is that, if you link the GUILE library with other files
|
||
* to produce an executable, this does not by itself cause the
|
||
* resulting executable to be covered by the GNU General Public License.
|
||
* Your use of that executable is in no way restricted on account of
|
||
* linking the GUILE library code into it.
|
||
*
|
||
* This exception does not however invalidate any other reasons why
|
||
* the executable file might be covered by the GNU General Public License.
|
||
*
|
||
* This exception applies only to the code released by the
|
||
* Free Software Foundation under the name GUILE. If you copy
|
||
* code from other Free Software Foundation releases into a copy of
|
||
* GUILE, as the General Public License permits, the exception does
|
||
* not apply to the code that you add in this way. To avoid misleading
|
||
* anyone as to the status of such modified files, you must delete
|
||
* this exception notice from them.
|
||
*
|
||
* If you write modifications of your own for GUILE, it is your choice
|
||
* whether to permit this exception to apply to your modifications.
|
||
* If you do not wish that, delete this exception notice. */
|
||
|
||
#define SCM_DEBUG_TYPING_STRICTNESS 0
|
||
#include "config.h"
|
||
#include "vm.h"
|
||
|
||
/* default stack size in the number of SCM */
|
||
#define VM_DEFAULT_STACK_SIZE (16 * 1024) /* = 64KB */
|
||
#define VM_MAXIMUM_STACK_SIZE (1024 * 1024) /* = 4MB */
|
||
|
||
/* I sometimes use this for debugging. */
|
||
#define vm_puts(OBJ) \
|
||
{ \
|
||
scm_display (OBJ, scm_def_errp); \
|
||
scm_newline (scm_def_errp); \
|
||
}
|
||
|
||
|
||
/*
|
||
* Generic object name
|
||
*/
|
||
|
||
static SCM scm_name_property;
|
||
|
||
SCM_DEFINE (scm_name, "name", 1, 0, 0,
|
||
(SCM obj),
|
||
"")
|
||
#define FUNC_NAME s_scm_name
|
||
{
|
||
return scm_primitive_property_ref (scm_name_property, obj);
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_set_name_x, "set-name!", 2, 0, 0,
|
||
(SCM obj, SCM name),
|
||
"")
|
||
#define FUNC_NAME s_scm_set_name_x
|
||
{
|
||
SCM_VALIDATE_SYMBOL (2, name);
|
||
return scm_primitive_property_set_x (scm_name_property, obj, name);
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
int
|
||
scm_smob_print_with_name (SCM smob, SCM port, scm_print_state *pstate)
|
||
{
|
||
int n = SCM_SMOBNUM (smob);
|
||
SCM name = scm_name (smob);
|
||
scm_puts ("#<", port);
|
||
scm_puts (SCM_SMOBNAME (n) ? SCM_SMOBNAME (n) : "smob", port);
|
||
scm_putc (' ', port);
|
||
if (SCM_FALSEP (name))
|
||
{
|
||
scm_puts ("0x", port);
|
||
scm_intprint (SCM_UNPACK (scm_smobs[n].size ? SCM_CDR (smob) : smob),
|
||
16, port);
|
||
}
|
||
else
|
||
{
|
||
scm_display (name, port);
|
||
}
|
||
scm_putc ('>', port);
|
||
return 1;
|
||
}
|
||
|
||
static void
|
||
init_name_property ()
|
||
{
|
||
scm_name_property
|
||
= scm_permanent_object (scm_primitive_make_property (SCM_BOOL_F));
|
||
}
|
||
|
||
|
||
/*
|
||
* Instruction
|
||
*/
|
||
|
||
static long scm_instruction_tag;
|
||
|
||
static struct scm_instruction scm_instruction_table[] = {
|
||
#include "vm_system.inst"
|
||
#include "vm_scheme.inst"
|
||
#include "vm_number.inst"
|
||
{op_last}
|
||
};
|
||
|
||
#define SCM_INSTRUCTION(OP) &scm_instruction_table[SCM_UNPACK (OP)]
|
||
|
||
static SCM
|
||
make_instruction (struct scm_instruction *instp)
|
||
{
|
||
SCM_RETURN_NEWSMOB (scm_instruction_tag, instp);
|
||
}
|
||
|
||
static int
|
||
print_instruction (SCM obj, SCM port, scm_print_state *pstate)
|
||
{
|
||
scm_puts ("#<instruction ", port);
|
||
scm_puts (SCM_INSTRUCTION_DATA (obj)->name, port);
|
||
scm_putc ('>', port);
|
||
return 1;
|
||
}
|
||
|
||
static void
|
||
init_instruction_type ()
|
||
{
|
||
scm_instruction_tag = scm_make_smob_type ("instruction", 0);
|
||
scm_set_smob_print (scm_instruction_tag, print_instruction);
|
||
}
|
||
|
||
/* C interface */
|
||
|
||
static struct scm_instruction *
|
||
scm_lookup_instruction (const char *name)
|
||
{
|
||
struct scm_instruction *p;
|
||
for (p = scm_instruction_table; p->opcode != op_last; p++)
|
||
if (strcmp (name, p->name) == 0)
|
||
return p;
|
||
return 0;
|
||
}
|
||
|
||
/* Scheme interface */
|
||
|
||
SCM_DEFINE (scm_instruction_p, "instruction?", 1, 0, 0,
|
||
(SCM obj),
|
||
"")
|
||
#define FUNC_NAME s_scm_instruction_p
|
||
{
|
||
return SCM_BOOL (SCM_INSTRUCTION_P (obj));
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_system_instruction_p, "system-instruction?", 1, 0, 0,
|
||
(SCM obj),
|
||
"")
|
||
#define FUNC_NAME s_scm_system_instruction_p
|
||
{
|
||
return SCM_BOOL (SCM_SYSTEM_INSTRUCTION_P (obj));
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_functional_instruction_p, "functional-instruction?", 1, 0, 0,
|
||
(SCM obj),
|
||
"")
|
||
#define FUNC_NAME s_scm_functional_instruction_p
|
||
{
|
||
return SCM_BOOL (SCM_FUNCTIONAL_INSTRUCTION_P (obj));
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_instruction_name_p, "instruction-name?", 1, 0, 0,
|
||
(SCM name),
|
||
"")
|
||
#define FUNC_NAME s_scm_instruction_name_p
|
||
{
|
||
SCM_VALIDATE_SYMBOL (1, name);
|
||
return SCM_BOOL (scm_lookup_instruction (SCM_SYMBOL_CHARS (name)));
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_symbol_to_instruction, "symbol->instruction", 1, 0, 0,
|
||
(SCM name),
|
||
"")
|
||
#define FUNC_NAME s_scm_symbol_to_instruction
|
||
{
|
||
struct scm_instruction *p;
|
||
SCM_VALIDATE_SYMBOL (1, name);
|
||
|
||
p = scm_lookup_instruction (SCM_SYMBOL_CHARS (name));
|
||
if (!p)
|
||
SCM_MISC_ERROR ("No such instruction: ~S", SCM_LIST1 (name));
|
||
|
||
return p->obj;
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_instruction_list, "instruction-list", 0, 0, 0,
|
||
(),
|
||
"")
|
||
#define FUNC_NAME s_scm_instruction_list
|
||
{
|
||
SCM list = SCM_EOL;
|
||
struct scm_instruction *p;
|
||
for (p = scm_instruction_table; p->opcode != op_last; p++)
|
||
list = scm_cons (p->obj, list);
|
||
return scm_reverse_x (list, SCM_EOL);
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_instruction_opcode, "instruction-opcode", 1, 0, 0,
|
||
(SCM inst),
|
||
"")
|
||
#define FUNC_NAME s_scm_instruction_opcode
|
||
{
|
||
SCM_VALIDATE_INSTRUCTION (1, inst);
|
||
return SCM_MAKINUM (SCM_INSTRUCTION_DATA (inst)->opcode);
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_instruction_name, "instruction-name", 1, 0, 0,
|
||
(SCM inst),
|
||
"")
|
||
#define FUNC_NAME s_scm_instruction_name
|
||
{
|
||
SCM_VALIDATE_INSTRUCTION (1, inst);
|
||
return SCM_CAR (scm_intern0 (SCM_INSTRUCTION_DATA (inst)->name));
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_instruction_type, "instruction-type", 1, 0, 0,
|
||
(SCM inst),
|
||
"")
|
||
#define FUNC_NAME s_scm_instruction_type
|
||
{
|
||
SCM_VALIDATE_INSTRUCTION (1, inst);
|
||
return SCM_MAKINUM (SCM_INSTRUCTION_DATA (inst)->type);
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_instruction_scheme_name, "instruction-scheme-name", 1, 0, 0,
|
||
(SCM inst),
|
||
"")
|
||
#define FUNC_NAME s_scm_instruction_scheme_name
|
||
{
|
||
SCM_VALIDATE_INSTRUCTION (1, inst);
|
||
if (SCM_FUNCTIONAL_INSTRUCTION_P (inst))
|
||
return SCM_CAR (scm_intern0 (SCM_INSTRUCTION_DATA (inst)->sname));
|
||
else
|
||
return SCM_BOOL_F;
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_instruction_arity, "instruction-arity", 1, 0, 0,
|
||
(SCM inst),
|
||
"")
|
||
#define FUNC_NAME s_scm_instruction_arity
|
||
{
|
||
SCM_VALIDATE_INSTRUCTION (1, inst);
|
||
if (SCM_FUNCTIONAL_INSTRUCTION_P (inst))
|
||
{
|
||
struct scm_instruction *p = SCM_INSTRUCTION_DATA (inst);
|
||
return SCM_LIST2 (SCM_MAKINUM (p->nargs), SCM_BOOL (p->restp));
|
||
}
|
||
else
|
||
return SCM_BOOL_F;
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
|
||
/*
|
||
* Bytecode
|
||
*/
|
||
|
||
static long scm_bytecode_tag;
|
||
|
||
static SCM
|
||
make_bytecode (int size)
|
||
{
|
||
struct scm_bytecode *p
|
||
= scm_must_malloc (sizeof (*p) + (size * sizeof (SCM)), "make_bytecode");
|
||
p->size = size;
|
||
SCM_RETURN_NEWSMOB (scm_bytecode_tag, p);
|
||
}
|
||
|
||
static SCM
|
||
mark_bytecode (SCM bytecode)
|
||
{
|
||
int i;
|
||
struct scm_instruction *p;
|
||
|
||
int size = SCM_BYTECODE_SIZE (bytecode);
|
||
SCM *base = SCM_BYTECODE_BASE (bytecode);
|
||
|
||
for (i = 0; i < size; i++)
|
||
{
|
||
p = SCM_INSTRUCTION (base[i]);
|
||
switch (p->type)
|
||
{
|
||
case INST_NONE:
|
||
break;
|
||
case INST_SCM:
|
||
case INST_TOP:
|
||
case INST_EXT:
|
||
case INST_CODE:
|
||
scm_gc_mark (base[++i]);
|
||
break;
|
||
case INST_INUM: /* a fixed integer; we don't need to mark it */
|
||
case INST_ADDR: /* real memory address; we shouldn't mark it! */
|
||
i++;
|
||
}
|
||
}
|
||
return SCM_BOOL_F;
|
||
}
|
||
|
||
static int
|
||
print_bytecode (SCM obj, SCM port, scm_print_state *pstate)
|
||
{
|
||
scm_puts ("#<bytecode 0x", port);
|
||
scm_intprint ((long) SCM_BYTECODE_BASE (obj), 16, port);
|
||
scm_putc ('>', port);
|
||
return 1;
|
||
}
|
||
|
||
static scm_sizet
|
||
free_bytecode (SCM bytecode)
|
||
{
|
||
int size = (sizeof (struct scm_bytecode)
|
||
+ (SCM_BYTECODE_SIZE (bytecode) * sizeof (SCM)));
|
||
if (SCM_BYTECODE_EXTS (bytecode))
|
||
{
|
||
size += (SCM_BYTECODE_EXTS (bytecode)[0] + 1) * sizeof (int);
|
||
scm_must_free (SCM_BYTECODE_EXTS (bytecode));
|
||
}
|
||
scm_must_free (SCM_BYTECODE_DATA (bytecode));
|
||
return size;
|
||
}
|
||
|
||
static void
|
||
init_bytecode_type ()
|
||
{
|
||
scm_bytecode_tag = scm_make_smob_type ("bytecode", 0);
|
||
scm_set_smob_mark (scm_bytecode_tag, mark_bytecode);
|
||
scm_set_smob_print (scm_bytecode_tag, print_bytecode);
|
||
scm_set_smob_free (scm_bytecode_tag, free_bytecode);
|
||
}
|
||
|
||
/* Internal functions */
|
||
|
||
static SCM
|
||
lookup_variable (SCM sym)
|
||
{
|
||
SCM eclo = scm_standard_eval_closure (scm_selected_module ());
|
||
SCM var = scm_eval_closure_lookup (eclo, sym, SCM_BOOL_F);
|
||
if (SCM_FALSEP (var))
|
||
var = scm_eval_closure_lookup (eclo, sym, SCM_BOOL_T);
|
||
return var;
|
||
}
|
||
|
||
/* Scheme interface */
|
||
|
||
SCM_DEFINE (scm_bytecode_p, "bytecode?", 1, 0, 0,
|
||
(SCM obj),
|
||
"")
|
||
#define FUNC_NAME s_scm_bytecode_p
|
||
{
|
||
return SCM_BOOL (SCM_BYTECODE_P (obj));
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_make_bytecode, "make-bytecode", 1, 0, 0,
|
||
(SCM code),
|
||
"")
|
||
#define FUNC_NAME s_scm_make_bytecode
|
||
{
|
||
int i, size, len, offset;
|
||
SCM header, body, nreqs, restp, nvars, nexts, exts, bytecode;
|
||
SCM *old, *new, *address;
|
||
|
||
/* Type check */
|
||
SCM_VALIDATE_VECTOR (1, code);
|
||
SCM_ASSERT_RANGE (1, code, SCM_LENGTH (code) == 2);
|
||
header = SCM_VELTS (code)[0];
|
||
body = SCM_VELTS (code)[1];
|
||
SCM_VALIDATE_VECTOR (1, header);
|
||
SCM_VALIDATE_VECTOR (2, body);
|
||
SCM_ASSERT_RANGE (1, header, SCM_LENGTH (header) == 5);
|
||
nreqs = SCM_VELTS (header)[0];
|
||
restp = SCM_VELTS (header)[1];
|
||
nvars = SCM_VELTS (header)[2];
|
||
nexts = SCM_VELTS (header)[3];
|
||
exts = SCM_VELTS (header)[4];
|
||
SCM_VALIDATE_INUM (1, nreqs);
|
||
SCM_VALIDATE_BOOL (2, restp);
|
||
SCM_VALIDATE_INUM (3, nvars);
|
||
SCM_VALIDATE_INUM (4, nexts);
|
||
SCM_VALIDATE_VECTOR (5, exts);
|
||
|
||
/* Create a new bytecode */
|
||
size = SCM_LENGTH (body);
|
||
old = SCM_VELTS (body);
|
||
bytecode = make_bytecode (size);
|
||
new = SCM_BYTECODE_BASE (bytecode);
|
||
|
||
/* Initialize the header */
|
||
SCM_BYTECODE_NREQS (bytecode) = SCM_INUM (nreqs);
|
||
SCM_BYTECODE_RESTP (bytecode) = SCM_FALSEP (restp) ? 0 : 1;
|
||
SCM_BYTECODE_NVARS (bytecode) = SCM_INUM (nvars);
|
||
SCM_BYTECODE_NEXTS (bytecode) = SCM_INUM (nexts);
|
||
len = SCM_LENGTH (exts);
|
||
if (len == 0)
|
||
{
|
||
SCM_BYTECODE_EXTS (bytecode) = NULL;
|
||
}
|
||
else
|
||
{
|
||
SCM_BYTECODE_EXTS (bytecode) =
|
||
scm_must_malloc ((len + 1) * sizeof (int), FUNC_NAME);
|
||
SCM_BYTECODE_EXTS (bytecode)[0] = len;
|
||
for (i = 0; i < len; i++)
|
||
SCM_BYTECODE_EXTS (bytecode)[i + 1] = SCM_INUM (SCM_VELTS (exts)[i]);
|
||
}
|
||
|
||
/* Initialize the body */
|
||
for (i = 0; i < size; i++)
|
||
{
|
||
struct scm_instruction *p;
|
||
|
||
/* Process instruction */
|
||
if (!SCM_SYMBOLP (old[i])
|
||
|| !(p = scm_lookup_instruction (SCM_SYMBOL_CHARS (old[i]))))
|
||
SCM_MISC_ERROR ("Invalid instruction: ~S", SCM_LIST1 (old[i]));
|
||
new[i] = SCM_PACK (p->opcode);
|
||
|
||
/* Process arguments */
|
||
if (p->type == INST_NONE)
|
||
continue;
|
||
if (++i >= size)
|
||
SCM_MISC_ERROR ("Unexpected end of code", SCM_EOL);
|
||
switch (p->type)
|
||
{
|
||
case INST_NONE:
|
||
/* never come here */
|
||
case INST_INUM:
|
||
SCM_VALIDATE_INUM (1, old[i]);
|
||
/* fall through */
|
||
case INST_SCM:
|
||
/* just copy */
|
||
new[i] = old[i];
|
||
break;
|
||
case INST_TOP:
|
||
/* top-level variable */
|
||
SCM_VALIDATE_SYMBOL (1, old[i]);
|
||
new[i] = lookup_variable (old[i]);
|
||
break;
|
||
case INST_EXT:
|
||
/* just copy for now */
|
||
SCM_VALIDATE_CONS (1, old[i]);
|
||
SCM_VALIDATE_INUM (1, SCM_CAR (old[i]));
|
||
SCM_VALIDATE_INUM (1, SCM_CDR (old[i]));
|
||
new[i] = old[i];
|
||
break;
|
||
case INST_CODE:
|
||
/* another bytecode */
|
||
new[i] = scm_make_bytecode (old[i]);
|
||
break;
|
||
case INST_ADDR:
|
||
/* real address */
|
||
SCM_VALIDATE_INUM (1, old[i]);
|
||
/* Without the following intermediate variables, type conversion
|
||
fails on my machine. Casting doesn't work well, why? */
|
||
offset = SCM_INUM (old[i]);
|
||
address = new + offset;
|
||
new[i] = SCM_VM_MAKE_ADDRESS (address);
|
||
break;
|
||
}
|
||
}
|
||
return bytecode;
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_bytecode_decode, "bytecode-decode", 1, 0, 0,
|
||
(SCM bytecode),
|
||
"")
|
||
#define FUNC_NAME s_scm_bytecode_decode
|
||
{
|
||
int i, size, offset;
|
||
SCM code, *old, *new;
|
||
|
||
SCM_VALIDATE_BYTECODE (1, bytecode);
|
||
|
||
size = SCM_BYTECODE_SIZE (bytecode);
|
||
old = SCM_BYTECODE_BASE (bytecode);
|
||
code = scm_make_vector (SCM_MAKINUM (size), SCM_BOOL_F);
|
||
new = SCM_VELTS (code);
|
||
|
||
for (i = 0; i < size; i++)
|
||
{
|
||
struct scm_instruction *p;
|
||
|
||
/* Process instruction */
|
||
p = SCM_INSTRUCTION (old[i]);
|
||
if (!p)
|
||
{
|
||
broken:
|
||
SCM_MISC_ERROR ("Broken bytecode", SCM_EOL);
|
||
}
|
||
new[i] = scm_instruction_name (p->obj);
|
||
|
||
/* Process arguments */
|
||
if (p->type == INST_NONE)
|
||
continue;
|
||
if (++i >= size)
|
||
goto broken;
|
||
switch (p->type)
|
||
{
|
||
case INST_NONE:
|
||
/* never come here */
|
||
case INST_INUM:
|
||
case INST_SCM:
|
||
case INST_EXT:
|
||
/* just copy */
|
||
new[i] = old[i];
|
||
break;
|
||
case INST_TOP:
|
||
/* top-level variable */
|
||
new[i] = SCM_CAR (old[i]);
|
||
break;
|
||
case INST_CODE:
|
||
/* another bytecode */
|
||
new[i] = scm_bytecode_decode (old[i]);
|
||
break;
|
||
case INST_ADDR:
|
||
/* program address */
|
||
offset = SCM_VM_ADDRESS (old[i]) - old;
|
||
new[i] = SCM_MAKINUM (offset);
|
||
break;
|
||
}
|
||
}
|
||
return code;
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
|
||
/*
|
||
* Program
|
||
*/
|
||
|
||
static long scm_program_tag;
|
||
|
||
static SCM
|
||
make_program (SCM code, SCM env)
|
||
{
|
||
SCM_RETURN_NEWSMOB2 (scm_program_tag, SCM_UNPACK (code), SCM_UNPACK (env));
|
||
}
|
||
|
||
static SCM
|
||
mark_program (SCM program)
|
||
{
|
||
scm_gc_mark (SCM_PROGRAM_CODE (program));
|
||
return SCM_PROGRAM_ENV (program);
|
||
}
|
||
|
||
static SCM scm_vm_apply (SCM vm, SCM program, SCM args);
|
||
static SCM make_vm (int stack_size);
|
||
|
||
static SCM
|
||
apply_program (SCM program, SCM args)
|
||
{
|
||
return scm_vm_apply (make_vm (VM_DEFAULT_STACK_SIZE), program, args);
|
||
}
|
||
|
||
static void
|
||
init_program_type ()
|
||
{
|
||
scm_program_tag = scm_make_smob_type ("program", 0);
|
||
scm_set_smob_mark (scm_program_tag, mark_program);
|
||
scm_set_smob_print (scm_program_tag, scm_smob_print_with_name);
|
||
scm_set_smob_apply (scm_program_tag, apply_program, 0, 0, 1);
|
||
}
|
||
|
||
/* Scheme interface */
|
||
|
||
SCM_DEFINE (scm_program_p, "program?", 1, 0, 0,
|
||
(SCM obj),
|
||
"")
|
||
#define FUNC_NAME s_scm_program_p
|
||
{
|
||
return SCM_BOOL (SCM_PROGRAM_P (obj));
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_make_program, "make-program", 2, 0, 0,
|
||
(SCM bytecode, SCM parent),
|
||
"")
|
||
#define FUNC_NAME s_scm_make_program
|
||
{
|
||
SCM_VALIDATE_BYTECODE (1, bytecode);
|
||
return make_program (bytecode, parent);
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_program_code, "program-code", 1, 0, 0,
|
||
(SCM program),
|
||
"")
|
||
#define FUNC_NAME s_scm_program_code
|
||
{
|
||
SCM_VALIDATE_PROGRAM (1, program);
|
||
return SCM_PROGRAM_CODE (program);
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_program_base, "program-base", 1, 0, 0,
|
||
(SCM program),
|
||
"")
|
||
#define FUNC_NAME s_scm_program_base
|
||
{
|
||
SCM_VALIDATE_PROGRAM (1, program);
|
||
return SCM_VM_MAKE_ADDRESS (SCM_PROGRAM_BASE (program));
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
|
||
/*
|
||
* VM Frame
|
||
*/
|
||
|
||
static long scm_vm_frame_tag;
|
||
|
||
/* This is used for debugging */
|
||
struct scm_vm_frame {
|
||
int size;
|
||
SCM program;
|
||
SCM variables;
|
||
SCM dynamic_link;
|
||
SCM external_link;
|
||
SCM stack_pointer;
|
||
SCM return_address;
|
||
};
|
||
|
||
#define SCM_VM_FRAME_P(OBJ) SCM_SMOB_PREDICATE (scm_vm_frame_tag, OBJ)
|
||
#define SCM_VM_FRAME_DATA(FR) ((struct scm_vm_frame *) SCM_SMOB_DATA (FR))
|
||
#define SCM_VALIDATE_VM_FRAME(POS,OBJ) SCM_MAKE_VALIDATE (POS, OBJ, VM_FRAME_P)
|
||
|
||
static SCM
|
||
make_vm_frame (SCM *fp)
|
||
{
|
||
int i;
|
||
int size = SCM_INUM (SCM_VM_FRAME_SIZE (fp));
|
||
struct scm_vm_frame *p = scm_must_malloc (sizeof (*p), "make_vm_frame");
|
||
p->program = SCM_VM_FRAME_PROGRAM (fp);
|
||
p->dynamic_link = SCM_VM_FRAME_DYNAMIC_LINK (fp);
|
||
p->external_link = SCM_VM_FRAME_EXTERNAL_LINK (fp);
|
||
p->stack_pointer = SCM_VM_FRAME_STACK_POINTER (fp);
|
||
p->return_address = SCM_VM_FRAME_RETURN_ADDRESS (fp);
|
||
|
||
if (!SCM_FALSEP (p->dynamic_link))
|
||
p->dynamic_link = make_vm_frame (SCM_VM_ADDRESS (p->dynamic_link));
|
||
|
||
size += SCM_PROGRAM_NREQS (p->program) + SCM_PROGRAM_RESTP (p->program);
|
||
p->variables = scm_make_vector (SCM_MAKINUM (size), SCM_BOOL_F);
|
||
for (i = 0; i < size; i++)
|
||
SCM_VELTS (p->variables)[i] = SCM_VM_FRAME_VARIABLE (fp, i);
|
||
|
||
SCM_RETURN_NEWSMOB (scm_vm_frame_tag, p);
|
||
}
|
||
|
||
static SCM
|
||
mark_vm_frame (SCM frame)
|
||
{
|
||
struct scm_vm_frame *p = SCM_VM_FRAME_DATA (frame);
|
||
scm_gc_mark (p->program);
|
||
scm_gc_mark (p->dynamic_link);
|
||
scm_gc_mark (p->external_link);
|
||
return p->variables;
|
||
}
|
||
|
||
static void
|
||
init_vm_frame_type ()
|
||
{
|
||
scm_vm_frame_tag = scm_make_smob_type ("vm-frame", 0);
|
||
scm_set_smob_mark (scm_vm_frame_tag, mark_vm_frame);
|
||
}
|
||
|
||
/* Scheme interface */
|
||
|
||
SCM_DEFINE (scm_frame_p, "frame?", 1, 0, 0,
|
||
(SCM obj),
|
||
"")
|
||
#define FUNC_NAME s_scm_frame_p
|
||
{
|
||
return SCM_BOOL (SCM_VM_FRAME_P (obj));
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_frame_program, "frame-program", 1, 0, 0,
|
||
(SCM frame),
|
||
"")
|
||
#define FUNC_NAME s_scm_frame_program
|
||
{
|
||
SCM_VALIDATE_VM_FRAME (1, frame);
|
||
return SCM_VM_FRAME_DATA (frame)->program;
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_frame_variables, "frame-variables", 1, 0, 0,
|
||
(SCM frame),
|
||
"")
|
||
#define FUNC_NAME s_scm_frame_variables
|
||
{
|
||
SCM_VALIDATE_VM_FRAME (1, frame);
|
||
return SCM_VM_FRAME_DATA (frame)->variables;
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_frame_dynamic_link, "frame-dynamic-link", 1, 0, 0,
|
||
(SCM frame),
|
||
"")
|
||
#define FUNC_NAME s_scm_frame_dynamic_link
|
||
{
|
||
SCM_VALIDATE_VM_FRAME (1, frame);
|
||
return SCM_VM_FRAME_DATA (frame)->dynamic_link;
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_frame_external_link, "frame-external-link", 1, 0, 0,
|
||
(SCM frame),
|
||
"")
|
||
#define FUNC_NAME s_scm_frame_external_link
|
||
{
|
||
SCM_VALIDATE_VM_FRAME (1, frame);
|
||
return SCM_VM_FRAME_DATA (frame)->external_link;
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_frame_stack_pointer, "frame-stack-pointer", 1, 0, 0,
|
||
(SCM frame),
|
||
"")
|
||
#define FUNC_NAME s_scm_frame_stack_pointer
|
||
{
|
||
SCM_VALIDATE_VM_FRAME (1, frame);
|
||
return SCM_VM_FRAME_DATA (frame)->stack_pointer;
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_frame_return_address, "frame-return-address", 1, 0, 0,
|
||
(SCM frame),
|
||
"")
|
||
#define FUNC_NAME s_scm_frame_return_address
|
||
{
|
||
SCM_VALIDATE_VM_FRAME (1, frame);
|
||
return SCM_VM_FRAME_DATA (frame)->return_address;
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
|
||
/*
|
||
* VM Continuation
|
||
*/
|
||
|
||
static long scm_vm_cont_tag;
|
||
|
||
static SCM
|
||
capture_vm_cont (struct scm_vm *vmp)
|
||
{
|
||
struct scm_vm *p = scm_must_malloc (sizeof (*p), "capture_vm_cont");
|
||
p->stack_size = vmp->stack_limit - vmp->sp;
|
||
p->stack_base = scm_must_malloc (p->stack_size * sizeof (SCM),
|
||
"capture_vm_cont");
|
||
p->stack_limit = p->stack_base + p->stack_size - 1;
|
||
p->pc = vmp->pc;
|
||
p->sp = (SCM *) (vmp->stack_limit - vmp->sp);
|
||
p->fp = (SCM *) (vmp->stack_limit - vmp->fp);
|
||
memcpy (p->stack_base, vmp->sp + 1, vmp->stack_size * sizeof (SCM));
|
||
SCM_RETURN_NEWSMOB (scm_vm_cont_tag, p);
|
||
}
|
||
|
||
static void
|
||
reinstate_vm_cont (struct scm_vm *vmp, SCM cont)
|
||
{
|
||
struct scm_vm *p = SCM_VM_CONT_VMP (cont);
|
||
if (vmp->stack_size < p->stack_size)
|
||
{
|
||
puts ("FIXME: Need to expand");
|
||
abort ();
|
||
}
|
||
vmp->pc = p->pc;
|
||
vmp->sp = vmp->stack_limit - (int) p->sp;
|
||
vmp->fp = vmp->stack_limit - (int) p->fp;
|
||
memcpy (vmp->sp + 1, p->stack_base, p->stack_size * sizeof (SCM));
|
||
}
|
||
|
||
static SCM
|
||
mark_vm_cont (SCM cont)
|
||
{
|
||
SCM *p;
|
||
struct scm_vm *vmp = SCM_VM_CONT_VMP (cont);
|
||
for (p = vmp->stack_base; p <= vmp->stack_limit; p++)
|
||
if (SCM_NIMP (*p))
|
||
scm_gc_mark (*p);
|
||
return SCM_BOOL_F;
|
||
}
|
||
|
||
static scm_sizet
|
||
free_vm_cont (SCM cont)
|
||
{
|
||
struct scm_vm *p = SCM_VM_CONT_VMP (cont);
|
||
int size = sizeof (struct scm_vm) + p->stack_size * sizeof (SCM);
|
||
scm_must_free (p->stack_base);
|
||
scm_must_free (p);
|
||
return size;
|
||
}
|
||
|
||
static void
|
||
init_vm_cont_type ()
|
||
{
|
||
scm_vm_cont_tag = scm_make_smob_type ("vm-cont", 0);
|
||
scm_set_smob_mark (scm_vm_cont_tag, mark_vm_cont);
|
||
scm_set_smob_free (scm_vm_cont_tag, free_vm_cont);
|
||
}
|
||
|
||
|
||
/*
|
||
* VM
|
||
*/
|
||
|
||
static long scm_vm_tag;
|
||
|
||
static SCM
|
||
make_vm (int stack_size)
|
||
{
|
||
struct scm_vm *vmp = scm_must_malloc (sizeof (struct scm_vm), "make_vm");
|
||
vmp->stack_size = stack_size;
|
||
vmp->stack_base = scm_must_malloc (stack_size * sizeof (SCM), "make_vm");
|
||
vmp->stack_limit = vmp->stack_base + vmp->stack_size - 1;
|
||
vmp->sp = vmp->stack_limit;
|
||
vmp->ac = SCM_BOOL_F;
|
||
vmp->pc = NULL;
|
||
vmp->fp = NULL;
|
||
vmp->options = SCM_EOL;
|
||
vmp->boot_hook = scm_make_hook (SCM_MAKINUM (1));
|
||
vmp->halt_hook = scm_make_hook (SCM_MAKINUM (1));
|
||
vmp->next_hook = scm_make_hook (SCM_MAKINUM (1));
|
||
vmp->call_hook = scm_make_hook (SCM_MAKINUM (1));
|
||
vmp->apply_hook = scm_make_hook (SCM_MAKINUM (1));
|
||
vmp->return_hook = scm_make_hook (SCM_MAKINUM (1));
|
||
SCM_RETURN_NEWSMOB (scm_vm_tag, vmp);
|
||
}
|
||
|
||
static SCM
|
||
mark_vm (SCM vm)
|
||
{
|
||
SCM *p;
|
||
struct scm_vm *vmp = SCM_VM_DATA (vm);
|
||
for (p = vmp->sp + 1; p <= vmp->stack_limit; p++)
|
||
if (SCM_NIMP (*p))
|
||
scm_gc_mark (*p);
|
||
|
||
scm_gc_mark (vmp->ac);
|
||
scm_gc_mark (vmp->boot_hook);
|
||
scm_gc_mark (vmp->halt_hook);
|
||
scm_gc_mark (vmp->next_hook);
|
||
scm_gc_mark (vmp->call_hook);
|
||
scm_gc_mark (vmp->apply_hook);
|
||
scm_gc_mark (vmp->return_hook);
|
||
return vmp->options;
|
||
}
|
||
|
||
static void
|
||
init_vm_type ()
|
||
{
|
||
scm_vm_tag = scm_make_smob_type ("vm", sizeof (struct scm_vm));
|
||
scm_set_smob_mark (scm_vm_tag, mark_vm);
|
||
scm_set_smob_print (scm_vm_tag, scm_smob_print_with_name);
|
||
}
|
||
|
||
/* Scheme interface */
|
||
|
||
SCM_DEFINE (scm_vm_version, "vm-version", 0, 0, 0,
|
||
(),
|
||
"")
|
||
#define FUNC_NAME s_scm_vm_version
|
||
{
|
||
return scm_makfrom0str (VERSION);
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_vm_p, "vm?", 1, 0, 0,
|
||
(SCM obj),
|
||
"")
|
||
#define FUNC_NAME s_scm_vm_p
|
||
{
|
||
return SCM_BOOL (SCM_VM_P (obj));
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_make_vm, "make-vm", 0, 0, 0,
|
||
(),
|
||
"")
|
||
#define FUNC_NAME s_scm_make_vm
|
||
{
|
||
return make_vm (VM_DEFAULT_STACK_SIZE);
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_vm_ac, "vm:ac", 1, 0, 0,
|
||
(SCM vm),
|
||
"")
|
||
#define FUNC_NAME s_scm_vm_ac
|
||
{
|
||
SCM_VALIDATE_VM (1, vm);
|
||
return SCM_VM_DATA (vm)->ac;
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_vm_pc, "vm:pc", 1, 0, 0,
|
||
(SCM vm),
|
||
"")
|
||
#define FUNC_NAME s_scm_vm_pc
|
||
{
|
||
SCM_VALIDATE_VM (1, vm);
|
||
return SCM_VM_MAKE_ADDRESS (SCM_VM_DATA (vm)->pc);
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_vm_sp, "vm:sp", 1, 0, 0,
|
||
(SCM vm),
|
||
"")
|
||
#define FUNC_NAME s_scm_vm_sp
|
||
{
|
||
SCM_VALIDATE_VM (1, vm);
|
||
return SCM_VM_MAKE_ADDRESS (SCM_VM_DATA (vm)->sp);
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_vm_fp, "vm:fp", 1, 0, 0,
|
||
(SCM vm),
|
||
"")
|
||
#define FUNC_NAME s_scm_vm_fp
|
||
{
|
||
SCM_VALIDATE_VM (1, vm);
|
||
return SCM_VM_MAKE_ADDRESS (SCM_VM_DATA (vm)->fp);
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_vm_current_frame, "vm-current-frame", 1, 0, 0,
|
||
(SCM vm),
|
||
"")
|
||
#define FUNC_NAME s_scm_vm_current_frame
|
||
{
|
||
SCM_VALIDATE_VM (1, vm);
|
||
return make_vm_frame (SCM_VM_DATA (vm)->fp);
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_vm_fetch_code, "vm-fetch-code", 2, 0, 0,
|
||
(SCM vm, SCM addr),
|
||
"")
|
||
#define FUNC_NAME s_scm_vm_fetch_code
|
||
{
|
||
SCM *p, list;
|
||
struct scm_instruction *inst;
|
||
|
||
SCM_VALIDATE_VM (1, vm);
|
||
SCM_VALIDATE_INUM (2, addr);
|
||
|
||
p = SCM_VM_ADDRESS (addr);
|
||
|
||
inst = SCM_INSTRUCTION (*p);
|
||
if (!inst)
|
||
SCM_MISC_ERROR ("Broken bytecode", SCM_LIST1 (addr));
|
||
|
||
list = SCM_LIST1 (scm_instruction_name (inst->obj));
|
||
if (inst->type != INST_NONE)
|
||
{
|
||
if (inst->type == INST_ADDR)
|
||
{
|
||
p = SCM_CODE_TO_ADDR (p[1]);
|
||
SCM_SETCDR (list, SCM_LIST1 (SCM_VM_MAKE_ADDRESS (p)));
|
||
}
|
||
else
|
||
SCM_SETCDR (list, SCM_LIST1 (p[1]));
|
||
}
|
||
return list;
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_vm_stack_to_list, "vm-stack->list", 1, 0, 0,
|
||
(SCM vm),
|
||
"")
|
||
#define FUNC_NAME s_scm_vm_stack_to_list
|
||
{
|
||
struct scm_vm *vmp;
|
||
SCM *p, list = SCM_EOL;
|
||
|
||
SCM_VALIDATE_VM (1, vm);
|
||
|
||
vmp = SCM_VM_DATA (vm);
|
||
for (p = vmp->sp + 1; p <= vmp->stack_limit; p++)
|
||
list = scm_cons (*p, list);
|
||
return list;
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_vm_option, "vm-option", 2, 0, 0,
|
||
(SCM vm, SCM key),
|
||
"")
|
||
#define FUNC_NAME s_scm_vm_option
|
||
{
|
||
SCM_VALIDATE_VM (1, vm);
|
||
SCM_VALIDATE_SYMBOL (2, key);
|
||
return scm_assq_ref (SCM_VM_DATA (vm)->options, key);
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_vm_set_option_x, "vm-set-option!", 3, 0, 0,
|
||
(SCM vm, SCM key, SCM val),
|
||
"")
|
||
#define FUNC_NAME s_scm_vm_set_option_x
|
||
{
|
||
SCM_VALIDATE_VM (1, vm);
|
||
SCM_VALIDATE_SYMBOL (2, key);
|
||
SCM_VM_DATA (vm)->options
|
||
= scm_assq_set_x (SCM_VM_DATA (vm)->options, key, val);
|
||
return SCM_UNSPECIFIED;
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_vm_boot_hook, "vm-boot-hook", 1, 0, 0,
|
||
(SCM vm),
|
||
"")
|
||
#define FUNC_NAME s_scm_vm_boot_hook
|
||
{
|
||
SCM_VALIDATE_VM (1, vm);
|
||
return SCM_VM_DATA (vm)->boot_hook;
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_vm_halt_hook, "vm-halt-hook", 1, 0, 0,
|
||
(SCM vm),
|
||
"")
|
||
#define FUNC_NAME s_scm_vm_halt_hook
|
||
{
|
||
SCM_VALIDATE_VM (1, vm);
|
||
return SCM_VM_DATA (vm)->halt_hook;
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_vm_next_hook, "vm-next-hook", 1, 0, 0,
|
||
(SCM vm),
|
||
"")
|
||
#define FUNC_NAME s_scm_vm_next_hook
|
||
{
|
||
SCM_VALIDATE_VM (1, vm);
|
||
return SCM_VM_DATA (vm)->next_hook;
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_vm_call_hook, "vm-call-hook", 1, 0, 0,
|
||
(SCM vm),
|
||
"")
|
||
#define FUNC_NAME s_scm_vm_call_hook
|
||
{
|
||
SCM_VALIDATE_VM (1, vm);
|
||
return SCM_VM_DATA (vm)->call_hook;
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_vm_apply_hook, "vm-apply-hook", 1, 0, 0,
|
||
(SCM vm),
|
||
"")
|
||
#define FUNC_NAME s_scm_vm_apply_hook
|
||
{
|
||
SCM_VALIDATE_VM (1, vm);
|
||
return SCM_VM_DATA (vm)->apply_hook;
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_vm_return_hook, "vm-return-hook", 1, 0, 0,
|
||
(SCM vm),
|
||
"")
|
||
#define FUNC_NAME s_scm_vm_return_hook
|
||
{
|
||
SCM_VALIDATE_VM (1, vm);
|
||
return SCM_VM_DATA (vm)->return_hook;
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_SYMBOL (sym_debug, "debug");
|
||
|
||
static SCM scm_regular_vm (SCM vm, SCM program);
|
||
static SCM scm_debug_vm (SCM vm, SCM program);
|
||
|
||
#define VM_CODE(name) SCM_PACK (scm_lookup_instruction (name)->opcode)
|
||
|
||
SCM_DEFINE (scm_vm_run, "vm-run", 2, 0, 0,
|
||
(SCM vm, SCM program),
|
||
"")
|
||
#define FUNC_NAME s_scm_vm_run
|
||
{
|
||
SCM bootcode;
|
||
static SCM template[5];
|
||
|
||
SCM_VALIDATE_VM (1, vm);
|
||
SCM_VALIDATE_PROGRAM (2, program);
|
||
|
||
if (SCM_EQ_P (template[0], SCM_PACK (0)))
|
||
{
|
||
template[0] = VM_CODE ("%loadc");
|
||
template[1] = SCM_BOOL_F; /* overwritten */
|
||
template[2] = VM_CODE ("%call");
|
||
template[3] = SCM_MAKINUM (0);
|
||
template[4] = VM_CODE ("%halt");
|
||
}
|
||
|
||
/* Create a boot program */
|
||
bootcode = make_bytecode (5);
|
||
memcpy (SCM_BYTECODE_BASE (bootcode), template, sizeof (SCM) * 5);
|
||
SCM_BYTECODE_BASE (bootcode)[1] = program;
|
||
SCM_BYTECODE_SIZE (bootcode) = 5;
|
||
SCM_BYTECODE_EXTS (bootcode) = NULL;
|
||
SCM_BYTECODE_NREQS (bootcode) = 0;
|
||
SCM_BYTECODE_RESTP (bootcode) = 0;
|
||
SCM_BYTECODE_NVARS (bootcode) = 0;
|
||
SCM_BYTECODE_NEXTS (bootcode) = 0;
|
||
program = SCM_MAKE_PROGRAM (bootcode, SCM_BOOL_F);
|
||
|
||
if (SCM_FALSEP (scm_vm_option (vm, sym_debug)))
|
||
return scm_regular_vm (vm, program);
|
||
else
|
||
return scm_debug_vm (vm, program);
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
SCM_DEFINE (scm_vm_apply, "vm-apply", 3, 0, 0,
|
||
(SCM vm, SCM program, SCM args),
|
||
"")
|
||
#define FUNC_NAME s_scm_vm_apply
|
||
{
|
||
int len;
|
||
SCM bootcode;
|
||
static SCM template[7];
|
||
|
||
SCM_VALIDATE_VM (1, vm);
|
||
SCM_VALIDATE_PROGRAM (2, program);
|
||
SCM_VALIDATE_LIST_COPYLEN (3, args, len);
|
||
|
||
if (SCM_EQ_P (template[0], SCM_PACK (0)))
|
||
{
|
||
template[0] = VM_CODE ("%push-list");
|
||
template[1] = SCM_EOL; /* overwritten */
|
||
template[2] = VM_CODE ("%loadc");
|
||
template[3] = SCM_BOOL_F; /* overwritten */
|
||
template[4] = VM_CODE ("%call");
|
||
template[5] = SCM_MAKINUM (0); /* overwritten */
|
||
template[6] = VM_CODE ("%halt");
|
||
}
|
||
|
||
/* Create a boot program */
|
||
bootcode = make_bytecode (7);
|
||
memcpy (SCM_BYTECODE_BASE (bootcode), template, sizeof (SCM) * 7);
|
||
SCM_BYTECODE_BASE (bootcode)[1] = args;
|
||
SCM_BYTECODE_BASE (bootcode)[3] = program;
|
||
SCM_BYTECODE_BASE (bootcode)[5] = SCM_MAKINUM (len);
|
||
SCM_BYTECODE_SIZE (bootcode) = 7;
|
||
SCM_BYTECODE_EXTS (bootcode) = NULL;
|
||
SCM_BYTECODE_NREQS (bootcode) = 0;
|
||
SCM_BYTECODE_RESTP (bootcode) = 0;
|
||
SCM_BYTECODE_NVARS (bootcode) = 0;
|
||
SCM_BYTECODE_NEXTS (bootcode) = 0;
|
||
program = SCM_MAKE_PROGRAM (bootcode, SCM_BOOL_F);
|
||
|
||
if (SCM_FALSEP (scm_vm_option (vm, sym_debug)))
|
||
return scm_regular_vm (vm, program);
|
||
else
|
||
return scm_debug_vm (vm, program);
|
||
}
|
||
#undef FUNC_NAME
|
||
|
||
|
||
/*
|
||
* The VM engines
|
||
*/
|
||
|
||
/* We don't want to snarf the engines */
|
||
#ifndef SCM_MAGIC_SNARFER
|
||
|
||
/* the regular engine */
|
||
#define VM_ENGINE SCM_VM_REGULAR_ENGINE
|
||
#include "vm_engine.c"
|
||
#undef VM_ENGINE
|
||
|
||
/* the debug engine */
|
||
#define VM_ENGINE SCM_VM_DEBUG_ENGINE
|
||
#include "vm_engine.c"
|
||
#undef VM_ENGINE
|
||
|
||
#endif /* not SCM_MAGIC_SNARFER */
|
||
|
||
|
||
/*
|
||
* Initialize
|
||
*/
|
||
|
||
static SCM scm_module_vm;
|
||
|
||
void
|
||
scm_init_vm ()
|
||
{
|
||
SCM old_module;
|
||
|
||
/* Initialize the module */
|
||
scm_module_vm = scm_make_module (scm_read_0str ("(vm vm)"));
|
||
old_module = scm_select_module (scm_module_vm);
|
||
init_name_property ();
|
||
init_instruction_type ();
|
||
init_bytecode_type ();
|
||
init_program_type ();
|
||
init_vm_frame_type ();
|
||
init_vm_cont_type ();
|
||
init_vm_type ();
|
||
#include "vm.x"
|
||
scm_select_module (old_module);
|
||
|
||
{
|
||
struct scm_instruction *p;
|
||
for (p = scm_instruction_table; p->opcode != op_last; p++)
|
||
{
|
||
p->obj = scm_permanent_object (make_instruction (p));
|
||
if (p->restp) p->type = INST_INUM;
|
||
}
|
||
}
|
||
}
|
||
|
||
void
|
||
scm_init_vm_vm_module ()
|
||
{
|
||
scm_register_module_xxx ("vm vm", (void *) scm_init_vm);
|
||
}
|