execute: implement runtime exceptions

This commit is contained in:
Zack Buhman 2025-01-11 01:08:18 -06:00
parent 94556bcd97
commit 48d8db8e9e
17 changed files with 439 additions and 37 deletions

View File

@ -10,7 +10,7 @@ CFLAGS += -Wall -Werror -Wfatal-errors -Wno-error=unused-variable -fstack-protec
CFLAGS += -I$(MAKEFILE_PATH)/ CFLAGS += -I$(MAKEFILE_PATH)/
CFLAGS += -I$(MAKEFILE_PATH)/c CFLAGS += -I$(MAKEFILE_PATH)/c
CFLAGS += -DDEBUG CFLAGS += -DDEBUG
CFLAGS += -DDEBUG_PRINT #CFLAGS += -DDEBUG_PRINT
LDFLAGS = -lm LDFLAGS = -lm
OPT ?= -O0 OPT ?= -O0
DEPFLAGS = -MMD -MP DEPFLAGS = -MMD -MP

View File

@ -9,23 +9,33 @@
#include "native_types_allocate.h" #include "native_types_allocate.h"
#include "parse_type.h" #include "parse_type.h"
#include "execute_helper.h" #include "execute_helper.h"
#include "vm_instance.h"
void op_aaload(struct vm * vm) void op_aaload(struct vm * vm)
{ {
int32_t index = operand_stack_pop_u32(vm->current_frame); int32_t index = operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame); struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); if (arrayref == nullptr)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException"));
assert(arrayref->length > 0);
if (index < 0 || index >= arrayref->length)
return vm_exception(vm, vm_instance_create(vm, "java/lang/ArrayIndexOutOfBoundsException"));
uint32_t value = arrayref->u32[index]; uint32_t value = arrayref->u32[index];
operand_stack_push_u32(vm->current_frame, value); operand_stack_push_u32(vm->current_frame, value);
} }
void op_aastore(struct vm * vm) void op_aastore(struct vm * vm)
{ {
uint32_t value = operand_stack_pop_u32(vm->current_frame); void * ref = operand_stack_pop_ref(vm->current_frame);
int32_t index = operand_stack_pop_u32(vm->current_frame); int32_t index = operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame); struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); if (arrayref == nullptr)
arrayref->u32[index] = value; return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException"));
assert(arrayref->length > 0);
if (index < 0 || index >= arrayref->length)
return vm_exception(vm, vm_instance_create(vm, "java/lang/ArrayIndexOutOfBoundsException"));
arrayref->ref[index] = ref;
} }
void op_aconst_null(struct vm * vm) void op_aconst_null(struct vm * vm)
@ -72,6 +82,9 @@ void op_anewarray(struct vm * vm, uint32_t index)
index); index);
int32_t count = operand_stack_pop_u32(vm->current_frame); int32_t count = operand_stack_pop_u32(vm->current_frame);
if (count < 0)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NegativeArraySizeException"));
struct arrayref * arrayref = ref_array_allocate(vm, count); struct arrayref * arrayref = ref_array_allocate(vm, count);
assert(arrayref != nullptr); assert(arrayref != nullptr);
arrayref->class_entry = class_entry; arrayref->class_entry = class_entry;
@ -94,6 +107,8 @@ void op_areturn(struct vm * vm)
void op_arraylength(struct vm * vm) void op_arraylength(struct vm * vm)
{ {
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame); struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
if (arrayref == nullptr)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException"));
int32_t length = arrayref->length; int32_t length = arrayref->length;
operand_stack_push_u32(vm->current_frame, length); operand_stack_push_u32(vm->current_frame, length);
} }
@ -131,6 +146,8 @@ void op_astore_3(struct vm * vm)
void op_athrow(struct vm * vm) void op_athrow(struct vm * vm)
{ {
struct objectref * objectref = operand_stack_pop_ref(vm->current_frame); struct objectref * objectref = operand_stack_pop_ref(vm->current_frame);
if (objectref == nullptr)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException"));
vm_exception(vm, objectref); vm_exception(vm, objectref);
} }
@ -138,7 +155,11 @@ void op_baload(struct vm * vm)
{ {
int32_t index = operand_stack_pop_u32(vm->current_frame); int32_t index = operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame); struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); if (arrayref == nullptr)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException"));
assert(arrayref->length > 0);
if (index < 0 || index >= arrayref->length)
return vm_exception(vm, vm_instance_create(vm, "java/lang/ArrayIndexOutOfBoundsException"));
int8_t value = arrayref->u8[index]; int8_t value = arrayref->u8[index];
operand_stack_push_u32(vm->current_frame, value); operand_stack_push_u32(vm->current_frame, value);
} }
@ -148,7 +169,11 @@ void op_bastore(struct vm * vm)
uint8_t value = operand_stack_pop_u32(vm->current_frame); uint8_t value = operand_stack_pop_u32(vm->current_frame);
int32_t index = operand_stack_pop_u32(vm->current_frame); int32_t index = operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame); struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); if (arrayref == nullptr)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException"));
assert(arrayref->length > 0);
if (index < 0 || index >= arrayref->length)
return vm_exception(vm, vm_instance_create(vm, "java/lang/ArrayIndexOutOfBoundsException"));
arrayref->u8[index] = value; arrayref->u8[index] = value;
} }
@ -166,7 +191,11 @@ void op_caload(struct vm * vm)
{ {
int32_t index = operand_stack_pop_u32(vm->current_frame); int32_t index = operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame); struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); if (arrayref == nullptr)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException"));
assert(arrayref->length > 0);
if (index < 0 || index >= arrayref->length)
return vm_exception(vm, vm_instance_create(vm, "java/lang/ArrayIndexOutOfBoundsException"));
uint16_t value = arrayref->u16[index]; uint16_t value = arrayref->u16[index];
operand_stack_push_u32(vm->current_frame, value); operand_stack_push_u32(vm->current_frame, value);
} }
@ -176,7 +205,11 @@ void op_castore(struct vm * vm)
uint16_t value = operand_stack_pop_u32(vm->current_frame); uint16_t value = operand_stack_pop_u32(vm->current_frame);
int32_t index = operand_stack_pop_u32(vm->current_frame); int32_t index = operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame); struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); if (arrayref == nullptr)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException"));
assert(arrayref->length > 0);
if (index < 0 || index >= arrayref->length)
return vm_exception(vm, vm_instance_create(vm, "java/lang/ArrayIndexOutOfBoundsException"));
arrayref->u16[index] = value; arrayref->u16[index] = value;
} }
@ -190,9 +223,8 @@ void op_checkcast(struct vm * vm, uint32_t index)
vm->current_frame->class_entry, vm->current_frame->class_entry,
index, index,
objectref); objectref);
if (!isinstance) { if (!isinstance)
assert(!"ClassCastException"); return vm_exception(vm, vm_instance_create(vm, "java/lang/ClassCastException"));
}
} }
} }
@ -229,7 +261,11 @@ void op_daload(struct vm * vm)
{ {
int32_t index = operand_stack_pop_u32(vm->current_frame); int32_t index = operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame); struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); if (arrayref == nullptr)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException"));
assert(arrayref->length > 0);
if (index < 0 || index >= arrayref->length)
return vm_exception(vm, vm_instance_create(vm, "java/lang/ArrayIndexOutOfBoundsException"));
uint64_t value = arrayref->u64[index]; uint64_t value = arrayref->u64[index];
operand_stack_push_u64(vm->current_frame, value); operand_stack_push_u64(vm->current_frame, value);
} }
@ -239,7 +275,11 @@ void op_dastore(struct vm * vm)
int64_t value = operand_stack_pop_u64(vm->current_frame); int64_t value = operand_stack_pop_u64(vm->current_frame);
int32_t index = operand_stack_pop_u32(vm->current_frame); int32_t index = operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame); struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); if (arrayref == nullptr)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException"));
assert(arrayref->length > 0);
if (index < 0 || index >= arrayref->length)
return vm_exception(vm, vm_instance_create(vm, "java/lang/ArrayIndexOutOfBoundsException"));
arrayref->u64[index] = value; arrayref->u64[index] = value;
} }
@ -511,7 +551,11 @@ void op_faload(struct vm * vm)
{ {
int32_t index = operand_stack_pop_u32(vm->current_frame); int32_t index = operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame); struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); if (arrayref == nullptr)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException"));
assert(arrayref->length > 0);
if (index < 0 || index >= arrayref->length)
return vm_exception(vm, vm_instance_create(vm, "java/lang/ArrayIndexOutOfBoundsException"));
uint32_t value = arrayref->u32[index]; uint32_t value = arrayref->u32[index];
operand_stack_push_u32(vm->current_frame, value); operand_stack_push_u32(vm->current_frame, value);
} }
@ -521,7 +565,11 @@ void op_fastore(struct vm * vm)
uint32_t value = operand_stack_pop_u32(vm->current_frame); uint32_t value = operand_stack_pop_u32(vm->current_frame);
int32_t index = operand_stack_pop_u32(vm->current_frame); int32_t index = operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame); struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); if (arrayref == nullptr)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException"));
assert(arrayref->length > 0);
if (index < 0 || index >= arrayref->length)
return vm_exception(vm, vm_instance_create(vm, "java/lang/ArrayIndexOutOfBoundsException"));
arrayref->u32[index] = value; arrayref->u32[index] = value;
} }
@ -697,7 +745,8 @@ void op_getfield(struct vm * vm, uint32_t index)
debugf("getfield instance_index %d\n", field_entry->instance_index); debugf("getfield instance_index %d\n", field_entry->instance_index);
struct objectref * objectref = operand_stack_pop_ref(vm->current_frame); struct objectref * objectref = operand_stack_pop_ref(vm->current_frame);
assert(objectref != nullptr); if (objectref == nullptr)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException"));
switch (field_descriptor_constant->utf8.bytes[0]) { switch (field_descriptor_constant->utf8.bytes[0]) {
case 'B': [[fallthrough]]; case 'B': [[fallthrough]];
@ -723,7 +772,7 @@ void op_getfield(struct vm * vm, uint32_t index)
} }
break; break;
default: default:
assert(false); assert(!"invalid field_descriptor_constant");
} }
} }
@ -836,7 +885,11 @@ void op_iaload(struct vm * vm)
{ {
int32_t index = operand_stack_pop_u32(vm->current_frame); int32_t index = operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame); struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); if (arrayref == nullptr)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException"));
assert(arrayref->length > 0);
if (index < 0 || index >= arrayref->length)
return vm_exception(vm, vm_instance_create(vm, "java/lang/ArrayIndexOutOfBoundsException"));
int32_t value = arrayref->u32[index]; int32_t value = arrayref->u32[index];
operand_stack_push_u32(vm->current_frame, value); operand_stack_push_u32(vm->current_frame, value);
} }
@ -854,7 +907,11 @@ void op_iastore(struct vm * vm)
uint32_t value = operand_stack_pop_u32(vm->current_frame); uint32_t value = operand_stack_pop_u32(vm->current_frame);
int32_t index = operand_stack_pop_u32(vm->current_frame); int32_t index = operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame); struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); if (arrayref == nullptr)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException"));
assert(arrayref->length > 0);
if (index < 0 || index >= arrayref->length)
return vm_exception(vm, vm_instance_create(vm, "java/lang/ArrayIndexOutOfBoundsException"));
arrayref->u32[index] = value; arrayref->u32[index] = value;
} }
@ -897,6 +954,8 @@ void op_idiv(struct vm * vm)
{ {
int32_t value2 = operand_stack_pop_u32(vm->current_frame); int32_t value2 = operand_stack_pop_u32(vm->current_frame);
int32_t value1 = operand_stack_pop_u32(vm->current_frame); int32_t value1 = operand_stack_pop_u32(vm->current_frame);
if (value2 == 0)
return vm_exception(vm, vm_instance_create(vm, "java/lang/ArithmeticException"));
int32_t result = value1 / value2; int32_t result = value1 / value2;
operand_stack_push_u32(vm->current_frame, result); operand_stack_push_u32(vm->current_frame, result);
} }
@ -1123,7 +1182,8 @@ void op_invokedynamic(struct vm * vm, uint32_t index)
void op_invokeinterface(struct vm * vm, uint32_t index, uint32_t count) void op_invokeinterface(struct vm * vm, uint32_t index, uint32_t count)
{ {
struct objectref * objectref = operand_stack_peek_ref(vm->current_frame, count); struct objectref * objectref = operand_stack_peek_ref(vm->current_frame, count);
assert(objectref != nullptr); if (objectref == nullptr)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException"));
struct class_entry * class_entry = objectref->class_entry; struct class_entry * class_entry = objectref->class_entry;
struct method_entry method_entry = struct method_entry method_entry =
@ -1138,6 +1198,23 @@ void op_invokeinterface(struct vm * vm, uint32_t index, uint32_t count)
void op_invokespecial(struct vm * vm, uint32_t index) void op_invokespecial(struct vm * vm, uint32_t index)
{ {
struct class_entry * origin_class_entry = vm->current_frame->class_entry;
struct constant * interfacemethodref_constant = &origin_class_entry->class_file->constant_pool[index - 1];
assert(interfacemethodref_constant->tag == CONSTANT_Methodref);
struct constant * nameandtype_constant = &origin_class_entry->class_file->constant_pool[interfacemethodref_constant->interfacemethodref.name_and_type_index - 1];
assert(nameandtype_constant->tag == CONSTANT_NameAndType);
struct constant * method_descriptor_constant = &origin_class_entry->class_file->constant_pool[nameandtype_constant->nameandtype.descriptor_index - 1];
assert(method_descriptor_constant->tag == CONSTANT_Utf8);
uint8_t return_type;
int nargs = descriptor_nargs(method_descriptor_constant, &return_type);
(void)return_type;
struct objectref * objectref = operand_stack_peek_ref(vm->current_frame, nargs + 1);
if (objectref == nullptr)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException"));
struct method_entry * method_entry = struct method_entry * method_entry =
class_resolver_lookup_method_from_methodref_index(vm->class_hash_table.length, class_resolver_lookup_method_from_methodref_index(vm->class_hash_table.length,
vm->class_hash_table.entry, vm->class_hash_table.entry,
@ -1178,9 +1255,9 @@ void op_invokevirtual(struct vm * vm, uint32_t index)
(void)return_type; (void)return_type;
struct objectref * objectref = operand_stack_peek_ref(vm->current_frame, nargs + 1); struct objectref * objectref = operand_stack_peek_ref(vm->current_frame, nargs + 1);
assert(objectref != nullptr); if (objectref == nullptr)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException"));
struct class_entry * class_entry = objectref->class_entry; struct class_entry * class_entry = objectref->class_entry;
debugf("class_entry: %p\n", class_entry);
struct method_entry method_entry = struct method_entry method_entry =
class_resolver_lookup_method_from_interfacemethodref_index(vm->class_hash_table.length, class_resolver_lookup_method_from_interfacemethodref_index(vm->class_hash_table.length,
@ -1204,6 +1281,8 @@ void op_irem(struct vm * vm)
{ {
int32_t value2 = operand_stack_pop_u32(vm->current_frame); int32_t value2 = operand_stack_pop_u32(vm->current_frame);
int32_t value1 = operand_stack_pop_u32(vm->current_frame); int32_t value1 = operand_stack_pop_u32(vm->current_frame);
if (value2 == 0)
return vm_exception(vm, vm_instance_create(vm, "java/lang/ArithmeticException"));
int32_t result = value1 % value2; int32_t result = value1 % value2;
operand_stack_push_u32(vm->current_frame, result); operand_stack_push_u32(vm->current_frame, result);
} }
@ -1366,7 +1445,11 @@ void op_laload(struct vm * vm)
{ {
int32_t index = operand_stack_pop_u32(vm->current_frame); int32_t index = operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame); struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); if (arrayref == nullptr)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException"));
assert(arrayref->length > 0);
if (index < 0 || index >= arrayref->length)
return vm_exception(vm, vm_instance_create(vm, "java/lang/ArrayIndexOutOfBoundsException"));
int64_t value = arrayref->u64[index]; int64_t value = arrayref->u64[index];
operand_stack_push_u64(vm->current_frame, value); operand_stack_push_u64(vm->current_frame, value);
} }
@ -1384,7 +1467,11 @@ void op_lastore(struct vm * vm)
uint64_t value = operand_stack_pop_u64(vm->current_frame); uint64_t value = operand_stack_pop_u64(vm->current_frame);
int32_t index = operand_stack_pop_u32(vm->current_frame); int32_t index = operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame); struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); if (arrayref == nullptr)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException"));
assert(arrayref->length > 0);
if (index < 0 || index >= arrayref->length)
return vm_exception(vm, vm_instance_create(vm, "java/lang/ArrayIndexOutOfBoundsException"));
arrayref->u64[index] = value; arrayref->u64[index] = value;
} }
@ -1461,6 +1548,8 @@ void op_ldiv(struct vm * vm)
{ {
int64_t value2 = operand_stack_pop_u64(vm->current_frame); int64_t value2 = operand_stack_pop_u64(vm->current_frame);
int64_t value1 = operand_stack_pop_u64(vm->current_frame); int64_t value1 = operand_stack_pop_u64(vm->current_frame);
if (value2 == 0)
return vm_exception(vm, vm_instance_create(vm, "java/lang/ArithmeticException"));
int64_t result = value1 / value2; int64_t result = value1 / value2;
operand_stack_push_u64(vm->current_frame, result); operand_stack_push_u64(vm->current_frame, result);
} }
@ -1546,6 +1635,8 @@ void op_lrem(struct vm * vm)
{ {
int64_t value2 = operand_stack_pop_u64(vm->current_frame); int64_t value2 = operand_stack_pop_u64(vm->current_frame);
int64_t value1 = operand_stack_pop_u64(vm->current_frame); int64_t value1 = operand_stack_pop_u64(vm->current_frame);
if (value2 == 0)
return vm_exception(vm, vm_instance_create(vm, "java/lang/ArithmeticException"));
int64_t result = value1 % value2; int64_t result = value1 % value2;
operand_stack_push_u64(vm->current_frame, result); operand_stack_push_u64(vm->current_frame, result);
} }
@ -1699,7 +1790,10 @@ void op_multianewarray(struct vm * vm, uint32_t index, uint32_t dimensions)
assert(dimensions > 0); assert(dimensions > 0);
int32_t dims[dimensions]; int32_t dims[dimensions];
for (int i = 0; i < dimensions; i++) { for (int i = 0; i < dimensions; i++) {
dims[dimensions - i - 1] = operand_stack_pop_u32(vm->current_frame); int32_t dim = operand_stack_pop_u32(vm->current_frame);
if (dim < 0)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NegativeArraySizeException"));
dims[dimensions - i - 1] = dim;
} }
struct arrayref * arrayref = _multiarray(vm, dims, dimensions, 0, type + 1, type_end); struct arrayref * arrayref = _multiarray(vm, dims, dimensions, 0, type + 1, type_end);
operand_stack_push_ref(vm->current_frame, arrayref); operand_stack_push_ref(vm->current_frame, arrayref);
@ -1742,6 +1836,8 @@ void op_new(struct vm * vm, uint32_t index)
void op_newarray(struct vm * vm, uint32_t atype) void op_newarray(struct vm * vm, uint32_t atype)
{ {
int32_t count = operand_stack_pop_u32(vm->current_frame); int32_t count = operand_stack_pop_u32(vm->current_frame);
if (count < 0)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NegativeArraySizeException"));
int32_t element_size = array_element_size(atype); int32_t element_size = array_element_size(atype);
struct arrayref * arrayref = prim_array_allocate(vm, element_size, count); struct arrayref * arrayref = prim_array_allocate(vm, element_size, count);
assert(arrayref != nullptr); assert(arrayref != nullptr);
@ -1809,7 +1905,8 @@ void op_putfield(struct vm * vm, uint32_t index)
{ {
uint32_t value = operand_stack_pop_u32(vm->current_frame); uint32_t value = operand_stack_pop_u32(vm->current_frame);
struct objectref * objectref = operand_stack_pop_ref(vm->current_frame); struct objectref * objectref = operand_stack_pop_ref(vm->current_frame);
assert(objectref != nullptr); if (objectref == nullptr)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException"));
objectref->u32[field_entry->instance_index] = value; objectref->u32[field_entry->instance_index] = value;
} }
break; break;
@ -1819,7 +1916,8 @@ void op_putfield(struct vm * vm, uint32_t index)
uint32_t high = operand_stack_pop_u32(vm->current_frame); uint32_t high = operand_stack_pop_u32(vm->current_frame);
uint32_t low = operand_stack_pop_u32(vm->current_frame); uint32_t low = operand_stack_pop_u32(vm->current_frame);
struct objectref * objectref = operand_stack_pop_ref(vm->current_frame); struct objectref * objectref = operand_stack_pop_ref(vm->current_frame);
assert(objectref != nullptr); if (objectref == nullptr)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException"));
objectref->u32[field_entry->instance_index + 1] = high; objectref->u32[field_entry->instance_index + 1] = high;
objectref->u32[field_entry->instance_index] = low; objectref->u32[field_entry->instance_index] = low;
} }
@ -1896,7 +1994,11 @@ void op_saload(struct vm * vm)
{ {
int32_t index = operand_stack_pop_u32(vm->current_frame); int32_t index = operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame); struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); if (arrayref == nullptr)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException"));
assert(arrayref->length > 0);
if (index < 0 || index >= arrayref->length)
return vm_exception(vm, vm_instance_create(vm, "java/lang/ArrayIndexOutOfBoundsException"));
int16_t value = arrayref->u16[index]; int16_t value = arrayref->u16[index];
operand_stack_push_u32(vm->current_frame, value); operand_stack_push_u32(vm->current_frame, value);
} }
@ -1906,7 +2008,11 @@ void op_sastore(struct vm * vm)
uint16_t value = operand_stack_pop_u32(vm->current_frame); uint16_t value = operand_stack_pop_u32(vm->current_frame);
int32_t index = operand_stack_pop_u32(vm->current_frame); int32_t index = operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame); struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length); if (arrayref == nullptr)
return vm_exception(vm, vm_instance_create(vm, "java/lang/NullPointerException"));
assert(arrayref->length > 0);
if (index < 0 || index >= arrayref->length)
return vm_exception(vm, vm_instance_create(vm, "java/lang/ArrayIndexOutOfBoundsException"));
arrayref->u16[index] = value; arrayref->u16[index] = value;
} }

