implement all reference operations

This commit is contained in:
Zack Buhman 2024-12-25 06:30:45 -06:00
parent bba08c9a3e
commit f1709eb369
7 changed files with 212 additions and 33 deletions

View File

@ -73,7 +73,7 @@ struct hash_table_entry * class_resolver_load_from_filenames(const char * filena
printf("\n"); printf("\n");
field_entry[i].field_info = &class_file->fields[i]; 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, hash_table_add(fields_hash_table_length,
fields_hash_table, fields_hash_table,

View File

@ -8,17 +8,27 @@
void op_aaload(struct vm * vm) 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) 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) 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) 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) 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) 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) void op_arraylength(struct vm * vm)
@ -105,12 +128,22 @@ void op_athrow(struct vm * vm)
void op_baload(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) 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) 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) void op_i2b(struct vm * vm)
{ {
uint32_t value = operand_stack_pop_u32(vm->current_frame); 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); 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) 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) 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) void op_if_icmpeq(struct vm * vm, int32_t branch)
@ -1532,12 +1573,14 @@ void op_new(struct vm * vm, uint32_t index)
reference to the instance, is pushed onto the operand stack. */ reference to the instance, is pushed onto the operand stack. */
int fields_count = class_entry->class_file->fields_count; int fields_count = class_entry->class_file->fields_count;
(void)fields_count; int32_t * objectref = (int32_t *)-1;
int32_t * objectref = memory_allocate(fields_count * 2 * 4); if (fields_count > 0) {
objectref = memory_allocate(fields_count * 2 * 4);
for (int i = 0; i < fields_count; i++) { for (int i = 0; i < fields_count; i++) {
objectref[i * 2] = 0; objectref[i * 2] = 0;
objectref[i * 2 + 1] = 0; objectref[i * 2 + 1] = 0;
} }
}
operand_stack_push_u32(vm->current_frame, (uint32_t)objectref); 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) 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) 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) void op_sipush(struct vm * vm, int32_t byte)

View File

