implement class instances
This commit is contained in:
parent
d0edd6b12b
commit
bba08c9a3e
@ -7,7 +7,10 @@
|
|||||||
|
|
||||||
struct field_entry {
|
struct field_entry {
|
||||||
struct field_info * field_info;
|
struct field_info * field_info;
|
||||||
uint32_t value;
|
union {
|
||||||
|
uint64_t value64;
|
||||||
|
uint32_t value32;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
enum initialization_state {
|
enum initialization_state {
|
||||||
|
292
c/execute.c
292
c/execute.c
@ -4,6 +4,7 @@
|
|||||||
#include "memory_allocator.h"
|
#include "memory_allocator.h"
|
||||||
#include "bswap.h"
|
#include "bswap.h"
|
||||||
#include "class_resolver.h"
|
#include "class_resolver.h"
|
||||||
|
#include "execute_helper.h"
|
||||||
|
|
||||||
void op_aaload(struct vm * vm)
|
void op_aaload(struct vm * vm)
|
||||||
{
|
{
|
||||||
@ -610,42 +611,55 @@ void op_fsub(struct vm * vm)
|
|||||||
|
|
||||||
void op_getfield(struct vm * vm, uint32_t index)
|
void op_getfield(struct vm * vm, uint32_t index)
|
||||||
{
|
{
|
||||||
assert(!"op_getfield");
|
struct class_entry * class_entry;
|
||||||
|
struct field_entry * field_entry;
|
||||||
|
struct constant * field_descriptor_constant;
|
||||||
|
class_entry_field_entry_from_constant_index(vm, index,
|
||||||
|
&class_entry,
|
||||||
|
&field_entry,
|
||||||
|
&field_descriptor_constant);
|
||||||
|
assert(field_descriptor_constant->utf8.length == 1);
|
||||||
|
|
||||||
|
uint32_t field_index = field_entry->field_info - class_entry->class_file->fields;
|
||||||
|
printf("putfield field_index %d\n", field_index);
|
||||||
|
|
||||||
|
int32_t * objectref = (int32_t *)operand_stack_pop_u32(vm->current_frame);
|
||||||
|
|
||||||
|
switch (field_descriptor_constant->utf8.bytes[0]) {
|
||||||
|
case 'Z': [[fallthrough]];
|
||||||
|
case 'B': [[fallthrough]];
|
||||||
|
case 'C': [[fallthrough]];
|
||||||
|
case 'S': [[fallthrough]];
|
||||||
|
case 'I': [[fallthrough]];
|
||||||
|
case 'F':
|
||||||
|
{
|
||||||
|
uint32_t value = objectref[field_index];
|
||||||
|
operand_stack_push_u32(vm->current_frame, value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'D': [[fallthrough]];
|
||||||
|
case 'J':
|
||||||
|
{
|
||||||
|
uint32_t low = objectref[field_index * 2];
|
||||||
|
uint32_t high = objectref[field_index * 2 + 1];
|
||||||
|
operand_stack_push_u32(vm->current_frame, low);
|
||||||
|
operand_stack_push_u32(vm->current_frame, high);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void op_getstatic(struct vm * vm, uint32_t index)
|
void op_getstatic(struct vm * vm, uint32_t index)
|
||||||
{
|
{
|
||||||
struct constant * fieldref_constant = &vm->current_thread.current_class->constant_pool[index - 1];
|
struct class_entry * class_entry;
|
||||||
#ifdef DEBUG
|
struct field_entry * field_entry;
|
||||||
assert(fieldref_constant->tag == CONSTANT_Fieldref);
|
struct constant * field_descriptor_constant;
|
||||||
#endif
|
class_entry_field_entry_from_constant_index(vm, index,
|
||||||
struct constant * class_constant = &vm->current_thread.current_class->constant_pool[fieldref_constant->fieldref.class_index - 1];
|
&class_entry,
|
||||||
#ifdef DEBUG
|
&field_entry,
|
||||||
assert(class_constant->tag == CONSTANT_Class);
|
&field_descriptor_constant);
|
||||||
#endif
|
|
||||||
struct constant * nameandtype_constant = &vm->current_thread.current_class->constant_pool[fieldref_constant->fieldref.name_and_type_index - 1];
|
|
||||||
#ifdef DEBUG
|
|
||||||
assert(nameandtype_constant->tag == CONSTANT_NameAndType);
|
|
||||||
#endif
|
|
||||||
struct constant * class_name_constant = &vm->current_thread.current_class->constant_pool[class_constant->class.name_index - 1];
|
|
||||||
#ifdef DEBUG
|
|
||||||
assert(class_name_constant->tag == CONSTANT_Utf8);
|
|
||||||
#endif
|
|
||||||
struct constant * field_name_constant = &vm->current_thread.current_class->constant_pool[nameandtype_constant->nameandtype.name_index - 1];
|
|
||||||
#ifdef DEBUG
|
|
||||||
assert(field_name_constant->tag == CONSTANT_Utf8);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct class_entry * class_entry = class_resolver_lookup_class(vm->class_hash_table.length,
|
|
||||||
vm->class_hash_table.entry,
|
|
||||||
class_name_constant->utf8.bytes,
|
|
||||||
class_name_constant->utf8.length);
|
|
||||||
assert(class_entry != nullptr);
|
|
||||||
|
|
||||||
struct field_entry * field_entry = class_resolver_lookup_field(class_entry,
|
|
||||||
field_name_constant->utf8.bytes,
|
|
||||||
field_name_constant->utf8.length);
|
|
||||||
assert(field_entry != nullptr);
|
|
||||||
|
|
||||||
/* On successful resolution of the field, the class or interface that
|
/* On successful resolution of the field, the class or interface that
|
||||||
declared the resolved field is initialized if that class or interface has
|
declared the resolved field is initialized if that class or interface has
|
||||||
@ -654,9 +668,31 @@ 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;
|
||||||
|
|
||||||
uint32_t value = field_entry->value;
|
assert(field_descriptor_constant->utf8.length == 1);
|
||||||
|
|
||||||
|
switch (field_descriptor_constant->utf8.bytes[0]) {
|
||||||
|
case 'Z': [[fallthrough]];
|
||||||
|
case 'B': [[fallthrough]];
|
||||||
|
case 'C': [[fallthrough]];
|
||||||
|
case 'S': [[fallthrough]];
|
||||||
|
case 'I': [[fallthrough]];
|
||||||
|
case 'F':
|
||||||
|
{
|
||||||
|
uint32_t value = field_entry->value32;
|
||||||
operand_stack_push_u32(vm->current_frame, value);
|
operand_stack_push_u32(vm->current_frame, value);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case 'D': [[fallthrough]];
|
||||||
|
case 'J':
|
||||||
|
{
|
||||||
|
uint64_t value = field_entry->value64;
|
||||||
|
operand_stack_push_u64(vm->current_frame, value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void op_goto(struct vm * vm, int32_t branch)
|
void op_goto(struct vm * vm, int32_t branch)
|
||||||
{
|
{
|
||||||
@ -996,48 +1032,22 @@ void op_invokeinterface(struct vm * vm, uint32_t index, uint32_t count)
|
|||||||
|
|
||||||
void op_invokespecial(struct vm * vm, uint32_t index)
|
void op_invokespecial(struct vm * vm, uint32_t index)
|
||||||
{
|
{
|
||||||
assert(!"op_invokespecial");
|
struct class_entry * class_entry;
|
||||||
|
struct method_info * method_info;
|
||||||
|
class_entry_method_info_from_constant_index(vm, index,
|
||||||
|
&class_entry,
|
||||||
|
&method_info);
|
||||||
|
|
||||||
|
vm_special_method_call(vm, class_entry->class_file, method_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
void op_invokestatic(struct vm * vm, uint32_t index)
|
void op_invokestatic(struct vm * vm, uint32_t index)
|
||||||
{
|
{
|
||||||
struct constant * methodref_constant = &vm->current_thread.current_class->constant_pool[index - 1];
|
struct class_entry * class_entry;
|
||||||
#ifdef DEBUG
|
struct method_info * method_info;
|
||||||
assert(methodref_constant->tag == CONSTANT_Methodref);
|
class_entry_method_info_from_constant_index(vm, index,
|
||||||
#endif
|
&class_entry,
|
||||||
struct constant * class_constant = &vm->current_thread.current_class->constant_pool[methodref_constant->methodref.class_index - 1];
|
&method_info);
|
||||||
#ifdef DEBUG
|
|
||||||
assert(class_constant->tag == CONSTANT_Class);
|
|
||||||
#endif
|
|
||||||
struct constant * nameandtype_constant = &vm->current_thread.current_class->constant_pool[methodref_constant->methodref.name_and_type_index - 1];
|
|
||||||
#ifdef DEBUG
|
|
||||||
assert(nameandtype_constant->tag == CONSTANT_NameAndType);
|
|
||||||
#endif
|
|
||||||
struct constant * class_name_constant = &vm->current_thread.current_class->constant_pool[class_constant->class.name_index - 1];
|
|
||||||
#ifdef DEBUG
|
|
||||||
assert(class_name_constant->tag == CONSTANT_Utf8);
|
|
||||||
#endif
|
|
||||||
struct constant * method_name_constant = &vm->current_thread.current_class->constant_pool[nameandtype_constant->nameandtype.name_index - 1];
|
|
||||||
#ifdef DEBUG
|
|
||||||
assert(method_name_constant->tag == CONSTANT_Utf8);
|
|
||||||
#endif
|
|
||||||
struct constant * method_descriptor_constant = &vm->current_thread.current_class->constant_pool[nameandtype_constant->nameandtype.descriptor_index - 1];
|
|
||||||
#ifdef DEBUG
|
|
||||||
assert(method_descriptor_constant->tag == CONSTANT_Utf8);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct class_entry * class_entry = class_resolver_lookup_class(vm->class_hash_table.length,
|
|
||||||
vm->class_hash_table.entry,
|
|
||||||
class_name_constant->utf8.bytes,
|
|
||||||
class_name_constant->utf8.length);
|
|
||||||
assert(class_entry != nullptr);
|
|
||||||
|
|
||||||
struct method_info * method_info = class_resolver_lookup_method(class_entry,
|
|
||||||
method_name_constant->utf8.bytes,
|
|
||||||
method_name_constant->utf8.length,
|
|
||||||
method_descriptor_constant->utf8.bytes,
|
|
||||||
method_descriptor_constant->utf8.length);
|
|
||||||
assert(method_info != nullptr);
|
|
||||||
|
|
||||||
/* On successful resolution of the method, the class or interface that
|
/* On successful resolution of the method, the class or interface that
|
||||||
declared the resolved method is initialized if that class or interface has
|
declared the resolved method is initialized if that class or interface has
|
||||||
@ -1048,7 +1058,13 @@ void op_invokestatic(struct vm * vm, uint32_t index)
|
|||||||
|
|
||||||
void op_invokevirtual(struct vm * vm, uint32_t index)
|
void op_invokevirtual(struct vm * vm, uint32_t index)
|
||||||
{
|
{
|
||||||
assert(!"op_invokevirtual");
|
struct class_entry * class_entry;
|
||||||
|
struct method_info * method_info;
|
||||||
|
class_entry_method_info_from_constant_index(vm, index,
|
||||||
|
&class_entry,
|
||||||
|
&method_info);
|
||||||
|
|
||||||
|
vm_special_method_call(vm, class_entry->class_file, method_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
void op_ior(struct vm * vm)
|
void op_ior(struct vm * vm)
|
||||||
@ -1273,7 +1289,7 @@ 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_thread.current_class->constant_pool[index - 1];
|
struct constant * constant = &vm->current_frame->class->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
|
||||||
@ -1283,7 +1299,7 @@ void op_ldc(struct vm * vm, uint32_t index)
|
|||||||
|
|
||||||
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_thread.current_class->constant_pool[index - 1];
|
struct constant * constant = &vm->current_frame->class->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
|
||||||
@ -1486,11 +1502,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_thread.current_class->constant_pool[index - 1];
|
struct constant * class_constant = &vm->current_frame->class->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_thread.current_class->constant_pool[class_constant->class.name_index - 1];
|
struct constant * class_name_constant = &vm->current_frame->class->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
|
||||||
@ -1517,9 +1533,13 @@ void op_new(struct vm * vm, uint32_t index)
|
|||||||
|
|
||||||
int fields_count = class_entry->class_file->fields_count;
|
int fields_count = class_entry->class_file->fields_count;
|
||||||
(void)fields_count;
|
(void)fields_count;
|
||||||
//int32_t * arrayref = memory_allocate();
|
int32_t * objectref = memory_allocate(fields_count * 2 * 4);
|
||||||
|
for (int i = 0; i < fields_count; i++) {
|
||||||
|
objectref[i * 2] = 0;
|
||||||
|
objectref[i * 2 + 1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
assert(!"op_new");
|
operand_stack_push_u32(vm->current_frame, (uint32_t)objectref);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ARRAY_TYPE {
|
enum ARRAY_TYPE {
|
||||||
@ -1594,42 +1614,72 @@ void op_pop2(struct vm * vm)
|
|||||||
|
|
||||||
void op_putfield(struct vm * vm, uint32_t index)
|
void op_putfield(struct vm * vm, uint32_t index)
|
||||||
{
|
{
|
||||||
assert(!"op_putfield");
|
struct class_entry * class_entry;
|
||||||
|
struct field_entry * field_entry;
|
||||||
|
struct constant * field_descriptor_constant;
|
||||||
|
class_entry_field_entry_from_constant_index(vm, index,
|
||||||
|
&class_entry,
|
||||||
|
&field_entry,
|
||||||
|
&field_descriptor_constant);
|
||||||
|
|
||||||
|
/* The type of a value stored by a putfield instruction must be compatible
|
||||||
|
with the descriptor of the referenced field (§4.3.2). If the field descriptor
|
||||||
|
type is boolean, byte, char, short, or int, then the value must be an int. If
|
||||||
|
the field descriptor type is float, long, or double, then the value must be a
|
||||||
|
float, long, or double, respectively. If the field descriptor type is a class
|
||||||
|
type or an array type, then the value must be a value of the field descriptor
|
||||||
|
type. */
|
||||||
|
|
||||||
|
assert(field_descriptor_constant->utf8.length == 1);
|
||||||
|
|
||||||
|
uint32_t field_index = field_entry->field_info - class_entry->class_file->fields;
|
||||||
|
printf("putfield field_index %d\n", field_index);
|
||||||
|
|
||||||
|
switch (field_descriptor_constant->utf8.bytes[0]) {
|
||||||
|
case 'Z': [[fallthrough]];
|
||||||
|
case 'B': [[fallthrough]];
|
||||||
|
case 'C': [[fallthrough]];
|
||||||
|
case 'S': [[fallthrough]];
|
||||||
|
case 'I': [[fallthrough]];
|
||||||
|
case 'F':
|
||||||
|
{
|
||||||
|
uint32_t value = operand_stack_pop_u32(vm->current_frame);
|
||||||
|
int32_t * objectref = (int32_t *)operand_stack_pop_u32(vm->current_frame);
|
||||||
|
objectref[field_index] = value;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'D': [[fallthrough]];
|
||||||
|
case 'J':
|
||||||
|
{
|
||||||
|
uint32_t high = 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);
|
||||||
|
objectref[field_index * 2 + 1] = high;
|
||||||
|
objectref[field_index * 2] = low;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void op_putstatic(struct vm * vm, uint32_t index)
|
void op_putstatic(struct vm * vm, uint32_t index)
|
||||||
{
|
{
|
||||||
struct constant * fieldref_constant = &vm->current_thread.current_class->constant_pool[index - 1];
|
struct class_entry * class_entry;
|
||||||
#ifdef DEBUG
|
struct field_entry * field_entry;
|
||||||
assert(fieldref_constant->tag == CONSTANT_Fieldref);
|
struct constant * field_descriptor_constant;
|
||||||
#endif
|
class_entry_field_entry_from_constant_index(vm, index,
|
||||||
struct constant * class_constant = &vm->current_thread.current_class->constant_pool[fieldref_constant->fieldref.class_index - 1];
|
&class_entry,
|
||||||
#ifdef DEBUG
|
&field_entry,
|
||||||
assert(class_constant->tag == CONSTANT_Class);
|
&field_descriptor_constant);
|
||||||
#endif
|
|
||||||
struct constant * nameandtype_constant = &vm->current_thread.current_class->constant_pool[fieldref_constant->fieldref.name_and_type_index - 1];
|
|
||||||
#ifdef DEBUG
|
|
||||||
assert(nameandtype_constant->tag == CONSTANT_NameAndType);
|
|
||||||
#endif
|
|
||||||
struct constant * class_name_constant = &vm->current_thread.current_class->constant_pool[class_constant->class.name_index - 1];
|
|
||||||
#ifdef DEBUG
|
|
||||||
assert(class_name_constant->tag == CONSTANT_Utf8);
|
|
||||||
#endif
|
|
||||||
struct constant * field_name_constant = &vm->current_thread.current_class->constant_pool[nameandtype_constant->nameandtype.name_index - 1];
|
|
||||||
#ifdef DEBUG
|
|
||||||
assert(field_name_constant->tag == CONSTANT_Utf8);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct class_entry * class_entry = class_resolver_lookup_class(vm->class_hash_table.length,
|
/* The type of a value stored by a putstatic instruction must be compatible
|
||||||
vm->class_hash_table.entry,
|
with the descriptor of the referenced field (§4.3.2). If the field
|
||||||
class_name_constant->utf8.bytes,
|
descriptor type is boolean, byte, char, short, or int, then the value must
|
||||||
class_name_constant->utf8.length);
|
be an int. If the field descriptor type is float, long, or double, then the
|
||||||
assert(class_entry != nullptr);
|
value must be a float, long, or double, respectively. If the field
|
||||||
|
descriptor type is a class type or an array type, then the value must be a
|
||||||
struct field_entry * field_entry = class_resolver_lookup_field(class_entry,
|
value of the field descriptor type. */
|
||||||
field_name_constant->utf8.bytes,
|
|
||||||
field_name_constant->utf8.length);
|
|
||||||
assert(field_entry != nullptr);
|
|
||||||
|
|
||||||
/* On successful resolution of the field, the class or interface that declared
|
/* On successful resolution of the field, the class or interface that declared
|
||||||
the resolved field is initialized if that class or interface has not
|
the resolved field is initialized if that class or interface has not
|
||||||
@ -1638,8 +1688,30 @@ 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);
|
||||||
|
|
||||||
|
switch (field_descriptor_constant->utf8.bytes[0]) {
|
||||||
|
case 'Z': [[fallthrough]];
|
||||||
|
case 'B': [[fallthrough]];
|
||||||
|
case 'C': [[fallthrough]];
|
||||||
|
case 'S': [[fallthrough]];
|
||||||
|
case 'I': [[fallthrough]];
|
||||||
|
case 'F':
|
||||||
|
{
|
||||||
uint32_t value = operand_stack_pop_u32(vm->current_frame);
|
uint32_t value = operand_stack_pop_u32(vm->current_frame);
|
||||||
field_entry->value = value;
|
field_entry->value32 = value;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'D': [[fallthrough]];
|
||||||
|
case 'J':
|
||||||
|
{
|
||||||
|
uint64_t value = operand_stack_pop_u64(vm->current_frame);
|
||||||
|
field_entry->value64 = value;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void op_ret(struct vm * vm, uint32_t index)
|
void op_ret(struct vm * vm, uint32_t index)
|
||||||
|
88
c/execute_helper.h
Normal file
88
c/execute_helper.h
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
#include "debug_class_file.h"
|
||||||
|
|
||||||
|
static inline void class_entry_field_entry_from_constant_index(struct vm * vm,
|
||||||
|
uint32_t index,
|
||||||
|
struct class_entry ** class_entry,
|
||||||
|
struct field_entry ** field_entry,
|
||||||
|
struct constant ** field_descriptor_constant)
|
||||||
|
{
|
||||||
|
struct constant * fieldref_constant = &vm->current_frame->class->constant_pool[index - 1];
|
||||||
|
#ifdef DEBUG
|
||||||
|
assert(fieldref_constant->tag == CONSTANT_Fieldref);
|
||||||
|
#endif
|
||||||
|
struct constant * class_constant = &vm->current_frame->class->constant_pool[fieldref_constant->fieldref.class_index - 1];
|
||||||
|
#ifdef DEBUG
|
||||||
|
assert(class_constant->tag == CONSTANT_Class);
|
||||||
|
#endif
|
||||||
|
struct constant * nameandtype_constant = &vm->current_frame->class->constant_pool[fieldref_constant->fieldref.name_and_type_index - 1];
|
||||||
|
#ifdef DEBUG
|
||||||
|
assert(nameandtype_constant->tag == CONSTANT_NameAndType);
|
||||||
|
#endif
|
||||||
|
struct constant * class_name_constant = &vm->current_frame->class->constant_pool[class_constant->class.name_index - 1];
|
||||||
|
#ifdef DEBUG
|
||||||
|
assert(class_name_constant->tag == CONSTANT_Utf8);
|
||||||
|
#endif
|
||||||
|
struct constant * field_name_constant = &vm->current_frame->class->constant_pool[nameandtype_constant->nameandtype.name_index - 1];
|
||||||
|
#ifdef DEBUG
|
||||||
|
assert(field_name_constant->tag == CONSTANT_Utf8);
|
||||||
|
#endif
|
||||||
|
*field_descriptor_constant = &vm->current_frame->class->constant_pool[nameandtype_constant->nameandtype.descriptor_index - 1];
|
||||||
|
#ifdef DEBUG
|
||||||
|
assert((*field_descriptor_constant)->tag == CONSTANT_Utf8);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
*class_entry = class_resolver_lookup_class(vm->class_hash_table.length,
|
||||||
|
vm->class_hash_table.entry,
|
||||||
|
class_name_constant->utf8.bytes,
|
||||||
|
class_name_constant->utf8.length);
|
||||||
|
assert(*class_entry != nullptr);
|
||||||
|
|
||||||
|
*field_entry = class_resolver_lookup_field(*class_entry,
|
||||||
|
field_name_constant->utf8.bytes,
|
||||||
|
field_name_constant->utf8.length);
|
||||||
|
assert(*field_entry != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void class_entry_method_info_from_constant_index(struct vm * vm,
|
||||||
|
uint32_t index,
|
||||||
|
struct class_entry ** class_entry,
|
||||||
|
struct method_info ** method_info)
|
||||||
|
{
|
||||||
|
struct constant * methodref_constant = &vm->current_frame->class->constant_pool[index - 1];
|
||||||
|
#ifdef DEBUG
|
||||||
|
assert(methodref_constant->tag == CONSTANT_Methodref);
|
||||||
|
#endif
|
||||||
|
struct constant * class_constant = &vm->current_frame->class->constant_pool[methodref_constant->methodref.class_index - 1];
|
||||||
|
#ifdef DEBUG
|
||||||
|
assert(class_constant->tag == CONSTANT_Class);
|
||||||
|
#endif
|
||||||
|
struct constant * nameandtype_constant = &vm->current_frame->class->constant_pool[methodref_constant->methodref.name_and_type_index - 1];
|
||||||
|
#ifdef DEBUG
|
||||||
|
assert(nameandtype_constant->tag == CONSTANT_NameAndType);
|
||||||
|
#endif
|
||||||
|
struct constant * class_name_constant = &vm->current_frame->class->constant_pool[class_constant->class.name_index - 1];
|
||||||
|
#ifdef DEBUG
|
||||||
|
assert(class_name_constant->tag == CONSTANT_Utf8);
|
||||||
|
#endif
|
||||||
|
struct constant * method_name_constant = &vm->current_frame->class->constant_pool[nameandtype_constant->nameandtype.name_index - 1];
|
||||||
|
#ifdef DEBUG
|
||||||
|
assert(method_name_constant->tag == CONSTANT_Utf8);
|
||||||
|
#endif
|
||||||
|
struct constant * method_descriptor_constant = &vm->current_frame->class->constant_pool[nameandtype_constant->nameandtype.descriptor_index - 1];
|
||||||
|
#ifdef DEBUG
|
||||||
|
assert(method_descriptor_constant->tag == CONSTANT_Utf8);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
*class_entry = class_resolver_lookup_class(vm->class_hash_table.length,
|
||||||
|
vm->class_hash_table.entry,
|
||||||
|
class_name_constant->utf8.bytes,
|
||||||
|
class_name_constant->utf8.length);
|
||||||
|
assert(*class_entry != nullptr);
|
||||||
|
|
||||||
|
*method_info = class_resolver_lookup_method(*class_entry,
|
||||||
|
method_name_constant->utf8.bytes,
|
||||||
|
method_name_constant->utf8.length,
|
||||||
|
method_descriptor_constant->utf8.bytes,
|
||||||
|
method_descriptor_constant->utf8.length);
|
||||||
|
assert(*method_info != nullptr);
|
||||||
|
}
|
57
c/frame.c
57
c/frame.c
@ -87,7 +87,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_thread.current_class == class_entry->class_file)
|
if (vm->current_frame->class == class_entry->class_file)
|
||||||
return true;
|
return true;
|
||||||
else
|
else
|
||||||
assert(false); // possible infinite initialization loop
|
assert(false); // possible infinite initialization loop
|
||||||
@ -154,6 +154,52 @@ 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)
|
||||||
|
{
|
||||||
|
/* 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
|
||||||
|
the method being invoked. The nargs argument values are consecutively made
|
||||||
|
the values of local variables of the new frame, with arg1 in local variable
|
||||||
|
0 (or, if arg1 is of type long or double, in local variables 0 and 1) and
|
||||||
|
so on. The new frame is then made current, and the Java Virtual Machine pc
|
||||||
|
is set to the opcode of the first instruction of the method to be
|
||||||
|
invoked. Execution continues with the first instruction of the method.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int code_name_index = find_code_name_index(class_file);
|
||||||
|
assert(code_name_index > 0);
|
||||||
|
|
||||||
|
struct Code_attribute * code = get_code_attribute(code_name_index,
|
||||||
|
method_info->attributes_count,
|
||||||
|
method_info->attributes);
|
||||||
|
assert(code != nullptr);
|
||||||
|
|
||||||
|
struct frame * old_frame = vm->current_frame;
|
||||||
|
|
||||||
|
vm->current_frame = stack_push_frame(&vm->frame_stack, 1);
|
||||||
|
vm->current_frame->code = code;
|
||||||
|
vm->current_frame->local_variable = stack_push_data(&vm->data_stack, code->max_locals);
|
||||||
|
vm->current_frame->operand_stack = stack_push_data(&vm->data_stack, code->max_stack);
|
||||||
|
vm->current_frame->operand_stack_ix = 0;
|
||||||
|
|
||||||
|
struct constant * descriptor_constant = &class_file->constant_pool[method_info->descriptor_index - 1];
|
||||||
|
int nargs = descriptor_nargs(descriptor_constant);
|
||||||
|
nargs += 1;
|
||||||
|
printf("nargs+1: %d\n", nargs);
|
||||||
|
for (int i = 0; i < nargs; i++) {
|
||||||
|
uint32_t value = operand_stack_pop_u32(old_frame);
|
||||||
|
printf("local[%d] = %x\n", nargs - i - 1, value);
|
||||||
|
vm->current_frame->local_variable[nargs - i - 1] = value;
|
||||||
|
}
|
||||||
|
vm->current_frame->return_type = descriptor_constant->utf8.bytes[descriptor_constant->utf8.length - 1];
|
||||||
|
|
||||||
|
vm->current_frame->pc = 0;
|
||||||
|
vm->current_frame->class = class_file;
|
||||||
|
vm->current_frame->method = method_info;
|
||||||
|
|
||||||
|
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_file * class_file, 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
|
||||||
@ -193,8 +239,8 @@ void vm_static_method_call(struct vm * vm, struct class_file * class_file, struc
|
|||||||
vm->current_frame->return_type = descriptor_constant->utf8.bytes[descriptor_constant->utf8.length - 1];
|
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_thread.current_class = class_file;
|
vm->current_frame->class = class_file;
|
||||||
vm->current_thread.current_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);
|
||||||
}
|
}
|
||||||
@ -261,6 +307,7 @@ void vm_method_return(struct vm * vm)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
assert(old_frame->operand_stack_ix == 0);
|
assert(old_frame->operand_stack_ix == 0);
|
||||||
|
printf("vm_method_return\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_vm_stack(struct vm * vm)
|
static void print_vm_stack(struct vm * vm)
|
||||||
@ -287,13 +334,13 @@ void vm_execute(struct vm * vm)
|
|||||||
print_vm_stack(vm);
|
print_vm_stack(vm);
|
||||||
decode_print_instruction(vm->current_frame->code->code, vm->current_frame->pc);
|
decode_print_instruction(vm->current_frame->code->code, vm->current_frame->pc);
|
||||||
uint32_t old_pc = vm->current_frame->pc;
|
uint32_t old_pc = vm->current_frame->pc;
|
||||||
struct method_info * old_method = vm->current_thread.current_method;
|
struct method_info * old_method = vm->current_frame->method;
|
||||||
decode_execute_instruction(vm, vm->current_frame->code->code, vm->current_frame->pc);
|
decode_execute_instruction(vm, vm->current_frame->code->code, vm->current_frame->pc);
|
||||||
if (vm->frame_stack.ix == 1) {
|
if (vm->frame_stack.ix == 1) {
|
||||||
printf("terminate\n");
|
printf("terminate\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (vm->current_thread.current_method == old_method && vm->current_frame->pc == old_pc) {
|
if (vm->current_frame->method == old_method && vm->current_frame->pc == old_pc) {
|
||||||
// if the instruction did not branch, increment pc
|
// if the instruction did not branch, increment pc
|
||||||
vm->current_frame->pc = vm->current_frame->next_pc;
|
vm->current_frame->pc = vm->current_frame->next_pc;
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
#include "class_resolver.h"
|
#include "class_resolver.h"
|
||||||
|
|
||||||
struct frame {
|
struct frame {
|
||||||
|
struct class_file * class;
|
||||||
|
struct method_info * method;
|
||||||
struct Code_attribute * code;
|
struct Code_attribute * code;
|
||||||
uint32_t * local_variable;
|
uint32_t * local_variable;
|
||||||
uint32_t * operand_stack;
|
uint32_t * operand_stack;
|
||||||
@ -15,11 +17,6 @@ struct frame {
|
|||||||
uint8_t return_type;
|
uint8_t return_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct thread {
|
|
||||||
struct class_file * current_class;
|
|
||||||
struct method_info * current_method;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct stack {
|
struct stack {
|
||||||
union {
|
union {
|
||||||
struct frame * frame;
|
struct frame * frame;
|
||||||
@ -32,7 +29,6 @@ struct stack {
|
|||||||
struct vm {
|
struct vm {
|
||||||
struct stack frame_stack;
|
struct stack frame_stack;
|
||||||
struct stack data_stack;
|
struct stack data_stack;
|
||||||
struct thread current_thread;
|
|
||||||
struct frame * current_frame;
|
struct frame * current_frame;
|
||||||
struct {
|
struct {
|
||||||
int length;
|
int length;
|
||||||
@ -148,6 +144,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_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_file * class_file, 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);
|
||||||
|
5
java/lang/Object.java
Normal file
5
java/lang/Object.java
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package java.lang;
|
||||||
|
|
||||||
|
class Object {
|
||||||
|
public Object() {}
|
||||||
|
}
|
13
p/LongStaticField.java
Normal file
13
p/LongStaticField.java
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package p;
|
||||||
|
|
||||||
|
class LongStaticField {
|
||||||
|
static long foo = 10;
|
||||||
|
|
||||||
|
static long test() {
|
||||||
|
return foo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main() {
|
||||||
|
test();
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user