View File

@ -392,7 +392,6 @@ void vm_exception(struct vm * vm, struct objectref * objectref)
debugs("\n method: "); debugs("\n method: ");
debug_print__method_info__method_name(vm->current_frame->class_entry->class_file, vm->current_frame->method_info); debug_print__method_info__method_name(vm->current_frame->class_entry->class_file, vm->current_frame->method_info);
debugf("\n pc: %d", vm->current_frame->pc); debugf("\n pc: %d", vm->current_frame->pc);
debugf("\n next_pc: %d\n", vm->current_frame->next_pc);
return; return;
} }

View File

@ -204,8 +204,6 @@ struct hash_table_entry * hash_table_add3(int hash_table_length,
hash = fnv_1(hash, key3, key3_length); hash = fnv_1(hash, key3, key3_length);
hash &= (hash_table_length - 1); hash &= (hash_table_length - 1);
printf("hash: %d %u %p\n", hash_table_length, hash, value);
struct hash_table_entry * e = &entry[hash]; struct hash_table_entry * e = &entry[hash];
while (e->next != nullptr) { while (e->next != nullptr) {
@ -270,8 +268,6 @@ struct hash_table_entry * hash_table_find3(int hash_table_length,
hash = fnv_1(hash, key3, key3_length); hash = fnv_1(hash, key3, key3_length);
hash &= (hash_table_length - 1); hash &= (hash_table_length - 1);
printf("hash: %d %u\n", hash_table_length, hash);
struct hash_table_entry * e = &entry[hash]; struct hash_table_entry * e = &entry[hash];
while (e != nullptr && e->key != nullptr) { while (e != nullptr && e->key != nullptr) {

View File

@ -40,6 +40,7 @@ struct arrayref {
// object array: // object array:
struct objectref * oref[0]; struct objectref * oref[0];
struct arrayref * aref[0]; struct arrayref * aref[0];
void * ref[0];
// primitive array: // primitive array:
uint8_t u8[0]; uint8_t u8[0];
uint16_t u16[0]; uint16_t u16[0];

View File

@ -0,0 +1,4 @@
package java.lang;
public class ArithmeticException extends RuntimeException {
}

View File

@ -0,0 +1,4 @@
package java.lang;
public class ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException {
}

View File

@ -0,0 +1,4 @@
package java.lang;
public class ArrayStoreException extends RuntimeException {
}

View File

@ -1,3 +1,5 @@
package java.lang;
class Backtrace { class Backtrace {
int[] backtrace_entry; // is actually (struct backtrace_entry) int[] backtrace_entry; // is actually (struct backtrace_entry)

View File

@ -0,0 +1,4 @@
package java.lang;
public class ClassCastException extends RuntimeException {
}

View File

@ -0,0 +1,4 @@
package java.lang;
public class Error extends Throwable {
}

View File

@ -0,0 +1,4 @@
package java.lang;
public class IndexOutOfBoundsException extends RuntimeException {
}

View File

@ -0,0 +1,4 @@
package java.lang;
public class NegativeArraySizeException extends RuntimeException {
}

View File

@ -0,0 +1,4 @@
package java.lang;
public class NullPointerException extends RuntimeException {
}

View File

@ -0,0 +1,4 @@
package java.lang;
public class RuntimeException extends Exception {
}

View File

@ -5,7 +5,7 @@ public class StringBuilder {
int count; int count;
public StringBuilder() { public StringBuilder() {
strings = new String[0]; strings = new String[5];
} }
public StringBuilder(int capacity) { public StringBuilder(int capacity) {
@ -14,7 +14,9 @@ public class StringBuilder {
private void ensureCapacityInternal(int minimumCapacity) { private void ensureCapacityInternal(int minimumCapacity) {
if (strings.length < minimumCapacity) { if (strings.length < minimumCapacity) {
String[] new_strings = new String[minimumCapacity + 3]; // round up to nearest allocation unit
int new_capacity = ((minimumCapacity + 3 + 7) & (~7)) - 3;
String[] new_strings = new String[new_capacity];
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
new_strings[i] = strings[i]; new_strings[i] = strings[i];
} }

View File

@ -0,0 +1,260 @@
package test;
class TestRuntimeException {
public static void testAA1() {
Object[] a = null;
Object b = a[0];
}
public static void testAA2() {
Object[] a = new Object[1];
Object b = a[42];
}
public static void testAA3() {
Object[] a = null;
a[0] = null;
}
public static void testAA4() {
Object[] a = new Object[1];
a[42] = null;
}
public static void test5() {
Object[] a = new Object[-5];
}
public static void test6() {
Object[] a = null;
int b = a.length;
}
public static void test7() throws Exception {
Exception e = null;
throw e;
}
public static void testBA1() {
byte[] a = null;
byte b = a[0];
}
public static void testBA2() {
byte[] a = new byte[1];
byte b = a[42];
}
public static void testBA3() {
byte[] a = null;
a[0] = 0;
}
public static void testBA4() {
byte[] a = new byte[1];
a[42] = 0;
}
public static void testCA1() {
char[] a = null;
char b = a[0];
}
public static void testCA2() {
char[] a = new char[1];
char b = a[42];
}
public static void testCA3() {
char[] a = null;
a[0] = 0;
}
public static void testCA4() {
char[] a = new char[1];
a[42] = 0;
}
public static void testCC() {
NullPointerException a = new NullPointerException();
Object b = a;
ArrayIndexOutOfBoundsException c = (ArrayIndexOutOfBoundsException)b;
}
public static void testDA1() {
double[] a = null;
double b = a[0];
}
public static void testDA2() {
double[] a = new double[1];
double b = a[42];
}
public static void testDA3() {
double[] a = null;
a[0] = 0;
}
public static void testDA4() {
double[] a = new double[1];
a[42] = 0;
}
public static void testFA1() {
float[] a = null;
float b = a[0];
}
public static void testFA2() {
float[] a = new float[1];
float b = a[42];
}
public static void testFA3() {
float[] a = null;
a[0] = 0;
}
public static void testFA4() {
float[] a = new float[1];
a[42] = 0;
}
public static void testIA1() {
int[] a = null;
int b = a[0];
}
public static void testIA2() {
int[] a = new int[1];
int b = a[42];
}
public static void testIA3() {
int[] a = null;
a[0] = 0;
}
public static void testIA4() {
int[] a = new int[1];
a[42] = 0;
}
public static void testidiv() {
int a = 42;
int b = 0;
int c = a / b;
}
public static void testirem() {
int a = 42;
int b = 0;
int c = a % b;
}
public static void testldiv() {
long a = 42;
long b = 0;
long c = a / b;
}
public static void testlrem() {
long a = 42;
long b = 0;
long c = a % b;
}
public static void testLA1() {
long[] a = null;
long b = a[0];
}
public static void testLA2() {
long[] a = new long[1];
long b = a[42];
}
public static void testLA3() {
long[] a = null;
a[0] = 0;
}
public static void testLA4() {
long[] a = new long[1];
a[42] = 0;
}
public static void testmultianewarray() {
int[][] a = new int[-1][-1];
}
public static void testnewarray() {
int[] a = new int[-1];
}
public static void testSA1() {
short[] a = null;
short b = a[0];
}
public static void testSA2() {
short[] a = new short[1];
short b = a[42];
}
public static void testSA3() {
short[] a = null;
a[0] = 0;
}
public static void testSA4() {
short[] a = new short[1];
a[42] = 0;
}
public static void main() throws Exception {
//testAA1();
//testAA2();
//testAA3();
//testAA4();
//test5();
//test6();
//test7();
//testBA1();
//testBA2();
//testBA3();
//testBA4();
//testCA1();
//testCA2();
//testCA3();
//testCA4();
//testCC();
//testDA1();
//testDA2();
//testDA3();
//testDA4();
//testFA1();
//testFA2();
//testFA3();
//testFA4();
//testIA1();
//testIA2();
//testIA3();
//testIA4();
//testidiv();
//testirem();
//testldiv();
//testlrem();
//testLA1();
//testLA2();
//testLA3();
//testLA4();
//testmultianewarray();
//testnewarray();
//testSA1();
//testSA2();
//testSA3();
//testSA4();
}
}