136 lines
3.4 KiB
C
136 lines
3.4 KiB
C
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
|
|
#include "vmstate.h"
|
|
#include "unit.h"
|
|
#include "error.h"
|
|
#include "load.h"
|
|
#include "hash.h"
|
|
#include "list.h"
|
|
|
|
static int lookup_sym(struct vm_unit_info *info,
|
|
const char *name,
|
|
struct vm_export_entry **ent) {
|
|
for (size_t i = 0; i < info->exports.size; ++i) {
|
|
struct vm_export_entry *export = vector_ref(&info->exports, i);
|
|
if (!strcmp(export->name, name)) {
|
|
*ent = export;
|
|
return 0;
|
|
}
|
|
}
|
|
return -ERR_SYMBOL_UNDEFINED;
|
|
}
|
|
|
|
static int execute_file(const char *filename) {
|
|
FILE *fp;
|
|
int res;
|
|
struct hash unit_map;
|
|
struct hash_pair *pair;
|
|
struct list_head unresolved;
|
|
struct vm_export_entry *export;
|
|
struct vm_ref_entry *ref_entry;
|
|
struct vm_state vm;
|
|
struct vm_unit_info *info;
|
|
struct vm_unresolved_ref *ref;
|
|
|
|
if ((res = vm_state_init(&vm, 4096)) != 0) {
|
|
return res;
|
|
}
|
|
|
|
list_head_init(&unresolved);
|
|
if (shash_init(&unit_map, 16) != 0) {
|
|
return -ERR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
if ((fp = fopen(filename, "rb")) == NULL) {
|
|
return -ERR_IMAGE_IO;
|
|
}
|
|
|
|
// Load main unit
|
|
if ((res = vm_load_unit_file(&vm, NULL, &unresolved, fp)) != 0) {
|
|
fclose(fp);
|
|
return res;
|
|
}
|
|
fclose(fp);
|
|
|
|
// Load any referenced units
|
|
list_for_each_entry(ref, &unresolved, link) {
|
|
struct vm_unit_info *info;
|
|
pair = hash_lookup(&unit_map, ref->unit_name);
|
|
|
|
if (!pair) {
|
|
info = malloc(sizeof(struct vm_unit_info));
|
|
if (!info) {
|
|
return -ERR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
if ((res = vm_load_unit(&vm, info, &unresolved, ref->unit_name)) != 0) {
|
|
return res;
|
|
}
|
|
|
|
if (hash_insert(&unit_map, ref->unit_name, info) != 0) {
|
|
return -ERR_OUT_OF_MEMORY;
|
|
}
|
|
}
|
|
}
|
|
|
|
while (!list_empty(&unresolved)) {
|
|
ref = list_first_entry(&unresolved, struct vm_unresolved_ref, link);
|
|
pair = hash_lookup(&unit_map, ref->unit_name);
|
|
assert(pair);
|
|
info = pair->value;
|
|
|
|
// Lookup symbol in that unit
|
|
if ((res = lookup_sym(info, ref->sym_name, &export)) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
// Resolve the reference
|
|
ref_entry = ref->entry;
|
|
ref_entry->unit_index = info->index;
|
|
if (export->is_native) {
|
|
ref_entry->flags = REF_NATIVE;
|
|
ref_entry->ref_native = export->ex_native;
|
|
} else {
|
|
ref_entry->flags = 0;
|
|
ref_entry->ref_index = export->ex_index;
|
|
}
|
|
|
|
list_del(&ref->link);
|
|
free(ref);
|
|
}
|
|
|
|
for (size_t i = 0; i < unit_map.bucket_count; ++i) {
|
|
list_for_each_entry(pair, &unit_map.buckets[i], link) {
|
|
info = pair->value;
|
|
vector_free(&info->exports);
|
|
free(info);
|
|
}
|
|
}
|
|
hash_free(&unit_map);
|
|
|
|
// Start execution
|
|
if ((res = vm_eval_unit(&vm, 0)) != 0) {
|
|
return res;
|
|
}
|
|
|
|
vm_state_free(&vm);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
int res;
|
|
if (argc != 2) {
|
|
fprintf(stderr, "Usage: %s INPUT", argv[0]);
|
|
return EXIT_FAILURE;
|
|
}
|
|
if ((res = execute_file(argv[1])) != 0) {
|
|
fprintf(stderr, "%s: %s\n", argv[1], vm_strerror(res));
|
|
return EXIT_FAILURE;
|
|
}
|
|
return EXIT_SUCCESS;
|
|
}
|