Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 7331be2

Browse files
authored
Merge pull request #12 from hankluo6/inheritance
Handle class inheritance correctly
2 parents ad67942 + 71875f4 commit 7331be2

File tree

7 files changed

+218
-49
lines changed

7 files changed

+218
-49
lines changed

‎Makefile‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ TESTS = \
4848
Constructor \
4949
Field \
5050
Static \
51-
Invokevirtual
51+
Invokevirtual \
52+
Inherit \
53+
Initializer
5254

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

‎class-heap.c‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ void free_class_heap()
9595
free(constant->info);
9696
}
9797
free(class_heap.class_info[i]->clazz->constant_pool.constant_pool);
98+
free(class_heap.class_info[i]->clazz->info);
9899

99100
field_t *field = class_heap.class_info[i]->clazz->fields;
100101
for (u2 j = 0; j < class_heap.class_info[i]->clazz->fields_count;

‎classfile.c‎

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ class_header_t get_class_header(FILE *class_file)
99
};
1010
}
1111

12-
class_info_t get_class_info(FILE *class_file)
12+
class_info_t *get_class_info(FILE *class_file)
1313
{
14-
class_info_t info = {
15-
.access_flags = read_u2(class_file),
16-
.this_class = read_u2(class_file),
17-
.super_class = read_u2(class_file),
18-
};
14+
class_info_t *info = malloc(sizeof(class_info_t));
15+
info->access_flags = read_u2(class_file);
16+
info->this_class = read_u2(class_file);
17+
info->super_class = read_u2(class_file);
18+
1919
u2 interfaces_count = read_u2(class_file);
2020
assert(!interfaces_count && "This VM does not support interfaces.");
2121
return info;
@@ -303,12 +303,15 @@ class_file_t get_class(FILE *class_file)
303303
class_file_t clazz = {.constant_pool = get_constant_pool(class_file)};
304304

305305
/* Read information about the class that was compiled. */
306-
get_class_info(class_file);
306+
clazz.info=get_class_info(class_file);
307307

308308
/* Read the list of fields */
309309
clazz.fields = get_fields(class_file, &clazz.constant_pool, &clazz);
310310

311311
/* Read the list of static methods */
312312
clazz.methods = get_methods(class_file, &clazz.constant_pool);
313+
314+
clazz.initialized = false;
315+
313316
return clazz;
314317
}

