Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ TESTS = \
Static \
Invokevirtual \
Inherit \
Initializer
Initializer \
Strings

check: $(addprefix tests/,$(TESTS:=-result.out))

Expand Down
9 changes: 9 additions & 0 deletions class-heap.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,15 @@ void free_class_heap()
}
free(class_heap.class_info[i]->clazz->methods);

bootmethods_attr_t *bootstrap =
class_heap.class_info[i]->clazz->bootstrap;
if (bootstrap) {
for (u2 j = 0; j < bootstrap->num_bootstrap_methods; j++)
free(bootstrap->bootstrap_methods[j].bootstrap_arguments);
free(bootstrap->bootstrap_methods);
free(bootstrap);
}

free(class_heap.class_info[i]->clazz);
free(class_heap.class_info[i]->name);
free(class_heap.class_info[i]);
Expand Down
63 changes: 62 additions & 1 deletion classfile.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class_info_t *get_class_info(FILE *class_file)
}

/**
* Get the number of integer parameters that a method takes.
* Get the number of parameters that a method takes.
* Use the descriptor string of the method to determine its signature.
*/
uint16_t get_number_of_parameters(method_t *method)
Expand Down Expand Up @@ -175,6 +175,15 @@ char *find_class_name_from_index(uint16_t idx, class_file_t *clazz)
return (char *) name->info;
}

bootmethods_t *find_bootstrap_method(uint16_t idx, class_file_t *clazz)
{
const_pool_info *info = get_constant(&clazz->constant_pool, idx);
assert(info->tag == CONSTANT_InvokeDynamic && "Expected a InvokeDynanmic");
return &clazz->bootstrap
->bootstrap_methods[((CONSTANT_InvokeDynamic_info *) info->info)
->bootstrap_method_attr_index];
}

