353 lines
13 KiB
C
Raw Normal View History

2025-12-02 06:54:32 +01:00
#define _POSIX_C_SOURCE 200809L
#include "ir.h"
#include "../runtime/labeltable.h"
2025-12-04 06:14:22 +01:00
#include "../utils/safe_alloc.h"
2025-12-02 06:54:32 +01:00
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
RavaInstructionList_t* rava_instruction_list_create() {
RavaInstructionList_t *list = calloc(1, sizeof(RavaInstructionList_t));
list->capacity = 16;
list->instructions = malloc(sizeof(RavaInstruction_t) * list->capacity);
list->count = 0;
list->next_label_id = 1;
return list;
}
void rava_instruction_list_destroy(RavaInstructionList_t *list) {
if (!list) return;
free(list->instructions);
free(list);
}
void rava_instruction_list_add(RavaInstructionList_t *list, RavaInstruction_t instr) {
if (list->count >= list->capacity) {
list->capacity *= 2;
2025-12-04 06:14:22 +01:00
RavaInstruction_t *new_instrs = rava_safe_realloc(list->instructions,
sizeof(RavaInstruction_t) * list->capacity);
if (!new_instrs) return;
list->instructions = new_instrs;
2025-12-02 06:54:32 +01:00
}
list->instructions[list->count++] = instr;
}
int rava_instruction_list_new_label(RavaInstructionList_t *list) {
return list->next_label_id++;
}
RavaMethod_t* rava_method_create(const char *name, RavaType_t *return_type) {
RavaMethod_t *method = calloc(1, sizeof(RavaMethod_t));
method->name = strdup(name);
method->return_type = return_type;
method->param_types = NULL;
method->param_count = 0;
method->local_count = 0;
method->instructions = rava_instruction_list_create();
method->label_table = NULL;
return method;
}
void rava_method_destroy(RavaMethod_t *method) {
if (!method) return;
free(method->name);
free(method->param_types);
rava_instruction_list_destroy(method->instructions);
if (method->label_table) {
rava_labeltable_destroy(method->label_table);
}
free(method);
}
2025-12-03 17:55:37 +01:00
static inline uint32_t _method_hash(const char *name) {
uint32_t hash = 5381;
while (*name) hash = ((hash << 5) + hash) ^ (uint32_t)*name++;
return hash & (RAVA_METHOD_HASH_SIZE - 1);
}
2025-12-02 06:54:32 +01:00
RavaClass_t* rava_class_create(const char *name) {
RavaClass_t *class = calloc(1, sizeof(RavaClass_t));
class->name = strdup(name);
class->superclass = NULL;
class->methods = NULL;
class->method_count = 0;
class->method_capacity = 0;
2025-12-03 17:55:37 +01:00
for (int i = 0; i < RAVA_METHOD_HASH_SIZE; i++) {
class->method_hash[i] = -1;
}
2025-12-02 06:54:32 +01:00
return class;
}
void rava_class_destroy(RavaClass_t *class) {
if (!class) return;
free(class->name);
free(class->superclass);
for (size_t i = 0; i < class->method_count; i++) {
rava_method_destroy(class->methods[i]);
}
free(class->methods);
free(class);
}
void rava_class_add_method(RavaClass_t *class, RavaMethod_t *method) {
if (class->method_count >= class->method_capacity) {
size_t new_capacity = class->method_capacity == 0 ? 4 : class->method_capacity * 2;
2025-12-04 06:14:22 +01:00
RavaMethod_t **new_methods = rava_safe_realloc(class->methods, sizeof(RavaMethod_t*) * new_capacity);
if (!new_methods) return;
class->methods = new_methods;
2025-12-02 06:54:32 +01:00
class->method_capacity = new_capacity;
}
2025-12-03 17:55:37 +01:00
uint32_t h = _method_hash(method->name);
class->method_hash[h] = (int)class->method_count;
2025-12-02 06:54:32 +01:00
class->methods[class->method_count++] = method;
}
RavaProgram_t* rava_program_create() {
RavaProgram_t *program = calloc(1, sizeof(RavaProgram_t));
program->classes = NULL;
program->class_count = 0;
program->class_capacity = 0;
return program;
}
void rava_program_destroy(RavaProgram_t *program) {
if (!program) return;
for (size_t i = 0; i < program->class_count; i++) {
rava_class_destroy(program->classes[i]);
}
free(program->classes);
free(program);
}
void rava_program_add_class(RavaProgram_t *program, RavaClass_t *class) {
if (program->class_count >= program->class_capacity) {
size_t new_capacity = program->class_capacity == 0 ? 4 : program->class_capacity * 2;
2025-12-04 06:14:22 +01:00
RavaClass_t **new_classes = rava_safe_realloc(program->classes, sizeof(RavaClass_t*) * new_capacity);
if (!new_classes) return;
program->classes = new_classes;
2025-12-02 06:54:32 +01:00
program->class_capacity = new_capacity;
}
program->classes[program->class_count++] = class;
}
2025-12-03 17:55:37 +01:00
static void _compute_max_stack(RavaMethod_t *method) {
if (!method->instructions) return;
int depth = 0;
int max_depth = 0;
for (size_t i = 0; i < method->instructions->count; i++) {
RavaInstruction_t *instr = &method->instructions->instructions[i];
switch (instr->opcode) {
case RAVA_OP_LOAD_CONST:
case RAVA_OP_LOAD_LONG:
case RAVA_OP_LOAD_DOUBLE:
case RAVA_OP_LOAD_STRING:
case RAVA_OP_LOAD_LOCAL:
case RAVA_OP_LOAD_FIELD:
case RAVA_OP_LOAD_STATIC:
case RAVA_OP_LOAD_THIS:
case RAVA_OP_NEW:
case RAVA_OP_DUP:
depth++;
break;
case RAVA_OP_STORE_LOCAL:
case RAVA_OP_STORE_FIELD:
case RAVA_OP_STORE_STATIC:
case RAVA_OP_POP:
case RAVA_OP_RETURN:
case RAVA_OP_THROW:
if (depth > 0) depth--;
break;
case RAVA_OP_ADD:
case RAVA_OP_SUB:
case RAVA_OP_MUL:
case RAVA_OP_DIV:
case RAVA_OP_MOD:
case RAVA_OP_EQ:
case RAVA_OP_NE:
case RAVA_OP_LT:
case RAVA_OP_LE:
case RAVA_OP_GT:
case RAVA_OP_GE:
case RAVA_OP_AND:
case RAVA_OP_OR:
case RAVA_OP_XOR:
case RAVA_OP_SHL:
case RAVA_OP_SHR:
case RAVA_OP_USHR:
case RAVA_OP_STORE_ARRAY:
if (depth > 0) depth--;
break;
case RAVA_OP_LOAD_ARRAY:
case RAVA_OP_ARRAY_LENGTH:
break;
default:
break;
}
if (depth > max_depth) max_depth = depth;
}
method->max_stack = max_depth + 16;
}
2025-12-04 06:14:22 +01:00
static void _mark_simple_methods(RavaMethod_t *method) {
if (!method || !method->instructions) return;
method->is_leaf = true;
method->is_simple = (method->instructions->count < 20);
for (size_t i = 0; i < method->instructions->count; i++) {
RavaOpCode_e op = method->instructions->instructions[i].opcode;
if (op == RAVA_OP_CALL || op == RAVA_OP_CALL_STATIC ||
op == RAVA_OP_CALL_RECURSIVE || op == RAVA_OP_CALL_VIRTUAL) {
method->is_leaf = false;
method->is_simple = false;
}
if (op == RAVA_OP_JUMP || op == RAVA_OP_JUMP_IF_TRUE ||
op == RAVA_OP_JUMP_IF_FALSE) {
method->is_simple = false;
}
}
}
2025-12-03 15:01:02 +01:00
void rava_program_prebuild_label_tables(RavaProgram_t *program) {
if (!program) return;
for (size_t i = 0; i < program->class_count; i++) {
RavaClass_t *class = program->classes[i];
for (size_t j = 0; j < class->method_count; j++) {
RavaMethod_t *method = class->methods[j];
if (!method->label_table && method->instructions) {
method->label_table = rava_labeltable_create(method->instructions);
}
2025-12-03 17:55:37 +01:00
if (method->max_stack == 0) {
_compute_max_stack(method);
}
2025-12-04 06:14:22 +01:00
_mark_simple_methods(method);
2025-12-03 15:01:02 +01:00
}
}
}
2025-12-02 06:54:32 +01:00
static const char* _rava_opcode_name(RavaOpCode_e opcode) {
switch (opcode) {
case RAVA_OP_NOP: return "NOP";
case RAVA_OP_LOAD_CONST: return "LOAD_CONST";
case RAVA_OP_LOAD_LOCAL: return "LOAD_LOCAL";
case RAVA_OP_STORE_LOCAL: return "STORE_LOCAL";
case RAVA_OP_ADD: return "ADD";
case RAVA_OP_SUB: return "SUB";
case RAVA_OP_MUL: return "MUL";
case RAVA_OP_DIV: return "DIV";
case RAVA_OP_MOD: return "MOD";
case RAVA_OP_NEG: return "NEG";
case RAVA_OP_EQ: return "EQ";
case RAVA_OP_NE: return "NE";
case RAVA_OP_LT: return "LT";
case RAVA_OP_LE: return "LE";
case RAVA_OP_GT: return "GT";
case RAVA_OP_GE: return "GE";
case RAVA_OP_JUMP: return "JUMP";
case RAVA_OP_JUMP_IF_TRUE: return "JUMP_IF_TRUE";
case RAVA_OP_JUMP_IF_FALSE: return "JUMP_IF_FALSE";
case RAVA_OP_LABEL: return "LABEL";
case RAVA_OP_CALL: return "CALL";
case RAVA_OP_CALL_STATIC: return "CALL_STATIC";
2025-12-03 23:51:38 +01:00
case RAVA_OP_CALL_RECURSIVE: return "CALL_RECURSIVE";
2025-12-04 06:14:22 +01:00
case RAVA_OP_CALL_INLINE: return "CALL_INLINE";
2025-12-02 06:54:32 +01:00
case RAVA_OP_RETURN: return "RETURN";
case RAVA_OP_RETURN_VOID: return "RETURN_VOID";
case RAVA_OP_NEW: return "NEW";
case RAVA_OP_NEW_ARRAY: return "NEW_ARRAY";
2025-12-03 14:08:55 +01:00
case RAVA_OP_NEW_ARRAY_OF_ARRAYS: return "NEW_ARRAY_OF_ARRAYS";
2025-12-02 06:54:32 +01:00
case RAVA_OP_ARRAY_LENGTH: return "ARRAY_LENGTH";
case RAVA_OP_LOAD_ARRAY: return "LOAD_ARRAY";
2025-12-04 06:14:22 +01:00
case RAVA_OP_LOAD_ARRAY_UNCHECKED: return "LOAD_ARRAY_UNCHECKED";
2025-12-02 06:54:32 +01:00
case RAVA_OP_STORE_ARRAY: return "STORE_ARRAY";
2025-12-04 06:14:22 +01:00
case RAVA_OP_STORE_ARRAY_UNCHECKED: return "STORE_ARRAY_UNCHECKED";
2025-12-02 06:54:32 +01:00
case RAVA_OP_POP: return "POP";
case RAVA_OP_DUP: return "DUP";
case RAVA_OP_PRINT: return "PRINT";
case RAVA_OP_PRINTLN: return "PRINTLN";
2025-12-04 16:49:20 +01:00
case RAVA_OP_ARRAYLIST_NEW: return "ARRAYLIST_NEW";
case RAVA_OP_ARRAYLIST_ADD: return "ARRAYLIST_ADD";
case RAVA_OP_ARRAYLIST_GET: return "ARRAYLIST_GET";
case RAVA_OP_ARRAYLIST_SET: return "ARRAYLIST_SET";
case RAVA_OP_ARRAYLIST_SIZE: return "ARRAYLIST_SIZE";
case RAVA_OP_ARRAYLIST_REMOVE: return "ARRAYLIST_REMOVE";
case RAVA_OP_ARRAYLIST_CLEAR: return "ARRAYLIST_CLEAR";
case RAVA_OP_ARRAYLIST_ISEMPTY: return "ARRAYLIST_ISEMPTY";
case RAVA_OP_HASHMAP_NEW: return "HASHMAP_NEW";
case RAVA_OP_HASHMAP_PUT: return "HASHMAP_PUT";
case RAVA_OP_HASHMAP_GET: return "HASHMAP_GET";
case RAVA_OP_HASHMAP_REMOVE: return "HASHMAP_REMOVE";
case RAVA_OP_HASHMAP_SIZE: return "HASHMAP_SIZE";
case RAVA_OP_HASHMAP_CONTAINSKEY: return "HASHMAP_CONTAINSKEY";
case RAVA_OP_HASHMAP_CLEAR: return "HASHMAP_CLEAR";
2025-12-05 00:28:01 +01:00
case RAVA_OP_SOCKET_NEW: return "SOCKET_NEW";
case RAVA_OP_SOCKET_CONNECT: return "SOCKET_CONNECT";
case RAVA_OP_SOCKET_READ: return "SOCKET_READ";
case RAVA_OP_SOCKET_WRITE: return "SOCKET_WRITE";
case RAVA_OP_SOCKET_CLOSE: return "SOCKET_CLOSE";
case RAVA_OP_SERVER_SOCKET_NEW: return "SERVER_SOCKET_NEW";
case RAVA_OP_SERVER_SOCKET_ACCEPT: return "SERVER_SOCKET_ACCEPT";
case RAVA_OP_SOCKET_GET_INPUT_STREAM: return "SOCKET_GET_INPUT_STREAM";
case RAVA_OP_SOCKET_GET_OUTPUT_STREAM: return "SOCKET_GET_OUTPUT_STREAM";
case RAVA_OP_INPUT_STREAM_READ: return "INPUT_STREAM_READ";
case RAVA_OP_OUTPUT_STREAM_WRITE: return "OUTPUT_STREAM_WRITE";
case RAVA_OP_STREAM_CLOSE: return "STREAM_CLOSE";
case RAVA_OP_METHOD_REF: return "METHOD_REF";
case RAVA_OP_METHOD_REF_INVOKE: return "METHOD_REF_INVOKE";
2025-12-02 06:54:32 +01:00
default: return "UNKNOWN";
}
}
void rava_ir_print(RavaProgram_t *program) {
if (!program) return;
printf("IR Program (%zu classes)\n", program->class_count);
printf("================================================================================\n\n");
for (size_t i = 0; i < program->class_count; i++) {
RavaClass_t *class = program->classes[i];
printf("Class: %s\n", class->name);
for (size_t j = 0; j < class->method_count; j++) {
RavaMethod_t *method = class->methods[j];
printf(" Method: %s (locals: %d)\n", method->name, method->local_count);
for (size_t k = 0; k < method->instructions->count; k++) {
RavaInstruction_t *instr = &method->instructions->instructions[k];
printf(" %04zu %-15s", k, _rava_opcode_name(instr->opcode));
switch (instr->opcode) {
case RAVA_OP_LOAD_CONST:
printf(" %lld", (long long)instr->operand.int_value);
break;
case RAVA_OP_LOAD_LOCAL:
case RAVA_OP_STORE_LOCAL:
printf(" [%d]", instr->operand.var.index);
break;
case RAVA_OP_LABEL:
case RAVA_OP_JUMP:
case RAVA_OP_JUMP_IF_TRUE:
case RAVA_OP_JUMP_IF_FALSE:
printf(" L%d", instr->operand.label_id);
break;
case RAVA_OP_CALL_STATIC:
printf(" %s.%s",
instr->operand.call.class_name,
instr->operand.call.method_name);
break;
2025-12-03 23:51:38 +01:00
case RAVA_OP_CALL_RECURSIVE:
printf(" %s.%s (recursive)",
instr->operand.call.class_name,
instr->operand.call.method_name);
break;
2025-12-02 06:54:32 +01:00
default:
break;
}
printf("\n");
}
printf("\n");
}
}
}