‎classfile.h‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,11 @@ typedef struct {
5656

5757
typedef struct {
5858
constant_pool_t constant_pool;
59+
class_info_t *info;
5960
method_t *methods;
6061
field_t *fields;
6162
u2 fields_count;
63+
bool initialized;
6264
} class_file_t;
6365

6466
typedef struct {
@@ -67,7 +69,7 @@ typedef struct {
6769
} meta_class_t;
6870

6971
class_header_t get_class_header(FILE *class_file);
70-
class_info_t get_class_info(FILE *class_file);
72+
class_info_t *get_class_info(FILE *class_file);
7173
method_t *get_methods(FILE *class_file, constant_pool_t *cp);
7274
void read_method_attributes(FILE *class_file,
7375
method_info *info,

‎jvm.c‎

Lines changed: 110 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -263,12 +263,28 @@ stack_entry_t *execute(method_t *method,
263263

264264
/* the method to be called */
265265
char *method_name, *method_descriptor, *class_name;
266-
class_name = find_method_info_from_index(index, clazz, &method_name,
267-
&method_descriptor);
266+
method_t *own_method = NULL;
267+
class_file_t *target_class = NULL;
268+
269+
/* recursively find method from child to parent */
270+
while (!own_method) {
271+
if (!target_class)
272+
class_name = find_method_info_from_index(
273+
index, clazz, &method_name, &method_descriptor);
274+
else
275+
class_name = find_class_name_from_index(
276+
target_class->info->super_class, target_class);
277+
find_or_add_class_to_heap(class_name, prefix, &target_class);
278+
assert(target_class &&
279+
"Failed to load class in i_invokestatic");
280+
own_method =
281+
find_method(method_name, method_descriptor, target_class);
282+
}
268283

269-
class_file_t *target_class;
270-
if (find_or_add_class_to_heap(class_name, prefix, &target_class)) {
271-
/* Call static initialization */
284+
/* call static initialization. Only the class that contains this
285+
* method should do static initialization */
286+
if (!target_class->initialized) {
287+
target_class->initialized = true;
272288
method_t *method = find_method("<clinit>", "()V", target_class);
273289
if (method) {
274290
local_variable_t own_locals[method->code.max_locals];
@@ -279,10 +295,7 @@ stack_entry_t *execute(method_t *method,
279295
free(exec_res);
280296
}
281297
}
282-
assert(target_class && "Failed to load class in invokestatic");
283298

284-
method_t *own_method =
285-
find_method(method_name, method_descriptor, target_class);
286299
uint16_t num_params = get_number_of_parameters(own_method);
287300
local_variable_t own_locals[own_method->code.max_locals];
288301
for (int i = num_params - 1; i >= 0; i--)
@@ -794,19 +807,33 @@ stack_entry_t *execute(method_t *method,
794807
uint16_t index = ((param1 << 8) | param2);
795808

796809
char *field_name, *field_descriptor, *class_name;
810+
field_t *field = NULL;
811+
class_file_t *target_class = NULL;
812+
797813
class_name = find_field_info_from_index(index, clazz, &field_name,
798814
&field_descriptor);
799-
800815
/* skip java.lang.System in order to support java print
801816
* method */
802817
if (!strcmp(class_name, "java/lang/System")) {
803818
pc += 3;
804819
break;
805820
}
806821

807-
class_file_t *target_class;
808-
if (find_or_add_class_to_heap(class_name, prefix, &target_class)) {
809-
/* Call static initialization */
822+
while (!field) {
823+
if (target_class)
824+
class_name = find_class_name_from_index(
825+
target_class->info->super_class, target_class);
826+
827+
find_or_add_class_to_heap(class_name, prefix, &target_class);
828+
assert(target_class && "Failed to load class in i_getstatic");
829+
830+
field = find_field(field_name, field_descriptor, target_class);
831+
}
832+
833+
/* call static initialization. Only the class that contains this
834+
* field should do static initialization */
835+
if (!target_class->initialized) {
836+
target_class->initialized = true;
810837
method_t *method = find_method("<clinit>", "()V", target_class);
811838
if (method) {
812839
local_variable_t own_locals[method->code.max_locals];
@@ -818,9 +845,6 @@ stack_entry_t *execute(method_t *method,
818845
}
819846
}
820847

821-
field_t *field =
822-
find_field(field_name, field_descriptor, target_class);
823-
824848
switch (field_descriptor[0]) {
825849
case 'B':
826850
/* signed byte */
@@ -866,12 +890,33 @@ stack_entry_t *execute(method_t *method,
866890
uint16_t index = ((param1 << 8) | param2);
867891

868892
char *field_name, *field_descriptor, *class_name;
893+
field_t *field = NULL;
894+
class_file_t *target_class = NULL;
869895
class_name = find_field_info_from_index(index, clazz, &field_name,
870896
&field_descriptor);
871897

872-
class_file_t *target_class;
873-
if (find_or_add_class_to_heap(class_name, prefix, &target_class)) {
874-
/* Call static initialization */
898+
/* skip java.lang.System in order to support java print
899+
* method */
900+
if (!strcmp(class_name, "java/lang/System")) {
901+
pc += 3;
902+
break;
903+
}
904+
905+
while (!field) {
906+
if (target_class)
907+
class_name = find_class_name_from_index(
908+
target_class->info->super_class, target_class);
909+
910+
find_or_add_class_to_heap(class_name, prefix, &target_class);
911+
assert(target_class && "Failed to load class in i_putstatic");
912+
913+
field = find_field(field_name, field_descriptor, target_class);
914+
}
915+
916+
/* call static initialization. Only the class that contains this
917+
* field should do static initialization */
918+
if (!target_class->initialized) {
919+
target_class->initialized = true;
875920
method_t *method = find_method("<clinit>", "()V", target_class);
876921
if (method) {
877922
local_variable_t own_locals[method->code.max_locals];
@@ -882,8 +927,6 @@ stack_entry_t *execute(method_t *method,
882927
free(exec_res);
883928
}
884929
}
885-
field_t *field =
886-
find_field(field_name, field_descriptor, target_class);
887930

888931
switch (field_descriptor[0]) {
889932
case 'B':
@@ -938,6 +981,9 @@ stack_entry_t *execute(method_t *method,
938981

939982
/* the method to be called */
940983
char *method_name, *method_descriptor, *class_name;
984+
class_file_t *target_class = NULL;
985+
method_t *method = NULL;
986+
941987
class_name = find_method_info_from_index(index, clazz, &method_name,
942988
&method_descriptor);
943989

@@ -964,9 +1010,22 @@ stack_entry_t *execute(method_t *method,
9641010
}
9651011

9661012
/* FIXME: consider method modifier */
967-
class_file_t *target_class;
968-
if (find_or_add_class_to_heap(class_name, prefix, &target_class)) {
969-
/* Call static initialization */
1013+
/* recursively find method from child to parent */
1014+
while (!method) {
1015+
if (target_class)
1016+
class_name = find_class_name_from_index(
1017+
target_class->info->super_class, target_class);
1018+
find_or_add_class_to_heap(class_name, prefix, &target_class);
1019+
assert(target_class &&
1020+
"Failed to load class in i_invokevirtual");
1021+
method =
1022+
find_method(method_name, method_descriptor, target_class);
1023+
}
1024+
1025+
/* call static initialization. Only the class that contains this
1026+
* method should do static initialization */
1027+
if (!target_class->initialized) {
1028+
target_class->initialized = true;
9701029
method_t *method = find_method("<clinit>", "()V", target_class);
9711030
if (method) {
9721031
local_variable_t own_locals[method->code.max_locals];
@@ -977,8 +1036,7 @@ stack_entry_t *execute(method_t *method,
9771036
free(exec_res);
9781037
}
9791038
}
980-
method_t *method =
981-
find_method(method_name, method_descriptor, target_class);
1039+
9821040
uint16_t num_params = get_number_of_parameters(method);
9831041
local_variable_t own_locals[method->code.max_locals];
9841042
memset(own_locals, 0, sizeof(own_locals));
@@ -1138,8 +1196,26 @@ stack_entry_t *execute(method_t *method,
11381196

11391197
char *class_name = find_class_name_from_index(index, clazz);
11401198
class_file_t *target_class;
1141-
if (find_or_add_class_to_heap(class_name, prefix, &target_class)) {
1142-
/* Call static initialization */
1199+
1200+
/* FIXME: use linked list to prevent wasted space */
1201+
class_file_t **stack = malloc(sizeof(class_file_t *) * 100);
1202+
size_t count = 0;
1203+
while (true) {
1204+
find_or_add_class_to_heap(class_name, prefix, &target_class);
1205+
assert(target_class && "Failed to load class in i_new");
1206+
stack[count++] = target_class;
1207+
class_name = find_class_name_from_index(
1208+
target_class->info->super_class, target_class);
1209+
if (!strcmp(class_name, "java/lang/Object"))
1210+
break;
1211+
}
1212+
1213+
/* call static initialization */
1214+
while (count) {
1215+
target_class = stack[--count];
1216+
if (target_class->initialized)
1217+
continue;
1218+
target_class->initialized = true;
11431219
method_t *method = find_method("<clinit>", "()V", target_class);
11441220
if (method) {
11451221
local_variable_t own_locals[method->code.max_locals];
@@ -1150,7 +1226,7 @@ stack_entry_t *execute(method_t *method,
11501226
free(exec_res);
11511227
}
11521228
}
1153-
assert(target_class&&"Failed to load class in new");
1229+
free(stack);
11541230

11551231
object_t *object = create_object(target_class);
11561232
push_ref(op_stack, object);
@@ -1178,8 +1254,12 @@ stack_entry_t *execute(method_t *method,
11781254
}
11791255

11801256
class_file_t *target_class;
1181-
if (find_or_add_class_to_heap(class_name, prefix, &target_class)) {
1182-
/* Call static initialization */
1257+
find_or_add_class_to_heap(class_name, prefix, &target_class);
1258+
assert(target_class && "Failed to load class in i_invokespecial");
1259+
1260+
/* call static initialization */
1261+
if (!target_class->initialized) {
1262+
target_class->initialized = true;
11831263
method_t *method = find_method("<clinit>", "()V", target_class);
11841264
if (method) {
11851265
local_variable_t own_locals[method->code.max_locals];
@@ -1190,7 +1270,6 @@ stack_entry_t *execute(method_t *method,
11901270
free(exec_res);
11911271
}
11921272
}
1193-
assert(target_class && "Failed to load class in i_invokespecial");
11941273

11951274
/* find constructor method from class */
11961275
method_t *constructor =
@@ -1254,15 +1333,6 @@ int main(int argc, char *argv[])
12541333
prefix[match - argv[1] + 1] = '0円';
12551334
}
12561335

1257-
method_t *method = find_method("<clinit>", "()V", clazz);
1258-
if (method) {
1259-
local_variable_t own_locals[method->code.max_locals];
1260-
stack_entry_t *exec_res = execute(method, own_locals, clazz);
1261-
assert(exec_res->type == STACK_ENTRY_NONE &&
1262-
"<clinit> must not return a value");
1263-
free(exec_res);
1264-
}
1265-
12661336
/* execute the main method if found */
12671337
method_t *main_method =
12681338
find_method("main", "([Ljava/lang/String;)V", clazz);

‎tests/Inherit.java‎

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
public class Inherit {
2+
static int x = 1;
3+
4+
public static void static_call() {
5+
System.out.println(1);
6+
}
7+
8+
public void virtual_call() {
9+
System.out.println(2);
10+
}
11+
12+
public static void main(String[] args) {
13+
Inherit obj = new Inherit();
14+
InheritA objA = new InheritA();
15+
InheritB objB = new InheritB();
16+
17+
/* check shared static fields */
18+
System.out.println(obj.x);
19+
System.out.println(objA.x);
20+
System.out.println(objB.x);
21+
obj.x = 2;
22+
System.out.println(obj.x);
23+
System.out.println(objA.x);
24+
System.out.println(objB.x);
25+
objA.x = 3;
26+
System.out.println(obj.x);
27+
System.out.println(objA.x);
28+
System.out.println(objB.x);
29+
30+
/* check static methods inheritance (compiler will replace objects with classes) */
31+
obj.static_call();
32+
objA.static_call();
33+
objB.static_call();
34+
35+
/* check virtual methods inheritance */
36+
obj.virtual_call();
37+
objA.virtual_call();
38+
objB.virtual_call();
39+
}
40+
}
41+
42+
class InheritA extends Inherit {
43+
44+
}
45+
46+
class InheritB extends InheritA {
47+
/* check override */
48+
public void virtual_call() {
49+
System.out.println(3);
50+
}
51+
public static void static_call() {
52+
System.out.println(4);
53+
}
54+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /