1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include "jvm.h"
#include <assert.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "heap.h"
#include "read_class.h"
/** The name of the method to invoke to run the class file */
const char MAIN_METHOD[] = "main";
/**
* The "descriptor" string for main(). The descriptor encodes main()'s signature,
* i.e. main() takes a String[] and returns void.
* If you're interested, the descriptor string is explained at
* https://docs.oracle.com/javase/specs/jvms/se12/html/jvms-4.html#jvms-4.3.2.
*/
const char MAIN_DESCRIPTOR[] = "([Ljava/lang/String;)V";
/**
* Represents the return value of a Java method: either void or an int or a reference.
* For simplification, we represent a reference as an index into a heap-allocated array.
* (In a real JVM, methods could also return object references or other primitives.)
*/
typedef struct {
/** Whether this returned value is an int */
bool has_value;
/** The returned value (only valid if `has_value` is true) */
int32_t value;
} optional_value_t;
/**
* Runs a method's instructions until the method returns.
*
* @param method the method to run
* @param locals the array of local variables, including the method parameters.
* Except for parameters, the locals are uninitialized.
* @param class the class file the method belongs to
* @param heap an array of heap-allocated pointers, useful for references
* @return an optional int containing the method's return value
*/
optional_value_t execute(method_t *method, int32_t *locals, class_file_t *class,
heap_t *heap) {
/* You should remove these casts to void in your solution.
* They are just here so the code compiles without warnings. */
(void) method;
(void) locals;
(void) class;
(void) heap;
// Return void
optional_value_t result = {.has_value = false};
return result;
}
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "USAGE: %s <class file>\n", argv[0]);
return 1;
}
// Open the class file for reading
FILE *class_file = fopen(argv[1], "r");
assert(class_file != NULL && "Failed to open file");
// Parse the class file
class_file_t *class = get_class(class_file);
int error = fclose(class_file);
assert(error == 0 && "Failed to close file");
// The heap array is initially allocated to hold zero elements.
heap_t *heap = heap_init();
// Execute the main method
method_t *main_method = find_method(MAIN_METHOD, MAIN_DESCRIPTOR, class);
assert(main_method != NULL && "Missing main() method");
/* In a real JVM, locals[0] would contain a reference to String[] args.
* But since TeenyJVM doesn't support Objects, we leave it uninitialized. */
int32_t locals[main_method->code.max_locals];
// Initialize all local variables to 0
memset(locals, 0, sizeof(locals));
optional_value_t result = execute(main_method, locals, class, heap);
assert(!result.has_value && "main() should return void");
// Free the internal data structures
free_class(class);
// Free the heap
heap_free(heap);
}