implement String support
This commit is contained in:
parent
3a75d5bcdc
commit
f1976baf57
3
Makefile
3
Makefile
@ -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 \
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
111
c/execute.c
111
c/execute.c
@ -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);
|
int32_t value = constant->integer.bytes;
|
||||||
#endif
|
operand_stack_push_u32(vm->current_frame, value);
|
||||||
int32_t value = constant->integer.bytes;
|
} else if (constant->tag == CONSTANT_String) {
|
||||||
operand_stack_push_u32(vm->current_frame, value);
|
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;
|
||||||
for (int i = 0; i < fields_count; i++) {
|
int32_t * objectfields = &objectref[1];
|
||||||
objectref[i * 2] = 0;
|
for (int i = 0; i < fields_count; i++) {
|
||||||
objectref[i * 2 + 1] = 0;
|
objectfields[i * 2] = 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;
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
36
c/frame.c
36
c/frame.c
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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);
|
||||||
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
2
c/main.c
2
c/main.c
@ -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
21
java/lang/String.java
Normal 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
18
p/TestString.java
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user