@ -47,7 +47,7 @@ int find_constantvalue_name_index(struct class_file * class_file)
return 0; 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->tag == CONSTANT_Utf8);
assert(descriptor_constant->utf8.length >= 2); assert(descriptor_constant->utf8.length >= 2);
@ -56,6 +56,7 @@ static int descriptor_nargs(struct constant * descriptor_constant)
printf("method descriptor: "); printf("method descriptor: ");
print_utf8_string(descriptor_constant); print_utf8_string(descriptor_constant);
printf("\n"); printf("\n");
printf("args: `");
int i = 1; int i = 1;
int nargs = 0; int nargs = 0;
@ -70,19 +71,37 @@ static int descriptor_nargs(struct constant * descriptor_constant)
case 'J': case 'J':
nargs += 2; nargs += 2;
break; break;
case 'L':
nargs += 1;
while (descriptor_constant->utf8.bytes[i] != ';') i += 1;
break;
default: default:
nargs += 1; nargs += 1;
break; break;
} }
i += 1; i += 1;
} }
assert(i + 2 == descriptor_constant->utf8.length); printf("\n");
*return_type = descriptor_constant->utf8.bytes[i + 1];
return nargs; return nargs;
} }
bool vm_initialize_class(struct vm * vm, struct class_entry * class_entry) 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) if (class_entry->initialization_state == CLASS_INITIALIZED)
return true; 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.bytes,
name_constant->utf8.length); name_constant->utf8.length);
assert(field_entry != nullptr); assert(field_entry != nullptr);
field_entry->value = constantvalue->integer.bytes; field_entry->value32 = constantvalue->integer.bytes;
printf(" constantvalue: %d\n", field_entry->value); printf(" constantvalue: %d\n", field_entry->value32);
break; 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->current_frame->next_pc = vm->current_frame->pc;
vm_static_method_call(vm, class_file, method_info); vm_static_method_call(vm, class_file, method_info);
// tamper with initialization_frame
vm->current_frame->initialization_frame = class_entry;
return false; return false;
} else {
class_entry->initialization_state = CLASS_INITIALIZED;
printf("<clinit> does not exist for this class\n");
} }
return true; 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->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 = stack_push_data(&vm->data_stack, code->max_stack);
vm->current_frame->operand_stack_ix = 0; 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]; 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; nargs += 1;
printf("nargs+1: %d\n", nargs); printf("nargs+1: %d\n", nargs);
for (int i = 0; i < nargs; i++) { 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); printf("local[%d] = %x\n", nargs - i - 1, value);
vm->current_frame->local_variable[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->pc = 0;
vm->current_frame->class = class_file; 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->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 = stack_push_data(&vm->data_stack, code->max_stack);
vm->current_frame->operand_stack_ix = 0; 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]; 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); printf("nargs %d\n", nargs);
for (int i = 0; i < nargs; i++) { for (int i = 0; i < nargs; i++) {
uint32_t value = operand_stack_pop_u32(old_frame); uint32_t value = operand_stack_pop_u32(old_frame);
printf("local[%d] = %x\n", nargs - i - 1, value); printf("local[%d] = %x\n", nargs - i - 1, value);
vm->current_frame->local_variable[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->pc = 0;
vm->current_frame->class = class_file; 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) 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; struct frame * old_frame = vm->current_frame;
stack_pop_data(&vm->data_stack, old_frame->code->max_locals); 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) { switch (old_frame->return_type) {
case 'Z': [[fallthrough]];
case 'B': [[fallthrough]]; case 'B': [[fallthrough]];
case 'C': [[fallthrough]]; case 'C': [[fallthrough]];
case 'S': [[fallthrough]]; case 'F': [[fallthrough]];
case 'I': [[fallthrough]]; case 'I': [[fallthrough]];
case 'F': case 'L': [[fallthrough]];
case 'S': [[fallthrough]];
case 'Z':
{ {
uint32_t value = operand_stack_pop_u32(old_frame); uint32_t value = operand_stack_pop_u32(old_frame);
operand_stack_push_u32(vm->current_frame, value); operand_stack_push_u32(vm->current_frame, value);
@ -304,6 +338,7 @@ void vm_method_return(struct vm * vm)
break; break;
default: default:
fprintf(stderr, "return type not implemented: %c\n", old_frame->return_type); fprintf(stderr, "return type not implemented: %c\n", old_frame->return_type);
assert(false);
break; break;
} }
assert(old_frame->operand_stack_ix == 0); assert(old_frame->operand_stack_ix == 0);

View File

@ -13,7 +13,8 @@ struct frame {
uint32_t * operand_stack; uint32_t * operand_stack;
uint32_t pc; uint32_t pc;
uint32_t next_pc; uint32_t next_pc;
uint16_t operand_stack_ix; int32_t operand_stack_ix;
struct class_entry * initialization_frame;
uint8_t return_type; uint8_t return_type;
}; };
@ -22,8 +23,8 @@ struct stack {
struct frame * frame; struct frame * frame;
uint32_t * data; uint32_t * data;
}; };
uint32_t ix; int32_t ix;
uint32_t capacity; int32_t capacity;
}; };
struct vm { struct vm {
@ -35,7 +36,6 @@ struct vm {
struct hash_table_entry * entry; struct hash_table_entry * entry;
} class_hash_table; } class_hash_table;
}; };
static inline struct frame * stack_push_frame(struct stack * stack, int num_frames) static inline struct frame * stack_push_frame(struct stack * stack, int num_frames)
{ {
struct frame * frame = &stack->frame[stack->ix]; 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) static inline uint32_t operand_stack_pop_u32(struct frame * frame)
{ {
frame->operand_stack_ix--; frame->operand_stack_ix--;
assert(frame->operand_stack_ix >= 0);
uint32_t value = frame->operand_stack[frame->operand_stack_ix]; uint32_t value = frame->operand_stack[frame->operand_stack_ix];
frame->operand_stack[frame->operand_stack_ix] = -1; frame->operand_stack[frame->operand_stack_ix] = -1;
return value; 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) static inline float operand_stack_pop_f32(struct frame * frame)
{ {
frame->operand_stack_ix--; frame->operand_stack_ix--;
assert(frame->operand_stack_ix >= 0);
uint32_t value = frame->operand_stack[frame->operand_stack_ix]; uint32_t value = frame->operand_stack[frame->operand_stack_ix];
frame->operand_stack[frame->operand_stack_ix] = -1; frame->operand_stack[frame->operand_stack_ix] = -1;
float f = *((float *)&value); 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) static inline uint64_t operand_stack_pop_u64(struct frame * frame)
{ {
frame->operand_stack_ix--; frame->operand_stack_ix--;
assert(frame->operand_stack_ix >= 0);
uint64_t high = frame->operand_stack[frame->operand_stack_ix]; uint64_t high = frame->operand_stack[frame->operand_stack_ix];
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 low = frame->operand_stack[frame->operand_stack_ix];
uint64_t value = (high << 32) | (low << 0); uint64_t value = (high << 32) | (low << 0);
return value; 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) static inline double operand_stack_pop_f64(struct frame * frame)
{ {
frame->operand_stack_ix--; frame->operand_stack_ix--;
assert(frame->operand_stack_ix >= 0);
uint64_t high = frame->operand_stack[frame->operand_stack_ix]; uint64_t high = frame->operand_stack[frame->operand_stack_ix];
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 low = frame->operand_stack[frame->operand_stack_ix];
uint64_t value = (high << 32) | (low << 0); uint64_t value = (high << 32) | (low << 0);
double f = *((double *)&value); double f = *((double *)&value);

17
p/ByteArray.java Normal file
View File

@ -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());
}
}

51
p/NullReference.java Normal file
View File

@ -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();
}
}

17
p/ShortArray.java Normal file
View File

@ -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();
}
}