#include <stdint.h> #include <assert.h> #include <string.h> #include <stdlib.h> #include <stdio.h> #include <stddef.h> #include <inttypes.h> #include <stdarg.h> #include "spvm_list.h" #include "spvm_hash.h" #include "spvm_compiler.h" #include "spvm_allocator.h" #include "spvm_opcode_array.h" #include "spvm_opcode.h" #include "spvm_class.h" #include "spvm_basic_type.h" #include "spvm_field.h" #include "spvm_method.h" #include "spvm_type.h" #include "spvm_weaken_backref.h" #include "spvm_limit.h" #include "spvm_string_buffer.h" #include "spvm_api.h" #include "spvm_object.h" #include "spvm_native.h" #include "spvm_string.h" #include "spvm_runtime_basic_type.h" #include "spvm_runtime_class.h" #include "spvm_runtime_class_var.h" #include "spvm_runtime_field.h" #include "spvm_runtime_info.h" #include "spvm_runtime_manager.h" #include "spvm_runtime_method.h" #include "spvm_runtime_string.h" #include "spvm_runtime_type.h" SPVM_ENV* SPVM_API_new_env_raw(SPVM_ENV* unused_env) { // The impelements of Native APIs void* env_init[] = { NULL, // class_vars_heap (void*)(intptr_t)sizeof(SPVM_OBJECT), // object_header_byte_size (void*)(intptr_t)offsetof(SPVM_OBJECT, weaken_backref_head), // weaken_backref_head (void*)(intptr_t)offsetof(SPVM_OBJECT, ref_count), // object_ref_count_offset (void*)(intptr_t)offsetof(SPVM_OBJECT, basic_type_id), // object_basic_type_id_offset (void*)(intptr_t)offsetof(SPVM_OBJECT, type_dimension), // object_type_dimension_offset (void*)(intptr_t)offsetof(SPVM_OBJECT, type_category), // object_type_category_offset (void*)(intptr_t)offsetof(SPVM_OBJECT, flag), // object_flag_offset (void*)(intptr_t)offsetof(SPVM_OBJECT, length), // object_length_offset (void*)(intptr_t)SPVM_BASIC_TYPE_C_ID_BYTE_OBJECT, // byte_object_basic_type_id (void*)(intptr_t)SPVM_BASIC_TYPE_C_ID_SHORT_OBJECT, // short_object_basic_type_id (void*)(intptr_t)SPVM_BASIC_TYPE_C_ID_INT_OBJECT, // int_object_basic_type_id (void*)(intptr_t)SPVM_BASIC_TYPE_C_ID_LONG_OBJECT, // long_object_basic_type_id (void*)(intptr_t)SPVM_BASIC_TYPE_C_ID_FLOAT_OBJECT, // float_object_basic_type_id (void*)(intptr_t)SPVM_BASIC_TYPE_C_ID_DOUBLE_OBJECT, // double_object_basic_type_id NULL, // runtime_info NULL, // exception_object NULL, // native_mortal_stack NULL, // native_mortal_stack_top NULL, // native_mortal_stack_capacity SPVM_API_get_basic_type_id, SPVM_API_get_field_id, SPVM_API_get_field_offset, SPVM_API_get_class_var_id, SPVM_API_get_class_method_id, SPVM_API_get_instance_method_id, SPVM_API_new_object_raw, SPVM_API_new_object, SPVM_API_new_byte_array_raw, SPVM_API_new_byte_array, SPVM_API_new_short_array_raw, SPVM_API_new_short_array, SPVM_API_new_int_array_raw, SPVM_API_new_int_array, SPVM_API_new_long_array_raw, SPVM_API_new_long_array, SPVM_API_new_float_array_raw, SPVM_API_new_float_array, SPVM_API_new_double_array_raw, SPVM_API_new_double_array, SPVM_API_new_object_array_raw, SPVM_API_new_object_array, SPVM_API_new_muldim_array_raw, SPVM_API_new_muldim_array, SPVM_API_new_mulnum_array_raw, SPVM_API_new_mulnum_array, SPVM_API_new_string_nolen_raw, SPVM_API_new_string_nolen, SPVM_API_new_string_raw, SPVM_API_new_string, SPVM_API_new_pointer_raw, SPVM_API_new_pointer, SPVM_API_concat_raw, SPVM_API_concat, SPVM_API_new_stack_trace_raw, SPVM_API_new_stack_trace, SPVM_API_length, SPVM_API_get_elems_byte, SPVM_API_get_elems_short, SPVM_API_get_elems_int, SPVM_API_get_elems_long, SPVM_API_get_elems_float, SPVM_API_get_elems_double, SPVM_API_get_elem_object, SPVM_API_set_elem_object, SPVM_API_get_field_byte, SPVM_API_get_field_short, SPVM_API_get_field_int, SPVM_API_get_field_long, SPVM_API_get_field_float, SPVM_API_get_field_double, SPVM_API_get_field_object, SPVM_API_set_field_byte, SPVM_API_set_field_short, SPVM_API_set_field_int, SPVM_API_set_field_long, SPVM_API_set_field_float, SPVM_API_set_field_double, SPVM_API_set_field_object, SPVM_API_get_class_var_byte, SPVM_API_get_class_var_short, SPVM_API_get_class_var_int, SPVM_API_get_class_var_long, SPVM_API_get_class_var_float, SPVM_API_get_class_var_double, SPVM_API_get_class_var_object, SPVM_API_set_class_var_byte, SPVM_API_set_class_var_short, SPVM_API_set_class_var_int, SPVM_API_set_class_var_long, SPVM_API_set_class_var_float, SPVM_API_set_class_var_double, SPVM_API_set_class_var_object, SPVM_API_pointer, SPVM_API_set_pointer, SPVM_API_call_spvm_method, SPVM_API_exception, SPVM_API_set_exception, SPVM_API_ref_count, SPVM_API_inc_ref_count, SPVM_API_dec_ref_count, SPVM_API_enter_scope, SPVM_API_push_mortal, SPVM_API_leave_scope, SPVM_API_remove_mortal, SPVM_API_is_type, SPVM_API_has_callback, SPVM_API_object_basic_type_id, SPVM_API_object_type_dimension, SPVM_API_weaken, SPVM_API_isweak, SPVM_API_unweaken, SPVM_API_alloc_memory_block_zero, SPVM_API_free_memory_block, SPVM_API_get_memory_blocks_count, SPVM_API_get_type_name_raw, SPVM_API_get_type_name, SPVM_API_new_env, SPVM_API_free_env, NULL, // memory_blocks_count SPVM_API_get_chars, SPVM_API_die, SPVM_API_new_object_by_name, SPVM_API_new_pointer_by_name, SPVM_API_set_field_byte_by_name, SPVM_API_set_field_short_by_name, SPVM_API_set_field_int_by_name, SPVM_API_set_field_long_by_name, SPVM_API_set_field_float_by_name, SPVM_API_set_field_double_by_name, SPVM_API_set_field_object_by_name, SPVM_API_get_field_byte_by_name, SPVM_API_get_field_short_by_name, SPVM_API_get_field_int_by_name, SPVM_API_get_field_long_by_name, SPVM_API_get_field_float_by_name, SPVM_API_get_field_double_by_name, SPVM_API_get_field_object_by_name, SPVM_API_set_class_var_byte_by_name, SPVM_API_set_class_var_short_by_name, SPVM_API_set_class_var_int_by_name, SPVM_API_set_class_var_long_by_name, SPVM_API_set_class_var_float_by_name, SPVM_API_set_class_var_double_by_name, SPVM_API_set_class_var_object_by_name, SPVM_API_get_class_var_byte_by_name, SPVM_API_get_class_var_short_by_name, SPVM_API_get_class_var_int_by_name, SPVM_API_get_class_var_long_by_name, SPVM_API_get_class_var_float_by_name, SPVM_API_get_class_var_double_by_name, SPVM_API_get_class_var_object_by_name, SPVM_API_call_class_method_by_name, SPVM_API_call_instance_method_by_name, SPVM_API_get_field_string_chars_by_name, (void*)(intptr_t)SPVM_BASIC_TYPE_C_ID_ANY_OBJECT, // any_object_basic_type_id SPVM_API_dump_raw, SPVM_API_dump, SPVM_API_call_spvm_method, // call_class_method SPVM_API_call_spvm_method, // call_instance_method SPVM_API_get_instance_method_id_static, SPVM_API_get_bool_object_value, (void*)(intptr_t)SPVM_BASIC_TYPE_C_ID_STRING, // string_basic_type_id SPVM_API_make_read_only, SPVM_API_is_read_only, SPVM_API_is_array, SPVM_API_is_string, SPVM_API_is_numeric_array, SPVM_API_is_mulnum_array, SPVM_API_get_elem_byte_size, SPVM_API_new_array_proto_raw, SPVM_API_new_array_proto, SPVM_API_copy_raw, SPVM_API_copy, SPVM_API_shorten, SPVM_API_has_interface, NULL, // no_symbol_cache_flag SPVM_API_set_no_symbol_cache_flag, SPVM_API_get_no_symbol_cache_flag, SPVM_API_print, SPVM_API_print_stderr, SPVM_API_new_env_raw, SPVM_API_free_env_raw, SPVM_API_init_env, SPVM_API_call_init_blocks, SPVM_API_cleanup_global_vars, SPVM_API_compiler_new, SPVM_API_compiler_free, SPVM_API_compiler_set_start_line, SPVM_API_compiler_get_start_line, SPVM_API_compiler_set_start_file, SPVM_API_compiler_get_start_file, SPVM_API_compiler_add_module_dir, SPVM_API_compiler_get_module_dirs_length, SPVM_API_compiler_get_module_dir, SPVM_API_compiler_compile_spvm, SPVM_API_compiler_get_error_messages_length, SPVM_API_compiler_get_error_message, SPVM_API_compiler_get_class_id, SPVM_API_compiler_get_classes_length, SPVM_API_compiler_get_class_name, SPVM_API_compiler_is_anon_class, SPVM_API_compiler_get_methods_length, SPVM_API_compiler_get_method_id, SPVM_API_compiler_get_method_id_by_name, SPVM_API_compiler_get_method_name, SPVM_API_compiler_get_method_signature, SPVM_API_compiler_is_anon_method, SPVM_API_compiler_is_init_block_method, SPVM_API_compiler_is_native_method, SPVM_API_compiler_is_precompile_method, SPVM_API_get_native_method_address, SPVM_API_get_precompile_method_address, SPVM_API_set_native_method_address, SPVM_API_set_precompile_method_address, SPVM_API_is_object_array, SPVM_API_get_method_id_without_signature, SPVM_API_get_constant_string_value, SPVM_API_compiler_build_runtime_info, }; SPVM_ENV* env = calloc(1, sizeof(env_init)); if (env == NULL) { return NULL; } memcpy(env, env_init, sizeof(env_init)); return env; } SPVM_RUNTIME_CLASS* SPVM_API_get_runtime_class_from_basic_type_id(SPVM_ENV* env, int32_t basic_type_id) { SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; SPVM_RUNTIME_CLASS* class = NULL; if (basic_type_id >= 0) { SPVM_RUNTIME_BASIC_TYPE* runtime_basic_type = SPVM_API_get_basic_type(env, basic_type_id); int32_t class_id = runtime_basic_type->class_id; class = SPVM_API_get_class(env, class_id); } return class; } int32_t SPVM_API_init_env(SPVM_ENV* env) { SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; // Mortal stack int32_t native_mortal_stack_capacity = 1; void* native_mortal_stack = calloc(sizeof(SPVM_OBJECT*), native_mortal_stack_capacity); if (native_mortal_stack == NULL) { return 1; } // Initialize Class Variables void* class_vars_heap = calloc(sizeof(SPVM_VALUE), ((int64_t)runtime_info->class_vars_length + 1)); if (class_vars_heap == NULL) { return 2; } env->native_mortal_stack_capacity = (void*)(intptr_t)native_mortal_stack_capacity; env->native_mortal_stack = native_mortal_stack; env->class_vars_heap = class_vars_heap; // Adjust alignment SPVM_VALUE int32_t object_header_byte_size = sizeof(SPVM_OBJECT); if (object_header_byte_size % sizeof(SPVM_VALUE) != 0) { object_header_byte_size += (sizeof(SPVM_VALUE) - object_header_byte_size % sizeof(SPVM_VALUE)); } assert(object_header_byte_size % sizeof(SPVM_VALUE) == 0); // Object header byte size env->object_header_byte_size = (void*)(intptr_t)object_header_byte_size; return 0; } void SPVM_API_make_read_only(SPVM_ENV* env, SPVM_OBJECT* string) { if (string && string->type_category == SPVM_TYPE_C_TYPE_CATEGORY_STRING) { string->flag |= SPVM_OBJECT_C_FLAG_IS_READ_ONLY; } } int32_t SPVM_API_is_read_only(SPVM_ENV* env, SPVM_OBJECT* string) { int32_t is_read_only; if (string) { if (string->flag & SPVM_OBJECT_C_FLAG_IS_READ_ONLY) { is_read_only = 1; } else { is_read_only = 0; } } else { is_read_only = 0; } return is_read_only; } SPVM_OBJECT* SPVM_API_dump(SPVM_ENV* env, SPVM_OBJECT* object) { (void)env; SPVM_OBJECT* str = SPVM_API_dump_raw(env, object); SPVM_API_push_mortal(env, str); return str; } SPVM_OBJECT* SPVM_API_dump_raw(SPVM_ENV* env, SPVM_OBJECT* object) { SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; int32_t depth = 0; SPVM_STRING_BUFFER* string_buffer = SPVM_STRING_BUFFER_new(runtime_info->allocator, 255, SPVM_ALLOCATOR_C_ALLOC_TYPE_TMP); SPVM_HASH* address_symtable = SPVM_HASH_new(runtime_info->allocator, 255, SPVM_ALLOCATOR_C_ALLOC_TYPE_TMP); SPVM_API_dump_recursive(env, object, &depth, string_buffer, address_symtable); int32_t string_buffer_length = string_buffer->length; SPVM_OBJECT* dump = SPVM_API_new_string_raw(env, string_buffer->buffer, string_buffer->length); SPVM_HASH_free(address_symtable); address_symtable = NULL; SPVM_STRING_BUFFER_free(string_buffer); string_buffer = NULL; return dump; } void SPVM_API_dump_recursive(SPVM_ENV* env, SPVM_OBJECT* object, int32_t* depth, SPVM_STRING_BUFFER* string_buffer, SPVM_HASH* address_symtable) { SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; char tmp_buffer[256]; SPVM_OBJECT* dump; if (object == NULL) { SPVM_STRING_BUFFER_add(string_buffer, "undef"); } else { int32_t basic_type_id = object->basic_type_id; int32_t type_dimension = object->type_dimension; SPVM_RUNTIME_BASIC_TYPE* basic_type = SPVM_API_get_basic_type(env, basic_type_id); const char* basic_type_name = SPVM_API_get_basic_type_name(env, basic_type->id); if (SPVM_API_is_string(env, object)) { const char* chars = env->get_chars(env, object); int32_t chars_length = env->length(env, object); SPVM_STRING_BUFFER_add(string_buffer, "\""); SPVM_STRING_BUFFER_add_len(string_buffer, (char*)chars, chars_length); SPVM_STRING_BUFFER_add(string_buffer, "\""); } else if (type_dimension > 0) { int32_t array_length = object->length; int32_t element_type_dimension = type_dimension - 1; SPVM_STRING_BUFFER_add(string_buffer, "[\n"); for (int32_t array_index = 0; array_index < array_length; array_index++) { for (int32_t depth_index = 0; depth_index < *depth + 1; depth_index++) { SPVM_STRING_BUFFER_add(string_buffer, " "); } if (SPVM_API_is_mulnum_array(env, object)) { SPVM_STRING_BUFFER_add(string_buffer, "{\n"); SPVM_RUNTIME_BASIC_TYPE* basic_type = SPVM_API_get_basic_type(env, basic_type_id); SPVM_RUNTIME_CLASS* class = SPVM_API_get_runtime_class_from_basic_type_id(env, basic_type->id); int32_t fields_length = class->field_ids_length; for (int32_t field_index = 0; field_index < fields_length; field_index++) { for (int32_t depth_index = 0; depth_index < *depth + 2; depth_index++) { SPVM_STRING_BUFFER_add(string_buffer, " "); } SPVM_RUNTIME_FIELD* field = SPVM_API_get_runtime_field_from_index(env, class->id, field_index); SPVM_RUNTIME_TYPE* field_type = SPVM_API_get_type(env, field->type_id); int32_t field_basic_type_id = field_type->basic_type_id; const char* field_name = SPVM_API_get_constant_string_value(env, field->name_id, NULL); SPVM_STRING_BUFFER_add(string_buffer, field_name); SPVM_STRING_BUFFER_add(string_buffer, " => "); switch (field_basic_type_id) { case SPVM_BASIC_TYPE_C_ID_BYTE: { int8_t* element = &((int8_t*)((intptr_t)object + env->object_header_byte_size))[array_index * fields_length]; sprintf(tmp_buffer, "%d", element[field_index]); SPVM_STRING_BUFFER_add(string_buffer, (const char*)tmp_buffer); break; } case SPVM_BASIC_TYPE_C_ID_SHORT: { int16_t* element = &((int16_t*)((intptr_t)object + env->object_header_byte_size))[array_index * fields_length]; sprintf(tmp_buffer, "%d", element[field_index]); SPVM_STRING_BUFFER_add(string_buffer, (const char*)tmp_buffer); break; } case SPVM_BASIC_TYPE_C_ID_INT: { int32_t* element = &((int32_t*)((intptr_t)object + env->object_header_byte_size))[array_index * fields_length]; sprintf(tmp_buffer, "%d", element[field_index]); SPVM_STRING_BUFFER_add(string_buffer, (const char*)tmp_buffer); break; } case SPVM_BASIC_TYPE_C_ID_LONG: { int64_t* element = &((int64_t*)((intptr_t)object + env->object_header_byte_size))[array_index * fields_length]; sprintf(tmp_buffer, "%lld", (long long int)element[field_index]); SPVM_STRING_BUFFER_add(string_buffer, (const char*)tmp_buffer); break; } case SPVM_BASIC_TYPE_C_ID_FLOAT: { float* element = &((float*)((intptr_t)object + env->object_header_byte_size))[array_index * fields_length]; sprintf(tmp_buffer, "%g", element[field_index]); SPVM_STRING_BUFFER_add(string_buffer, (const char*)tmp_buffer); break; } case SPVM_BASIC_TYPE_C_ID_DOUBLE: { double* element = &((double*)((intptr_t)object + env->object_header_byte_size))[array_index * fields_length]; sprintf(tmp_buffer, "%g", element[field_index]); SPVM_STRING_BUFFER_add(string_buffer, (const char*)tmp_buffer); break; } } if (field_index == fields_length - 1) { SPVM_STRING_BUFFER_add(string_buffer, "\n"); } else { SPVM_STRING_BUFFER_add(string_buffer, ",\n"); } } SPVM_STRING_BUFFER_add(string_buffer, " }"); } else if (SPVM_API_is_numeric_array(env, object)) { switch (basic_type_id) { case SPVM_BASIC_TYPE_C_ID_BYTE: { int8_t element = ((int8_t*)((intptr_t)object + env->object_header_byte_size))[array_index]; sprintf(tmp_buffer, "%d", element); SPVM_STRING_BUFFER_add(string_buffer, (const char*)tmp_buffer); break; } case SPVM_BASIC_TYPE_C_ID_SHORT: { int16_t element = ((int16_t*)((intptr_t)object + env->object_header_byte_size))[array_index]; sprintf(tmp_buffer, "%d", element); SPVM_STRING_BUFFER_add(string_buffer, (const char*)tmp_buffer); break; } case SPVM_BASIC_TYPE_C_ID_INT: { int32_t element = ((int32_t*)((intptr_t)object + env->object_header_byte_size))[array_index]; sprintf(tmp_buffer, "%d", element); SPVM_STRING_BUFFER_add(string_buffer, (const char*)tmp_buffer); break; } case SPVM_BASIC_TYPE_C_ID_LONG: { int64_t element = ((int64_t*)((intptr_t)object + env->object_header_byte_size))[array_index]; sprintf(tmp_buffer, "%lld", (long long int)element); SPVM_STRING_BUFFER_add(string_buffer, (const char*)tmp_buffer); break; } case SPVM_BASIC_TYPE_C_ID_FLOAT: { float element = ((float*)((intptr_t)object + env->object_header_byte_size))[array_index]; sprintf(tmp_buffer, "%g", element); SPVM_STRING_BUFFER_add(string_buffer, (const char*)tmp_buffer); break; } case SPVM_BASIC_TYPE_C_ID_DOUBLE: { double element = ((double*)((intptr_t)object + env->object_header_byte_size))[array_index]; sprintf(tmp_buffer, "%g", element); SPVM_STRING_BUFFER_add(string_buffer, (const char*)tmp_buffer); break; } } } else if (SPVM_API_is_object_array(env, object)) { SPVM_OBJECT* element = (((SPVM_OBJECT**)((intptr_t)object + env->object_header_byte_size))[array_index]); (*depth)++; SPVM_API_dump_recursive(env, element, depth, string_buffer, address_symtable); (*depth)--; } else { assert(0); } if (array_index == array_length - 1) { SPVM_STRING_BUFFER_add(string_buffer, "\n"); } else { SPVM_STRING_BUFFER_add(string_buffer, ",\n"); } } for (int32_t depth_index = 0; depth_index < *depth; depth_index++) { SPVM_STRING_BUFFER_add(string_buffer, " "); } SPVM_STRING_BUFFER_add(string_buffer, "]"); SPVM_STRING_BUFFER_add(string_buffer, " : "); SPVM_STRING_BUFFER_add(string_buffer, basic_type_name); for (int32_t type_dimension_index = 0; type_dimension_index < type_dimension; type_dimension_index++) { SPVM_STRING_BUFFER_add(string_buffer, "[]"); } sprintf(tmp_buffer, "(%p)", object); SPVM_STRING_BUFFER_add(string_buffer, tmp_buffer); } else { sprintf(tmp_buffer, "%p", object); int32_t exists = (int32_t)(intptr_t)SPVM_HASH_fetch(address_symtable, tmp_buffer, strlen(tmp_buffer)); if (exists) { sprintf(tmp_buffer, "REUSE_OBJECT(%p)", object); SPVM_STRING_BUFFER_add(string_buffer, tmp_buffer); } else { SPVM_HASH_insert(address_symtable, tmp_buffer, strlen(tmp_buffer), (void*)(intptr_t)1); SPVM_RUNTIME_BASIC_TYPE* basic_type = SPVM_API_get_basic_type(env, basic_type_id); SPVM_RUNTIME_CLASS* class = SPVM_API_get_runtime_class_from_basic_type_id(env, basic_type->id); assert(class); SPVM_STRING_BUFFER_add(string_buffer, "{\n"); // Free object fields int32_t fields_length = class->field_ids_length; for (int32_t field_index = 0; field_index < fields_length; field_index++) { for (int32_t depth_index = 0; depth_index < *depth + 1; depth_index++) { SPVM_STRING_BUFFER_add(string_buffer, " "); } SPVM_RUNTIME_FIELD* field = SPVM_API_get_runtime_field_from_index(env, class->id, field_index); SPVM_RUNTIME_TYPE* field_type = SPVM_API_get_type(env, field->type_id); int32_t field_basic_type_id = field_type->basic_type_id; int32_t field_type_dimension = field_type->dimension; int32_t field_offset = field->offset; const char* field_name = SPVM_API_get_constant_string_value(env, field->name_id, NULL); SPVM_STRING_BUFFER_add(string_buffer, field_name); SPVM_STRING_BUFFER_add(string_buffer, " => "); if (field_type_dimension == 0 && field_basic_type_id >= SPVM_BASIC_TYPE_C_ID_BYTE && field_basic_type_id <= SPVM_BASIC_TYPE_C_ID_DOUBLE) { switch (field_basic_type_id) { case SPVM_BASIC_TYPE_C_ID_BYTE: { int8_t field_value = *(int8_t*)((intptr_t)object + (intptr_t)env->object_header_byte_size + field_offset); sprintf(tmp_buffer, "%d", field_value); SPVM_STRING_BUFFER_add(string_buffer, (const char*)tmp_buffer); break; } case SPVM_BASIC_TYPE_C_ID_SHORT: { int16_t field_value = *(int16_t*)((intptr_t)object + (intptr_t)env->object_header_byte_size + field_offset); sprintf(tmp_buffer, "%d", field_value); SPVM_STRING_BUFFER_add(string_buffer, (const char*)tmp_buffer); break; } case SPVM_BASIC_TYPE_C_ID_INT: { int32_t field_value = *(int32_t*)((intptr_t)object + (intptr_t)env->object_header_byte_size + field_offset); sprintf(tmp_buffer, "%d", field_value); SPVM_STRING_BUFFER_add(string_buffer, (const char*)tmp_buffer); break; } case SPVM_BASIC_TYPE_C_ID_LONG: { int64_t field_value = *(int64_t*)((intptr_t)object + (intptr_t)env->object_header_byte_size + field_offset); sprintf(tmp_buffer, "%lld", (long long int)field_value); SPVM_STRING_BUFFER_add(string_buffer, (const char*)tmp_buffer); break; } case SPVM_BASIC_TYPE_C_ID_FLOAT: { float field_value = *(float*)((intptr_t)object + (intptr_t)env->object_header_byte_size + field_offset); sprintf(tmp_buffer, "%g", field_value); SPVM_STRING_BUFFER_add(string_buffer, (const char*)tmp_buffer); break; } case SPVM_BASIC_TYPE_C_ID_DOUBLE: { double field_value = *(double*)((intptr_t)object + (intptr_t)env->object_header_byte_size + field_offset); sprintf(tmp_buffer, "%g", field_value); SPVM_STRING_BUFFER_add(string_buffer, (const char*)tmp_buffer); break; } default : { assert(0); } } } else { SPVM_OBJECT* field_value = *(SPVM_OBJECT**)((intptr_t)object + (intptr_t)env->object_header_byte_size + field_offset); (*depth)++; SPVM_API_dump_recursive(env, field_value, depth, string_buffer, address_symtable); (*depth)--; } if (field_index == fields_length - 1) { SPVM_STRING_BUFFER_add(string_buffer, "\n"); } else { SPVM_STRING_BUFFER_add(string_buffer, ",\n"); } } for (int32_t depth_index = 0; depth_index < *depth; depth_index++) { SPVM_STRING_BUFFER_add(string_buffer, " "); } SPVM_STRING_BUFFER_add(string_buffer, "}"); SPVM_STRING_BUFFER_add(string_buffer, " : "); SPVM_STRING_BUFFER_add(string_buffer, basic_type_name); sprintf(tmp_buffer, "(%p)", object); SPVM_STRING_BUFFER_add(string_buffer, tmp_buffer); } } } } const char* SPVM_API_get_field_string_chars_by_name(SPVM_ENV* env, SPVM_OBJECT* obj, const char* class_name, const char* field_name, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_field_id(env, class_name, field_name, "string"); if (id < 0) { *exception_flag = 1; env->die(env, "field not found, class name:%s, field name:%s, type:string", class_name, field_name, file, line); return NULL; }; SPVM_OBJECT* value = env->get_field_object(env, obj, id); if (value == NULL) { return NULL; } else { const char* chars = env->get_chars(env, value); return chars; } } int32_t SPVM_API_call_class_method_by_name(SPVM_ENV* env, const char* class_name, const char* method_name, const char* signature, SPVM_VALUE* stack, const char* file, int32_t line) { int32_t method_id = env->get_class_method_id(env, class_name, method_name, signature); if (method_id < 0) { env->die(env, "Method not found, class name:%s, sub name:%s, signature:%s", class_name, method_name, signature, file, line); return 1; } int32_t e = env->call_class_method(env, method_id, stack); if (e) { const char* message = env->get_chars(env, env->get_exception(env)); env->die(env, "%s", message, file, line); return e; } return 0; } int32_t SPVM_API_call_instance_method_by_name(SPVM_ENV* env, SPVM_OBJECT* object, const char* method_name, const char* signature, SPVM_VALUE* stack, const char* file, int32_t line) { if (object == NULL) { env->die(env, "Object must not be NULL", file, line); return 1; }; int32_t method_id = env->get_instance_method_id(env, object, method_name, signature); if (method_id < 0) { env->die(env, "Method not found, object:%p, sub name:%s, signature:%s", object, method_name, signature, file, line); return 1; }; int32_t e = env->call_instance_method(env, method_id, stack); if (e) { const char* message = env->get_chars(env, env->get_exception(env)); env->die(env, "%s", message, file, line); return e; } return 0; } void* SPVM_API_new_object_by_name(SPVM_ENV* env, const char* class_name, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_basic_type_id(env, class_name); if (id < 0) { env->die(env, "Class \"%s\" not found", class_name, file, line); *exception_flag = 1; return NULL; }; void* object = env->new_object(env, id); return object; } SPVM_OBJECT* SPVM_API_new_pointer_by_name(SPVM_ENV* env, const char* class_name, void* pointer, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_basic_type_id(env, class_name); if (id < 0) { *exception_flag = 1; env->die(env, "class \"%s\" not found", class_name, file, line); return NULL; }; SPVM_OBJECT* object = env->new_pointer(env, id, pointer); return object; } void SPVM_API_set_field_byte_by_name(SPVM_ENV* env, SPVM_OBJECT* object, const char* class_name, const char* field_name, int8_t value, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_field_id(env, class_name, field_name, "byte"); if (id < 0) { *exception_flag = 1; env->die(env, "field not found, class name:%s, field name:%s, signature:byte", class_name, field_name, file, line); return; } env->set_field_byte(env, object, id, value); } void SPVM_API_set_field_short_by_name(SPVM_ENV* env, SPVM_OBJECT* object, const char* class_name, const char* field_name, int16_t value, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_field_id(env, class_name, field_name, "short"); if (id < 0) { *exception_flag = 1; env->die(env, "field not found, class name:%s, field name:%s, signature:short", class_name, field_name, file, line); return; }; env->set_field_short(env, object, id, value); } void SPVM_API_set_field_int_by_name(SPVM_ENV* env, SPVM_OBJECT* object, const char* class_name, const char* field_name, int32_t value, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_field_id(env, class_name, field_name, "int"); if (id < 0) { *exception_flag = 1; env->die(env, "field not found, class name:%s, field name:%s, signature:int", class_name, field_name, file, line); return; }; env->set_field_int(env, object, id, value); } void SPVM_API_set_field_long_by_name(SPVM_ENV* env, SPVM_OBJECT* object, const char* class_name, const char* field_name, int64_t value, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_field_id(env, class_name, field_name, "long"); if (id < 0) { *exception_flag = 1; env->die(env, "field not found, class name:%s, field name:%s, signature:long", class_name, field_name, file, line); return; }; env->set_field_long(env, object, id, value); } void SPVM_API_set_field_float_by_name(SPVM_ENV* env, SPVM_OBJECT* object, const char* class_name, const char* field_name, float value, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_field_id(env, class_name, field_name, "float"); if (id < 0) { *exception_flag = 1; env->die(env, "field not found, class name:%s, field name:%s, signature:float", class_name, field_name, file, line); return; }; env->set_field_float(env, object, id, value); } void SPVM_API_set_field_double_by_name(SPVM_ENV* env, SPVM_OBJECT* object, const char* class_name, const char* field_name, double value, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_field_id(env, class_name, field_name, "double"); if (id < 0) { *exception_flag = 1; env->die(env, "field not found, class name:%s, field name:%s, signature:double", class_name, field_name, file, line); return; }; env->set_field_double(env, object, id, value); } void SPVM_API_set_field_object_by_name(SPVM_ENV* env, SPVM_OBJECT* object, const char* class_name, const char* field_name, const char* signature, SPVM_OBJECT* value, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_field_id(env, class_name, field_name, signature); if (id < 0) { *exception_flag = 1; env->die(env, "field not found, class name:%s, field name:%s, signature:%s", class_name, field_name, signature, file, line); return; }; env->set_field_object(env, object, id, value); } int8_t SPVM_API_get_field_byte_by_name(SPVM_ENV* env, SPVM_OBJECT* object, const char* class_name, const char* field_name, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_field_id(env, class_name, field_name, "byte"); if (id < 0) { *exception_flag = 1; env->die(env, "field not found, class name:%s, field name:%s, signature:byte", class_name, field_name, file, line); return 0; }; int8_t value = env->get_field_byte(env, object, id); return value; } int16_t SPVM_API_get_field_short_by_name(SPVM_ENV* env, SPVM_OBJECT* object, const char* class_name, const char* field_name, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_field_id(env, class_name, field_name, "short"); if (id < 0) { *exception_flag = 1; env->die(env, "field not found, class name:%s, field name:%s, signature:short", class_name, field_name, file, line); return 0; }; int16_t value = env->get_field_short(env, object, id); return value; } int32_t SPVM_API_get_field_int_by_name(SPVM_ENV* env, SPVM_OBJECT* object, const char* class_name, const char* field_name, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_field_id(env, class_name, field_name, "int"); if (id < 0) { *exception_flag = 1; env->die(env, "field not found, class name:%s, field name:%s, signature:int", class_name, field_name, file, line); return 0; }; int32_t value = env->get_field_int(env, object, id); return value; } int64_t SPVM_API_get_field_long_by_name(SPVM_ENV* env, SPVM_OBJECT* object, const char* class_name, const char* field_name, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_field_id(env, class_name, field_name, "long"); if (id < 0) { *exception_flag = 1; env->die(env, "field not found, class name:%s, field name:%s, signature:long", class_name, field_name, file, line); return 0; }; int64_t value = env->get_field_long(env, object, id); return value; } float SPVM_API_get_field_float_by_name(SPVM_ENV* env, SPVM_OBJECT* object, const char* class_name, const char* field_name, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_field_id(env, class_name, field_name, "float"); if (id < 0) { *exception_flag = 1; env->die(env, "field not found, class name:%s, field name:%s, signature:float", class_name, field_name, file, line); return 0; }; float value = env->get_field_float(env, object, id); return value; } double SPVM_API_get_field_double_by_name(SPVM_ENV* env, SPVM_OBJECT* object, const char* class_name, const char* field_name, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_field_id(env, class_name, field_name, "double"); if (id < 0) { *exception_flag = 1; env->die(env, "field not found, class name:%s, field name:%s, signature:double", class_name, field_name, file, line); return 0; }; double value = env->get_field_double(env, object, id); return value; } SPVM_OBJECT* SPVM_API_get_field_object_by_name(SPVM_ENV* env, SPVM_OBJECT* object, const char* class_name, const char* field_name, const char* signature, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_field_id(env, class_name, field_name, signature); if (id < 0) { *exception_flag = 1; env->die(env, "field not found, class name:%s, field name:%s, signature:%s", class_name, field_name, signature, file, line); return NULL; }; SPVM_OBJECT* value = env->get_field_object(env, object, id); return value; } void SPVM_API_set_class_var_byte_by_name(SPVM_ENV* env, const char* class_name, const char* class_var_name, int8_t value, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_class_var_id(env, class_name, class_var_name, "byte"); if (id < 0) { *exception_flag = 1; env->die(env, "Class variable not defined. Class name:%s, Variable name:%s, Type:byte", class_name, class_var_name, file, line); return; }; env->set_class_var_byte(env, id, value); } void SPVM_API_set_class_var_short_by_name(SPVM_ENV* env, const char* class_name, const char* class_var_name, int16_t value, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_class_var_id(env, class_name, class_var_name, "short"); if (id < 0) { *exception_flag = 1; env->die(env, "Class variable not defined. Class name:%s, Variable name:%s, Type:byte", class_name, class_var_name, file, line); return; }; env->set_class_var_short(env, id, value); } void SPVM_API_set_class_var_int_by_name(SPVM_ENV* env, const char* class_name, const char* class_var_name, int32_t value, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_class_var_id(env, class_name, class_var_name, "int"); if (id < 0) { *exception_flag = 1; env->die(env, "Class variable not defined. Class name:%s, Variable name:%s, Type:byte", class_name, class_var_name, file, line); return; }; env->set_class_var_int(env, id, value); } void SPVM_API_set_class_var_long_by_name(SPVM_ENV* env, const char* class_name, const char* class_var_name, int64_t value, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_class_var_id(env, class_name, class_var_name, "long"); if (id < 0) { *exception_flag = 1; env->die(env, "Class variable not defined. Class name:%s, Variable name:%s, Type:long", class_name, class_var_name, file, line); return; }; env->set_class_var_long(env, id, value); } void SPVM_API_set_class_var_float_by_name(SPVM_ENV* env, const char* class_name, const char* class_var_name, float value, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_class_var_id(env, class_name, class_var_name, "float"); if (id < 0) { *exception_flag = 1; env->die(env, "Class variable not defined. Class name:%s, Variable name:%s, Type:float", class_name, class_var_name, file, line); return; }; env->set_class_var_float(env, id, value); } void SPVM_API_set_class_var_double_by_name(SPVM_ENV* env, const char* class_name, const char* class_var_name, double value, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_class_var_id(env, class_name, class_var_name, "double"); if (id < 0) { *exception_flag = 1; env->die(env, "Class variable not defined. Class name:%s, Variable name:%s, Type:double", class_name, class_var_name, file, line); return; }; env->set_class_var_double(env, id, value); } void SPVM_API_set_class_var_object_by_name(SPVM_ENV* env, const char* class_name, const char* class_var_name, const char* type_signature, SPVM_OBJECT* value, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_class_var_id(env, class_name, class_var_name, type_signature); if (id < 0) { *exception_flag = 1; env->die(env, "Class variable not defined. Class name:%s, Variable name:%s, Type:%s", class_name, class_var_name, type_signature, file, line); return; }; env->set_class_var_object(env, id, value); } int8_t SPVM_API_get_class_var_byte_by_name(SPVM_ENV* env, const char* class_name, const char* class_var_name, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_class_var_id(env, class_name, class_var_name, "byte"); if (id < 0) { *exception_flag = 1; env->die(env, "Class variable not defined. Class name:%s, Variable name:%s, Type:byte", class_name, class_var_name, file, line); return 0; }; int8_t value = env->get_class_var_byte(env, id); return value; } int16_t SPVM_API_get_class_var_short_by_name(SPVM_ENV* env, const char* class_name, const char* class_var_name, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_class_var_id(env, class_name, class_var_name, "short"); if (id < 0) { *exception_flag = 1; env->die(env, "Class variable not defined. Class name:%s, Variable name:%s, Type:short", class_name, class_var_name, file, line); return 0; }; int16_t value = env->get_class_var_short(env, id); return value; } int32_t SPVM_API_get_class_var_int_by_name(SPVM_ENV* env, const char* class_name, const char* class_var_name, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_class_var_id(env, class_name, class_var_name, "int"); if (id < 0) { *exception_flag = 1; env->die(env, "Class variable not defined. Class name:%s, Variable name:%s, Type:int", class_name, class_var_name, file, line); return 0; }; int32_t value = env->get_class_var_int(env, id); return value; } int64_t SPVM_API_get_class_var_long_by_name(SPVM_ENV* env, const char* class_name, const char* class_var_name, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_class_var_id(env, class_name, class_var_name, "long"); if (id < 0) { *exception_flag = 1; env->die(env, "Class variable not defined. Class name:%s, Variable name:%s, Type:long", class_name, class_var_name, file, line); return 0; }; int64_t value = env->get_class_var_long(env, id); return value; } float SPVM_API_get_class_var_float_by_name(SPVM_ENV* env, const char* class_name, const char* class_var_name, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_class_var_id(env, class_name, class_var_name, "float"); if (id < 0) { *exception_flag = 1; env->die(env, "Class variable not defined. Class name:%s, Variable name:%s, Type:float", class_name, class_var_name, file, line); return 0; }; float value = env->get_class_var_float(env, id); return value; } double SPVM_API_get_class_var_double_by_name(SPVM_ENV* env, const char* class_name, const char* class_var_name, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_class_var_id(env, class_name, class_var_name, "double"); if (id < 0) { *exception_flag = 1; env->die(env, "Class variable not defined. Class name:%s, Variable name:%s, Type:double", class_name, class_var_name, file, line); return 0; }; double value = env->get_class_var_double(env, id); return value; } SPVM_OBJECT* SPVM_API_get_class_var_object_by_name(SPVM_ENV* env, const char* class_name, const char* class_var_name, const char* type_signature, int32_t* exception_flag, const char* file, int32_t line) { *exception_flag = 0; int32_t id = env->get_class_var_id(env, class_name, class_var_name, type_signature); if (id < 0) { *exception_flag = 1; env->die(env, "Class variable not defined. Class name:%s, Variable name:%s, Type:%s", class_name, class_var_name, type_signature, file, line); return NULL; }; SPVM_OBJECT* value = env->get_class_var_object(env, id); return value; } int32_t SPVM_API_die(SPVM_ENV* env, const char* message, ...) { va_list args; char* message_with_line = (char*)env->alloc_memory_block_zero(env, 512); int32_t message_length = strlen(message); if (message_length > 255) { message_length = 255; } memcpy(message_with_line, message, message_length); const char* file_line = " at %s line %d"; memcpy(message_with_line + message_length, file_line, strlen(file_line)); char* buffer = (char*)env->alloc_memory_block_zero(env, 512); va_start(args, message); vsnprintf(buffer, 511, message_with_line, args); va_end(args); void* exception = env->new_string_raw(env, buffer, strlen(buffer)); env->free_memory_block(env, message_with_line); message_with_line = NULL; env->free_memory_block(env, buffer); buffer = NULL; env->set_exception(env, exception); return 1; } int32_t SPVM_API_remove_mortal(SPVM_ENV* env, int32_t original_mortal_stack_top, SPVM_OBJECT* remove_object) { (void)env; int32_t remove_count = 0; if (remove_object != NULL) { int32_t match_mortal_stack_index = -1; for (int32_t mortal_stack_index = original_mortal_stack_top; mortal_stack_index < (intptr_t)env->native_mortal_stack_top; mortal_stack_index++) { SPVM_OBJECT* object = ((SPVM_OBJECT**)(env->native_mortal_stack))[mortal_stack_index]; if (remove_object == object) { remove_count++; match_mortal_stack_index = mortal_stack_index; SPVM_API_dec_ref_count(env, object); } } if (remove_count) { for (int32_t mortal_stack_index = match_mortal_stack_index; mortal_stack_index < (intptr_t)env->native_mortal_stack_top; mortal_stack_index++) { ((SPVM_OBJECT**)(env->native_mortal_stack))[mortal_stack_index] = ((SPVM_OBJECT**)(env->native_mortal_stack))[mortal_stack_index + 1]; } env->native_mortal_stack_top = (void*)((intptr_t)env->native_mortal_stack_top - remove_count); } } return remove_count; } void SPVM_API_cleanup_global_vars(SPVM_ENV* env) { // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; // Free exception SPVM_API_set_exception(env, NULL); // Free objects of class variables for (int32_t class_var_id = 0; class_var_id < runtime_info->class_vars_length; class_var_id++) { SPVM_RUNTIME_CLASS_VAR* class_var = SPVM_API_get_class_var(env, class_var_id); SPVM_RUNTIME_TYPE* class_var_type = SPVM_API_get_type(env, class_var->type_id); int32_t class_var_type_category = class_var_type->category; switch (class_var_type_category) { case SPVM_TYPE_C_TYPE_CATEGORY_ANY_OBJECT: case SPVM_TYPE_C_TYPE_CATEGORY_CLASS: case SPVM_TYPE_C_TYPE_CATEGORY_NUMERIC_ARRAY: case SPVM_TYPE_C_TYPE_CATEGORY_MULNUM_ARRAY: case SPVM_TYPE_C_TYPE_CATEGORY_OBJECT_ARRAY: case SPVM_TYPE_C_TYPE_CATEGORY_STRING: { SPVM_OBJECT* object = *(void**)&((SPVM_VALUE*)env->class_vars_heap)[class_var_id]; if (object) { SPVM_API_dec_ref_count(env, object); } } } } } void SPVM_API_free_env_raw(SPVM_ENV* env) { // Free class variables heap if (env->class_vars_heap != NULL) { free(env->class_vars_heap); env->class_vars_heap = NULL; } // Free mortal stack if (env->native_mortal_stack != NULL) { free(env->native_mortal_stack); env->native_mortal_stack = NULL; } // Free env free(env); env = NULL; } int32_t SPVM_API_call_spvm_method(SPVM_ENV* env, int32_t method_id, SPVM_VALUE* stack) { (void)env; // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; // Method SPVM_RUNTIME_METHOD* method = SPVM_API_get_method(env, method_id); int32_t exception_flag; // Call native method if (method->flag & SPVM_METHOD_C_FLAG_NATIVE) { // Enter scope int32_t original_mortal_stack_top = SPVM_API_enter_scope(env); // Call native subrotuine int32_t (*native_address)(SPVM_ENV*, SPVM_VALUE*) = runtime_info->method_native_addresses[method->id]; assert(native_address != NULL); exception_flag = (*native_address)(env, stack); // Increment ref count of return value if (!exception_flag) { SPVM_RUNTIME_TYPE* method_return_type = SPVM_API_get_type(env, method->return_type_id); switch (method_return_type->category) { case SPVM_TYPE_C_TYPE_CATEGORY_ANY_OBJECT: case SPVM_TYPE_C_TYPE_CATEGORY_CLASS: case SPVM_TYPE_C_TYPE_CATEGORY_NUMERIC_ARRAY: case SPVM_TYPE_C_TYPE_CATEGORY_MULNUM_ARRAY: case SPVM_TYPE_C_TYPE_CATEGORY_OBJECT_ARRAY: case SPVM_TYPE_C_TYPE_CATEGORY_STRING: { if (*(void**)&stack[0] != NULL) { SPVM_API_INC_REF_COUNT_ONLY(*(void**)&stack[0]); } } } } // Leave scope SPVM_API_leave_scope(env, original_mortal_stack_top); // Decrement ref count of return value if (!exception_flag) { SPVM_RUNTIME_TYPE* method_return_type = SPVM_API_get_type(env, method->return_type_id); switch (method_return_type->category) { case SPVM_TYPE_C_TYPE_CATEGORY_ANY_OBJECT: case SPVM_TYPE_C_TYPE_CATEGORY_CLASS: case SPVM_TYPE_C_TYPE_CATEGORY_NUMERIC_ARRAY: case SPVM_TYPE_C_TYPE_CATEGORY_MULNUM_ARRAY: case SPVM_TYPE_C_TYPE_CATEGORY_OBJECT_ARRAY: case SPVM_TYPE_C_TYPE_CATEGORY_STRING: { if (*(void**)&stack[0] != NULL) { SPVM_API_DEC_REF_COUNT_ONLY(*(void**)&stack[0]); } } } } // Set default exception message if (exception_flag && env->exception_object == NULL) { void* exception = env->new_string_nolen_raw(env, "Error"); env->set_exception(env, exception); } } else { // Call precompiled method void* method_precompile_address = runtime_info->method_precompile_addresses[method->id]; if (method_precompile_address) { int32_t (*precompile_address)(SPVM_ENV*, SPVM_VALUE*) = method_precompile_address; exception_flag = (*precompile_address)(env, stack); } // Call sub virtual machine else { exception_flag = SPVM_API_call_spvm_method_vm(env, method_id, stack); } } return exception_flag; } int32_t SPVM_API_call_spvm_method_vm(SPVM_ENV* env, int32_t method_id, SPVM_VALUE* stack) { (void)env; // Opcode relative index register int32_t opcode_rel_index = 0; // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; // Runtime method SPVM_RUNTIME_METHOD* method = SPVM_API_get_method(env, method_id); // Runtime class SPVM_RUNTIME_CLASS* class = SPVM_API_get_class(env, method->class_id); // Operation codes SPVM_OPCODE* opcodes = runtime_info->opcodes; // Exception flag int32_t exception_flag = 0; // Operation code base int32_t method_opcodes_base = method->opcodes_base; // Call method argument stack top int32_t stack_index = 0; // Mortal stack uint16_t* mortal_stack = NULL; int32_t mortal_stack_top = 0; // object variables void** object_vars = NULL; // ref variables void** ref_vars = NULL; // double variables double* double_vars = NULL; // float variables float* float_vars = NULL; // long variables int64_t* long_vars = NULL; // int variables int32_t* int_vars = NULL; // short variables int16_t* short_vars = NULL; // byte variables int8_t* byte_vars = NULL; // Alloc variable memory // Allignment is 8. This is numeric type max byte size // Order 8, 4, 2, 1 numeric variable, and addrress variables char* call_stack = NULL; { // Numeric area byte size int32_t numeric_vars_byte_size = 0; numeric_vars_byte_size += method->call_stack_long_vars_legnth * 8; numeric_vars_byte_size += method->call_stack_double_vars_legnth * 8; numeric_vars_byte_size += method->call_stack_int_vars_legnth * 4; numeric_vars_byte_size += method->call_stack_float_vars_legnth * 4; numeric_vars_byte_size += method->call_stack_short_vars_legnth * 2; numeric_vars_byte_size += method->mortal_stack_length * 2; numeric_vars_byte_size += method->call_stack_byte_vars_legnth * 1; if (numeric_vars_byte_size % 8 != 0) { numeric_vars_byte_size += (8 - (numeric_vars_byte_size % 8)); } // Address area byte size int32_t address_vars_byte_size = 0; address_vars_byte_size += method->call_stack_object_vars_legnth * sizeof(void*); address_vars_byte_size += method->call_stack_ref_vars_legnth * sizeof(void*); // Total area byte size int32_t total_vars_byte_size = numeric_vars_byte_size + address_vars_byte_size; call_stack = SPVM_API_alloc_memory_block_zero(env, total_vars_byte_size + 1); if (call_stack == NULL) { void* exception = env->new_string_nolen_raw(env, "Can't alloc call stack memory"); env->set_exception(env, exception); exception_flag = 1; return exception_flag; } int32_t call_stack_offset = 0; // Double variables double_vars = (double*)&call_stack[call_stack_offset]; call_stack_offset += method->call_stack_double_vars_legnth * 8; // Long varialbes long_vars = (int64_t*)&call_stack[call_stack_offset]; call_stack_offset += method->call_stack_long_vars_legnth * 8; // Float variables float_vars = (float*)&call_stack[call_stack_offset]; call_stack_offset += method->call_stack_float_vars_legnth * 4; // Int variables int_vars = (int32_t*)&call_stack[call_stack_offset]; call_stack_offset += method->call_stack_int_vars_legnth * 4; // Short variables short_vars = (int16_t*)&call_stack[call_stack_offset]; call_stack_offset += method->call_stack_short_vars_legnth * 2; // Mortal stack mortal_stack = (uint16_t*)&call_stack[call_stack_offset]; call_stack_offset += method->mortal_stack_length * 2; // Byte variables byte_vars = (int8_t*)&call_stack[call_stack_offset]; call_stack_offset += method->call_stack_byte_vars_legnth * 1; call_stack_offset = numeric_vars_byte_size; // Object variables object_vars = (void**)&call_stack[call_stack_offset]; call_stack_offset += method->call_stack_object_vars_legnth * sizeof(void*); // Refernce variables ref_vars = (void**)&call_stack[call_stack_offset]; call_stack_offset += method->call_stack_ref_vars_legnth * sizeof(void*); } // Buffer for string convertion // double need 17 digit // int64_t need 21 gidit (-9223372036854775808 + (null character)) char tmp_buffer[256]; int32_t object_header_byte_size = (intptr_t)env->object_header_byte_size; // Execute operation codes while (1) { SPVM_OPCODE* opcode = &(opcodes[method_opcodes_base + opcode_rel_index]); int32_t opcode_id = opcode->id; switch (opcode_id) { case SPVM_OPCODE_C_ID_GET_ARG_BYTE: { byte_vars[opcode->operand1] = *(int8_t*)&stack[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_GET_ARG_SHORT: { short_vars[opcode->operand1] = *(int16_t*)&stack[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_GET_ARG_INT: { int_vars[opcode->operand1] = *(int32_t*)&stack[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_GET_ARG_LONG: { long_vars[opcode->operand1] = *(int64_t*)&stack[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_GET_ARG_FLOAT: { float_vars[opcode->operand1] = *(float*)&stack[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_GET_ARG_DOUBLE: { double_vars[opcode->operand1] = *(double*)&stack[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_GET_ARG_OBJECT: { object_vars[opcode->operand1] = *(void**)&stack[opcode->operand2]; void* object = *(void**)&object_vars[opcode->operand1]; if (object != NULL) { SPVM_API_INC_REF_COUNT_ONLY(object); } break; } case SPVM_OPCODE_C_ID_GET_ARG_REF: { ref_vars[opcode->operand1] = *(void**)&stack[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_GET_ARG_MULNUM_BYTE: { int32_t type_width = opcode->operand3; for (int32_t field_index = 0; field_index < type_width; field_index++) { byte_vars[opcode->operand1 + field_index] = *(int8_t*)&stack[opcode->operand2 + field_index]; } break; } case SPVM_OPCODE_C_ID_GET_ARG_MULNUM_SHORT: { int32_t type_width = opcode->operand3; for (int32_t field_index = 0; field_index < type_width; field_index++) { short_vars[opcode->operand1 + field_index] = *(int16_t*)&stack[opcode->operand2 + field_index]; } break; } case SPVM_OPCODE_C_ID_GET_ARG_MULNUM_INT: { int32_t type_width = opcode->operand3; for (int32_t field_index = 0; field_index < type_width; field_index++) { int_vars[opcode->operand1 + field_index] = *(int32_t*)&stack[opcode->operand2 + field_index]; } break; } case SPVM_OPCODE_C_ID_GET_ARG_MULNUM_LONG: { int32_t type_width = opcode->operand3; for (int32_t field_index = 0; field_index < type_width; field_index++) { long_vars[opcode->operand1 + field_index] = *(int64_t*)&stack[opcode->operand2 + field_index]; } break; } case SPVM_OPCODE_C_ID_GET_ARG_MULNUM_FLOAT: { int32_t type_width = opcode->operand3; for (int32_t field_index = 0; field_index < type_width; field_index++) { float_vars[opcode->operand1 + field_index] = *(float*)&stack[opcode->operand2 + field_index]; } break; } case SPVM_OPCODE_C_ID_GET_ARG_MULNUM_DOUBLE: { int32_t type_width = opcode->operand3; for (int32_t field_index = 0; field_index < type_width; field_index++) { double_vars[opcode->operand1 + field_index] = *(double*)&stack[opcode->operand2 + field_index]; } break; } case SPVM_OPCODE_C_ID_BOOL_INT: { int_vars[0] = int_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_BOOL_LONG: { int_vars[0] = !!long_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_BOOL_FLOAT: { int_vars[0] = !!float_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_BOOL_DOUBLE: { int_vars[0] = !!double_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_BOOL_BOOL_OBJECT: { int_vars[0] = !!env->get_bool_object_value(env, *(void**)&object_vars[opcode->operand1]); break; } case SPVM_OPCODE_C_ID_BOOL_OBJECT: { int_vars[0] = !!*(void**)&object_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_IS_UNDEF: { int_vars[0] = *(void**)&object_vars[opcode->operand1] == NULL; break; } case SPVM_OPCODE_C_ID_IS_NOT_UNDEF: { int_vars[0] = *(void**)&object_vars[opcode->operand1] != NULL; break; } case SPVM_OPCODE_C_ID_EQ_INT: { int_vars[0] = int_vars[opcode->operand1] == int_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_EQ_LONG: { int_vars[0] = long_vars[opcode->operand1] == long_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_EQ_FLOAT: { int_vars[0] = float_vars[opcode->operand1] == float_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_EQ_DOUBLE: { int_vars[0] = double_vars[opcode->operand1] == double_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_EQ_OBJECT: { int_vars[0] = *(void**)&object_vars[opcode->operand1] == *(void**)&object_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_NE_INT: { int_vars[0] = int_vars[opcode->operand1] != int_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_NE_LONG: { int_vars[0] = long_vars[opcode->operand1] != long_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_NE_FLOAT: { int_vars[0] = float_vars[opcode->operand1] != float_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_NE_DOUBLE: { int_vars[0] = double_vars[opcode->operand1] != double_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_NE_OBJECT: { int_vars[0] = *(void**)&object_vars[opcode->operand1] != *(void**)&object_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_GT_INT: { int_vars[0] = int_vars[opcode->operand1] > int_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_GT_LONG: { int_vars[0] = long_vars[opcode->operand1] > long_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_GT_FLOAT: { int_vars[0] = float_vars[opcode->operand1] > float_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_GT_DOUBLE: { int_vars[0] = double_vars[opcode->operand1] > double_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_GE_INT: { int_vars[0] = int_vars[opcode->operand1] >= int_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_GE_LONG: { int_vars[0] = long_vars[opcode->operand1] >= long_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_GE_FLOAT: { int_vars[0] = float_vars[opcode->operand1] >= float_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_GE_DOUBLE: { int_vars[0] = double_vars[opcode->operand1] >= double_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_LT_INT: { int_vars[0] = int_vars[opcode->operand1] < int_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_LT_LONG: { int_vars[0] = long_vars[opcode->operand1] < long_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_LT_FLOAT: { int_vars[0] = float_vars[opcode->operand1] < float_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_LT_DOUBLE: { int_vars[0] = double_vars[opcode->operand1] < double_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_LE_INT: { int_vars[0] = int_vars[opcode->operand1] <= int_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_LE_LONG: { int_vars[0] = long_vars[opcode->operand1] <= long_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_LE_FLOAT: { int_vars[0] = float_vars[opcode->operand1] <= float_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_LE_DOUBLE: { int_vars[0] = double_vars[opcode->operand1] <= double_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_CMP_INT: { int_vars[0] = int_vars[opcode->operand1] > int_vars[opcode->operand2] ? 1 : int_vars[opcode->operand1] < int_vars[opcode->operand2] ? -1 : 0; break; } case SPVM_OPCODE_C_ID_CMP_LONG: { int_vars[0] = long_vars[opcode->operand1] > long_vars[opcode->operand2] ? 1 : long_vars[opcode->operand1] < long_vars[opcode->operand2] ? -1 : 0; break; } case SPVM_OPCODE_C_ID_CMP_FLOAT: { int_vars[0] = float_vars[opcode->operand1] > float_vars[opcode->operand2] ? 1 : float_vars[opcode->operand1] < float_vars[opcode->operand2] ? -1 : 0; break; } case SPVM_OPCODE_C_ID_CMP_DOUBLE: { int_vars[0] = double_vars[opcode->operand1] > double_vars[opcode->operand2] ? 1 : double_vars[opcode->operand1] < double_vars[opcode->operand2] ? -1 : 0; break; } case SPVM_OPCODE_C_ID_IS_TYPE: { void* object = *(void**)&object_vars[opcode->operand1]; int32_t check_basic_type_id = opcode->operand2; int32_t check_type_dimension = opcode->operand3; if (object) { int_vars[0] = env->is_type(env, object, check_basic_type_id, check_type_dimension); } else { int_vars[0] = 0; } break; } case SPVM_OPCODE_C_ID_HAS_CALLBACK: { void* object = *(void**)&object_vars[opcode->operand1]; int32_t callback_basic_type_id = opcode->operand2; if (object) { int_vars[0] = env->has_callback(env, object, callback_basic_type_id); } else { int_vars[0] = 0; } break; } case SPVM_OPCODE_C_ID_HAS_INTERFACE: { void* object = *(void**)&object_vars[opcode->operand1]; int32_t callback_basic_type_id = opcode->operand2; if (object) { int_vars[0] = env->has_interface(env, object, callback_basic_type_id); } else { int_vars[0] = 0; } break; } case SPVM_OPCODE_C_ID_STRING_EQ: case SPVM_OPCODE_C_ID_STRING_NE: case SPVM_OPCODE_C_ID_STRING_GT: case SPVM_OPCODE_C_ID_STRING_GE: case SPVM_OPCODE_C_ID_STRING_LT: case SPVM_OPCODE_C_ID_STRING_LE: case SPVM_OPCODE_C_ID_STRING_CMP: { void* object1 = *(void**)&object_vars[opcode->operand1]; void* object2 = *(void**)&object_vars[opcode->operand2]; if (object1 == NULL && object2 == NULL) { switch (opcode_id) { case SPVM_OPCODE_C_ID_STRING_EQ: { int_vars[0] = 1; break; } case SPVM_OPCODE_C_ID_STRING_NE: { int_vars[0] = 0; break; } case SPVM_OPCODE_C_ID_STRING_GT: { int_vars[0] = 0; break; } case SPVM_OPCODE_C_ID_STRING_GE: { int_vars[0] = 1; break; } case SPVM_OPCODE_C_ID_STRING_LT: { int_vars[0] = 0; break; } case SPVM_OPCODE_C_ID_STRING_LE: { int_vars[0] = 1; break; } case SPVM_OPCODE_C_ID_STRING_CMP: { int_vars[0] = 0; break; } } } else if (object1 != NULL && object2 == NULL) { switch (opcode_id) { case SPVM_OPCODE_C_ID_STRING_EQ: { int_vars[0] = 0; break; } case SPVM_OPCODE_C_ID_STRING_NE: { int_vars[0] = 1; break; } case SPVM_OPCODE_C_ID_STRING_GT: { int_vars[0] = 1; break; } case SPVM_OPCODE_C_ID_STRING_GE: { int_vars[0] = 1; break; } case SPVM_OPCODE_C_ID_STRING_LT: { int_vars[0] = 0; break; } case SPVM_OPCODE_C_ID_STRING_LE: { int_vars[0] = 0; break; } case SPVM_OPCODE_C_ID_STRING_CMP: { int_vars[0] = 1; break; } } } else if (object1 == NULL && object2 != NULL) { switch (opcode_id) { case SPVM_OPCODE_C_ID_STRING_EQ: { int_vars[0] = 0; break; } case SPVM_OPCODE_C_ID_STRING_NE: { int_vars[0] = 1; break; } case SPVM_OPCODE_C_ID_STRING_GT: { int_vars[0] = 0; break; } case SPVM_OPCODE_C_ID_STRING_GE: { int_vars[0] = 0; break; } case SPVM_OPCODE_C_ID_STRING_LT: { int_vars[0] = 1; break; } case SPVM_OPCODE_C_ID_STRING_LE: { int_vars[0] = 1; break; } case SPVM_OPCODE_C_ID_STRING_CMP: { int_vars[0] = -1; break; } } } else { int32_t length1 = *(int32_t*)((intptr_t)object1 + (intptr_t)env->object_length_offset); int32_t length2 = *(int32_t*)((intptr_t)object2 + (intptr_t)env->object_length_offset); const char* bytes1 = env->get_chars(env, object1); const char* bytes2 = env->get_chars(env, object2); int32_t short_string_length = length1 < length2 ? length1 : length2; int32_t retval = memcmp(bytes1, bytes2, short_string_length); int32_t cmp; if (retval) { cmp = retval < 0 ? -1 : 1; } else if (length1 == length2) { cmp = 0; } else { cmp = length1 < length2 ? -1 : 1; } switch (opcode_id) { case SPVM_OPCODE_C_ID_STRING_EQ: { int_vars[0] = (cmp == 0); break; } case SPVM_OPCODE_C_ID_STRING_NE: { int_vars[0] = (cmp != 0); break; } case SPVM_OPCODE_C_ID_STRING_GT: { int_vars[0] = (cmp == 1); break; } case SPVM_OPCODE_C_ID_STRING_GE: { int_vars[0] = (cmp >= 0); break; } case SPVM_OPCODE_C_ID_STRING_LT: { int_vars[0] = (cmp == -1); break; } case SPVM_OPCODE_C_ID_STRING_LE: { int_vars[0] = (cmp <= 0); break; } case SPVM_OPCODE_C_ID_STRING_CMP: { int_vars[0] = cmp; break; } } } break; } case SPVM_OPCODE_C_ID_ADD_INT: { int_vars[opcode->operand0] = int_vars[opcode->operand1] + int_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_ADD_LONG: { long_vars[opcode->operand0] = long_vars[opcode->operand1] + long_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_ADD_FLOAT: { float_vars[opcode->operand0] = float_vars[opcode->operand1] + float_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_ADD_DOUBLE: { double_vars[opcode->operand0] = double_vars[opcode->operand1] + double_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_SUBTRACT_INT: { int_vars[opcode->operand0] = int_vars[opcode->operand1] - int_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_SUBTRACT_LONG: { long_vars[opcode->operand0] = long_vars[opcode->operand1] - long_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_SUBTRACT_FLOAT: { float_vars[opcode->operand0] = float_vars[opcode->operand1] - float_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_SUBTRACT_DOUBLE: { double_vars[opcode->operand0] = double_vars[opcode->operand1] - double_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_MULTIPLY_INT: { int_vars[opcode->operand0] = int_vars[opcode->operand1] * int_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_MULTIPLY_LONG: { long_vars[opcode->operand0] = long_vars[opcode->operand1] * long_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_MULTIPLY_FLOAT: { float_vars[opcode->operand0] = float_vars[opcode->operand1] * float_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_MULTIPLY_DOUBLE: { double_vars[opcode->operand0] = double_vars[opcode->operand1] * double_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_DIVIDE_INT: { if (__builtin_expect(int_vars[opcode->operand2] == 0, 0)) { void* exception = env->new_string_nolen_raw(env, "0 division"); env->set_exception(env, exception); exception_flag = 1; } else { int_vars[opcode->operand0] = int_vars[opcode->operand1] / int_vars[opcode->operand2]; } break; } case SPVM_OPCODE_C_ID_DIVIDE_LONG: { if (__builtin_expect(long_vars[opcode->operand2] == 0, 0)) { void* exception = env->new_string_nolen_raw(env, "0 division"); env->set_exception(env, exception); exception_flag = 1; } else { long_vars[opcode->operand0] = long_vars[opcode->operand1] / long_vars[opcode->operand2]; } break; } case SPVM_OPCODE_C_ID_DIVIDE_FLOAT: { float_vars[opcode->operand0] = float_vars[opcode->operand1] / float_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_DIVIDE_DOUBLE: { double_vars[opcode->operand0] = double_vars[opcode->operand1] / double_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_DIVIDE_UNSIGNED_INT: { if (__builtin_expect(int_vars[opcode->operand2] == 0, 0)) { void* exception = env->new_string_nolen_raw(env, "0 division"); env->set_exception(env, exception); exception_flag = 1; } else { int_vars[opcode->operand0] = (uint32_t)int_vars[opcode->operand1] / (uint32_t)int_vars[opcode->operand2]; } break; } case SPVM_OPCODE_C_ID_DIVIDE_UNSIGNED_LONG: { if (__builtin_expect(long_vars[opcode->operand2] == 0, 0)) { void* exception = env->new_string_nolen_raw(env, "0 division"); env->set_exception(env, exception); exception_flag = 1; } else { long_vars[opcode->operand0] = (uint64_t)long_vars[opcode->operand1] / (uint64_t)long_vars[opcode->operand2]; } break; } case SPVM_OPCODE_C_ID_REMAINDER_INT: { if (__builtin_expect(int_vars[opcode->operand2] == 0, 0)) { void* exception = env->new_string_nolen_raw(env, "0 division"); env->set_exception(env, exception); exception_flag = 1; } else { int_vars[opcode->operand0] = int_vars[opcode->operand1] % int_vars[opcode->operand2]; } break; } case SPVM_OPCODE_C_ID_REMAINDER_LONG: { if (__builtin_expect(long_vars[opcode->operand2] == 0, 0)) { void* exception = env->new_string_nolen_raw(env, "0 division"); env->set_exception(env, exception); exception_flag = 1; } else { long_vars[opcode->operand0] = long_vars[opcode->operand1] % long_vars[opcode->operand2]; } break; } case SPVM_OPCODE_C_ID_REMAINDER_UNSIGNED_INT: { if (__builtin_expect(int_vars[opcode->operand2] == 0, 0)) { void* exception = env->new_string_nolen_raw(env, "0 division"); env->set_exception(env, exception); exception_flag = 1; } else { int_vars[opcode->operand0] = (uint32_t)int_vars[opcode->operand1] % (uint32_t)int_vars[opcode->operand2]; } break; } case SPVM_OPCODE_C_ID_REMAINDER_UNSIGNED_LONG: { if (__builtin_expect(long_vars[opcode->operand2] == 0, 0)) { void* exception = env->new_string_nolen_raw(env, "0 division"); env->set_exception(env, exception); exception_flag = 1; } else { long_vars[opcode->operand0] = (uint64_t)long_vars[opcode->operand1] % (uint64_t)long_vars[opcode->operand2]; } break; } case SPVM_OPCODE_C_ID_LEFT_SHIFT_INT: { int_vars[opcode->operand0] = int_vars[opcode->operand1] << int_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_LEFT_SHIFT_LONG: { long_vars[opcode->operand0] = long_vars[opcode->operand1] << int_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_RIGHT_ARITHMETIC_SHIFT_INT: { int_vars[opcode->operand0] = int_vars[opcode->operand1] >> int_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_RIGHT_ARITHMETIC_SHIFT_LONG: { long_vars[opcode->operand0] = long_vars[opcode->operand1] >> int_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_RIGHT_LOGICAL_SHIFT_INT: { int_vars[opcode->operand0] = (int32_t)((uint32_t)int_vars[opcode->operand1] >> int_vars[opcode->operand2]); break; } case SPVM_OPCODE_C_ID_RIGHT_LOGICAL_SHIFT_LONG: { long_vars[opcode->operand0] = (int64_t)((uint64_t)long_vars[opcode->operand1] >> int_vars[opcode->operand2]); break; } case SPVM_OPCODE_C_ID_BIT_AND_INT: { int_vars[opcode->operand0] = int_vars[opcode->operand1] & int_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_BIT_AND_LONG: { long_vars[opcode->operand0] = long_vars[opcode->operand1] & long_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_BIT_OR_INT: { int_vars[opcode->operand0] = int_vars[opcode->operand1] | int_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_BIT_OR_LONG: { long_vars[opcode->operand0] = long_vars[opcode->operand1] | long_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_BIT_XOR_INT: { int_vars[opcode->operand0] = int_vars[opcode->operand1] ^ int_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_BIT_XOR_LONG: { long_vars[opcode->operand0] = long_vars[opcode->operand1] ^ long_vars[opcode->operand2]; break; } case SPVM_OPCODE_C_ID_NEGATE_INT: { int_vars[opcode->operand0] = -int_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_NEGATE_LONG: { long_vars[opcode->operand0] = -long_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_NEGATE_FLOAT: { float_vars[opcode->operand0] = -float_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_NEGATE_DOUBLE: { double_vars[opcode->operand0] = -double_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_BIT_NOT_INT: { int_vars[opcode->operand0] = ~int_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_BIT_NOT_LONG: { long_vars[opcode->operand0] = ~long_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_INT_TO_LONG: { long_vars[opcode->operand0] = (int64_t)int_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_INT_TO_FLOAT: { float_vars[opcode->operand0] = (float)int_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_INT_TO_DOUBLE: { double_vars[opcode->operand0] = (double)int_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_LONG_TO_INT: { int_vars[opcode->operand0] = (int32_t)long_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_LONG_TO_FLOAT: { float_vars[opcode->operand0] = (float)long_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_LONG_TO_DOUBLE: { double_vars[opcode->operand0] = (double)long_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_FLOAT_TO_INT: { int_vars[opcode->operand0] = (int32_t)float_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_FLOAT_TO_LONG: { long_vars[opcode->operand0] = (int64_t)float_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_FLOAT_TO_DOUBLE: { double_vars[opcode->operand0] = (double)float_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_DOUBLE_TO_INT: { int_vars[opcode->operand0] = (int32_t)double_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_DOUBLE_TO_LONG: { long_vars[opcode->operand0] = (int64_t)double_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_DOUBLE_TO_FLOAT: { float_vars[opcode->operand0] = (float)double_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_INT_TO_BYTE: { byte_vars[opcode->operand0] = (int8_t)(int_vars[opcode->operand1]); break; } case SPVM_OPCODE_C_ID_CONVERT_INT_TO_SHORT: { short_vars[opcode->operand0] = (int16_t)(int_vars[opcode->operand1]); break; } case SPVM_OPCODE_C_ID_CONVERT_BYTE_TO_INT: { int_vars[opcode->operand0] = (int32_t)byte_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_SHORT_TO_INT: { int_vars[opcode->operand0] = (int32_t)short_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_BYTE_TO_LONG: { long_vars[opcode->operand0] = (int64_t)byte_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_BYTE_TO_FLOAT: { float_vars[opcode->operand0] = (float)byte_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_BYTE_TO_DOUBLE: { double_vars[opcode->operand0] = (double)byte_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_SHORT_TO_BYTE: { byte_vars[opcode->operand0] = (int8_t)short_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_SHORT_TO_LONG: { long_vars[opcode->operand0] = (int64_t)short_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_SHORT_TO_FLOAT: { float_vars[opcode->operand0] = (float)short_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_SHORT_TO_DOUBLE: { double_vars[opcode->operand0] = (double)short_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_LONG_TO_BYTE: { byte_vars[opcode->operand0] = (int8_t)long_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_LONG_TO_SHORT: { short_vars[opcode->operand0] = (int16_t)long_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_FLOAT_TO_BYTE: { byte_vars[opcode->operand0] = (int8_t)float_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_FLOAT_TO_SHORT: { short_vars[opcode->operand0] = (int16_t)float_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_DOUBLE_TO_BYTE: { byte_vars[opcode->operand0] = (int8_t)double_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_DOUBLE_TO_SHORT: { short_vars[opcode->operand0] = (int16_t)double_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_BYTE_TO_SHORT: { short_vars[opcode->operand0] = (int16_t)byte_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_CONVERT_BYTE_TO_STRING: { sprintf(tmp_buffer, "%" PRId8, byte_vars[opcode->operand1]); int32_t string_length = strlen(tmp_buffer); void* string = env->new_string_raw(env, tmp_buffer, string_length); SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], string); break; } case SPVM_OPCODE_C_ID_CONVERT_STRING_TO_BYTE_ARRAY: { void* src_string = object_vars[opcode->operand1]; int32_t src_string_length = env->length(env, src_string); const char* src_string_data = env->get_chars(env, src_string); void* byte_array = env->new_byte_array_raw(env, src_string_length); int8_t* byte_array_data = env->get_elems_byte(env, byte_array); memcpy(byte_array_data, src_string_data, src_string_length); SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], byte_array); break; } case SPVM_OPCODE_C_ID_CONVERT_BYTE_ARRAY_TO_STRING: { void* src_byte_array = object_vars[opcode->operand1]; int32_t src_byte_array_length = env->length(env, src_byte_array); int8_t* src_byte_array_data = env->get_elems_byte(env, src_byte_array); void* string = env->new_string_raw(env, (const char*)src_byte_array_data, src_byte_array_length); SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], string); break; } case SPVM_OPCODE_C_ID_CONVERT_SHORT_TO_STRING: { sprintf(tmp_buffer, "%" PRId16, short_vars[opcode->operand1]); int32_t string_length = strlen(tmp_buffer); void* string = env->new_string_raw(env, tmp_buffer, string_length); SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], string); break; } case SPVM_OPCODE_C_ID_CONVERT_INT_TO_STRING: { sprintf(tmp_buffer, "%" PRId32, int_vars[opcode->operand1]); int32_t string_length = strlen(tmp_buffer); void* string = env->new_string_raw(env, tmp_buffer, string_length); SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], string); break; } case SPVM_OPCODE_C_ID_CONVERT_LONG_TO_STRING: { sprintf(tmp_buffer, "%" PRId64, long_vars[opcode->operand1]); int32_t string_length = strlen(tmp_buffer); void* string = env->new_string_raw(env, tmp_buffer, string_length); SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], string); break; } case SPVM_OPCODE_C_ID_CONVERT_FLOAT_TO_STRING: { sprintf(tmp_buffer, "%g", float_vars[opcode->operand1]); int32_t string_length = strlen(tmp_buffer); void* string = env->new_string_raw(env, tmp_buffer, string_length); SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], string); break; } case SPVM_OPCODE_C_ID_CONVERT_DOUBLE_TO_STRING: { sprintf(tmp_buffer, "%g", double_vars[opcode->operand1]); int32_t string_length = strlen(tmp_buffer); void* string = env->new_string_raw(env, tmp_buffer, string_length); SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], string); break; } case SPVM_OPCODE_C_ID_INIT_BYTE: byte_vars[opcode->operand0] = 0; break; case SPVM_OPCODE_C_ID_INIT_SHORT: short_vars[opcode->operand0] = 0; break; case SPVM_OPCODE_C_ID_INIT_INT: int_vars[opcode->operand0] = 0; break; case SPVM_OPCODE_C_ID_INIT_LONG: { long_vars[opcode->operand0] = 0; break; } case SPVM_OPCODE_C_ID_INIT_FLOAT: { float_vars[opcode->operand0] = 0; break; } case SPVM_OPCODE_C_ID_INIT_DOUBLE: { double_vars[opcode->operand0] = 0; break; } case SPVM_OPCODE_C_ID_INIT_UNDEF: SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], NULL); break; case SPVM_OPCODE_C_ID_INIT_MULNUM_BYTE: { int32_t fields_length = opcode->operand2; for (int32_t field_index = 0; field_index < fields_length; field_index++) { byte_vars[opcode->operand0 + field_index] = 0; } break; } case SPVM_OPCODE_C_ID_INIT_MULNUM_SHORT: { int32_t fields_length = opcode->operand2; for (int32_t field_index = 0; field_index < fields_length; field_index++) { short_vars[opcode->operand0 + field_index] = 0; } break; } case SPVM_OPCODE_C_ID_INIT_MULNUM_INT: { int32_t fields_length = opcode->operand2; for (int32_t field_index = 0; field_index < fields_length; field_index++) { int_vars[opcode->operand0 + field_index] = 0; } break; } case SPVM_OPCODE_C_ID_INIT_MULNUM_LONG: { int32_t fields_length = opcode->operand2; for (int32_t field_index = 0; field_index < fields_length; field_index++) { long_vars[opcode->operand0 + field_index] = 0; } break; } case SPVM_OPCODE_C_ID_INIT_MULNUM_FLOAT: { int32_t fields_length = opcode->operand2; for (int32_t field_index = 0; field_index < fields_length; field_index++) { float_vars[opcode->operand0 + field_index] = 0; } break; } case SPVM_OPCODE_C_ID_INIT_MULNUM_DOUBLE: { int32_t fields_length = opcode->operand2; for (int32_t field_index = 0; field_index < fields_length; field_index++) { double_vars[opcode->operand0 + field_index] = 0; } break; } case SPVM_OPCODE_C_ID_MOVE_CONSTANT_BYTE: byte_vars[opcode->operand0] = (int8_t)(uint8_t)opcode->operand1; break; case SPVM_OPCODE_C_ID_MOVE_CONSTANT_INT: int_vars[opcode->operand0] = (int32_t)opcode->operand1; break; case SPVM_OPCODE_C_ID_MOVE_CONSTANT_LONG: { long_vars[opcode->operand0] = *(int64_t*)&opcode->operand1; break; } case SPVM_OPCODE_C_ID_MOVE_CONSTANT_FLOAT: { SPVM_VALUE value; value.ival = (int32_t)opcode->operand1; float_vars[opcode->operand0] = value.fval; break; } case SPVM_OPCODE_C_ID_MOVE_CONSTANT_DOUBLE: { double_vars[opcode->operand0] = *(double*)&opcode->operand1; break; } case SPVM_OPCODE_C_ID_ARRAY_FETCH_BYTE: { void* array = *(void**)&object_vars[opcode->operand1]; int32_t index = int_vars[opcode->operand2]; if (__builtin_expect(array == NULL, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { byte_vars[opcode->operand0] = ((int8_t*)((intptr_t)array + object_header_byte_size))[index]; } } break; } case SPVM_OPCODE_C_ID_ARRAY_FETCH_SHORT: { void* array = *(void**)&object_vars[opcode->operand1]; int32_t index = int_vars[opcode->operand2]; if (__builtin_expect(!array, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { short_vars[opcode->operand0] = ((int16_t*)((intptr_t)array + object_header_byte_size))[index]; } } break; } case SPVM_OPCODE_C_ID_ARRAY_FETCH_INT: { void* array = *(void**)&object_vars[opcode->operand1]; int32_t index = int_vars[opcode->operand2]; if (__builtin_expect(!array, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { int_vars[opcode->operand0] = ((int32_t*)((intptr_t)array + object_header_byte_size))[index]; } } break; } case SPVM_OPCODE_C_ID_ARRAY_FETCH_LONG: { void* array = *(void**)&object_vars[opcode->operand1]; int32_t index = int_vars[opcode->operand2]; if (__builtin_expect(!array, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { long_vars[opcode->operand0] = ((int64_t*)((intptr_t)array + object_header_byte_size))[index]; } } break; } case SPVM_OPCODE_C_ID_ARRAY_FETCH_FLOAT: { void* array = *(void**)&object_vars[opcode->operand1]; int32_t index = int_vars[opcode->operand2]; if (__builtin_expect(!array, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { float_vars[opcode->operand0] = ((float*)((intptr_t)array + object_header_byte_size))[index]; } } break; } case SPVM_OPCODE_C_ID_ARRAY_FETCH_DOUBLE: { void* array = *(void**)&object_vars[opcode->operand1]; int32_t index = int_vars[opcode->operand2]; if (__builtin_expect(!array, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { double_vars[opcode->operand0] = ((double*)((intptr_t)array + object_header_byte_size))[index]; } } break; } case SPVM_OPCODE_C_ID_ARRAY_FETCH_OBJECT: { void* array = *(void**)&object_vars[opcode->operand1]; int32_t index = int_vars[opcode->operand2]; if (__builtin_expect(!array, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { void* object = ((void**)((intptr_t)array + object_header_byte_size))[index]; SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], object); } } break; } case SPVM_OPCODE_C_ID_ARRAY_STORE_BYTE: { void* array = *(void**)&object_vars[opcode->operand0]; int32_t index = int_vars[opcode->operand1]; if (__builtin_expect(!array, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { ((int8_t*)((intptr_t)array + object_header_byte_size))[index] = byte_vars[opcode->operand2]; } } break; } case SPVM_OPCODE_C_ID_ARRAY_STORE_SHORT: { void* array = *(void**)&object_vars[opcode->operand0]; int32_t index = int_vars[opcode->operand1]; if (__builtin_expect(!array, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { ((int16_t*)((intptr_t)array + object_header_byte_size))[index] = short_vars[opcode->operand2]; } } break; } case SPVM_OPCODE_C_ID_ARRAY_STORE_INT: { void* array = *(void**)&object_vars[opcode->operand0]; int32_t index = int_vars[opcode->operand1]; if (__builtin_expect(!array, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { ((int32_t*)((intptr_t)array + object_header_byte_size))[index] = int_vars[opcode->operand2]; } } break; } case SPVM_OPCODE_C_ID_ARRAY_STORE_LONG: { void* array = *(void**)&object_vars[opcode->operand0]; int32_t index = int_vars[opcode->operand1]; if (__builtin_expect(!array, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { ((int64_t*)((intptr_t)array + object_header_byte_size))[index] = long_vars[opcode->operand2]; } } break; } case SPVM_OPCODE_C_ID_ARRAY_STORE_FLOAT: { void* array = *(void**)&object_vars[opcode->operand0]; int32_t index = int_vars[opcode->operand1]; if (__builtin_expect(!array, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { ((float*)((intptr_t)array + object_header_byte_size))[index] = float_vars[opcode->operand2]; } } break; } case SPVM_OPCODE_C_ID_ARRAY_STORE_DOUBLE: { void* array = *(void**)&object_vars[opcode->operand0]; int32_t index = int_vars[opcode->operand1]; if (__builtin_expect(!array, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { ((double*)((intptr_t)array + object_header_byte_size))[index] = double_vars[opcode->operand2]; } } break; } case SPVM_OPCODE_C_ID_ARRAY_STORE_OBJECT: { void* array = *(void**)&object_vars[opcode->operand0]; int32_t index = int_vars[opcode->operand1]; if (__builtin_expect(!array, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { void** element_address = &((void**)((intptr_t)array + object_header_byte_size))[index]; SPVM_API_OBJECT_ASSIGN(element_address, *(void**)&object_vars[opcode->operand2]); } } break; } case SPVM_OPCODE_C_ID_ARRAY_STORE_OBJECT_CHECK_TYPE: { void* array = *(void**)&object_vars[opcode->operand0]; int32_t index = int_vars[opcode->operand1]; if (__builtin_expect(!array, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { void** element_address = &((void**)((intptr_t)array + object_header_byte_size))[index]; void* object = *(void**)&object_vars[opcode->operand2]; int32_t is_valid; if (object == NULL) { is_valid = 1; } else { int32_t array_basic_type_id = *(int32_t*)((intptr_t)array + (intptr_t)env->object_basic_type_id_offset); int32_t array_type_dimension = *(uint8_t*)((intptr_t)array + (intptr_t)env->object_type_dimension_offset); int32_t element_basic_type_id = *(int32_t*)((intptr_t)object + (intptr_t)env->object_basic_type_id_offset); int32_t element_type_dimension = *(uint8_t*)((intptr_t)object + (intptr_t)env->object_type_dimension_offset); if (array_basic_type_id == element_basic_type_id && array_type_dimension == element_type_dimension + 1) { is_valid = 1; } else if (array_basic_type_id == (intptr_t)env->any_object_basic_type_id && array_type_dimension == element_type_dimension + 1) { is_valid = 1; } else { is_valid = 0; } } if (is_valid) { SPVM_API_OBJECT_ASSIGN(element_address, object); } else { void* exception = env->new_string_nolen_raw(env, "Assigned element type is invalid"); env->set_exception(env, exception); exception_flag = 1; } } } break; } case SPVM_OPCODE_C_ID_ARRAY_STORE_UNDEF: { void* array = *(void**)&object_vars[opcode->operand0]; int32_t index = int_vars[opcode->operand1]; if (__builtin_expect(!array, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { void* object_address = &((void**)((intptr_t)array + object_header_byte_size))[index]; SPVM_API_OBJECT_ASSIGN(object_address, NULL); } } break; } case SPVM_OPCODE_C_ID_MULNUM_ARRAY_FETCH_BYTE: { void* array = *(void**)&object_vars[opcode->operand1]; int32_t index = int_vars[opcode->operand2]; int32_t fields_length = opcode->operand3; if (__builtin_expect(array == NULL, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { int32_t field_index; for (field_index = 0; field_index < fields_length; field_index++) { byte_vars[opcode->operand0 + field_index] = ((int8_t*)((intptr_t)array + object_header_byte_size))[fields_length * index + field_index]; } } } break; } case SPVM_OPCODE_C_ID_MULNUM_ARRAY_FETCH_SHORT: { void* array = *(void**)&object_vars[opcode->operand1]; int32_t index = int_vars[opcode->operand2]; int32_t fields_length = opcode->operand3; if (__builtin_expect(array == NULL, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { for (int32_t field_index = 0; field_index < fields_length; field_index++) { short_vars[opcode->operand0 + field_index] = ((int16_t*)((intptr_t)array + object_header_byte_size))[fields_length * index + field_index]; } } } break; } case SPVM_OPCODE_C_ID_MULNUM_ARRAY_FETCH_INT: { void* array = *(void**)&object_vars[opcode->operand1]; int32_t index = int_vars[opcode->operand2]; int32_t fields_length = opcode->operand3; if (__builtin_expect(array == NULL, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { for (int32_t field_index = 0; field_index < fields_length; field_index++) { int_vars[opcode->operand0 + field_index] = ((int32_t*)((intptr_t)array + object_header_byte_size))[fields_length * index + field_index]; } } } break; } case SPVM_OPCODE_C_ID_MULNUM_ARRAY_FETCH_LONG: { void* array = *(void**)&object_vars[opcode->operand1]; int32_t index = int_vars[opcode->operand2]; int32_t fields_length = opcode->operand3; if (__builtin_expect(array == NULL, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { int32_t field_index; for (field_index = 0; field_index < fields_length; field_index++) { long_vars[opcode->operand0 + field_index] = ((int64_t*)((intptr_t)array + object_header_byte_size))[fields_length * index + field_index]; } } } break; } case SPVM_OPCODE_C_ID_MULNUM_ARRAY_FETCH_FLOAT: { void* array = *(void**)&object_vars[opcode->operand1]; int32_t index = int_vars[opcode->operand2]; int32_t fields_length = opcode->operand3; if (__builtin_expect(array == NULL, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { int32_t field_index; for (field_index = 0; field_index < fields_length; field_index++) { float_vars[opcode->operand0 + field_index] = ((float*)((intptr_t)array + object_header_byte_size))[fields_length * index + field_index]; } } } break; } case SPVM_OPCODE_C_ID_MULNUM_ARRAY_FETCH_DOUBLE: { void* array = *(void**)&object_vars[opcode->operand1]; int32_t index = int_vars[opcode->operand2]; int32_t fields_length = opcode->operand3; if (__builtin_expect(array == NULL, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { int32_t field_index; for (field_index = 0; field_index < fields_length; field_index++) { double_vars[opcode->operand0 + field_index] = ((double*)((intptr_t)array + object_header_byte_size))[fields_length * index + field_index]; } } } break; } case SPVM_OPCODE_C_ID_MULNUM_ARRAY_FIELD_FETCH_BYTE: { void* array = *(void**)&object_vars[opcode->operand1]; int32_t index = int_vars[opcode->operand2]; int32_t fields_length = (opcode->operand3 & 0xFF) + 1; int32_t field_index = opcode->operand3 >> 8; if (__builtin_expect(array == NULL, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { byte_vars[opcode->operand0] = ((int8_t*)((intptr_t)array + object_header_byte_size))[fields_length * index + field_index]; } } break; } case SPVM_OPCODE_C_ID_MULNUM_ARRAY_FIELD_FETCH_SHORT: { void* array = *(void**)&object_vars[opcode->operand1]; int32_t index = int_vars[opcode->operand2]; int32_t fields_length = (opcode->operand3 & 0xFF) + 1; int32_t field_index = opcode->operand3 >> 8; if (__builtin_expect(array == NULL, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { short_vars[opcode->operand0] = ((int16_t*)((intptr_t)array + object_header_byte_size))[fields_length * index + field_index]; } } break; } case SPVM_OPCODE_C_ID_MULNUM_ARRAY_FIELD_FETCH_INT: { void* array = *(void**)&object_vars[opcode->operand1]; int32_t index = int_vars[opcode->operand2]; int32_t fields_length = (opcode->operand3 & 0xFF) + 1; int32_t field_index = opcode->operand3 >> 8; if (__builtin_expect(array == NULL, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { int_vars[opcode->operand0] = ((int32_t*)((intptr_t)array + object_header_byte_size))[fields_length * index + field_index]; } } break; } case SPVM_OPCODE_C_ID_MULNUM_ARRAY_FIELD_FETCH_LONG: { void* array = *(void**)&object_vars[opcode->operand1]; int32_t index = int_vars[opcode->operand2]; int32_t fields_length = (opcode->operand3 & 0xFF) + 1; int32_t field_index = opcode->operand3 >> 8; if (__builtin_expect(array == NULL, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { long_vars[opcode->operand0] = ((int64_t*)((intptr_t)array + object_header_byte_size))[fields_length * index + field_index]; } } break; } case SPVM_OPCODE_C_ID_MULNUM_ARRAY_FIELD_FETCH_FLOAT: { void* array = *(void**)&object_vars[opcode->operand1]; int32_t index = int_vars[opcode->operand2]; int32_t fields_length = (opcode->operand3 & 0xFF) + 1; int32_t field_index = opcode->operand3 >> 8; if (__builtin_expect(array == NULL, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { float_vars[opcode->operand0] = ((float*)((intptr_t)array + object_header_byte_size))[fields_length * index + field_index]; } } break; } case SPVM_OPCODE_C_ID_MULNUM_ARRAY_FIELD_FETCH_DOUBLE: { void* array = *(void**)&object_vars[opcode->operand1]; int32_t index = int_vars[opcode->operand2]; int32_t fields_length = (opcode->operand3 & 0xFF) + 1; int32_t field_index = opcode->operand3 >> 8; if (__builtin_expect(array == NULL, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { double_vars[opcode->operand0] = ((double*)((intptr_t)array + object_header_byte_size))[fields_length * index + field_index]; } } break; } case SPVM_OPCODE_C_ID_MULNUM_ARRAY_STORE_BYTE: { void* array = *(void**)&object_vars[opcode->operand0]; int32_t index = int_vars[opcode->operand1]; int32_t fields_length = opcode->operand3; if (__builtin_expect(!array, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { int32_t field_index; for (field_index = 0; field_index < fields_length; field_index++) { ((int8_t*)((intptr_t)array + object_header_byte_size))[fields_length * index + field_index] = byte_vars[opcode->operand2 + field_index]; } } } break; } case SPVM_OPCODE_C_ID_MULNUM_ARRAY_STORE_SHORT: { void* array = *(void**)&object_vars[opcode->operand0]; int32_t index = int_vars[opcode->operand1]; int32_t fields_length = opcode->operand3; if (__builtin_expect(!array, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { int32_t field_index; for (field_index = 0; field_index < fields_length; field_index++) { ((int16_t*)((intptr_t)array + object_header_byte_size))[fields_length * index + field_index] = short_vars[opcode->operand2 + field_index]; } } } break; } case SPVM_OPCODE_C_ID_MULNUM_ARRAY_STORE_INT: { void* array = *(void**)&object_vars[opcode->operand0]; int32_t index = int_vars[opcode->operand1]; int32_t fields_length = opcode->operand3; if (__builtin_expect(!array, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { int32_t field_index; for (field_index = 0; field_index < fields_length; field_index++) { ((int32_t*)((intptr_t)array + object_header_byte_size))[fields_length * index + field_index] = int_vars[opcode->operand2 + field_index]; } } } break; } case SPVM_OPCODE_C_ID_MULNUM_ARRAY_STORE_LONG: { void* array = *(void**)&object_vars[opcode->operand0]; int32_t index = int_vars[opcode->operand1]; int32_t fields_length = opcode->operand3; if (__builtin_expect(!array, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { int32_t field_index; for (field_index = 0; field_index < fields_length; field_index++) { ((int64_t*)((intptr_t)array + object_header_byte_size))[fields_length * index + field_index] = long_vars[opcode->operand2 + field_index]; } } } break; } case SPVM_OPCODE_C_ID_MULNUM_ARRAY_STORE_FLOAT: { void* array = *(void**)&object_vars[opcode->operand0]; int32_t index = int_vars[opcode->operand1]; int32_t fields_length = opcode->operand3; if (__builtin_expect(!array, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { int32_t field_index; for (field_index = 0; field_index < fields_length; field_index++) { ((float*)((intptr_t)array + object_header_byte_size))[fields_length * index + field_index] = float_vars[opcode->operand2 + field_index]; } } } break; } case SPVM_OPCODE_C_ID_MULNUM_ARRAY_STORE_DOUBLE: { void* array = *(void**)&object_vars[opcode->operand0]; int32_t index = int_vars[opcode->operand1]; int32_t fields_length = opcode->operand3; if (__builtin_expect(!array, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { int32_t field_index; for (field_index = 0; field_index < fields_length; field_index++) { ((double*)((intptr_t)array + object_header_byte_size))[fields_length * index + field_index] = double_vars[opcode->operand2 + field_index]; } } } break; } case SPVM_OPCODE_C_ID_MULNUM_ARRAY_FIELD_STORE_BYTE: { void* array = *(void**)&object_vars[opcode->operand0]; int32_t index = int_vars[opcode->operand1]; int32_t fields_length = (opcode->operand3 & 0xFF) + 1; int32_t field_index = opcode->operand3 >> 8; if (__builtin_expect(!array, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { ((int8_t*)((intptr_t)array + object_header_byte_size))[fields_length * index + field_index] = byte_vars[opcode->operand2]; } } break; } case SPVM_OPCODE_C_ID_MULNUM_ARRAY_FIELD_STORE_SHORT: { void* array = *(void**)&object_vars[opcode->operand0]; int32_t index = int_vars[opcode->operand1]; int32_t fields_length = (opcode->operand3 & 0xFF) + 1; int32_t field_index = opcode->operand3 >> 8; if (__builtin_expect(!array, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { ((int16_t*)((intptr_t)array + object_header_byte_size))[fields_length * index + field_index] = short_vars[opcode->operand2]; } } break; } case SPVM_OPCODE_C_ID_MULNUM_ARRAY_FIELD_STORE_INT: { void* array = *(void**)&object_vars[opcode->operand0]; int32_t index = int_vars[opcode->operand1]; int32_t fields_length = (opcode->operand3 & 0xFF) + 1; int32_t field_index = opcode->operand3 >> 8; if (__builtin_expect(!array, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { ((int32_t*)((intptr_t)array + object_header_byte_size))[fields_length * index + field_index] = int_vars[opcode->operand2]; } } break; } case SPVM_OPCODE_C_ID_MULNUM_ARRAY_FIELD_STORE_LONG: { void* array = *(void**)&object_vars[opcode->operand0]; int32_t index = int_vars[opcode->operand1]; int32_t fields_length = (opcode->operand3 & 0xFF) + 1; int32_t field_index = opcode->operand3 >> 8; if (__builtin_expect(!array, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { ((int64_t*)((intptr_t)array + object_header_byte_size))[fields_length * index + field_index] = long_vars[opcode->operand2]; } } break; } case SPVM_OPCODE_C_ID_MULNUM_ARRAY_FIELD_STORE_FLOAT: { void* array = *(void**)&object_vars[opcode->operand0]; int32_t index = int_vars[opcode->operand1]; int32_t fields_length = (opcode->operand3 & 0xFF) + 1; int32_t field_index = opcode->operand3 >> 8; if (__builtin_expect(!array, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { ((float*)((intptr_t)array + object_header_byte_size))[fields_length * index + field_index] = float_vars[opcode->operand2]; } } break; } case SPVM_OPCODE_C_ID_MULNUM_ARRAY_FIELD_STORE_DOUBLE: { void* array = *(void**)&object_vars[opcode->operand0]; int32_t index = int_vars[opcode->operand1]; int32_t fields_length = (opcode->operand3 & 0xFF) + 1; int32_t field_index = opcode->operand3 >> 8; if (__builtin_expect(!array, 0)) { void* exception = env->new_string_nolen_raw(env, "Array must not be undef"); env->set_exception(env, exception); exception_flag = 1; } else { if (__builtin_expect(index < 0 || index >= *(int32_t*)((intptr_t)array + (intptr_t)env->object_length_offset), 0)) { void* exception = env->new_string_nolen_raw(env, "Index is out of range"); env->set_exception(env, exception); exception_flag = 1; } else { ((double*)((intptr_t)array + object_header_byte_size))[fields_length * index + field_index] = double_vars[opcode->operand2]; } } break; } case SPVM_OPCODE_C_ID_MULNUM_DEREF_BYTE: { int8_t* value_ref = *(int8_t**)&ref_vars[opcode->operand1]; int32_t fields_length = opcode->operand3; for (int32_t field_index = 0; field_index < fields_length; field_index++) { byte_vars[opcode->operand0 + field_index] = value_ref[field_index]; } break; } case SPVM_OPCODE_C_ID_MULNUM_DEREF_SHORT: { int16_t* value_ref = *(int16_t**)&ref_vars[opcode->operand1]; int32_t fields_length = opcode->operand3; for (int32_t field_index = 0; field_index < fields_length; field_index++) { short_vars[opcode->operand0 + field_index] = value_ref[field_index]; } break; } case SPVM_OPCODE_C_ID_MULNUM_DEREF_INT: { int32_t* value_ref = *(int32_t**)&ref_vars[opcode->operand1]; int32_t fields_length = opcode->operand3; for (int32_t field_index = 0; field_index < fields_length; field_index++) { int_vars[opcode->operand0 + field_index] = value_ref[field_index]; } break; } case SPVM_OPCODE_C_ID_MULNUM_DEREF_LONG: { int64_t* value_ref = *(int64_t**)&ref_vars[opcode->operand1]; int32_t fields_length = opcode->operand3; for (int32_t field_index = 0; field_index < fields_length; field_index++) { long_vars[opcode->operand0 + field_index] = value_ref[field_index]; } break; } case SPVM_OPCODE_C_ID_MULNUM_DEREF_FLOAT: { float* value_ref = *(float**)&ref_vars[opcode->operand1]; int32_t fields_length = opcode->operand3; for (int32_t field_index = 0; field_index < fields_length; field_index++) { float_vars[opcode->operand0 + field_index] = value_ref[field_index]; } break; } case SPVM_OPCODE_C_ID_MULNUM_DEREF_DOUBLE: { double* value_ref = *(double**)&ref_vars[opcode->operand1]; int32_t fields_length = opcode->operand3; for (int32_t field_index = 0; field_index < fields_length; field_index++) { double_vars[opcode->operand0 + field_index] = value_ref[field_index]; } break; } case SPVM_OPCODE_C_ID_MULNUM_DEREF_GET_FIELD_BYTE: { int8_t* value_ref = *(int8_t**)&ref_vars[opcode->operand1]; int32_t field_index = opcode->operand2; byte_vars[opcode->operand0] = value_ref[field_index]; break; } case SPVM_OPCODE_C_ID_MULNUM_DEREF_GET_FIELD_SHORT: { int16_t* value_ref = *(int16_t**)&ref_vars[opcode->operand1]; int32_t field_index = opcode->operand2; short_vars[opcode->operand0] = value_ref[field_index]; break; } case SPVM_OPCODE_C_ID_MULNUM_DEREF_GET_FIELD_INT: { int32_t* value_ref = *(int32_t**)&ref_vars[opcode->operand1]; int32_t field_index = opcode->operand2; int_vars[opcode->operand0] = value_ref[field_index]; break; } case SPVM_OPCODE_C_ID_MULNUM_DEREF_GET_FIELD_LONG: { int64_t* value_ref = *(int64_t**)&ref_vars[opcode->operand1]; int32_t field_index = opcode->operand2; long_vars[opcode->operand0] = value_ref[field_index]; break; } case SPVM_OPCODE_C_ID_MULNUM_DEREF_GET_FIELD_FLOAT: { float* value_ref = *(float**)&ref_vars[opcode->operand1]; int32_t field_index = opcode->operand2; float_vars[opcode->operand0] = value_ref[field_index]; break; } case SPVM_OPCODE_C_ID_MULNUM_DEREF_GET_FIELD_DOUBLE: { double* value_ref = *(double**)&ref_vars[opcode->operand1]; int32_t field_index = opcode->operand2; double_vars[opcode->operand0] = value_ref[field_index]; break; } case SPVM_OPCODE_C_ID_MULNUM_DEREF_SET_FIELD_BYTE: { int8_t* value_ref = *(int8_t**)&ref_vars[opcode->operand0]; int32_t field_index = opcode->operand2; value_ref[field_index] = byte_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_MULNUM_DEREF_SET_FIELD_SHORT: { int16_t* value_ref = *(int16_t**)&ref_vars[opcode->operand0]; int32_t field_index = opcode->operand2; value_ref[field_index] = short_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_MULNUM_DEREF_SET_FIELD_INT: { int32_t* value_ref = *(int32_t**)&ref_vars[opcode->operand0]; int32_t field_index = opcode->operand2; value_ref[field_index] = int_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_MULNUM_DEREF_SET_FIELD_LONG: { int64_t* value_ref = *(int64_t**)&ref_vars[opcode->operand0]; int32_t field_index = opcode->operand2; value_ref[field_index] = long_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_MULNUM_DEREF_SET_FIELD_FLOAT: { float* value_ref = *(float**)&ref_vars[opcode->operand0]; int32_t field_index = opcode->operand2; value_ref[field_index] = float_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_MULNUM_DEREF_SET_FIELD_DOUBLE: { double* value_ref = *(double**)&ref_vars[opcode->operand0]; int32_t field_index = opcode->operand2; value_ref[field_index] = double_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_MOVE_BYTE: { byte_vars[opcode->operand0] = byte_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_MOVE_SHORT: { short_vars[opcode->operand0] = short_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_MOVE_INT: { int_vars[opcode->operand0] = int_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_MOVE_LONG: { long_vars[opcode->operand0] = long_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_MOVE_FLOAT: { float_vars[opcode->operand0] = float_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_MOVE_DOUBLE: { double_vars[opcode->operand0] = double_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_MOVE_OBJECT: { SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], *(void**)&object_vars[opcode->operand1]); break; } case SPVM_OPCODE_C_ID_MOVE_OBJECT_CHECK_READ_ONLY: { void* string = *(void**)&object_vars[opcode->operand1]; if (env->is_read_only(env, string)) { void* exception = env->new_string_nolen_raw(env, "Read-only strings can't be converted to mutable strings."); env->set_exception(env, exception); exception_flag = 1; } else { SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], string); } break; } case SPVM_OPCODE_C_ID_COPY: { void* object = *(void**)&object_vars[opcode->operand1]; if (object) { if (!(env->is_string(env, object) || env->is_numeric_array(env, object) || env->is_mulnum_array(env, object))) { void* exception = env->new_string_nolen_raw(env, "The operand of the copy operator must be a string type, a numeric type, or a multi numeric type"); env->set_exception(env, exception); exception_flag = 1; } else { void* new_object_raw = env->copy_raw(env, object); SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], new_object_raw); } } else { SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], NULL); } break; } case SPVM_OPCODE_C_ID_MOVE_UNDEF: { SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], NULL); break; } case SPVM_OPCODE_C_ID_MOVE_REF: { *(void**)&ref_vars[opcode->operand0] = *(void**)&ref_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_MULNUM_MOVE_BYTE: { int32_t fields_length = opcode->operand2; for (int32_t field_index = 0; field_index < fields_length; field_index++) { byte_vars[opcode->operand0 + field_index] = byte_vars[opcode->operand1 + field_index]; } break; } case SPVM_OPCODE_C_ID_MULNUM_MOVE_SHORT: { int32_t fields_length = opcode->operand2; for (int32_t field_index = 0; field_index < fields_length; field_index++) { short_vars[opcode->operand0 + field_index] = short_vars[opcode->operand1 + field_index]; } break; } case SPVM_OPCODE_C_ID_MULNUM_MOVE_INT: { int32_t fields_length = opcode->operand2; for (int32_t field_index = 0; field_index < fields_length; field_index++) { int_vars[opcode->operand0 + field_index] = int_vars[opcode->operand1 + field_index]; } break; } case SPVM_OPCODE_C_ID_MULNUM_MOVE_LONG: { int32_t fields_length = opcode->operand2; for (int32_t field_index = 0; field_index < fields_length; field_index++) { long_vars[opcode->operand0 + field_index] = long_vars[opcode->operand1 + field_index]; } break; } case SPVM_OPCODE_C_ID_MULNUM_MOVE_FLOAT: { int32_t fields_length = opcode->operand2; for (int32_t field_index = 0; field_index < fields_length; field_index++) { float_vars[opcode->operand0 + field_index] = float_vars[opcode->operand1 + field_index]; } break; } case SPVM_OPCODE_C_ID_MULNUM_MOVE_DOUBLE: { int32_t fields_length = opcode->operand2; for (int32_t field_index = 0; field_index < fields_length; field_index++) { double_vars[opcode->operand0 + field_index] = double_vars[opcode->operand1 + field_index]; } break; } case SPVM_OPCODE_C_ID_MULNUM_GET_FIELD_BYTE: { int32_t field_index = opcode->operand2; byte_vars[opcode->operand0] = byte_vars[opcode->operand1 + field_index]; break; } case SPVM_OPCODE_C_ID_MULNUM_GET_FIELD_SHORT: { int32_t field_index = opcode->operand2; short_vars[opcode->operand0] = short_vars[opcode->operand1 + field_index]; break; } case SPVM_OPCODE_C_ID_MULNUM_GET_FIELD_INT: { int32_t field_index = opcode->operand2; int_vars[opcode->operand0] = int_vars[opcode->operand1 + field_index]; break; } case SPVM_OPCODE_C_ID_MULNUM_GET_FIELD_LONG: { int32_t field_index = opcode->operand2; long_vars[opcode->operand0] = long_vars[opcode->operand1 + field_index]; break; } case SPVM_OPCODE_C_ID_MULNUM_GET_FIELD_FLOAT: { int32_t field_index = opcode->operand2; float_vars[opcode->operand0] = float_vars[opcode->operand1 + field_index]; break; } case SPVM_OPCODE_C_ID_MULNUM_GET_FIELD_DOUBLE: { int32_t field_index = opcode->operand2; double_vars[opcode->operand0] = double_vars[opcode->operand1 + field_index]; break; } case SPVM_OPCODE_C_ID_MULNUM_SET_FIELD_BYTE: { int32_t field_index = opcode->operand2; byte_vars[opcode->operand0 + field_index] = byte_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_MULNUM_SET_FIELD_SHORT: { int32_t field_index = opcode->operand2; short_vars[opcode->operand0 + field_index] = short_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_MULNUM_SET_FIELD_INT: { int32_t field_index = opcode->operand2; int_vars[opcode->operand0 + field_index] = int_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_MULNUM_SET_FIELD_LONG: { int32_t field_index = opcode->operand2; long_vars[opcode->operand0 + field_index] = long_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_MULNUM_SET_FIELD_FLOAT: { int32_t field_index = opcode->operand2; float_vars[opcode->operand0 + field_index] = float_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_MULNUM_SET_FIELD_DOUBLE: { int32_t field_index = opcode->operand2; double_vars[opcode->operand0 + field_index] = double_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_PUSH_MORTAL: { mortal_stack[mortal_stack_top] = opcode->operand0; mortal_stack_top++; break; } case SPVM_OPCODE_C_ID_LEAVE_SCOPE: { int32_t original_mortal_stack_top = opcode->operand0; int32_t mortal_stack_index; for (mortal_stack_index = original_mortal_stack_top; mortal_stack_index < mortal_stack_top; mortal_stack_index++) { int32_t var_index = mortal_stack[mortal_stack_index]; void** object_address = (void**)&object_vars[var_index]; if (*(void**)&object_vars[var_index] != NULL) { if (SPVM_API_GET_REF_COUNT(*object_address) > 1) { SPVM_API_DEC_REF_COUNT_ONLY(*object_address); } else { env->dec_ref_count(env, *object_address); } } *object_address = NULL; } mortal_stack_top = original_mortal_stack_top; break; } case SPVM_OPCODE_C_ID_NEW_OBJECT: { int32_t basic_type_id = opcode->operand1; void* object = env->new_object_raw(env, basic_type_id); if (object == NULL) { void* exception = env->new_string_nolen_raw(env, "Can't allocate memory for object"); env->set_exception(env, exception); exception_flag = 1; } else { // Push object SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], object); } break; } case SPVM_OPCODE_C_ID_NEW_BYTE_ARRAY: { int32_t length = int_vars[opcode->operand1]; if (length >= 0) { void* object = env->new_byte_array_raw(env, length); if (object == NULL) { void* exception = env->new_string_nolen_raw(env, "Can't allocate memory for byte array"); env->set_exception(env, exception); exception_flag = 1; } else { SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], object); } } else { void* exception = env->new_string_nolen_raw(env, "Array length must be more than or equal to 0"); env->set_exception(env, exception); exception_flag = 1; } break; } case SPVM_OPCODE_C_ID_NEW_SHORT_ARRAY: { // length int32_t length = int_vars[opcode->operand1]; if (length >= 0) { void* object = env->new_short_array_raw(env, length); if (object == NULL) { void* exception = env->new_string_nolen_raw(env, "Can't allocate memory for short array"); env->set_exception(env, exception); exception_flag = 1; } else { // Set array SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], object); } } else { void* exception = env->new_string_nolen_raw(env, "Array length must be more than or equal to 0"); env->set_exception(env, exception); exception_flag = 1; } break; } case SPVM_OPCODE_C_ID_NEW_INT_ARRAY: { // length int32_t length = int_vars[opcode->operand1]; if (length >= 0) { void* object = env->new_int_array_raw(env, length); if (object == NULL) { void* exception = env->new_string_nolen_raw(env, "Can't allocate memory for int array"); env->set_exception(env, exception); exception_flag = 1; } else { // Set array SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], object); } } else { void* exception = env->new_string_nolen_raw(env, "Array length must be more than or equal to 0"); env->set_exception(env, exception); exception_flag = 1; } break; } case SPVM_OPCODE_C_ID_NEW_LONG_ARRAY: { int32_t length = int_vars[opcode->operand1]; if (length >= 0) { void* object = env->new_long_array_raw(env, length); if (object == NULL) { void* exception = env->new_string_nolen_raw(env, "Can't allocate memory for long array"); env->set_exception(env, exception); exception_flag = 1; } else { SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], object); } } else { void* exception = env->new_string_nolen_raw(env, "Array length must be more than or equal to 0"); env->set_exception(env, exception); exception_flag = 1; } break; } case SPVM_OPCODE_C_ID_NEW_FLOAT_ARRAY: { int32_t length = int_vars[opcode->operand1]; if (length >= 0) { void* object = env->new_float_array_raw(env, length); if (object == NULL) { void* exception = env->new_string_nolen_raw(env, "Can't allocate memory for float array"); env->set_exception(env, exception); exception_flag = 1; } else { SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], object); } } else { void* exception = env->new_string_nolen_raw(env, "Array length must be more than or equal to 0"); env->set_exception(env, exception); exception_flag = 1; } break; } case SPVM_OPCODE_C_ID_NEW_DOUBLE_ARRAY: { int32_t length = int_vars[opcode->operand1]; if (length >= 0) { void* object = env->new_double_array_raw(env, length); if (object == NULL) { void* exception = env->new_string_nolen_raw(env, "Can't allocate memory for double array"); env->set_exception(env, exception); exception_flag = 1; } else { SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], object); } } else { void* exception = env->new_string_nolen_raw(env, "Array length must be more than or equal to 0"); env->set_exception(env, exception); exception_flag = 1; } break; } case SPVM_OPCODE_C_ID_NEW_OBJECT_ARRAY: { int32_t basic_type_id = opcode->operand1; int32_t length = int_vars[opcode->operand2]; if (length >= 0) { void* object = env->new_object_array_raw(env, basic_type_id, length); if (object == NULL) { void* exception = env->new_string_nolen_raw(env, "Can't allocate memory for object array"); env->set_exception(env, exception); exception_flag = 1; } else { SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], object); } } else { void* exception = env->new_string_nolen_raw(env, "Array length must be more than or equal to 0"); env->set_exception(env, exception); exception_flag = 1; } break; } case SPVM_OPCODE_C_ID_NEW_MULTI_ARRAY: { int32_t basic_type_id = opcode->operand1; int32_t element_dimension = opcode->operand3; int32_t length = int_vars[opcode->operand2]; if (length >= 0) { void* object = env->new_muldim_array_raw(env, basic_type_id, element_dimension, length); if (object == NULL) { void* exception = env->new_string_nolen_raw(env, "Can't allocate memory for multi dimention array"); env->set_exception(env, exception); exception_flag = 1; } else { SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], object); } } else { void* exception = env->new_string_nolen_raw(env, "Array length must be more than or equal to 0"); env->set_exception(env, exception); exception_flag = 1; } break; } case SPVM_OPCODE_C_ID_NEW_MULNUM_ARRAY: { int32_t basic_type_id = opcode->operand1; int32_t length = int_vars[opcode->operand2]; if (length >= 0) { void* object = env->new_mulnum_array_raw(env, basic_type_id, length); if (object == NULL) { void* exception = env->new_string_nolen_raw(env, "Can't allocate memory for muti numeric array"); env->set_exception(env, exception); exception_flag = 1; } else { SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], object); } } else { void* exception = env->new_string_nolen_raw(env, "Array length must be more than or equal to 0"); env->set_exception(env, exception); exception_flag = 1; } break; } case SPVM_OPCODE_C_ID_NEW_CONSTANT_STRING: { int32_t string_id = opcode->operand1; int32_t constant_string_length; const char* constant_string = env->get_constant_string_value(env, string_id, &constant_string_length); void* string = env->new_string_raw(env, constant_string, constant_string_length); if (string == NULL) { void* exception = env->new_string_nolen_raw(env, "Can't allocate memory for string"); env->set_exception(env, exception); exception_flag = 1; } else { env->make_read_only(env, string); SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0] , string); } break; } case SPVM_OPCODE_C_ID_ARRAY_LENGTH: { if (*(void**)&object_vars[opcode->operand1] == NULL) { void* exception = env->new_string_nolen_raw(env, "Can't get the array length of undef."); env->set_exception(env, exception); exception_flag = 1; } else { int_vars[opcode->operand0] = *(int32_t*)((intptr_t)*(void**)&object_vars[opcode->operand1] + (intptr_t)env->object_length_offset); } break; } case SPVM_OPCODE_C_ID_IS_READ_ONLY: { void* string = *(void**)&object_vars[opcode->operand1]; int32_t is_read_only = env->is_read_only(env, string); int_vars[0] = is_read_only; break; } case SPVM_OPCODE_C_ID_CONCAT: { void* string1 = *(void**)&object_vars[opcode->operand1]; void* string2 = *(void**)&object_vars[opcode->operand2]; if (string1 == NULL) { void* exception = env->new_string_nolen_raw(env, "\".\" operater left value must be defined"); env->set_exception(env, exception); exception_flag = 1; } else if (string2 == NULL) { void* exception = env->new_string_nolen_raw(env, "\".\" operater right value must be defined"); env->set_exception(env, exception); exception_flag = 1; } else { void* string3 = env->concat_raw(env, string1, string2); SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], string3); } break; } case SPVM_OPCODE_C_ID_REFOP: { void* object = object_vars[opcode->operand1]; if (object == NULL) { object_vars[opcode->operand0] = NULL; } else { void* type_name = env->get_type_name_raw(env, object); SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], type_name); } break; } case SPVM_OPCODE_C_ID_DUMP: { void* object = object_vars[opcode->operand1]; void* dump = env->dump_raw(env, object); SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], dump); break; } case SPVM_OPCODE_C_ID_NEW_STRING_LEN: { int32_t length = int_vars[opcode->operand1]; if (length >= 0) { void* string = env->new_string_raw(env, NULL, length); if (string == NULL) { void* exception = env->new_string_nolen_raw(env, "The new_string_len operator can't allocate enough memory"); env->set_exception(env, exception); exception_flag = 1; } else { SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], string); } } else { void* exception = env->new_string_nolen_raw(env, "The length of the new_string_len operator must be a positive number"); env->set_exception(env, exception); exception_flag = 1; } break; } case SPVM_OPCODE_C_ID_GOTO: opcode_rel_index = opcode->operand0; continue; case SPVM_OPCODE_C_ID_IF_EQ_ZERO: { if (int_vars[0] == 0) { opcode_rel_index = opcode->operand0; continue; } break; } case SPVM_OPCODE_C_ID_IF_NE_ZERO: { if (int_vars[0]) { opcode_rel_index = opcode->operand0; continue; } break; } case SPVM_OPCODE_C_ID_PUSH_ARG_BYTE: { *(int8_t*)&stack[stack_index] = byte_vars[opcode->operand0]; stack_index++; break; } case SPVM_OPCODE_C_ID_PUSH_ARG_SHORT: { *(int16_t*)&stack[stack_index] = short_vars[opcode->operand0]; stack_index++; break; } case SPVM_OPCODE_C_ID_PUSH_ARG_INT: { *(int32_t*)&stack[stack_index] = int_vars[opcode->operand0]; stack_index++; break; } case SPVM_OPCODE_C_ID_PUSH_ARG_LONG: { *(int64_t*)&stack[stack_index] = long_vars[opcode->operand0]; stack_index++; break; } case SPVM_OPCODE_C_ID_PUSH_ARG_FLOAT: { *(float*)&stack[stack_index] = float_vars[opcode->operand0]; stack_index++; break; } case SPVM_OPCODE_C_ID_PUSH_ARG_DOUBLE: { *(double*)&stack[stack_index] = double_vars[opcode->operand0]; stack_index++; break; } case SPVM_OPCODE_C_ID_PUSH_ARG_OBJECT: { *(void**)&stack[stack_index] = *(void**)&object_vars[opcode->operand0]; stack_index++; break; } case SPVM_OPCODE_C_ID_PUSH_ARG_REF: { *(void**)&stack[stack_index] = *(void**)&ref_vars[opcode->operand0]; stack_index++; break; } case SPVM_OPCODE_C_ID_PUSH_ARG_UNDEF: *(void**)&stack[stack_index] = NULL; stack_index++; break; case SPVM_OPCODE_C_ID_PUSH_ARG_MULNUM_BYTE: { int32_t fields_length = opcode->operand1; for (int32_t field_index = 0; field_index < fields_length; field_index++) { *(int8_t*)&stack[stack_index + field_index] = byte_vars[opcode->operand0 + field_index]; } stack_index += fields_length; break; } case SPVM_OPCODE_C_ID_PUSH_ARG_MULNUM_SHORT: { int32_t fields_length = opcode->operand1; for (int32_t field_index = 0; field_index < fields_length; field_index++) { *(int16_t*)&stack[stack_index + field_index] = short_vars[opcode->operand0 + field_index]; } stack_index += fields_length; break; } case SPVM_OPCODE_C_ID_PUSH_ARG_MULNUM_INT: { int32_t fields_length = opcode->operand1; for (int32_t field_index = 0; field_index < fields_length; field_index++) { *(int32_t*)&stack[stack_index + field_index] = int_vars[opcode->operand0 + field_index]; } stack_index += fields_length; break; } case SPVM_OPCODE_C_ID_PUSH_ARG_MULNUM_LONG: { int32_t fields_length = opcode->operand1; for (int32_t field_index = 0; field_index < fields_length; field_index++) { *(int64_t*)&stack[stack_index + field_index] = long_vars[opcode->operand0 + field_index]; } stack_index += fields_length; break; } case SPVM_OPCODE_C_ID_PUSH_ARG_MULNUM_FLOAT: { int32_t fields_length = opcode->operand1; for (int32_t field_index = 0; field_index < fields_length; field_index++) { *(float*)&stack[stack_index + field_index] = float_vars[opcode->operand0 + field_index]; } stack_index += fields_length; break; } case SPVM_OPCODE_C_ID_PUSH_ARG_MULNUM_DOUBLE: { int32_t fields_length = opcode->operand1; for (int32_t field_index = 0; field_index < fields_length; field_index++) { *(double*)&stack[stack_index + field_index] = double_vars[opcode->operand0 + field_index]; } stack_index += fields_length; break; } case SPVM_OPCODE_C_ID_CHECK_OBJECT_TYPE: { void* object = *(void**)&object_vars[opcode->operand1]; if (object != NULL) { int32_t check_basic_type_id = opcode->operand2; int32_t check_type_dimension = opcode->operand3; int32_t object_basic_type_id = *(int32_t*)((intptr_t)object + (intptr_t)env->object_basic_type_id_offset); int32_t object_type_dimension = *(uint8_t*)((intptr_t)object + (intptr_t)env->object_type_dimension_offset); if (object_basic_type_id == check_basic_type_id && object_type_dimension == check_type_dimension) { SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], *(void**)&object_vars[opcode->operand1]); } else { void* exception = env->new_string_nolen_raw(env, "Can't convert imcompatible object type in runtime."); env->set_exception(env, exception); exception_flag = 1; } } break; } case SPVM_OPCODE_C_ID_CHECK_CALLBACK: { void* object = *(void**)&object_vars[opcode->operand1]; if (object != NULL) { int32_t check_basic_type_id = opcode->operand2; int32_t object_basic_type_id = *(int32_t*)((intptr_t)object + (intptr_t)env->object_basic_type_id_offset); int32_t object_type_dimension = *(uint8_t*)((intptr_t)object + (intptr_t)env->object_type_dimension_offset); if (env->has_callback(env, object, check_basic_type_id)) { SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], *(void**)&object_vars[opcode->operand1]); } else { void* exception = env->new_string_nolen_raw(env, "Can't convert imcompatible callback type."); env->set_exception(env, exception); exception_flag = 1; } } break; } case SPVM_OPCODE_C_ID_CHECK_INTERFACE: { void* object = *(void**)&object_vars[opcode->operand1]; if (object != NULL) { int32_t check_basic_type_id = opcode->operand2; int32_t object_basic_type_id = *(int32_t*)((intptr_t)object + (intptr_t)env->object_basic_type_id_offset); int32_t object_type_dimension = *(uint8_t*)((intptr_t)object + (intptr_t)env->object_type_dimension_offset); if (env->has_interface(env, object, check_basic_type_id)) { SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], *(void**)&object_vars[opcode->operand1]); } else { void* exception = env->new_string_nolen_raw(env, "Can't convert imcompatible callback type."); env->set_exception(env, exception); exception_flag = 1; } } break; } case SPVM_OPCODE_C_ID_CALL_CLASS_METHOD_BY_ID: case SPVM_OPCODE_C_ID_CALL_INSTANCE_METHOD_BY_ID: { int32_t call_method_id = opcode->operand1; SPVM_RUNTIME_METHOD* call_spvm_method = SPVM_API_get_method(env, call_method_id); stack_index = 0; exception_flag = env->call_spvm_method(env, call_method_id, stack); SPVM_RUNTIME_TYPE* call_spvm_method_return_type = SPVM_API_get_type(env, call_spvm_method->return_type_id); switch (call_spvm_method_return_type->category) { case SPVM_TYPE_C_TYPE_CATEGORY_VOID: { break; } case SPVM_TYPE_C_TYPE_CATEGORY_BYTE: { if (!exception_flag) { byte_vars[opcode->operand0] = *(int8_t*)&stack[0]; } break; } case SPVM_TYPE_C_TYPE_CATEGORY_SHORT: { if (!exception_flag) { short_vars[opcode->operand0] = *(int16_t*)&stack[0]; } break; } case SPVM_TYPE_C_TYPE_CATEGORY_INT: { if (!exception_flag) { int_vars[opcode->operand0] = *(int32_t*)&stack[0]; } break; } case SPVM_TYPE_C_TYPE_CATEGORY_LONG: { if (!exception_flag) { long_vars[opcode->operand0] = *(int64_t*)&stack[0]; } break; } case SPVM_TYPE_C_TYPE_CATEGORY_FLOAT: { if (!exception_flag) { float_vars[opcode->operand0] = *(float*)&stack[0]; } break; } case SPVM_TYPE_C_TYPE_CATEGORY_DOUBLE: { if (!exception_flag) { double_vars[opcode->operand0] = *(double*)&stack[0]; } break; } case SPVM_TYPE_C_TYPE_CATEGORY_STRING: case SPVM_TYPE_C_TYPE_CATEGORY_CLASS: case SPVM_TYPE_C_TYPE_CATEGORY_ANY_OBJECT: case SPVM_TYPE_C_TYPE_CATEGORY_NUMERIC_ARRAY: case SPVM_TYPE_C_TYPE_CATEGORY_OBJECT_ARRAY: case SPVM_TYPE_C_TYPE_CATEGORY_MULNUM_ARRAY: { if (!exception_flag) { SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], stack[0].oval); } break; } case SPVM_TYPE_C_TYPE_CATEGORY_MULNUM_BYTE: { if (!exception_flag) { int32_t fields_length = opcode->operand3; for (int32_t field_index = 0; field_index < fields_length; field_index++) { byte_vars[opcode->operand0 + field_index] = *(int8_t*)&stack[field_index]; } } break; } case SPVM_TYPE_C_TYPE_CATEGORY_MULNUM_SHORT: { if (!exception_flag) { int32_t fields_length = opcode->operand3; for (int32_t field_index = 0; field_index < fields_length; field_index++) { short_vars[opcode->operand0 + field_index] = *(int16_t*)&stack[field_index]; } } break; } case SPVM_TYPE_C_TYPE_CATEGORY_MULNUM_INT: { if (!exception_flag) { int32_t fields_length = opcode->operand3; for (int32_t field_index = 0; field_index < fields_length; field_index++) { int_vars[opcode->operand0 + field_index] = *(int32_t*)&stack[field_index]; } } break; } case SPVM_TYPE_C_TYPE_CATEGORY_MULNUM_LONG: { if (!exception_flag) { int32_t fields_length = opcode->operand3; for (int32_t field_index = 0; field_index < fields_length; field_index++) { long_vars[opcode->operand0 + field_index] = *(int64_t*)&stack[field_index]; } } break; } case SPVM_TYPE_C_TYPE_CATEGORY_MULNUM_FLOAT: { if (!exception_flag) { int32_t fields_length = opcode->operand3; for (int32_t field_index = 0; field_index < fields_length; field_index++) { float_vars[opcode->operand0 + field_index] = *(float*)&stack[field_index]; } } break; } case SPVM_TYPE_C_TYPE_CATEGORY_MULNUM_DOUBLE: { if (!exception_flag) { int32_t fields_length = opcode->operand3; for (int32_t field_index = 0; field_index < fields_length; field_index++) { double_vars[opcode->operand0 + field_index] = *(double*)&stack[field_index]; } } break; } } break; } case SPVM_OPCODE_C_ID_CALL_INSTANCE_METHOD_BY_SIGNATURE: { int32_t decl_method_id = opcode->operand1; SPVM_RUNTIME_METHOD* decl_method = SPVM_API_get_method(env, decl_method_id); void* object = stack[0].oval; const char* decl_method_name = SPVM_API_get_constant_string_value(env, decl_method->name_id, NULL); const char* decl_method_signature = SPVM_API_get_constant_string_value(env, decl_method->signature_id, NULL); int32_t call_method_id = env->get_instance_method_id(env, object, decl_method_name, decl_method_signature); stack_index = 0; if (call_method_id < 0) { memset(tmp_buffer, sizeof(tmp_buffer), 0); SPVM_RUNTIME_CLASS* decl_method_class = SPVM_API_get_class(env, decl_method->class_id); snprintf(tmp_buffer, 255, "Can't find the \"%s\" method with the signature \"%s\" that is declared in \"%s\"", decl_method_name, decl_method_signature, SPVM_API_get_constant_string_value(env, decl_method_class->name_id, NULL)); void* exception = env->new_string_nolen_raw(env, tmp_buffer); env->set_exception(env, exception); exception_flag = 1; } else { exception_flag = env->call_spvm_method(env, call_method_id, stack); SPVM_RUNTIME_TYPE* decl_method_return_type = SPVM_API_get_type(env, decl_method->return_type_id); switch (decl_method_return_type->category) { case SPVM_TYPE_C_TYPE_CATEGORY_VOID: { break; } case SPVM_TYPE_C_TYPE_CATEGORY_BYTE: { if (!exception_flag) { byte_vars[opcode->operand0] = *(int8_t*)&stack[0]; } break; } case SPVM_TYPE_C_TYPE_CATEGORY_SHORT: { if (!exception_flag) { short_vars[opcode->operand0] = *(int16_t*)&stack[0]; } break; } case SPVM_TYPE_C_TYPE_CATEGORY_INT: { if (!exception_flag) { int_vars[opcode->operand0] = *(int32_t*)&stack[0]; } break; } case SPVM_TYPE_C_TYPE_CATEGORY_LONG: { if (!exception_flag) { long_vars[opcode->operand0] = *(int64_t*)&stack[0]; } break; } case SPVM_TYPE_C_TYPE_CATEGORY_FLOAT: { if (!exception_flag) { float_vars[opcode->operand0] = *(float*)&stack[0]; } break; } case SPVM_TYPE_C_TYPE_CATEGORY_DOUBLE: { if (!exception_flag) { double_vars[opcode->operand0] = *(double*)&stack[0]; } break; } case SPVM_TYPE_C_TYPE_CATEGORY_STRING: case SPVM_TYPE_C_TYPE_CATEGORY_CLASS: case SPVM_TYPE_C_TYPE_CATEGORY_ANY_OBJECT: case SPVM_TYPE_C_TYPE_CATEGORY_NUMERIC_ARRAY: case SPVM_TYPE_C_TYPE_CATEGORY_OBJECT_ARRAY: case SPVM_TYPE_C_TYPE_CATEGORY_MULNUM_ARRAY: { if (!exception_flag) { SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], stack[0].oval); } break; } case SPVM_TYPE_C_TYPE_CATEGORY_MULNUM_BYTE: { if (!exception_flag) { int32_t fields_length = opcode->operand3; for (int32_t field_index = 0; field_index < fields_length; field_index++) { byte_vars[opcode->operand0 + field_index] = *(int8_t*)&stack[field_index]; } } break; } case SPVM_TYPE_C_TYPE_CATEGORY_MULNUM_SHORT: { if (!exception_flag) { int32_t fields_length = opcode->operand3; for (int32_t field_index = 0; field_index < fields_length; field_index++) { short_vars[opcode->operand0 + field_index] = *(int16_t*)&stack[field_index]; } } break; } case SPVM_TYPE_C_TYPE_CATEGORY_MULNUM_INT: { if (!exception_flag) { int32_t fields_length = opcode->operand3; for (int32_t field_index = 0; field_index < fields_length; field_index++) { int_vars[opcode->operand0 + field_index] = *(int32_t*)&stack[field_index]; } } break; } case SPVM_TYPE_C_TYPE_CATEGORY_MULNUM_LONG: { if (!exception_flag) { int32_t fields_length = opcode->operand3; for (int32_t field_index = 0; field_index < fields_length; field_index++) { long_vars[opcode->operand0 + field_index] = *(int64_t*)&stack[field_index]; } } break; } case SPVM_TYPE_C_TYPE_CATEGORY_MULNUM_FLOAT: { if (!exception_flag) { int32_t fields_length = opcode->operand3; for (int32_t field_index = 0; field_index < fields_length; field_index++) { float_vars[opcode->operand0 + field_index] = *(float*)&stack[field_index]; } } break; } case SPVM_TYPE_C_TYPE_CATEGORY_MULNUM_DOUBLE: { if (!exception_flag) { int32_t fields_length = opcode->operand3; for (int32_t field_index = 0; field_index < fields_length; field_index++) { double_vars[opcode->operand0 + field_index] = *(double*)&stack[field_index]; } } break; } } } break; } case SPVM_OPCODE_C_ID_IF_EXCEPTION_CATCH: { if (exception_flag) { exception_flag = 0; int32_t method_index = opcode->operand1; int32_t method_id = class->method_ids_base + method_index; SPVM_RUNTIME_METHOD* method = SPVM_API_get_method(env, method_id); int32_t line = opcode->operand2; const char* method_name = SPVM_API_get_constant_string_value(env, method->name_id, NULL); SPVM_RUNTIME_CLASS* method_class = SPVM_API_get_class(env, method->class_id); const char* class_name = SPVM_API_get_constant_string_value(env, method_class->name_id, NULL); const char* file = SPVM_API_get_constant_string_value(env, method_class->module_file_id, NULL); // Exception stack trace env->set_exception(env, env->new_stack_trace_raw(env, env->get_exception(env), class_name, method_name, file, line)); opcode_rel_index = opcode->operand0; continue; } break; } case SPVM_OPCODE_C_ID_IF_EXCEPTION_RETURN: { if (exception_flag) { int32_t method_index = opcode->operand1; int32_t method_id = class->method_ids_base + method_index; SPVM_RUNTIME_METHOD* method = SPVM_API_get_method(env, method_id); int32_t line = opcode->operand2; const char* method_name = SPVM_API_get_constant_string_value(env, method->name_id, NULL); SPVM_RUNTIME_CLASS* method_class = SPVM_API_get_class(env, method->class_id); const char* class_name = SPVM_API_get_constant_string_value(env, method_class->name_id, NULL); const char* file = SPVM_API_get_constant_string_value(env, class->module_file_id, NULL); // Exception stack trace env->set_exception(env, env->new_stack_trace_raw(env, env->get_exception(env), class_name, method_name, file, line)); opcode_rel_index = opcode->operand0; continue; } break; } case SPVM_OPCODE_C_ID_SET_DIE_FLAG_TRUE: { exception_flag = 1; break; } case SPVM_OPCODE_C_ID_PRINT: { void* object = object_vars[opcode->operand0]; if (object) { const char* bytes = env->get_chars(env, object); int32_t string_length = env->length(env, object); if (string_length > 0) { size_t ret = fwrite(bytes, 1, string_length, stdout); } } break; } case SPVM_OPCODE_C_ID_MAKE_READ_ONLY: { void* string = object_vars[opcode->operand0]; env->make_read_only(env, string); break; } case SPVM_OPCODE_C_ID_WARN: { int32_t line = opcode->operand1; const char* file = SPVM_API_get_constant_string_value(env, class->module_file_id, NULL); void* object = object_vars[opcode->operand0]; int32_t empty_or_undef = 0; if (object) { const char* bytes = env->get_chars(env, object); int32_t string_length = env->length(env, object); if (string_length > 0) { size_t ret = fwrite(bytes, 1, string_length, stderr); // Add line and file information if last character is not '\n' int32_t add_line_file; if (bytes[string_length - 1] != '\n') { fprintf(stderr, " at %s line %d\n", file, line); } } else { empty_or_undef = 1; } } else { empty_or_undef = 1; } if (empty_or_undef) { fprintf(stderr, "Warning: something's wrong at %s line %d\n", file, line); } fflush(stderr); break; } case SPVM_OPCODE_C_ID_RETURN_VOID: { opcode_rel_index = opcode->operand1; continue; } case SPVM_OPCODE_C_ID_RETURN_BYTE: { *(int8_t*)&stack[0] = byte_vars[opcode->operand0]; opcode_rel_index = opcode->operand1; continue; } case SPVM_OPCODE_C_ID_RETURN_SHORT: { *(int16_t*)&stack[0] = short_vars[opcode->operand0]; opcode_rel_index = opcode->operand1; continue; } case SPVM_OPCODE_C_ID_RETURN_INT: { *(int32_t*)&stack[0] = int_vars[opcode->operand0]; opcode_rel_index = opcode->operand1; continue; } case SPVM_OPCODE_C_ID_RETURN_LONG: { *(int64_t*)&stack[0] = long_vars[opcode->operand0]; opcode_rel_index = opcode->operand1; continue; } case SPVM_OPCODE_C_ID_RETURN_FLOAT: { *(float*)&stack[0] = float_vars[opcode->operand0]; opcode_rel_index = opcode->operand1; continue; } case SPVM_OPCODE_C_ID_RETURN_DOUBLE: { *(double*)&stack[0] = double_vars[opcode->operand0]; opcode_rel_index = opcode->operand1; continue; } case SPVM_OPCODE_C_ID_RETURN_OBJECT: { *(void**)&stack[0] = *(void**)&object_vars[opcode->operand0]; // Increment ref count of return value not to release by leave scope if (*(void**)&stack[0] != NULL) { SPVM_API_INC_REF_COUNT_ONLY(*(void**)&stack[0]); } opcode_rel_index = opcode->operand1; continue; } case SPVM_OPCODE_C_ID_RETURN_UNDEF: { *(void**)&stack[0] = NULL; opcode_rel_index = opcode->operand1; continue; } case SPVM_OPCODE_C_ID_RETURN_MULNUM_BYTE: { int32_t fields_length = opcode->operand2; for (int32_t field_index = 0; field_index < fields_length; field_index++) { *(int8_t*)&stack[field_index] = byte_vars[opcode->operand0 + field_index]; } opcode_rel_index = opcode->operand1; continue; } case SPVM_OPCODE_C_ID_RETURN_MULNUM_SHORT: { int32_t fields_length = opcode->operand2; for (int32_t field_index = 0; field_index < fields_length; field_index++) { *(int16_t*)&stack[field_index] = short_vars[opcode->operand0 + field_index]; } opcode_rel_index = opcode->operand1; continue; } case SPVM_OPCODE_C_ID_RETURN_MULNUM_INT: { int32_t fields_length = opcode->operand2; for (int32_t field_index = 0; field_index < fields_length; field_index++) { *(int32_t*)&stack[field_index] = int_vars[opcode->operand0 + field_index]; } opcode_rel_index = opcode->operand1; continue; } case SPVM_OPCODE_C_ID_RETURN_MULNUM_LONG: { int32_t fields_length = opcode->operand2; for (int32_t field_index = 0; field_index < fields_length; field_index++) { *(int64_t*)&stack[field_index] = long_vars[opcode->operand0 + field_index]; } opcode_rel_index = opcode->operand1; continue; } case SPVM_OPCODE_C_ID_RETURN_MULNUM_FLOAT: { int32_t fields_length = opcode->operand2; for (int32_t field_index = 0; field_index < fields_length; field_index++) { *(float*)&stack[field_index] = float_vars[opcode->operand0 + field_index]; } opcode_rel_index = opcode->operand1; continue; } case SPVM_OPCODE_C_ID_RETURN_MULNUM_DOUBLE: { int32_t fields_length = opcode->operand2; for (int32_t field_index = 0; field_index < fields_length; field_index++) { *(double*)&stack[field_index] = double_vars[opcode->operand0 + field_index]; } opcode_rel_index = opcode->operand1; continue; } case SPVM_OPCODE_C_ID_LOOKUP_SWITCH: { int32_t switch_id = opcode->operand1; // Default branch int32_t default_opcode_rel_index = opcode->operand2; // Cases length int32_t case_infos_length = opcode->operand3; if (case_infos_length > 0) { // min SPVM_OPCODE* opcode_case_info_min = &(opcodes[method_opcodes_base + opcode_rel_index + 1 + 0]); int32_t min = opcode_case_info_min->operand1; // max SPVM_OPCODE* opcode_case_info_max = &(opcodes[method_opcodes_base + opcode_rel_index + 1 + case_infos_length - 1]); int32_t max = opcode_case_info_max->operand1; if (int_vars[opcode->operand0] >= min && int_vars[opcode->operand0] <= max) { // 2 opcode_rel_index searching int32_t cur_min_pos = 0; int32_t cur_max_pos = case_infos_length - 1; while (1) { if (cur_max_pos < cur_min_pos) { opcode_rel_index = default_opcode_rel_index; break; } int32_t cur_half_pos = cur_min_pos + (cur_max_pos - cur_min_pos) / 2; SPVM_OPCODE* opcode_case_cur_half = &(opcodes[method_opcodes_base + opcode_rel_index + 1 + cur_half_pos]); int32_t cur_half = opcode_case_cur_half->operand1; if (int_vars[opcode->operand0] > cur_half) { cur_min_pos = cur_half_pos + 1; } else if (int_vars[opcode->operand0] < cur_half) { cur_max_pos = cur_half_pos - 1; } else { opcode_rel_index = opcode_case_cur_half->operand2; break; } } } else { opcode_rel_index = default_opcode_rel_index; } } else { opcode_rel_index = default_opcode_rel_index; } continue; } case SPVM_OPCODE_C_ID_GET_FIELD_BYTE: { int32_t field_id = opcode->operand2; SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); int32_t field_offset = field->offset; void* object = *(void**)&object_vars[opcode->operand1]; if (__builtin_expect(object == NULL, 0)) { void* exception = env->new_string_nolen_raw(env, "Invocants of getting fields must not be undefined values"); env->set_exception(env, exception); exception_flag = 1; } else { byte_vars[opcode->operand0] = *(int8_t*)((intptr_t)object + object_header_byte_size + field_offset); } break; } case SPVM_OPCODE_C_ID_GET_FIELD_SHORT: { int32_t field_id = opcode->operand2; SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); int32_t field_offset = field->offset; void* object = *(void**)&object_vars[opcode->operand1]; if (__builtin_expect(object == NULL, 0)) { void* exception = env->new_string_nolen_raw(env, "Invocants of getting fields must not be undefined values"); env->set_exception(env, exception); exception_flag = 1; } else { short_vars[opcode->operand0] = *(int16_t*)((intptr_t)object + object_header_byte_size + field_offset); } break; } case SPVM_OPCODE_C_ID_GET_FIELD_INT: { int32_t field_id = opcode->operand2; SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); int32_t field_offset = field->offset; void* object = *(void**)&object_vars[opcode->operand1]; if (__builtin_expect(object == NULL, 0)) { void* exception = env->new_string_nolen_raw(env, "Invocants of getting fields must not be undefined values"); env->set_exception(env, exception); exception_flag = 1; } else { int_vars[opcode->operand0] = *(int32_t*)((intptr_t)object + object_header_byte_size + field_offset); } break; } case SPVM_OPCODE_C_ID_GET_FIELD_LONG: { int32_t field_id = opcode->operand2; SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); int32_t field_offset = field->offset; void* object = *(void**)&object_vars[opcode->operand1]; if (__builtin_expect(object == NULL, 0)) { void* exception = env->new_string_nolen_raw(env, "Invocants of getting fields must not be undefined values"); env->set_exception(env, exception); exception_flag = 1; } else { long_vars[opcode->operand0] = *(int64_t*)((intptr_t)object + object_header_byte_size + field_offset); } break; } case SPVM_OPCODE_C_ID_GET_FIELD_FLOAT: { int32_t field_id = opcode->operand2; SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); int32_t field_offset = field->offset; void* object = *(void**)&object_vars[opcode->operand1]; if (__builtin_expect(object == NULL, 0)) { void* exception = env->new_string_nolen_raw(env, "Invocants of getting fields must not be undefined values"); env->set_exception(env, exception); exception_flag = 1; } else { float_vars[opcode->operand0] = *(float*)((intptr_t)object + object_header_byte_size + field_offset); } break; } case SPVM_OPCODE_C_ID_GET_FIELD_DOUBLE: { int32_t field_id = opcode->operand2; SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); int32_t field_offset = field->offset; void* object = *(void**)&object_vars[opcode->operand1]; if (__builtin_expect(object == NULL, 0)) { void* exception = env->new_string_nolen_raw(env, "Invocants of getting fields must not be undefined values"); env->set_exception(env, exception); exception_flag = 1; } else { double_vars[opcode->operand0] = *(double*)((intptr_t)object + object_header_byte_size + field_offset); } break; } case SPVM_OPCODE_C_ID_GET_FIELD_OBJECT: { int32_t field_id = opcode->operand2; SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); int32_t field_offset = field->offset; void* object = *(void**)&object_vars[opcode->operand1]; if (__builtin_expect(object == NULL, 0)) { void* exception = env->new_string_nolen_raw(env, "Invocants of getting fields must not be undefined values"); env->set_exception(env, exception); exception_flag = 1; } else { void* get_field_object = *(void**)((intptr_t)object + object_header_byte_size + field_offset); SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], get_field_object); } break; } case SPVM_OPCODE_C_ID_SET_FIELD_BYTE: { void* object = *(void**)&object_vars[opcode->operand0]; int32_t field_id = opcode->operand1; SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); int32_t field_offset = field->offset; if (__builtin_expect(object == NULL, 0)) { void* exception = env->new_string_nolen_raw(env, "Invocants of setting fields must not be undefined values"); env->set_exception(env, exception); exception_flag = 1; } else { *(int8_t*)((intptr_t)object + object_header_byte_size + field_offset) = byte_vars[opcode->operand2]; } break; } case SPVM_OPCODE_C_ID_SET_FIELD_SHORT: { void* object = *(void**)&object_vars[opcode->operand0]; int32_t field_id = opcode->operand1; SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); int32_t field_offset = field->offset; if (__builtin_expect(object == NULL, 0)) { void* exception = env->new_string_nolen_raw(env, "Invocants of setting fields must not be undefined values"); env->set_exception(env, exception); exception_flag = 1; } else { *(int16_t*)((intptr_t)object + object_header_byte_size + field_offset) = short_vars[opcode->operand2]; } break; } case SPVM_OPCODE_C_ID_SET_FIELD_INT: { void* object = *(void**)&object_vars[opcode->operand0]; int32_t field_id = opcode->operand1; SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); int32_t field_offset = field->offset; if (__builtin_expect(object == NULL, 0)) { void* exception = env->new_string_nolen_raw(env, "Invocants of setting fields must not be undefined values"); env->set_exception(env, exception); exception_flag = 1; } else { *(int32_t*)((intptr_t)object + object_header_byte_size + field_offset) = int_vars[opcode->operand2]; } break; } case SPVM_OPCODE_C_ID_SET_FIELD_LONG: { void* object = *(void**)&object_vars[opcode->operand0]; int32_t field_id = opcode->operand1; SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); int32_t field_offset = field->offset; if (__builtin_expect(object == NULL, 0)) { void* exception = env->new_string_nolen_raw(env, "Invocants of setting fields must not be undefined values"); env->set_exception(env, exception); exception_flag = 1; } else { *(int64_t*)((intptr_t)object + object_header_byte_size + field_offset) = long_vars[opcode->operand2]; } break; } case SPVM_OPCODE_C_ID_SET_FIELD_FLOAT: { void* object = *(void**)&object_vars[opcode->operand0]; int32_t field_id = opcode->operand1; SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); int32_t field_offset = field->offset; if (__builtin_expect(object == NULL, 0)) { void* exception = env->new_string_nolen_raw(env, "Invocants of setting fields must not be undefined values"); env->set_exception(env, exception); exception_flag = 1; } else { *(float*)((intptr_t)object + object_header_byte_size + field_offset) = float_vars[opcode->operand2]; } break; } case SPVM_OPCODE_C_ID_SET_FIELD_DOUBLE: { void* object = *(void**)&object_vars[opcode->operand0]; int32_t field_id = opcode->operand1; SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); int32_t field_offset = field->offset; if (__builtin_expect(object == NULL, 0)) { void* exception = env->new_string_nolen_raw(env, "Invocants of setting fields must not be undefined values"); env->set_exception(env, exception); exception_flag = 1; } else { *(double*)((intptr_t)object + object_header_byte_size + field_offset) = double_vars[opcode->operand2]; } break; } case SPVM_OPCODE_C_ID_SET_FIELD_OBJECT: { void* object = *(void**)&object_vars[opcode->operand0]; int32_t field_id = opcode->operand1; SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); int32_t field_offset = field->offset; if (__builtin_expect(object == NULL, 0)) { void* exception = env->new_string_nolen_raw(env, "Invocants of setting fields must not be undefined values"); env->set_exception(env, exception); exception_flag = 1; } else { void* get_field_object_address = (void**)((intptr_t)object + object_header_byte_size + field_offset); SPVM_API_OBJECT_ASSIGN(get_field_object_address, *(void**)&object_vars[opcode->operand2]); } break; } case SPVM_OPCODE_C_ID_SET_FIELD_UNDEF: { void* object = *(void**)&object_vars[opcode->operand0]; int32_t field_id = opcode->operand1; SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); int32_t field_offset = field->offset; if (__builtin_expect(object == NULL, 0)) { void* exception = env->new_string_nolen_raw(env, "Invocants of setting fields must not be undefined values"); env->set_exception(env, exception); exception_flag = 1; } else { void* get_field_object_address = (void**)((intptr_t)object + object_header_byte_size + field_offset); SPVM_API_OBJECT_ASSIGN(get_field_object_address, NULL); } break; } case SPVM_OPCODE_C_ID_WEAKEN_FIELD: { int32_t field_id = opcode->operand1; SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); int32_t field_offset = field->offset; void* object = *(void**)&object_vars[opcode->operand0]; if (object == NULL) { SPVM_OBJECT* exception = env->new_string_nolen_raw(env, "Object to weaken an object field must not be undefined."); env->set_exception(env, exception); exception_flag = 1; } else { void** get_field_object_address = (void**)((intptr_t)object + object_header_byte_size + field_offset); int32_t status = env->weaken(env, get_field_object_address); if (status != 0) { void* exception = env->new_string_nolen_raw(env, "Can't allocate memory for weaken back reference"); env->set_exception(env, exception); exception_flag = 1; } } break; } case SPVM_OPCODE_C_ID_UNWEAKEN_FIELD: { int32_t field_id = opcode->operand1; SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); int32_t field_offset = field->offset; void* object = *(void**)&object_vars[opcode->operand0]; if (object == NULL) { SPVM_OBJECT* exception = env->new_string_nolen_raw(env, "Object to unweaken an object field must not be undefined."); env->set_exception(env, exception); exception_flag = 1; } else { void** get_field_object_address = (void**)((intptr_t)object + object_header_byte_size + field_offset); env->unweaken(env, get_field_object_address); } break; } case SPVM_OPCODE_C_ID_ISWEAK_FIELD: { int32_t field_id = opcode->operand2; SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); int32_t field_offset = field->offset; void* object = *(void**)&object_vars[opcode->operand1]; if (object == NULL) { SPVM_OBJECT* exception = env->new_string_nolen_raw(env, "Object to isweak an object field must not be undefined."); env->set_exception(env, exception); exception_flag = 1; } else { void** get_field_object_address = (void**)((intptr_t)object + object_header_byte_size + field_offset); int_vars[0] = env->isweak(env, get_field_object_address); } break; } case SPVM_OPCODE_C_ID_HAS_IMPLEMENT: { int32_t implement_method_id = opcode->operand2; SPVM_RUNTIME_METHOD* implement_method = SPVM_API_get_method(env, implement_method_id); const char* implement_method_name = SPVM_API_get_constant_string_value(env, implement_method->name_id, NULL); int32_t interface_basic_type_id = opcode->operand3; SPVM_RUNTIME_BASIC_TYPE* interface_basic_type = SPVM_API_get_basic_type(env, interface_basic_type_id); SPVM_RUNTIME_CLASS* interface_class = SPVM_API_get_runtime_class_from_basic_type_id(env, interface_basic_type->id); SPVM_RUNTIME_METHOD* interface_method = SPVM_API_get_runtime_method_from_runtime_class(env, interface_class->id, implement_method_name); const char* implement_method_signature = SPVM_API_get_constant_string_value(env, implement_method->signature_id, NULL); void* object = *(void**)&object_vars[opcode->operand1]; int32_t call_method_id = env->get_instance_method_id(env, object, implement_method_name, implement_method_signature); int_vars[0] = call_method_id >= 0; break; } case SPVM_OPCODE_C_ID_REFCNT: { void* object = object_vars[opcode->operand1]; if (object == NULL) { int_vars[opcode->operand0] = 0; } else { int_vars[opcode->operand0] = env->get_ref_count(env, object); } break; } case SPVM_OPCODE_C_ID_REF_BYTE: *(void**)&ref_vars[opcode->operand0] = &byte_vars[opcode->operand1]; break; case SPVM_OPCODE_C_ID_REF_SHORT: *(void**)&ref_vars[opcode->operand0] = &short_vars[opcode->operand1]; break; case SPVM_OPCODE_C_ID_REF_INT: *(void**)&ref_vars[opcode->operand0] = &int_vars[opcode->operand1]; break; case SPVM_OPCODE_C_ID_REF_LONG: *(void**)&ref_vars[opcode->operand0] = &long_vars[opcode->operand1]; break; case SPVM_OPCODE_C_ID_REF_FLOAT: *(void**)&ref_vars[opcode->operand0] = &float_vars[opcode->operand1]; break; case SPVM_OPCODE_C_ID_REF_DOUBLE: *(void**)&ref_vars[opcode->operand0] = &double_vars[opcode->operand1]; break; case SPVM_OPCODE_C_ID_GET_DEREF_BYTE: { byte_vars[opcode->operand0] = *(int8_t*)*(void**)&ref_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_GET_DEREF_SHORT: { short_vars[opcode->operand0] = *(int16_t*)*(void**)&ref_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_GET_DEREF_INT: { int_vars[opcode->operand0] = *(int32_t*)*(void**)&ref_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_GET_DEREF_LONG: { long_vars[opcode->operand0] = *(int64_t*)*(void**)&ref_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_GET_DEREF_FLOAT: { float_vars[opcode->operand0] = *(float*)*(void**)&ref_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_GET_DEREF_DOUBLE: { double_vars[opcode->operand0] = *(double*)*(void**)&ref_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_SET_DEREF_BYTE: { *(int8_t*)*(void**)&ref_vars[opcode->operand0] = byte_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_SET_DEREF_SHORT: { *(int16_t*)*(void**)&ref_vars[opcode->operand0] = short_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_SET_DEREF_INT: { *(int32_t*)*(void**)&ref_vars[opcode->operand0] = int_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_SET_DEREF_LONG: { *(int64_t*)*(void**)&ref_vars[opcode->operand0] = long_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_SET_DEREF_FLOAT: { *(float*)*(void**)&ref_vars[opcode->operand0] = float_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_SET_DEREF_DOUBLE: { *(double*)*(void**)&ref_vars[opcode->operand0] = double_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_GET_CLASS_VAR_BYTE: { int32_t class_var_id = opcode->operand1; byte_vars[opcode->operand0] = *(int8_t*)&((SPVM_VALUE*)env->class_vars_heap)[class_var_id]; break; } case SPVM_OPCODE_C_ID_GET_CLASS_VAR_SHORT: { int32_t class_var_id = opcode->operand1; short_vars[opcode->operand0] = *(int16_t*)&((SPVM_VALUE*)env->class_vars_heap)[class_var_id]; break; } case SPVM_OPCODE_C_ID_GET_CLASS_VAR_INT: { int32_t class_var_id = opcode->operand1; int_vars[opcode->operand0] = *(int32_t*)&((SPVM_VALUE*)env->class_vars_heap)[class_var_id]; break; } case SPVM_OPCODE_C_ID_GET_CLASS_VAR_LONG: { int32_t class_var_id = opcode->operand1; long_vars[opcode->operand0] = *(int64_t*)&((SPVM_VALUE*)env->class_vars_heap)[class_var_id]; break; } case SPVM_OPCODE_C_ID_GET_CLASS_VAR_FLOAT: { int32_t class_var_id = opcode->operand1; float_vars[opcode->operand0] = *(float*)&((SPVM_VALUE*)env->class_vars_heap)[class_var_id]; break; } case SPVM_OPCODE_C_ID_GET_CLASS_VAR_DOUBLE: { int32_t class_var_id = opcode->operand1; double_vars[opcode->operand0] = *(double*)&((SPVM_VALUE*)env->class_vars_heap)[class_var_id]; break; } case SPVM_OPCODE_C_ID_GET_CLASS_VAR_OBJECT: { int32_t class_var_id = opcode->operand1; SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], *(void**)&((SPVM_VALUE*)env->class_vars_heap)[class_var_id]); break; } case SPVM_OPCODE_C_ID_SET_CLASS_VAR_BYTE: { int32_t class_var_id = opcode->operand0; *(int8_t*)&((SPVM_VALUE*)env->class_vars_heap)[class_var_id] = byte_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_SET_CLASS_VAR_SHORT: { int32_t class_var_id = opcode->operand0; *(int16_t*)&((SPVM_VALUE*)env->class_vars_heap)[class_var_id] = short_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_SET_CLASS_VAR_INT: { int32_t class_var_id = opcode->operand0; *(int32_t*)&((SPVM_VALUE*)env->class_vars_heap)[class_var_id] = int_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_SET_CLASS_VAR_LONG: { int32_t class_var_id = opcode->operand0; *(int64_t*)&((SPVM_VALUE*)env->class_vars_heap)[class_var_id] = long_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_SET_CLASS_VAR_FLOAT: { int32_t class_var_id = opcode->operand0; *(float*)&((SPVM_VALUE*)env->class_vars_heap)[class_var_id] = float_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_SET_CLASS_VAR_DOUBLE: { int32_t class_var_id = opcode->operand0; *(double*)&((SPVM_VALUE*)env->class_vars_heap)[class_var_id] = double_vars[opcode->operand1]; break; } case SPVM_OPCODE_C_ID_SET_CLASS_VAR_OBJECT: { int32_t class_var_id = opcode->operand0; SPVM_API_OBJECT_ASSIGN((void**)&((SPVM_VALUE*)env->class_vars_heap)[class_var_id], *(void**)&object_vars[opcode->operand1]); break; } case SPVM_OPCODE_C_ID_SET_CLASS_VAR_UNDEF: { int32_t class_var_id = opcode->operand0; SPVM_API_OBJECT_ASSIGN((void**)&((SPVM_VALUE*)env->class_vars_heap)[class_var_id], NULL); break; } case SPVM_OPCODE_C_ID_GET_EXCEPTION_VAR: { SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], env->get_exception(env)); break; } case SPVM_OPCODE_C_ID_SET_EXCEPTION_VAR: { env->set_exception(env, *(void**)&object_vars[opcode->operand0]); break; } case SPVM_OPCODE_C_ID_SET_EXCEPTION_VAR_UNDEF: { env->set_exception(env, NULL); break; } case SPVM_OPCODE_C_ID_END_METHOD: { goto label_END_METHOD; } case SPVM_OPCODE_C_ID_CONVERT_BYTE_TO_BYTE_OBJECT: { int8_t value = byte_vars[opcode->operand1]; int32_t basic_type_id = (intptr_t)(void*)env->byte_object_basic_type_id; void* object = env->new_object_raw(env, basic_type_id); SPVM_VALUE* fields = (SPVM_VALUE*)((intptr_t)object + object_header_byte_size); *(int8_t*)&fields[0] = value; SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], object); break; } case SPVM_OPCODE_C_ID_CONVERT_SHORT_TO_SHORT_OBJECT: { int16_t value = short_vars[opcode->operand1]; int32_t basic_type_id = (intptr_t)(void*)env->short_object_basic_type_id; void* object = env->new_object_raw(env, basic_type_id); SPVM_VALUE* fields = (SPVM_VALUE*)((intptr_t)object + object_header_byte_size); *(int16_t*)&fields[0] = value; SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], object); break; } case SPVM_OPCODE_C_ID_CONVERT_INT_TO_INT_OBJECT: { int32_t value = int_vars[opcode->operand1]; int32_t basic_type_id = (intptr_t)(void*)env->int_object_basic_type_id; void* object = env->new_object_raw(env, basic_type_id); SPVM_VALUE* fields = (SPVM_VALUE*)((intptr_t)object + object_header_byte_size); *(int32_t*)&fields[0] = value; SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], object); break; } case SPVM_OPCODE_C_ID_CONVERT_LONG_TO_LONG_OBJECT: { int64_t value = long_vars[opcode->operand1]; int32_t basic_type_id = (intptr_t)(void*)env->long_object_basic_type_id; void* object = env->new_object_raw(env, basic_type_id); SPVM_VALUE* fields = (SPVM_VALUE*)((intptr_t)object + object_header_byte_size); *(int64_t*)&fields[0] = value; SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], object); break; } case SPVM_OPCODE_C_ID_CONVERT_FLOAT_TO_FLOAT_OBJECT: { float value = float_vars[opcode->operand1]; int32_t basic_type_id = (intptr_t)(void*)env->float_object_basic_type_id; void* object = env->new_object_raw(env, basic_type_id); SPVM_VALUE* fields = (SPVM_VALUE*)((intptr_t)object + object_header_byte_size); *(float*)&fields[0] = value; SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], object); break; } case SPVM_OPCODE_C_ID_CONVERT_DOUBLE_TO_DOUBLE_OBJECT: { double value = double_vars[opcode->operand1]; int32_t basic_type_id = (intptr_t)(void*)env->double_object_basic_type_id; void* object = env->new_object_raw(env, basic_type_id); SPVM_VALUE* fields = (SPVM_VALUE*)((intptr_t)object + object_header_byte_size); *(double*)&fields[0] = value; SPVM_API_OBJECT_ASSIGN((void**)&object_vars[opcode->operand0], object); break; } case SPVM_OPCODE_C_ID_CONVERT_BYTE_OBJECT_TO_BYTE: { void* object = *(void**)&object_vars[opcode->operand1]; if (object == NULL) { void* exception = env->new_string_nolen_raw(env, "Can't convert undef value."); env->set_exception(env, exception); exception_flag = 1; } else { int32_t object_basic_type_id = *(int32_t*)((intptr_t)object + (intptr_t)env->object_basic_type_id_offset); int32_t object_type_dimension = *(uint8_t*)((intptr_t)object + (intptr_t)env->object_type_dimension_offset); if (object_basic_type_id == (intptr_t)(void*)env->byte_object_basic_type_id && object_type_dimension == 0) { SPVM_VALUE* fields = (SPVM_VALUE*)((intptr_t)object + object_header_byte_size); byte_vars[opcode->operand0] = *(int8_t*)&fields[0]; } else { void* exception = env->new_string_nolen_raw(env, "Can't convert imcompatible object type from Byte to byte."); env->set_exception(env, exception); exception_flag = 1; } } break; } case SPVM_OPCODE_C_ID_CONVERT_SHORT_OBJECT_TO_SHORT: { void* object = *(void**)&object_vars[opcode->operand1]; if (object == NULL) { void* exception = env->new_string_nolen_raw(env, "Can't convert undef value."); env->set_exception(env, exception); exception_flag = 1; } else { int32_t object_basic_type_id = *(int32_t*)((intptr_t)object + (intptr_t)env->object_basic_type_id_offset); int32_t object_type_dimension = *(uint8_t*)((intptr_t)object + (intptr_t)env->object_type_dimension_offset); if (object_basic_type_id == (intptr_t)(void*)env->short_object_basic_type_id && object_type_dimension == 0) { SPVM_VALUE* fields = (SPVM_VALUE*)((intptr_t)object + object_header_byte_size); short_vars[opcode->operand0] = *(int16_t*)&fields[0]; } else { void* exception = env->new_string_nolen_raw(env, "Can't convert imcompatible object type from Short to short."); env->set_exception(env, exception); exception_flag = 1; } } break; } case SPVM_OPCODE_C_ID_CONVERT_INT_OBJECT_TO_INT: { void* object = *(void**)&object_vars[opcode->operand1]; if (object == NULL) { void* exception = env->new_string_nolen_raw(env, "Can't convert undef value."); env->set_exception(env, exception); exception_flag = 1; } else { int32_t object_basic_type_id = *(int32_t*)((intptr_t)object + (intptr_t)env->object_basic_type_id_offset); int32_t object_type_dimension = *(uint8_t*)((intptr_t)object + (intptr_t)env->object_type_dimension_offset); if (object_basic_type_id == (intptr_t)(void*)env->int_object_basic_type_id && object_type_dimension == 0) { SPVM_VALUE* fields = (SPVM_VALUE*)((intptr_t)object + object_header_byte_size); int_vars[opcode->operand0] = *(int32_t*)&fields[0]; } else { void* exception = env->new_string_nolen_raw(env, "Can't convert imcompatible object type from Int to int."); env->set_exception(env, exception); exception_flag = 1; } } break; } case SPVM_OPCODE_C_ID_CONVERT_LONG_OBJECT_TO_LONG: { void* object = *(void**)&object_vars[opcode->operand1]; if (object == NULL) { void* exception = env->new_string_nolen_raw(env, "Can't convert undef value."); env->set_exception(env, exception); exception_flag = 1; } else { int32_t object_basic_type_id = *(int32_t*)((intptr_t)object + (intptr_t)env->object_basic_type_id_offset); int32_t object_type_dimension = *(uint8_t*)((intptr_t)object + (intptr_t)env->object_type_dimension_offset); if (object_basic_type_id == (intptr_t)(void*)env->long_object_basic_type_id && object_type_dimension == 0) { SPVM_VALUE* fields = (SPVM_VALUE*)((intptr_t)object + object_header_byte_size); long_vars[opcode->operand0] = *(int64_t*)&fields[0]; } else { void* exception = env->new_string_nolen_raw(env, "Can't convert imcompatible object type from Long to long."); env->set_exception(env, exception); exception_flag = 1; } } break; } case SPVM_OPCODE_C_ID_CONVERT_FLOAT_OBJECT_TO_FLOAT: { void* object = *(void**)&object_vars[opcode->operand1]; if (object == NULL) { void* exception = env->new_string_nolen_raw(env, "Can't convert undef value."); env->set_exception(env, exception); exception_flag = 1; } else { int32_t object_basic_type_id = *(int32_t*)((intptr_t)object + (intptr_t)env->object_basic_type_id_offset); int32_t object_type_dimension = *(uint8_t*)((intptr_t)object + (intptr_t)env->object_type_dimension_offset); if (object_basic_type_id == (intptr_t)(void*)env->float_object_basic_type_id && object_type_dimension == 0) { SPVM_VALUE* fields = (SPVM_VALUE*)((intptr_t)object + object_header_byte_size); float_vars[opcode->operand0] = *(float*)&fields[0]; } else { void* exception = env->new_string_nolen_raw(env, "Can't convert imcompatible object type from Float to float."); env->set_exception(env, exception); exception_flag = 1; } } break; } case SPVM_OPCODE_C_ID_CONVERT_DOUBLE_OBJECT_TO_DOUBLE: { void* object = *(void**)&object_vars[opcode->operand1]; if (object == NULL) { void* exception = env->new_string_nolen_raw(env, "Can't convert undef value."); env->set_exception(env, exception); exception_flag = 1; } else { int32_t object_basic_type_id = *(int32_t*)((intptr_t)object + (intptr_t)env->object_basic_type_id_offset); int32_t object_type_dimension = *(uint8_t*)((intptr_t)object + (intptr_t)env->object_type_dimension_offset); if (object_basic_type_id == (intptr_t)(void*)env->double_object_basic_type_id && object_type_dimension == 0) { SPVM_VALUE* fields = (SPVM_VALUE*)((intptr_t)object + object_header_byte_size); double_vars[opcode->operand0] = *(double*)&fields[0]; } else { void* exception = env->new_string_nolen_raw(env, "Can't convert imcompatible object type from Double to double."); env->set_exception(env, exception); exception_flag = 1; } } break; } } opcode_rel_index++; } label_END_METHOD: // Decrement ref count of return value if (!exception_flag) { SPVM_RUNTIME_TYPE* method_return_type = SPVM_API_get_type(env, method->return_type_id); switch (method_return_type->category) { case SPVM_TYPE_C_TYPE_CATEGORY_ANY_OBJECT: case SPVM_TYPE_C_TYPE_CATEGORY_CLASS: case SPVM_TYPE_C_TYPE_CATEGORY_NUMERIC_ARRAY: case SPVM_TYPE_C_TYPE_CATEGORY_MULNUM_ARRAY: case SPVM_TYPE_C_TYPE_CATEGORY_OBJECT_ARRAY: case SPVM_TYPE_C_TYPE_CATEGORY_STRING: { if (*(void**)&stack[0] != NULL) { SPVM_API_DEC_REF_COUNT_ONLY(*(void**)&stack[0]); } } } } SPVM_API_free_memory_block(env, call_stack); call_stack = NULL; return exception_flag; } int32_t SPVM_API_is_type(SPVM_ENV* env, SPVM_OBJECT* object, int32_t basic_type_id, int32_t type_dimension) { // Object must be not null assert(object); if (object->basic_type_id == basic_type_id && object->type_dimension == type_dimension) { return 1; } else { return 0; } } int32_t SPVM_API_is_array(SPVM_ENV* env, SPVM_OBJECT* object) { int32_t is_array; if (object) { is_array = object->type_dimension > 0; } else { is_array = 0; } return is_array; } int32_t SPVM_API_is_string(SPVM_ENV* env, SPVM_OBJECT* object) { int32_t is_string; if (object) { is_string = object->type_category == SPVM_TYPE_C_TYPE_CATEGORY_STRING; } else { is_string = 0; } return is_string; } int32_t SPVM_API_is_numeric_array(SPVM_ENV* env, SPVM_OBJECT* object) { int32_t is_numeric_array; if (object) { is_numeric_array = object->type_category == SPVM_TYPE_C_TYPE_CATEGORY_NUMERIC_ARRAY; } else { is_numeric_array = 0; } return is_numeric_array; } int32_t SPVM_API_is_object_array(SPVM_ENV* env, SPVM_OBJECT* object) { int32_t is_object_array; if (object) { is_object_array = object->type_category == SPVM_TYPE_C_TYPE_CATEGORY_OBJECT_ARRAY; } else { is_object_array = 0; } return is_object_array; } int32_t SPVM_API_is_mulnum_array(SPVM_ENV* env, SPVM_OBJECT* object) { int32_t is_mulnum_array; if (object) { is_mulnum_array = object->type_category == SPVM_TYPE_C_TYPE_CATEGORY_MULNUM_ARRAY; } else { is_mulnum_array = 0; } return is_mulnum_array; } int32_t SPVM_API_get_elem_byte_size(SPVM_ENV* env, SPVM_OBJECT* array) { SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; int32_t elem_byte_size; if (array) { if (SPVM_API_is_string(env, array)) { elem_byte_size = 1; } else if (SPVM_API_is_object_array(env, array)) { elem_byte_size = sizeof(void*); } else if (SPVM_API_is_numeric_array(env, array)) { int32_t basic_type_id = array->basic_type_id; int32_t type_dimension = array->type_dimension; assert(type_dimension == 1); SPVM_RUNTIME_BASIC_TYPE* basic_type = SPVM_API_get_basic_type(env, basic_type_id); if (basic_type_id == SPVM_BASIC_TYPE_C_ID_BYTE) { elem_byte_size = 1; } else if (basic_type_id == SPVM_BASIC_TYPE_C_ID_SHORT) { elem_byte_size = 2; } else if (basic_type_id == SPVM_BASIC_TYPE_C_ID_INT || basic_type_id == SPVM_BASIC_TYPE_C_ID_FLOAT) { elem_byte_size = 4; } else if (basic_type_id == SPVM_BASIC_TYPE_C_ID_LONG || basic_type_id == SPVM_BASIC_TYPE_C_ID_DOUBLE) { elem_byte_size = 8; } else { assert(0); } } else if (SPVM_API_is_mulnum_array(env, array)) { int32_t basic_type_id = array->basic_type_id; int32_t type_dimension = array->type_dimension; assert(type_dimension == 1); SPVM_RUNTIME_BASIC_TYPE* basic_type = SPVM_API_get_basic_type(env, basic_type_id); assert(basic_type->class_id > -1); SPVM_RUNTIME_CLASS* class = SPVM_API_get_class(env, basic_type->class_id); int32_t width = class->field_ids_length; SPVM_RUNTIME_FIELD* first_field = SPVM_API_get_runtime_field_from_index(env, class->id, 0); int32_t first_field_type_id = first_field->type_id; assert(first_field_type_id > -1); SPVM_RUNTIME_TYPE* first_field_type = SPVM_API_get_type(env, first_field_type_id); int32_t field_basic_type_id = first_field_type->basic_type_id; if (field_basic_type_id == SPVM_BASIC_TYPE_C_ID_BYTE) { elem_byte_size = 1 * width; } else if (field_basic_type_id == SPVM_BASIC_TYPE_C_ID_SHORT) { elem_byte_size = 2 * width; } else if (field_basic_type_id == SPVM_BASIC_TYPE_C_ID_INT || field_basic_type_id == SPVM_BASIC_TYPE_C_ID_FLOAT) { elem_byte_size = 4 * width; } else if (field_basic_type_id == SPVM_BASIC_TYPE_C_ID_LONG || field_basic_type_id == SPVM_BASIC_TYPE_C_ID_DOUBLE) { elem_byte_size = 8 * width; } else { assert(0); } } } else { elem_byte_size = 0; } return elem_byte_size; } int32_t SPVM_API_has_callback(SPVM_ENV* env, SPVM_OBJECT* object, int32_t callback_basic_type_id) { (void)env; SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; // Object must be not null assert(object); int32_t class_basic_type_id = object->basic_type_id; int32_t class_type_dimension = object->type_dimension; int32_t has_callback; if (class_type_dimension > 0) { return 0; } SPVM_RUNTIME_BASIC_TYPE* class_basic_type = SPVM_API_get_basic_type(env, class_basic_type_id); SPVM_RUNTIME_BASIC_TYPE* callback_basic_type = SPVM_API_get_basic_type(env, callback_basic_type_id); if (class_basic_type->class_id < 0) { return 0; } if (callback_basic_type->class_id < 0) { return 0; } SPVM_RUNTIME_CLASS* class = SPVM_API_get_class(env, class_basic_type->class_id); SPVM_RUNTIME_CLASS* callback = SPVM_API_get_class(env, callback_basic_type->class_id); // Class which have only anon sub if (class->flag & SPVM_CLASS_C_FLAG_ANON_METHOD_CLASS) { assert(class->method_ids_length == 1); assert(callback->method_ids_length == 1); SPVM_RUNTIME_METHOD* found_method = SPVM_API_get_runtime_method_from_index(env, class->id, 0); SPVM_RUNTIME_METHOD* method_callback = SPVM_API_get_runtime_method_from_index(env, callback->id, 0); const char* method_callback_signature = SPVM_API_get_constant_string_value(env, method_callback->signature_id, NULL); const char* found_method_signature = SPVM_API_get_constant_string_value(env, found_method->signature_id, NULL); if (strcmp(method_callback_signature, found_method_signature) == 0) { return 1; } else { return 0; } } // Normal class else { assert(callback->method_ids_length == 1); SPVM_RUNTIME_METHOD* method_callback = SPVM_API_get_runtime_method_from_index(env, callback->id, 0); const char* method_callback_name = SPVM_API_get_constant_string_value(env, method_callback->name_id, NULL); SPVM_RUNTIME_METHOD* found_method = SPVM_API_get_runtime_method_from_runtime_class(env, class->id, method_callback_name); if (!found_method) { return 0; } const char* method_callback_signature = SPVM_API_get_constant_string_value(env, method_callback->signature_id, NULL); const char* found_method_signature = SPVM_API_get_constant_string_value(env, found_method->signature_id, NULL); if (strcmp(method_callback_signature, found_method_signature) == 0) { return 1; } else { return 0; } } return has_callback; } int32_t SPVM_API_has_interface(SPVM_ENV* env, SPVM_OBJECT* object, int32_t interface_basic_type_id) { (void)env; SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; // Object must be not null assert(object); int32_t class_basic_type_id = object->basic_type_id; int32_t class_type_dimension = object->type_dimension; int32_t has_interface; if (class_type_dimension > 0) { return 0; } SPVM_RUNTIME_BASIC_TYPE* class_basic_type = SPVM_API_get_basic_type(env, class_basic_type_id); SPVM_RUNTIME_BASIC_TYPE* interface_basic_type = SPVM_API_get_basic_type(env, interface_basic_type_id); if (class_basic_type->class_id < 0) { return 0; } if (interface_basic_type->class_id < 0) { return 0; } SPVM_RUNTIME_CLASS* class = SPVM_API_get_class(env, class_basic_type->class_id); SPVM_RUNTIME_CLASS* interface = SPVM_API_get_class(env, interface_basic_type->class_id); if (class->id, interface->id) { return 1; } for (int32_t i = 0; i < class->interface_class_ids_length; i++) { int32_t must_implement_class_id = class->interface_class_ids_base + i; if (must_implement_class_id == interface->id) { return 1; } } return 0; } int32_t SPVM_API_enter_scope(SPVM_ENV* env) { (void)env; int32_t mortal_stack_top = (intptr_t)env->native_mortal_stack_top; return mortal_stack_top; } int32_t SPVM_API_push_mortal(SPVM_ENV* env, SPVM_OBJECT* object) { (void)env; if (object != NULL) { // Extend mortal stack if (env->native_mortal_stack_top >= env->native_mortal_stack_capacity) { int32_t new_mortal_stack_capacity = (intptr_t)env->native_mortal_stack_capacity * 2; SPVM_OBJECT** new_mortal_stack = SPVM_API_alloc_memory_block_zero(env, sizeof(void*) * new_mortal_stack_capacity); if (new_mortal_stack == NULL) { return 1; } memcpy(new_mortal_stack, env->native_mortal_stack, sizeof(void*) * (intptr_t)env->native_mortal_stack_capacity); env->native_mortal_stack_capacity = (void*)(intptr_t)new_mortal_stack_capacity; SPVM_API_free_memory_block(env, env->native_mortal_stack); env->native_mortal_stack = NULL; env->native_mortal_stack = new_mortal_stack; } ((SPVM_OBJECT**)(env->native_mortal_stack))[(intptr_t)env->native_mortal_stack_top] = object; env->native_mortal_stack_top = (void*)((intptr_t)env->native_mortal_stack_top + 1); object->ref_count++; } return 0; } SPVM_OBJECT* SPVM_API_get_type_name_raw(SPVM_ENV* env, SPVM_OBJECT* object) { (void)env; assert(object); SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; int32_t basic_type_id = object->basic_type_id; int32_t type_dimension = object->type_dimension; SPVM_RUNTIME_BASIC_TYPE* basic_type = SPVM_API_get_basic_type(env, basic_type_id); const char* basic_type_name = SPVM_API_get_basic_type_name(env, basic_type->id); int32_t length = 0; // Basic type length += strlen(basic_type_name); //[] length += type_dimension * 2; int32_t scope_id = env->enter_scope(env); void* type_name_byte_array = env->new_byte_array(env, length + 1); char* cur = SPVM_API_alloc_memory_block_zero(env, length + 1); int32_t cur_index = 0; sprintf((char*)cur, "%s", basic_type_name); cur_index += strlen(basic_type_name); int32_t dim_index; for (dim_index = 0; dim_index < type_dimension; dim_index++) { sprintf((char*)(cur + cur_index), "[]"); cur_index += 2; } void* sv_type_name = env->new_string_raw(env, (const char*)cur, length); SPVM_API_free_memory_block(env, cur); env->leave_scope(env, scope_id); return sv_type_name; } SPVM_OBJECT* SPVM_API_get_type_name(SPVM_ENV* env, SPVM_OBJECT* object_in) { (void)env; SPVM_OBJECT* object = SPVM_API_get_type_name_raw(env, object_in); SPVM_API_push_mortal(env, object); return object; } void SPVM_API_leave_scope(SPVM_ENV* env, int32_t original_mortal_stack_top) { (void)env; int32_t mortal_stack_index; for (mortal_stack_index = original_mortal_stack_top; mortal_stack_index < (intptr_t)env->native_mortal_stack_top; mortal_stack_index++) { SPVM_OBJECT* object = ((SPVM_OBJECT**)(env->native_mortal_stack))[mortal_stack_index]; if (object != NULL) { if (object->ref_count > 1) { object->ref_count--; } else { SPVM_API_dec_ref_count(env, object); } } ((SPVM_OBJECT**)(env->native_mortal_stack))[mortal_stack_index] = NULL; } env->native_mortal_stack_top = (void*)(intptr_t)original_mortal_stack_top; } SPVM_OBJECT* SPVM_API_new_stack_trace_raw(SPVM_ENV* env, SPVM_OBJECT* exception, const char* class_name, const char* method_name, const char* file, int32_t line) { // stack trace symbols const char* new_line_part = "\n "; const char* arrow_part = "->"; const char* at_part = " at "; // Exception const char* exception_bytes = env->get_chars(env, exception); int32_t exception_length = env->length(env, exception); // Total string length int32_t total_length = 0; total_length += exception_length; total_length += strlen(new_line_part); total_length += strlen(class_name); total_length += strlen(arrow_part); total_length += strlen(method_name); total_length += strlen(at_part); total_length += strlen(file); const char* line_part = " line "; char line_str[20]; sprintf(line_str, "%" PRId32, line); total_length += strlen(line_part); total_length += strlen(line_str); // Create exception message void* new_exception = env->new_string_raw(env, NULL, total_length); const char* new_exception_bytes = env->get_chars(env, new_exception); memcpy( (void*)(new_exception_bytes), (void*)(exception_bytes), exception_length ); sprintf( (char*)new_exception_bytes + exception_length, "%s%s%s%s%s%s%s%" PRId32, new_line_part, class_name, arrow_part, method_name, at_part, file, line_part, line ); return new_exception; } SPVM_OBJECT* SPVM_API_new_stack_trace(SPVM_ENV* env, SPVM_OBJECT* exception, const char* class_name, const char* method_name, const char* file, int32_t line) { (void)env; SPVM_OBJECT* str = SPVM_API_new_stack_trace_raw(env, exception, class_name, method_name, file, line); SPVM_API_push_mortal(env, str); return str; } void SPVM_API_fprint(SPVM_ENV* env, FILE* fh, SPVM_OBJECT* string) { (void)env; if (string == NULL) { return; } const char* bytes = env->get_chars(env, string); int32_t string_length = env->length(env, string); { int32_t i; for (i = 0; i < string_length; i++) { putc((char)bytes[i], fh); } } } void SPVM_API_print(SPVM_ENV* env, SPVM_OBJECT* string) { (void)env; SPVM_API_fprint(env, stdout, string); } void SPVM_API_print_stderr(SPVM_ENV* env, SPVM_OBJECT* string) { (void)env; SPVM_API_fprint(env, stderr, string); } SPVM_OBJECT* SPVM_API_concat_raw(SPVM_ENV* env, SPVM_OBJECT* string1, SPVM_OBJECT* string2) { (void)env; int32_t string1_length = SPVM_API_length(env, string1); int32_t string2_length = SPVM_API_length(env, string2); int32_t string3_length = string1_length + string2_length; SPVM_OBJECT* string3 = SPVM_API_new_byte_array_raw(env, string3_length); string3->basic_type_id = SPVM_BASIC_TYPE_C_ID_STRING; string3->type_dimension = 0; string3->type_category = SPVM_TYPE_C_TYPE_CATEGORY_STRING; const char* string1_bytes = SPVM_API_get_chars(env, string1); const char* string2_bytes = SPVM_API_get_chars(env, string2); char* string3_bytes = (char*)SPVM_API_get_chars(env, string3); if (string1_length > 0) { memcpy(string3_bytes, string1_bytes, string1_length); } if (string2_length) { memcpy(string3_bytes + string1_length, string2_bytes, string2_length); } return string3; } SPVM_OBJECT* SPVM_API_concat(SPVM_ENV* env, SPVM_OBJECT* string1, SPVM_OBJECT* string2) { (void)env; SPVM_OBJECT* str = SPVM_API_concat_raw(env, string1, string2); SPVM_API_push_mortal(env, str); return str; } int32_t SPVM_API_get_memory_blocks_count(SPVM_ENV* env) { (void)env; SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; SPVM_ALLOCATOR* allocator = runtime_info->allocator; int32_t memory_blocks_count = SPVM_ALLOCATOR_get_memory_blocks_count(allocator); return memory_blocks_count; } void SPVM_API_free_weaken_back_refs(SPVM_ENV* env, SPVM_WEAKEN_BACKREF* weaken_backref_head) { (void)env; SPVM_WEAKEN_BACKREF* weaken_backref_head_cur = weaken_backref_head; SPVM_WEAKEN_BACKREF* weaken_backref_head_next = NULL; while (weaken_backref_head_cur != NULL){ *(weaken_backref_head_cur->object_address) = NULL; weaken_backref_head_next = weaken_backref_head_cur->next; SPVM_API_free_memory_block(env, weaken_backref_head_cur); weaken_backref_head_cur = NULL; weaken_backref_head_cur = weaken_backref_head_next; } } int32_t SPVM_API_isweak(SPVM_ENV* env, SPVM_OBJECT** object_address) { (void)env; int32_t isweak = (intptr_t)*object_address & 1; return isweak; } int32_t SPVM_API_weaken(SPVM_ENV* env, SPVM_OBJECT** object_address) { (void)env; assert(object_address); if (*object_address == NULL) { return 0; } if (SPVM_API_isweak(env, object_address)) { return 0; } SPVM_OBJECT* object = *object_address; // Decrelement reference count if (object->ref_count == 1) { // If reference count is 1, the object is freeed without weaken SPVM_API_dec_ref_count(env, *object_address); *object_address = NULL; return 0; } else { object->ref_count--; } // Create weaken_backref_head if (object->weaken_backref_head == NULL) { SPVM_WEAKEN_BACKREF* new_weaken_backref = SPVM_API_alloc_memory_block_zero(env, sizeof(SPVM_WEAKEN_BACKREF)); if (new_weaken_backref == NULL) { return 1; } new_weaken_backref->object_address = object_address; object->weaken_backref_head = new_weaken_backref; } // Add weaken_back_ref else { SPVM_WEAKEN_BACKREF* weaken_backref_next = object->weaken_backref_head; SPVM_WEAKEN_BACKREF* new_weaken_backref = SPVM_API_alloc_memory_block_zero(env, sizeof(SPVM_WEAKEN_BACKREF)); if (new_weaken_backref) { return 1; } new_weaken_backref->object_address = object_address; while (weaken_backref_next->next != NULL){ weaken_backref_next = weaken_backref_next->next; } weaken_backref_next->next = new_weaken_backref; } // Weaken is implemented by tag pointer. // If pointer most right bit is 1, object is weaken. *object_address = (SPVM_OBJECT*)((intptr_t)*object_address | 1); return 0; } void SPVM_API_unweaken(SPVM_ENV* env, SPVM_OBJECT** object_address) { (void)env; assert(object_address); if (*object_address == NULL) { return; } if (!SPVM_API_isweak(env, object_address)) { return; } // Unweaken *object_address = (SPVM_OBJECT*)((intptr_t)*object_address & ~(intptr_t)1); SPVM_OBJECT* object = *object_address; // Increment reference count object->ref_count++; // Remove weaken back ref SPVM_WEAKEN_BACKREF** weaken_backref_next_address = &object->weaken_backref_head; assert(*weaken_backref_next_address); int32_t pass_one = 0; while (*weaken_backref_next_address != NULL){ if ((*weaken_backref_next_address)->object_address == object_address) { pass_one++; SPVM_WEAKEN_BACKREF* tmp = (*weaken_backref_next_address)->next; SPVM_API_free_memory_block(env, *weaken_backref_next_address); *weaken_backref_next_address = NULL; *weaken_backref_next_address = tmp; break; } *weaken_backref_next_address = (*weaken_backref_next_address)->next; } assert(pass_one == 1); } int32_t SPVM_API_set_exception(SPVM_ENV* env, SPVM_OBJECT* exception) { if (env->exception_object != NULL) { SPVM_API_dec_ref_count(env, (SPVM_OBJECT*)env->exception_object); } SPVM_API_OBJECT_ASSIGN(&env->exception_object, exception); if (env->exception_object != NULL) { ((SPVM_OBJECT*)env->exception_object)->ref_count++; } return 1; } SPVM_OBJECT* SPVM_API_exception(SPVM_ENV* env) { (void)env; return env->exception_object; } SPVM_OBJECT* SPVM_API_new_byte_array(SPVM_ENV* env, int32_t length) { (void)env; SPVM_OBJECT* object = SPVM_API_new_byte_array_raw(env, length); SPVM_API_push_mortal(env, object); return object; } SPVM_OBJECT* SPVM_API_new_short_array(SPVM_ENV* env, int32_t length) { (void)env; SPVM_OBJECT* object = SPVM_API_new_short_array_raw(env, length); SPVM_API_push_mortal(env, object); return object; } SPVM_OBJECT* SPVM_API_new_int_array(SPVM_ENV* env, int32_t length) { (void)env; SPVM_OBJECT* object = SPVM_API_new_int_array_raw(env, length); SPVM_API_push_mortal(env, object); return object; } SPVM_OBJECT* SPVM_API_new_long_array(SPVM_ENV* env, int32_t length) { (void)env; SPVM_OBJECT* object = SPVM_API_new_long_array_raw(env, length); SPVM_API_push_mortal(env, object); return object; } SPVM_OBJECT* SPVM_API_new_float_array(SPVM_ENV* env, int32_t length) { (void)env; SPVM_OBJECT* object = SPVM_API_new_float_array_raw(env, length); SPVM_API_push_mortal(env, object); return object; } SPVM_OBJECT* SPVM_API_new_double_array(SPVM_ENV* env, int32_t length) { (void)env; SPVM_OBJECT* object = SPVM_API_new_double_array_raw(env, length); SPVM_API_push_mortal(env, object); return object; } SPVM_OBJECT* SPVM_API_new_object_array(SPVM_ENV* env, int32_t basic_type_id, int32_t length) { (void)env; SPVM_OBJECT* object = SPVM_API_new_object_array_raw(env, basic_type_id, length); SPVM_API_push_mortal(env, object); return object; } SPVM_OBJECT* SPVM_API_new_muldim_array(SPVM_ENV* env, int32_t basic_type_id, int32_t element_dimension, int32_t length) { (void)env; SPVM_OBJECT* object = SPVM_API_new_muldim_array_raw(env, basic_type_id, element_dimension, length); SPVM_API_push_mortal(env, object); return object; } SPVM_OBJECT* SPVM_API_new_mulnum_array(SPVM_ENV* env, int32_t basic_type_id, int32_t length) { (void)env; SPVM_OBJECT* object = SPVM_API_new_mulnum_array_raw(env, basic_type_id, length); SPVM_API_push_mortal(env, object); return object; } SPVM_OBJECT* SPVM_API_new_object(SPVM_ENV* env, int32_t basic_type_id) { (void)env; SPVM_OBJECT* object = SPVM_API_new_object_raw(env, basic_type_id); SPVM_API_push_mortal(env, object); return object; } SPVM_OBJECT* SPVM_API_new_pointer(SPVM_ENV* env, int32_t basic_type_id, void* pointer) { (void)env; SPVM_OBJECT* object = SPVM_API_new_pointer_raw(env, basic_type_id, pointer); SPVM_API_push_mortal(env, object); return object; } SPVM_OBJECT* SPVM_API_new_string_nolen_raw(SPVM_ENV* env, const char* bytes) { (void)env; int32_t length = strlen((char*)bytes); SPVM_OBJECT* object = SPVM_API_new_byte_array_raw(env, length); object->basic_type_id = SPVM_BASIC_TYPE_C_ID_STRING; object->type_dimension = 0; object->type_category = SPVM_TYPE_C_TYPE_CATEGORY_STRING; if (bytes != NULL && length > 0) { memcpy((void*)((intptr_t)object + env->object_header_byte_size), (char*)bytes, length); } return object; } SPVM_OBJECT* SPVM_API_new_string_nolen(SPVM_ENV* env, const char* bytes) { (void)env; SPVM_OBJECT* object = SPVM_API_new_string_nolen_raw(env, bytes); SPVM_API_push_mortal(env, object); return object; } SPVM_OBJECT* SPVM_API_new_string_raw(SPVM_ENV* env, const char* bytes, int32_t length) { (void)env; SPVM_OBJECT* object = SPVM_API_new_byte_array_raw(env, length); object->basic_type_id = SPVM_BASIC_TYPE_C_ID_STRING; object->type_dimension = 0; object->type_category = SPVM_TYPE_C_TYPE_CATEGORY_STRING; if (bytes != NULL && length > 0) { memcpy((void*)((intptr_t)object + env->object_header_byte_size), (char*)bytes, length); } return object; } int32_t SPVM_API_get_filed_first_int(SPVM_ENV* env, SPVM_OBJECT* object) { int32_t value = *(int32_t*)((intptr_t)object + env->object_header_byte_size); return value; } int32_t SPVM_API_get_bool_object_value(SPVM_ENV* env, SPVM_OBJECT* bool_object) { (void)env; int32_t value = SPVM_API_get_filed_first_int(env, bool_object); return value; } SPVM_OBJECT* SPVM_API_new_string(SPVM_ENV* env, const char* bytes, int32_t length) { (void)env; SPVM_OBJECT* object = SPVM_API_new_string_raw(env, bytes, length); SPVM_API_push_mortal(env, object); return object; } SPVM_OBJECT* SPVM_API_new_byte_array_raw(SPVM_ENV* env, int32_t length) { (void)env; // If lenght is less than 0, return NULL. if (length < 0) { return NULL; } int64_t alloc_byte_size = (intptr_t)env->object_header_byte_size + sizeof(int8_t) * ((int64_t)length + 1); // Create object SPVM_OBJECT* object = SPVM_API_alloc_memory_block_zero(env, alloc_byte_size); if (!object) { return NULL; } object->type_dimension = 1; object->basic_type_id = SPVM_BASIC_TYPE_C_ID_BYTE; object->length = length; object->type_category = SPVM_TYPE_C_TYPE_CATEGORY_NUMERIC_ARRAY; return object; } SPVM_OBJECT* SPVM_API_new_short_array_raw(SPVM_ENV* env, int32_t length) { (void)env; int64_t alloc_byte_size = (intptr_t)env->object_header_byte_size + sizeof(int16_t) * ((int64_t)length + 1); // Create object SPVM_OBJECT* object = SPVM_API_alloc_memory_block_zero(env, alloc_byte_size); if (!object) { return NULL; } object->type_dimension = 1; object->basic_type_id = SPVM_BASIC_TYPE_C_ID_SHORT; // Set array length object->length = length; object->type_category = SPVM_TYPE_C_TYPE_CATEGORY_NUMERIC_ARRAY; return object; } SPVM_OBJECT* SPVM_API_new_int_array_raw(SPVM_ENV* env, int32_t length) { (void)env; int64_t alloc_byte_size = (intptr_t)env->object_header_byte_size + sizeof(int32_t) * ((int64_t)length + 1); // Create object SPVM_OBJECT* object = SPVM_API_alloc_memory_block_zero(env, alloc_byte_size); if (!object) { return NULL; } object->type_dimension = 1; object->basic_type_id = SPVM_BASIC_TYPE_C_ID_INT; // Set array length object->length = length; object->type_category = SPVM_TYPE_C_TYPE_CATEGORY_NUMERIC_ARRAY; return object; } SPVM_OBJECT* SPVM_API_new_long_array_raw(SPVM_ENV* env, int32_t length) { (void)env; if (length < 0) { return NULL; } int64_t alloc_byte_size = (intptr_t)env->object_header_byte_size + sizeof(int64_t) * ((int64_t)length + 1); // Create object SPVM_OBJECT* object = SPVM_API_alloc_memory_block_zero(env, alloc_byte_size); if (!object) { return NULL; } object->type_dimension = 1; object->basic_type_id = SPVM_BASIC_TYPE_C_ID_LONG; // Set array length object->length = length; object->type_category = SPVM_TYPE_C_TYPE_CATEGORY_NUMERIC_ARRAY; return object; } SPVM_OBJECT* SPVM_API_new_float_array_raw(SPVM_ENV* env, int32_t length) { (void)env; int64_t alloc_byte_size = (intptr_t)env->object_header_byte_size + sizeof(float) * ((int64_t)length + 1); // Create object SPVM_OBJECT* object = SPVM_API_alloc_memory_block_zero(env, alloc_byte_size); if (!object) { return NULL; } object->type_dimension = 1; object->basic_type_id = SPVM_BASIC_TYPE_C_ID_FLOAT; // Set array length object->length = length; object->type_category = SPVM_TYPE_C_TYPE_CATEGORY_NUMERIC_ARRAY; return object; } SPVM_OBJECT* SPVM_API_new_double_array_raw(SPVM_ENV* env, int32_t length) { (void)env; int64_t alloc_byte_size = (intptr_t)env->object_header_byte_size + sizeof(double) * ((int64_t)length + 1); // Create object SPVM_OBJECT* object = SPVM_API_alloc_memory_block_zero(env, alloc_byte_size); if (!object) { return NULL; } object->type_dimension = 1; object->basic_type_id = SPVM_BASIC_TYPE_C_ID_DOUBLE; // Set array length object->length = length; object->type_category = SPVM_TYPE_C_TYPE_CATEGORY_NUMERIC_ARRAY; return object; } SPVM_OBJECT* SPVM_API_new_object_array_raw(SPVM_ENV* env, int32_t basic_type_id, int32_t length) { (void)env; SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; int64_t alloc_byte_size = (intptr_t)env->object_header_byte_size + sizeof(void*) * ((int64_t)length + 1); // Create object SPVM_OBJECT* object = SPVM_API_alloc_memory_block_zero(env, alloc_byte_size); if (!object) { return NULL; } for (int32_t index = 0; index < length; index++) { SPVM_OBJECT* get_field_object = ((SPVM_OBJECT**)((intptr_t)object + env->object_header_byte_size))[index]; } SPVM_RUNTIME_BASIC_TYPE* basic_type = SPVM_API_get_basic_type(env, basic_type_id); object->basic_type_id = basic_type->id; object->type_dimension = 1; // Set array length object->length = length; object->type_category = SPVM_TYPE_C_TYPE_CATEGORY_OBJECT_ARRAY; return object; } SPVM_OBJECT* SPVM_API_new_muldim_array_raw(SPVM_ENV* env, int32_t basic_type_id, int32_t element_dimension, int32_t length) { (void)env; int64_t alloc_byte_size = (intptr_t)env->object_header_byte_size + sizeof(void*) * ((int64_t)length + 1); // Create object SPVM_OBJECT* object = SPVM_API_alloc_memory_block_zero(env, alloc_byte_size); if (!object) { return NULL; } object->basic_type_id = basic_type_id; object->type_dimension = element_dimension + 1; // Set array length object->length = length; object->type_category = SPVM_TYPE_C_TYPE_CATEGORY_OBJECT_ARRAY; return object; } SPVM_OBJECT* SPVM_API_new_mulnum_array_raw(SPVM_ENV* env, int32_t basic_type_id, int32_t length) { (void)env; SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; // valut_t array dimension must be 1 SPVM_RUNTIME_BASIC_TYPE* basic_type = SPVM_API_get_basic_type(env, basic_type_id); const char* basic_type_name = SPVM_API_get_basic_type_name(env, basic_type->id); // Class SPVM_RUNTIME_CLASS* class = SPVM_API_get_runtime_class_from_basic_type_id(env, basic_type->id); int32_t fields_length = class->field_ids_length; SPVM_RUNTIME_FIELD* field_first = SPVM_API_get_runtime_field_from_index(env, class->id, 0); SPVM_RUNTIME_TYPE* first_field_type = SPVM_API_get_type(env, field_first->type_id); int32_t field_basic_type_id = first_field_type->basic_type_id; int32_t unit_size; if (field_basic_type_id == SPVM_BASIC_TYPE_C_ID_BYTE) { unit_size = sizeof(int8_t); } else if (field_basic_type_id == SPVM_BASIC_TYPE_C_ID_SHORT) { unit_size = sizeof(int16_t); } else if (field_basic_type_id == SPVM_BASIC_TYPE_C_ID_INT) { unit_size = sizeof(int32_t); } else if (field_basic_type_id == SPVM_BASIC_TYPE_C_ID_LONG) { unit_size = sizeof(int64_t); } else if (field_basic_type_id == SPVM_BASIC_TYPE_C_ID_FLOAT) { unit_size = sizeof(float); } else if (field_basic_type_id == SPVM_BASIC_TYPE_C_ID_DOUBLE) { unit_size = sizeof(double); } else { assert(0); } int64_t alloc_byte_size = (intptr_t)env->object_header_byte_size + unit_size * fields_length * ((int64_t)length + 1); // Create object SPVM_OBJECT* object = SPVM_API_alloc_memory_block_zero(env, alloc_byte_size); if (!object) { return NULL; } object->basic_type_id = basic_type->id; object->type_dimension = 1; // Set array length object->length = length; object->type_category = SPVM_TYPE_C_TYPE_CATEGORY_MULNUM_ARRAY; return object; } SPVM_OBJECT* SPVM_API_new_object_raw(SPVM_ENV* env, int32_t basic_type_id) { (void)env; SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; SPVM_RUNTIME_BASIC_TYPE* basic_type = SPVM_API_get_basic_type(env, basic_type_id); SPVM_RUNTIME_CLASS* class; if (!SPVM_API_get_runtime_class_from_basic_type_id(env, basic_type->id)) { class = NULL; } else { class = SPVM_API_get_runtime_class_from_basic_type_id(env, basic_type->id); } if (!class) { return NULL; } // Alloc body length + 1 int32_t fields_length = class->field_ids_length; int64_t alloc_byte_size = (intptr_t)env->object_header_byte_size + sizeof(SPVM_VALUE) * ((int64_t)fields_length + 1); // Create object SPVM_OBJECT* object = SPVM_API_alloc_memory_block_zero(env, alloc_byte_size); if (!object) { return NULL; } object->basic_type_id = basic_type->id; object->type_dimension = 0; object->length = fields_length; // Object type id object->type_category = SPVM_TYPE_C_TYPE_CATEGORY_CLASS; // Has destructor if (class->method_destructor_id >= 0) { object->flag |= SPVM_OBJECT_C_FLAG_HAS_DESTRUCTOR; } return object; } SPVM_OBJECT* SPVM_API_new_pointer_raw(SPVM_ENV* env, int32_t basic_type_id, void* pointer) { (void)env; SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; SPVM_RUNTIME_BASIC_TYPE* basic_type = SPVM_API_get_basic_type(env, basic_type_id); SPVM_RUNTIME_CLASS* class; if (!SPVM_API_get_runtime_class_from_basic_type_id(env, basic_type->id)) { class = NULL; } else { class = SPVM_API_get_runtime_class_from_basic_type_id(env, basic_type->id); } if (!class) { return NULL; } int64_t alloc_byte_size = (intptr_t)env->object_header_byte_size + sizeof(void*); // Create object SPVM_OBJECT* object = SPVM_API_alloc_memory_block_zero(env, alloc_byte_size); if (!object) { return NULL; } *(void**)((intptr_t)object + (intptr_t)env->object_header_byte_size) = pointer; object->basic_type_id = basic_type->id; object->type_dimension = 0; object->length = 0; // Object type id object->type_category = SPVM_TYPE_C_TYPE_CATEGORY_CLASS; // Has destructor if (SPVM_API_get_method(env, class->method_destructor_id)) { object->flag |= SPVM_OBJECT_C_FLAG_HAS_DESTRUCTOR; } return object; } int32_t SPVM_API_object_type_dimension(SPVM_ENV* env, SPVM_OBJECT* object) { return object->type_dimension; } int32_t SPVM_API_object_basic_type_id(SPVM_ENV* env, SPVM_OBJECT* object) { return object->basic_type_id; } int32_t SPVM_API_length(SPVM_ENV* env, SPVM_OBJECT* object) { (void)env; int32_t length = object->length; return length; } int8_t* SPVM_API_get_elems_byte(SPVM_ENV* env, SPVM_OBJECT* object) { (void)env; return (int8_t*)((intptr_t)object + env->object_header_byte_size); } const char* SPVM_API_get_chars(SPVM_ENV* env, SPVM_OBJECT* string) { (void)env; return (const char*)((intptr_t)string + env->object_header_byte_size); } int16_t* SPVM_API_get_elems_short(SPVM_ENV* env, SPVM_OBJECT* object) { (void)env; return (int16_t*)((intptr_t)object + env->object_header_byte_size); } int32_t* SPVM_API_get_elems_int(SPVM_ENV* env, SPVM_OBJECT* object) { (void)env; return (int32_t*)((intptr_t)object + env->object_header_byte_size); } int64_t* SPVM_API_get_elems_long(SPVM_ENV* env, SPVM_OBJECT* object) { (void)env; return (int64_t*)((intptr_t)object + env->object_header_byte_size); } float* SPVM_API_get_elems_float(SPVM_ENV* env, SPVM_OBJECT* object) { (void)env; return (float*)((intptr_t)object + env->object_header_byte_size); } double* SPVM_API_get_elems_double(SPVM_ENV* env, SPVM_OBJECT* object) { (void)env; return (double*)((intptr_t)object + env->object_header_byte_size); } SPVM_OBJECT* SPVM_API_get_elem_object(SPVM_ENV* env, SPVM_OBJECT* array, int32_t index) { (void)env; SPVM_OBJECT* object_maybe_weaken = ((SPVM_OBJECT**)((intptr_t)array + env->object_header_byte_size))[index]; SPVM_OBJECT* object = SPVM_API_GET_OBJECT_NO_WEAKEN_ADDRESS(object_maybe_weaken); return object; } void SPVM_API_set_elem_object(SPVM_ENV* env, SPVM_OBJECT* array, int32_t index, SPVM_OBJECT* oval) { (void)env; void* object_address = &((void**)((intptr_t)array + env->object_header_byte_size))[index]; SPVM_API_OBJECT_ASSIGN(object_address, oval); } void* SPVM_API_pointer(SPVM_ENV* env, SPVM_OBJECT* object) { (void)env; return *(void**)((intptr_t)object + (intptr_t)env->object_header_byte_size); } void SPVM_API_set_pointer(SPVM_ENV* env, SPVM_OBJECT* object, void* ptr) { (void)env; *(void**)((intptr_t)object + (intptr_t)env->object_header_byte_size) = ptr; } void SPVM_API_dec_ref_count(SPVM_ENV* env, SPVM_OBJECT* object) { assert(object != NULL); assert(object->ref_count > 0); // Not weakened assert((((intptr_t)object) & 1) == 0); // If reference count is zero, free address. if (object->ref_count == 1) { // Free elements of object array if (object->type_category == SPVM_TYPE_C_TYPE_CATEGORY_OBJECT_ARRAY) { int32_t length = object->length; for (int32_t index = 0; index < length; index++) { SPVM_OBJECT** get_field_object_address = &(((SPVM_OBJECT**)((intptr_t)object + env->object_header_byte_size))[index]); if (*get_field_object_address != NULL) { SPVM_API_dec_ref_count(env, *get_field_object_address); } } } // Free class object else if (object->type_category == SPVM_TYPE_C_TYPE_CATEGORY_CLASS) { // Class SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; SPVM_RUNTIME_BASIC_TYPE* basic_type = SPVM_API_get_basic_type(env, object->basic_type_id); SPVM_RUNTIME_CLASS* class; if (!SPVM_API_get_runtime_class_from_basic_type_id(env, basic_type->id)) { class = NULL; } else { class = SPVM_API_get_runtime_class_from_basic_type_id(env, basic_type->id); } int32_t is_pointer = 0; if (class) { if (class->flag & SPVM_CLASS_C_FLAG_POINTER) { is_pointer = 1; } } // Call destructor if (object->flag & SPVM_OBJECT_C_FLAG_HAS_DESTRUCTOR) { SPVM_VALUE args[1]; args[0].oval = object; int32_t exception_flag = SPVM_API_call_spvm_method(env, class->method_destructor_id, args); // Exception in destructor is changed to warning if (exception_flag) { void* exception = env->get_exception(env); const char* exception_chars = env->get_chars(env, exception); fprintf(stderr, "(in cleanup) %s\n", exception_chars); } assert(object->ref_count > 0); } // Free object fields int32_t object_fields_offset = class->object_fields_offset; int32_t object_fields_length = class->object_fields_length; for (int32_t index = 0; index < object_fields_length; index++) { SPVM_OBJECT** get_field_object_address = &(((SPVM_OBJECT**)((intptr_t)object + (intptr_t)env->object_header_byte_size + object_fields_offset))[index]); if (*get_field_object_address != NULL) { // If object is weak, unweaken if (SPVM_API_isweak(env, get_field_object_address)) { SPVM_API_unweaken(env, get_field_object_address); } SPVM_API_dec_ref_count(env, *get_field_object_address); } } } // Free weak back refenreces if (object->weaken_backref_head != NULL) { SPVM_API_free_weaken_back_refs(env, object->weaken_backref_head); object->weaken_backref_head = NULL; } // Decrement reference count object->ref_count--; // Free object SPVM_API_free_memory_block(env, object); object = NULL; } else { // Decrement reference count object->ref_count--; } } void SPVM_API_inc_ref_count(SPVM_ENV* env, SPVM_OBJECT* object) { (void)env; if (object != NULL) { assert(object->ref_count >= 0); // Increment reference count object->ref_count++; } } int32_t SPVM_API_ref_count(SPVM_ENV* env, SPVM_OBJECT* object) { (void)env; return object->ref_count; } int32_t SPVM_API_get_field_offset(SPVM_ENV* env, int32_t field_id) { (void)env; // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; // Field SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); return field->offset; } int32_t SPVM_API_get_field_id(SPVM_ENV* env, const char* class_name, const char* field_name, const char* signature) { (void)env; // Basic type SPVM_RUNTIME_BASIC_TYPE* basic_type = SPVM_API_get_basic_type_with_name(env, class_name); if (!basic_type) { return -1; } if (!SPVM_API_get_runtime_class_from_basic_type_id(env, basic_type->id)) { return -1; } // Class SPVM_RUNTIME_CLASS* class = SPVM_API_get_runtime_class_from_basic_type_id(env, basic_type->id); // Field SPVM_RUNTIME_FIELD* field = SPVM_API_get_runtime_field_from_runtime_class(env, class->id, field_name); if (!field) { return -1; } // Signature const char* field_signature = SPVM_API_get_constant_string_value(env, field->signature_id, NULL); if (strcmp(signature, field_signature) != 0) { return -1; } int32_t field_id = field->id; return field_id; } int32_t SPVM_API_get_class_var_id(SPVM_ENV* env, const char* class_name, const char* class_var_name, const char* signature) { (void)env; // Basic type SPVM_RUNTIME_BASIC_TYPE* basic_type = SPVM_API_get_basic_type_with_name(env, class_name); // Class name SPVM_RUNTIME_CLASS* class; if (!basic_type) { return -1; } else if (!SPVM_API_get_runtime_class_from_basic_type_id(env, basic_type->id)) { return -1; } else { class = SPVM_API_get_runtime_class_from_basic_type_id(env, basic_type->id); } // Class variable name SPVM_RUNTIME_CLASS_VAR* class_var = SPVM_API_get_runtime_class_var_from_runtime_class(env, class->id, class_var_name); if (!class_var) { return -1; } const char* class_var_signature = SPVM_API_get_constant_string_value(env, class_var->signature_id, NULL); // Signature if (strcmp(signature, class_var_signature) != 0) { return -1; } return class_var->id; } SPVM_RUNTIME_METHOD* SPVM_API_get_runtime_method_from_runtime_class(SPVM_ENV* env, int32_t class_id, const char* search_method_name) { SPVM_RUNTIME_CLASS* class = SPVM_API_get_class(env, class_id); SPVM_RUNTIME_METHOD* found_method = NULL; if (class->method_ids_length > 0) { for (int32_t method_id = class->method_ids_base; method_id < class->method_ids_base + class->method_ids_length; method_id++) { SPVM_RUNTIME_METHOD* method = SPVM_API_get_method(env, method_id); const char* method_name = SPVM_API_get_name(env, method->name_id); if (strcmp(method_name, search_method_name) == 0) { found_method = method; break; } } } return found_method; } SPVM_RUNTIME_FIELD* SPVM_API_get_runtime_field_from_runtime_class(SPVM_ENV* env, int32_t class_id, const char* search_field_name) { SPVM_RUNTIME_CLASS* class = SPVM_API_get_class(env, class_id); SPVM_RUNTIME_FIELD* found_field = NULL; if (class->field_ids_length > 0) { for (int32_t field_id = class->field_ids_base; field_id < class->field_ids_base + class->field_ids_length; field_id++) { SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); const char* field_name = SPVM_API_get_name(env, field->name_id); if (strcmp(field_name, search_field_name) == 0) { found_field = field; break; } } } return found_field; } SPVM_RUNTIME_CLASS_VAR* SPVM_API_get_runtime_class_var_from_runtime_class(SPVM_ENV* env, int32_t class_id, const char* search_class_var_name) { SPVM_RUNTIME_CLASS* class = SPVM_API_get_class(env, class_id); SPVM_RUNTIME_CLASS_VAR* found_class_var = NULL; if (class->class_var_ids_length > 0) { for (int32_t class_var_id = class->class_var_ids_base; class_var_id < class->class_var_ids_base + class->class_var_ids_length; class_var_id++) { SPVM_RUNTIME_CLASS_VAR* class_var = SPVM_API_get_class_var(env, class_var_id); const char* class_var_name = SPVM_API_get_name(env, class_var->name_id); if (strcmp(class_var_name, search_class_var_name) == 0) { found_class_var = class_var; break; } } } return found_class_var; } SPVM_RUNTIME_FIELD* SPVM_API_get_runtime_field_from_index(SPVM_ENV* env, int32_t class_id, int32_t field_index) { SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; SPVM_RUNTIME_FIELD* field = NULL; SPVM_RUNTIME_CLASS* class = SPVM_API_get_class(env, class_id); if (class) { int32_t field_id = class->field_ids_base + field_index; field = SPVM_API_get_field(env, field_id); } return field; } SPVM_RUNTIME_METHOD* SPVM_API_get_runtime_method_from_index(SPVM_ENV* env, int32_t class_id, int32_t method_index) { SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; SPVM_RUNTIME_METHOD* method = NULL; SPVM_RUNTIME_CLASS* class = SPVM_API_get_class(env, class_id); if (class) { int32_t method_id = class->method_ids_base + method_index; method = SPVM_API_get_method(env, method_id); } return method; } int32_t SPVM_API_get_class_method_id(SPVM_ENV* env, const char* class_name, const char* method_name, const char* signature) { (void)env; // Method ID int32_t method_id = -1; // Basic type SPVM_RUNTIME_BASIC_TYPE* basic_type = SPVM_API_get_basic_type_with_name(env, class_name); if (basic_type) { // Class SPVM_RUNTIME_CLASS* class = SPVM_API_get_runtime_class_from_basic_type_id(env, basic_type->id); if (class) { // Method SPVM_RUNTIME_METHOD* method = SPVM_API_get_runtime_method_from_runtime_class(env, class->id, method_name); if (method) { // Class method if (method->is_class_method) { // Signature const char* method_signature = SPVM_API_get_constant_string_value(env, method->signature_id, NULL); if (strcmp(signature, method_signature) == 0) { method_id = method->id; } } } } } return method_id; } int32_t SPVM_API_get_method_id_without_signature(SPVM_ENV* env, const char* class_name, const char* method_name) { (void)env; // Method ID int32_t method_id = -1; // Basic type SPVM_RUNTIME_BASIC_TYPE* basic_type = SPVM_API_get_basic_type_with_name(env, class_name); if (basic_type) { // Class SPVM_RUNTIME_CLASS* class = SPVM_API_get_runtime_class_from_basic_type_id(env, basic_type->id); if (class) { // Method SPVM_RUNTIME_METHOD* method = SPVM_API_get_runtime_method_from_runtime_class(env, class->id, method_name); if (method) { method_id = method->id; } } } return method_id; } int32_t SPVM_API_get_instance_method_id_static(SPVM_ENV* env, const char* class_name, const char* method_name, const char* signature) { (void)env; // Method ID int32_t method_id = -1; // Basic type SPVM_RUNTIME_BASIC_TYPE* basic_type = SPVM_API_get_basic_type_with_name(env, class_name); if (basic_type) { // Class SPVM_RUNTIME_CLASS* class = SPVM_API_get_runtime_class_from_basic_type_id(env, basic_type->id); if (class) { // Method SPVM_RUNTIME_METHOD* method = SPVM_API_get_runtime_method_from_runtime_class(env, class->id, method_name); if (method) { // Instance method if (!method->is_class_method) { // Signature const char* method_signature = SPVM_API_get_constant_string_value(env, method->signature_id, NULL); if (strcmp(signature, method_signature) == 0) { method_id = method->id; } } } } } return method_id; } int32_t SPVM_API_get_instance_method_id(SPVM_ENV* env, SPVM_OBJECT* object, const char* method_name, const char* signature) { (void)env; // Method ID int32_t method_id = -1; // Compiler SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; // Basic type SPVM_RUNTIME_BASIC_TYPE* basic_type = SPVM_API_get_basic_type(env, object->basic_type_id); // Class SPVM_RUNTIME_CLASS* class = SPVM_API_get_runtime_class_from_basic_type_id(env, basic_type->id); if (class) { // Method SPVM_RUNTIME_METHOD* method = NULL; // Anon instance method if (class->flag & SPVM_CLASS_C_FLAG_ANON_METHOD_CLASS) { // Method name int32_t method_id = class->method_ids_base; method = SPVM_API_get_method(env, method_id); } // Normal instance method else { method = SPVM_API_get_runtime_method_from_runtime_class(env, class->id, method_name); } if (method) { // Instance method if (!method->is_class_method) { // Signature const char* method_signature = SPVM_API_get_constant_string_value(env, method->signature_id, NULL); if (strcmp(signature, method_signature) == 0) { method_id = method->id; } } } } return method_id; } SPVM_RUNTIME_BASIC_TYPE* SPVM_API_get_basic_type_with_name(SPVM_ENV* env, const char* basic_type_name) { // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; SPVM_RUNTIME_BASIC_TYPE* basic_type = (SPVM_RUNTIME_BASIC_TYPE*)SPVM_HASH_fetch(runtime_info->basic_type_symtable, basic_type_name, strlen(basic_type_name)); return basic_type; } SPVM_RUNTIME_BASIC_TYPE* SPVM_API_get_basic_type(SPVM_ENV* env, int32_t basic_type_id) { // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; if (basic_type_id < 0) { return NULL; } if (basic_type_id >= runtime_info->basic_types_length) { return NULL; } SPVM_RUNTIME_BASIC_TYPE* basic_type = &runtime_info->basic_types[basic_type_id]; return basic_type; } SPVM_RUNTIME_CLASS* SPVM_API_get_class(SPVM_ENV* env, int32_t class_id) { // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; if (class_id < 0) { return NULL; } if (class_id >= runtime_info->classes_length) { return NULL; } SPVM_RUNTIME_CLASS* class = &runtime_info->classes[class_id]; return class; } SPVM_RUNTIME_TYPE* SPVM_API_get_type(SPVM_ENV* env, int32_t type_id) { // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; if (type_id < 0) { return NULL; } if (type_id >= runtime_info->types_length) { return NULL; } SPVM_RUNTIME_TYPE* type = &runtime_info->types[type_id]; return type; } SPVM_RUNTIME_CLASS_VAR* SPVM_API_get_class_var(SPVM_ENV* env, int32_t class_var_id) { // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; if (class_var_id < 0) { return NULL; } if (class_var_id >= runtime_info->class_vars_length) { return NULL; } SPVM_RUNTIME_CLASS_VAR* class_var = &runtime_info->class_vars[class_var_id]; return class_var; } SPVM_RUNTIME_FIELD* SPVM_API_get_field(SPVM_ENV* env, int32_t field_id) { // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; if (field_id < 0) { return NULL; } if (field_id >= runtime_info->fields_length) { return NULL; } SPVM_RUNTIME_FIELD* field = &runtime_info->fields[field_id]; return field; } SPVM_RUNTIME_METHOD* SPVM_API_get_method(SPVM_ENV* env, int32_t method_id) { // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; if (method_id < 0) { return NULL; } if (method_id >= runtime_info->methods_length) { return NULL; } SPVM_RUNTIME_METHOD* method = &runtime_info->methods[method_id]; return method; } int32_t SPVM_API_get_basic_type_id(SPVM_ENV* env, const char* basic_type_name) { (void)env; if (basic_type_name == NULL) { return -1; } SPVM_RUNTIME_BASIC_TYPE* basic_type = SPVM_API_get_basic_type_with_name(env, basic_type_name); if (basic_type) { int32_t basic_type_id = basic_type->id; return basic_type_id; } else { return -1; } } int8_t SPVM_API_get_field_byte(SPVM_ENV* env, SPVM_OBJECT* object, int32_t field_id) { // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; // Field SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); // Get field value int8_t value = *(int8_t*)((intptr_t)object + env->object_header_byte_size + field->offset); return value; } int16_t SPVM_API_get_field_short(SPVM_ENV* env, SPVM_OBJECT* object, int32_t field_id) { // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; // Field SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); // Get field value int16_t value = *(int16_t*)((intptr_t)object + env->object_header_byte_size + field->offset); return value; } int32_t SPVM_API_get_field_int(SPVM_ENV* env, SPVM_OBJECT* object, int32_t field_id) { // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; // Field SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); // Get field value int32_t value = *(int32_t*)((intptr_t)object + env->object_header_byte_size + field->offset); return value; } int64_t SPVM_API_get_field_long(SPVM_ENV* env, SPVM_OBJECT* object, int32_t field_id) { // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; // Field SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); // Get field value int64_t value = *(int64_t*)((intptr_t)object + env->object_header_byte_size + field->offset); return value; } float SPVM_API_get_field_float(SPVM_ENV* env, SPVM_OBJECT* object, int32_t field_id) { // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; // Field SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); // Get field value float value = *(float*)((intptr_t)object + env->object_header_byte_size + field->offset); return value; } double SPVM_API_get_field_double(SPVM_ENV* env, SPVM_OBJECT* object, int32_t field_id) { // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; // Field SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); // Get field value double value = *(double*)((intptr_t)object + env->object_header_byte_size + field->offset); return value; } SPVM_OBJECT* SPVM_API_get_field_object(SPVM_ENV* env, SPVM_OBJECT* object, int32_t field_id) { // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; // Field SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); // Get field value SPVM_OBJECT* value_maybe_weaken = *(SPVM_OBJECT**)((intptr_t)object + env->object_header_byte_size + field->offset); SPVM_OBJECT* value = SPVM_API_GET_OBJECT_NO_WEAKEN_ADDRESS(value_maybe_weaken); return value; } void SPVM_API_set_field_byte(SPVM_ENV* env, SPVM_OBJECT* object, int32_t field_id, int8_t value) { // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; // Field SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); // Get field value *(int8_t*)((intptr_t)object + env->object_header_byte_size + field->offset) = value; } void SPVM_API_set_field_short(SPVM_ENV* env, SPVM_OBJECT* object, int32_t field_id, int16_t value) { // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; // Field SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); // Get field value *(int16_t*)((intptr_t)object + env->object_header_byte_size + field->offset) = value; } void SPVM_API_set_field_int(SPVM_ENV* env, SPVM_OBJECT* object, int32_t field_id, int32_t value) { // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; // Field SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); // Get field value *(int32_t*)((intptr_t)object + env->object_header_byte_size + field->offset) = value; } void SPVM_API_set_field_long(SPVM_ENV* env, SPVM_OBJECT* object, int32_t field_id, int64_t value) { // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; // Field SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); // Get field value *(int64_t*)((intptr_t)object + env->object_header_byte_size + field->offset) = value; } void SPVM_API_set_field_float(SPVM_ENV* env, SPVM_OBJECT* object, int32_t field_id, float value) { // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; // Field SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); // Get field value *(float*)((intptr_t)object + env->object_header_byte_size + field->offset) = value; } void SPVM_API_set_field_double(SPVM_ENV* env, SPVM_OBJECT* object, int32_t field_id, double value) { // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; // Field SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); // Get field value *(double*)((intptr_t)object + env->object_header_byte_size + field->offset) = value; } void SPVM_API_set_field_object(SPVM_ENV* env, SPVM_OBJECT* object, int32_t field_id, SPVM_OBJECT* value) { // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; // Field SPVM_RUNTIME_FIELD* field = SPVM_API_get_field(env, field_id); // Get field value void* get_field_object_address = (void**)((intptr_t)object + env->object_header_byte_size + field->offset); SPVM_API_OBJECT_ASSIGN(get_field_object_address, value); } void* SPVM_API_alloc_memory_block_zero(SPVM_ENV* env, size_t byte_size) { // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; assert(byte_size > 0); if ((uint64_t)byte_size > (uint64_t)SIZE_MAX) { return NULL; } void* block = SPVM_ALLOCATOR_alloc_memory_block_tmp(runtime_info->allocator, (size_t)byte_size); #ifdef SPVM_DEBUG_ALLOC_MEMORY_COUNT SPVM_ALLOCATOR* allocator = runtime_info->allocator; fprintf(stderr, "[ALLOC_MEMORY %p (All:%d, Tmp:%d, Perm: %d]\n", block, (int32_t)(intptr_t)env->get_memory_blocks_count(env), allocator->memory_blocks_count_tmp, allocator->memory_blocks_count_permanent); #endif return block; } void SPVM_API_free_memory_block(SPVM_ENV* env, void* block) { // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; if (block) { SPVM_ALLOCATOR_free_memory_block_tmp(runtime_info->allocator, block); #ifdef SPVM_DEBUG_ALLOC_MEMORY_COUNT SPVM_ALLOCATOR* allocator = runtime_info->allocator; fprintf(stderr, "[FREE_MEMORY %p (All:%d, Tmp:%d, Perm: %d]\n", block, (int32_t)(intptr_t)env->get_memory_blocks_count(env), allocator->memory_blocks_count_tmp, allocator->memory_blocks_count_permanent); #endif } } int8_t SPVM_API_get_class_var_byte(SPVM_ENV* env, int32_t packagke_var_id) { // Get field value int8_t value = ((SPVM_VALUE*)(env->class_vars_heap))[packagke_var_id].bval; return value; } int16_t SPVM_API_get_class_var_short(SPVM_ENV* env, int32_t packagke_var_id) { // Get field value int16_t value = ((SPVM_VALUE*)(env->class_vars_heap))[packagke_var_id].sval; return value; } int32_t SPVM_API_get_class_var_int(SPVM_ENV* env, int32_t packagke_var_id) { // Get field value int32_t value = ((SPVM_VALUE*)(env->class_vars_heap))[packagke_var_id].ival; return value; } int64_t SPVM_API_get_class_var_long(SPVM_ENV* env, int32_t packagke_var_id) { // Get field value int64_t value = ((SPVM_VALUE*)(env->class_vars_heap))[packagke_var_id].lval; return value; } float SPVM_API_get_class_var_float(SPVM_ENV* env, int32_t packagke_var_id) { // Get field value float value = ((SPVM_VALUE*)(env->class_vars_heap))[packagke_var_id].fval; return value; } double SPVM_API_get_class_var_double(SPVM_ENV* env, int32_t packagke_var_id) { // Get field value double value = ((SPVM_VALUE*)(env->class_vars_heap))[packagke_var_id].dval; return value; } SPVM_OBJECT* SPVM_API_get_class_var_object(SPVM_ENV* env, int32_t packagke_var_id) { // Get field value SPVM_OBJECT* value_maybe_weaken = (SPVM_OBJECT*)((SPVM_VALUE*)(env->class_vars_heap))[packagke_var_id].oval; SPVM_OBJECT* value = SPVM_API_GET_OBJECT_NO_WEAKEN_ADDRESS(value_maybe_weaken); return value; } void SPVM_API_set_class_var_byte(SPVM_ENV* env, int32_t packagke_var_id, int8_t value) { // Get field value ((SPVM_VALUE*)(env->class_vars_heap))[packagke_var_id].bval = value; } void SPVM_API_set_class_var_short(SPVM_ENV* env, int32_t packagke_var_id, int16_t value) { // Get field value ((SPVM_VALUE*)(env->class_vars_heap))[packagke_var_id].sval = value; } void SPVM_API_set_class_var_int(SPVM_ENV* env, int32_t packagke_var_id, int32_t value) { // Get field value ((SPVM_VALUE*)(env->class_vars_heap))[packagke_var_id].ival = value; } void SPVM_API_set_class_var_long(SPVM_ENV* env, int32_t packagke_var_id, int64_t value) { // Get field value ((SPVM_VALUE*)(env->class_vars_heap))[packagke_var_id].lval = value; } void SPVM_API_set_class_var_float(SPVM_ENV* env, int32_t packagke_var_id, float value) { // Get field value ((SPVM_VALUE*)(env->class_vars_heap))[packagke_var_id].fval = value; } void SPVM_API_set_class_var_double(SPVM_ENV* env, int32_t packagke_var_id, double value) { // Get field value ((SPVM_VALUE*)(env->class_vars_heap))[packagke_var_id].dval = value; } void SPVM_API_set_class_var_object(SPVM_ENV* env, int32_t packagke_var_id, SPVM_OBJECT* value) { // Get field value void* get_field_object_address = &((SPVM_VALUE*)(env->class_vars_heap))[packagke_var_id].oval; SPVM_API_OBJECT_ASSIGN(get_field_object_address, value); } SPVM_OBJECT* SPVM_API_new_array_proto_raw(SPVM_ENV* env, SPVM_OBJECT* array, int32_t length) { if (array == NULL) { return NULL; } if (length < 0) { return NULL; } int32_t element_byte_size = env->get_elem_byte_size(env, array); int64_t alloc_byte_size = (intptr_t)env->object_header_byte_size + element_byte_size * ((int64_t)length + 1); // Create object SPVM_OBJECT* new_array = SPVM_API_alloc_memory_block_zero(env, (size_t)alloc_byte_size); if (!new_array) { return NULL; } new_array->basic_type_id = array->basic_type_id; new_array->type_dimension = array->type_dimension; new_array->type_category = array->type_category; new_array->length = length; return new_array; } SPVM_OBJECT* SPVM_API_new_array_proto(SPVM_ENV* env, SPVM_OBJECT* array, int32_t length) { (void)env; SPVM_OBJECT* object = SPVM_API_new_array_proto_raw(env, array, length); SPVM_API_push_mortal(env, object); return object; } SPVM_OBJECT* SPVM_API_copy_raw(SPVM_ENV* env, SPVM_OBJECT* object) { if (!object) { return NULL; } SPVM_OBJECT* new_object; int32_t length = object->length; if (env->is_string(env, object)) { new_object = env->new_string_raw(env, NULL, length); const char* object_chars = env->get_chars(env, object); char* new_object_chars = (char*)env->get_chars(env, new_object); memcpy(new_object_chars, object_chars, length); } else if (env->is_numeric_array(env, object) || env->is_mulnum_array(env, object)) { new_object = env->new_array_proto_raw(env, object, length); const char* object_bytes = (const char*)env->get_elems_byte(env, object); char* new_object_bytes = (char*)env->get_elems_byte(env, new_object); int32_t element_byte_size = env->get_elem_byte_size(env, object); memcpy(new_object_bytes, object_bytes, element_byte_size * length); } else { new_object = NULL; } return new_object; } SPVM_OBJECT* SPVM_API_copy(SPVM_ENV* env, SPVM_OBJECT* object) { (void)env; SPVM_OBJECT* new_object = SPVM_API_copy_raw(env, object); SPVM_API_push_mortal(env, new_object); return new_object; } void SPVM_API_shorten(SPVM_ENV* env, SPVM_OBJECT* string, int32_t new_length) { (void)env; if (string != NULL) { if (env->is_string(env, string)) { if (!env->is_read_only(env, string)) { int32_t length = string->length; if (new_length > length) { new_length = length; } else if (new_length < 0) { new_length = 0; } string->length = new_length; char* chars = (char*)env->get_chars(env, string); if (new_length > length) { memset(chars + new_length, 0, new_length - length); } } } } } void SPVM_API_set_no_symbol_cache_flag(SPVM_ENV* env, int32_t flag) { (void)env; env->no_symbol_cache_flag = (void*)(intptr_t)flag; } int32_t SPVM_API_get_no_symbol_cache_flag(SPVM_ENV* env) { (void)env; return (int32_t)(intptr_t)env->no_symbol_cache_flag; } void SPVM_API_call_init_blocks(SPVM_ENV* env) { (void)env; // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; // Call INIT blocks int32_t classes_length = runtime_info->classes_length; SPVM_VALUE stack[SPVM_LIMIT_C_METHOD_ARGS_MAX_COUNT]; for (int32_t class_id = 0; class_id < classes_length; class_id++) { SPVM_RUNTIME_CLASS* class = SPVM_API_get_class(env, class_id); if (class->has_init_block) { SPVM_RUNTIME_METHOD* init_method = SPVM_API_get_runtime_method_from_runtime_class(env, class->id, "INIT"); assert(init_method); env->call_spvm_method(env, init_method->id, stack); } } } SPVM_ENV* SPVM_API_new_env(SPVM_ENV* env) { (void)env; // New raw env SPVM_ENV* new_env = SPVM_API_new_env_raw(NULL); // Set the compiler new_env->runtime_info = env->runtime_info; // Initialize env new_env->init_env(new_env); // Call init blocks new_env->call_init_blocks(new_env); return new_env; } void SPVM_API_free_env(SPVM_ENV* env) { (void)env; env->cleanup_global_vars(env); SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; SPVM_ALLOCATOR* allocator = runtime_info->allocator; SPVM_ALLOCATOR_free(allocator); runtime_info->allocator = NULL; allocator= NULL; env->free_env_raw(env); } const char* SPVM_API_get_constant_string_value(SPVM_ENV* env, int32_t string_id, int32_t* string_length) { SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; SPVM_RUNTIME_STRING* constant_string = &runtime_info->strings[string_id]; const char* constant_string_value = constant_string->value; if (string_length) { *string_length = constant_string->length; } return constant_string_value; } const char* SPVM_API_get_name(SPVM_ENV* env, int32_t string_id) { const char* name = SPVM_API_get_constant_string_value(env, string_id, NULL); return name; } void SPVM_API_set_native_method_address(SPVM_ENV* env, int32_t method_id, void* address) { (void)env; // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; SPVM_RUNTIME_METHOD* method = SPVM_API_get_method(env, method_id); runtime_info->method_native_addresses[method->id] = address; } void SPVM_API_set_precompile_method_address(SPVM_ENV* env, int32_t method_id, void* address) { (void)env; // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; SPVM_RUNTIME_METHOD* method = SPVM_API_get_method(env, method_id); runtime_info->method_precompile_addresses[method->id] = address; } void* SPVM_API_get_native_method_address(SPVM_ENV* env, int32_t method_id) { (void)env; // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; SPVM_RUNTIME_METHOD* method = SPVM_API_get_method(env, method_id); void* native_method_address = runtime_info->method_native_addresses[method->id]; return native_method_address; } void* SPVM_API_get_precompile_method_address(SPVM_ENV* env, int32_t method_id) { (void)env; // Runtime SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; SPVM_RUNTIME_METHOD* method = SPVM_API_get_method(env, method_id); void* precompile_method_address = runtime_info->method_precompile_addresses[method->id]; return precompile_method_address; } // flag // 0 : all // 1 : native method // 2 : precompile method int32_t SPVM_API_compiler_get_next_method_id_flag(SPVM_ENV* env, SPVM_COMPILER* compiler, const char* method_abs_name, int32_t start_index, int32_t flag) { (void)env; SPVM_LIST* methods = compiler->methods; int32_t found_index = -1; for (int32_t method_index = start_index; method_index < methods->length; method_index++) { SPVM_METHOD* method = SPVM_LIST_fetch(methods, method_index); if (!method) { break; } // Native method if (flag == 0 || flag == 1) { if (method->flag & SPVM_METHOD_C_FLAG_NATIVE) { found_index = method_index; break; } } // Precompile method if (flag == 0 || flag == 2) { if (method->flag & SPVM_METHOD_C_FLAG_PRECOMPILE) { found_index = method_index; break; } } // Normal method if (flag == 0) { found_index = method_index; break; } } return found_index; } int32_t SPVM_API_compiler_get_class_id(SPVM_ENV* env, SPVM_COMPILER* compiler, const char* class_name) { (void)env; SPVM_CLASS* class = SPVM_HASH_fetch(compiler->class_symtable, class_name, strlen(class_name)); int32_t class_id; if (class) { class_id = class->id; } else { class_id = -1; } return class_id; } int32_t SPVM_API_compiler_get_classes_length(SPVM_ENV* env, SPVM_COMPILER* compiler) { (void)env; int32_t classes_length= compiler->classes->length; return classes_length; } const char* SPVM_API_compiler_get_class_name(SPVM_ENV* env, SPVM_COMPILER* compiler, int32_t class_id) { (void)env; SPVM_CLASS* class = SPVM_LIST_fetch(compiler->classes, class_id); const char* class_name = class->name; return class_name; } int32_t SPVM_API_compiler_is_anon_class(SPVM_ENV* env, SPVM_COMPILER* compiler, int32_t class_id) { (void)env; SPVM_CLASS* class = SPVM_LIST_fetch(compiler->classes, class_id); return class->is_anon; } int32_t SPVM_API_compiler_get_methods_length(SPVM_ENV* env, SPVM_COMPILER* compiler, int32_t class_id) { (void)env; SPVM_CLASS* class = SPVM_LIST_fetch(compiler->classes, class_id); int32_t methods_length = class->methods->length; return methods_length; } int32_t SPVM_API_compiler_get_method_id(SPVM_ENV* env, SPVM_COMPILER* compiler, int32_t class_id, int32_t method_index_of_class) { (void)env; SPVM_CLASS* class = SPVM_LIST_fetch(compiler->classes, class_id); int32_t method_id; if (class) { SPVM_METHOD* method = SPVM_LIST_fetch(class->methods, method_index_of_class); if (method) { method_id = method->id; } else { method_id = -2; } } else { method_id = -1; } return method_id; } int32_t SPVM_API_compiler_get_method_id_by_name(SPVM_ENV* env, SPVM_COMPILER* compiler, const char* class_name, const char* method_name) { (void)env; SPVM_CLASS* class = SPVM_HASH_fetch(compiler->class_symtable, class_name, strlen(class_name)); int32_t method_id; if (class) { SPVM_METHOD* method_symtable = SPVM_HASH_fetch(class->method_symtable, method_name, strlen(method_name)); if (method_symtable) { method_id = method_symtable->id; } else { method_id = -2; } } else { method_id = -1; } return method_id; } const char* SPVM_API_compiler_get_method_name(SPVM_ENV* env, SPVM_COMPILER* compiler, int32_t method_id) { (void)env; SPVM_METHOD* method = SPVM_LIST_fetch(compiler->methods, method_id); return method->name; } int32_t SPVM_API_compiler_is_anon_method(SPVM_ENV* env, SPVM_COMPILER* compiler, int32_t method_id) { (void)env; SPVM_METHOD* method = SPVM_LIST_fetch(compiler->methods, method_id); return method->flag & SPVM_METHOD_C_FLAG_ANON; } int32_t SPVM_API_compiler_is_init_block_method(SPVM_ENV* env, SPVM_COMPILER* compiler, int32_t method_id) { (void)env; SPVM_METHOD* method = SPVM_LIST_fetch(compiler->methods, method_id); return method->is_init; } int32_t SPVM_API_compiler_is_native_method(SPVM_ENV* env, SPVM_COMPILER* compiler, int32_t method_id) { (void)env; SPVM_METHOD* method = SPVM_LIST_fetch(compiler->methods, method_id); return method->flag & SPVM_METHOD_C_FLAG_NATIVE; } int32_t SPVM_API_compiler_is_precompile_method(SPVM_ENV* env, SPVM_COMPILER* compiler, int32_t method_id) { (void)env; SPVM_METHOD* method = SPVM_LIST_fetch(compiler->methods, method_id); return method->flag & SPVM_METHOD_C_FLAG_PRECOMPILE; } const char* SPVM_API_compiler_get_method_signature(SPVM_ENV* env, SPVM_COMPILER* compiler, int32_t method_id) { (void)env; SPVM_METHOD* method = SPVM_LIST_fetch(compiler->methods, method_id); return method->signature; } void* SPVM_API_compiler_get_native_method_address(SPVM_ENV* env, SPVM_COMPILER* compiler, int32_t method_id) { (void)env; SPVM_METHOD* method = SPVM_LIST_fetch(compiler->methods, method_id); void* native_method_address = method->native_address; return native_method_address; } void* SPVM_API_compiler_get_precompile_method_address(SPVM_ENV* env, SPVM_COMPILER* compiler, int32_t method_id) { (void)env; SPVM_METHOD* method = SPVM_LIST_fetch(compiler->methods, method_id); void* precompile_method_address = method->precompile_address; return precompile_method_address; } void SPVM_API_compiler_set_native_method_address(SPVM_ENV* env, SPVM_COMPILER* compiler, int32_t method_id, void* address) { (void)env; SPVM_METHOD* method = SPVM_LIST_fetch(compiler->methods, method_id); method->native_address = address; } void SPVM_API_compiler_set_precompile_method_address(SPVM_ENV* env, SPVM_COMPILER* compiler, int32_t method_id, void* address) { (void)env; SPVM_METHOD* method = SPVM_LIST_fetch(compiler->methods, method_id); method->precompile_address = address; } const char* SPVM_API_compiler_get_method_abs_name(SPVM_ENV* env, SPVM_COMPILER* compiler, int32_t method_id) { (void)env; SPVM_METHOD* method = SPVM_LIST_fetch(compiler->methods, method_id); const char* method_abs_name = method->abs_name; return method_abs_name; } SPVM_COMPILER* SPVM_API_compiler_new(SPVM_ENV* env) { (void*)env; SPVM_COMPILER* compiler = SPVM_COMPILER_new(); return compiler; } void SPVM_API_compiler_set_start_line(SPVM_ENV* env, SPVM_COMPILER* compiler, int32_t start_line) { (void*)env; compiler->start_line = start_line; } int32_t SPVM_API_compiler_get_start_line(SPVM_ENV* env, SPVM_COMPILER* compiler) { (void*)env; return compiler->start_line; } void SPVM_API_compiler_set_start_file(SPVM_ENV* env, SPVM_COMPILER* compiler, const char* start_file) { (void*)env; compiler->start_file = start_file; } const char* SPVM_API_compiler_get_start_file(SPVM_ENV* env, SPVM_COMPILER* compiler) { (void*)env; return compiler->start_file; } void SPVM_API_compiler_add_module_dir(SPVM_ENV* env, SPVM_COMPILER* compiler, const char* module_dir) { (void*)env; SPVM_LIST_push(compiler->module_dirs, (void*)module_dir); } int32_t SPVM_API_compiler_get_module_dirs_length (SPVM_ENV* env, SPVM_COMPILER* compiler) { (void*)env; SPVM_LIST* module_dirs = compiler->module_dirs; int32_t module_dirs_length = module_dirs->length; return module_dirs_length; } const char* SPVM_API_compiler_get_module_dir (SPVM_ENV* env, SPVM_COMPILER* compiler, int32_t module_dir_id) { (void*)env; const char* module_dir = SPVM_LIST_fetch(compiler->module_dirs, module_dir_id); return module_dir; } int32_t SPVM_API_compiler_compile_spvm(SPVM_ENV* env, SPVM_COMPILER* compiler, const char* class_name) { (void*)env; int32_t error_code = SPVM_COMPILER_compile_spvm(compiler, class_name); return error_code; } SPVM_RUNTIME_INFO* SPVM_API_compiler_build_runtime_info(SPVM_ENV* env, SPVM_COMPILER* compiler) { (void*)env; SPVM_RUNTIME_INFO* runtime_info = SPVM_COMPILER_build_runtime_info(compiler); return runtime_info; } void SPVM_API_compiler_free(SPVM_ENV* env, SPVM_COMPILER* compiler) { (void*)env; SPVM_COMPILER_free(compiler); } int32_t SPVM_API_compiler_get_error_messages_length(SPVM_ENV* env, SPVM_COMPILER* compiler) { return SPVM_COMPILER_get_error_messages_length(compiler); } const char* SPVM_API_compiler_get_error_message(SPVM_ENV* env, SPVM_COMPILER* compiler, int32_t index) { return SPVM_COMPILER_get_error_message(compiler, index); } const char* SPVM_API_get_basic_type_name(SPVM_ENV* env, int32_t basic_type_id) { SPVM_RUNTIME_INFO* runtime_info = env->runtime_info; SPVM_RUNTIME_BASIC_TYPE* basic_type = (SPVM_RUNTIME_BASIC_TYPE*)SPVM_API_get_basic_type(env, basic_type_id); SPVM_RUNTIME_STRING* basic_type_name_string = (SPVM_RUNTIME_STRING*)&runtime_info->strings[basic_type->name_id]; const char* basic_type_name = (const char*)&runtime_info->string_buffer[basic_type_name_string->string_buffer_id]; return basic_type_name; }