simon 01/08/29 05:07:06
Modified: . README
Added: . Makefile assemble.pl basic_opcodes.c bytecode.c
bytecode.h config.h disassemble.pl events.h
exceptions.h global_setup.c interpreter.c
interpreter.h io.h make_op_header.pl
make_op_table_build.pl memory.c memory.h op.h
opcode_table parrot.c parrot.h register.c
register.h stacks.h string.c string.h strnative.c
strnative.h test.pasm test.pbc test_main.c
test_opcodes.c
Log:
Initial checkin of Simon's work directory - Dan, feel free to nuke.
I'm still working on the string stuff, though.
Revision Changes Path
1.3 +3 -8 parrot/README
Index: README
===================================================================
RCS file: /home/perlcvs/parrot/README,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -w -r1.2 -r1.3
--- README 2001/08/29 11:44:39 1.2
+++ README 2001/08/29 12:07:01 1.3
@@ -1,9 +1,4 @@
-
-
-For access to the Parrot CVS module, see http://dev.perl.org/cvs/
-
-Simon or Dan, please change this file. I just put it here so you can
-see that something happened. :-)
-
-Be sure to send mail to [EMAIL PROTECTED]
+This is not yet ready for public consumption; this is just
+my working copy of Parrot so that there's *something* here.
+(And to test that we can check stuff in, as well.)
1.1 parrot/Makefile
Index: Makefile
===================================================================
H_FILES = config.h exceptions.h io.h op.h register.h string.h events.h interpreter.h
memory.h parrot.h stacks.h bytecode.h
O_FILES = global_setup.o interpreter.o parrot.o register.o basic_opcodes.o memory.o
bytecode.o string.o strnative.o
C_FLAGS = -Wall
CC = gcc $(C_FLAGS)
all : $(O_FILES)
test_prog: test_main.o $(O_FILES)
gcc -o test_prog $(O_FILES) test_main.o
driver.o: $(H_FILES)
global_setup.o: $(H_FILES)
string.o: $(H_FILES)
strnative.o: $(H_FILES)
interpreter.o: $(H_FILES)
memory.o: $(H_FILES)
bytecode.o: $(H_FILES)
parrot.o: $(H_FILES)
register.o: $(H_FILES)
basic_opcodes.o: $(H_FILES)
1.1 parrot/assemble.pl
Index: assemble.pl
===================================================================
#! /usr/bin/perl -w
#
# assemble.pl - take a parrot assembly file and spit out a bytecode file
my %opcodes;
my %pack_type;
%pack_type = (i => 'l',
n => 'd',
);
open OPCODES, "<opcode_table" or die "Can't get opcode table, $!/$^E";
while (<OPCODES>) {
next if /^\s*#/;
chomp;
my ($code, $name, $args, @types) = split /\s+/, $_;
$opcodes{$name} = {CODE => $code,
ARGS => $args,
TYPES => [@types]
};
}
my $pc = 0;
my @code;
my %constants;
my @constants;
# First scan for labels and strings
while (<>) {
s/^\s*//;
if (s/^\s*([a-zA-Z_]\w+):\s*//) { $labels{$1} = $pc; }
1 while s/\"([^\\\"]*(?:\\.[^\\\"]*)*)\"/constantize($1)/eg;
my ($opcode, @args) = split /\s+/, $_;
push @code, $_;
$pc += 1+@args;
}
emit_magic();
emit_fixup_section();
emit_constants_section();
# Now assemble
$pc = 0;
while ($_ = shift @code) {
chomp;
s/,/ /g;
my ($opcode, @args) = split /\s+/, $_;
if (!exists $opcodes{lc $opcode}) {
die "No opcode $opcode";
}
if (@args != $opcodes{$opcode}{ARGS}) {
die "wrong arg count--got ". scalar @args. " needed " .
$opcodes{$opcode}{ARGS};
}
$args[0] = fixup($args[0])
if $opcode eq "branch_ic" and $args[0] =~ /[a-zA-Z]/;
if ($opcode eq "eq_i_ic") {
$args[2] = fixup($args[2]) if $args[2] =~ /[a-zA-Z]/;
$args[3] = fixup($args[3]) if $args[3] =~ /[a-zA-Z]/;
}
if ($opcode eq "if_i_ic") {
$args[1] = fixup($args[1]) if $args[1] =~ /[a-zA-Z]/;
$args[2] = fixup($args[2]) if $args[2] =~ /[a-zA-Z]/;
}
print pack "l", $opcodes{$opcode}{CODE};
foreach (0..$#args) {
$args[$_] =~ s/^[INPS]?(\d+)$/$1/i;
$type = $pack_type{$opcodes{$opcode}{TYPES}[$_]};
print pack $type, $args[$_];
}
$pc += 1+@args;
}
sub fixup {
my $l = shift;
die "Unknown label $l" unless exists $labels{$l};
return $labels{$l} - $pc;
}
sub constantize {
my $s = shift;
return $constants{$s} if exists $constants{$s};
push @constants, $s;
return $constants{$s} = $#constants;
}
my $sizeof_packi = length(pack($pack_type{i},1024));
sub emit_magic { print pack($pack_type{i}, 0x13155a1) }
# Dummy for now.
sub emit_fixup_section { print pack($pack_type{i}, 0) }
sub emit_constants_section {
# First, compute how big it's going to be.
# The fields we'll need to fill in are: strlen, flags, encoding, type
my $size =0 ;
$size += length($_)+4*$sizeof_packi for @constants;
print pack($pack_type{i}, $size);
# Now emit each constant
for (@constants) {
print pack($pack_type{i},0) x 3; # Flags, encoding, type
print pack($pack_type{i},length($_)); # Strlen followed by that many bytes.
print $_;
}
}
1.1 parrot/basic_opcodes.c
Index: basic_opcodes.c
===================================================================
/* basic_opcodes.c
*
* Just some basic opcodes
*
*/
#include "parrot.h"
// SET Ix, CONSTANT
IV *set_i_ic(IV cur_opcode[], struct Perl_Interp *interpreter) {
INT_REG(cur_opcode[1]) = cur_opcode[2];
return cur_opcode + 3;
}
// ADD Ix, Iy, Iz
IV *add_i(IV cur_opcode[], struct Perl_Interp *interpreter) {
INT_REG(cur_opcode[1]) = INT_REG(cur_opcode[2]) +
INT_REG(cur_opcode[3]);
return cur_opcode + 4;
}
// SUB Ix, Iy, Iz
IV *sub_i(IV cur_opcode[], struct Perl_Interp *interpreter) {
INT_REG(cur_opcode[1]) = INT_REG(cur_opcode[2]) -
INT_REG(cur_opcode[3]);
return cur_opcode + 4;
}
// MUL Ix, Iy, Iz
IV *mul_i(IV cur_opcode[], struct Perl_Interp *interpreter) {
INT_REG(cur_opcode[1]) = INT_REG(cur_opcode[2]) *
INT_REG(cur_opcode[3]);
return cur_opcode + 4;
}
// DIV Ix, Iy, Iz
IV *div_i(IV cur_opcode[], struct Perl_Interp *interpreter) {
INT_REG(cur_opcode[1]) = INT_REG(cur_opcode[2]) /
INT_REG(cur_opcode[3]);
return cur_opcode + 4;
}
// EQ Ix, Iy, EQ_BRANCH, NE_BRANCH
IV *eq_i_ic(IV cur_opcode[], struct Perl_Interp *interpreter) {
if (INT_REG(cur_opcode[1]) == INT_REG(cur_opcode[2])) {
return cur_opcode + cur_opcode[3];
} else {
return cur_opcode + cur_opcode[4];
}
}
// IF IXx, TRUE_BRANCH, FALSE_BRANCH
IV *if_i_ic(IV cur_opcode[], struct Perl_Interp *interpreter) {
if (INT_REG(cur_opcode[1])) {
return cur_opcode + cur_opcode[2];
} else {
return cur_opcode + cur_opcode[3];
}
}
// TIME Ix
IV *time_i(IV cur_opcode[], struct Perl_Interp *interpreter) {
INT_REG(cur_opcode[1]) = time(NULL);
return cur_opcode + 2;
}
// PRINT Ix
IV *print_i(IV cur_opcode[], struct Perl_Interp *interpreter) {
printf("I reg %i is %i\n", cur_opcode[1], INT_REG(cur_opcode[1]));
return(cur_opcode + 2);
}
// BRANCH CONSTANT
IV *branch_ic(IV cur_opcode[], struct Perl_Interp *interpreter) {
return cur_opcode + cur_opcode[1];
}
// END
IV *end(IV cur_opcode[], struct Perl_Interp *interpreter) {
return 0;
}
// INC Ix
IV *inc_i(IV cur_opcode[], struct Perl_Interp *interpreter) {
INT_REG(cur_opcode[1])++;
return cur_opcode + 2;
}
// INC Ix, nnn
IV *inc_i_ic(IV cur_opcode[], struct Perl_Interp *interpreter) {
INT_REG(cur_opcode[1]) += cur_opcode[2];
return cur_opcode + 3;
}
// DEC Ix
IV *dec_i(IV cur_opcode[], struct Perl_Interp *interpreter) {
INT_REG(cur_opcode[1]);
return cur_opcode + 2;
}
// DEC Ix, nnn
IV *dec_i_ic(IV cur_opcode[], struct Perl_Interp *interpreter) {
INT_REG(cur_opcode[1]) += cur_opcode[2];
return cur_opcode + 3;
}
// JUMP Ix
IV *jump_i(IV cur_opcode[], struct Perl_Interp *interpreter) {
return (IV *)INT_REG(cur_opcode[1]);
}
// SET Nx, CONSTANT
IV *set_n_nc(IV cur_opcode[], struct Perl_Interp *interpreter) {
NUM_REG(cur_opcode[1]) = *(double *)&cur_opcode[2];
return cur_opcode + 4; // Don't forget, NVs are two slots wide
}
// ADD Nx, Ny, Nz
IV *add_n(IV cur_opcode[], struct Perl_Interp *interpreter) {
NUM_REG(cur_opcode[1]) = NUM_REG(cur_opcode[2]) +
NUM_REG(cur_opcode[3]);
return cur_opcode + 4;
}
// SUB Nx, Ny, Iz
IV *sub_n(IV cur_opcode[], struct Perl_Interp *interpreter) {
NUM_REG(cur_opcode[1]) = NUM_REG(cur_opcode[2]) -
NUM_REG(cur_opcode[3]);
return cur_opcode + 4;
}
// MUL Nx, Ny, Iz
IV *mul_n(IV cur_opcode[], struct Perl_Interp *interpreter) {
NUM_REG(cur_opcode[1]) = NUM_REG(cur_opcode[2]) *
NUM_REG(cur_opcode[3]);
return cur_opcode + 4;
}
// DIV Nx, Ny, Iz
IV *div_n(IV cur_opcode[], struct Perl_Interp *interpreter) {
NUM_REG(cur_opcode[1]) = NUM_REG(cur_opcode[2]) /
NUM_REG(cur_opcode[3]);
return cur_opcode + 4;
}
// EQ Nx, Ny, EQ_BRANCH, NE_BRANCH
IV *eq_n_ic(IV cur_opcode[], struct Perl_Interp *interpreter) {
if (NUM_REG(cur_opcode[1]) == NUM_REG(cur_opcode[2])) {
return cur_opcode + cur_opcode[3];
} else {
return cur_opcode + cur_opcode[4];
}
}
// IF Nx, TRUE_BRANCH, FALSE_BRANCH
IV *if_n_ic(IV cur_opcode[], struct Perl_Interp *interpreter) {
if (NUM_REG(cur_opcode[1])) {
return cur_opcode + cur_opcode[2];
} else {
return cur_opcode + cur_opcode[3];
}
}
// TIME Nx
IV *time_n(IV cur_opcode[], struct Perl_Interp *interpreter) {
NUM_REG(cur_opcode[1]) = time(NULL);
return cur_opcode + 2;
}
// PRINT Nx
IV *print_n(IV cur_opcode[], struct Perl_Interp *interpreter) {
printf("N reg %i is %Lf\n", cur_opcode[1], NUM_REG(cur_opcode[1]));
return(cur_opcode + 2);
}
// INC Nx
IV *inc_n(IV cur_opcode[], struct Perl_Interp *interpreter) {
NUM_REG(cur_opcode[1]) += 1;
return cur_opcode + 2;
}
// INC Nx, nnn
IV *inc_n_nc(IV cur_opcode[], struct Perl_Interp *interpreter) {
(NV)NUM_REG(cur_opcode[1]) += *(double *)&cur_opcode[2];
return cur_opcode + 4;
}
// DEC Nx
IV *dec_n(IV cur_opcode[], struct Perl_Interp *interpreter) {
NUM_REG(cur_opcode[1]);
return cur_opcode + 2;
}
// DEC Nx, nnn
IV *dec_n_nc(IV cur_opcode[], struct Perl_Interp *interpreter) {
NUM_REG(cur_opcode[1]) += *(double *)&cur_opcode[2];
return cur_opcode + 4;
}
// ITON Nx, Iy
IV *iton_n_i(IV cur_opcode[], struct Perl_Interp *interpreter) {
IV number;
number = INT_REG(cur_opcode[2]);
NUM_REG(cur_opcode[1]) = (NV)number;
return cur_opcode + 3;
}
// NTOI Ix, Ny
IV *ntoi_i_n(IV cur_opcode[], struct Perl_Interp *interpreter) {
NV number;
number = NUM_REG(cur_opcode[2]);
INT_REG(cur_opcode[1]) = number;
return cur_opcode + 3;
}
1.1 parrot/bytecode.c
Index: bytecode.c
===================================================================
#include "parrot.h"
#define GRAB_IV(x) *((IV*)*x)++
static int
check_magic(void** program_code) {
return (GRAB_IV(program_code) == PARROT_MAGIC);
}
static void
read_constants_table(void** program_code)
{
IV len = GRAB_IV(program_code);
/* For now, just skip over it */
((IV*)*program_code) += len;
}
static void
read_fixup_table(void** program_code)
{
IV len = GRAB_IV(program_code);
/* For now, just skip over it */
((IV*)*program_code) += len;
}
void *
init_bytecode(void* program_code)
{
if (!check_magic(&program_code)) {
printf("This isn't Parrot bytecode!\n");
exit(1);
}
read_constants_table(&program_code);
read_fixup_table(&program_code);
return program_code;
}
1.1 parrot/bytecode.h
Index: bytecode.h
===================================================================
/* bytecode.h
*
* Bytecode functions header
*
*/
#if !defined(PARROT_BYTECODE_H_GUARD)
#define PARROT_BYTECODE_H_GUARD
void* init_bytecode(void* program_code);
#endif
1.1 parrot/config.h
Index: config.h
===================================================================
/* config.h
*
* Platform-specific config file
*
*/
#if !defined(PARROT_CONFIG_H_GUARD)
#define PARROT_CONFIG_H_GUARD
typedef long IV;
typedef long double NV;
typedef void VTABLE;
typedef void DPOINTER;
typedef void SYNC;
//typedef IV *(*opcode_funcs)(void *, void *) OPFUNC;
#define FRAMES_PER_CHUNK 16
#define FRAMES_PER_PMC_REG_CHUNK FRAMES_PER_CHUNK
#define FRAMES_PER_NUM_REG_CHUNK FRAMES_PER_CHUNK
#define FRAMES_PER_INT_REG_CHUNK FRAMES_PER_CHUNK
#define FRAMES_PER_STR_REG_CHUNK FRAMES_PER_CHUNK
#define MASK_CHUNK_LOW_BITS 0xfffff000
#endif
1.1 parrot/disassemble.pl
Index: disassemble.pl
===================================================================
#! perl -w
#
# Disassemble.pl
#
# Turn a parrot bytecode file into text
my %opcodes;
my %unpack_type;
%unpack_type = (i => 'l',
n => 'd',
);
my %unpack_size = (i => 4,
n => 8,
);
open OPCODES, "<opcode_table" or die "Can't get opcode table, $!/$^E";
while (<OPCODES>) {
next if /^\s*#/;
chomp;
my ($code, $name, $args, @types) = split /\s+/, $_;
$opcodes{$name} = {CODE => $code,
ARGS => $args,
TYPES => [@types]
};
$opcodes[$code] = {NAME => $name,
ARGS => $args,
TYPES => [@types]
}
}
$/ = \4;
while (<>) {
$code = unpack 'l', $_;
$args = $opcodes[$code]{ARGS};
print $opcodes[$code]{NAME};
if ($args) {
foreach (1..$args) {
local $/ = \$unpack_size{$opcodes[$code]{TYPES}[$_-1]};
$data = <>;
print " ", unpack $unpack_type{$opcodes[$code]{TYPES}[$_-1]}, $data;
}
}
print "\n";
}
1.1 parrot/events.h
Index: events.h
===================================================================
/* Events.h
*
* Event header
*
*/
#if !defined(PARROT_EVENT_H_GUARD)
#define PARROT_EVENT_H_GUARD
#define EXECUTE_OPCODE(x) interpreter->opcode_funcs[*(IV *)x]->(code, interpreter)
#define CHECK_EVENTS(x)
#endif
1.1 parrot/exceptions.h
Index: exceptions.h
===================================================================
/* exceptions.h
*
* define the internal interpreter exceptions
*
*/
#if !defined(PARROT_EXCEPTIONS_H_GUARD)
#define PARROT_EXCEPTIONS_H_GUARD
#define INTERNAL_EXCEPTION(x,y) {fprintf(stderr, y); exit(x);}
#define NO_REG_FRAMES 1
#endif
1.1 parrot/global_setup.c
Index: global_setup.c
===================================================================
/* Global_setup.c
*
* Performs all the global setting up of things. This includes the
* (very few) global variables that Parrot totes around
*
*/
#define INSIDE_GLOBAL_SETUP
#include "parrot.h"
void init_world() {
}
1.1 parrot/interpreter.c
Index: interpreter.c
===================================================================
/* Interpreter.c
*
* Main interpreter code
*
*/
#include "parrot.h"
void runops (struct Perl_Interp *interpreter, IV *code) {
while (code) {
IV *(*func)();
void **foo;
foo = (void *)interpreter->opcode_funcs;
(void *)func = foo[*code];
// printf("code %i\n", *code);
code = func(code, interpreter)
CHECK_EVENTS(interpreter);
}
}
struct Perl_Interp *make_interpreter() {
struct Perl_Interp *interpreter;
/* Get an empty interpreter from system memory */
interpreter = Sys_Allocate(sizeof(struct Perl_Interp));
/* Set up the memory allocation system */
Setup_Allocator(interpreter);
/* Set up the initial register chunks */
interpreter->int_reg_base = Allocate_Aligned(sizeof(struct IRegChunk));
interpreter->num_reg_base = Allocate_Aligned(sizeof(struct NRegChunk));
interpreter->string_reg_base = Allocate_Aligned(sizeof(struct SRegChunk));
interpreter->pmc_reg_base = Allocate_Aligned(sizeof(struct PRegChunk));
/* Set up the initial register frame pointers */
interpreter->int_reg = &interpreter->int_reg_base->IReg[0];
interpreter->num_reg = &interpreter->num_reg_base->NReg[0];
interpreter->string_reg = &interpreter->string_reg_base->SReg[0];
interpreter->pmc_reg = &interpreter->pmc_reg_base->PReg[0];
/* Initialize the integer register chunk */
interpreter->int_reg_base->used = 1;
interpreter->int_reg_base->free = FRAMES_PER_INT_REG_CHUNK - 1;
interpreter->int_reg_base->next = NULL;
interpreter->int_reg_base->prev = NULL;
/* Initialize the initial numeric register chunk */
interpreter->num_reg_base->used = 1;
interpreter->num_reg_base->free = FRAMES_PER_NUM_REG_CHUNK - 1;
interpreter->num_reg_base->next = NULL;
interpreter->num_reg_base->prev = NULL;
/* Initialize the inital string register chunk */
interpreter->string_reg_base->used = 1;
interpreter->string_reg_base->free = FRAMES_PER_STR_REG_CHUNK - 1;
interpreter->string_reg_base->next = NULL;
interpreter->string_reg_base->prev = NULL;
/* Initialize the initial PMC register chunk. Gotta NULL them out,
too, otherwise we might GC Wrong Things later */
interpreter->pmc_reg_base->used = 1;
interpreter->pmc_reg_base->free = FRAMES_PER_PMC_REG_CHUNK - 1;
interpreter->pmc_reg_base->next = NULL;
interpreter->pmc_reg_base->prev = NULL;
clear_p(interpreter);
/* Need a default stack */
interpreter->stack_base = Allocate_New_Stack();
/* Need an empty stash */
interpreter->perl_stash = Allocate_New_Stash();
/* The default opcode function table would be a good thing here... */
{
void **foo;
foo = Sys_Allocate(2048 * sizeof(void *));
foo[0] = set_i_ic;
foo[1] = add_i;
foo[7] = sub_i;
foo[8] = mul_i;
foo[9] = div_i;
foo[2] = eq_i_ic;
foo[3] = time_i;
foo[4] = print_i;
foo[5] = branch_ic;
foo[6] = end;
foo[10] = if_i_ic;
foo[11] = inc_i;
foo[12] = inc_i_ic;
foo[13] = dec_i;
foo[14] = dec_i_ic;
foo[15] = jump_i;
foo[16] = set_n_nc;
foo[17] = add_n;
foo[18] = sub_n;
foo[19] = mul_n;
foo[20] = div_n;
foo[21] = eq_n_ic;
foo[22] = time_n;
foo[23] = print_n;
foo[24] = if_n_ic;
foo[25] = inc_n;
foo[26] = inc_n_nc;
foo[27] = dec_n;
foo[28] = dec_n_nc;
foo[29] = iton_n_i;
foo[30] = ntoi_i_n;
(void *)interpreter->opcode_funcs = foo;
}
/* In case the I/O system needs something */
Init_IO(interpreter);
/* Done. Return and be done with it */
return interpreter;
}
1.1 parrot/interpreter.h
Index: interpreter.h
===================================================================
/* interpreter.h
*
* "Insert apropos quote here"
*
* This include file defines the structures used by the interpreter
*
*/
#if !defined(PARROT_INTERPRETER_H_GUARD)
#define PARROT_INTERPRETER_H_GUARD
#include "parrot.h"
struct Perl_Interp {
struct IReg *int_reg; // Current top of int reg stack
struct NReg *num_reg; // Current top of the float reg stack
struct SReg *string_reg; // Current top of the string stack
struct PReg *pmc_reg; // Current top of the PMC stack
struct Stack *stack_top; // Current top of the generic stack
struct IRegChunk *int_reg_base; // base of the int reg stack
struct NRegChunk *num_reg_base; // Base of the float reg stack
struct SRegChunk *string_reg_base; // Base of the string stack
struct PRegChunk *pmc_reg_base; // Base of the PMC stack
struct StackFrame *stack_base; // Base of the generic stack
struct Stash *perl_stash; // Pointer to the global
// variable area
struct Arenas *arena_base; // Pointer to this
// interpreter's arena
IV *(*(*opcode_funcs)[2048])(); // Opcode
// function table
};
struct Perl_Interp *make_interpreter();
#endif
1.1 parrot/io.h
Index: io.h
===================================================================
/* io.h
*
* I/O operations header
*
*/
#if !defined(PARROT_IO_H_GUARD)
#define PARROT_IO_H_GUARD
#define Init_IO(x)
#endif
1.1 parrot/make_op_header.pl
Index: make_op_header.pl
===================================================================
#! perl -w
#
# rip through opcode_table and spit out a chunk of C header for the
# functions in it
while (<>) {
next if /^\s*#/;
chomp;
(undef, $name, undef) = split /\t/, $_;
print "IV *$name(IV *, struct Perl_Interp *);\n";
}
1.1 parrot/make_op_table_build.pl
Index: make_op_table_build.pl
===================================================================
#! perl -w
#
# rip through opcode_table and spit out a chunk of C header for the
# functions in it
while (<>) {
next if /^\s*#/;
chomp;
next unless $_;
($num, $name, undef) = split /\s+/, $_;
print "\tfoo[$num] = $name;\n";
}
1.1 parrot/memory.c
Index: memory.c
===================================================================
/* Memory.c
*
* Handle memory allocation
*
*/
#include "parrot.h"
/* Allocate a chunk of memory aligned on a power-of-2 boundary */
void *Allocate_Aligned(IV size) {
IV boundary;
IV max_to_alloc;
IV temp;
void *mem = NULL;
boundary = 1;
for (temp = size; temp; temp >>= 1) {
boundary *= 2;
}
max_to_alloc = boundary * 2;
mem = malloc(max_to_alloc);
return mem;
}
void *Sys_Allocate(IV size) {
return malloc(size);
}
void Setup_Allocator(struct Perl_Interp *interpreter) {
}
1.1 parrot/memory.h
Index: memory.h
===================================================================
/* Memory.h
*
* Memory functions header
*
*/
#if !defined(PARROT_MEMORY_H_GUARD)
#define PARROT_MEMORY_H_GUARD
void *Allocate_Aligned(IV);
void *Sys_Allocate(IV);
void Setup_Allocator(struct Perl_Interp *);
#define Allocate_New_Stash() NULL
#define Allocate_New_Stack() NULL
#define Sys_Memcopy memcpy
#endif
1.1 parrot/op.h
Index: op.h
===================================================================
/* op.h
*
* Opcode header
*
*/
#if !defined(PARROT_OP_H_GUARD)
#define PARROT_OP_H_GUARD
typedef IV OP;
#define DEFAULT_OPCODE_TABLE NULL
IV *set_i_ic(IV *, struct Perl_Interp *);
IV *add_i(IV *, struct Perl_Interp *);
IV *sub_i(IV *, struct Perl_Interp *);
IV *mul_i(IV *, struct Perl_Interp *);
IV *div_i(IV *, struct Perl_Interp *);
IV *eq_i_ic(IV *, struct Perl_Interp *);
IV *time_i(IV *, struct Perl_Interp *);
IV *print_i(IV *, struct Perl_Interp *);
IV *branch_ic(IV *, struct Perl_Interp *);
IV *end(IV *, struct Perl_Interp *);
IV *if_i_ic(IV *, struct Perl_Interp *);
IV *inc_i(IV *, struct Perl_Interp *);
IV *inc_i_ic(IV *, struct Perl_Interp *);
IV *dec_i(IV *, struct Perl_Interp *);
IV *dec_i_ic(IV *, struct Perl_Interp *);
IV *jump_i(IV *, struct Perl_Interp *);
IV *set_n_nc(IV *, struct Perl_Interp *);
IV *add_n(IV *, struct Perl_Interp *);
IV *sub_n(IV *, struct Perl_Interp *);
IV *mul_n(IV *, struct Perl_Interp *);
IV *div_n(IV *, struct Perl_Interp *);
IV *eq_n_ic(IV *, struct Perl_Interp *);
IV *time_n(IV *, struct Perl_Interp *);
IV *print_n(IV *, struct Perl_Interp *);
IV *if_n_ic(IV *, struct Perl_Interp *);
IV *inc_n(IV *, struct Perl_Interp *);
IV *inc_n_nc(IV *, struct Perl_Interp *);
IV *dec_n(IV *, struct Perl_Interp *);
IV *dec_n_nc(IV *, struct Perl_Interp *);
IV *iton_n_i(IV *, struct Perl_Interp *);
IV *ntoi_i_n(IV *, struct Perl_Interp *);
#endif
1.1 parrot/opcode_table
Index: opcode_table
===================================================================
# opcode function table
#
# format is:
# number name args arg_types
#
# All fields should be whitespace separated
#
# The arg_types are the types to be packed (integer, number, whatever)
# not the type of the register or anything. So N3 is still an i, since that
# 3 specifying the register should be packed as an integer.
0 set_i_ic 2 i i
1 add_i 3 i i i
7 sub_i 3 i i i
8 mul_i 3 i i i
9 div_i 3 i i i
2 eq_i_ic 4 i i i i
3 time_i 1 i
4 print_i 1 i
5 branch_ic 1 i
6 end 0
10 if_i_ic 3 i i i
11 inc_i 1 i
12 inc_i_ic 2 i i
13 dec_i 1 i
14 dec_i_ic 2 i i
15 jump_i 1 i
16 set_n_nc 2 i n
17 add_n 3 i i i
18 sub_n 3 i i i
19 mul_n 3 i i i
20 div_n 3 i i i
21 eq_n_ic 4 i i i i
22 time_n 1 i
23 print_n 1 i
24 if_n_ic 3 i i i
25 inc_n 1 i
26 inc_n_nc 2 i n
27 dec_n 1 i
28 dec_n_nc 2 i n
29 iton_n_i 2 i i
30 ntoi_i_n 2 i i
1.1 parrot/parrot.c
Index: parrot.c
===================================================================
/* Parrot.c
*
* Main driver file for Parrot
*
*/
#include "parrot.h"
1.1 parrot/parrot.h
Index: parrot.h
===================================================================
/* parrot.h
*
* General header file includes for the parrot interpreter
*
*/
#if !defined(PARROT_PARROT_H_GUARD)
#define PARROT_PARROT_H_GUARD
#if defined(INSIDE_GLOBAL_SETUP)
#define VAR_SCOPE
#else
#define VAR_SCOPE extern
#endif
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
//#include <types.h>
#include <time.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#define NUM_REGISTERS 32
#define PARROT_MAGIC 0x13155a1
struct PMC {
VTABLE *vtable;
IV flags;
DPOINTER *data;
union {
IV int_val;
NV num_val;
DPOINTER *struct_val;
} cache;
SYNC *synchronize;
};
typedef struct PMC PMC;
#include "string.h"
#include "interpreter.h"
#include "register.h"
#include "exceptions.h"
#include "memory.h"
#include "bytecode.h"
#include "io.h"
#include "op.h"
#include "events.h"
#endif
1.1 parrot/register.c
Index: register.c
===================================================================
/* register.c
*
* Register handling routines
*
*/
#include "parrot.h"
void push_i(struct Perl_Interp *interpreter) {
struct IRegChunk *chunk_base;
chunk_base = CHUNK_BASE(interpreter->int_reg);
/* Do we have any slots left in the current chunk? */
if (chunk_base->free) {
interpreter->int_reg = &chunk_base->IReg[chunk_base->used++];
chunk_base->free--;
}
/* Nope, so plan B time. Allocate a new chunk of integer register frames */
else {
struct IRegChunk *new_chunk;
new_chunk = Allocate_Aligned(sizeof(struct IRegChunk));
new_chunk->used = 1;
new_chunk->free = FRAMES_PER_INT_REG_CHUNK - 1;
new_chunk->next = NULL;
new_chunk->prev = chunk_base;
chunk_base->next = new_chunk;
interpreter->int_reg = &new_chunk->IReg[0];
}
}
void pop_i(struct Perl_Interp *interpreter) {
struct IRegChunk *chunk_base;
chunk_base = CHUNK_BASE(interpreter->int_reg);
/* Is there more than one register frame in use? */
if (chunk_base->used > 1) {
chunk_base->used--;
chunk_base->free++;
interpreter->int_reg = &chunk_base->IReg[chunk_base->used - 1];
}
/* nope. Walk back */
else {
/* Can we even walk back? */
if (chunk_base->prev) {
/* Do so. We don't need to adjust used/free, since they're
already OK for the "We're full" case */
chunk_base = chunk_base->prev;
interpreter->int_reg = &chunk_base->IReg[chunk_base->used];
}
/* Nope. So pitch a fit */
else {
INTERNAL_EXCEPTION(NO_REG_FRAMES, "No more I register frames to pop!");
}
}
}
void clear_i(struct Perl_Interp *interpreter) {
int i;
for (i=0; i<NUM_REGISTERS; i++) {
INT_REG(i) = 0;
}
}
void push_s(struct Perl_Interp *interpreter) {
struct SRegChunk *chunk_base;
chunk_base = CHUNK_BASE(interpreter->string_reg);
/* Do we have any slots left in the current chunk? */
if (chunk_base->free) {
interpreter->string_reg = &chunk_base->SReg[chunk_base->used++];
chunk_base->free--;
}
/* Nope, so plan B time. Allocate a new chunk of string register frames */
else {
struct SRegChunk *new_chunk;
new_chunk = Allocate_Aligned(sizeof(struct SRegChunk));
new_chunk->used = 1;
new_chunk->free = FRAMES_PER_STR_REG_CHUNK - 1;
new_chunk->next = NULL;
new_chunk->prev = chunk_base;
chunk_base->next = new_chunk;
interpreter->string_reg = &new_chunk->SReg[0];
}
}
void pop_s(struct Perl_Interp *interpreter) {
struct SRegChunk *chunk_base;
chunk_base = CHUNK_BASE(interpreter->string_reg);
/* Is there more than one register frame in use? */
if (chunk_base->used > 1) {
chunk_base->used--;
chunk_base->free++;
interpreter->string_reg = &chunk_base->SReg[chunk_base->used - 1];
}
/* nope. Walk back */
else {
/* Can we even walk back? */
if (chunk_base->prev) {
/* Do so. We don't need to adjust used/free, since they're
already OK for the "We're full" case */
chunk_base = chunk_base->prev;
interpreter->string_reg = &chunk_base->SReg[chunk_base->used];
}
/* Nope. So pitch a fit */
else {
INTERNAL_EXCEPTION(NO_REG_FRAMES, "No more S register frames to pop!");
}
}
}
void clear_s(struct Perl_Interp *interpreter) {
int i;
for (i=0; i<NUM_REGISTERS; i++) {
STR_REG(i) = NULL;
}
}
void push_n(struct Perl_Interp *interpreter) {
struct NRegChunk *chunk_base;
chunk_base = CHUNK_BASE(interpreter->num_reg);
/* Do we have any slots left in the current chunk? */
if (chunk_base->free) {
interpreter->num_reg = &chunk_base->NReg[chunk_base->used++];
chunk_base->free--;
}
/* Nope, so plan B time. Allocate a new chunk of float register frames */
else {
struct NRegChunk *new_chunk;
new_chunk = Allocate_Aligned(sizeof(struct NRegChunk));
new_chunk->used = 1;
new_chunk->free = FRAMES_PER_NUM_REG_CHUNK - 1;
new_chunk->next = NULL;
new_chunk->prev = chunk_base;
chunk_base->next = new_chunk;
interpreter->num_reg = &new_chunk->NReg[0];
}
}
void pop_n(struct Perl_Interp *interpreter) {
struct NRegChunk *chunk_base;
chunk_base = CHUNK_BASE(interpreter->num_reg);
/* Is there more than one register frame in use? */
if (chunk_base->used > 1) {
chunk_base->used--;
chunk_base->free++;
interpreter->num_reg = &chunk_base->NReg[chunk_base->used - 1];
}
/* nope. Walk back */
else {
/* Can we even walk back? */
if (chunk_base->prev) {
/* Do so. We don't need to adjust used/free, since they're
already OK for the "We're full" case */
chunk_base = chunk_base->prev;
interpreter->num_reg = &chunk_base->NReg[chunk_base->used];
}
/* Nope. So pitch a fit */
else {
INTERNAL_EXCEPTION(NO_REG_FRAMES, "No more N register frames to pop!");
}
}
}
void clear_n(struct Perl_Interp *interpreter) {
int i;
for (i=0; i<NUM_REGISTERS; i++) {
NUM_REG(i) = 0;
}
}
void push_p(struct Perl_Interp *interpreter) {
struct PRegChunk *chunk_base;
chunk_base = CHUNK_BASE(interpreter->pmc_reg);
/* Do we have any slots left in the current chunk? */
if (chunk_base->free) {
interpreter->pmc_reg = &chunk_base->PReg[chunk_base->used++];
chunk_base->free--;
}
/* Nope, so plan B time. Allocate a new chunk of float register frames */
else {
struct PRegChunk *new_chunk;
new_chunk = Allocate_Aligned(sizeof(struct PRegChunk));
new_chunk->used = 1;
new_chunk->free = FRAMES_PER_PMC_REG_CHUNK - 1;
new_chunk->next = NULL;
new_chunk->prev = chunk_base;
chunk_base->next = new_chunk;
interpreter->pmc_reg = &new_chunk->PReg[0];
}
}
void pop_p(struct Perl_Interp *interpreter) {
struct PRegChunk *chunk_base;
chunk_base = CHUNK_BASE(interpreter->pmc_reg);
/* Is there more than one register frame in use? */
if (chunk_base->used > 1) {
chunk_base->used--;
chunk_base->free++;
interpreter->pmc_reg = &chunk_base->PReg[chunk_base->used - 1];
}
/* nope. Walk back */
else {
/* Can we even walk back? */
if (chunk_base->prev) {
/* Do so. We don't need to adjust used/free, since they're
already OK for the "We're full" case */
chunk_base = chunk_base->prev;
interpreter->pmc_reg = &chunk_base->PReg[chunk_base->used];
}
/* Nope. So pitch a fit */
else {
INTERNAL_EXCEPTION(NO_REG_FRAMES, "No more P register frames to pop!");
}
}
}
void clear_p(struct Perl_Interp *interpreter) {
int i;
for (i=0; i<NUM_REGISTERS; i++) {
PMC_REG(i) = NULL;
}
}
void push_on_stack(void *thing, IV size, IV type) {
}
void pop_off_stack(void *thing, IV type) {
}
1.1 parrot/register.h
Index: register.h
===================================================================
/* register.h
*
* Define the register structures
*
*/
#if !defined(__PARROT_REGISTER_H_GUARD)
#define __PARROT_REGISTER_H_GUARD
#include "parrot.h"
struct IReg {
IV registers[NUM_REGISTERS];
};
struct NReg {
NV registers[NUM_REGISTERS];
};
struct SReg {
STRING *registers[NUM_REGISTERS];
};
struct PReg {
PMC *registers[NUM_REGISTERS];
};
struct IRegChunk {
IV used;
IV free;
struct IRegChunk *next;
struct IRegChunk *prev;
struct IReg IReg[FRAMES_PER_CHUNK];
};
struct NRegChunk {
IV used;
IV free;
struct NRegChunk *next;
struct NRegChunk *prev;
struct NReg NReg[FRAMES_PER_CHUNK];
};
struct SRegChunk {
IV used;
IV free;
struct SRegChunk *next;
struct SRegChunk *prev;
struct SReg SReg[FRAMES_PER_CHUNK];
};
struct PRegChunk {
IV used;
IV free;
struct PRegChunk *next;
struct PRegChunk *prev;
struct PReg PReg[FRAMES_PER_CHUNK];
};
/* Accessor macros */
#define INT_REG(x) interpreter->int_reg->registers[x]
#define STR_REG(x) interpreter->string_reg->registers[x]
#define PMC_REG(x) interpreter->pmc_reg->registers[x]
#define NUM_REG(x) interpreter->num_reg->registers[x]
/* This macro masks off the low bits of a register chunk address,
since we're guaranteed to be aligned */
#define CHUNK_BASE(x) (void *)(MASK_CHUNK_LOW_BITS && (IV)x)
void clear_i(struct Perl_Interp *);
void clear_s(struct Perl_Interp *);
void clear_p(struct Perl_Interp *);
void clear_n(struct Perl_Interp *);
#endif /* __PARROT_REGISTER_H */
1.1 parrot/stacks.h
Index: stacks.h
===================================================================
/* stacks.h
*
* Define the structures in the perl 6 stack system
*
*/
struct Stack_Entry {
IV entry_type;
union {
NV number;
IV int;
PMC *pmc;
STRING *string;
void *generic_pointer;
} entry;
}
struct Stack {
struct *Stack_Entry[];
}
1.1 parrot/string.c
Index: string.c
===================================================================
/* string.c
*
* String handling code
*
*/
#include "parrot.h"
STRING_VTABLE Parrot_string_vtable[enc_max];
STRING *
string_make(char *buffer, IV buflen, IV encoding, IV flags, IV type) {
STRING *s = Sys_Allocate(sizeof(STRING));
Sys_Memcopy(s->bufstart, buffer, buflen);
s->encoding = encoding;
s->buflen = buflen;
s->flags = flags;
string_compute_strlen(s);
s->type = type;
return s;
}
/* Setup string vtables */
void
string_init(void) {
Parrot_string_vtable[enc_native] = string_native_vtable();
}
/* vtable despatch functions */
IV
string_compute_strlen(STRING *s) {
return (s->strlen = (Parrot_string_vtable[s->encoding].compute_strlen)(s));
}
1.1 parrot/string.h
Index: string.h
===================================================================
/* string.h
*
* String data info
*
*/
#if !defined(PARROT_STRING_H_GUARD)
#define PARROT_STRING_H_GUARD 1
struct parrot_string {
void *bufstart;
IV buflen;
IV bufused;
IV flags;
IV strlen;
IV encoding;
IV type;
IV unused;
};
enum {
enc_native,
enc_utf8,
enc_utf16,
enc_utf32,
enc_foreign,
enc_max
};
typedef struct parrot_string STRING;
/* String vtable functions */
typedef IV (*string_to_iv_t)(STRING *);
struct string_vtable {
string_to_iv_t compute_strlen;
};
typedef struct string_vtable STRING_VTABLE;
/* Declarations of accessors */
IV string_compute_strlen(STRING*);
#include "strnative.h"
#endif
1.1 parrot/strnative.c
Index: strnative.c
===================================================================
/* strnative.c
Functions for handling strings in native byte format
"Native" in this context means the equivalent of "LANG=C": No
fancy multi-byte stuff, this is plain old byte-at-a-time. But
we don't make any assumptions about what those bytes *mean*.
*/
#include "parrot.h"
static IV
string_native_compute_strlen (STRING *s) {
return s->buflen;
}
STRING_VTABLE
string_native_vtable (void) {
return (STRING_VTABLE) {
string_native_compute_strlen,
};
}
1.1 parrot/strnative.h
Index: strnative.h
===================================================================
/* strnative.h
*
* Native string handling functions header
*
*/
#if !defined(PARROT_STRNATIVE_H_GUARD)
#define PARROT_STRNATIVE_H_GUARD
STRING_VTABLE string_native_vtable (void);
#endif
1.1 parrot/test.pasm
Index: test.pasm
===================================================================
time_i I1
set_i_ic I2, 0
set_n_nc N1, 50
print_n N1
set_n_nc N2, 5
print_n N2
add_n N1, N1, N2
print_n N1
set_i_ic I3, 1
set_i_ic I4, 10000000
REDO: eq_i_ic I2, I4, DONE, NEXT
NEXT: add_i I2, I2, I3
branch_ic REDO
DONE: time_i I5
print_i I1
print_i I5
print_i I2
sub_i I2, I5, I1
print_i I2
set_i_ic I1, 3
mul_i I4, I4, I1
iton_n_i N1, I4
iton_n_i N2, I2
print_i I4
print_n N1
print_i I2
print_n N2
div_n N1, N1, N2
print_n N1
end
1.1 parrot/test.pbc
<<Binary file>>
1.1 parrot/test_main.c
Index: test_main.c
===================================================================
/* driver.c
*
* A sample main program
*
*/
#include "parrot.h"
IV opcodes[] = {3, 1, // put the time in reg 1
0, 2, 0, // Set reg 2 to 0
0, 3, 1, // set reg 3 to 1
0, 4, 100000000, // set reg 4 to 100M
2, 2, 4, 11, 5, // is reg 2 eq to reg 4?
1, 2, 2, 3, // Add register 2 to 3, store in 2
5, -9, // branch back to if
3, 5, // Put the time in reg 5
4, 1, // Print reg 1
4, 5, // Print reg 5
6 // exit
};
int main(int argc, char **argv) {
struct Perl_Interp *interpreter;
init_world();
interpreter = make_interpreter();
/* If we got only the program name, run the test program */
if (argc == 1) {
runops(interpreter, opcodes);
}
/* Otherwise load in the program they gave and try that */
else {
void *program_code;
struct stat file_stat;
int fd;
if (stat(argv[1], &file_stat)) {
printf("can't stat %s, code %i\n", argv[1], errno);
return 1;
}
fd = open(argv[1], O_RDONLY);
if (!fd) {
printf("Can't open, error %i\n", errno);
return 1;
}
program_code = mmap(0, file_stat.st_size, PROT_READ, MAP_SHARED, fd, 0);
if (!program_code) {
printf("Can't mmap, code %i\n", errno);
return 1;
}
program_code = init_bytecode(program_code);
runops(interpreter, program_code);
}
return 0;
}
1.1 parrot/test_opcodes.c
Index: test_opcodes.c
===================================================================
/* basic_opcodes.c
*
* Just some basic opcodes
*
*/
#include "parrot.h"
// SET Ix, CONSTANT
IV *set_i(IV cur_opcode[], struct Perl_Interp *interpreter) {
INT_REG(cur_opcode[1]) = cur_opcode[2];
return cur_opcode + 3;
}
// ADD Ix, Iy, Iz
IV *add_i(IV cur_opcode[], struct Perl_Interp *interpreter) {
INT_REG(cur_opcode[1]) = INT_REG(cur_opcode[2]) +
INT_REG(cur_opcode[3]);
return cur_opcode + 4;
}
// SUB Ix, Iy, Iz
IV *sub_i(IV cur_opcode[], struct Perl_Interp *interpreter) {
INT_REG(cur_opcode[1]) = INT_REG(cur_opcode[2]) -
INT_REG(cur_opcode[3]);
return cur_opcode + 4;
}
// MUL Ix, Iy, Iz
IV *mul_i(IV cur_opcode[], struct Perl_Interp *interpreter) {
INT_REG(cur_opcode[1]) = INT_REG(cur_opcode[2]) *
INT_REG(cur_opcode[3]);
return cur_opcode + 4;
}
// DIV Ix, Iy, Iz
IV *div_i(IV cur_opcode[], struct Perl_Interp *interpreter) {
INT_REG(cur_opcode[1]) = INT_REG(cur_opcode[2]) /
INT_REG(cur_opcode[3]);
return cur_opcode + 4;
}
// EQ Ix, Iy, EQ_BRANCH, NE_BRANCH
IV *eq_i(IV cur_opcode[], struct Perl_Interp *interpreter) {
if (INT_REG(cur_opcode[1]) == INT_REG(cur_opcode[2])) {
return cur_opcode + cur_opcode[3];
} else {
return cur_opcode + cur_opcode[4];
}
}
// IF IXx, TRUE_BRANCH, FALSE_BRANCH
IV *if_i(IV cur_opcode[], struct Perl_Interp *interpreter) {
if (INT_REG(cur_opcode[1])) {
return cur_opcode + cur_opcode[2];
} else {
return cur_opcode + cur_opcode[3];
}
}
// TIME Ix
IV *time_i(IV cur_opcode[], struct Perl_Interp *interpreter) {
INT_REG(cur_opcode[1]) = time(NULL);
return cur_opcode + 2;
}
// PRINT Ix
IV *print_i(IV cur_opcode[], struct Perl_Interp *interpreter) {
printf("I reg %i is %i\n", cur_opcode[1], INT_REG(cur_opcode[1]));
return(cur_opcode + 2);
}
// BRANCH CONSTANT
IV *branch_i_c(IV cur_opcode[], struct Perl_Interp *interpreter) {
return cur_opcode + cur_opcode[1];
}
// END
IV *end(IV cur_opcode[], struct Perl_Interp *interpreter) {
return 0;
}