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 6c5646a

Browse files
authored
Merge pull request #8 from hankluo6/field
Add more class related opcodes
2 parents 266e518 + 7d71178 commit 6c5646a

File tree

11 files changed

+292
-5
lines changed

11 files changed

+292
-5
lines changed

‎Makefile‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ TESTS = \
4545
Recursion \
4646
Long \
4747
Caller \
48-
Constructor
48+
Constructor \
49+
Field \
50+
Static
4951

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

‎class-heap.c‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ void free_class_heap()
9191
free(constant->info);
9292
}
9393
free(class_heap.class_info[i]->clazz->constant_pool.constant_pool);
94+
95+
field_t *field = class_heap.class_info[i]->clazz->fields;
96+
for (u2 j = 0; j < class_heap.class_info[i]->clazz->fields_count;
97+
j++, field++)
98+
free(field->static_var);
9499
free(class_heap.class_info[i]->clazz->fields);
95100

96101
for (method_t *method = class_heap.class_info[i]->clazz->methods;

‎classfile.c‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,27 @@ uint16_t get_number_of_parameters(method_t *method)
3131
return strlen(method->descriptor) - 3;
3232
}
3333

34+
/**
35+
* Find the field with the given name and signature.
36+
* The difference between `find_field` and `object_heap:find_field_addr`
37+
* is that `find_field` is used to find class level field (i.e. static field),
38+
* and `find_field_addr` is used to find object level field.
39+
*
40+
* @param name the field name
41+
* @param desc the field descriptor string, e.g. "(I)I"
42+
* @param clazz the parsed class file
43+
* @return the field if it was found, or NULL
44+
*/
45+
field_t *find_field(const char *name, const char *desc, class_file_t *clazz)
46+
{
47+
field_t *field = clazz->fields;
48+
for (u2 i = 0; i < clazz->fields_count; ++i, field++) {
49+
if (!(strcmp(name, field->name) || strcmp(desc, field->descriptor)))
50+
return field;
51+
}
52+
return NULL;
53+
}
54+
3455
/**
3556
* Find the method with the given name and signature.
3657
* The descriptor is necessary because Java allows method overloading.
@@ -218,6 +239,7 @@ field_t *get_fields(FILE *class_file, constant_pool_t *cp, class_file_t *clazz)
218239
const_pool_info *descriptor = get_constant(cp, info.descriptor_index);
219240
assert(descriptor->tag == CONSTANT_Utf8 && "Expected a UTF8");
220241
field->descriptor = (char *) descriptor->info;
242+
field->static_var = malloc(sizeof(variable_t));
221243

222244
read_field_attributes(class_file, &info);
223245
}

‎classfile.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ typedef struct {
5151
char *class_name;
5252
char *name;
5353
char *descriptor;
54+
variable_t *static_var; /* store static fields in the class */
5455
} field_t;
5556

