mirror of https://github.com/ademakov/libjit
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
242 lines
5.7 KiB
242 lines
5.7 KiB
/* hellovm.c - a kind of "hello world" for libjit
|
|
*
|
|
* Written by Norbert Bollow <nb@SoftwareEconomics.biz>
|
|
*
|
|
* This program is a JIT for the "Hello VM" bytecode language, which
|
|
* has just one (string) register, and three opcodes: A) load string
|
|
* constant into register, B) output contents of register, C) exit program.
|
|
*
|
|
* Compile with: gcc hellovm.c -ljit -o hellovm
|
|
*
|
|
* A valid "Hello VM" bytecode language program, suitable as input file for
|
|
* this JIT, can be generated by the following perl script
|
|
*
|
|
* #!/usr/bin/perl
|
|
* open TEST, ">test";
|
|
* $bytecode="AHello World!\n\x00BC";
|
|
* print TEST "HelloVM\x00", pack('i',length($bytecode)), $bytecode;
|
|
*
|
|
* A slightly less trivial example can be generated e.g. with
|
|
* $bytecode="AHello, \x00BBAWorld!\n\x00BC";
|
|
*
|
|
* The contents of this file are in the Public Domain.
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#include <jit/jit.h>
|
|
char* readbytes(int, int);
|
|
static void hellovm_output(char *);
|
|
static void hellovm_exit();
|
|
static void out_of_memory();
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int fd;
|
|
char *buf;
|
|
int len;
|
|
jit_context_t context;
|
|
const jit_type_t hellovm_output_arg_type=jit_type_void_ptr;
|
|
jit_type_t hellovm_signature_main;
|
|
jit_type_t hellovm_signature_exit, hellovm_signature_output;
|
|
jit_type_t hellovm_type_string;
|
|
jit_value_t hellovm_reg;
|
|
jit_value_t tmp;
|
|
char *str;
|
|
jit_function_t hellovm_main;
|
|
int pos;
|
|
int willexit=0;
|
|
int retval;
|
|
|
|
if(argc != 2)
|
|
{
|
|
printf("Usage: hellovm program\n");
|
|
return 99;
|
|
}
|
|
|
|
if((fd = open(argv[1], O_RDONLY)) < 0)
|
|
{
|
|
perror(argv[1]);
|
|
return 99;
|
|
}
|
|
|
|
/* read filetype identification string and length field */
|
|
buf=readbytes(fd, 12);
|
|
|
|
/* check filetype identification string */
|
|
if(jit_strcmp("HelloVM", buf)!=0)
|
|
{
|
|
fprintf(stderr, "%s is not in HelloVM format.\n", argv[1]);
|
|
return 99;
|
|
}
|
|
|
|
/* check length field and read bytecode data */
|
|
len=*((int*) (buf+8));
|
|
if(len<0)
|
|
{
|
|
fprintf(stderr, "%s: Invalid length field.\n", argv[1]);
|
|
return 99;
|
|
}
|
|
free(buf);
|
|
buf=readbytes(fd, len);
|
|
close(fd);
|
|
|
|
/* Now the fun begins :) */
|
|
jit_init();
|
|
context = jit_context_create();
|
|
jit_context_build_start(context);
|
|
/* Build signatures for output and exit functions */
|
|
hellovm_signature_output = jit_type_create_signature
|
|
(jit_abi_cdecl, jit_type_void,
|
|
(jit_type_t*)&hellovm_output_arg_type, 1, 0);
|
|
if (!hellovm_signature_output) out_of_memory();
|
|
hellovm_signature_exit = jit_type_create_signature
|
|
(jit_abi_cdecl, jit_type_void, NULL, 0, 0);
|
|
if (!hellovm_signature_exit) out_of_memory();
|
|
/* There is always a single function with signature: int main() */
|
|
hellovm_signature_main = jit_type_create_signature
|
|
(jit_abi_cdecl, jit_type_int, NULL, 0, 0);
|
|
if (!hellovm_signature_main) out_of_memory();
|
|
hellovm_main = jit_function_create(context, hellovm_signature_main);
|
|
if (!hellovm_main) out_of_memory();
|
|
/* The HelloVM has a single register holding a NUL-terminated string */
|
|
hellovm_type_string = jit_type_create_pointer(jit_type_sys_char, 1);
|
|
if (!hellovm_type_string) out_of_memory();
|
|
hellovm_reg = jit_value_create(hellovm_main, hellovm_type_string);
|
|
if (!hellovm_reg) out_of_memory();
|
|
/* Initialize the string register with "" */
|
|
tmp=jit_value_create_nint_constant
|
|
(hellovm_main, hellovm_type_string, (int)"");
|
|
if (!tmp) out_of_memory();
|
|
jit_insn_store(hellovm_main, hellovm_reg, tmp);
|
|
/* Now JIT the supplied bytecodes */
|
|
pos=0;
|
|
while(pos<len)
|
|
{
|
|
switch(buf[pos])
|
|
{
|
|
case 'A':
|
|
{
|
|
/* load string constant into hellovm_reg */
|
|
pos++;
|
|
str=jit_strndup(buf+pos, len-pos);
|
|
if (!str && buf[pos] && len-pos)
|
|
out_of_memory();
|
|
tmp=jit_value_create_nint_constant
|
|
(hellovm_main, hellovm_type_string,
|
|
(int)str);
|
|
if (!tmp) out_of_memory();
|
|
jit_insn_store(hellovm_main, hellovm_reg, tmp);
|
|
pos+=jit_strlen(str)+1;
|
|
}
|
|
break;
|
|
case 'B':
|
|
{
|
|
/* output contents of hellovm_reg */
|
|
pos++;
|
|
jit_insn_call_native
|
|
(hellovm_main, "hellovm_output",
|
|
(void *)hellovm_output,
|
|
hellovm_signature_output,
|
|
&hellovm_reg, 1,
|
|
JIT_CALL_NOTHROW);
|
|
}
|
|
break;
|
|
case 'C':
|
|
{
|
|
/* exit with exit value 0 */
|
|
pos++;
|
|
jit_insn_call_native
|
|
(hellovm_main, "hellovm_exit",
|
|
(void *)hellovm_exit,
|
|
hellovm_signature_exit,
|
|
NULL, 0,
|
|
JIT_CALL_NOTHROW|JIT_CALL_NORETURN);
|
|
willexit=1;
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
fprintf(stderr, "Error: Illegal opcode\n");
|
|
return 99;
|
|
}
|
|
}
|
|
}
|
|
if(willexit)
|
|
{
|
|
if (!jit_function_compile(hellovm_main))
|
|
{
|
|
fprintf(stderr, "JIT compilation error\n");
|
|
return 99;
|
|
}
|
|
jit_context_build_end(context);
|
|
free(buf);
|
|
if (!jit_function_apply(hellovm_main, NULL, &retval))
|
|
{
|
|
fprintf(stderr, "Exception during execution\n");
|
|
return 99;
|
|
}
|
|
/* not reached with the current instruction set */
|
|
return retval;
|
|
}
|
|
else
|
|
{
|
|
jit_function_abandon(hellovm_main);
|
|
fprintf(stderr, "Error: program without exit opcode\n");
|
|
return 99;
|
|
}
|
|
}
|
|
|
|
static void hellovm_output(char *value)
|
|
{
|
|
fputs(value, stdout);
|
|
}
|
|
|
|
static void hellovm_nulput(char *value)
|
|
{
|
|
putchar(0);
|
|
}
|
|
|
|
static void hellovm_exit()
|
|
{
|
|
exit(0);
|
|
}
|
|
|
|
static void out_of_memory()
|
|
{
|
|
fprintf(stderr, "Out of memory.\n");
|
|
exit(99);
|
|
}
|
|
|
|
/* This function will not return unless the specified number of bytes
|
|
* has been read successfully */
|
|
char* readbytes(int file, int bytestoread)
|
|
{
|
|
char *buffer;
|
|
int pos=0;
|
|
int bytesread;
|
|
|
|
if((buffer = jit_malloc(bytestoread)) == NULL)
|
|
{
|
|
perror("memory allocation error in readbytes()");
|
|
exit(99);
|
|
}
|
|
|
|
while (pos<bytestoread)
|
|
{
|
|
bytesread=read(file, buffer+pos, bytestoread-pos);
|
|
if(bytesread==-1)
|
|
{
|
|
perror("read error in readbytes()");
|
|
exit(99);
|
|
}
|
|
if(bytesread==0)
|
|
{
|
|
fprintf(stderr, "unexpected eof in readbytes()\n");
|
|
exit(99);
|
|
}
|
|
pos+=bytesread;
|
|
}
|
|
return buffer;
|
|
}
|
|
|