#define _POSIX_C_SOURCE 200809L #include "runtime.h" #include "labeltable.h" #include "methodcache.h" #include "nanbox.h" #include "fastframe.h" #include "superinst.h" #include #include #include #include #include #include #define STACK_ENSURE_CAPACITY(stack) do { \ if ((stack)->top >= (stack)->capacity) { \ (stack)->capacity *= 2; \ (stack)->values = realloc((stack)->values, sizeof(RavaValue_t) * (stack)->capacity); \ } \ } while(0) #define STACK_PUSH(stack, val) do { \ STACK_ENSURE_CAPACITY(stack); \ (stack)->values[(stack)->top++] = (val); \ } while(0) #define STACK_POP(stack) ((stack)->top > 0 ? (stack)->values[--(stack)->top] : (RavaValue_t){0}) #define STACK_PEEK(stack) ((stack)->top > 0 ? (stack)->values[(stack)->top - 1] : (RavaValue_t){0}) #define STACK_PUSH_INT(stack, v) do { \ STACK_ENSURE_CAPACITY(stack); \ RavaValue_t _v; _v.type = RAVA_VAL_INT; _v.data.int_val = (v); \ (stack)->values[(stack)->top++] = _v; \ } while(0) #define STACK_PUSH_LONG(stack, v) do { \ STACK_ENSURE_CAPACITY(stack); \ RavaValue_t _v; _v.type = RAVA_VAL_LONG; _v.data.long_val = (v); \ (stack)->values[(stack)->top++] = _v; \ } while(0) #define STACK_PUSH_BOOL(stack, v) do { \ STACK_ENSURE_CAPACITY(stack); \ RavaValue_t _v; _v.type = RAVA_VAL_BOOLEAN; _v.data.bool_val = (v); \ (stack)->values[(stack)->top++] = _v; \ } while(0) #define VALUE_IS_INT(v) ((v).type == RAVA_VAL_INT) #define VALUE_IS_LONG(v) ((v).type == RAVA_VAL_LONG) #define VALUE_AS_INT_FAST(v) ((v).data.int_val) #define VALUE_AS_LONG_FAST(v) ((v).data.long_val) RavaValue_t rava_value_int(int32_t value) { RavaValue_t val; val.type = RAVA_VAL_INT; val.data.int_val = value; return val; } RavaValue_t rava_value_long(int64_t value) { RavaValue_t val; val.type = RAVA_VAL_LONG; val.data.long_val = value; return val; } RavaValue_t rava_value_float(float value) { RavaValue_t val; val.type = RAVA_VAL_FLOAT; val.data.float_val = value; return val; } RavaValue_t rava_value_double(double value) { RavaValue_t val; val.type = RAVA_VAL_DOUBLE; val.data.double_val = value; return val; } RavaValue_t rava_value_boolean(bool value) { RavaValue_t val; val.type = RAVA_VAL_BOOLEAN; val.data.bool_val = value; return val; } RavaValue_t rava_value_null() { RavaValue_t val; val.type = RAVA_VAL_NULL; val.data.object_val = NULL; return val; } RavaValue_t rava_value_array(RavaArray_t *array) { RavaValue_t val; val.type = RAVA_VAL_ARRAY; val.data.array_val = array; return val; } RavaValue_t rava_value_string(const char *str) { RavaValue_t val; val.type = RAVA_VAL_STRING; val.data.string_val = str ? strdup(str) : NULL; return val; } const char* rava_value_as_string(RavaValue_t value) { if (value.type == RAVA_VAL_STRING) { return value.data.string_val ? value.data.string_val : ""; } return ""; } static inline RavaNanboxValue_t rava_value_to_nanbox(RavaValue_t val) { switch (val.type) { case RAVA_VAL_INT: return rava_nanbox_int(val.data.int_val); case RAVA_VAL_LONG: return rava_nanbox_long(val.data.long_val); case RAVA_VAL_DOUBLE: return rava_nanbox_double(val.data.double_val); case RAVA_VAL_FLOAT: return rava_nanbox_double((double)val.data.float_val); case RAVA_VAL_BOOLEAN: return rava_nanbox_bool(val.data.bool_val); case RAVA_VAL_NULL: return rava_nanbox_null(); case RAVA_VAL_STRING: return rava_nanbox_string(val.data.string_val); case RAVA_VAL_OBJECT: return rava_nanbox_object(val.data.object_val); case RAVA_VAL_ARRAY: return rava_nanbox_array(val.data.array_val); default: return rava_nanbox_null(); } } static inline RavaValue_t rava_nanbox_to_value(RavaNanboxValue_t nb) { RavaValue_t val; if (rava_nanbox_is_int(nb)) { val.type = RAVA_VAL_INT; val.data.int_val = rava_nanbox_as_int(nb); } else if (rava_nanbox_is_long(nb)) { val.type = RAVA_VAL_LONG; val.data.long_val = rava_nanbox_as_long(nb); } else if (rava_nanbox_is_double(nb)) { val.type = RAVA_VAL_DOUBLE; val.data.double_val = rava_nanbox_as_double(nb); } else if (rava_nanbox_is_bool(nb)) { val.type = RAVA_VAL_BOOLEAN; val.data.bool_val = rava_nanbox_as_bool(nb); } else if (rava_nanbox_is_null(nb)) { val.type = RAVA_VAL_NULL; val.data.object_val = NULL; } else if (rava_nanbox_is_string(nb)) { val.type = RAVA_VAL_STRING; val.data.string_val = (char*)rava_nanbox_as_string(nb); } else if (rava_nanbox_is_object(nb)) { val.type = RAVA_VAL_OBJECT; val.data.object_val = rava_nanbox_as_object(nb); } else if (rava_nanbox_is_array(nb)) { val.type = RAVA_VAL_ARRAY; val.data.array_val = rava_nanbox_as_array(nb); } else { val.type = RAVA_VAL_NULL; val.data.object_val = NULL; } return val; } RavaArray_t* rava_array_create(RavaValueType_e element_type, size_t length) { if (length > 1000000) { length = 1000000; } RavaArray_t *array = malloc(sizeof(RavaArray_t)); if (!array) return NULL; array->element_type = element_type; array->length = length; array->data = NULL; switch (element_type) { case RAVA_VAL_INT: array->data = calloc(length, sizeof(int32_t)); break; case RAVA_VAL_LONG: array->data = calloc(length, sizeof(int64_t)); break; case RAVA_VAL_DOUBLE: array->data = calloc(length, sizeof(double)); break; case RAVA_VAL_BOOLEAN: array->data = calloc(length, sizeof(bool)); break; case RAVA_VAL_ARRAY: case RAVA_VAL_OBJECT: array->data = calloc(length, sizeof(RavaValue_t)); break; default: array->data = calloc(length, sizeof(void*)); break; } if (!array->data && length > 0) { free(array); return NULL; } return array; } void rava_array_destroy(RavaArray_t *array) { if (!array) return; free(array->data); free(array); } void rava_array_set_int(RavaArray_t *array, size_t index, int32_t value) { if (!array || !array->data || index >= array->length) return; ((int32_t*)array->data)[index] = value; } int32_t rava_array_get_int(RavaArray_t *array, size_t index) { if (!array || !array->data || index >= array->length) return 0; return ((int32_t*)array->data)[index]; } void rava_array_set_value(RavaArray_t *array, size_t index, RavaValue_t value) { if (!array || !array->data || index >= array->length) return; ((RavaValue_t*)array->data)[index] = value; } RavaValue_t rava_array_get_value(RavaArray_t *array, size_t index) { if (!array || !array->data || index >= array->length) return rava_value_null(); return ((RavaValue_t*)array->data)[index]; } size_t rava_array_length(RavaArray_t *array) { if (!array) return 0; return array->length; } RavaObject_t* rava_object_create(const char *class_name) { RavaObject_t *obj = calloc(1, sizeof(RavaObject_t)); if (!obj) return NULL; obj->class_name = strdup(class_name); obj->field_capacity = 8; obj->field_names = calloc(obj->field_capacity, sizeof(char*)); obj->field_values = calloc(obj->field_capacity, sizeof(RavaValue_t)); obj->field_count = 0; return obj; } void rava_object_destroy(RavaObject_t *obj) { if (!obj) return; free(obj->class_name); for (size_t i = 0; i < obj->field_count; i++) { free(obj->field_names[i]); } free(obj->field_names); free(obj->field_values); free(obj); } void rava_object_set_field(RavaObject_t *obj, const char *name, RavaValue_t value) { if (!obj || !name) return; for (size_t i = 0; i < obj->field_count; i++) { if (strcmp(obj->field_names[i], name) == 0) { obj->field_values[i] = value; return; } } if (obj->field_count >= obj->field_capacity) { obj->field_capacity *= 2; obj->field_names = realloc(obj->field_names, obj->field_capacity * sizeof(char*)); obj->field_values = realloc(obj->field_values, obj->field_capacity * sizeof(RavaValue_t)); } obj->field_names[obj->field_count] = strdup(name); obj->field_values[obj->field_count] = value; obj->field_count++; } RavaValue_t rava_object_get_field(RavaObject_t *obj, const char *name) { if (!obj || !name) return rava_value_null(); for (size_t i = 0; i < obj->field_count; i++) { if (strcmp(obj->field_names[i], name) == 0) { return obj->field_values[i]; } } return rava_value_null(); } RavaValue_t rava_value_object(RavaObject_t *obj) { RavaValue_t val; val.type = RAVA_VAL_OBJECT; val.data.object_val = obj; return val; } int32_t rava_value_as_int(RavaValue_t value) { switch (value.type) { case RAVA_VAL_INT: return value.data.int_val; case RAVA_VAL_LONG: return (int32_t)value.data.long_val; case RAVA_VAL_FLOAT: return (int32_t)value.data.float_val; case RAVA_VAL_DOUBLE: return (int32_t)value.data.double_val; case RAVA_VAL_BOOLEAN: return value.data.bool_val ? 1 : 0; case RAVA_VAL_CHAR: return value.data.char_val; default: return 0; } } int64_t rava_value_as_long(RavaValue_t value) { switch (value.type) { case RAVA_VAL_INT: return value.data.int_val; case RAVA_VAL_LONG: return value.data.long_val; case RAVA_VAL_FLOAT: return (int64_t)value.data.float_val; case RAVA_VAL_DOUBLE: return (int64_t)value.data.double_val; default: return 0; } } double rava_value_as_double(RavaValue_t value) { switch (value.type) { case RAVA_VAL_INT: return value.data.int_val; case RAVA_VAL_LONG: return (double)value.data.long_val; case RAVA_VAL_FLOAT: return value.data.float_val; case RAVA_VAL_DOUBLE: return value.data.double_val; default: return 0.0; } } bool rava_value_as_boolean(RavaValue_t value) { if (value.type == RAVA_VAL_BOOLEAN) { return value.data.bool_val; } return rava_value_as_int(value) != 0; } RavaStack_t* rava_stack_create(size_t capacity) { RavaStack_t *stack = malloc(sizeof(RavaStack_t)); stack->capacity = capacity; stack->values = malloc(sizeof(RavaValue_t) * capacity); stack->top = 0; return stack; } void rava_stack_destroy(RavaStack_t *stack) { if (!stack) return; free(stack->values); free(stack); } void rava_stack_push(RavaStack_t *stack, RavaValue_t value) { if (stack->top >= stack->capacity) { stack->capacity *= 2; stack->values = realloc(stack->values, sizeof(RavaValue_t) * stack->capacity); } stack->values[stack->top++] = value; } RavaValue_t rava_stack_pop(RavaStack_t *stack) { if (stack->top == 0) { return rava_value_int(0); } return stack->values[--stack->top]; } RavaValue_t rava_stack_peek(RavaStack_t *stack) { if (stack->top == 0) { return rava_value_int(0); } return stack->values[stack->top - 1]; } bool rava_stack_is_empty(RavaStack_t *stack) { return stack->top == 0; } RavaCallFrame_t* rava_call_frame_create(RavaMethod_t *method) { RavaCallFrame_t *frame = calloc(1, sizeof(RavaCallFrame_t)); frame->method = method; frame->local_count = method->local_count; frame->locals = calloc(method->local_count, sizeof(RavaValue_t)); frame->pc = 0; frame->operand_stack = rava_stack_create(256); frame->has_this = false; frame->this_ref = rava_value_null(); return frame; } void rava_call_frame_destroy(RavaCallFrame_t *frame) { if (!frame) return; free(frame->locals); rava_stack_destroy(frame->operand_stack); free(frame); } RavaCallStack_t* rava_call_stack_create() { RavaCallStack_t *stack = malloc(sizeof(RavaCallStack_t)); stack->capacity = 256; stack->frames = malloc(sizeof(RavaCallFrame_t*) * stack->capacity); stack->count = 0; return stack; } void rava_call_stack_destroy(RavaCallStack_t *stack) { if (!stack) return; for (size_t i = 0; i < stack->count; i++) { rava_call_frame_destroy(stack->frames[i]); } free(stack->frames); free(stack); } void rava_call_stack_push(RavaCallStack_t *stack, RavaCallFrame_t *frame) { if (stack->count >= stack->capacity) { stack->capacity *= 2; stack->frames = realloc(stack->frames, sizeof(RavaCallFrame_t*) * stack->capacity); } stack->frames[stack->count++] = frame; } RavaCallFrame_t* rava_call_stack_pop(RavaCallStack_t *stack) { if (stack->count == 0) return NULL; RavaCallFrame_t *frame = stack->frames[--stack->count]; return frame; } RavaCallFrame_t* rava_call_stack_current(RavaCallStack_t *stack) { if (stack->count == 0) return NULL; return stack->frames[stack->count - 1]; } static RavaStaticFieldTable_t* rava_static_field_table_create() { RavaStaticFieldTable_t *table = malloc(sizeof(RavaStaticFieldTable_t)); table->capacity = 16; table->fields = calloc(table->capacity, sizeof(RavaStaticField_t)); table->count = 0; return table; } static void rava_static_field_table_destroy(RavaStaticFieldTable_t *table) { if (!table) return; for (size_t i = 0; i < table->count; i++) { free(table->fields[i].class_name); free(table->fields[i].field_name); } free(table->fields); free(table); } static RavaValue_t* rava_static_field_table_get(RavaStaticFieldTable_t *table, const char *class_name, const char *field_name) { for (size_t i = 0; i < table->count; i++) { if (strcmp(table->fields[i].class_name, class_name) == 0 && strcmp(table->fields[i].field_name, field_name) == 0) { return &table->fields[i].value; } } return NULL; } static void rava_static_field_table_set(RavaStaticFieldTable_t *table, const char *class_name, const char *field_name, RavaValue_t value) { RavaValue_t *existing = rava_static_field_table_get(table, class_name, field_name); if (existing) { *existing = value; return; } if (table->count >= table->capacity) { table->capacity *= 2; table->fields = realloc(table->fields, sizeof(RavaStaticField_t) * table->capacity); } table->fields[table->count].class_name = strdup(class_name); table->fields[table->count].field_name = strdup(field_name); table->fields[table->count].value = value; table->count++; } static RavaExceptionStack_t* rava_exception_stack_create() { RavaExceptionStack_t *stack = calloc(1, sizeof(RavaExceptionStack_t)); stack->capacity = 16; stack->handlers = calloc(stack->capacity, sizeof(RavaExceptionHandler_t)); stack->count = 0; return stack; } static void rava_exception_stack_destroy(RavaExceptionStack_t *stack) { if (!stack) return; free(stack->handlers); free(stack); } static void rava_exception_stack_push(RavaExceptionStack_t *stack, RavaExceptionHandler_t handler) { if (stack->count >= stack->capacity) { stack->capacity *= 2; stack->handlers = realloc(stack->handlers, stack->capacity * sizeof(RavaExceptionHandler_t)); } stack->handlers[stack->count++] = handler; } static bool rava_exception_stack_pop(RavaExceptionStack_t *stack, RavaExceptionHandler_t *handler) { if (stack->count == 0) return false; *handler = stack->handlers[--stack->count]; return true; } RavaVM_t* rava_vm_create(RavaProgram_t *program) { RavaVM_t *vm = calloc(1, sizeof(RavaVM_t)); vm->program = program; vm->call_stack = rava_call_stack_create(); vm->static_fields = rava_static_field_table_create(); vm->method_cache = rava_methodcache_create(); vm->error_message = NULL; vm->had_error = false; vm->has_exception = false; vm->exception_value = rava_value_null(); vm->exception_stack = rava_exception_stack_create(); return vm; } void rava_vm_destroy(RavaVM_t *vm) { if (!vm) return; rava_call_stack_destroy(vm->call_stack); rava_static_field_table_destroy(vm->static_fields); if (vm->method_cache) { rava_methodcache_destroy((MethodCache_t*)vm->method_cache); } rava_exception_stack_destroy(vm->exception_stack); free(vm->error_message); free(vm); } static RavaClass_t* _rava_vm_find_class(RavaVM_t *vm, const char *class_name) { for (size_t i = 0; i < vm->program->class_count; i++) { if (strcmp(vm->program->classes[i]->name, class_name) == 0) { return vm->program->classes[i]; } } return NULL; } static RavaMethod_t* _rava_vm_find_method(RavaVM_t *vm, const char *class_name, const char *method_name) { const char *current_class = class_name; while (current_class) { RavaClass_t *class = _rava_vm_find_class(vm, current_class); if (!class) break; for (size_t j = 0; j < class->method_count; j++) { if (strcmp(class->methods[j]->name, method_name) == 0) { return class->methods[j]; } } current_class = class->superclass; } return NULL; } static RavaMethod_t* _rava_vm_find_method_cached(RavaVM_t *vm, const char *class_name, const char *method_name) { MethodCache_t *cache = (MethodCache_t*)vm->method_cache; RavaMethod_t *cached = rava_methodcache_lookup(cache, class_name, method_name); if (cached) return cached; RavaMethod_t *method = _rava_vm_find_method(vm, class_name, method_name); if (method) { rava_methodcache_insert(cache, class_name, method_name, method); } return method; } #ifndef __GNUC__ static bool _rava_vm_execute_instruction(RavaVM_t *vm, RavaCallFrame_t *frame, RavaInstruction_t *instr) { RavaStack_t *stack = frame->operand_stack; switch (instr->opcode) { case RAVA_OP_NOP: break; case RAVA_OP_LOAD_CONST: rava_stack_push(stack, rava_value_int((int32_t)instr->operand.int_value)); break; case RAVA_OP_LOAD_LONG: rava_stack_push(stack, rava_value_long(instr->operand.int_value)); break; case RAVA_OP_LOAD_DOUBLE: rava_stack_push(stack, rava_value_double(instr->operand.float_value)); break; case RAVA_OP_LOAD_STRING: rava_stack_push(stack, rava_value_string(instr->operand.string_value)); break; case RAVA_OP_LOAD_LOCAL: if ((size_t)instr->operand.var.index < frame->local_count) { rava_stack_push(stack, frame->locals[instr->operand.var.index]); } break; case RAVA_OP_LOAD_THIS: if (frame->has_this) { rava_stack_push(stack, frame->this_ref); } else { rava_stack_push(stack, rava_value_null()); } break; case RAVA_OP_STORE_LOCAL: if ((size_t)instr->operand.var.index < frame->local_count) { frame->locals[instr->operand.var.index] = rava_stack_pop(stack); } break; case RAVA_OP_LOAD_STATIC: { RavaValue_t *field_val = rava_static_field_table_get( vm->static_fields, instr->operand.field.class_name, instr->operand.field.field_name ); if (field_val) { rava_stack_push(stack, *field_val); } else { rava_stack_push(stack, rava_value_int(0)); } break; } case RAVA_OP_STORE_STATIC: { RavaValue_t value = rava_stack_pop(stack); rava_static_field_table_set( vm->static_fields, instr->operand.field.class_name, instr->operand.field.field_name, value ); break; } case RAVA_OP_ADD: { RavaValue_t b = rava_stack_pop(stack); RavaValue_t a = rava_stack_pop(stack); if (a.type == RAVA_VAL_STRING || b.type == RAVA_VAL_STRING) { char buf_a[64], buf_b[64]; const char *str_a, *str_b; if (a.type == RAVA_VAL_STRING) { str_a = a.data.string_val ? a.data.string_val : "null"; } else if (a.type == RAVA_VAL_LONG) { snprintf(buf_a, sizeof(buf_a), "%ld", (long)rava_value_as_long(a)); str_a = buf_a; } else { snprintf(buf_a, sizeof(buf_a), "%d", rava_value_as_int(a)); str_a = buf_a; } if (b.type == RAVA_VAL_STRING) { str_b = b.data.string_val ? b.data.string_val : "null"; } else if (b.type == RAVA_VAL_LONG) { snprintf(buf_b, sizeof(buf_b), "%ld", (long)rava_value_as_long(b)); str_b = buf_b; } else { snprintf(buf_b, sizeof(buf_b), "%d", rava_value_as_int(b)); str_b = buf_b; } size_t len = strlen(str_a) + strlen(str_b) + 1; char *result = malloc(len); strcpy(result, str_a); strcat(result, str_b); rava_stack_push(stack, rava_value_string(result)); free(result); } else if (a.type == RAVA_VAL_LONG || b.type == RAVA_VAL_LONG) { rava_stack_push(stack, rava_value_long(rava_value_as_long(a) + rava_value_as_long(b))); } else { rava_stack_push(stack, rava_value_int(rava_value_as_int(a) + rava_value_as_int(b))); } break; } case RAVA_OP_SUB: { RavaValue_t b = rava_stack_pop(stack); RavaValue_t a = rava_stack_pop(stack); if (a.type == RAVA_VAL_LONG || b.type == RAVA_VAL_LONG) { rava_stack_push(stack, rava_value_long(rava_value_as_long(a) - rava_value_as_long(b))); } else { rava_stack_push(stack, rava_value_int(rava_value_as_int(a) - rava_value_as_int(b))); } break; } case RAVA_OP_MUL: { RavaValue_t b = rava_stack_pop(stack); RavaValue_t a = rava_stack_pop(stack); if (a.type == RAVA_VAL_LONG || b.type == RAVA_VAL_LONG) { rava_stack_push(stack, rava_value_long(rava_value_as_long(a) * rava_value_as_long(b))); } else { rava_stack_push(stack, rava_value_int(rava_value_as_int(a) * rava_value_as_int(b))); } break; } case RAVA_OP_DIV: { RavaValue_t b = rava_stack_pop(stack); RavaValue_t a = rava_stack_pop(stack); if (a.type == RAVA_VAL_LONG || b.type == RAVA_VAL_LONG) { int64_t divisor = rava_value_as_long(b); if (divisor == 0) { vm->had_error = true; vm->error_message = strdup("Division by zero"); return false; } rava_stack_push(stack, rava_value_long(rava_value_as_long(a) / divisor)); } else { int32_t divisor = rava_value_as_int(b); if (divisor == 0) { vm->had_error = true; vm->error_message = strdup("Division by zero"); return false; } rava_stack_push(stack, rava_value_int(rava_value_as_int(a) / divisor)); } break; } case RAVA_OP_MOD: { RavaValue_t b = rava_stack_pop(stack); RavaValue_t a = rava_stack_pop(stack); if (a.type == RAVA_VAL_LONG || b.type == RAVA_VAL_LONG) { rava_stack_push(stack, rava_value_long(rava_value_as_long(a) % rava_value_as_long(b))); } else { rava_stack_push(stack, rava_value_int(rava_value_as_int(a) % rava_value_as_int(b))); } break; } case RAVA_OP_NEG: { RavaValue_t a = rava_stack_pop(stack); rava_stack_push(stack, rava_value_int(-rava_value_as_int(a))); break; } case RAVA_OP_EQ: { RavaValue_t b = rava_stack_pop(stack); RavaValue_t a = rava_stack_pop(stack); rava_stack_push(stack, rava_value_boolean(rava_value_as_int(a) == rava_value_as_int(b))); break; } case RAVA_OP_NE: { RavaValue_t b = rava_stack_pop(stack); RavaValue_t a = rava_stack_pop(stack); rava_stack_push(stack, rava_value_boolean(rava_value_as_int(a) != rava_value_as_int(b))); break; } case RAVA_OP_LT: { RavaValue_t b = rava_stack_pop(stack); RavaValue_t a = rava_stack_pop(stack); rava_stack_push(stack, rava_value_boolean(rava_value_as_int(a) < rava_value_as_int(b))); break; } case RAVA_OP_LE: { RavaValue_t b = rava_stack_pop(stack); RavaValue_t a = rava_stack_pop(stack); rava_stack_push(stack, rava_value_boolean(rava_value_as_int(a) <= rava_value_as_int(b))); break; } case RAVA_OP_GT: { RavaValue_t b = rava_stack_pop(stack); RavaValue_t a = rava_stack_pop(stack); rava_stack_push(stack, rava_value_boolean(rava_value_as_int(a) > rava_value_as_int(b))); break; } case RAVA_OP_GE: { RavaValue_t b = rava_stack_pop(stack); RavaValue_t a = rava_stack_pop(stack); rava_stack_push(stack, rava_value_boolean(rava_value_as_int(a) >= rava_value_as_int(b))); break; } case RAVA_OP_AND: { RavaValue_t b = rava_stack_pop(stack); RavaValue_t a = rava_stack_pop(stack); rava_stack_push(stack, rava_value_int(rava_value_as_int(a) & rava_value_as_int(b))); break; } case RAVA_OP_OR: { RavaValue_t b = rava_stack_pop(stack); RavaValue_t a = rava_stack_pop(stack); rava_stack_push(stack, rava_value_int(rava_value_as_int(a) | rava_value_as_int(b))); break; } case RAVA_OP_NOT: { RavaValue_t a = rava_stack_pop(stack); rava_stack_push(stack, rava_value_boolean(!rava_value_as_boolean(a))); break; } case RAVA_OP_JUMP: { if (!frame->method->label_table) { frame->method->label_table = rava_labeltable_create(frame->method->instructions); } size_t target_pc = rava_labeltable_lookup((LabelTable_t*)frame->method->label_table, instr->operand.label_id); if (target_pc > 0) { frame->pc = target_pc - 1; return true; } break; } case RAVA_OP_JUMP_IF_TRUE: { RavaValue_t cond = rava_stack_pop(stack); if (rava_value_as_boolean(cond)) { if (!frame->method->label_table) { frame->method->label_table = rava_labeltable_create(frame->method->instructions); } size_t target_pc = rava_labeltable_lookup((LabelTable_t*)frame->method->label_table, instr->operand.label_id); if (target_pc > 0) { frame->pc = target_pc - 1; return true; } } break; } case RAVA_OP_JUMP_IF_FALSE: { RavaValue_t cond = rava_stack_pop(stack); if (!rava_value_as_boolean(cond)) { if (!frame->method->label_table) { frame->method->label_table = rava_labeltable_create(frame->method->instructions); } size_t target_pc = rava_labeltable_lookup((LabelTable_t*)frame->method->label_table, instr->operand.label_id); if (target_pc > 0) { frame->pc = target_pc - 1; return true; } } break; } case RAVA_OP_LABEL: break; case RAVA_OP_CALL_STATIC: { RavaMethod_t *method = _rava_vm_find_method_cached(vm, instr->operand.call.class_name, instr->operand.call.method_name); if (!method) { vm->had_error = true; vm->error_message = malloc(256); snprintf(vm->error_message, 256, "Method not found: %s.%s", instr->operand.call.class_name, instr->operand.call.method_name); return false; } RavaCallFrame_t *new_frame = rava_call_frame_create(method); for (int i = instr->operand.call.arg_count - 1; i >= 0; i--) { new_frame->locals[i] = rava_stack_pop(stack); } rava_call_stack_push(vm->call_stack, new_frame); while (new_frame->pc < new_frame->method->instructions->count) { RavaInstruction_t *next_instr = &new_frame->method->instructions->instructions[new_frame->pc]; if (next_instr->opcode == RAVA_OP_RETURN || next_instr->opcode == RAVA_OP_RETURN_VOID) { RavaValue_t result = rava_value_int(0); if (next_instr->opcode == RAVA_OP_RETURN && !rava_stack_is_empty(new_frame->operand_stack)) { result = rava_stack_pop(new_frame->operand_stack); } rava_call_stack_pop(vm->call_stack); rava_call_frame_destroy(new_frame); if (next_instr->opcode == RAVA_OP_RETURN) { rava_stack_push(stack, result); } break; } new_frame->pc++; if (!_rava_vm_execute_instruction(vm, new_frame, next_instr)) { return false; } } break; } case RAVA_OP_CALL_VIRTUAL: { RavaValue_t args[16]; for (int i = instr->operand.call.arg_count - 1; i >= 0; i--) { args[i] = rava_stack_pop(stack); } RavaValue_t obj_val = rava_stack_pop(stack); const char *class_name = instr->operand.call.class_name; if (obj_val.type == RAVA_VAL_OBJECT && obj_val.data.object_val) { class_name = obj_val.data.object_val->class_name; } RavaMethod_t *method = _rava_vm_find_method_cached(vm, class_name, instr->operand.call.method_name); if (!method) { if (strcmp(instr->operand.call.method_name, "") == 0 && instr->operand.call.arg_count == 0) { break; } vm->had_error = true; vm->error_message = malloc(256); snprintf(vm->error_message, 256, "Method not found: %s.%s", class_name, instr->operand.call.method_name); return false; } RavaCallFrame_t *new_frame = rava_call_frame_create(method); new_frame->has_this = true; new_frame->this_ref = obj_val; for (int i = 0; i < instr->operand.call.arg_count; i++) { new_frame->locals[i] = args[i]; } rava_call_stack_push(vm->call_stack, new_frame); while (new_frame->pc < new_frame->method->instructions->count) { RavaInstruction_t *next_instr = &new_frame->method->instructions->instructions[new_frame->pc]; if (next_instr->opcode == RAVA_OP_RETURN || next_instr->opcode == RAVA_OP_RETURN_VOID) { RavaValue_t result = rava_value_int(0); if (next_instr->opcode == RAVA_OP_RETURN && !rava_stack_is_empty(new_frame->operand_stack)) { result = rava_stack_pop(new_frame->operand_stack); } rava_call_stack_pop(vm->call_stack); rava_call_frame_destroy(new_frame); if (next_instr->opcode == RAVA_OP_RETURN) { rava_stack_push(stack, result); } break; } new_frame->pc++; if (!_rava_vm_execute_instruction(vm, new_frame, next_instr)) { return false; } } break; } case RAVA_OP_CALL_SUPER: { RavaValue_t args[16]; for (int i = instr->operand.call.arg_count - 1; i >= 0; i--) { args[i] = rava_stack_pop(stack); } RavaValue_t obj_val = rava_stack_pop(stack); const char *super_class = instr->operand.call.class_name; RavaMethod_t *method = _rava_vm_find_method_cached(vm, super_class, instr->operand.call.method_name); if (!method) { vm->had_error = true; vm->error_message = malloc(256); snprintf(vm->error_message, 256, "Super method not found: %s.%s", super_class, instr->operand.call.method_name); return false; } RavaCallFrame_t *new_frame = rava_call_frame_create(method); new_frame->has_this = true; new_frame->this_ref = obj_val; for (int i = 0; i < instr->operand.call.arg_count; i++) { new_frame->locals[i] = args[i]; } rava_call_stack_push(vm->call_stack, new_frame); while (new_frame->pc < new_frame->method->instructions->count) { RavaInstruction_t *next_instr = &new_frame->method->instructions->instructions[new_frame->pc]; if (next_instr->opcode == RAVA_OP_RETURN || next_instr->opcode == RAVA_OP_RETURN_VOID) { RavaValue_t result = rava_value_int(0); if (next_instr->opcode == RAVA_OP_RETURN && !rava_stack_is_empty(new_frame->operand_stack)) { result = rava_stack_pop(new_frame->operand_stack); } rava_call_stack_pop(vm->call_stack); rava_call_frame_destroy(new_frame); if (next_instr->opcode == RAVA_OP_RETURN) { rava_stack_push(stack, result); } break; } new_frame->pc++; if (!_rava_vm_execute_instruction(vm, new_frame, next_instr)) { return false; } } break; } case RAVA_OP_RETURN: case RAVA_OP_RETURN_VOID: return true; case RAVA_OP_THROW: { RavaValue_t exception = rava_stack_pop(stack); vm->has_exception = true; vm->exception_value = exception; RavaExceptionHandler_t handler; if (rava_exception_stack_pop(vm->exception_stack, &handler)) { locals[handler.exception_local] = exception; pc = label_table_lookup(method->label_table, handler.catch_label); vm->has_exception = false; } else { return false; } break; } case RAVA_OP_TRY_BEGIN: { RavaExceptionHandler_t handler; handler.catch_label = instr->operand.try_handler.catch_label; handler.finally_label = instr->operand.try_handler.finally_label; handler.end_label = instr->operand.try_handler.end_label; handler.exception_local = instr->operand.try_handler.exception_local; handler.stack_depth = stack->top; rava_exception_stack_push(vm->exception_stack, handler); break; } case RAVA_OP_TRY_END: { RavaExceptionHandler_t handler; rava_exception_stack_pop(vm->exception_stack, &handler); break; } case RAVA_OP_POP: rava_stack_pop(stack); break; case RAVA_OP_DUP: rava_stack_push(stack, rava_stack_peek(stack)); break; case RAVA_OP_PRINT: { RavaValue_t value = rava_stack_pop(stack); switch (value.type) { case RAVA_VAL_STRING: printf("%s", value.data.string_val ? value.data.string_val : "null"); break; case RAVA_VAL_BOOLEAN: printf("%s", value.data.bool_val ? "true" : "false"); break; case RAVA_VAL_DOUBLE: printf("%g", value.data.double_val); break; case RAVA_VAL_FLOAT: printf("%g", (double)value.data.float_val); break; case RAVA_VAL_LONG: printf("%ld", (long)value.data.long_val); break; case RAVA_VAL_NULL: printf("null"); break; case RAVA_VAL_ARRAY: printf("[array@%p]", (void*)value.data.array_val); break; default: printf("%d", rava_value_as_int(value)); break; } fflush(stdout); break; } case RAVA_OP_PRINTLN: { RavaValue_t value = rava_stack_pop(stack); switch (value.type) { case RAVA_VAL_STRING: printf("%s\n", value.data.string_val ? value.data.string_val : "null"); break; case RAVA_VAL_BOOLEAN: printf("%s\n", value.data.bool_val ? "true" : "false"); break; case RAVA_VAL_DOUBLE: printf("%g\n", value.data.double_val); break; case RAVA_VAL_FLOAT: printf("%g\n", (double)value.data.float_val); break; case RAVA_VAL_LONG: printf("%ld\n", (long)value.data.long_val); break; case RAVA_VAL_NULL: printf("null\n"); break; case RAVA_VAL_ARRAY: printf("[array@%p]\n", (void*)value.data.array_val); break; default: printf("%d\n", rava_value_as_int(value)); break; } fflush(stdout); break; } case RAVA_OP_NEW: { const char *class_name = instr->operand.call.class_name; RavaObject_t *obj = rava_object_create(class_name); if (obj) { rava_stack_push(stack, rava_value_object(obj)); } else { rava_stack_push(stack, rava_value_null()); } break; } case RAVA_OP_NEW_ARRAY: { RavaValue_t length_val = rava_stack_pop(stack); int32_t length = rava_value_as_int(length_val); if (length < 0) length = 0; RavaArray_t *array = rava_array_create(RAVA_VAL_INT, (size_t)length); if (array) { rava_stack_push(stack, rava_value_array(array)); } else { rava_stack_push(stack, rava_value_null()); } break; } case RAVA_OP_NEW_ARRAY_OF_ARRAYS: { RavaValue_t length_val = rava_stack_pop(stack); int32_t length = rava_value_as_int(length_val); if (length < 0) length = 0; RavaArray_t *array = rava_array_create(RAVA_VAL_ARRAY, (size_t)length); if (array) { rava_stack_push(stack, rava_value_array(array)); } else { rava_stack_push(stack, rava_value_null()); } break; } case RAVA_OP_GET_FIELD: { RavaValue_t obj_val = rava_stack_pop(stack); if (obj_val.type == RAVA_VAL_OBJECT && obj_val.data.object_val) { RavaValue_t field_val = rava_object_get_field(obj_val.data.object_val, instr->operand.field.field_name); rava_stack_push(stack, field_val); } else { rava_stack_push(stack, rava_value_null()); } break; } case RAVA_OP_PUT_FIELD: { RavaValue_t value = rava_stack_pop(stack); RavaValue_t obj_val = rava_stack_pop(stack); if (obj_val.type == RAVA_VAL_OBJECT && obj_val.data.object_val) { rava_object_set_field(obj_val.data.object_val, instr->operand.field.field_name, value); } break; } case RAVA_OP_ARRAY_LENGTH: { RavaValue_t array_val = rava_stack_pop(stack); if (array_val.type == RAVA_VAL_ARRAY) { size_t length = rava_array_length(array_val.data.array_val); rava_stack_push(stack, rava_value_int((int32_t)length)); } else { rava_stack_push(stack, rava_value_int(0)); } break; } case RAVA_OP_LOAD_ARRAY: { RavaValue_t index_val = rava_stack_pop(stack); RavaValue_t array_val = rava_stack_pop(stack); if (array_val.type == RAVA_VAL_ARRAY) { int32_t index = rava_value_as_int(index_val); RavaArray_t *arr = array_val.data.array_val; if (arr->element_type == RAVA_VAL_ARRAY || arr->element_type == RAVA_VAL_OBJECT) { rava_stack_push(stack, rava_array_get_value(arr, (size_t)index)); } else { int32_t value = rava_array_get_int(arr, (size_t)index); rava_stack_push(stack, rava_value_int(value)); } } else { rava_stack_push(stack, rava_value_int(0)); } break; } case RAVA_OP_STORE_ARRAY: { RavaValue_t value_val = rava_stack_pop(stack); RavaValue_t index_val = rava_stack_pop(stack); RavaValue_t array_val = rava_stack_pop(stack); if (array_val.type == RAVA_VAL_ARRAY) { int32_t index = rava_value_as_int(index_val); RavaArray_t *arr = array_val.data.array_val; if (arr->element_type == RAVA_VAL_ARRAY || arr->element_type == RAVA_VAL_OBJECT) { rava_array_set_value(arr, (size_t)index, value_val); } else { int32_t value = rava_value_as_int(value_val); rava_array_set_int(arr, (size_t)index, value); } } break; } case RAVA_OP_STRING_LENGTH: { RavaValue_t str_val = rava_stack_pop(stack); if (str_val.type == RAVA_VAL_STRING && str_val.data.string_val) { rava_stack_push(stack, rava_value_int((int32_t)strlen(str_val.data.string_val))); } else { rava_stack_push(stack, rava_value_int(0)); } break; } case RAVA_OP_STRING_CHARAT: { RavaValue_t index_val = rava_stack_pop(stack); RavaValue_t str_val = rava_stack_pop(stack); int32_t index = rava_value_as_int(index_val); if (str_val.type == RAVA_VAL_STRING && str_val.data.string_val) { size_t len = strlen(str_val.data.string_val); if (index >= 0 && (size_t)index < len) { RavaValue_t char_val; char_val.type = RAVA_VAL_CHAR; char_val.data.char_val = str_val.data.string_val[index]; rava_stack_push(stack, char_val); } else { rava_stack_push(stack, rava_value_int(0)); } } else { rava_stack_push(stack, rava_value_int(0)); } break; } case RAVA_OP_STRING_EQUALS: { RavaValue_t b = rava_stack_pop(stack); RavaValue_t a = rava_stack_pop(stack); bool result = false; if (a.type == RAVA_VAL_STRING && b.type == RAVA_VAL_STRING) { if (a.data.string_val && b.data.string_val) { result = strcmp(a.data.string_val, b.data.string_val) == 0; } else { result = (a.data.string_val == b.data.string_val); } } rava_stack_push(stack, rava_value_boolean(result)); break; } case RAVA_OP_STRING_SUBSTRING: { RavaValue_t end_val = rava_stack_pop(stack); RavaValue_t start_val = rava_stack_pop(stack); RavaValue_t str_val = rava_stack_pop(stack); if (str_val.type == RAVA_VAL_STRING && str_val.data.string_val) { size_t len = strlen(str_val.data.string_val); size_t start = (size_t)rava_value_as_int(start_val); size_t end = (size_t)rava_value_as_int(end_val); if (start > len) start = len; if (end > len) end = len; if (start > end) start = end; size_t sub_len = end - start; char *sub = malloc(sub_len + 1); strncpy(sub, str_val.data.string_val + start, sub_len); sub[sub_len] = '\0'; rava_stack_push(stack, rava_value_string(sub)); } else { rava_stack_push(stack, rava_value_string("")); } break; } case RAVA_OP_STRING_COMPARETO: { RavaValue_t b = rava_stack_pop(stack); RavaValue_t a = rava_stack_pop(stack); if (a.type == RAVA_VAL_STRING && b.type == RAVA_VAL_STRING && a.data.string_val && b.data.string_val) { rava_stack_push(stack, rava_value_int(strcmp(a.data.string_val, b.data.string_val))); } else { rava_stack_push(stack, rava_value_int(0)); } break; } case RAVA_OP_STRING_INDEXOF: { RavaValue_t needle_val = rava_stack_pop(stack); RavaValue_t str_val = rava_stack_pop(stack); if (str_val.type == RAVA_VAL_STRING && str_val.data.string_val && needle_val.type == RAVA_VAL_STRING && needle_val.data.string_val) { const char *found = strstr(str_val.data.string_val, needle_val.data.string_val); rava_stack_push(stack, rava_value_int(found ? (int32_t)(found - str_val.data.string_val) : -1)); } else { rava_stack_push(stack, rava_value_int(-1)); } break; } case RAVA_OP_STRING_CONTAINS: { RavaValue_t needle_val = rava_stack_pop(stack); RavaValue_t str_val = rava_stack_pop(stack); if (str_val.type == RAVA_VAL_STRING && str_val.data.string_val && needle_val.type == RAVA_VAL_STRING && needle_val.data.string_val) { rava_stack_push(stack, rava_value_boolean(strstr(str_val.data.string_val, needle_val.data.string_val) != NULL)); } else { rava_stack_push(stack, rava_value_boolean(false)); } break; } case RAVA_OP_STRING_STARTSWITH: { RavaValue_t prefix_val = rava_stack_pop(stack); RavaValue_t str_val = rava_stack_pop(stack); if (str_val.type == RAVA_VAL_STRING && str_val.data.string_val && prefix_val.type == RAVA_VAL_STRING && prefix_val.data.string_val) { size_t plen = strlen(prefix_val.data.string_val); rava_stack_push(stack, rava_value_boolean(strncmp(str_val.data.string_val, prefix_val.data.string_val, plen) == 0)); } else { rava_stack_push(stack, rava_value_boolean(false)); } break; } case RAVA_OP_STRING_ENDSWITH: { RavaValue_t suffix_val = rava_stack_pop(stack); RavaValue_t str_val = rava_stack_pop(stack); if (str_val.type == RAVA_VAL_STRING && str_val.data.string_val && suffix_val.type == RAVA_VAL_STRING && suffix_val.data.string_val) { size_t slen = strlen(str_val.data.string_val); size_t suflen = strlen(suffix_val.data.string_val); if (suflen <= slen) { rava_stack_push(stack, rava_value_boolean(strcmp(str_val.data.string_val + slen - suflen, suffix_val.data.string_val) == 0)); } else { rava_stack_push(stack, rava_value_boolean(false)); } } else { rava_stack_push(stack, rava_value_boolean(false)); } break; } case RAVA_OP_STRING_TOLOWERCASE: { RavaValue_t str_val = rava_stack_pop(stack); if (str_val.type == RAVA_VAL_STRING && str_val.data.string_val) { size_t len = strlen(str_val.data.string_val); char *lower = malloc(len + 1); for (size_t i = 0; i <= len; i++) { lower[i] = (char)tolower((unsigned char)str_val.data.string_val[i]); } rava_stack_push(stack, rava_value_string(lower)); } else { rava_stack_push(stack, rava_value_string("")); } break; } case RAVA_OP_STRING_TOUPPERCASE: { RavaValue_t str_val = rava_stack_pop(stack); if (str_val.type == RAVA_VAL_STRING && str_val.data.string_val) { size_t len = strlen(str_val.data.string_val); char *upper = malloc(len + 1); for (size_t i = 0; i <= len; i++) { upper[i] = (char)toupper((unsigned char)str_val.data.string_val[i]); } rava_stack_push(stack, rava_value_string(upper)); } else { rava_stack_push(stack, rava_value_string("")); } break; } case RAVA_OP_STRING_TRIM: { RavaValue_t str_val = rava_stack_pop(stack); if (str_val.type == RAVA_VAL_STRING && str_val.data.string_val) { const char *start = str_val.data.string_val; while (*start && isspace((unsigned char)*start)) start++; const char *end = str_val.data.string_val + strlen(str_val.data.string_val); while (end > start && isspace((unsigned char)*(end - 1))) end--; size_t len = (size_t)(end - start); char *trimmed = malloc(len + 1); strncpy(trimmed, start, len); trimmed[len] = '\0'; rava_stack_push(stack, rava_value_string(trimmed)); } else { rava_stack_push(stack, rava_value_string("")); } break; } case RAVA_OP_FILE_READ: { RavaValue_t path_val = rava_stack_pop(stack); if (path_val.type == RAVA_VAL_STRING && path_val.data.string_val) { FILE *file = fopen(path_val.data.string_val, "r"); if (file) { fseek(file, 0, SEEK_END); long size = ftell(file); fseek(file, 0, SEEK_SET); char *content = malloc(size + 1); if (content) { size_t read = fread(content, 1, size, file); content[read] = '\0'; rava_stack_push(stack, rava_value_string(content)); free(content); } else { rava_stack_push(stack, rava_value_null()); } fclose(file); } else { rava_stack_push(stack, rava_value_null()); } } else { rava_stack_push(stack, rava_value_null()); } break; } case RAVA_OP_FILE_WRITE: { RavaValue_t content_val = rava_stack_pop(stack); RavaValue_t path_val = rava_stack_pop(stack); if (path_val.type == RAVA_VAL_STRING && path_val.data.string_val && content_val.type == RAVA_VAL_STRING && content_val.data.string_val) { FILE *file = fopen(path_val.data.string_val, "w"); if (file) { fputs(content_val.data.string_val, file); fclose(file); rava_stack_push(stack, rava_value_boolean(true)); } else { rava_stack_push(stack, rava_value_boolean(false)); } } else { rava_stack_push(stack, rava_value_boolean(false)); } break; } case RAVA_OP_FILE_EXISTS: { RavaValue_t path_val = rava_stack_pop(stack); if (path_val.type == RAVA_VAL_STRING && path_val.data.string_val) { FILE *file = fopen(path_val.data.string_val, "r"); if (file) { fclose(file); rava_stack_push(stack, rava_value_boolean(true)); } else { rava_stack_push(stack, rava_value_boolean(false)); } } else { rava_stack_push(stack, rava_value_boolean(false)); } break; } case RAVA_OP_FILE_DELETE: { RavaValue_t path_val = rava_stack_pop(stack); if (path_val.type == RAVA_VAL_STRING && path_val.data.string_val) { int result = remove(path_val.data.string_val); rava_stack_push(stack, rava_value_boolean(result == 0)); } else { rava_stack_push(stack, rava_value_boolean(false)); } break; } case RAVA_OP_CURRENT_TIME_MILLIS: { struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); int64_t millis = (int64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000; rava_stack_push(stack, rava_value_long(millis)); break; } case RAVA_OP_NANO_TIME: { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); int64_t nanos = (int64_t)ts.tv_sec * 1000000000LL + ts.tv_nsec; rava_stack_push(stack, rava_value_long(nanos)); break; } case RAVA_OP_MATH_ABS: { RavaValue_t val = rava_stack_pop(stack); if (val.type == RAVA_VAL_DOUBLE) { rava_stack_push(stack, rava_value_double(fabs(val.data.double_val))); } else if (val.type == RAVA_VAL_LONG) { int64_t v = val.data.long_val; rava_stack_push(stack, rava_value_long(v < 0 ? -v : v)); } else { int32_t v = rava_value_as_int(val); rava_stack_push(stack, rava_value_int(v < 0 ? -v : v)); } break; } case RAVA_OP_MATH_SQRT: { RavaValue_t val = rava_stack_pop(stack); double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); rava_stack_push(stack, rava_value_double(sqrt(d))); break; } case RAVA_OP_MATH_POW: { RavaValue_t exp = rava_stack_pop(stack); RavaValue_t base = rava_stack_pop(stack); double b = (base.type == RAVA_VAL_DOUBLE) ? base.data.double_val : (double)rava_value_as_int(base); double e = (exp.type == RAVA_VAL_DOUBLE) ? exp.data.double_val : (double)rava_value_as_int(exp); rava_stack_push(stack, rava_value_double(pow(b, e))); break; } case RAVA_OP_MATH_MIN: { RavaValue_t b = rava_stack_pop(stack); RavaValue_t a = rava_stack_pop(stack); if (a.type == RAVA_VAL_DOUBLE || b.type == RAVA_VAL_DOUBLE) { double da = (a.type == RAVA_VAL_DOUBLE) ? a.data.double_val : (double)rava_value_as_int(a); double db = (b.type == RAVA_VAL_DOUBLE) ? b.data.double_val : (double)rava_value_as_int(b); rava_stack_push(stack, rava_value_double(da < db ? da : db)); } else { int32_t ia = rava_value_as_int(a); int32_t ib = rava_value_as_int(b); rava_stack_push(stack, rava_value_int(ia < ib ? ia : ib)); } break; } case RAVA_OP_MATH_MAX: { RavaValue_t b = rava_stack_pop(stack); RavaValue_t a = rava_stack_pop(stack); if (a.type == RAVA_VAL_DOUBLE || b.type == RAVA_VAL_DOUBLE) { double da = (a.type == RAVA_VAL_DOUBLE) ? a.data.double_val : (double)rava_value_as_int(a); double db = (b.type == RAVA_VAL_DOUBLE) ? b.data.double_val : (double)rava_value_as_int(b); rava_stack_push(stack, rava_value_double(da > db ? da : db)); } else { int32_t ia = rava_value_as_int(a); int32_t ib = rava_value_as_int(b); rava_stack_push(stack, rava_value_int(ia > ib ? ia : ib)); } break; } case RAVA_OP_MATH_FLOOR: { RavaValue_t val = rava_stack_pop(stack); double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); rava_stack_push(stack, rava_value_double(floor(d))); break; } case RAVA_OP_MATH_CEIL: { RavaValue_t val = rava_stack_pop(stack); double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); rava_stack_push(stack, rava_value_double(ceil(d))); break; } case RAVA_OP_MATH_ROUND: { RavaValue_t val = rava_stack_pop(stack); double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); rava_stack_push(stack, rava_value_long((int64_t)round(d))); break; } case RAVA_OP_MATH_SIN: { RavaValue_t val = rava_stack_pop(stack); double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); rava_stack_push(stack, rava_value_double(sin(d))); break; } case RAVA_OP_MATH_COS: { RavaValue_t val = rava_stack_pop(stack); double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); rava_stack_push(stack, rava_value_double(cos(d))); break; } case RAVA_OP_MATH_TAN: { RavaValue_t val = rava_stack_pop(stack); double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); rava_stack_push(stack, rava_value_double(tan(d))); break; } case RAVA_OP_MATH_LOG: { RavaValue_t val = rava_stack_pop(stack); double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); rava_stack_push(stack, rava_value_double(log(d))); break; } case RAVA_OP_MATH_EXP: { RavaValue_t val = rava_stack_pop(stack); double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); rava_stack_push(stack, rava_value_double(exp(d))); break; } case RAVA_OP_MATH_RANDOM: { rava_stack_push(stack, rava_value_double((double)rand() / (double)RAND_MAX)); break; } case RAVA_OP_CAST: { RavaValue_t val = rava_stack_pop(stack); RavaType_t *target_type = instr->operand.var.type; if (target_type) { switch (target_type->kind) { case RAVA_TYPE_INT: if (val.type == RAVA_VAL_DOUBLE) { rava_stack_push(stack, rava_value_int((int32_t)val.data.double_val)); } else if (val.type == RAVA_VAL_LONG) { rava_stack_push(stack, rava_value_int((int32_t)val.data.long_val)); } else { rava_stack_push(stack, val); } break; case RAVA_TYPE_LONG: if (val.type == RAVA_VAL_DOUBLE) { rava_stack_push(stack, rava_value_long((int64_t)val.data.double_val)); } else if (val.type == RAVA_VAL_INT) { rava_stack_push(stack, rava_value_long((int64_t)rava_value_as_int(val))); } else { rava_stack_push(stack, val); } break; case RAVA_TYPE_DOUBLE: case RAVA_TYPE_FLOAT: if (val.type == RAVA_VAL_INT) { rava_stack_push(stack, rava_value_double((double)rava_value_as_int(val))); } else if (val.type == RAVA_VAL_LONG) { rava_stack_push(stack, rava_value_double((double)val.data.long_val)); } else { rava_stack_push(stack, val); } break; default: rava_stack_push(stack, val); break; } } else { rava_stack_push(stack, val); } break; } default: break; } return true; } #endif #ifdef __GNUC__ __attribute__((unused)) static bool _rava_vm_execute_fast(RavaVM_t *vm, RavaCallFrame_t *frame) { static const void *dispatch_table[] = { &&op_nop, &&op_load_const, &&op_load_long, &&op_load_double, &&op_load_string, &&op_load_local, &&op_load_field, &&op_load_static, &&op_load_array, &&op_store_local, &&op_store_field, &&op_store_static, &&op_store_array, &&op_add, &&op_sub, &&op_mul, &&op_div, &&op_mod, &&op_neg, &&op_and, &&op_or, &&op_xor, &&op_not, &&op_bitnot, &&op_shl, &&op_shr, &&op_ushr, &&op_eq, &&op_ne, &&op_lt, &&op_le, &&op_gt, &&op_ge, &&op_jump, &&op_jump_if_true, &&op_jump_if_false, &&op_label, &&op_call, &&op_call_static, &&op_call_virtual, &&op_call_super, &&op_call_native, &&op_return, &&op_return_void, &&op_new, &&op_new_array, &&op_new_array_of_arrays, &&op_array_length, &&op_get_field, &&op_put_field, &&op_cast, &&op_instanceof, &&op_throw, &&op_try_begin, &&op_try_end, &&op_pop, &&op_dup, &&op_print, &&op_println, &&op_string_length, &&op_string_charat, &&op_string_substring, &&op_string_equals, &&op_string_compareto, &&op_string_indexof, &&op_string_contains, &&op_string_startswith, &&op_string_endswith, &&op_string_tolowercase, &&op_string_touppercase, &&op_string_trim, &&op_load_this, &&op_file_read, &&op_file_write, &&op_file_exists, &&op_file_delete, &&op_current_time_millis, &&op_nano_time, &&op_inc_local, &&op_dec_local, &&op_load_local_const_add, &&op_load_local_const_lt_jumpfalse, &&op_load_local_const_le_jumpfalse, &&op_load_two_locals, &&op_add_local_to_local, &&op_load_local_lt_local_jumpfalse, &&op_math_abs, &&op_math_sqrt, &&op_math_pow, &&op_math_min, &&op_math_max, &&op_math_floor, &&op_math_ceil, &&op_math_round, &&op_math_sin, &&op_math_cos, &&op_math_tan, &&op_math_log, &&op_math_exp, &&op_math_random }; RavaStack_t *stack = frame->operand_stack; RavaInstruction_t *instructions = frame->method->instructions->instructions; size_t instr_count = frame->method->instructions->count; register size_t pc = frame->pc; RavaInstruction_t *instr; if (!frame->method->label_table) { frame->method->label_table = rava_labeltable_create(frame->method->instructions); } LabelTable_t *label_table = (LabelTable_t*)frame->method->label_table; #define DISPATCH() do { \ if (pc >= instr_count) goto done; \ instr = &instructions[pc++]; \ if (instr->opcode >= sizeof(dispatch_table)/sizeof(dispatch_table[0])) { \ fprintf(stderr, "Invalid opcode: %d at pc=%zu\n", instr->opcode, pc-1); \ vm->had_error = true; \ goto done; \ } \ goto *dispatch_table[instr->opcode]; \ } while(0) #define DISPATCH_NEXT() do { \ instr = &instructions[pc++]; \ goto *dispatch_table[instr->opcode]; \ } while(0) DISPATCH(); op_nop: DISPATCH(); op_load_const: STACK_PUSH_INT(stack, (int32_t)instr->operand.int_value); DISPATCH(); op_load_long: STACK_PUSH_LONG(stack, instr->operand.int_value); DISPATCH(); op_load_double: { RavaValue_t v; v.type = RAVA_VAL_DOUBLE; v.data.double_val = instr->operand.float_value; STACK_PUSH(stack, v); DISPATCH(); } op_load_string: STACK_PUSH(stack, rava_value_string(instr->operand.string_value)); DISPATCH(); op_load_local: STACK_PUSH(stack, frame->locals[instr->operand.var.index]); DISPATCH(); op_load_field: { RavaValue_t obj_val = STACK_POP(stack); if (obj_val.type == RAVA_VAL_OBJECT && obj_val.data.object_val) { STACK_PUSH(stack, rava_object_get_field(obj_val.data.object_val, instr->operand.field.field_name)); } else { STACK_PUSH_INT(stack, 0); } DISPATCH(); } op_load_static: { RavaValue_t *field_val = rava_static_field_table_get(vm->static_fields, instr->operand.field.class_name, instr->operand.field.field_name); STACK_PUSH(stack, field_val ? *field_val : rava_value_int(0)); DISPATCH(); } op_load_array: { RavaValue_t idx = STACK_POP(stack); RavaValue_t arr = STACK_POP(stack); if (arr.type == RAVA_VAL_ARRAY && arr.data.array_val) { size_t index = (size_t)rava_value_as_int(idx); if (index < arr.data.array_val->length) { switch (arr.data.array_val->element_type) { case RAVA_VAL_INT: STACK_PUSH_INT(stack, ((int32_t*)arr.data.array_val->data)[index]); break; case RAVA_VAL_LONG: STACK_PUSH_LONG(stack, ((int64_t*)arr.data.array_val->data)[index]); break; case RAVA_VAL_ARRAY: case RAVA_VAL_OBJECT: STACK_PUSH(stack, ((RavaValue_t*)arr.data.array_val->data)[index]); break; default: STACK_PUSH_INT(stack, ((int32_t*)arr.data.array_val->data)[index]); break; } } else { STACK_PUSH_INT(stack, 0); } } else { STACK_PUSH_INT(stack, 0); } DISPATCH(); } op_store_local: frame->locals[instr->operand.var.index] = STACK_POP(stack); DISPATCH(); op_store_field: { RavaValue_t value = STACK_POP(stack); RavaValue_t obj_val = STACK_POP(stack); if (obj_val.type == RAVA_VAL_OBJECT && obj_val.data.object_val) { rava_object_set_field(obj_val.data.object_val, instr->operand.field.field_name, value); } DISPATCH(); } op_store_static: { RavaValue_t value = STACK_POP(stack); rava_static_field_table_set(vm->static_fields, instr->operand.field.class_name, instr->operand.field.field_name, value); DISPATCH(); } op_store_array: { RavaValue_t value = STACK_POP(stack); RavaValue_t idx = STACK_POP(stack); RavaValue_t arr = STACK_POP(stack); if (arr.type == RAVA_VAL_ARRAY && arr.data.array_val) { size_t index = (size_t)rava_value_as_int(idx); if (index < arr.data.array_val->length) { switch (arr.data.array_val->element_type) { case RAVA_VAL_INT: ((int32_t*)arr.data.array_val->data)[index] = rava_value_as_int(value); break; case RAVA_VAL_LONG: ((int64_t*)arr.data.array_val->data)[index] = rava_value_as_long(value); break; case RAVA_VAL_ARRAY: case RAVA_VAL_OBJECT: ((RavaValue_t*)arr.data.array_val->data)[index] = value; break; default: ((int32_t*)arr.data.array_val->data)[index] = rava_value_as_int(value); break; } } } DISPATCH(); } op_add: { RavaValue_t b = STACK_POP(stack); RavaValue_t a = STACK_POP(stack); if (VALUE_IS_INT(a) && VALUE_IS_INT(b)) { STACK_PUSH_INT(stack, VALUE_AS_INT_FAST(a) + VALUE_AS_INT_FAST(b)); } else if (a.type == RAVA_VAL_STRING || b.type == RAVA_VAL_STRING) { char buf_a[64], buf_b[64]; const char *str_a, *str_b; if (a.type == RAVA_VAL_STRING) str_a = a.data.string_val ? a.data.string_val : "null"; else if (VALUE_IS_LONG(a)) { snprintf(buf_a, 64, "%ld", (long)VALUE_AS_LONG_FAST(a)); str_a = buf_a; } else { snprintf(buf_a, 64, "%d", rava_value_as_int(a)); str_a = buf_a; } if (b.type == RAVA_VAL_STRING) str_b = b.data.string_val ? b.data.string_val : "null"; else if (VALUE_IS_LONG(b)) { snprintf(buf_b, 64, "%ld", (long)VALUE_AS_LONG_FAST(b)); str_b = buf_b; } else { snprintf(buf_b, 64, "%d", rava_value_as_int(b)); str_b = buf_b; } size_t len = strlen(str_a) + strlen(str_b) + 1; char *result = malloc(len); strcpy(result, str_a); strcat(result, str_b); STACK_PUSH(stack, rava_value_string(result)); free(result); } else if (VALUE_IS_LONG(a) || VALUE_IS_LONG(b)) { STACK_PUSH_LONG(stack, rava_value_as_long(a) + rava_value_as_long(b)); } else { STACK_PUSH_INT(stack, rava_value_as_int(a) + rava_value_as_int(b)); } DISPATCH(); } op_sub: { RavaValue_t b = STACK_POP(stack); RavaValue_t a = STACK_POP(stack); if (VALUE_IS_INT(a) && VALUE_IS_INT(b)) { STACK_PUSH_INT(stack, VALUE_AS_INT_FAST(a) - VALUE_AS_INT_FAST(b)); } else if (VALUE_IS_LONG(a) || VALUE_IS_LONG(b)) { STACK_PUSH_LONG(stack, rava_value_as_long(a) - rava_value_as_long(b)); } else { STACK_PUSH_INT(stack, rava_value_as_int(a) - rava_value_as_int(b)); } DISPATCH(); } op_mul: { RavaValue_t b = STACK_POP(stack); RavaValue_t a = STACK_POP(stack); if (VALUE_IS_INT(a) && VALUE_IS_INT(b)) { STACK_PUSH_INT(stack, VALUE_AS_INT_FAST(a) * VALUE_AS_INT_FAST(b)); } else if (VALUE_IS_LONG(a) || VALUE_IS_LONG(b)) { STACK_PUSH_LONG(stack, rava_value_as_long(a) * rava_value_as_long(b)); } else { STACK_PUSH_INT(stack, rava_value_as_int(a) * rava_value_as_int(b)); } DISPATCH(); } op_div: { RavaValue_t b = STACK_POP(stack); RavaValue_t a = STACK_POP(stack); if (VALUE_IS_INT(a) && VALUE_IS_INT(b)) { int32_t divisor = VALUE_AS_INT_FAST(b); if (divisor == 0) { vm->had_error = true; goto done; } STACK_PUSH_INT(stack, VALUE_AS_INT_FAST(a) / divisor); } else if (VALUE_IS_LONG(a) || VALUE_IS_LONG(b)) { int64_t divisor = rava_value_as_long(b); if (divisor == 0) { vm->had_error = true; goto done; } STACK_PUSH_LONG(stack, rava_value_as_long(a) / divisor); } else { int32_t divisor = rava_value_as_int(b); if (divisor == 0) { vm->had_error = true; goto done; } STACK_PUSH_INT(stack, rava_value_as_int(a) / divisor); } DISPATCH(); } op_mod: { RavaValue_t b = STACK_POP(stack); RavaValue_t a = STACK_POP(stack); if (VALUE_IS_INT(a) && VALUE_IS_INT(b)) { int32_t divisor = VALUE_AS_INT_FAST(b); if (divisor == 0) { vm->had_error = true; goto done; } STACK_PUSH_INT(stack, VALUE_AS_INT_FAST(a) % divisor); } else if (VALUE_IS_LONG(a) || VALUE_IS_LONG(b)) { int64_t divisor = rava_value_as_long(b); if (divisor == 0) { vm->had_error = true; goto done; } STACK_PUSH_LONG(stack, rava_value_as_long(a) % divisor); } else { int32_t divisor = rava_value_as_int(b); if (divisor == 0) { vm->had_error = true; goto done; } STACK_PUSH_INT(stack, rava_value_as_int(a) % divisor); } DISPATCH(); } op_neg: { RavaValue_t a = STACK_POP(stack); if (VALUE_IS_INT(a)) { STACK_PUSH_INT(stack, -VALUE_AS_INT_FAST(a)); } else if (VALUE_IS_LONG(a)) { STACK_PUSH_LONG(stack, -VALUE_AS_LONG_FAST(a)); } else { STACK_PUSH_INT(stack, -rava_value_as_int(a)); } DISPATCH(); } op_and: { RavaValue_t b = STACK_POP(stack); RavaValue_t a = STACK_POP(stack); STACK_PUSH_INT(stack, rava_value_as_int(a) & rava_value_as_int(b)); DISPATCH(); } op_or: { RavaValue_t b = STACK_POP(stack); RavaValue_t a = STACK_POP(stack); STACK_PUSH_INT(stack, rava_value_as_int(a) | rava_value_as_int(b)); DISPATCH(); } op_xor: { RavaValue_t b = STACK_POP(stack); RavaValue_t a = STACK_POP(stack); STACK_PUSH_INT(stack, rava_value_as_int(a) ^ rava_value_as_int(b)); DISPATCH(); } op_not: { RavaValue_t a = STACK_POP(stack); STACK_PUSH_BOOL(stack, !rava_value_as_boolean(a)); DISPATCH(); } op_bitnot: { RavaValue_t a = STACK_POP(stack); STACK_PUSH(stack, rava_value_int(~rava_value_as_int(a))); DISPATCH(); } op_shl: { RavaValue_t b = STACK_POP(stack); RavaValue_t a = STACK_POP(stack); STACK_PUSH_INT(stack, rava_value_as_int(a) << rava_value_as_int(b)); DISPATCH(); } op_shr: { RavaValue_t b = STACK_POP(stack); RavaValue_t a = STACK_POP(stack); STACK_PUSH_INT(stack, rava_value_as_int(a) >> rava_value_as_int(b)); DISPATCH(); } op_ushr: { RavaValue_t b = STACK_POP(stack); RavaValue_t a = STACK_POP(stack); STACK_PUSH_INT(stack, (uint32_t)rava_value_as_int(a) >> rava_value_as_int(b)); DISPATCH(); } op_eq: { RavaValue_t b = STACK_POP(stack); RavaValue_t a = STACK_POP(stack); if (VALUE_IS_INT(a) && VALUE_IS_INT(b)) { STACK_PUSH_BOOL(stack, VALUE_AS_INT_FAST(a) == VALUE_AS_INT_FAST(b)); } else if (VALUE_IS_LONG(a) || VALUE_IS_LONG(b)) { STACK_PUSH_BOOL(stack, rava_value_as_long(a) == rava_value_as_long(b)); } else { STACK_PUSH_BOOL(stack, rava_value_as_int(a) == rava_value_as_int(b)); } DISPATCH(); } op_ne: { RavaValue_t b = STACK_POP(stack); RavaValue_t a = STACK_POP(stack); if (VALUE_IS_INT(a) && VALUE_IS_INT(b)) { STACK_PUSH_BOOL(stack, VALUE_AS_INT_FAST(a) != VALUE_AS_INT_FAST(b)); } else if (VALUE_IS_LONG(a) || VALUE_IS_LONG(b)) { STACK_PUSH_BOOL(stack, rava_value_as_long(a) != rava_value_as_long(b)); } else { STACK_PUSH_BOOL(stack, rava_value_as_int(a) != rava_value_as_int(b)); } DISPATCH(); } op_lt: { RavaValue_t b = STACK_POP(stack); RavaValue_t a = STACK_POP(stack); if (VALUE_IS_INT(a) && VALUE_IS_INT(b)) { STACK_PUSH_BOOL(stack, VALUE_AS_INT_FAST(a) < VALUE_AS_INT_FAST(b)); } else if (VALUE_IS_LONG(a) || VALUE_IS_LONG(b)) { STACK_PUSH_BOOL(stack, rava_value_as_long(a) < rava_value_as_long(b)); } else { STACK_PUSH_BOOL(stack, rava_value_as_int(a) < rava_value_as_int(b)); } DISPATCH(); } op_le: { RavaValue_t b = STACK_POP(stack); RavaValue_t a = STACK_POP(stack); if (VALUE_IS_INT(a) && VALUE_IS_INT(b)) { STACK_PUSH_BOOL(stack, VALUE_AS_INT_FAST(a) <= VALUE_AS_INT_FAST(b)); } else if (VALUE_IS_LONG(a) || VALUE_IS_LONG(b)) { STACK_PUSH_BOOL(stack, rava_value_as_long(a) <= rava_value_as_long(b)); } else { STACK_PUSH_BOOL(stack, rava_value_as_int(a) <= rava_value_as_int(b)); } DISPATCH(); } op_gt: { RavaValue_t b = STACK_POP(stack); RavaValue_t a = STACK_POP(stack); if (VALUE_IS_INT(a) && VALUE_IS_INT(b)) { STACK_PUSH_BOOL(stack, VALUE_AS_INT_FAST(a) > VALUE_AS_INT_FAST(b)); } else if (VALUE_IS_LONG(a) || VALUE_IS_LONG(b)) { STACK_PUSH_BOOL(stack, rava_value_as_long(a) > rava_value_as_long(b)); } else { STACK_PUSH_BOOL(stack, rava_value_as_int(a) > rava_value_as_int(b)); } DISPATCH(); } op_ge: { RavaValue_t b = STACK_POP(stack); RavaValue_t a = STACK_POP(stack); if (VALUE_IS_INT(a) && VALUE_IS_INT(b)) { STACK_PUSH_BOOL(stack, VALUE_AS_INT_FAST(a) >= VALUE_AS_INT_FAST(b)); } else if (VALUE_IS_LONG(a) || VALUE_IS_LONG(b)) { STACK_PUSH_BOOL(stack, rava_value_as_long(a) >= rava_value_as_long(b)); } else { STACK_PUSH_BOOL(stack, rava_value_as_int(a) >= rava_value_as_int(b)); } DISPATCH(); } op_jump: { pc = rava_labeltable_lookup(label_table, instr->operand.label_id); DISPATCH(); } op_jump_if_true: { RavaValue_t cond = STACK_POP(stack); if (rava_value_as_boolean(cond)) { pc = rava_labeltable_lookup(label_table, instr->operand.label_id); } DISPATCH(); } op_jump_if_false: { RavaValue_t cond = STACK_POP(stack); if (!rava_value_as_boolean(cond)) { pc = rava_labeltable_lookup(label_table, instr->operand.label_id); } DISPATCH(); } op_label: DISPATCH(); op_call: op_call_static: { frame->pc = pc; RavaMethod_t *target_method = _rava_vm_find_method_cached(vm, instr->operand.call.class_name, instr->operand.call.method_name); if (!target_method) { vm->had_error = true; vm->error_message = malloc(256); snprintf(vm->error_message, 256, "Method not found: %s.%s", instr->operand.call.class_name, instr->operand.call.method_name); goto done; } RavaCallFrame_t *new_frame = rava_call_frame_create(target_method); for (int i = instr->operand.call.arg_count - 1; i >= 0; i--) { new_frame->locals[i] = STACK_POP(stack); } rava_call_stack_push(vm->call_stack, new_frame); if (!_rava_vm_execute_fast(vm, new_frame)) { goto done; } if (!rava_stack_is_empty(new_frame->operand_stack)) { STACK_PUSH(stack, rava_stack_pop(new_frame->operand_stack)); } rava_call_stack_pop(vm->call_stack); rava_call_frame_destroy(new_frame); DISPATCH(); } op_call_virtual: { frame->pc = pc; RavaValue_t this_val = stack->values[stack->top - instr->operand.call.arg_count - 1]; const char *target_class = instr->operand.call.class_name; if (this_val.type == RAVA_VAL_OBJECT && this_val.data.object_val) { target_class = this_val.data.object_val->class_name; } RavaMethod_t *target_method = _rava_vm_find_method_cached(vm, target_class, instr->operand.call.method_name); if (!target_method) { if (strcmp(instr->operand.call.method_name, "") == 0 && instr->operand.call.arg_count == 0) { STACK_POP(stack); DISPATCH(); } vm->had_error = true; vm->error_message = malloc(256); snprintf(vm->error_message, 256, "Method not found: %s.%s", target_class, instr->operand.call.method_name); goto done; } RavaCallFrame_t *new_frame = rava_call_frame_create(target_method); new_frame->has_this = true; RavaValue_t args[16]; for (int i = instr->operand.call.arg_count - 1; i >= 0; i--) { args[i] = STACK_POP(stack); } new_frame->this_ref = STACK_POP(stack); for (int i = 0; i < instr->operand.call.arg_count; i++) { new_frame->locals[i] = args[i]; } rava_call_stack_push(vm->call_stack, new_frame); if (!_rava_vm_execute_fast(vm, new_frame)) { goto done; } if (!rava_stack_is_empty(new_frame->operand_stack)) { STACK_PUSH(stack, rava_stack_pop(new_frame->operand_stack)); } rava_call_stack_pop(vm->call_stack); rava_call_frame_destroy(new_frame); DISPATCH(); } op_call_super: { frame->pc = pc; const char *super_class = instr->operand.call.class_name; RavaMethod_t *target_method = _rava_vm_find_method_cached(vm, super_class, instr->operand.call.method_name); if (!target_method) { vm->had_error = true; vm->error_message = malloc(256); snprintf(vm->error_message, 256, "Super method not found: %s.%s", super_class, instr->operand.call.method_name); goto done; } RavaCallFrame_t *new_frame = rava_call_frame_create(target_method); new_frame->has_this = true; RavaValue_t args[16]; for (int i = instr->operand.call.arg_count - 1; i >= 0; i--) { args[i] = STACK_POP(stack); } new_frame->this_ref = STACK_POP(stack); for (int i = 0; i < instr->operand.call.arg_count; i++) { new_frame->locals[i] = args[i]; } rava_call_stack_push(vm->call_stack, new_frame); if (!_rava_vm_execute_fast(vm, new_frame)) { goto done; } if (!rava_stack_is_empty(new_frame->operand_stack)) { STACK_PUSH(stack, rava_stack_pop(new_frame->operand_stack)); } rava_call_stack_pop(vm->call_stack); rava_call_frame_destroy(new_frame); DISPATCH(); } op_call_native: DISPATCH(); op_return: goto done; op_return_void: goto done; op_new: { RavaObject_t *obj = rava_object_create(instr->operand.call.class_name); STACK_PUSH(stack, rava_value_object(obj)); DISPATCH(); } op_new_array: { RavaValue_t size_val = STACK_POP(stack); size_t size = (size_t)rava_value_as_int(size_val); RavaArray_t *array = rava_array_create(RAVA_VAL_INT, size); STACK_PUSH(stack, rava_value_array(array)); DISPATCH(); } op_new_array_of_arrays: { RavaValue_t size_val = STACK_POP(stack); size_t size = (size_t)rava_value_as_int(size_val); RavaArray_t *array = rava_array_create(RAVA_VAL_ARRAY, size); STACK_PUSH(stack, rava_value_array(array)); DISPATCH(); } op_array_length: { RavaValue_t arr = STACK_POP(stack); if (arr.type == RAVA_VAL_ARRAY && arr.data.array_val) { STACK_PUSH_INT(stack, (int32_t)arr.data.array_val->length); } else { STACK_PUSH_INT(stack, 0); } DISPATCH(); } op_get_field: { RavaValue_t obj_val = STACK_POP(stack); if (obj_val.type == RAVA_VAL_OBJECT && obj_val.data.object_val) { STACK_PUSH(stack, rava_object_get_field(obj_val.data.object_val, instr->operand.field.field_name)); } else { STACK_PUSH_INT(stack, 0); } DISPATCH(); } op_put_field: { RavaValue_t value = STACK_POP(stack); RavaValue_t obj_val = STACK_POP(stack); if (obj_val.type == RAVA_VAL_OBJECT && obj_val.data.object_val) { rava_object_set_field(obj_val.data.object_val, instr->operand.field.field_name, value); } DISPATCH(); } op_cast: { RavaValue_t val = STACK_POP(stack); RavaType_t *target_type = instr->operand.var.type; if (target_type) { switch (target_type->kind) { case RAVA_TYPE_INT: if (val.type == RAVA_VAL_DOUBLE) { STACK_PUSH_INT(stack, (int32_t)val.data.double_val); } else if (val.type == RAVA_VAL_LONG) { STACK_PUSH_INT(stack, (int32_t)val.data.long_val); } else { STACK_PUSH(stack, val); } break; case RAVA_TYPE_LONG: if (val.type == RAVA_VAL_DOUBLE) { STACK_PUSH_LONG(stack, (int64_t)val.data.double_val); } else if (val.type == RAVA_VAL_INT) { STACK_PUSH_LONG(stack, (int64_t)rava_value_as_int(val)); } else { STACK_PUSH(stack, val); } break; case RAVA_TYPE_DOUBLE: { RavaValue_t r; r.type = RAVA_VAL_DOUBLE; if (val.type == RAVA_VAL_INT) { r.data.double_val = (double)rava_value_as_int(val); } else if (val.type == RAVA_VAL_LONG) { r.data.double_val = (double)val.data.long_val; } else { r.data.double_val = val.data.double_val; } STACK_PUSH(stack, r); break; } case RAVA_TYPE_FLOAT: { RavaValue_t r; r.type = RAVA_VAL_DOUBLE; if (val.type == RAVA_VAL_INT) { r.data.double_val = (double)rava_value_as_int(val); } else if (val.type == RAVA_VAL_LONG) { r.data.double_val = (double)val.data.long_val; } else { r.data.double_val = val.data.double_val; } STACK_PUSH(stack, r); break; } default: STACK_PUSH(stack, val); break; } } else { STACK_PUSH(stack, val); } DISPATCH(); } op_instanceof: { RavaValue_t val = STACK_POP(stack); bool result = false; if (val.type == RAVA_VAL_OBJECT && val.data.object_val) { result = strcmp(val.data.object_val->class_name, instr->operand.string_value) == 0; } STACK_PUSH(stack, rava_value_boolean(result)); DISPATCH(); } op_throw: { RavaValue_t exception = STACK_POP(stack); vm->has_exception = true; vm->exception_value = exception; RavaExceptionHandler_t handler; if (rava_exception_stack_pop(vm->exception_stack, &handler)) { frame->locals[handler.exception_local] = exception; pc = rava_labeltable_lookup(label_table, handler.catch_label); vm->has_exception = false; DISPATCH(); } else { vm->had_error = true; goto done; } } op_try_begin: { RavaExceptionHandler_t handler; handler.catch_label = instr->operand.try_handler.catch_label; handler.finally_label = instr->operand.try_handler.finally_label; handler.end_label = instr->operand.try_handler.end_label; handler.exception_local = instr->operand.try_handler.exception_local; handler.stack_depth = stack->top; rava_exception_stack_push(vm->exception_stack, handler); DISPATCH(); } op_try_end: { RavaExceptionHandler_t handler; rava_exception_stack_pop(vm->exception_stack, &handler); DISPATCH(); } op_pop: (void)STACK_POP(stack); DISPATCH(); op_dup: { RavaValue_t top = STACK_PEEK(stack); STACK_PUSH(stack, top); DISPATCH(); } op_print: { RavaValue_t value = STACK_POP(stack); switch (value.type) { case RAVA_VAL_STRING: printf("%s", value.data.string_val ? value.data.string_val : "null"); break; case RAVA_VAL_BOOLEAN: printf("%s", value.data.bool_val ? "true" : "false"); break; case RAVA_VAL_DOUBLE: printf("%g", value.data.double_val); break; case RAVA_VAL_LONG: printf("%ld", (long)value.data.long_val); break; case RAVA_VAL_NULL: printf("null"); break; default: printf("%d", rava_value_as_int(value)); break; } fflush(stdout); DISPATCH(); } op_println: { RavaValue_t value = STACK_POP(stack); switch (value.type) { case RAVA_VAL_STRING: printf("%s\n", value.data.string_val ? value.data.string_val : "null"); break; case RAVA_VAL_BOOLEAN: printf("%s\n", value.data.bool_val ? "true" : "false"); break; case RAVA_VAL_DOUBLE: printf("%g\n", value.data.double_val); break; case RAVA_VAL_LONG: printf("%ld\n", (long)value.data.long_val); break; case RAVA_VAL_NULL: printf("null\n"); break; default: printf("%d\n", rava_value_as_int(value)); break; } DISPATCH(); } op_string_length: { RavaValue_t str = STACK_POP(stack); if (str.type == RAVA_VAL_STRING && str.data.string_val) { STACK_PUSH_INT(stack, (int32_t)strlen(str.data.string_val)); } else { STACK_PUSH_INT(stack, 0); } DISPATCH(); } op_string_charat: { RavaValue_t idx = STACK_POP(stack); RavaValue_t str = STACK_POP(stack); if (str.type == RAVA_VAL_STRING && str.data.string_val) { size_t index = (size_t)rava_value_as_int(idx); if (index < strlen(str.data.string_val)) { RavaValue_t v; v.type = RAVA_VAL_CHAR; v.data.char_val = str.data.string_val[index]; STACK_PUSH(stack, v); } else { RavaValue_t v; v.type = RAVA_VAL_CHAR; v.data.char_val = 0; STACK_PUSH(stack, v); } } else { RavaValue_t v; v.type = RAVA_VAL_CHAR; v.data.char_val = 0; STACK_PUSH(stack, v); } DISPATCH(); } op_string_substring: { RavaValue_t end_val = STACK_POP(stack); RavaValue_t start_val = STACK_POP(stack); RavaValue_t str = STACK_POP(stack); if (str.type == RAVA_VAL_STRING && str.data.string_val) { size_t len = strlen(str.data.string_val); size_t start = (size_t)rava_value_as_int(start_val); size_t end = (size_t)rava_value_as_int(end_val); if (start > len) start = len; if (end > len) end = len; if (start > end) start = end; size_t sub_len = end - start; char *sub = malloc(sub_len + 1); strncpy(sub, str.data.string_val + start, sub_len); sub[sub_len] = '\0'; STACK_PUSH(stack, rava_value_string(sub)); free(sub); } else { STACK_PUSH(stack, rava_value_string("")); } DISPATCH(); } op_string_equals: { RavaValue_t b = STACK_POP(stack); RavaValue_t a = STACK_POP(stack); if (a.type == RAVA_VAL_STRING && b.type == RAVA_VAL_STRING) { if (a.data.string_val && b.data.string_val) { STACK_PUSH_BOOL(stack, strcmp(a.data.string_val, b.data.string_val) == 0); } else { STACK_PUSH_BOOL(stack, a.data.string_val == b.data.string_val); } } else { STACK_PUSH_BOOL(stack, false); } DISPATCH(); } op_string_compareto: { RavaValue_t b = STACK_POP(stack); RavaValue_t a = STACK_POP(stack); if (a.type == RAVA_VAL_STRING && b.type == RAVA_VAL_STRING && a.data.string_val && b.data.string_val) { STACK_PUSH_INT(stack, strcmp(a.data.string_val, b.data.string_val)); } else { STACK_PUSH_INT(stack, 0); } DISPATCH(); } op_string_indexof: { RavaValue_t needle = STACK_POP(stack); RavaValue_t str = STACK_POP(stack); if (str.type == RAVA_VAL_STRING && str.data.string_val && needle.type == RAVA_VAL_STRING && needle.data.string_val) { const char *found = strstr(str.data.string_val, needle.data.string_val); STACK_PUSH_INT(stack, found ? (int32_t)(found - str.data.string_val) : -1); } else { STACK_PUSH_INT(stack, -1); } DISPATCH(); } op_string_contains: { RavaValue_t needle = STACK_POP(stack); RavaValue_t str = STACK_POP(stack); if (str.type == RAVA_VAL_STRING && str.data.string_val && needle.type == RAVA_VAL_STRING && needle.data.string_val) { STACK_PUSH_BOOL(stack, strstr(str.data.string_val, needle.data.string_val) != NULL); } else { STACK_PUSH_BOOL(stack, false); } DISPATCH(); } op_string_startswith: { RavaValue_t prefix = STACK_POP(stack); RavaValue_t str = STACK_POP(stack); if (str.type == RAVA_VAL_STRING && str.data.string_val && prefix.type == RAVA_VAL_STRING && prefix.data.string_val) { size_t plen = strlen(prefix.data.string_val); STACK_PUSH_BOOL(stack, strncmp(str.data.string_val, prefix.data.string_val, plen) == 0); } else { STACK_PUSH_BOOL(stack, false); } DISPATCH(); } op_string_endswith: { RavaValue_t suffix = STACK_POP(stack); RavaValue_t str = STACK_POP(stack); if (str.type == RAVA_VAL_STRING && str.data.string_val && suffix.type == RAVA_VAL_STRING && suffix.data.string_val) { size_t slen = strlen(str.data.string_val); size_t suflen = strlen(suffix.data.string_val); if (suflen <= slen) { STACK_PUSH_BOOL(stack, strcmp(str.data.string_val + slen - suflen, suffix.data.string_val) == 0); } else { STACK_PUSH_BOOL(stack, false); } } else { STACK_PUSH_BOOL(stack, false); } DISPATCH(); } op_string_tolowercase: { RavaValue_t str = STACK_POP(stack); if (str.type == RAVA_VAL_STRING && str.data.string_val) { size_t len = strlen(str.data.string_val); char *lower = malloc(len + 1); for (size_t i = 0; i <= len; i++) { lower[i] = (char)tolower((unsigned char)str.data.string_val[i]); } STACK_PUSH(stack, rava_value_string(lower)); } else { STACK_PUSH(stack, rava_value_string("")); } DISPATCH(); } op_string_touppercase: { RavaValue_t str = STACK_POP(stack); if (str.type == RAVA_VAL_STRING && str.data.string_val) { size_t len = strlen(str.data.string_val); char *upper = malloc(len + 1); for (size_t i = 0; i <= len; i++) { upper[i] = (char)toupper((unsigned char)str.data.string_val[i]); } STACK_PUSH(stack, rava_value_string(upper)); } else { STACK_PUSH(stack, rava_value_string("")); } DISPATCH(); } op_string_trim: { RavaValue_t str = STACK_POP(stack); if (str.type == RAVA_VAL_STRING && str.data.string_val) { const char *start = str.data.string_val; while (*start && isspace((unsigned char)*start)) start++; const char *end = str.data.string_val + strlen(str.data.string_val); while (end > start && isspace((unsigned char)*(end - 1))) end--; size_t len = (size_t)(end - start); char *trimmed = malloc(len + 1); strncpy(trimmed, start, len); trimmed[len] = '\0'; STACK_PUSH(stack, rava_value_string(trimmed)); } else { STACK_PUSH(stack, rava_value_string("")); } DISPATCH(); } op_load_this: if (frame->has_this) { STACK_PUSH(stack, frame->this_ref); } else { STACK_PUSH(stack, rava_value_null()); } DISPATCH(); op_file_read: { RavaValue_t path_val = STACK_POP(stack); if (path_val.type == RAVA_VAL_STRING && path_val.data.string_val) { FILE *file = fopen(path_val.data.string_val, "r"); if (file) { fseek(file, 0, SEEK_END); long size = ftell(file); fseek(file, 0, SEEK_SET); char *content = malloc(size + 1); if (content) { size_t rd = fread(content, 1, size, file); content[rd] = '\0'; STACK_PUSH(stack, rava_value_string(content)); free(content); } else { STACK_PUSH(stack, rava_value_null()); } fclose(file); } else { STACK_PUSH(stack, rava_value_null()); } } else { STACK_PUSH(stack, rava_value_null()); } DISPATCH(); } op_file_write: { RavaValue_t content_val = STACK_POP(stack); RavaValue_t path_val = STACK_POP(stack); if (path_val.type == RAVA_VAL_STRING && path_val.data.string_val && content_val.type == RAVA_VAL_STRING && content_val.data.string_val) { FILE *file = fopen(path_val.data.string_val, "w"); if (file) { fputs(content_val.data.string_val, file); fclose(file); STACK_PUSH_BOOL(stack, true); } else { STACK_PUSH_BOOL(stack, false); } } else { STACK_PUSH_BOOL(stack, false); } DISPATCH(); } op_file_exists: { RavaValue_t path_val = STACK_POP(stack); if (path_val.type == RAVA_VAL_STRING && path_val.data.string_val) { FILE *file = fopen(path_val.data.string_val, "r"); if (file) { fclose(file); STACK_PUSH_BOOL(stack, true); } else { STACK_PUSH_BOOL(stack, false); } } else { STACK_PUSH_BOOL(stack, false); } DISPATCH(); } op_file_delete: { RavaValue_t path_val = STACK_POP(stack); if (path_val.type == RAVA_VAL_STRING && path_val.data.string_val) { int result = remove(path_val.data.string_val); STACK_PUSH_BOOL(stack, result == 0); } else { STACK_PUSH_BOOL(stack, false); } DISPATCH(); } op_current_time_millis: { struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); int64_t millis = (int64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000; STACK_PUSH_LONG(stack, millis); DISPATCH(); } op_nano_time: { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); int64_t nanos = (int64_t)ts.tv_sec * 1000000000LL + ts.tv_nsec; STACK_PUSH_LONG(stack, nanos); DISPATCH(); } op_inc_local: { size_t idx = (size_t)instr->operand.var.index; if (VALUE_IS_INT(frame->locals[idx])) { frame->locals[idx].data.int_val++; } else { frame->locals[idx].data.long_val++; } DISPATCH(); } op_dec_local: { size_t idx = (size_t)instr->operand.var.index; if (VALUE_IS_INT(frame->locals[idx])) { frame->locals[idx].data.int_val--; } else { frame->locals[idx].data.long_val--; } DISPATCH(); } op_load_local_const_add: { size_t idx = (size_t)instr->operand.super.local_index; int64_t c = instr->operand.super.const_value; RavaValue_t v = frame->locals[idx]; if (VALUE_IS_INT(v)) { STACK_PUSH_INT(stack, VALUE_AS_INT_FAST(v) + (int32_t)c); } else { STACK_PUSH_LONG(stack, rava_value_as_long(v) + c); } DISPATCH(); } op_load_local_const_lt_jumpfalse: { size_t idx = (size_t)instr->operand.super.local_index; int64_t c = instr->operand.super.const_value; int label = instr->operand.super.label_id; int64_t local_val = rava_value_as_long(frame->locals[idx]); if (!(local_val < c)) { pc = rava_labeltable_lookup(label_table, label); } DISPATCH(); } op_load_local_const_le_jumpfalse: { size_t idx = (size_t)instr->operand.super.local_index; int64_t c = instr->operand.super.const_value; int label = instr->operand.super.label_id; int64_t local_val = rava_value_as_long(frame->locals[idx]); if (!(local_val <= c)) { pc = rava_labeltable_lookup(label_table, label); } DISPATCH(); } op_load_two_locals: { size_t idx1 = (size_t)instr->operand.two_locals.index1; size_t idx2 = (size_t)instr->operand.two_locals.index2; STACK_PUSH(stack, frame->locals[idx1]); STACK_PUSH(stack, frame->locals[idx2]); DISPATCH(); } op_add_local_to_local: { size_t dest = (size_t)instr->operand.add_locals.dest_index; size_t src = (size_t)instr->operand.add_locals.src_index; if (VALUE_IS_INT(frame->locals[dest]) && VALUE_IS_INT(frame->locals[src])) { frame->locals[dest].data.int_val += frame->locals[src].data.int_val; } else { frame->locals[dest].data.long_val = rava_value_as_long(frame->locals[dest]) + rava_value_as_long(frame->locals[src]); frame->locals[dest].type = RAVA_VAL_LONG; } DISPATCH(); } op_load_local_lt_local_jumpfalse: { size_t local1 = (size_t)instr->operand.cmp_locals.local1; size_t local2 = (size_t)instr->operand.cmp_locals.local2; int label = instr->operand.cmp_locals.label_id; int64_t v1 = rava_value_as_long(frame->locals[local1]); int64_t v2 = rava_value_as_long(frame->locals[local2]); if (!(v1 < v2)) { pc = rava_labeltable_lookup(label_table, label); } DISPATCH(); } op_math_abs: { RavaValue_t val = STACK_POP(stack); if (val.type == RAVA_VAL_DOUBLE) { RavaValue_t r; r.type = RAVA_VAL_DOUBLE; r.data.double_val = fabs(val.data.double_val); STACK_PUSH(stack, r); } else if (val.type == RAVA_VAL_LONG) { int64_t v = val.data.long_val; STACK_PUSH_LONG(stack, v < 0 ? -v : v); } else { int32_t v = rava_value_as_int(val); STACK_PUSH_INT(stack, v < 0 ? -v : v); } DISPATCH(); } op_math_sqrt: { RavaValue_t val = STACK_POP(stack); double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); RavaValue_t r; r.type = RAVA_VAL_DOUBLE; r.data.double_val = sqrt(d); STACK_PUSH(stack, r); DISPATCH(); } op_math_pow: { RavaValue_t exp = STACK_POP(stack); RavaValue_t base = STACK_POP(stack); double b = (base.type == RAVA_VAL_DOUBLE) ? base.data.double_val : (double)rava_value_as_int(base); double e = (exp.type == RAVA_VAL_DOUBLE) ? exp.data.double_val : (double)rava_value_as_int(exp); RavaValue_t r; r.type = RAVA_VAL_DOUBLE; r.data.double_val = pow(b, e); STACK_PUSH(stack, r); DISPATCH(); } op_math_min: { RavaValue_t b = STACK_POP(stack); RavaValue_t a = STACK_POP(stack); if (a.type == RAVA_VAL_DOUBLE || b.type == RAVA_VAL_DOUBLE) { double da = (a.type == RAVA_VAL_DOUBLE) ? a.data.double_val : (double)rava_value_as_int(a); double db = (b.type == RAVA_VAL_DOUBLE) ? b.data.double_val : (double)rava_value_as_int(b); RavaValue_t r; r.type = RAVA_VAL_DOUBLE; r.data.double_val = da < db ? da : db; STACK_PUSH(stack, r); } else { int32_t ia = rava_value_as_int(a); int32_t ib = rava_value_as_int(b); STACK_PUSH_INT(stack, ia < ib ? ia : ib); } DISPATCH(); } op_math_max: { RavaValue_t b = STACK_POP(stack); RavaValue_t a = STACK_POP(stack); if (a.type == RAVA_VAL_DOUBLE || b.type == RAVA_VAL_DOUBLE) { double da = (a.type == RAVA_VAL_DOUBLE) ? a.data.double_val : (double)rava_value_as_int(a); double db = (b.type == RAVA_VAL_DOUBLE) ? b.data.double_val : (double)rava_value_as_int(b); RavaValue_t r; r.type = RAVA_VAL_DOUBLE; r.data.double_val = da > db ? da : db; STACK_PUSH(stack, r); } else { int32_t ia = rava_value_as_int(a); int32_t ib = rava_value_as_int(b); STACK_PUSH_INT(stack, ia > ib ? ia : ib); } DISPATCH(); } op_math_floor: { RavaValue_t val = STACK_POP(stack); double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); RavaValue_t r; r.type = RAVA_VAL_DOUBLE; r.data.double_val = floor(d); STACK_PUSH(stack, r); DISPATCH(); } op_math_ceil: { RavaValue_t val = STACK_POP(stack); double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); RavaValue_t r; r.type = RAVA_VAL_DOUBLE; r.data.double_val = ceil(d); STACK_PUSH(stack, r); DISPATCH(); } op_math_round: { RavaValue_t val = STACK_POP(stack); double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); STACK_PUSH_LONG(stack, (int64_t)round(d)); DISPATCH(); } op_math_sin: { RavaValue_t val = STACK_POP(stack); double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); RavaValue_t r; r.type = RAVA_VAL_DOUBLE; r.data.double_val = sin(d); STACK_PUSH(stack, r); DISPATCH(); } op_math_cos: { RavaValue_t val = STACK_POP(stack); double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); RavaValue_t r; r.type = RAVA_VAL_DOUBLE; r.data.double_val = cos(d); STACK_PUSH(stack, r); DISPATCH(); } op_math_tan: { RavaValue_t val = STACK_POP(stack); double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); RavaValue_t r; r.type = RAVA_VAL_DOUBLE; r.data.double_val = tan(d); STACK_PUSH(stack, r); DISPATCH(); } op_math_log: { RavaValue_t val = STACK_POP(stack); double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); RavaValue_t r; r.type = RAVA_VAL_DOUBLE; r.data.double_val = log(d); STACK_PUSH(stack, r); DISPATCH(); } op_math_exp: { RavaValue_t val = STACK_POP(stack); double d = (val.type == RAVA_VAL_DOUBLE) ? val.data.double_val : (double)rava_value_as_int(val); RavaValue_t r; r.type = RAVA_VAL_DOUBLE; r.data.double_val = exp(d); STACK_PUSH(stack, r); DISPATCH(); } op_math_random: { RavaValue_t r; r.type = RAVA_VAL_DOUBLE; r.data.double_val = (double)rand() / (double)RAND_MAX; STACK_PUSH(stack, r); DISPATCH(); } done: frame->pc = pc; return !vm->had_error; #undef DISPATCH #undef DISPATCH_NEXT } static bool _rava_vm_execute_ultrafast(RavaVM_t *vm, RavaMethod_t *entry_method) { static const void *dispatch_table[] = { &&uf_nop, &&uf_load_const, &&uf_load_long, &&uf_load_double, &&uf_load_string, &&uf_load_local, &&uf_load_field, &&uf_load_static, &&uf_load_array, &&uf_store_local, &&uf_store_field, &&uf_store_static, &&uf_store_array, &&uf_add, &&uf_sub, &&uf_mul, &&uf_div, &&uf_mod, &&uf_neg, &&uf_and, &&uf_or, &&uf_xor, &&uf_not, &&uf_bitnot, &&uf_shl, &&uf_shr, &&uf_ushr, &&uf_eq, &&uf_ne, &&uf_lt, &&uf_le, &&uf_gt, &&uf_ge, &&uf_jump, &&uf_jump_if_true, &&uf_jump_if_false, &&uf_label, &&uf_call, &&uf_call_static, &&uf_call_virtual, &&uf_call_super, &&uf_call_native, &&uf_return, &&uf_return_void, &&uf_new, &&uf_new_array, &&uf_new_array_of_arrays, &&uf_array_length, &&uf_get_field, &&uf_put_field, &&uf_cast, &&uf_instanceof, &&uf_throw, &&uf_try_begin, &&uf_try_end, &&uf_pop, &&uf_dup, &&uf_print, &&uf_println, &&uf_string_length, &&uf_string_charat, &&uf_string_substring, &&uf_string_equals, &&uf_string_compareto, &&uf_string_indexof, &&uf_string_contains, &&uf_string_startswith, &&uf_string_endswith, &&uf_string_tolowercase, &&uf_string_touppercase, &&uf_string_trim, &&uf_load_this, &&uf_file_read, &&uf_file_write, &&uf_file_exists, &&uf_file_delete, &&uf_current_time_millis, &&uf_nano_time, &&uf_inc_local, &&uf_dec_local, &&uf_load_local_const_add, &&uf_load_local_const_lt_jumpfalse, &&uf_load_local_const_le_jumpfalse, &&uf_load_two_locals, &&uf_add_local_to_local, &&uf_load_local_lt_local_jumpfalse, &&uf_math_abs, &&uf_math_sqrt, &&uf_math_pow, &&uf_math_min, &&uf_math_max, &&uf_math_floor, &&uf_math_ceil, &&uf_math_round, &&uf_math_sin, &&uf_math_cos, &&uf_math_tan, &&uf_math_log, &&uf_math_exp, &&uf_math_random }; rava_fastframe_reset(); FastFrame_t *frame = rava_fastframe_push(entry_method, entry_method->local_count); if (!frame) return false; if (!entry_method->label_table) { rava_optimize_superinstructions(entry_method); entry_method->label_table = rava_labeltable_create(entry_method->instructions); } RavaInstruction_t *instructions = entry_method->instructions->instructions; size_t instr_count = entry_method->instructions->count; register size_t pc = 0; RavaInstruction_t *instr; RavaNanboxValue_t result = rava_nanbox_null(); #define UF_DISPATCH() do { \ if (pc >= instr_count) goto uf_done; \ instr = &instructions[pc++]; \ goto *dispatch_table[instr->opcode]; \ } while(0) #define UF_PUSH(v) rava_fastframe_stack_push(frame, v) #define UF_POP() rava_fastframe_stack_pop(frame) #define UF_PEEK() rava_fastframe_stack_peek(frame) UF_DISPATCH(); uf_nop: UF_DISPATCH(); uf_load_const: UF_PUSH(rava_nanbox_int((int32_t)instr->operand.int_value)); UF_DISPATCH(); uf_load_long: UF_PUSH(rava_nanbox_long(instr->operand.int_value)); UF_DISPATCH(); uf_load_double: UF_PUSH(rava_nanbox_double(instr->operand.float_value)); UF_DISPATCH(); uf_load_string: UF_PUSH(rava_nanbox_string(instr->operand.string_value)); UF_DISPATCH(); uf_load_local: UF_PUSH(frame->locals[instr->operand.var.index]); UF_DISPATCH(); uf_store_local: frame->locals[instr->operand.var.index] = UF_POP(); UF_DISPATCH(); uf_add: { RavaNanboxValue_t b = UF_POP(); RavaNanboxValue_t a = UF_POP(); if (rava_nanbox_is_int(a) && rava_nanbox_is_int(b)) { UF_PUSH(rava_nanbox_int(rava_nanbox_as_int(a) + rava_nanbox_as_int(b))); } else if (rava_nanbox_is_string(a) || rava_nanbox_is_string(b)) { char buf_a[64], buf_b[64]; const char *str_a, *str_b; if (rava_nanbox_is_string(a)) str_a = rava_nanbox_as_string(a) ? rava_nanbox_as_string(a) : "null"; else if (rava_nanbox_is_int(a)) { snprintf(buf_a, 64, "%d", rava_nanbox_as_int(a)); str_a = buf_a; } else if (rava_nanbox_is_long(a)) { snprintf(buf_a, 64, "%ld", (long)rava_nanbox_as_long(a)); str_a = buf_a; } else if (rava_nanbox_is_double(a)) { snprintf(buf_a, 64, "%g", rava_nanbox_as_double(a)); str_a = buf_a; } else if (rava_nanbox_is_bool(a)) { str_a = rava_nanbox_as_bool(a) ? "true" : "false"; } else { str_a = "null"; } if (rava_nanbox_is_string(b)) str_b = rava_nanbox_as_string(b) ? rava_nanbox_as_string(b) : "null"; else if (rava_nanbox_is_int(b)) { snprintf(buf_b, 64, "%d", rava_nanbox_as_int(b)); str_b = buf_b; } else if (rava_nanbox_is_long(b)) { snprintf(buf_b, 64, "%ld", (long)rava_nanbox_as_long(b)); str_b = buf_b; } else if (rava_nanbox_is_double(b)) { snprintf(buf_b, 64, "%g", rava_nanbox_as_double(b)); str_b = buf_b; } else if (rava_nanbox_is_bool(b)) { str_b = rava_nanbox_as_bool(b) ? "true" : "false"; } else { str_b = "null"; } size_t len = strlen(str_a) + strlen(str_b) + 1; char *result = malloc(len); strcpy(result, str_a); strcat(result, str_b); UF_PUSH(rava_nanbox_string(result)); } else if (rava_nanbox_is_long(a) || rava_nanbox_is_long(b)) { UF_PUSH(rava_nanbox_long(rava_nanbox_to_long(a) + rava_nanbox_to_long(b))); } else if (rava_nanbox_is_double(a) || rava_nanbox_is_double(b)) { UF_PUSH(rava_nanbox_double(rava_nanbox_to_double(a) + rava_nanbox_to_double(b))); } else { UF_PUSH(rava_nanbox_long(rava_nanbox_to_long(a) + rava_nanbox_to_long(b))); } UF_DISPATCH(); } uf_sub: { RavaNanboxValue_t b = UF_POP(); RavaNanboxValue_t a = UF_POP(); if (rava_nanbox_is_int(a) && rava_nanbox_is_int(b)) { UF_PUSH(rava_nanbox_int(rava_nanbox_as_int(a) - rava_nanbox_as_int(b))); } else if (rava_nanbox_is_long(a) || rava_nanbox_is_long(b)) { UF_PUSH(rava_nanbox_long(rava_nanbox_to_long(a) - rava_nanbox_to_long(b))); } else { UF_PUSH(rava_nanbox_long(rava_nanbox_to_long(a) - rava_nanbox_to_long(b))); } UF_DISPATCH(); } uf_mul: { RavaNanboxValue_t b = UF_POP(); RavaNanboxValue_t a = UF_POP(); if (rava_nanbox_is_int(a) && rava_nanbox_is_int(b)) { UF_PUSH(rava_nanbox_int(rava_nanbox_as_int(a) * rava_nanbox_as_int(b))); } else if (rava_nanbox_is_long(a) || rava_nanbox_is_long(b)) { UF_PUSH(rava_nanbox_long(rava_nanbox_to_long(a) * rava_nanbox_to_long(b))); } else { UF_PUSH(rava_nanbox_long(rava_nanbox_to_long(a) * rava_nanbox_to_long(b))); } UF_DISPATCH(); } uf_div: { RavaNanboxValue_t b = UF_POP(); RavaNanboxValue_t a = UF_POP(); int64_t bv = rava_nanbox_to_long(b); if (bv == 0) { UF_PUSH(rava_nanbox_int(0)); UF_DISPATCH(); } if (rava_nanbox_is_int(a) && rava_nanbox_is_int(b)) { UF_PUSH(rava_nanbox_int(rava_nanbox_as_int(a) / rava_nanbox_as_int(b))); } else { UF_PUSH(rava_nanbox_long(rava_nanbox_to_long(a) / bv)); } UF_DISPATCH(); } uf_mod: { RavaNanboxValue_t b = UF_POP(); RavaNanboxValue_t a = UF_POP(); int64_t bv = rava_nanbox_to_long(b); if (bv == 0) { UF_PUSH(rava_nanbox_int(0)); UF_DISPATCH(); } if (rava_nanbox_is_int(a) && rava_nanbox_is_int(b)) { UF_PUSH(rava_nanbox_int(rava_nanbox_as_int(a) % rava_nanbox_as_int(b))); } else { UF_PUSH(rava_nanbox_long(rava_nanbox_to_long(a) % bv)); } UF_DISPATCH(); } uf_neg: { RavaNanboxValue_t a = UF_POP(); if (rava_nanbox_is_int(a)) { UF_PUSH(rava_nanbox_int(-rava_nanbox_as_int(a))); } else { UF_PUSH(rava_nanbox_long(-rava_nanbox_to_long(a))); } UF_DISPATCH(); } uf_and: { RavaNanboxValue_t b = UF_POP(); RavaNanboxValue_t a = UF_POP(); UF_PUSH(rava_nanbox_long(rava_nanbox_to_long(a) & rava_nanbox_to_long(b))); UF_DISPATCH(); } uf_or: { RavaNanboxValue_t b = UF_POP(); RavaNanboxValue_t a = UF_POP(); UF_PUSH(rava_nanbox_long(rava_nanbox_to_long(a) | rava_nanbox_to_long(b))); UF_DISPATCH(); } uf_xor: { RavaNanboxValue_t b = UF_POP(); RavaNanboxValue_t a = UF_POP(); UF_PUSH(rava_nanbox_long(rava_nanbox_to_long(a) ^ rava_nanbox_to_long(b))); UF_DISPATCH(); } uf_not: { RavaNanboxValue_t a = UF_POP(); UF_PUSH(rava_nanbox_bool(!rava_nanbox_to_bool(a))); UF_DISPATCH(); } uf_bitnot: { RavaNanboxValue_t a = UF_POP(); UF_PUSH(rava_nanbox_long(~rava_nanbox_to_long(a))); UF_DISPATCH(); } uf_shl: { RavaNanboxValue_t b = UF_POP(); RavaNanboxValue_t a = UF_POP(); UF_PUSH(rava_nanbox_long(rava_nanbox_to_long(a) << (rava_nanbox_to_int(b) & 63))); UF_DISPATCH(); } uf_shr: { RavaNanboxValue_t b = UF_POP(); RavaNanboxValue_t a = UF_POP(); UF_PUSH(rava_nanbox_long(rava_nanbox_to_long(a) >> (rava_nanbox_to_int(b) & 63))); UF_DISPATCH(); } uf_ushr: { RavaNanboxValue_t b = UF_POP(); RavaNanboxValue_t a = UF_POP(); UF_PUSH(rava_nanbox_long((uint64_t)rava_nanbox_to_long(a) >> (rava_nanbox_to_int(b) & 63))); UF_DISPATCH(); } uf_eq: { RavaNanboxValue_t b = UF_POP(); RavaNanboxValue_t a = UF_POP(); UF_PUSH(rava_nanbox_bool(rava_nanbox_to_long(a) == rava_nanbox_to_long(b))); UF_DISPATCH(); } uf_ne: { RavaNanboxValue_t b = UF_POP(); RavaNanboxValue_t a = UF_POP(); UF_PUSH(rava_nanbox_bool(rava_nanbox_to_long(a) != rava_nanbox_to_long(b))); UF_DISPATCH(); } uf_lt: { RavaNanboxValue_t b = UF_POP(); RavaNanboxValue_t a = UF_POP(); UF_PUSH(rava_nanbox_bool(rava_nanbox_to_long(a) < rava_nanbox_to_long(b))); UF_DISPATCH(); } uf_le: { RavaNanboxValue_t b = UF_POP(); RavaNanboxValue_t a = UF_POP(); UF_PUSH(rava_nanbox_bool(rava_nanbox_to_long(a) <= rava_nanbox_to_long(b))); UF_DISPATCH(); } uf_gt: { RavaNanboxValue_t b = UF_POP(); RavaNanboxValue_t a = UF_POP(); UF_PUSH(rava_nanbox_bool(rava_nanbox_to_long(a) > rava_nanbox_to_long(b))); UF_DISPATCH(); } uf_ge: { RavaNanboxValue_t b = UF_POP(); RavaNanboxValue_t a = UF_POP(); UF_PUSH(rava_nanbox_bool(rava_nanbox_to_long(a) >= rava_nanbox_to_long(b))); UF_DISPATCH(); } uf_jump: { LabelTable_t *lt = (LabelTable_t*)frame->method->label_table; pc = rava_labeltable_lookup(lt, instr->operand.label_id); UF_DISPATCH(); } uf_jump_if_true: { RavaNanboxValue_t cond = UF_POP(); if (rava_nanbox_to_bool(cond)) { LabelTable_t *lt = (LabelTable_t*)frame->method->label_table; pc = rava_labeltable_lookup(lt, instr->operand.label_id); } UF_DISPATCH(); } uf_jump_if_false: { RavaNanboxValue_t cond = UF_POP(); if (!rava_nanbox_to_bool(cond)) { LabelTable_t *lt = (LabelTable_t*)frame->method->label_table; pc = rava_labeltable_lookup(lt, instr->operand.label_id); } UF_DISPATCH(); } uf_label: UF_DISPATCH(); uf_call: uf_call_static: { RavaMethod_t *target = _rava_vm_find_method_cached(vm, instr->operand.call.class_name, instr->operand.call.method_name); if (!target) { vm->had_error = true; goto uf_done; } if (!target->label_table) { rava_optimize_superinstructions(target); target->label_table = rava_labeltable_create(target->instructions); } RavaNanboxValue_t args[16]; for (int i = instr->operand.call.arg_count - 1; i >= 0; i--) { args[i] = UF_POP(); } frame->pc = pc; FastFrame_t *new_frame = rava_fastframe_push(target, target->local_count); if (!new_frame) { vm->had_error = true; goto uf_done; } for (int i = 0; i < instr->operand.call.arg_count; i++) { new_frame->locals[i] = args[i]; } frame = new_frame; instructions = target->instructions->instructions; instr_count = target->instructions->count; pc = 0; UF_DISPATCH(); } uf_call_virtual: { int arg_count = instr->operand.call.arg_count; RavaNanboxValue_t args[16]; for (int i = arg_count - 1; i >= 0; i--) { args[i] = UF_POP(); } RavaNanboxValue_t obj_val = UF_POP(); if (rava_nanbox_is_null(obj_val)) { vm->had_error = true; goto uf_done; } RavaObject_t *obj = rava_nanbox_as_object(obj_val); const char *class_name = obj->class_name; RavaMethod_t *target = _rava_vm_find_method_cached(vm, class_name, instr->operand.call.method_name); if (!target) { if (strcmp(instr->operand.call.method_name, "") == 0 && arg_count == 0) { UF_DISPATCH(); } vm->had_error = true; goto uf_done; } if (!target->label_table) { rava_optimize_superinstructions(target); target->label_table = rava_labeltable_create(target->instructions); } frame->pc = pc; FastFrame_t *new_frame = rava_fastframe_push(target, target->local_count); if (!new_frame) { vm->had_error = true; goto uf_done; } new_frame->has_this = true; new_frame->this_ref = obj_val; for (int i = 0; i < arg_count; i++) { new_frame->locals[i] = args[i]; } frame = new_frame; instructions = target->instructions->instructions; instr_count = target->instructions->count; pc = 0; UF_DISPATCH(); } uf_call_super: { int arg_count = instr->operand.call.arg_count; RavaNanboxValue_t args[16]; for (int i = arg_count - 1; i >= 0; i--) { args[i] = UF_POP(); } RavaNanboxValue_t obj_val = UF_POP(); const char *super_class = instr->operand.call.class_name; RavaMethod_t *target = _rava_vm_find_method_cached(vm, super_class, instr->operand.call.method_name); if (!target) { vm->had_error = true; goto uf_done; } if (!target->label_table) { rava_optimize_superinstructions(target); target->label_table = rava_labeltable_create(target->instructions); } frame->pc = pc; FastFrame_t *new_frame = rava_fastframe_push(target, target->local_count); if (!new_frame) { vm->had_error = true; goto uf_done; } new_frame->has_this = true; new_frame->this_ref = obj_val; for (int i = 0; i < arg_count; i++) { new_frame->locals[i] = args[i]; } frame = new_frame; instructions = target->instructions->instructions; instr_count = target->instructions->count; pc = 0; UF_DISPATCH(); } uf_call_native: UF_DISPATCH(); uf_return: { result = UF_POP(); rava_fastframe_pop(); frame = rava_fastframe_current(); if (!frame) { RavaCallFrame_t *old_frame = rava_call_stack_current(vm->call_stack); if (old_frame) { rava_stack_push(old_frame->operand_stack, rava_nanbox_to_value(result)); } goto uf_done; } UF_PUSH(result); pc = frame->pc; instructions = frame->method->instructions->instructions; instr_count = frame->method->instructions->count; UF_DISPATCH(); } uf_return_void: { rava_fastframe_pop(); frame = rava_fastframe_current(); if (!frame) goto uf_done; pc = frame->pc; instructions = frame->method->instructions->instructions; instr_count = frame->method->instructions->count; UF_DISPATCH(); } uf_new: { RavaObject_t *obj = rava_object_create(instr->operand.call.class_name); UF_PUSH(rava_nanbox_object(obj)); UF_DISPATCH(); } uf_new_array: { RavaNanboxValue_t size_val = UF_POP(); int32_t size = rava_nanbox_to_int(size_val); RavaArray_t *arr = rava_array_create(RAVA_VAL_INT, size > 0 ? (size_t)size : 0); UF_PUSH(rava_nanbox_array(arr)); UF_DISPATCH(); } uf_new_array_of_arrays: { RavaNanboxValue_t size_val = UF_POP(); int32_t size = rava_nanbox_to_int(size_val); RavaArray_t *arr = rava_array_create(RAVA_VAL_ARRAY, size > 0 ? (size_t)size : 0); UF_PUSH(rava_nanbox_array(arr)); UF_DISPATCH(); } uf_array_length: { RavaNanboxValue_t arr_val = UF_POP(); RavaArray_t *arr = rava_nanbox_as_array(arr_val); UF_PUSH(rava_nanbox_int(arr ? (int32_t)arr->length : 0)); UF_DISPATCH(); } uf_load_array: { RavaNanboxValue_t idx = UF_POP(); RavaNanboxValue_t arr_val = UF_POP(); RavaArray_t *arr = rava_nanbox_as_array(arr_val); int32_t i = rava_nanbox_to_int(idx); if (arr && i >= 0 && (size_t)i < arr->length) { if (arr->element_type == RAVA_VAL_ARRAY || arr->element_type == RAVA_VAL_OBJECT) { RavaValue_t v = rava_array_get_value(arr, (size_t)i); UF_PUSH(rava_value_to_nanbox(v)); } else { int32_t val = rava_array_get_int(arr, (size_t)i); UF_PUSH(rava_nanbox_int(val)); } } else { UF_PUSH(rava_nanbox_int(0)); } UF_DISPATCH(); } uf_store_array: { RavaNanboxValue_t val = UF_POP(); RavaNanboxValue_t idx = UF_POP(); RavaNanboxValue_t arr_val = UF_POP(); RavaArray_t *arr = rava_nanbox_as_array(arr_val); int32_t i = rava_nanbox_to_int(idx); if (arr && i >= 0 && (size_t)i < arr->length) { if (arr->element_type == RAVA_VAL_ARRAY || arr->element_type == RAVA_VAL_OBJECT) { rava_array_set_value(arr, (size_t)i, rava_nanbox_to_value(val)); } else { rava_array_set_int(arr, (size_t)i, rava_nanbox_to_int(val)); } } UF_DISPATCH(); } uf_get_field: uf_load_field: { RavaNanboxValue_t obj_val = UF_POP(); RavaObject_t *obj = rava_nanbox_as_object(obj_val); if (obj) { RavaValue_t v = rava_object_get_field(obj, instr->operand.field.field_name); UF_PUSH(rava_value_to_nanbox(v)); } else { UF_PUSH(rava_nanbox_null()); } UF_DISPATCH(); } uf_put_field: uf_store_field: { RavaNanboxValue_t val = UF_POP(); RavaNanboxValue_t obj_val = UF_POP(); RavaObject_t *obj = rava_nanbox_as_object(obj_val); if (obj) { rava_object_set_field(obj, instr->operand.field.field_name, rava_nanbox_to_value(val)); } UF_DISPATCH(); } uf_load_static: { RavaValue_t *v = rava_static_field_table_get(vm->static_fields, instr->operand.field.class_name, instr->operand.field.field_name); UF_PUSH(v ? rava_value_to_nanbox(*v) : rava_nanbox_null()); UF_DISPATCH(); } uf_store_static: { RavaNanboxValue_t val = UF_POP(); rava_static_field_table_set(vm->static_fields, instr->operand.field.class_name, instr->operand.field.field_name, rava_nanbox_to_value(val)); UF_DISPATCH(); } uf_string_indexof: { RavaNanboxValue_t needle = UF_POP(); RavaNanboxValue_t s = UF_POP(); const char *str = rava_nanbox_as_string(s); const char *nstr = rava_nanbox_as_string(needle); if (str && nstr) { const char *found = strstr(str, nstr); UF_PUSH(rava_nanbox_int(found ? (int32_t)(found - str) : -1)); } else { UF_PUSH(rava_nanbox_int(-1)); } UF_DISPATCH(); } uf_string_contains: { RavaNanboxValue_t needle = UF_POP(); RavaNanboxValue_t s = UF_POP(); const char *str = rava_nanbox_as_string(s); const char *nstr = rava_nanbox_as_string(needle); UF_PUSH(rava_nanbox_bool(str && nstr && strstr(str, nstr) != NULL)); UF_DISPATCH(); } uf_string_startswith: { RavaNanboxValue_t prefix = UF_POP(); RavaNanboxValue_t s = UF_POP(); const char *str = rava_nanbox_as_string(s); const char *pstr = rava_nanbox_as_string(prefix); if (str && pstr) { size_t plen = strlen(pstr); UF_PUSH(rava_nanbox_bool(strncmp(str, pstr, plen) == 0)); } else { UF_PUSH(rava_nanbox_bool(false)); } UF_DISPATCH(); } uf_string_endswith: { RavaNanboxValue_t suffix = UF_POP(); RavaNanboxValue_t s = UF_POP(); const char *str = rava_nanbox_as_string(s); const char *sstr = rava_nanbox_as_string(suffix); if (str && sstr) { size_t slen = strlen(str); size_t suflen = strlen(sstr); if (suflen <= slen) { UF_PUSH(rava_nanbox_bool(strcmp(str + slen - suflen, sstr) == 0)); } else { UF_PUSH(rava_nanbox_bool(false)); } } else { UF_PUSH(rava_nanbox_bool(false)); } UF_DISPATCH(); } uf_string_tolowercase: { RavaNanboxValue_t s = UF_POP(); const char *str = rava_nanbox_as_string(s); if (str) { size_t len = strlen(str); char *lower = malloc(len + 1); for (size_t i = 0; i <= len; i++) { lower[i] = (char)tolower((unsigned char)str[i]); } UF_PUSH(rava_nanbox_string(lower)); } else { UF_PUSH(rava_nanbox_string("")); } UF_DISPATCH(); } uf_string_touppercase: { RavaNanboxValue_t s = UF_POP(); const char *str = rava_nanbox_as_string(s); if (str) { size_t len = strlen(str); char *upper = malloc(len + 1); for (size_t i = 0; i <= len; i++) { upper[i] = (char)toupper((unsigned char)str[i]); } UF_PUSH(rava_nanbox_string(upper)); } else { UF_PUSH(rava_nanbox_string("")); } UF_DISPATCH(); } uf_string_trim: { RavaNanboxValue_t s = UF_POP(); const char *str = rava_nanbox_as_string(s); if (str) { const char *start = str; while (*start && isspace((unsigned char)*start)) start++; const char *end = str + strlen(str); while (end > start && isspace((unsigned char)*(end - 1))) end--; size_t len = (size_t)(end - start); char *trimmed = malloc(len + 1); strncpy(trimmed, start, len); trimmed[len] = '\0'; UF_PUSH(rava_nanbox_string(trimmed)); } else { UF_PUSH(rava_nanbox_string("")); } UF_DISPATCH(); } uf_load_this: if (frame->has_this) { UF_PUSH(frame->this_ref); } else { UF_PUSH(rava_nanbox_null()); } UF_DISPATCH(); uf_pop: UF_POP(); UF_DISPATCH(); uf_dup: { RavaNanboxValue_t v = UF_PEEK(); UF_PUSH(v); UF_DISPATCH(); } uf_print: { RavaNanboxValue_t v = UF_POP(); if (rava_nanbox_is_int(v)) { printf("%d", rava_nanbox_as_int(v)); } else if (rava_nanbox_is_long(v)) { printf("%ld", rava_nanbox_as_long(v)); } else if (rava_nanbox_is_double(v)) { printf("%g", rava_nanbox_as_double(v)); } else if (rava_nanbox_is_bool(v)) { printf("%s", rava_nanbox_as_bool(v) ? "true" : "false"); } else if (rava_nanbox_is_string(v)) { printf("%s", rava_nanbox_as_string(v)); } else if (rava_nanbox_is_null(v)) { printf("null"); } UF_DISPATCH(); } uf_println: { RavaNanboxValue_t v = UF_POP(); if (rava_nanbox_is_int(v)) { printf("%d\n", rava_nanbox_as_int(v)); } else if (rava_nanbox_is_long(v)) { printf("%ld\n", rava_nanbox_as_long(v)); } else if (rava_nanbox_is_double(v)) { printf("%g\n", rava_nanbox_as_double(v)); } else if (rava_nanbox_is_bool(v)) { printf("%s\n", rava_nanbox_as_bool(v) ? "true" : "false"); } else if (rava_nanbox_is_string(v)) { printf("%s\n", rava_nanbox_as_string(v)); } else if (rava_nanbox_is_null(v)) { printf("null\n"); } UF_DISPATCH(); } uf_string_length: { RavaNanboxValue_t s = UF_POP(); const char *str = rava_nanbox_as_string(s); UF_PUSH(rava_nanbox_int(str ? (int32_t)strlen(str) : 0)); UF_DISPATCH(); } uf_string_charat: { RavaNanboxValue_t idx = UF_POP(); RavaNanboxValue_t s = UF_POP(); const char *str = rava_nanbox_as_string(s); int32_t i = rava_nanbox_to_int(idx); if (str && i >= 0 && (size_t)i < strlen(str)) { UF_PUSH(rava_nanbox_int((int32_t)str[i])); } else { UF_PUSH(rava_nanbox_int(0)); } UF_DISPATCH(); } uf_string_substring: { RavaNanboxValue_t end_val = UF_POP(); RavaNanboxValue_t start_val = UF_POP(); RavaNanboxValue_t s = UF_POP(); const char *str = rava_nanbox_as_string(s); int32_t start = rava_nanbox_to_int(start_val); int32_t end = rava_nanbox_to_int(end_val); if (str && start >= 0 && end >= start && (size_t)end <= strlen(str)) { size_t len = (size_t)(end - start); char *sub = malloc(len + 1); strncpy(sub, str + start, len); sub[len] = '\0'; UF_PUSH(rava_nanbox_string(sub)); } else { UF_PUSH(rava_nanbox_string("")); } UF_DISPATCH(); } uf_string_equals: { RavaNanboxValue_t b = UF_POP(); RavaNanboxValue_t a = UF_POP(); const char *sa = rava_nanbox_as_string(a); const char *sb = rava_nanbox_as_string(b); UF_PUSH(rava_nanbox_bool(sa && sb && strcmp(sa, sb) == 0)); UF_DISPATCH(); } uf_string_compareto: { RavaNanboxValue_t b = UF_POP(); RavaNanboxValue_t a = UF_POP(); const char *sa = rava_nanbox_as_string(a); const char *sb = rava_nanbox_as_string(b); if (sa && sb) { UF_PUSH(rava_nanbox_int(strcmp(sa, sb))); } else { UF_PUSH(rava_nanbox_int(0)); } UF_DISPATCH(); } uf_cast: { RavaNanboxValue_t val = UF_POP(); RavaType_t *target_type = instr->operand.var.type; if (target_type) { switch (target_type->kind) { case RAVA_TYPE_INT: if (rava_nanbox_is_double(val)) { UF_PUSH(rava_nanbox_int((int32_t)rava_nanbox_to_double(val))); } else if (rava_nanbox_is_long(val)) { UF_PUSH(rava_nanbox_int((int32_t)rava_nanbox_to_long(val))); } else { UF_PUSH(val); } break; case RAVA_TYPE_LONG: if (rava_nanbox_is_double(val)) { UF_PUSH(rava_nanbox_long((int64_t)rava_nanbox_to_double(val))); } else if (rava_nanbox_is_int(val)) { UF_PUSH(rava_nanbox_long((int64_t)rava_nanbox_to_int(val))); } else { UF_PUSH(val); } break; case RAVA_TYPE_DOUBLE: case RAVA_TYPE_FLOAT: if (rava_nanbox_is_int(val)) { UF_PUSH(rava_nanbox_double((double)rava_nanbox_to_int(val))); } else if (rava_nanbox_is_long(val)) { UF_PUSH(rava_nanbox_double((double)rava_nanbox_to_long(val))); } else { UF_PUSH(val); } break; default: UF_PUSH(val); break; } } else { UF_PUSH(val); } UF_DISPATCH(); } uf_instanceof: { RavaNanboxValue_t val = UF_POP(); bool result = false; if (rava_nanbox_is_object(val)) { RavaObject_t *obj = rava_nanbox_as_object(val); if (obj) { result = strcmp(obj->class_name, instr->operand.string_value) == 0; } } UF_PUSH(rava_nanbox_bool(result)); UF_DISPATCH(); } uf_throw: { RavaNanboxValue_t exception = UF_POP(); vm->has_exception = true; vm->exception_value = rava_nanbox_to_value(exception); RavaExceptionHandler_t handler; if (rava_exception_stack_pop(vm->exception_stack, &handler)) { frame->locals[handler.exception_local] = exception; LabelTable_t *lt = (LabelTable_t*)frame->method->label_table; pc = rava_labeltable_lookup(lt, handler.catch_label); vm->has_exception = false; UF_DISPATCH(); } else { vm->had_error = true; goto uf_done; } } uf_try_begin: { RavaExceptionHandler_t handler; handler.catch_label = instr->operand.try_handler.catch_label; handler.finally_label = instr->operand.try_handler.finally_label; handler.end_label = instr->operand.try_handler.end_label; handler.exception_local = instr->operand.try_handler.exception_local; handler.stack_depth = frame->stack_top; rava_exception_stack_push(vm->exception_stack, handler); UF_DISPATCH(); } uf_try_end: { RavaExceptionHandler_t handler; rava_exception_stack_pop(vm->exception_stack, &handler); UF_DISPATCH(); } uf_file_read: uf_file_write: uf_file_exists: uf_file_delete: UF_DISPATCH(); uf_current_time_millis: { struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); int64_t ms = (int64_t)ts.tv_sec * 1000 + (int64_t)ts.tv_nsec / 1000000; UF_PUSH(rava_nanbox_long(ms)); UF_DISPATCH(); } uf_nano_time: { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); int64_t ns = (int64_t)ts.tv_sec * 1000000000LL + (int64_t)ts.tv_nsec; UF_PUSH(rava_nanbox_long(ns)); UF_DISPATCH(); } uf_inc_local: { int idx = instr->operand.var.index; RavaNanboxValue_t v = frame->locals[idx]; if (rava_nanbox_is_int(v)) { frame->locals[idx] = rava_nanbox_int(rava_nanbox_as_int(v) + 1); } else { frame->locals[idx] = rava_nanbox_long(rava_nanbox_to_long(v) + 1); } UF_DISPATCH(); } uf_dec_local: { int idx = instr->operand.var.index; RavaNanboxValue_t v = frame->locals[idx]; if (rava_nanbox_is_int(v)) { frame->locals[idx] = rava_nanbox_int(rava_nanbox_as_int(v) - 1); } else { frame->locals[idx] = rava_nanbox_long(rava_nanbox_to_long(v) - 1); } UF_DISPATCH(); } uf_load_local_const_add: { int idx = instr->operand.super.local_index; int64_t c = instr->operand.super.const_value; RavaNanboxValue_t v = frame->locals[idx]; if (rava_nanbox_is_int(v)) { UF_PUSH(rava_nanbox_int(rava_nanbox_as_int(v) + (int32_t)c)); } else { UF_PUSH(rava_nanbox_long(rava_nanbox_to_long(v) + c)); } UF_DISPATCH(); } uf_load_local_const_lt_jumpfalse: { int idx = instr->operand.super.local_index; int64_t c = instr->operand.super.const_value; int label = instr->operand.super.label_id; RavaNanboxValue_t v = frame->locals[idx]; int64_t local_val = rava_nanbox_to_long(v); if (!(local_val < c)) { LabelTable_t *lt = (LabelTable_t*)frame->method->label_table; pc = rava_labeltable_lookup(lt, label); } UF_DISPATCH(); } uf_load_local_const_le_jumpfalse: { int idx = instr->operand.super.local_index; int64_t c = instr->operand.super.const_value; int label = instr->operand.super.label_id; RavaNanboxValue_t v = frame->locals[idx]; int64_t local_val = rava_nanbox_to_long(v); if (!(local_val <= c)) { LabelTable_t *lt = (LabelTable_t*)frame->method->label_table; pc = rava_labeltable_lookup(lt, label); } UF_DISPATCH(); } uf_load_two_locals: { int idx1 = instr->operand.two_locals.index1; int idx2 = instr->operand.two_locals.index2; UF_PUSH(frame->locals[idx1]); UF_PUSH(frame->locals[idx2]); UF_DISPATCH(); } uf_add_local_to_local: { int dest = instr->operand.add_locals.dest_index; int src = instr->operand.add_locals.src_index; RavaNanboxValue_t d = frame->locals[dest]; RavaNanboxValue_t s = frame->locals[src]; if (rava_nanbox_is_int(d) && rava_nanbox_is_int(s)) { frame->locals[dest] = rava_nanbox_int(rava_nanbox_as_int(d) + rava_nanbox_as_int(s)); } else { frame->locals[dest] = rava_nanbox_long(rava_nanbox_to_long(d) + rava_nanbox_to_long(s)); } UF_DISPATCH(); } uf_load_local_lt_local_jumpfalse: { int local1 = instr->operand.cmp_locals.local1; int local2 = instr->operand.cmp_locals.local2; int label = instr->operand.cmp_locals.label_id; int64_t v1 = rava_nanbox_to_long(frame->locals[local1]); int64_t v2 = rava_nanbox_to_long(frame->locals[local2]); if (!(v1 < v2)) { LabelTable_t *lt = (LabelTable_t*)frame->method->label_table; pc = rava_labeltable_lookup(lt, label); } UF_DISPATCH(); } uf_math_abs: { RavaNanboxValue_t val = UF_POP(); if (rava_nanbox_is_double(val)) { double d = rava_nanbox_to_double(val); UF_PUSH(rava_nanbox_double(fabs(d))); } else { int64_t v = rava_nanbox_to_long(val); UF_PUSH(rava_nanbox_long(v < 0 ? -v : v)); } UF_DISPATCH(); } uf_math_sqrt: { RavaNanboxValue_t val = UF_POP(); double d = rava_nanbox_is_double(val) ? rava_nanbox_to_double(val) : (double)rava_nanbox_to_long(val); UF_PUSH(rava_nanbox_double(sqrt(d))); UF_DISPATCH(); } uf_math_pow: { RavaNanboxValue_t exp = UF_POP(); RavaNanboxValue_t base = UF_POP(); double b = rava_nanbox_is_double(base) ? rava_nanbox_to_double(base) : (double)rava_nanbox_to_long(base); double e = rava_nanbox_is_double(exp) ? rava_nanbox_to_double(exp) : (double)rava_nanbox_to_long(exp); UF_PUSH(rava_nanbox_double(pow(b, e))); UF_DISPATCH(); } uf_math_min: { RavaNanboxValue_t b = UF_POP(); RavaNanboxValue_t a = UF_POP(); if (rava_nanbox_is_double(a) || rava_nanbox_is_double(b)) { double da = rava_nanbox_is_double(a) ? rava_nanbox_to_double(a) : (double)rava_nanbox_to_long(a); double db = rava_nanbox_is_double(b) ? rava_nanbox_to_double(b) : (double)rava_nanbox_to_long(b); UF_PUSH(rava_nanbox_double(da < db ? da : db)); } else { int64_t ia = rava_nanbox_to_long(a); int64_t ib = rava_nanbox_to_long(b); UF_PUSH(rava_nanbox_long(ia < ib ? ia : ib)); } UF_DISPATCH(); } uf_math_max: { RavaNanboxValue_t b = UF_POP(); RavaNanboxValue_t a = UF_POP(); if (rava_nanbox_is_double(a) || rava_nanbox_is_double(b)) { double da = rava_nanbox_is_double(a) ? rava_nanbox_to_double(a) : (double)rava_nanbox_to_long(a); double db = rava_nanbox_is_double(b) ? rava_nanbox_to_double(b) : (double)rava_nanbox_to_long(b); UF_PUSH(rava_nanbox_double(da > db ? da : db)); } else { int64_t ia = rava_nanbox_to_long(a); int64_t ib = rava_nanbox_to_long(b); UF_PUSH(rava_nanbox_long(ia > ib ? ia : ib)); } UF_DISPATCH(); } uf_math_floor: { RavaNanboxValue_t val = UF_POP(); double d = rava_nanbox_is_double(val) ? rava_nanbox_to_double(val) : (double)rava_nanbox_to_long(val); UF_PUSH(rava_nanbox_double(floor(d))); UF_DISPATCH(); } uf_math_ceil: { RavaNanboxValue_t val = UF_POP(); double d = rava_nanbox_is_double(val) ? rava_nanbox_to_double(val) : (double)rava_nanbox_to_long(val); UF_PUSH(rava_nanbox_double(ceil(d))); UF_DISPATCH(); } uf_math_round: { RavaNanboxValue_t val = UF_POP(); double d = rava_nanbox_is_double(val) ? rava_nanbox_to_double(val) : (double)rava_nanbox_to_long(val); UF_PUSH(rava_nanbox_long((int64_t)round(d))); UF_DISPATCH(); } uf_math_sin: { RavaNanboxValue_t val = UF_POP(); double d = rava_nanbox_is_double(val) ? rava_nanbox_to_double(val) : (double)rava_nanbox_to_long(val); UF_PUSH(rava_nanbox_double(sin(d))); UF_DISPATCH(); } uf_math_cos: { RavaNanboxValue_t val = UF_POP(); double d = rava_nanbox_is_double(val) ? rava_nanbox_to_double(val) : (double)rava_nanbox_to_long(val); UF_PUSH(rava_nanbox_double(cos(d))); UF_DISPATCH(); } uf_math_tan: { RavaNanboxValue_t val = UF_POP(); double d = rava_nanbox_is_double(val) ? rava_nanbox_to_double(val) : (double)rava_nanbox_to_long(val); UF_PUSH(rava_nanbox_double(tan(d))); UF_DISPATCH(); } uf_math_log: { RavaNanboxValue_t val = UF_POP(); double d = rava_nanbox_is_double(val) ? rava_nanbox_to_double(val) : (double)rava_nanbox_to_long(val); UF_PUSH(rava_nanbox_double(log(d))); UF_DISPATCH(); } uf_math_exp: { RavaNanboxValue_t val = UF_POP(); double d = rava_nanbox_is_double(val) ? rava_nanbox_to_double(val) : (double)rava_nanbox_to_long(val); UF_PUSH(rava_nanbox_double(exp(d))); UF_DISPATCH(); } uf_math_random: { UF_PUSH(rava_nanbox_double((double)rand() / (double)RAND_MAX)); UF_DISPATCH(); } uf_done: rava_fastframe_reset(); return !vm->had_error; #undef UF_DISPATCH #undef UF_PUSH #undef UF_POP #undef UF_PEEK } #endif static bool _rava_vm_run_static_initializers(RavaVM_t *vm) { for (size_t c = 0; c < vm->program->class_count; c++) { RavaClass_t *cls = vm->program->classes[c]; for (size_t m = 0; m < cls->method_count; m++) { RavaMethod_t *method = cls->methods[m]; if (strcmp(method->name, "") == 0) { RavaCallFrame_t *frame = rava_call_frame_create(method); rava_call_stack_push(vm->call_stack, frame); #ifdef __GNUC__ if (!_rava_vm_execute_fast(vm, frame)) { return false; } #else while (frame->pc < frame->method->instructions->count) { RavaInstruction_t *instr = &frame->method->instructions->instructions[frame->pc]; if (instr->opcode == RAVA_OP_RETURN || instr->opcode == RAVA_OP_RETURN_VOID) { break; } frame->pc++; if (!_rava_vm_execute_instruction(vm, frame, instr)) { return false; } } #endif rava_call_stack_pop(vm->call_stack); rava_call_frame_destroy(frame); } } } return true; } bool rava_vm_execute(RavaVM_t *vm, const char *class_name, const char *method_name) { if (!_rava_vm_run_static_initializers(vm)) { return false; } RavaMethod_t *method = _rava_vm_find_method_cached(vm, class_name, method_name); if (!method) { vm->had_error = true; vm->error_message = malloc(256); snprintf(vm->error_message, 256, "Method not found: %s.%s", class_name, method_name); return false; } RavaCallFrame_t *frame = rava_call_frame_create(method); rava_call_stack_push(vm->call_stack, frame); #ifdef __GNUC__ return _rava_vm_execute_ultrafast(vm, method); #else while (frame->pc < frame->method->instructions->count) { RavaInstruction_t *instr = &frame->method->instructions->instructions[frame->pc]; if (instr->opcode == RAVA_OP_RETURN || instr->opcode == RAVA_OP_RETURN_VOID) { break; } frame->pc++; if (!_rava_vm_execute_instruction(vm, frame, instr)) { return false; } } return !vm->had_error; #endif } RavaValue_t rava_vm_get_result(RavaVM_t *vm) { RavaCallFrame_t *frame = rava_call_stack_current(vm->call_stack); if (frame && !rava_stack_is_empty(frame->operand_stack)) { return rava_stack_peek(frame->operand_stack); } return rava_value_int(0); }