5657
typedef struct {
@@ -73,6 +74,7 @@ void read_method_attributes(FILE *class_file,
7374
code_t *code,
7475
constant_pool_t *cp);
7576
uint16_t get_number_of_parameters(method_t *method);
77+
field_t *find_field(const char *name, const char *desc, class_file_t *clazz);
7678
method_t *find_method(const char *name, const char *desc, class_file_t *clazz);
7779
method_t *find_method_from_index(uint16_t idx, class_file_t *clazz);
7880
class_file_t get_class(FILE *class_file);

‎jvm.c‎

Lines changed: 204 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ typedef enum {
9494
i_areturn = 0xb0,
9595
i_return = 0xb1,
9696
i_getstatic = 0xb2,
97+
i_putstatic = 0xb3,
98+
i_getfield = 0xb4,
99+
i_putfield = 0xb5,
97100
i_invokevirtual = 0xb6,
98101
i_invokespecial = 0xb7,
99102
i_invokestatic = 0xb8,
@@ -783,10 +786,124 @@ stack_entry_t *execute(method_t *method,
783786
break;
784787

785788
/* Get static field from class */
786-
case i_getstatic:
787-
/* FIXME: unimplemented */
789+
case i_getstatic: {
790+
uint8_t param1 = code_buf[pc + 1], param2 = code_buf[pc + 2];
791+
uint16_t index = ((param1 << 8) | param2);
792+
793+
char *field_name, *field_descriptor, *class_name;
794+
class_name = find_field_info_from_index(index, clazz, &field_name,
795+
&field_descriptor);
796+
797+
/* skip java.lang.System in order to support java print
798+
* method */
799+
if (!strcmp(class_name, "java/lang/System")) {
800+
pc += 3;
801+
break;
802+
}
803+
804+
class_file_t *target_class =
805+
find_or_add_class_to_heap(class_name, prefix);
806+
field_t *field =
807+
find_field(field_name, field_descriptor, target_class);
808+
809+
switch (field_descriptor[0]) {
810+
case 'B':
811+
/* signed byte */
812+
push_byte(op_stack, field->static_var->value.char_value);
813+
break;
814+
case 'C':
815+
/* FIXME: complete Unicode handling */
816+
/* unicode character code */
817+
push_short(op_stack, field->static_var->value.short_value);
818+
break;
819+
case 'I':
820+
/* integer */
821+
push_int(op_stack, field->static_var->value.int_value);
822+
break;
823+
case 'J':
824+
/* long integer */
825+
push_long(op_stack, field->static_var->value.long_value);
826+
break;
827+
case 'S':
828+
/* signed short */
829+
push_short(op_stack, field->static_var->value.short_value);
830+
break;
831+
case 'Z':
832+
/* true or false */
833+
push_byte(op_stack, field->static_var->value.char_value);
834+
break;
835+
case 'L':
836+
/* an instance of class */
837+
push_ref(op_stack, field->static_var->value.ptr_value);
838+
break;
839+
default:
840+
fprintf(stderr, "Unknown field descriptor %c\n",
841+
field_descriptor[0]);
842+
exit(1);
843+
}
788844
pc += 3;
789845
break;
846+
}
847+
848+
/* Put static field to class */
849+
case i_putstatic: {
850+
uint8_t param1 = code_buf[pc + 1], param2 = code_buf[pc + 2];
851+
uint16_t index = ((param1 << 8) | param2);
852+
853+
char *field_name, *field_descriptor, *class_name;
854+
class_name = find_field_info_from_index(index, clazz, &field_name,
855+
&field_descriptor);
856+
857+
class_file_t *target_class =
858+
find_or_add_class_to_heap(class_name, prefix);
859+
field_t *field =
860+
find_field(field_name, field_descriptor, target_class);
861+
862+
switch (field_descriptor[0]) {
863+
case 'B':
864+
/* signed byte */
865+
field->static_var->value.char_value = (u1) pop_int(op_stack);
866+
field->static_var->type = VAR_BYTE;
867+
break;
868+
case 'C':
869+
/* FIXME: complete Unicode handling */
870+
/* unicode character code */
871+
field->static_var->value.char_value = (u2) pop_int(op_stack);
872+
field->static_var->type = VAR_SHORT;
873+
break;
874+
case 'I':
875+
/* integer */
876+
field->static_var->value.int_value = (u4) pop_int(op_stack);
877+
field->static_var->type = VAR_INT;
878+
break;
879+
case 'J':
880+
/* long integer */
881+
field->static_var->value.long_value = (u8) pop_int(op_stack);
882+
field->static_var->type = VAR_LONG;
883+
break;
884+
case 'S':
885+
/* signed short */
886+
field->static_var->value.short_value = (u2) pop_int(op_stack);
887+
field->static_var->type = VAR_SHORT;
888+
break;
889+
case 'Z':
890+
/* true or false */
891+
field->static_var->value.char_value = (u1) pop_int(op_stack);
892+
field->static_var->type = VAR_BYTE;
893+
break;
894+
case 'L':
895+
/* an instance of class ClassName */
896+
field->static_var->value.ptr_value = pop_ref(op_stack);
897+
field->static_var->type = VAR_PTR;
898+
break;
899+
default:
900+
fprintf(stderr, "Unknown field descriptor %c\n",
901+
field_descriptor[0]);
902+
exit(1);
903+
}
904+
pc += 3;
905+
break;
906+
}
790907

791908
/* Invoke instance method; dispatch based on class */
792909
case i_invokevirtual:
@@ -820,6 +937,91 @@ stack_entry_t *execute(method_t *method,
820937
pc += 3;
821938
break;
822939

940+
/* Fetch field from object */
941+
case i_getfield: {
942+
uint8_t param1 = code_buf[pc + 1], param2 = code_buf[pc + 2];
943+
uint16_t index = ((param1 << 8) | param2);
944+
945+
object_t *obj = pop_ref(op_stack);
946+
char *field_name, *field_descriptor;
947+
find_field_info_from_index(index, clazz, &field_name,
948+
&field_descriptor);
949+
950+
variable_t *addr = find_field_addr(obj, field_name);
951+
952+
switch (field_descriptor[0]) {
953+
case 'I':
954+
push_int(op_stack, addr->value.int_value);
955+
break;
956+
case 'J':
957+
push_long(op_stack, addr->value.long_value);
958+
break;
959+
case 'L':
960+
push_ref(op_stack, addr->value.ptr_value);
961+
break;
962+
default:
963+
assert(0 && "Only support integer and reference field");
964+
break;
965+
}
966+
pc += 3;
967+
break;
968+
}
969+
970+
/* Set field in object */
971+
case i_putfield: {
972+
uint8_t param1 = code_buf[pc + 1], param2 = code_buf[pc + 2];
973+
uint16_t index = ((param1 << 8) | param2);
974+
int64_t value = 0;
975+
void *addr = NULL;
976+
977+
/* get prepared value from the stack */
978+
stack_entry_t element = top(op_stack);
979+
switch (element.type) {
980+
/* integer */
981+
case STACK_ENTRY_INT:
982+
case STACK_ENTRY_SHORT:
983+
case STACK_ENTRY_BYTE:
984+
case STACK_ENTRY_LONG:
985+
value = pop_int(op_stack);
986+
break;
987+
case STACK_ENTRY_REF:
988+
addr = pop_ref(op_stack);
989+
break;
990+
default:
991+
assert(0 && "Only support integer and reference field");
992+
break;
993+
}
994+
995+
object_t *obj = pop_ref(op_stack);
996+
997+
/* update value into object's field */
998+
char *field_name, *field_descriptor;
999+
find_field_info_from_index(index, clazz, &field_name,
1000+
&field_descriptor);
1001+
1002+
variable_t *var = find_field_addr(obj, field_name);
1003+
1004+
switch (field_descriptor[0]) {
1005+
case 'I':
1006+
var->value.int_value = (int32_t) value;
1007+
var->type = VAR_INT;
1008+
break;
1009+
case 'J':
1010+
var->value.long_value = value;
1011+
var->type = VAR_LONG;
1012+
break;
1013+
case 'L':
1014+
var->value.ptr_value = addr;
1015+
var->type = VAR_PTR;
1016+
break;
1017+
default:
1018+
assert(0 && "Only support integer and reference field");
1019+
break;
1020+
}
1021+
pc += 3;
1022+
break;
1023+
}
1024+
8231025
/* create new object */
8241026
case i_new: {
8251027
uint8_t param1 = code_buf[pc + 1], param2 = code_buf[pc + 2];

‎object-heap.c‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,18 @@ object_t *create_object(class_file_t *clazz)
2626
return new_obj;
2727
}
2828

29+
variable_t *find_field_addr(object_t *obj, char *name)
30+
{
31+
field_t *field = obj->class->fields;
32+
for (u2 i = 0; i < obj->class->fields_count; i++, field++) {
33+
if (!strcmp(field->name, name)) {
34+
return &obj->value[i];
35+
}
36+
}
37+
assert(0 && "Can't find field in the object");
38+
return NULL;
39+
}
40+
2941
void free_object_heap()
3042
{
3143
for (int i = 0; i < object_heap.length; ++i) {

‎object-heap.h‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@ typedef struct {
1515

1616
void init_object_heap();
1717
void free_object_heap();
18-
object_t *create_object(class_file_t *clazz);
18+
object_t *create_object(class_file_t *clazz);
19+
variable_t *find_field_addr(object_t *obj, char *name);

‎stack.c‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ void push_ref(stack_frame_t *stack, void *addr)
4343
stack->size++;
4444
}
4545

46+
stack_entry_t top(stack_frame_t *stack)
47+
{
48+
return stack->store[stack->size - 1];
49+
}
50+
4651
/* pop top of stack value and convert to 64 bits integer */
4752
int64_t stack_to_int(value_t *entry, size_t size)
4853
{

‎stack.h‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,5 @@ int64_t pop_int(stack_frame_t *stack);
4343
void *pop_ref(stack_frame_t *stack);
4444
void pop_to_local(stack_frame_t *stack, local_variable_t *locals);
4545
size_t get_type_size(stack_entry_type_t type);
46-
int64_t stack_to_int(value_t *entry, size_t size);
46+
int64_t stack_to_int(value_t *entry, size_t size);
47+
stack_entry_t top(stack_frame_t *stack);

‎tests/Field.java‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
class Field {
2+
Field(int a, int b, int c) {
3+
x = a;
4+
y = b;
5+
z = c;
6+
}
7+
public static void main(String[] args) {
8+
Field f = new Field(1, 2, 3);
9+
System.out.println(f.x + f.y + f.z);
10+
}
11+
int x, y, z;
12+
}

0 commit comments

Comments
(0)

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