diff --git a/c/class_resolver.c b/c/class_resolver.c index 0c96f5c..1cebaa8 100644 --- a/c/class_resolver.c +++ b/c/class_resolver.c @@ -73,7 +73,7 @@ struct hash_table_entry * class_resolver_load_from_filenames(const char * filena printf("\n"); field_entry[i].field_info = &class_file->fields[i]; - field_entry[i].value = 0; + field_entry[i].value64 = 0; hash_table_add(fields_hash_table_length, fields_hash_table, diff --git a/c/execute.c b/c/execute.c index e73d8d8..9f90326 100644 --- a/c/execute.c +++ b/c/execute.c @@ -8,17 +8,27 @@ void op_aaload(struct vm * vm) { - assert(!"op_aaload"); + int32_t index = operand_stack_pop_u32(vm->current_frame); + int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame); + assert(arrayref[0] > 0 && index < arrayref[0]); + uint32_t * referencearray = (uint32_t *)&arrayref[1]; + uint32_t value = referencearray[index]; + operand_stack_push_u32(vm->current_frame, value); } void op_aastore(struct vm * vm) { - assert(!"op_aastore"); + uint32_t value = operand_stack_pop_u32(vm->current_frame); + int32_t index = operand_stack_pop_u32(vm->current_frame); + int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame); + assert(arrayref[0] > 0 && index < arrayref[0]); + int32_t * referencearray = (int32_t *)&arrayref[1]; + referencearray[index] = value; } void op_aconst_null(struct vm * vm) { - assert(!"op_aconst_null"); + operand_stack_push_u32(vm->current_frame, 0); } void op_aload(struct vm * vm, uint32_t index) @@ -53,12 +63,25 @@ void op_aload_3(struct vm * vm) void op_anewarray(struct vm * vm, uint32_t index) { - assert(!"op_anewarray"); + int32_t count = operand_stack_pop_u32(vm->current_frame); + int32_t size = 4 * count + 4; + int32_t * arrayref = memory_allocate(size); + assert(arrayref != 0); + arrayref[0] = count; + + /* All components of the new array are initialized to null, the default value + for reference types */ + for (int i = 0; i < count; i++) { + arrayref[i + 1] = 0; + } + + operand_stack_push_u32(vm->current_frame, (uint32_t)arrayref); } void op_areturn(struct vm * vm) { - assert(!"op_areturn"); + assert(vm->current_frame->return_type == 'L'); + vm_method_return(vm); } void op_arraylength(struct vm * vm) @@ -105,12 +128,22 @@ void op_athrow(struct vm * vm) void op_baload(struct vm * vm) { - assert(!"op_baload"); + int32_t index = operand_stack_pop_u32(vm->current_frame); + int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame); + assert(arrayref[0] > 0 && index < arrayref[0]); + int8_t * chararray = (int8_t *)&arrayref[1]; + int8_t value = chararray[index]; + operand_stack_push_u32(vm->current_frame, value); } void op_bastore(struct vm * vm) { - assert(!"op_bastore"); + int8_t value = operand_stack_pop_u32(vm->current_frame); + int32_t index = operand_stack_pop_u32(vm->current_frame); + int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame); + assert(arrayref[0] > 0 && index < arrayref[0]); + int8_t * chararray = (int8_t *)&arrayref[1]; + chararray[index] = value; } void op_bipush(struct vm * vm, int32_t byte) @@ -707,7 +740,7 @@ void op_goto_w(struct vm * vm, int32_t branch) void op_i2b(struct vm * vm) { uint32_t value = operand_stack_pop_u32(vm->current_frame); - uint8_t result = value; + int8_t result = value; operand_stack_push_u32(vm->current_frame, result); } @@ -827,12 +860,20 @@ void op_idiv(struct vm * vm) void op_if_acmpeq(struct vm * vm, int32_t branch) { - assert(!"op_if_acmpeq"); + int32_t value2 = operand_stack_pop_u32(vm->current_frame); + int32_t value1 = operand_stack_pop_u32(vm->current_frame); + if (value1 == value2) { + vm->current_frame->pc = vm->current_frame->pc + branch; + } } void op_if_acmpne(struct vm * vm, int32_t branch) { - assert(!"op_if_acmpne"); + int32_t value2 = operand_stack_pop_u32(vm->current_frame); + int32_t value1 = operand_stack_pop_u32(vm->current_frame); + if (value1 != value2) { + vm->current_frame->pc = vm->current_frame->pc + branch; + } } void op_if_icmpeq(struct vm * vm, int32_t branch) @@ -1532,11 +1573,13 @@ void op_new(struct vm * vm, uint32_t index) reference to the instance, is pushed onto the operand stack. */ int fields_count = class_entry->class_file->fields_count; - (void)fields_count; - int32_t * objectref = memory_allocate(fields_count * 2 * 4); - for (int i = 0; i < fields_count; i++) { - objectref[i * 2] = 0; - objectref[i * 2 + 1] = 0; + int32_t * objectref = (int32_t *)-1; + if (fields_count > 0) { + objectref = memory_allocate(fields_count * 2 * 4); + for (int i = 0; i < fields_count; i++) { + objectref[i * 2] = 0; + objectref[i * 2 + 1] = 0; + } } operand_stack_push_u32(vm->current_frame, (uint32_t)objectref); @@ -1726,12 +1769,22 @@ void op_return(struct vm * vm) void op_saload(struct vm * vm) { - assert(!"op_saload"); + int32_t index = operand_stack_pop_u32(vm->current_frame); + int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame); + assert(arrayref[0] > 0 && index < arrayref[0]); + int16_t * shortarray = (int16_t *)&arrayref[1]; + int16_t value = shortarray[index]; + operand_stack_push_u32(vm->current_frame, value); } void op_sastore(struct vm * vm) { - assert(!"op_sastore"); + uint16_t value = operand_stack_pop_u32(vm->current_frame); + int32_t index = operand_stack_pop_u32(vm->current_frame); + int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame); + assert(arrayref[0] > 0 && index < arrayref[0]); + int16_t * shortarray = (int16_t *)&arrayref[1]; + shortarray[index] = value; } void op_sipush(struct vm * vm, int32_t byte) diff --git a/c/frame.c b/c/frame.c index a555ec0..5b4fc2e 100644 --- a/c/frame.c +++ b/c/frame.c @@ -47,7 +47,7 @@ int find_constantvalue_name_index(struct class_file * class_file) return 0; } -static int descriptor_nargs(struct constant * descriptor_constant) +static int descriptor_nargs(struct constant * descriptor_constant, uint8_t * return_type) { assert(descriptor_constant->tag == CONSTANT_Utf8); assert(descriptor_constant->utf8.length >= 2); @@ -56,6 +56,7 @@ static int descriptor_nargs(struct constant * descriptor_constant) printf("method descriptor: "); print_utf8_string(descriptor_constant); printf("\n"); + printf("args: `"); int i = 1; int nargs = 0; @@ -70,19 +71,37 @@ static int descriptor_nargs(struct constant * descriptor_constant) case 'J': nargs += 2; break; + case 'L': + nargs += 1; + while (descriptor_constant->utf8.bytes[i] != ';') i += 1; + break; default: nargs += 1; break; } i += 1; } - assert(i + 2 == descriptor_constant->utf8.length); + printf("\n"); + + *return_type = descriptor_constant->utf8.bytes[i + 1]; return nargs; } bool vm_initialize_class(struct vm * vm, struct class_entry * class_entry) { + printf("vm_initialize_class: "); + struct constant * class_constant = &class_entry->class_file->constant_pool[class_entry->class_file->this_class - 1]; + #ifdef DEBUG + assert(class_constant->tag == CONSTANT_Class); + #endif + struct constant * class_name_constant = &class_entry->class_file->constant_pool[class_constant->class.name_index - 1]; + #ifdef DEBUG + assert(class_name_constant->tag == CONSTANT_Utf8); + #endif + print_constant(class_name_constant); + printf("\n"); + if (class_entry->initialization_state == CLASS_INITIALIZED) return true; @@ -120,8 +139,8 @@ bool vm_initialize_class(struct vm * vm, struct class_entry * class_entry) name_constant->utf8.bytes, name_constant->utf8.length); assert(field_entry != nullptr); - field_entry->value = constantvalue->integer.bytes; - printf(" constantvalue: %d\n", field_entry->value); + field_entry->value32 = constantvalue->integer.bytes; + printf(" constantvalue: %d\n", field_entry->value32); break; } } @@ -148,7 +167,13 @@ bool vm_initialize_class(struct vm * vm, struct class_entry * class_entry) vm->current_frame->next_pc = vm->current_frame->pc; vm_static_method_call(vm, class_file, method_info); + + // tamper with initialization_frame + vm->current_frame->initialization_frame = class_entry; return false; + } else { + class_entry->initialization_state = CLASS_INITIALIZED; + printf(" does not exist for this class\n"); } return true; @@ -181,9 +206,10 @@ void vm_special_method_call(struct vm * vm, struct class_file * class_file, stru vm->current_frame->local_variable = stack_push_data(&vm->data_stack, code->max_locals); vm->current_frame->operand_stack = stack_push_data(&vm->data_stack, code->max_stack); vm->current_frame->operand_stack_ix = 0; + vm->current_frame->initialization_frame = nullptr; struct constant * descriptor_constant = &class_file->constant_pool[method_info->descriptor_index - 1]; - int nargs = descriptor_nargs(descriptor_constant); + int nargs = descriptor_nargs(descriptor_constant, &vm->current_frame->return_type); nargs += 1; printf("nargs+1: %d\n", nargs); for (int i = 0; i < nargs; i++) { @@ -191,7 +217,6 @@ void vm_special_method_call(struct vm * vm, struct class_file * class_file, stru printf("local[%d] = %x\n", nargs - i - 1, value); vm->current_frame->local_variable[nargs - i - 1] = value; } - vm->current_frame->return_type = descriptor_constant->utf8.bytes[descriptor_constant->utf8.length - 1]; vm->current_frame->pc = 0; vm->current_frame->class = class_file; @@ -227,16 +252,17 @@ void vm_static_method_call(struct vm * vm, struct class_file * class_file, struc vm->current_frame->local_variable = stack_push_data(&vm->data_stack, code->max_locals); vm->current_frame->operand_stack = stack_push_data(&vm->data_stack, code->max_stack); vm->current_frame->operand_stack_ix = 0; + vm->current_frame->initialization_frame = nullptr; struct constant * descriptor_constant = &class_file->constant_pool[method_info->descriptor_index - 1]; - int nargs = descriptor_nargs(descriptor_constant); + int nargs = descriptor_nargs(descriptor_constant, &vm->current_frame->return_type); printf("nargs %d\n", nargs); for (int i = 0; i < nargs; i++) { uint32_t value = operand_stack_pop_u32(old_frame); printf("local[%d] = %x\n", nargs - i - 1, value); vm->current_frame->local_variable[nargs - i - 1] = value; } - vm->current_frame->return_type = descriptor_constant->utf8.bytes[descriptor_constant->utf8.length - 1]; + ; vm->current_frame->pc = 0; vm->current_frame->class = class_file; @@ -247,6 +273,13 @@ void vm_static_method_call(struct vm * vm, struct class_file * class_file, struc void vm_method_return(struct vm * vm) { + if (vm->current_frame->initialization_frame != nullptr) { + printf("vm_method_return: initialization_frame!=nullptr\n"); + struct class_entry * class_entry = vm->current_frame->initialization_frame; + class_entry->initialization_state = CLASS_INITIALIZED; + vm->current_frame->initialization_frame = 0; + } + struct frame * old_frame = vm->current_frame; stack_pop_data(&vm->data_stack, old_frame->code->max_locals); @@ -282,12 +315,13 @@ void vm_method_return(struct vm * vm) */ switch (old_frame->return_type) { - case 'Z': [[fallthrough]]; case 'B': [[fallthrough]]; case 'C': [[fallthrough]]; - case 'S': [[fallthrough]]; + case 'F': [[fallthrough]]; case 'I': [[fallthrough]]; - case 'F': + case 'L': [[fallthrough]]; + case 'S': [[fallthrough]]; + case 'Z': { uint32_t value = operand_stack_pop_u32(old_frame); operand_stack_push_u32(vm->current_frame, value); @@ -304,6 +338,7 @@ void vm_method_return(struct vm * vm) break; default: fprintf(stderr, "return type not implemented: %c\n", old_frame->return_type); + assert(false); break; } assert(old_frame->operand_stack_ix == 0); diff --git a/c/frame.h b/c/frame.h index b9788d5..984911e 100644 --- a/c/frame.h +++ b/c/frame.h @@ -13,7 +13,8 @@ struct frame { uint32_t * operand_stack; uint32_t pc; uint32_t next_pc; - uint16_t operand_stack_ix; + int32_t operand_stack_ix; + struct class_entry * initialization_frame; uint8_t return_type; }; @@ -22,8 +23,8 @@ struct stack { struct frame * frame; uint32_t * data; }; - uint32_t ix; - uint32_t capacity; + int32_t ix; + int32_t capacity; }; struct vm { @@ -35,7 +36,6 @@ struct vm { struct hash_table_entry * entry; } class_hash_table; }; - static inline struct frame * stack_push_frame(struct stack * stack, int num_frames) { struct frame * frame = &stack->frame[stack->ix]; @@ -77,6 +77,7 @@ static inline void operand_stack_push_u32(struct frame * frame, uint32_t value) static inline uint32_t operand_stack_pop_u32(struct frame * frame) { frame->operand_stack_ix--; + assert(frame->operand_stack_ix >= 0); uint32_t value = frame->operand_stack[frame->operand_stack_ix]; frame->operand_stack[frame->operand_stack_ix] = -1; return value; @@ -99,6 +100,7 @@ static inline void operand_stack_push_f32(struct frame * frame, float f) static inline float operand_stack_pop_f32(struct frame * frame) { frame->operand_stack_ix--; + assert(frame->operand_stack_ix >= 0); uint32_t value = frame->operand_stack[frame->operand_stack_ix]; frame->operand_stack[frame->operand_stack_ix] = -1; float f = *((float *)&value); @@ -116,8 +118,10 @@ static inline void operand_stack_push_u64(struct frame * frame, uint64_t value) static inline uint64_t operand_stack_pop_u64(struct frame * frame) { frame->operand_stack_ix--; + assert(frame->operand_stack_ix >= 0); uint64_t high = frame->operand_stack[frame->operand_stack_ix]; frame->operand_stack_ix--; + assert(frame->operand_stack_ix >= 0); uint64_t low = frame->operand_stack[frame->operand_stack_ix]; uint64_t value = (high << 32) | (low << 0); return value; @@ -135,8 +139,10 @@ static inline void operand_stack_push_f64(struct frame * frame, double f) static inline double operand_stack_pop_f64(struct frame * frame) { frame->operand_stack_ix--; + assert(frame->operand_stack_ix >= 0); uint64_t high = frame->operand_stack[frame->operand_stack_ix]; frame->operand_stack_ix--; + assert(frame->operand_stack_ix >= 0); uint64_t low = frame->operand_stack[frame->operand_stack_ix]; uint64_t value = (high << 32) | (low << 0); double f = *((double *)&value); diff --git a/p/ByteArray.java b/p/ByteArray.java new file mode 100644 index 0000000..6ff21c4 --- /dev/null +++ b/p/ByteArray.java @@ -0,0 +1,17 @@ +package p; + +class ByteArray { + static byte test() { + byte[] l = new byte[10]; + for (int i = 0; i < l.length; i++) + l[i] = (byte)(i * 3); + byte sum = 0; + for (int i = 0; i < l.length; i++) + sum += l[i]; + return sum; + } + + public static void main() { + System.out.println(test()); + } +} diff --git a/p/NullReference.java b/p/NullReference.java new file mode 100644 index 0000000..34b676e --- /dev/null +++ b/p/NullReference.java @@ -0,0 +1,51 @@ +package p; + +class NullReference { + int field; + + static int test() { + Object o = null; + if (o == null) + return 1; + else + return 0; + } + + static NullReference test2(NullReference r) { + NullReference b = new NullReference(); + b.field = 39; + return b; + } + + static int test3() { + NullReference a = new NullReference(); + a.field = 12; + NullReference c = test2(a); + + if (a != c) + c.field += 1000; + + return c.field; + } + + static int test4() { + Object[] oa = new Object[10]; + for (int i = 0; i < oa.length; i++) { + if (i % 2 == 0) + oa[i] = null; + else + oa[i] = new Object(); + } + int count = 0; + for (int i = 0; i < oa.length; i++) { + if (oa[i] == null) + count += 1; + } + return count; + } + + public static void main() { + test4(); + test3(); + } +} diff --git a/p/ShortArray.java b/p/ShortArray.java new file mode 100644 index 0000000..5ab5e2e --- /dev/null +++ b/p/ShortArray.java @@ -0,0 +1,17 @@ +package p; + +class ShortArray { + static short test() { + short[] l = new short[10]; + for (int i = 0; i < l.length; i++) + l[i] = (short)(i * 3); + short sum = 0; + for (int i = 0; i < l.length; i++) + sum += l[i]; + return sum; + } + + public static void main() { + test(); + } +}