#define _POSIX_C_SOURCE 200809L #include "runtime.h" #include "labeltable.h" #include "methodcache.h" #include "nanbox.h" #include "fastframe.h" #include "superinst.h" #include "../utils/safe_alloc.h" #include #include #include #include #include #include #ifdef __GNUC__ #define LIKELY(x) __builtin_expect(!!(x), 1) #define UNLIKELY(x) __builtin_expect(!!(x), 0) #else #define LIKELY(x) (x) #define UNLIKELY(x) (x) #endif #define STACK_ENSURE_CAPACITY(stack) do { \ if ((stack)->top >= (stack)->capacity) { \ (stack)->capacity *= 2; \ RavaValue_t *_new_values = realloc((stack)->values, sizeof(RavaValue_t) * (stack)->capacity); \ if (_new_values) (stack)->values = _new_values; \ } \ } 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_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; } static char* _rava_get_string_buffer(RavaVM_t *vm, size_t needed) { if (needed >= RAVA_STRING_BUFFER_SIZE) { return malloc(needed); } char *buf = vm->string_pool.buffers[vm->string_pool.current]; vm->string_pool.current = (vm->string_pool.current + 1) % RAVA_STRING_BUFFER_COUNT; return buf; } static uint32_t _intern_hash(const char *str) { uint32_t hash = 5381; while (*str) hash = ((hash << 5) + hash) ^ (uint32_t)*str++; return hash; } static const char* _rava_intern_string(RavaVM_t *vm, const char *str) { uint32_t h = _intern_hash(str); for (size_t i = 0; i < RAVA_INTERN_TABLE_SIZE; i++) { size_t idx = (h + i) & (RAVA_INTERN_TABLE_SIZE - 1); if (vm->intern_table.strings[idx] == NULL) { if (vm->intern_table.count >= RAVA_INTERN_TABLE_SIZE - 1) { static bool warned = false; if (!warned) { fprintf(stderr, "Warning: String intern table full (%d entries)\n", RAVA_INTERN_TABLE_SIZE); warned = true; } } vm->intern_table.strings[idx] = strdup(str); vm->intern_table.count++; return vm->intern_table.strings[idx]; } if (strcmp(vm->intern_table.strings[idx], str) == 0) { return vm->intern_table.strings[idx]; } } return strdup(str); } static inline uint32_t _rava_field_hash(const char *name) { uint32_t hash = 5381; while (*name) { hash = ((hash << 5) + hash) ^ (uint32_t)*name++; } return hash; } static void _rava_object_set_field_vm(RavaObject_t *obj, const char *name, RavaValue_t value, RavaVM_t *vm) { if (!obj || !name) return; uint32_t hash = _rava_field_hash(name); for (size_t probe = 0; probe < RAVA_OBJECT_HASH_SIZE; probe++) { uint32_t idx = (hash + probe) & (RAVA_OBJECT_HASH_SIZE - 1); int field_idx = obj->field_hash[idx]; if (field_idx == -1) { if (obj->field_count >= obj->field_capacity) { size_t new_cap = obj->field_capacity * 2; char **new_names = rava_safe_realloc(obj->field_names, new_cap * sizeof(char*)); RavaValue_t *new_values = rava_safe_realloc(obj->field_values, new_cap * sizeof(RavaValue_t)); if (!new_names || !new_values) return; obj->field_names = new_names; obj->field_values = new_values; obj->field_capacity = new_cap; } obj->field_names[obj->field_count] = (char*)(vm ? _rava_intern_string(vm, name) : strdup(name)); obj->field_values[obj->field_count] = value; obj->field_hash[idx] = (int)obj->field_count; obj->field_count++; return; } if ((size_t)field_idx < obj->field_count && strcmp(obj->field_names[field_idx], name) == 0) { obj->field_values[field_idx] = value; return; } } } int64_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 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; 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)); if (!stack) return NULL; stack->capacity = capacity; stack->values = malloc(sizeof(RavaValue_t) * capacity); if (!stack->values) { free(stack); return NULL; } 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; RavaValue_t *new_values = rava_safe_realloc(stack->values, sizeof(RavaValue_t) * stack->capacity); if (!new_values) return; stack->values = new_values; } 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)); if (!frame) return NULL; frame->method = method; frame->local_count = method->local_count; frame->locals = calloc(method->local_count, sizeof(RavaValue_t)); if (!frame->locals && method->local_count > 0) { free(frame); return NULL; } frame->pc = 0; size_t stack_size = method->max_stack > 0 ? (size_t)method->max_stack : 64; frame->operand_stack = rava_stack_create(stack_size); if (!frame->operand_stack) { free(frame->locals); free(frame); return NULL; } 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)); if (!stack) return NULL; stack->capacity = 256; stack->frames = malloc(sizeof(RavaCallFrame_t*) * stack->capacity); if (!stack->frames) { free(stack); return NULL; } 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); } #define RAVA_MAX_CALL_STACK_DEPTH 10000 bool rava_call_stack_push(RavaCallStack_t *stack, RavaCallFrame_t *frame) { if (stack->count >= RAVA_MAX_CALL_STACK_DEPTH) { return false; } if (stack->count >= stack->capacity) { stack->capacity *= 2; RavaCallFrame_t **new_frames = rava_safe_realloc(stack->frames, sizeof(RavaCallFrame_t*) * stack->capacity); if (!new_frames) return false; stack->frames = new_frames; } stack->frames[stack->count++] = frame; return true; } 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 inline uint32_t _rava_static_hash(const char *class_name, const char *field_name) { uint32_t hash = 5381; while (*class_name) { hash = ((hash << 5) + hash) ^ (uint32_t)*class_name++; } hash = ((hash << 5) + hash) ^ '.'; while (*field_name) { hash = ((hash << 5) + hash) ^ (uint32_t)*field_name++; } return hash; } static RavaStaticFieldTable_t* rava_static_field_table_create() { RavaStaticFieldTable_t *table = malloc(sizeof(RavaStaticFieldTable_t)); if (!table) return NULL; table->capacity = 16; table->fields = calloc(table->capacity, sizeof(RavaStaticField_t)); if (!table->fields) { free(table); return NULL; } table->count = 0; for (int i = 0; i < RAVA_STATIC_HASH_SIZE; i++) { table->hash_table[i] = -1; } 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) { uint32_t hash = _rava_static_hash(class_name, field_name); for (size_t probe = 0; probe < RAVA_STATIC_HASH_SIZE; probe++) { uint32_t slot = (hash + probe) & (RAVA_STATIC_HASH_SIZE - 1); int idx = table->hash_table[slot]; if (idx == -1) { return NULL; } if ((size_t)idx < table->count && strcmp(table->fields[idx].class_name, class_name) == 0 && strcmp(table->fields[idx].field_name, field_name) == 0) { return &table->fields[idx].value; } } return NULL; } static void rava_static_field_table_set(RavaStaticFieldTable_t *table, const char *class_name, const char *field_name, RavaValue_t value) { uint32_t hash = _rava_static_hash(class_name, field_name); for (size_t probe = 0; probe < RAVA_STATIC_HASH_SIZE; probe++) { uint32_t slot = (hash + probe) & (RAVA_STATIC_HASH_SIZE - 1); int idx = table->hash_table[slot]; if (idx == -1) { if (table->count >= table->capacity) { size_t new_cap = table->capacity * 2; RavaStaticField_t *new_fields = rava_safe_realloc(table->fields, sizeof(RavaStaticField_t) * new_cap); if (!new_fields) return; table->fields = new_fields; table->capacity = new_cap; } 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->hash_table[slot] = (int)table->count; table->count++; return; } if ((size_t)idx < table->count && strcmp(table->fields[idx].class_name, class_name) == 0 && strcmp(table->fields[idx].field_name, field_name) == 0) { table->fields[idx].value = value; return; } } } static RavaExceptionStack_t* rava_exception_stack_create() { RavaExceptionStack_t *stack = calloc(1, sizeof(RavaExceptionStack_t)); if (!stack) return NULL; stack->count = 0; return stack; } static void rava_exception_stack_destroy(RavaExceptionStack_t *stack) { free(stack); } static void rava_exception_stack_push(RavaExceptionStack_t *stack, RavaExceptionHandler_t handler) { if (stack->count >= RAVA_MAX_EXCEPTION_DEPTH) return; 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; } static inline uint32_t _rava_class_hash(const char *name) { uint32_t hash = 5381; while (*name) { hash = ((hash << 5) + hash) ^ (uint32_t)*name++; } return hash & (RAVA_CLASS_HASH_SIZE - 1); } static bool g_gc_initialized = false; RavaVM_t* rava_vm_create(RavaProgram_t *program) { if (!g_gc_initialized) { rava_gc_init(); g_gc_initialized = true; } RavaVM_t *vm = calloc(1, sizeof(RavaVM_t)); if (!vm) return NULL; 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->exception_stack = rava_exception_stack_create(); vm->native_registry = rava_native_registry_create(); if (!vm->call_stack || !vm->static_fields || !vm->method_cache || !vm->exception_stack || !vm->native_registry) { rava_vm_destroy(vm); return NULL; } vm->error_message = NULL; vm->had_error = false; vm->has_exception = false; vm->exception_value = rava_value_null(); for (size_t i = 0; i < RAVA_CLASS_HASH_SIZE; i++) { vm->class_hash[i] = -1; } for (size_t i = 0; i < program->class_count; i++) { uint32_t h = _rava_class_hash(program->classes[i]->name); vm->class_hash[h] = (int)i; } rava_gc_set_vm(vm); 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); rava_native_registry_destroy(vm->native_registry); for (size_t i = 0; i < RAVA_INTERN_TABLE_SIZE; i++) { free(vm->intern_table.strings[i]); } free(vm->error_message); free(vm); } static RavaClass_t* _rava_vm_find_class(RavaVM_t *vm, const char *class_name) { uint32_t h = _rava_class_hash(class_name); int idx = vm->class_hash[h]; if (idx >= 0 && (size_t)idx < vm->program->class_count && strcmp(vm->program->classes[idx]->name, class_name) == 0) { return vm->program->classes[idx]; } for (size_t i = 0; i < vm->program->class_count; i++) { if (strcmp(vm->program->classes[i]->name, class_name) == 0) { vm->class_hash[h] = (int)i; return vm->program->classes[i]; } } return NULL; } static inline uint32_t _rava_method_hash(const char *name) { uint32_t hash = 5381; while (*name) hash = ((hash << 5) + hash) ^ (uint32_t)*name++; return hash & (RAVA_METHOD_HASH_SIZE - 1); } 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; uint32_t h = _rava_method_hash(method_name); int idx = class->method_hash[h]; if (idx >= 0 && (size_t)idx < class->method_count && strcmp(class->methods[idx]->name, method_name) == 0) { return class->methods[idx]; } for (size_t j = 0; j < class->method_count; j++) { if (strcmp(class->methods[j]->name, method_name) == 0) { class->method_hash[h] = (int)j; 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), "%ld", (long)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), "%ld", (long)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); int64_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); int64_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_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(RAVA_ERROR_BUFFER_SIZE); snprintf(vm->error_message, RAVA_ERROR_BUFFER_SIZE, "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); } if (!rava_call_stack_push(vm->call_stack, new_frame)) { vm->had_error = true; vm->error_message = strdup("Stack overflow"); rava_call_frame_destroy(new_frame); return false; } 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; } const char *mname = instr->operand.call.method_name; if (strcmp(mname, "hashCode") == 0 && instr->operand.call.arg_count == 0) { rava_stack_push(stack, rava_value_int(rava_object_hashcode(obj_val))); break; } if (strcmp(mname, "equals") == 0 && instr->operand.call.arg_count == 1) { rava_stack_push(stack, rava_value_boolean(rava_object_equals(obj_val, args[0]))); break; } if (strcmp(mname, "toString") == 0 && instr->operand.call.arg_count == 0) { char *str = rava_object_tostring(obj_val); rava_stack_push(stack, rava_value_string(str)); free(str); break; } if (strcmp(mname, "getClass") == 0 && instr->operand.call.arg_count == 0) { rava_stack_push(stack, rava_value_string(rava_object_getclass(obj_val))); break; } vm->had_error = true; vm->error_message = malloc(RAVA_ERROR_BUFFER_SIZE); snprintf(vm->error_message, RAVA_ERROR_BUFFER_SIZE, "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]; } if (!rava_call_stack_push(vm->call_stack, new_frame)) { vm->had_error = true; vm->error_message = strdup("Stack overflow"); rava_call_frame_destroy(new_frame); return false; } 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(RAVA_ERROR_BUFFER_SIZE); snprintf(vm->error_message, RAVA_ERROR_BUFFER_SIZE, "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]; } if (!rava_call_stack_push(vm->call_stack, new_frame)) { vm->had_error = true; vm->error_message = strdup("Stack overflow"); rava_call_frame_destroy(new_frame); return false; } 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("%ld", (long)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("%ld\n", (long)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); int64_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); int64_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_vm(obj_val.data.object_val, instr->operand.field.field_name, value, vm); } 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((int64_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) { int64_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 { int64_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) { int64_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 { int64_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((int64_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_SOCKET_NEW: { RavaValue_t port_val = rava_stack_pop(stack); RavaValue_t host_val = rava_stack_pop(stack); const char *host = (host_val.type == RAVA_VAL_STRING) ? host_val.data.string_val : "localhost"; int port = rava_value_as_int(port_val); RavaSocket_t *sock = rava_socket_create_connected(host, port); rava_stack_push(stack, rava_value_socket(sock)); break; } case RAVA_OP_SERVER_SOCKET_NEW: { RavaValue_t port_val = rava_stack_pop(stack); int port = rava_value_as_int(port_val); RavaSocket_t *sock = rava_server_socket_create(port); rava_stack_push(stack, rava_value_socket(sock)); break; } case RAVA_OP_SOCKET_CONNECT: { RavaValue_t port_val = rava_stack_pop(stack); RavaValue_t host_val = rava_stack_pop(stack); RavaValue_t sock_val = rava_stack_pop(stack); if (sock_val.type == RAVA_VAL_SOCKET && sock_val.data.socket_val) { const char *host = (host_val.type == RAVA_VAL_STRING) ? host_val.data.string_val : "localhost"; int port = rava_value_as_int(port_val); bool result = rava_socket_connect(sock_val.data.socket_val, host, port); rava_stack_push(stack, rava_value_boolean(result)); } else { rava_stack_push(stack, rava_value_boolean(false)); } break; } case RAVA_OP_SERVER_SOCKET_ACCEPT: { RavaValue_t sock_val = rava_stack_pop(stack); if (sock_val.type == RAVA_VAL_SOCKET && sock_val.data.socket_val) { RavaSocket_t *client = rava_server_socket_accept(sock_val.data.socket_val); if (client) { rava_stack_push(stack, rava_value_socket(client)); } else { rava_stack_push(stack, rava_value_null()); } } else { rava_stack_push(stack, rava_value_null()); } break; } case RAVA_OP_SOCKET_GET_INPUT_STREAM: { RavaValue_t sock_val = rava_stack_pop(stack); if (sock_val.type == RAVA_VAL_SOCKET && sock_val.data.socket_val) { RavaStream_t *stream = rava_socket_get_input_stream(sock_val.data.socket_val); rava_stack_push(stack, rava_value_stream(stream)); } else { rava_stack_push(stack, rava_value_null()); } break; } case RAVA_OP_SOCKET_GET_OUTPUT_STREAM: { RavaValue_t sock_val = rava_stack_pop(stack); if (sock_val.type == RAVA_VAL_SOCKET && sock_val.data.socket_val) { RavaStream_t *stream = rava_socket_get_output_stream(sock_val.data.socket_val); rava_stack_push(stack, rava_value_stream(stream)); } else { rava_stack_push(stack, rava_value_null()); } break; } case RAVA_OP_INPUT_STREAM_READ: { RavaValue_t stream_val = rava_stack_pop(stack); if (stream_val.type == RAVA_VAL_STREAM && stream_val.data.stream_val) { char *data = rava_stream_read(stream_val.data.stream_val); if (data) { rava_stack_push(stack, rava_value_string(data)); free(data); } else { rava_stack_push(stack, rava_value_null()); } } else { rava_stack_push(stack, rava_value_null()); } break; } case RAVA_OP_OUTPUT_STREAM_WRITE: { int arg_count = instr->operand.int_value; if (arg_count >= 1) { RavaValue_t data_val = rava_stack_pop(stack); RavaValue_t stream_val = rava_stack_pop(stack); if (stream_val.type == RAVA_VAL_STREAM && stream_val.data.stream_val) { if (data_val.type == RAVA_VAL_STRING && data_val.data.string_val) { rava_stream_write(stream_val.data.stream_val, data_val.data.string_val); } else if (data_val.type == RAVA_VAL_INT) { rava_stream_write_byte(stream_val.data.stream_val, data_val.data.int_val); } } } break; } case RAVA_OP_SOCKET_CLOSE: { RavaValue_t val = rava_stack_pop(stack); if (val.type == RAVA_VAL_SOCKET && val.data.socket_val) { rava_socket_close(val.data.socket_val); } else if (val.type == RAVA_VAL_STREAM && val.data.stream_val) { rava_stream_close(val.data.stream_val); } break; } case RAVA_OP_STREAM_CLOSE: { RavaValue_t val = rava_stack_pop(stack); if (val.type == RAVA_VAL_STREAM && val.data.stream_val) { rava_stream_close(val.data.stream_val); } break; } case RAVA_OP_METHOD_REF: { RavaMethodRef_t *ref = rava_method_ref_create( instr->operand.method_ref.class_name, instr->operand.method_ref.method_name, instr->operand.method_ref.is_constructor, instr->operand.method_ref.is_static ); if (!instr->operand.method_ref.is_static && stack->top > 0) { ref->target = rava_stack_pop(stack); ref->has_target = true; } rava_stack_push(stack, rava_value_method_ref(ref)); break; } case RAVA_OP_METHOD_REF_INVOKE: { RavaValue_t ref_val = rava_stack_pop(stack); if (ref_val.type != RAVA_VAL_METHOD_REF) { break; } RavaMethodRef_t *ref = ref_val.data.method_ref_val; if (ref->is_static) { RavaMethod_t *method = rava_vm_find_method(vm, ref->class_name, ref->method_name); if (method) { _rava_vm_call_method(vm, method, instr->operand.call.arg_count, false, NULL); } } else if (ref->has_target) { RavaMethod_t *method = rava_vm_find_method(vm, ref->class_name, ref->method_name); if (method) { rava_stack_push(stack, ref->target); _rava_vm_call_method(vm, method, instr->operand.call.arg_count, true, NULL); } } 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_ARRAYLIST_NEW: { RavaArrayList_t *list = rava_arraylist_create(); rava_stack_push(stack, rava_value_arraylist(list)); break; } case RAVA_OP_ARRAYLIST_ADD: { RavaValue_t value = rava_stack_pop(stack); RavaValue_t list_val = rava_stack_pop(stack); if (list_val.type == RAVA_VAL_ARRAYLIST) { rava_arraylist_add(list_val.data.arraylist_val, value); } break; } case RAVA_OP_ARRAYLIST_GET: { RavaValue_t index_or_key = rava_stack_pop(stack); RavaValue_t coll_val = rava_stack_pop(stack); if (coll_val.type == RAVA_VAL_ARRAYLIST) { rava_stack_push(stack, rava_arraylist_get(coll_val.data.arraylist_val, (size_t)rava_value_as_int(index_or_key))); } else if (coll_val.type == RAVA_VAL_HASHMAP && index_or_key.type == RAVA_VAL_STRING) { rava_stack_push(stack, rava_hashmap_get(coll_val.data.hashmap_val, index_or_key.data.string_val)); } else { rava_stack_push(stack, rava_value_null()); } break; } case RAVA_OP_ARRAYLIST_SET: { RavaValue_t value = rava_stack_pop(stack); RavaValue_t index = rava_stack_pop(stack); RavaValue_t list_val = rava_stack_pop(stack); if (list_val.type == RAVA_VAL_ARRAYLIST) { rava_arraylist_set(list_val.data.arraylist_val, (size_t)rava_value_as_int(index), value); } break; } case RAVA_OP_ARRAYLIST_SIZE: { RavaValue_t coll_val = rava_stack_pop(stack); if (coll_val.type == RAVA_VAL_ARRAYLIST) { rava_stack_push(stack, rava_value_int((int32_t)rava_arraylist_size(coll_val.data.arraylist_val))); } else if (coll_val.type == RAVA_VAL_HASHMAP) { rava_stack_push(stack, rava_value_int((int32_t)rava_hashmap_size(coll_val.data.hashmap_val))); } else { rava_stack_push(stack, rava_value_int(0)); } break; } case RAVA_OP_ARRAYLIST_REMOVE: { RavaValue_t index_or_key = rava_stack_pop(stack); RavaValue_t coll_val = rava_stack_pop(stack); if (coll_val.type == RAVA_VAL_ARRAYLIST) { rava_stack_push(stack, rava_arraylist_remove(coll_val.data.arraylist_val, (size_t)rava_value_as_int(index_or_key))); } else if (coll_val.type == RAVA_VAL_HASHMAP && index_or_key.type == RAVA_VAL_STRING) { rava_stack_push(stack, rava_hashmap_remove(coll_val.data.hashmap_val, index_or_key.data.string_val)); } else { rava_stack_push(stack, rava_value_null()); } break; } case RAVA_OP_ARRAYLIST_CLEAR: { RavaValue_t coll_val = rava_stack_pop(stack); if (coll_val.type == RAVA_VAL_ARRAYLIST) { rava_arraylist_clear(coll_val.data.arraylist_val); } else if (coll_val.type == RAVA_VAL_HASHMAP) { rava_hashmap_clear(coll_val.data.hashmap_val); } break; } case RAVA_OP_ARRAYLIST_ISEMPTY: { RavaValue_t list_val = rava_stack_pop(stack); if (list_val.type == RAVA_VAL_ARRAYLIST) { rava_stack_push(stack, rava_value_boolean(rava_arraylist_isempty(list_val.data.arraylist_val))); } else { rava_stack_push(stack, rava_value_boolean(true)); } break; } case RAVA_OP_HASHMAP_NEW: { RavaHashMap_t *map = rava_hashmap_create(); rava_stack_push(stack, rava_value_hashmap(map)); break; } case RAVA_OP_HASHMAP_PUT: { RavaValue_t value = rava_stack_pop(stack); RavaValue_t key_val = rava_stack_pop(stack); RavaValue_t map_val = rava_stack_pop(stack); if (map_val.type == RAVA_VAL_HASHMAP && key_val.type == RAVA_VAL_STRING) { rava_hashmap_put(map_val.data.hashmap_val, key_val.data.string_val, value); } break; } case RAVA_OP_HASHMAP_GET: { RavaValue_t key_val = rava_stack_pop(stack); RavaValue_t map_val = rava_stack_pop(stack); if (map_val.type == RAVA_VAL_HASHMAP && key_val.type == RAVA_VAL_STRING) { rava_stack_push(stack, rava_hashmap_get(map_val.data.hashmap_val, key_val.data.string_val)); } else { rava_stack_push(stack, rava_value_null()); } break; } case RAVA_OP_HASHMAP_REMOVE: { RavaValue_t key_val = rava_stack_pop(stack); RavaValue_t map_val = rava_stack_pop(stack); if (map_val.type == RAVA_VAL_HASHMAP && key_val.type == RAVA_VAL_STRING) { rava_stack_push(stack, rava_hashmap_remove(map_val.data.hashmap_val, key_val.data.string_val)); } else { rava_stack_push(stack, rava_value_null()); } break; } case RAVA_OP_HASHMAP_SIZE: { RavaValue_t map_val = rava_stack_pop(stack); if (map_val.type == RAVA_VAL_HASHMAP) { rava_stack_push(stack, rava_value_int((int32_t)rava_hashmap_size(map_val.data.hashmap_val))); } else { rava_stack_push(stack, rava_value_int(0)); } break; } case RAVA_OP_HASHMAP_CONTAINSKEY: { RavaValue_t key_val = rava_stack_pop(stack); RavaValue_t map_val = rava_stack_pop(stack); if (map_val.type == RAVA_VAL_HASHMAP && key_val.type == RAVA_VAL_STRING) { rava_stack_push(stack, rava_value_boolean(rava_hashmap_containskey(map_val.data.hashmap_val, key_val.data.string_val))); } else { rava_stack_push(stack, rava_value_boolean(false)); } break; } case RAVA_OP_HASHMAP_CLEAR: { RavaValue_t map_val = rava_stack_pop(stack); if (map_val.type == RAVA_VAL_HASHMAP) { rava_hashmap_clear(map_val.data.hashmap_val); } 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_load_array_unchecked, &&op_store_local, &&op_store_field, &&op_store_static, &&op_store_array, &&op_store_array_unchecked, &&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_recursive, &&op_call_inline, &&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) { int32_t i = rava_value_as_int(idx); if (i >= 0 && (size_t)i < arr.data.array_val->length) { size_t index = (size_t)i; 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_load_array_unchecked: { RavaValue_t idx = STACK_POP(stack); RavaValue_t arr = STACK_POP(stack); size_t index = (size_t)rava_value_as_int(idx); 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; } 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_vm(obj_val.data.object_val, instr->operand.field.field_name, value, vm); } 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) { int32_t i = rava_value_as_int(idx); if (i >= 0 && (size_t)i < arr.data.array_val->length) { size_t index = (size_t)i; 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_store_array_unchecked: { RavaValue_t value = STACK_POP(stack); RavaValue_t idx = STACK_POP(stack); RavaValue_t arr = STACK_POP(stack); size_t index = (size_t)rava_value_as_int(idx); 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 (LIKELY(VALUE_IS_INT(a) && VALUE_IS_INT(b))) { STACK_PUSH_INT(stack, VALUE_AS_INT_FAST(a) + VALUE_AS_INT_FAST(b)); } else if (UNLIKELY(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, "%ld", (long)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, "%ld", (long)rava_value_as_int(b)); str_b = buf_b; } size_t len_a = strlen(str_a); size_t len_b = strlen(str_b); size_t len = len_a + len_b + 1; bool need_free = (len >= RAVA_STRING_BUFFER_SIZE); char *result = need_free ? malloc(len) : _rava_get_string_buffer(vm, len); memcpy(result, str_a, len_a); memcpy(result + len_a, str_b, len_b + 1); STACK_PUSH(stack, rava_value_string(result)); if (need_free) 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 (LIKELY(VALUE_IS_INT(a) && VALUE_IS_INT(b))) { STACK_PUSH_INT(stack, VALUE_AS_INT_FAST(a) - VALUE_AS_INT_FAST(b)); } else if (UNLIKELY(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 (LIKELY(VALUE_IS_INT(a) && VALUE_IS_INT(b))) { STACK_PUSH_INT(stack, VALUE_AS_INT_FAST(a) * VALUE_AS_INT_FAST(b)); } else if (UNLIKELY(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 (LIKELY(VALUE_IS_INT(a) && VALUE_IS_INT(b))) { int32_t divisor = VALUE_AS_INT_FAST(b); if (UNLIKELY(divisor == 0)) { vm->had_error = true; goto done; } STACK_PUSH_INT(stack, VALUE_AS_INT_FAST(a) / divisor); } else if (UNLIKELY(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 (LIKELY(VALUE_IS_INT(a) && VALUE_IS_INT(b))) { int32_t divisor = VALUE_AS_INT_FAST(b); if (UNLIKELY(divisor == 0)) { vm->had_error = true; goto done; } STACK_PUSH_INT(stack, VALUE_AS_INT_FAST(a) % divisor); } else if (UNLIKELY(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 (LIKELY(VALUE_IS_INT(a) && VALUE_IS_INT(b))) { STACK_PUSH_BOOL(stack, VALUE_AS_INT_FAST(a) == VALUE_AS_INT_FAST(b)); } else if (UNLIKELY(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 (LIKELY(VALUE_IS_INT(a) && VALUE_IS_INT(b))) { STACK_PUSH_BOOL(stack, VALUE_AS_INT_FAST(a) != VALUE_AS_INT_FAST(b)); } else if (UNLIKELY(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 (LIKELY(VALUE_IS_INT(a) && VALUE_IS_INT(b))) { STACK_PUSH_BOOL(stack, VALUE_AS_INT_FAST(a) < VALUE_AS_INT_FAST(b)); } else if (UNLIKELY(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 (LIKELY(VALUE_IS_INT(a) && VALUE_IS_INT(b))) { STACK_PUSH_BOOL(stack, VALUE_AS_INT_FAST(a) <= VALUE_AS_INT_FAST(b)); } else if (UNLIKELY(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 (LIKELY(VALUE_IS_INT(a) && VALUE_IS_INT(b))) { STACK_PUSH_BOOL(stack, VALUE_AS_INT_FAST(a) > VALUE_AS_INT_FAST(b)); } else if (UNLIKELY(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 (LIKELY(VALUE_IS_INT(a) && VALUE_IS_INT(b))) { STACK_PUSH_BOOL(stack, VALUE_AS_INT_FAST(a) >= VALUE_AS_INT_FAST(b)); } else if (UNLIKELY(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(RAVA_ERROR_BUFFER_SIZE); snprintf(vm->error_message, RAVA_ERROR_BUFFER_SIZE, "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_recursive: { frame->pc = pc; RavaMethod_t *target_method = (RavaMethod_t*)instr->operand.call.cached_method; if (UNLIKELY(!target_method)) { target_method = frame->method; instr->operand.call.cached_method = target_method; } 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_inline: { frame->pc = pc; RavaMethod_t *target_method = (RavaMethod_t*)instr->operand.call.cached_method; if (UNLIKELY(!target_method)) { 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(RAVA_ERROR_BUFFER_SIZE); snprintf(vm->error_message, RAVA_ERROR_BUFFER_SIZE, "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(RAVA_ERROR_BUFFER_SIZE); snprintf(vm->error_message, RAVA_ERROR_BUFFER_SIZE, "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_vm(obj_val.data.object_val, instr->operand.field.field_name, value, vm); } 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("%ld", (long)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("%ld\n", (long)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, rava_object_equals(a, b)); } 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_load_array_unchecked, &&uf_store_local, &&uf_store_field, &&uf_store_static, &&uf_store_array, &&uf_store_array_unchecked, &&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_recursive, &&uf_call_inline, &&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, &&uf_arraylist_new, &&uf_arraylist_add, &&uf_arraylist_get, &&uf_arraylist_set, &&uf_arraylist_size, &&uf_arraylist_remove, &&uf_arraylist_clear, &&uf_arraylist_isempty, &&uf_hashmap_new, &&uf_hashmap_put, &&uf_hashmap_get, &&uf_hashmap_remove, &&uf_hashmap_size, &&uf_hashmap_containskey, &&uf_hashmap_clear, &&uf_socket_new, &&uf_socket_connect, &&uf_socket_read, &&uf_socket_write, &&uf_socket_close, &&uf_server_socket_new, &&uf_server_socket_accept, &&uf_socket_get_input_stream, &&uf_socket_get_output_stream, &&uf_input_stream_read, &&uf_output_stream_write, &&uf_stream_close, &&uf_method_ref, &&uf_method_ref_invoke }; 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 (LIKELY(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 (UNLIKELY(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, "%ld", (long)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, "%ld", (long)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_a = strlen(str_a); size_t len_b = strlen(str_b); size_t len = len_a + len_b + 1; bool need_free = (len >= RAVA_STRING_BUFFER_SIZE); char *result = need_free ? malloc(len) : _rava_get_string_buffer(vm, len); memcpy(result, str_a, len_a); memcpy(result + len_a, str_b, len_b + 1); UF_PUSH(rava_nanbox_string(result)); if (need_free) free(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 (LIKELY(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 (UNLIKELY(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 (LIKELY(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 (UNLIKELY(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 (UNLIKELY(bv == 0)) { UF_PUSH(rava_nanbox_int(0)); UF_DISPATCH(); } if (LIKELY(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_recursive: { RavaMethod_t *target = (RavaMethod_t*)instr->operand.call.cached_method; if (UNLIKELY(!target)) { target = frame->method; instr->operand.call.cached_method = target; } 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_inline: { RavaMethod_t *target = (RavaMethod_t*)instr->operand.call.cached_method; if (UNLIKELY(!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; } const char *mname = instr->operand.call.method_name; if (!rava_nanbox_is_object(obj_val)) { RavaValue_t val = rava_nanbox_to_value(obj_val); if (strcmp(mname, "hashCode") == 0 && arg_count == 0) { UF_PUSH(rava_nanbox_int(rava_object_hashcode(val))); UF_DISPATCH(); } if (strcmp(mname, "equals") == 0 && arg_count == 1) { RavaValue_t other = rava_nanbox_to_value(args[0]); UF_PUSH(rava_nanbox_bool(rava_object_equals(val, other))); UF_DISPATCH(); } if (strcmp(mname, "toString") == 0 && arg_count == 0) { char *str = rava_object_tostring(val); UF_PUSH(rava_nanbox_string(str)); UF_DISPATCH(); } if (strcmp(mname, "getClass") == 0 && arg_count == 0) { UF_PUSH(rava_nanbox_string(rava_object_getclass(val))); UF_DISPATCH(); } 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(mname, "") == 0 && arg_count == 0) { UF_DISPATCH(); } RavaValue_t val = rava_nanbox_to_value(obj_val); if (strcmp(mname, "hashCode") == 0 && arg_count == 0) { UF_PUSH(rava_nanbox_int(rava_object_hashcode(val))); UF_DISPATCH(); } if (strcmp(mname, "equals") == 0 && arg_count == 1) { RavaValue_t other = rava_nanbox_to_value(args[0]); UF_PUSH(rava_nanbox_bool(rava_object_equals(val, other))); UF_DISPATCH(); } if (strcmp(mname, "toString") == 0 && arg_count == 0) { char *str = rava_object_tostring(val); UF_PUSH(rava_nanbox_string(str)); UF_DISPATCH(); } if (strcmp(mname, "getClass") == 0 && arg_count == 0) { UF_PUSH(rava_nanbox_string(rava_object_getclass(val))); 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); int64_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 { int64_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_load_array_unchecked: { RavaNanboxValue_t idx = UF_POP(); RavaNanboxValue_t arr_val = UF_POP(); RavaArray_t *arr = rava_nanbox_as_array(arr_val); size_t i = (size_t)rava_nanbox_to_int(idx); if (arr->element_type == RAVA_VAL_ARRAY || arr->element_type == RAVA_VAL_OBJECT) { RavaValue_t v = rava_array_get_value(arr, i); UF_PUSH(rava_value_to_nanbox(v)); } else { int64_t val = rava_array_get_int(arr, i); UF_PUSH(rava_nanbox_int(val)); } 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); int64_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_store_array_unchecked: { 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); size_t i = (size_t)rava_nanbox_to_int(idx); if (arr->element_type == RAVA_VAL_ARRAY || arr->element_type == RAVA_VAL_OBJECT) { rava_array_set_value(arr, i, rava_nanbox_to_value(val)); } else { rava_array_set_int(arr, 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_vm(obj, instr->operand.field.field_name, rava_nanbox_to_value(val), vm); } 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("%ld", (long)rava_nanbox_as_int(v)); } else if (rava_nanbox_is_long(v)) { printf("%ld", (long)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("%ld\n", (long)rava_nanbox_as_int(v)); } else if (rava_nanbox_is_long(v)) { printf("%ld\n", (long)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(); if (rava_nanbox_is_string(a) && rava_nanbox_is_string(b)) { 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)); } else { RavaValue_t val_a = rava_nanbox_to_value(a); RavaValue_t val_b = rava_nanbox_to_value(b); UF_PUSH(rava_nanbox_bool(rava_object_equals(val_a, val_b))); } 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_arraylist_new: { RavaArrayList_t *list = rava_arraylist_create(); UF_PUSH(rava_nanbox_object(list)); UF_DISPATCH(); } uf_arraylist_add: { RavaNanboxValue_t val = UF_POP(); RavaNanboxValue_t list_nb = UF_POP(); RavaArrayList_t *list = (RavaArrayList_t*)rava_nanbox_as_object(list_nb); if (list) { RavaValue_t v; if (rava_nanbox_is_int(val)) { v = rava_value_int(rava_nanbox_to_int(val)); } else if (rava_nanbox_is_double(val)) { v = rava_value_double(rava_nanbox_to_double(val)); } else { v = rava_value_null(); } rava_arraylist_add(list, v); } UF_DISPATCH(); } uf_arraylist_get: { RavaNanboxValue_t idx_nb = UF_POP(); RavaNanboxValue_t coll_nb = UF_POP(); void *ptr = rava_nanbox_as_object(coll_nb); if (rava_nanbox_is_int(idx_nb)) { RavaArrayList_t *list = (RavaArrayList_t*)ptr; if (list) { RavaValue_t v = rava_arraylist_get(list, (size_t)rava_nanbox_to_int(idx_nb)); if (v.type == RAVA_VAL_INT) { UF_PUSH(rava_nanbox_int(v.data.int_val)); } else if (v.type == RAVA_VAL_DOUBLE) { UF_PUSH(rava_nanbox_double(v.data.double_val)); } else { UF_PUSH(rava_nanbox_null()); } } else { UF_PUSH(rava_nanbox_null()); } } else if (rava_nanbox_is_string(idx_nb)) { RavaHashMap_t *map = (RavaHashMap_t*)ptr; if (map) { RavaValue_t v = rava_hashmap_get(map, rava_nanbox_as_string(idx_nb)); if (v.type == RAVA_VAL_INT) { UF_PUSH(rava_nanbox_int(v.data.int_val)); } else if (v.type == RAVA_VAL_DOUBLE) { UF_PUSH(rava_nanbox_double(v.data.double_val)); } else { UF_PUSH(rava_nanbox_null()); } } else { UF_PUSH(rava_nanbox_null()); } } else { UF_PUSH(rava_nanbox_null()); } UF_DISPATCH(); } uf_arraylist_set: { RavaNanboxValue_t val = UF_POP(); RavaNanboxValue_t idx_nb = UF_POP(); RavaNanboxValue_t list_nb = UF_POP(); RavaArrayList_t *list = (RavaArrayList_t*)rava_nanbox_as_object(list_nb); if (list) { RavaValue_t v; if (rava_nanbox_is_int(val)) { v = rava_value_int(rava_nanbox_to_int(val)); } else if (rava_nanbox_is_double(val)) { v = rava_value_double(rava_nanbox_to_double(val)); } else { v = rava_value_null(); } rava_arraylist_set(list, (size_t)rava_nanbox_to_int(idx_nb), v); } UF_DISPATCH(); } uf_arraylist_size: { RavaNanboxValue_t coll_nb = UF_POP(); void *ptr = rava_nanbox_as_object(coll_nb); if (ptr) { uint8_t gc_type = ((RavaGCHeader_t*)ptr)->gc_type; if (gc_type == RAVA_GC_TYPE_ARRAYLIST) { UF_PUSH(rava_nanbox_int((int32_t)rava_arraylist_size((RavaArrayList_t*)ptr))); } else if (gc_type == RAVA_GC_TYPE_HASHMAP) { UF_PUSH(rava_nanbox_int((int32_t)rava_hashmap_size((RavaHashMap_t*)ptr))); } else { UF_PUSH(rava_nanbox_int(0)); } } else { UF_PUSH(rava_nanbox_int(0)); } UF_DISPATCH(); } uf_arraylist_remove: { RavaNanboxValue_t idx_or_key = UF_POP(); RavaNanboxValue_t coll_nb = UF_POP(); void *ptr = rava_nanbox_as_object(coll_nb); if (ptr) { uint8_t gc_type = ((RavaGCHeader_t*)ptr)->gc_type; if (gc_type == RAVA_GC_TYPE_ARRAYLIST && rava_nanbox_is_int(idx_or_key)) { RavaValue_t v = rava_arraylist_remove((RavaArrayList_t*)ptr, (size_t)rava_nanbox_to_int(idx_or_key)); if (v.type == RAVA_VAL_INT) { UF_PUSH(rava_nanbox_int(v.data.int_val)); } else { UF_PUSH(rava_nanbox_null()); } } else if (gc_type == RAVA_GC_TYPE_HASHMAP && rava_nanbox_is_string(idx_or_key)) { RavaValue_t v = rava_hashmap_remove((RavaHashMap_t*)ptr, rava_nanbox_as_string(idx_or_key)); if (v.type == RAVA_VAL_INT) { UF_PUSH(rava_nanbox_int(v.data.int_val)); } else { UF_PUSH(rava_nanbox_null()); } } else { UF_PUSH(rava_nanbox_null()); } } else { UF_PUSH(rava_nanbox_null()); } UF_DISPATCH(); } uf_arraylist_clear: { RavaNanboxValue_t coll_nb = UF_POP(); void *ptr = rava_nanbox_as_object(coll_nb); if (ptr) { uint8_t gc_type = ((RavaGCHeader_t*)ptr)->gc_type; if (gc_type == RAVA_GC_TYPE_ARRAYLIST) { rava_arraylist_clear((RavaArrayList_t*)ptr); } else if (gc_type == RAVA_GC_TYPE_HASHMAP) { rava_hashmap_clear((RavaHashMap_t*)ptr); } } UF_DISPATCH(); } uf_arraylist_isempty: { RavaNanboxValue_t list_nb = UF_POP(); RavaArrayList_t *list = (RavaArrayList_t*)rava_nanbox_as_object(list_nb); if (list) { UF_PUSH(rava_nanbox_int(rava_arraylist_isempty(list) ? 1 : 0)); } else { UF_PUSH(rava_nanbox_int(1)); } UF_DISPATCH(); } uf_hashmap_new: { RavaHashMap_t *map = rava_hashmap_create(); UF_PUSH(rava_nanbox_object(map)); UF_DISPATCH(); } uf_hashmap_put: { RavaNanboxValue_t val = UF_POP(); RavaNanboxValue_t key_nb = UF_POP(); RavaNanboxValue_t map_nb = UF_POP(); RavaHashMap_t *map = (RavaHashMap_t*)rava_nanbox_as_object(map_nb); if (map && rava_nanbox_is_string(key_nb)) { RavaValue_t v; if (rava_nanbox_is_int(val)) { v = rava_value_int(rava_nanbox_to_int(val)); } else if (rava_nanbox_is_double(val)) { v = rava_value_double(rava_nanbox_to_double(val)); } else { v = rava_value_null(); } rava_hashmap_put(map, rava_nanbox_as_string(key_nb), v); } UF_DISPATCH(); } uf_hashmap_get: { RavaNanboxValue_t key_nb = UF_POP(); RavaNanboxValue_t map_nb = UF_POP(); RavaHashMap_t *map = (RavaHashMap_t*)rava_nanbox_as_object(map_nb); if (map && rava_nanbox_is_string(key_nb)) { RavaValue_t v = rava_hashmap_get(map, rava_nanbox_as_string(key_nb)); if (v.type == RAVA_VAL_INT) { UF_PUSH(rava_nanbox_int(v.data.int_val)); } else if (v.type == RAVA_VAL_DOUBLE) { UF_PUSH(rava_nanbox_double(v.data.double_val)); } else { UF_PUSH(rava_nanbox_null()); } } else { UF_PUSH(rava_nanbox_null()); } UF_DISPATCH(); } uf_hashmap_remove: { RavaNanboxValue_t key_nb = UF_POP(); RavaNanboxValue_t map_nb = UF_POP(); RavaHashMap_t *map = (RavaHashMap_t*)rava_nanbox_as_object(map_nb); if (map && rava_nanbox_is_string(key_nb)) { RavaValue_t v = rava_hashmap_remove(map, rava_nanbox_as_string(key_nb)); if (v.type == RAVA_VAL_INT) { UF_PUSH(rava_nanbox_int(v.data.int_val)); } else { UF_PUSH(rava_nanbox_null()); } } else { UF_PUSH(rava_nanbox_null()); } UF_DISPATCH(); } uf_hashmap_size: { RavaNanboxValue_t map_nb = UF_POP(); RavaHashMap_t *map = (RavaHashMap_t*)rava_nanbox_as_object(map_nb); if (map) { UF_PUSH(rava_nanbox_int((int32_t)rava_hashmap_size(map))); } else { UF_PUSH(rava_nanbox_int(0)); } UF_DISPATCH(); } uf_hashmap_containskey: { RavaNanboxValue_t key_nb = UF_POP(); RavaNanboxValue_t map_nb = UF_POP(); RavaHashMap_t *map = (RavaHashMap_t*)rava_nanbox_as_object(map_nb); if (map && rava_nanbox_is_string(key_nb)) { UF_PUSH(rava_nanbox_int(rava_hashmap_containskey(map, rava_nanbox_as_string(key_nb)) ? 1 : 0)); } else { UF_PUSH(rava_nanbox_int(0)); } UF_DISPATCH(); } uf_hashmap_clear: { RavaNanboxValue_t map_nb = UF_POP(); RavaHashMap_t *map = (RavaHashMap_t*)rava_nanbox_as_object(map_nb); if (map) { rava_hashmap_clear(map); } UF_DISPATCH(); } uf_socket_new: { RavaNanboxValue_t port_nb = UF_POP(); RavaNanboxValue_t host_nb = UF_POP(); const char *host = rava_nanbox_is_string(host_nb) ? rava_nanbox_as_string(host_nb) : "localhost"; int port = rava_nanbox_as_int(port_nb); RavaSocket_t *sock = rava_socket_create_connected(host, port); UF_PUSH(rava_nanbox_object((void*)sock)); UF_DISPATCH(); } uf_server_socket_new: { RavaNanboxValue_t port_nb = UF_POP(); int port = rava_nanbox_as_int(port_nb); RavaSocket_t *sock = rava_server_socket_create(port); UF_PUSH(rava_nanbox_object((void*)sock)); UF_DISPATCH(); } uf_socket_connect: { RavaNanboxValue_t port_nb = UF_POP(); RavaNanboxValue_t host_nb = UF_POP(); RavaNanboxValue_t sock_nb = UF_POP(); RavaSocket_t *sock = (RavaSocket_t*)rava_nanbox_as_object(sock_nb); if (sock) { const char *host = rava_nanbox_is_string(host_nb) ? rava_nanbox_as_string(host_nb) : "localhost"; int port = rava_nanbox_as_int(port_nb); bool result = rava_socket_connect(sock, host, port); UF_PUSH(rava_nanbox_int(result ? 1 : 0)); } else { UF_PUSH(rava_nanbox_int(0)); } UF_DISPATCH(); } uf_server_socket_accept: { RavaNanboxValue_t sock_nb = UF_POP(); RavaSocket_t *server = (RavaSocket_t*)rava_nanbox_as_object(sock_nb); if (server) { RavaSocket_t *client = rava_server_socket_accept(server); if (client) { UF_PUSH(rava_nanbox_object((void*)client)); } else { UF_PUSH(rava_nanbox_null()); } } else { UF_PUSH(rava_nanbox_null()); } UF_DISPATCH(); } uf_socket_get_input_stream: { RavaNanboxValue_t sock_nb = UF_POP(); RavaSocket_t *sock = (RavaSocket_t*)rava_nanbox_as_object(sock_nb); if (sock) { RavaStream_t *stream = rava_socket_get_input_stream(sock); UF_PUSH(rava_nanbox_object((void*)stream)); } else { UF_PUSH(rava_nanbox_null()); } UF_DISPATCH(); } uf_socket_get_output_stream: { RavaNanboxValue_t sock_nb = UF_POP(); RavaSocket_t *sock = (RavaSocket_t*)rava_nanbox_as_object(sock_nb); if (sock) { RavaStream_t *stream = rava_socket_get_output_stream(sock); UF_PUSH(rava_nanbox_object((void*)stream)); } else { UF_PUSH(rava_nanbox_null()); } UF_DISPATCH(); } uf_input_stream_read: { RavaNanboxValue_t stream_nb = UF_POP(); RavaStream_t *stream = (RavaStream_t*)rava_nanbox_as_object(stream_nb); if (stream) { char *data = rava_stream_read(stream); if (data) { UF_PUSH(rava_nanbox_string(data)); free(data); } else { UF_PUSH(rava_nanbox_null()); } } else { UF_PUSH(rava_nanbox_null()); } UF_DISPATCH(); } uf_output_stream_write: { int arg_count = instr->operand.int_value; if (arg_count >= 1) { RavaNanboxValue_t data_nb = UF_POP(); RavaNanboxValue_t stream_nb = UF_POP(); RavaStream_t *stream = (RavaStream_t*)rava_nanbox_as_object(stream_nb); if (stream) { if (rava_nanbox_is_string(data_nb)) { rava_stream_write(stream, rava_nanbox_as_string(data_nb)); } else if (rava_nanbox_is_int(data_nb)) { rava_stream_write_byte(stream, rava_nanbox_as_int(data_nb)); } } } UF_DISPATCH(); } uf_socket_close: { RavaNanboxValue_t val = UF_POP(); void *ptr = rava_nanbox_as_object(val); if (ptr) { rava_socket_close((RavaSocket_t*)ptr); } UF_DISPATCH(); } uf_socket_read: uf_socket_write: uf_stream_close: UF_DISPATCH(); uf_method_ref: uf_method_ref_invoke: 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(RAVA_ERROR_BUFFER_SIZE); snprintf(vm->error_message, RAVA_ERROR_BUFFER_SIZE, "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); } RavaNativeValue_t rava_value_to_native(RavaValue_t value) { RavaNativeValue_t native; switch (value.type) { case RAVA_VAL_INT: native.type = RAVA_NATIVE_INT; native.data.int_val = value.data.int_val; break; case RAVA_VAL_LONG: native.type = RAVA_NATIVE_LONG; native.data.long_val = value.data.long_val; break; case RAVA_VAL_FLOAT: case RAVA_VAL_DOUBLE: native.type = RAVA_NATIVE_DOUBLE; native.data.double_val = (value.type == RAVA_VAL_FLOAT) ? (double)value.data.float_val : value.data.double_val; break; case RAVA_VAL_BOOLEAN: native.type = RAVA_NATIVE_BOOLEAN; native.data.bool_val = value.data.bool_val; break; case RAVA_VAL_STRING: native.type = RAVA_NATIVE_STRING; native.data.string_val = value.data.string_val; break; case RAVA_VAL_OBJECT: native.type = RAVA_NATIVE_OBJECT; native.data.object_val = value.data.object_val; break; case RAVA_VAL_ARRAY: native.type = RAVA_NATIVE_ARRAY; native.data.array_val = value.data.array_val; break; default: native.type = RAVA_NATIVE_VOID; break; } return native; } RavaValue_t rava_native_to_value(RavaNativeValue_t native) { RavaValue_t value; switch (native.type) { case RAVA_NATIVE_INT: value = rava_value_int(native.data.int_val); break; case RAVA_NATIVE_LONG: value = rava_value_long(native.data.long_val); break; case RAVA_NATIVE_DOUBLE: value = rava_value_double(native.data.double_val); break; case RAVA_NATIVE_BOOLEAN: value = rava_value_boolean(native.data.bool_val); break; case RAVA_NATIVE_STRING: value = rava_value_string(native.data.string_val); break; case RAVA_NATIVE_OBJECT: value.type = RAVA_VAL_OBJECT; value.data.object_val = native.data.object_val; break; case RAVA_NATIVE_ARRAY: value.type = RAVA_VAL_ARRAY; value.data.array_val = native.data.array_val; break; default: value = rava_value_null(); break; } return value; } bool rava_vm_load_native_library(RavaVM_t *vm, const char *path) { if (!vm || !vm->native_registry || !path) return false; RavaNativeLibrary_t *lib = rava_native_library_load(vm->native_registry, path); return lib != NULL; } bool rava_vm_register_native(RavaVM_t *vm, const char *class_name, const char *method_name, RavaNativeType_e return_type, RavaNativeType_e *param_types, size_t param_count, RavaNativeFunction_fn function, void *user_data) { if (!vm || !vm->native_registry) return false; return rava_native_register_method(vm->native_registry, class_name, method_name, return_type, param_types, param_count, function, user_data); } RavaValue_t rava_vm_call_native(RavaVM_t *vm, const char *class_name, const char *method_name, RavaValue_t *args, size_t arg_count) { if (!vm || !vm->native_registry) return rava_value_null(); RavaNativeMethod_t *method = rava_native_find_method(vm->native_registry, class_name, method_name); if (!method) { vm->had_error = true; vm->error_message = malloc(256); snprintf(vm->error_message, 256, "Native method not found: %s.%s", class_name, method_name); return rava_value_null(); } RavaNativeValue_t native_args[RAVA_MAX_METHOD_PARAMS]; for (size_t i = 0; i < arg_count && i < RAVA_MAX_METHOD_PARAMS; i++) { native_args[i] = rava_value_to_native(args[i]); } RavaNativeValue_t result = rava_native_invoke(method, native_args, arg_count); return rava_native_to_value(result); }