implement String support

This commit is contained in:
Zack Buhman 2024-12-25 10:10:28 -06:00
parent 3a75d5bcdc
commit f1976baf57
12 changed files with 236 additions and 83 deletions

View File

@ -4,6 +4,9 @@
%.class: %.java %.class: %.java
javac $< javac $<
java/lang/%.class: java/lang/%.java
javac --source 8 --target 8 --boot-class-path . $<
OBJ = \ OBJ = \
c/decode.o \ c/decode.o \
c/class_file.o \ c/class_file.o \

View File

@ -10,6 +10,7 @@
#include "class_resolver.h" #include "class_resolver.h"
#include "string.h" #include "string.h"
#include "debug_class_file.h" #include "debug_class_file.h"
#include "memory_allocator.h"
struct hash_table_entry * class_resolver_load_from_filenames(const char * filenames[], int length, int * hash_table_length) struct hash_table_entry * class_resolver_load_from_filenames(const char * filenames[], int length, int * hash_table_length)
{ {
@ -47,6 +48,13 @@ struct hash_table_entry * class_resolver_load_from_filenames(const char * filena
class_name_length, class_name_length,
&class_entry[i]); &class_entry[i]);
// make hash table for strings
int strings_hash_table_length = class_file->constant_pool_count;
uint32_t strings_hash_table_size = (sizeof (struct hash_table_entry)) * strings_hash_table_length;
struct hash_table_entry * strings_hash_table = malloc_class_arena(strings_hash_table_size);
class_entry[i].strings.length = strings_hash_table_length;
class_entry[i].strings.entry = strings_hash_table;
// make hash table for interfaces // make hash table for interfaces
/* /*
if (class_file->interfaces_count != 0) { if (class_file->interfaces_count != 0) {
@ -186,3 +194,51 @@ struct method_info * class_resolver_lookup_method(struct class_entry * class_ent
return (struct method_info *)e->value; return (struct method_info *)e->value;
} }
int32_t * class_resolver_lookup_string(int class_hash_table_length,
struct hash_table_entry * class_hash_table,
struct class_entry * class_entry,
const int string_index)
{
printf("class_resolver_lookup_string: %d\n", string_index);
int strings_hash_table_length = class_entry->strings.length;
struct hash_table_entry * strings_hash_table = class_entry->strings.entry;
struct hash_table_entry * e = hash_table_find_int(strings_hash_table_length,
strings_hash_table,
string_index);
if (e != nullptr) {
int32_t * objectref = (int32_t *)e->value;
return objectref;
}
struct constant * utf8_constant = &class_entry->class_file->constant_pool[string_index - 1];
assert(utf8_constant->tag == CONSTANT_Utf8);
struct class_entry * string_class_entry = class_resolver_lookup_class(class_hash_table_length,
class_hash_table,
(const uint8_t *)"java/lang/String",
16);
int32_t size = utf8_constant->utf8.length + 4;
int32_t * arrayref = memory_allocate(size);
assert(arrayref != nullptr);
arrayref[0] = utf8_constant->utf8.length;
uint8_t * bytearray = (uint8_t *)&arrayref[1];
for (int i = 0; i < utf8_constant->utf8.length; i++)
bytearray[i] = utf8_constant->utf8.bytes[i];
assert(string_class_entry != nullptr);
int32_t * objectref = memory_allocate(4 + 4);
assert(objectref != nullptr);
objectref[0] = (int32_t)string_class_entry;
objectref[1] = (int32_t)arrayref;
hash_table_add_int(strings_hash_table_length,
strings_hash_table,
string_index,
objectref);
return objectref;
}

View File

@ -23,6 +23,11 @@ struct class_entry {
struct class_file * class_file; struct class_file * class_file;
enum initialization_state initialization_state; enum initialization_state initialization_state;
struct {
int length;
struct hash_table_entry * entry;
} strings;
struct { struct {
int length; int length;
struct hash_table_entry * entry; struct hash_table_entry * entry;
@ -52,3 +57,7 @@ struct method_info * class_resolver_lookup_method(struct class_entry * class_ent
struct field_entry * class_resolver_lookup_field(struct class_entry * class_entry, struct field_entry * class_resolver_lookup_field(struct class_entry * class_entry,
const uint8_t * field_name, const uint8_t * field_name,
int field_name_length); int field_name_length);
int32_t * class_resolver_lookup_string(int class_hash_table_length,
struct hash_table_entry * class_hash_table,
struct class_entry * class_entry,
const int string_index);

View File

@ -131,8 +131,8 @@ 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);
int32_t * arrayref = (int32_t *)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]); assert(arrayref[0] > 0 && index < arrayref[0]);
int8_t * chararray = (int8_t *)&arrayref[1]; int8_t * bytearray = (int8_t *)&arrayref[1];
int8_t value = chararray[index]; int8_t value = bytearray[index];
operand_stack_push_u32(vm->current_frame, value); operand_stack_push_u32(vm->current_frame, value);
} }
@ -142,8 +142,8 @@ void op_bastore(struct vm * vm)
int32_t index = 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); int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame);
assert(arrayref[0] > 0 && index < arrayref[0]); assert(arrayref[0] > 0 && index < arrayref[0]);
int8_t * chararray = (int8_t *)&arrayref[1]; int8_t * bytearray = (int8_t *)&arrayref[1];
chararray[index] = value; bytearray[index] = value;
} }
void op_bipush(struct vm * vm, int32_t byte) void op_bipush(struct vm * vm, int32_t byte)
@ -682,30 +682,34 @@ void op_getfield(struct vm * vm, uint32_t index)
&class_entry, &class_entry,
&field_entry, &field_entry,
&field_descriptor_constant); &field_descriptor_constant);
assert(field_descriptor_constant->utf8.length == 1); // could be an array
assert(field_descriptor_constant->utf8.length == 1 || field_descriptor_constant->utf8.length == 2);
uint32_t field_index = field_entry->field_info - class_entry->class_file->fields; uint32_t field_index = field_entry->field_info - class_entry->class_file->fields;
printf("putfield field_index %d\n", field_index); printf("putfield field_index %d\n", field_index);
int32_t * objectref = (int32_t *)operand_stack_pop_u32(vm->current_frame); int32_t * objectref = (int32_t *)operand_stack_pop_u32(vm->current_frame);
int32_t * objectfields = &objectref[1];
switch (field_descriptor_constant->utf8.bytes[0]) { switch (field_descriptor_constant->utf8.bytes[0]) {
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': [[fallthrough]];
case '[':
{ {
uint32_t value = objectref[field_index]; uint32_t value = objectfields[field_index];
operand_stack_push_u32(vm->current_frame, value); operand_stack_push_u32(vm->current_frame, value);
} }
break; break;
case 'D': [[fallthrough]]; case 'D': [[fallthrough]];
case 'J': case 'J':
{ {
uint32_t low = objectref[field_index * 2]; uint32_t low = objectfields[field_index * 2];
uint32_t high = objectref[field_index * 2 + 1]; uint32_t high = objectfields[field_index * 2 + 1];
operand_stack_push_u32(vm->current_frame, low); operand_stack_push_u32(vm->current_frame, low);
operand_stack_push_u32(vm->current_frame, high); operand_stack_push_u32(vm->current_frame, high);
} }
@ -732,15 +736,17 @@ void op_getstatic(struct vm * vm, uint32_t index)
if (!vm_initialize_class(vm, class_entry)) if (!vm_initialize_class(vm, class_entry))
return; return;
assert(field_descriptor_constant->utf8.length == 1); assert(field_descriptor_constant->utf8.length == 1 || field_descriptor_constant->utf8.length == 2);
switch (field_descriptor_constant->utf8.bytes[0]) { switch (field_descriptor_constant->utf8.bytes[0]) {
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': [[fallthrough]];
case '[':
{ {
uint32_t value = field_entry->value32; uint32_t value = field_entry->value32;
operand_stack_push_u32(vm->current_frame, value); operand_stack_push_u32(vm->current_frame, value);
@ -1110,7 +1116,7 @@ void op_invokespecial(struct vm * vm, uint32_t index)
&class_entry, &class_entry,
&method_info); &method_info);
vm_special_method_call(vm, class_entry->class_file, method_info); vm_special_method_call(vm, class_entry, method_info);
} }
void op_invokestatic(struct vm * vm, uint32_t index) void op_invokestatic(struct vm * vm, uint32_t index)
@ -1125,7 +1131,7 @@ void op_invokestatic(struct vm * vm, uint32_t index)
declared the resolved method is initialized if that class or interface has declared the resolved method is initialized if that class or interface has
not already been initialized (§5.5). */ not already been initialized (§5.5). */
vm_static_method_call(vm, class_entry->class_file, method_info); vm_static_method_call(vm, class_entry, method_info);
} }
void op_invokevirtual(struct vm * vm, uint32_t index) void op_invokevirtual(struct vm * vm, uint32_t index)
@ -1136,7 +1142,7 @@ void op_invokevirtual(struct vm * vm, uint32_t index)
&class_entry, &class_entry,
&method_info); &method_info);
vm_special_method_call(vm, class_entry->class_file, method_info); vm_special_method_call(vm, class_entry, method_info);
} }
void op_ior(struct vm * vm) void op_ior(struct vm * vm)
@ -1361,17 +1367,24 @@ void op_lconst_1(struct vm * vm)
void op_ldc(struct vm * vm, uint32_t index) void op_ldc(struct vm * vm, uint32_t index)
{ {
struct constant * constant = &vm->current_frame->class->constant_pool[index - 1]; struct constant * constant = &vm->current_frame->class_entry->class_file->constant_pool[index - 1];
#ifdef DEBUG if (constant->tag == CONSTANT_Integer || constant->tag == CONSTANT_Float) {
assert(constant->tag == CONSTANT_Integer || constant->tag == CONSTANT_Float);
#endif
int32_t value = constant->integer.bytes; int32_t value = constant->integer.bytes;
operand_stack_push_u32(vm->current_frame, value); operand_stack_push_u32(vm->current_frame, value);
} else if (constant->tag == CONSTANT_String) {
int32_t * objectref = class_resolver_lookup_string(vm->class_hash_table.length,
vm->class_hash_table.entry,
vm->current_frame->class_entry,
constant->string.string_index);
operand_stack_push_u32(vm->current_frame, (uint32_t)objectref);
} else {
assert(false);
}
} }
void op_ldc2_w(struct vm * vm, uint32_t index) void op_ldc2_w(struct vm * vm, uint32_t index)
{ {
struct constant * constant = &vm->current_frame->class->constant_pool[index - 1]; struct constant * constant = &vm->current_frame->class_entry->class_file->constant_pool[index - 1];
#ifdef DEBUG #ifdef DEBUG
assert(constant->tag == CONSTANT_Long || constant->tag == CONSTANT_Double); assert(constant->tag == CONSTANT_Long || constant->tag == CONSTANT_Double);
#endif #endif
@ -1381,7 +1394,7 @@ void op_ldc2_w(struct vm * vm, uint32_t index)
void op_ldc_w(struct vm * vm, uint32_t index) void op_ldc_w(struct vm * vm, uint32_t index)
{ {
struct constant * constant = &vm->current_frame->class->constant_pool[index - 1]; struct constant * constant = &vm->current_frame->class_entry->class_file->constant_pool[index - 1];
#ifdef DEBUG #ifdef DEBUG
assert(constant->tag == CONSTANT_Integer || constant->tag == CONSTANT_Float); assert(constant->tag == CONSTANT_Integer || constant->tag == CONSTANT_Float);
#endif #endif
@ -1579,11 +1592,11 @@ void op_multianewarray(struct vm * vm, uint32_t index, uint32_t dimensions)
void op_new(struct vm * vm, uint32_t index) void op_new(struct vm * vm, uint32_t index)
{ {
struct constant * class_constant = &vm->current_frame->class->constant_pool[index - 1]; struct constant * class_constant = &vm->current_frame->class_entry->class_file->constant_pool[index - 1];
#ifdef DEBUG #ifdef DEBUG
assert(class_constant->tag == CONSTANT_Class); assert(class_constant->tag == CONSTANT_Class);
#endif #endif
struct constant * class_name_constant = &vm->current_frame->class->constant_pool[class_constant->class.name_index - 1]; struct constant * class_name_constant = &vm->current_frame->class_entry->class_file->constant_pool[class_constant->class.name_index - 1];
#ifdef DEBUG #ifdef DEBUG
assert(class_name_constant->tag == CONSTANT_Utf8); assert(class_name_constant->tag == CONSTANT_Utf8);
#endif #endif
@ -1609,13 +1622,13 @@ 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;
int32_t * objectref = (int32_t *)-1; int32_t * objectref = memory_allocate(fields_count * 2 * 4 + 4);
if (fields_count > 0) { assert(objectref != nullptr);
objectref = memory_allocate(fields_count * 2 * 4); objectref[0] = (int32_t)class_entry;
int32_t * objectfields = &objectref[1];
for (int i = 0; i < fields_count; i++) { for (int i = 0; i < fields_count; i++) {
objectref[i * 2] = 0; objectfields[i * 2] = 0;
objectref[i * 2 + 1] = 0; objectfields[i * 2 + 1] = 0;
}
} }
operand_stack_push_u32(vm->current_frame, (uint32_t)objectref); operand_stack_push_u32(vm->current_frame, (uint32_t)objectref);
@ -1709,22 +1722,25 @@ void op_putfield(struct vm * vm, uint32_t index)
type or an array type, then the value must be a value of the field descriptor type or an array type, then the value must be a value of the field descriptor
type. */ type. */
assert(field_descriptor_constant->utf8.length == 1); assert(field_descriptor_constant->utf8.length == 1 || field_descriptor_constant->utf8.length == 2);
uint32_t field_index = field_entry->field_info - class_entry->class_file->fields; uint32_t field_index = field_entry->field_info - class_entry->class_file->fields;
printf("putfield field_index %d\n", field_index); printf("putfield field_index %d\n", field_index);
switch (field_descriptor_constant->utf8.bytes[0]) { switch (field_descriptor_constant->utf8.bytes[0]) {
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': [[fallthrough]];
case '[':
{ {
uint32_t value = operand_stack_pop_u32(vm->current_frame); uint32_t value = operand_stack_pop_u32(vm->current_frame);
int32_t * objectref = (int32_t *)operand_stack_pop_u32(vm->current_frame); int32_t * objectref = (int32_t *)operand_stack_pop_u32(vm->current_frame);
objectref[field_index] = value; int32_t * objectfields = &objectref[1];
objectfields[field_index] = value;
} }
break; break;
case 'D': [[fallthrough]]; case 'D': [[fallthrough]];
@ -1733,8 +1749,9 @@ 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);
int32_t * objectref = (int32_t *)operand_stack_pop_u32(vm->current_frame); int32_t * objectref = (int32_t *)operand_stack_pop_u32(vm->current_frame);
objectref[field_index * 2 + 1] = high; int32_t * objectfields = &objectref[1];
objectref[field_index * 2] = low; objectfields[field_index * 2 + 1] = high;
objectfields[field_index * 2] = low;
} }
break; break;
default: default:
@ -1767,15 +1784,17 @@ void op_putstatic(struct vm * vm, uint32_t index)
if (!vm_initialize_class(vm, class_entry)) if (!vm_initialize_class(vm, class_entry))
return; return;
assert(field_descriptor_constant->utf8.length == 1); assert(field_descriptor_constant->utf8.length == 1 || field_descriptor_constant->utf8.length == 2);
switch (field_descriptor_constant->utf8.bytes[0]) { switch (field_descriptor_constant->utf8.bytes[0]) {
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': [[fallthrough]];
case '[':
{ {
uint32_t value = operand_stack_pop_u32(vm->current_frame); uint32_t value = operand_stack_pop_u32(vm->current_frame);
field_entry->value32 = value; field_entry->value32 = value;

View File

@ -6,27 +6,27 @@ static inline void class_entry_field_entry_from_constant_index(struct vm * vm,
struct field_entry ** field_entry, struct field_entry ** field_entry,
struct constant ** field_descriptor_constant) struct constant ** field_descriptor_constant)
{ {
struct constant * fieldref_constant = &vm->current_frame->class->constant_pool[index - 1]; struct constant * fieldref_constant = &vm->current_frame->class_entry->class_file->constant_pool[index - 1];
#ifdef DEBUG #ifdef DEBUG
assert(fieldref_constant->tag == CONSTANT_Fieldref); assert(fieldref_constant->tag == CONSTANT_Fieldref);
#endif #endif
struct constant * class_constant = &vm->current_frame->class->constant_pool[fieldref_constant->fieldref.class_index - 1]; struct constant * class_constant = &vm->current_frame->class_entry->class_file->constant_pool[fieldref_constant->fieldref.class_index - 1];
#ifdef DEBUG #ifdef DEBUG
assert(class_constant->tag == CONSTANT_Class); assert(class_constant->tag == CONSTANT_Class);
#endif #endif
struct constant * nameandtype_constant = &vm->current_frame->class->constant_pool[fieldref_constant->fieldref.name_and_type_index - 1]; struct constant * nameandtype_constant = &vm->current_frame->class_entry->class_file->constant_pool[fieldref_constant->fieldref.name_and_type_index - 1];
#ifdef DEBUG #ifdef DEBUG
assert(nameandtype_constant->tag == CONSTANT_NameAndType); assert(nameandtype_constant->tag == CONSTANT_NameAndType);
#endif #endif
struct constant * class_name_constant = &vm->current_frame->class->constant_pool[class_constant->class.name_index - 1]; struct constant * class_name_constant = &vm->current_frame->class_entry->class_file->constant_pool[class_constant->class.name_index - 1];
#ifdef DEBUG #ifdef DEBUG
assert(class_name_constant->tag == CONSTANT_Utf8); assert(class_name_constant->tag == CONSTANT_Utf8);
#endif #endif
struct constant * field_name_constant = &vm->current_frame->class->constant_pool[nameandtype_constant->nameandtype.name_index - 1]; struct constant * field_name_constant = &vm->current_frame->class_entry->class_file->constant_pool[nameandtype_constant->nameandtype.name_index - 1];
#ifdef DEBUG #ifdef DEBUG
assert(field_name_constant->tag == CONSTANT_Utf8); assert(field_name_constant->tag == CONSTANT_Utf8);
#endif #endif
*field_descriptor_constant = &vm->current_frame->class->constant_pool[nameandtype_constant->nameandtype.descriptor_index - 1]; *field_descriptor_constant = &vm->current_frame->class_entry->class_file->constant_pool[nameandtype_constant->nameandtype.descriptor_index - 1];
#ifdef DEBUG #ifdef DEBUG
assert((*field_descriptor_constant)->tag == CONSTANT_Utf8); assert((*field_descriptor_constant)->tag == CONSTANT_Utf8);
#endif #endif
@ -48,27 +48,27 @@ static inline void class_entry_method_info_from_constant_index(struct vm * vm,
struct class_entry ** class_entry, struct class_entry ** class_entry,
struct method_info ** method_info) struct method_info ** method_info)
{ {
struct constant * methodref_constant = &vm->current_frame->class->constant_pool[index - 1]; struct constant * methodref_constant = &vm->current_frame->class_entry->class_file->constant_pool[index - 1];
#ifdef DEBUG #ifdef DEBUG
assert(methodref_constant->tag == CONSTANT_Methodref); assert(methodref_constant->tag == CONSTANT_Methodref);
#endif #endif
struct constant * class_constant = &vm->current_frame->class->constant_pool[methodref_constant->methodref.class_index - 1]; struct constant * class_constant = &vm->current_frame->class_entry->class_file->constant_pool[methodref_constant->methodref.class_index - 1];
#ifdef DEBUG #ifdef DEBUG
assert(class_constant->tag == CONSTANT_Class); assert(class_constant->tag == CONSTANT_Class);
#endif #endif
struct constant * nameandtype_constant = &vm->current_frame->class->constant_pool[methodref_constant->methodref.name_and_type_index - 1]; struct constant * nameandtype_constant = &vm->current_frame->class_entry->class_file->constant_pool[methodref_constant->methodref.name_and_type_index - 1];
#ifdef DEBUG #ifdef DEBUG
assert(nameandtype_constant->tag == CONSTANT_NameAndType); assert(nameandtype_constant->tag == CONSTANT_NameAndType);
#endif #endif
struct constant * class_name_constant = &vm->current_frame->class->constant_pool[class_constant->class.name_index - 1]; struct constant * class_name_constant = &vm->current_frame->class_entry->class_file->constant_pool[class_constant->class.name_index - 1];
#ifdef DEBUG #ifdef DEBUG
assert(class_name_constant->tag == CONSTANT_Utf8); assert(class_name_constant->tag == CONSTANT_Utf8);
#endif #endif
struct constant * method_name_constant = &vm->current_frame->class->constant_pool[nameandtype_constant->nameandtype.name_index - 1]; struct constant * method_name_constant = &vm->current_frame->class_entry->class_file->constant_pool[nameandtype_constant->nameandtype.name_index - 1];
#ifdef DEBUG #ifdef DEBUG
assert(method_name_constant->tag == CONSTANT_Utf8); assert(method_name_constant->tag == CONSTANT_Utf8);
#endif #endif
struct constant * method_descriptor_constant = &vm->current_frame->class->constant_pool[nameandtype_constant->nameandtype.descriptor_index - 1]; struct constant * method_descriptor_constant = &vm->current_frame->class_entry->class_file->constant_pool[nameandtype_constant->nameandtype.descriptor_index - 1];
#ifdef DEBUG #ifdef DEBUG
assert(method_descriptor_constant->tag == CONSTANT_Utf8); assert(method_descriptor_constant->tag == CONSTANT_Utf8);
#endif #endif

View File

@ -56,7 +56,6 @@ static int descriptor_nargs(struct constant * descriptor_constant, uint8_t * ret
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;
@ -81,7 +80,6 @@ static int descriptor_nargs(struct constant * descriptor_constant, uint8_t * ret
} }
i += 1; i += 1;
} }
printf("\n");
*return_type = descriptor_constant->utf8.bytes[i + 1]; *return_type = descriptor_constant->utf8.bytes[i + 1];
@ -106,7 +104,7 @@ bool vm_initialize_class(struct vm * vm, struct class_entry * class_entry)
return true; return true;
if (class_entry->initialization_state == CLASS_INITIALIZING) { if (class_entry->initialization_state == CLASS_INITIALIZING) {
if (vm->current_frame->class == class_entry->class_file) if (vm->current_frame->class_entry->class_file == class_entry->class_file)
return true; return true;
else else
assert(false); // possible infinite initialization loop assert(false); // possible infinite initialization loop
@ -166,10 +164,9 @@ bool vm_initialize_class(struct vm * vm, struct class_entry * class_entry)
// tamper with next_pc // tamper with next_pc
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_entry, method_info);
// tamper with initialization_frame vm->current_frame->initialization_frame = 1;
vm->current_frame->initialization_frame = class_entry;
return false; return false;
} else { } else {
class_entry->initialization_state = CLASS_INITIALIZED; class_entry->initialization_state = CLASS_INITIALIZED;
@ -179,7 +176,7 @@ bool vm_initialize_class(struct vm * vm, struct class_entry * class_entry)
return true; return true;
} }
void vm_special_method_call(struct vm * vm, struct class_file * class_file, struct method_info * method_info) void vm_special_method_call(struct vm * vm, struct class_entry * class_entry, struct method_info * method_info)
{ {
/* If the method is not native, the nargs argument values are popped from the /* If the method is not native, the nargs argument values are popped from the
operand stack. A new frame is created on the Java Virtual Machine stack for operand stack. A new frame is created on the Java Virtual Machine stack for
@ -191,7 +188,7 @@ void vm_special_method_call(struct vm * vm, struct class_file * class_file, stru
invoked. Execution continues with the first instruction of the method. invoked. Execution continues with the first instruction of the method.
*/ */
int code_name_index = find_code_name_index(class_file); int code_name_index = find_code_name_index(class_entry->class_file);
assert(code_name_index > 0); assert(code_name_index > 0);
struct Code_attribute * code = get_code_attribute(code_name_index, struct Code_attribute * code = get_code_attribute(code_name_index,
@ -206,9 +203,9 @@ 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; vm->current_frame->initialization_frame = 0;
struct constant * descriptor_constant = &class_file->constant_pool[method_info->descriptor_index - 1]; struct constant * descriptor_constant = &class_entry->class_file->constant_pool[method_info->descriptor_index - 1];
int nargs = descriptor_nargs(descriptor_constant, &vm->current_frame->return_type); 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);
@ -219,13 +216,13 @@ void vm_special_method_call(struct vm * vm, struct class_file * class_file, stru
} }
vm->current_frame->pc = 0; vm->current_frame->pc = 0;
vm->current_frame->class = class_file; vm->current_frame->class_entry = class_entry;
vm->current_frame->method = method_info; vm->current_frame->method = method_info;
printf("operand_stack_ix: %d\n", vm->current_frame->operand_stack_ix); printf("operand_stack_ix: %d\n", vm->current_frame->operand_stack_ix);
} }
void vm_static_method_call(struct vm * vm, struct class_file * class_file, struct method_info * method_info) void vm_static_method_call(struct vm * vm, struct class_entry * class_entry, struct method_info * method_info)
{ {
/* If the method is not native, the nargs argument values are popped from the /* If the method is not native, the nargs argument values are popped from the
operand stack. A new frame is created on the Java Virtual Machine stack for operand stack. A new frame is created on the Java Virtual Machine stack for
@ -237,7 +234,7 @@ void vm_static_method_call(struct vm * vm, struct class_file * class_file, struc
invoked. Execution continues with the first instruction of the method. invoked. Execution continues with the first instruction of the method.
*/ */
int code_name_index = find_code_name_index(class_file); int code_name_index = find_code_name_index(class_entry->class_file);
assert(code_name_index > 0); assert(code_name_index > 0);
struct Code_attribute * code = get_code_attribute(code_name_index, struct Code_attribute * code = get_code_attribute(code_name_index,
@ -252,9 +249,9 @@ 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; vm->current_frame->initialization_frame = 0;
struct constant * descriptor_constant = &class_file->constant_pool[method_info->descriptor_index - 1]; struct constant * descriptor_constant = &class_entry->class_file->constant_pool[method_info->descriptor_index - 1];
int nargs = descriptor_nargs(descriptor_constant, &vm->current_frame->return_type); 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++) {
@ -265,7 +262,7 @@ void vm_static_method_call(struct vm * vm, struct class_file * class_file, struc
; ;
vm->current_frame->pc = 0; vm->current_frame->pc = 0;
vm->current_frame->class = class_file; vm->current_frame->class_entry = class_entry;
vm->current_frame->method = method_info; vm->current_frame->method = method_info;
printf("operand_stack_ix: %d\n", vm->current_frame->operand_stack_ix); printf("operand_stack_ix: %d\n", vm->current_frame->operand_stack_ix);
@ -273,10 +270,9 @@ 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) { if (vm->current_frame->initialization_frame != 0) {
printf("vm_method_return: initialization_frame!=nullptr\n"); printf("vm_method_return: initialization_frame!=0\n");
struct class_entry * class_entry = vm->current_frame->initialization_frame; vm->current_frame->class_entry->initialization_state = CLASS_INITIALIZED;
class_entry->initialization_state = CLASS_INITIALIZED;
vm->current_frame->initialization_frame = 0; vm->current_frame->initialization_frame = 0;
} }

View File

@ -6,7 +6,7 @@
#include "class_resolver.h" #include "class_resolver.h"
struct frame { struct frame {
struct class_file * class; struct class_entry * class_entry;
struct method_info * method; struct method_info * method;
struct Code_attribute * code; struct Code_attribute * code;
uint32_t * local_variable; uint32_t * local_variable;
@ -14,7 +14,7 @@ struct frame {
uint32_t pc; uint32_t pc;
uint32_t next_pc; uint32_t next_pc;
int32_t operand_stack_ix; int32_t operand_stack_ix;
struct class_entry * initialization_frame; uint8_t initialization_frame;
uint8_t return_type; uint8_t return_type;
}; };
@ -150,7 +150,7 @@ static inline double operand_stack_pop_f64(struct frame * frame)
} }
bool vm_initialize_class(struct vm * vm, struct class_entry * class_entry); bool vm_initialize_class(struct vm * vm, struct class_entry * class_entry);
void vm_special_method_call(struct vm * vm, struct class_file * class_file, struct method_info * method_info); void vm_special_method_call(struct vm * vm, struct class_entry * class_entry, struct method_info * method_info);
void vm_static_method_call(struct vm * vm, struct class_file * class_file, struct method_info * method_info); void vm_static_method_call(struct vm * vm, struct class_entry * class_entry, struct method_info * method_info);
void vm_method_return(struct vm * vm); void vm_method_return(struct vm * vm);
void vm_execute(struct vm * vm); void vm_execute(struct vm * vm);

View File

@ -166,3 +166,25 @@ struct hash_table_entry * hash_table_find2(int hash_table_length,
} }
return nullptr; return nullptr;
} }
void hash_table_add_int(int hash_table_length,
struct hash_table_entry * entry,
int key,
void * value)
{
hash_table_add(hash_table_length,
entry,
(const uint8_t *)&key,
4,
value);
}
struct hash_table_entry * hash_table_find_int(int hash_table_length,
struct hash_table_entry * entry,
int key)
{
return hash_table_find(hash_table_length,
entry,
(const uint8_t *)&key,
4);
}

View File

@ -37,3 +37,12 @@ struct hash_table_entry * hash_table_find2(int hash_table_length,
int key1_length, int key1_length,
const uint8_t * key2, const uint8_t * key2,
int key2_length); int key2_length);
void hash_table_add_int(int hash_table_length,
struct hash_table_entry * entry,
int key,
void * value);
struct hash_table_entry * hash_table_find_int(int hash_table_length,
struct hash_table_entry * entry,
int key);

View File

@ -54,6 +54,6 @@ int main(int argc, const char * argv[])
entry_frame->operand_stack = 0; entry_frame->operand_stack = 0;
entry_frame->operand_stack_ix = 0; entry_frame->operand_stack_ix = 0;
vm_static_method_call(&vm, class_entry->class_file, method_info); vm_static_method_call(&vm, class_entry, method_info);
vm_execute(&vm); vm_execute(&vm);
} }

21
java/lang/String.java Normal file
View File

@ -0,0 +1,21 @@
package java.lang;
class String {
private final byte[] value;
public String() {
this.value = new byte[0];
}
public String(String original) {
this.value = original.value;
}
public String(byte[] value) {
this.value = value;
}
public byte[] getBytes() {
return this.value;
}
}

18
p/TestString.java Normal file
View File

@ -0,0 +1,18 @@
package p;
class TestString {
static int test() {
String s = new String("asdf");
byte[] b = s.getBytes();
int sum = 0;
for (int i = 0; i < b.length; i++) {
sum += b[i];
}
return sum;
}
public static void main() {
test();
}
}