void read_field_attributes(FILE *class_file, field_info *info)
{
for (u2 i = 0; i < info->attributes_count; i++) {
Expand Down Expand Up @@ -223,6 +232,54 @@ void read_method_attributes(FILE *class_file,
assert(found_code && "Missing method code");
}

bootmethods_attr_t *read_bootstrap_attribute(FILE *class_file,
constant_pool_t *cp)
{
u2 attributes_count = read_u2(class_file);
for (u2 i = 0; i < attributes_count; i++) {
attribute_info ainfo = {
.attribute_name_index = read_u2(class_file),
.attribute_length = read_u4(class_file),
};
long attribute_end = ftell(class_file) + ainfo.attribute_length;
const_pool_info *type_constant =
get_constant(cp, ainfo.attribute_name_index);
assert(type_constant->tag == CONSTANT_Utf8 && "Expected a UTF8");
if (!strcmp((char *) type_constant->info, "BootstrapMethods")) {
bootmethods_attr_t *bootstrap = malloc(sizeof(*bootstrap));

bootstrap->num_bootstrap_methods = read_u2(class_file);
bootstrap->bootstrap_methods = malloc(
sizeof(bootmethods_t) * bootstrap->num_bootstrap_methods);

assert(bootstrap->bootstrap_methods &&
"Failed to allocate bootstrap method");
for (int j = 0; j < bootstrap->num_bootstrap_methods; ++j) {
bootstrap->bootstrap_methods[j].bootstrap_method_ref =
read_u2(class_file);
bootstrap->bootstrap_methods[j].num_bootstrap_arguments =
read_u2(class_file);
bootstrap->bootstrap_methods[j].bootstrap_arguments = malloc(
sizeof(u2) *
bootstrap->bootstrap_methods[j].num_bootstrap_arguments);
assert(bootstrap->bootstrap_methods[j].bootstrap_arguments &&
"Failed to allocate bootstrap argument");
for (int k = 0;
k <
bootstrap->bootstrap_methods[j].num_bootstrap_arguments;
++k) {
bootstrap->bootstrap_methods[j].bootstrap_arguments[k] =
read_u2(class_file);
}
}
return bootstrap;
}
/* Skip the rest of the attribute */
fseek(class_file, attribute_end, SEEK_SET);
}
return NULL;
}

#define IS_STATIC 0x0008

field_t *get_fields(FILE *class_file, constant_pool_t *cp, class_file_t *clazz)
Expand Down Expand Up @@ -311,6 +368,10 @@ class_file_t get_class(FILE *class_file)
/* Read the list of static methods */
clazz.methods = get_methods(class_file, &clazz.constant_pool);

/* Read the list of attributes */
clazz.bootstrap =
read_bootstrap_attribute(class_file, &clazz.constant_pool);

clazz.initialized = false;

return clazz;
Expand Down
17 changes: 17 additions & 0 deletions classfile.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,26 @@ typedef struct {
variable_t *static_var; /* store static fields in the class */
} field_t;

typedef struct {
u2 bootstrap_method_ref;
u2 num_bootstrap_arguments;
u2 *bootstrap_arguments;
} bootmethods_t;

typedef struct {
u2 attribute_name_index;
u4 attribute_length;
u2 num_bootstrap_methods;
bootmethods_t *bootstrap_methods;
} bootmethods_attr_t;

typedef struct class_file {
constant_pool_t constant_pool;
class_info_t *info;
method_t *methods;
field_t *fields;
u2 fields_count;
bootmethods_attr_t *bootstrap;
bool initialized;
struct class_file *next;
struct class_file *prev;
Expand Down Expand Up @@ -89,4 +103,7 @@ char *find_field_info_from_index(uint16_t idx,
char **name_info,
char **descriptor_info);
void read_field_attributes(FILE *class_file, field_info *info);
bootmethods_t *find_bootstrap_method(uint16_t idx, class_file_t *clazz);
bootmethods_attr_t *read_bootstrap_attribute(FILE *class_file,
constant_pool_t *cp);
field_t *get_fields(FILE *class_file, constant_pool_t *cp, class_file_t *clazz);
43 changes: 43 additions & 0 deletions constant-pool.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,23 @@ CONSTANT_Class_info *get_class_name(constant_pool_t *cp, u2 idx)
return (CONSTANT_Class_info *) class->info;
}

CONSTANT_MethodHandle_info *get_method_handle(constant_pool_t *cp, u2 idx)
{
const_pool_info *handle = get_constant(cp, idx);
assert(handle->tag == CONSTANT_MethodHandle && "Expected a MethodHandle");
return (CONSTANT_MethodHandle_info *) handle->info;
}

char *get_string_utf(constant_pool_t *cp, u2 idx)
{
const_pool_info *str = get_constant(cp, idx);
assert(str->tag == CONSTANT_String && "Expected a String");
const_pool_info *utf8 =
get_constant(cp, ((CONSTANT_String_info *) str->info)->string_index);
assert(utf8->tag == CONSTANT_Utf8 && "Expected a UTF8");
return (char *) utf8->info;
}

constant_pool_t get_constant_pool(FILE *class_file)
{
constant_pool_t cp = {
Expand Down Expand Up @@ -120,6 +137,32 @@ constant_pool_t get_constant_pool(FILE *class_file)
break;
}

case CONSTANT_String: {
CONSTANT_String_info *value = malloc(sizeof(*value));
assert(value && "Failed to allocate String constant");
value->string_index = read_u2(class_file);
constant->info = (u1 *) value;
break;
}

case CONSTANT_InvokeDynamic: {
CONSTANT_InvokeDynamic_info *value = malloc(sizeof(*value));
assert(value && "Failed to allocate InvokeDynamic constant");
value->bootstrap_method_attr_index = read_u2(class_file);
value->name_and_type_index = read_u2(class_file);
constant->info = (u1 *) value;
break;
}

case CONSTANT_MethodHandle: {
CONSTANT_MethodHandle_info *value = malloc(sizeof(*value));
assert(value && "Failed to allocate MethodHandle constant");
value->reference_kind = read_u1(class_file);
value->reference_index = read_u2(class_file);
constant->info = (u1 *) value;
break;
}

default:
fprintf(stderr, "Unknown constant type %d\n", constant->tag);
exit(1);
Expand Down
19 changes: 19 additions & 0 deletions constant-pool.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@ typedef enum {
CONSTANT_Integer = 3,
CONSTANT_Long = 5,
CONSTANT_Class = 7,
CONSTANT_String = 8,
CONSTANT_FieldRef = 9,
CONSTANT_MethodRef = 10,
CONSTANT_NameAndType = 12,
CONSTANT_MethodHandle = 15,
CONSTANT_InvokeDynamic = 18,
} const_pool_tag_t;

typedef struct {
Expand All @@ -41,6 +44,20 @@ typedef struct {
u2 descriptor_index;
} CONSTANT_NameAndType_info;

typedef struct {
u2 string_index;
} CONSTANT_String_info;

typedef struct {
u2 bootstrap_method_attr_index;
u2 name_and_type_index;
} CONSTANT_InvokeDynamic_info;

typedef struct {
u1 reference_kind;
u2 reference_index;
} CONSTANT_MethodHandle_info;

typedef struct {
const_pool_tag_t tag;
u1 *info;
Expand All @@ -58,3 +75,5 @@ const_pool_info *get_constant(constant_pool_t *constant_pool, u2 index);
constant_pool_t get_constant_pool(FILE *class_file);
CONSTANT_FieldOrMethodRef_info *get_methodref(constant_pool_t *cp, u2 idx);
CONSTANT_Class_info *get_class_name(constant_pool_t *cp, u2 idx);
CONSTANT_MethodHandle_info *get_method_handle(constant_pool_t *cp, u2 idx);
char *get_string_utf(constant_pool_t *cp, u2 idx);
Loading