-
Notifications
You must be signed in to change notification settings - Fork 1
Description
Over the course of the semester, the compilers make greater use of specialized runtime functionality defined in various C files. We need to implement a similar functionality for our interpreter.
Our runtimes will be implemented in pure Racket. Racket functions must be made to interpret values from the registers and stack, and then return their results by pushing to the appropriate register or stack, emulating the behavior of the a86 call instruction. Ideally, this behavior would be (mostly?) automated, such that client compilers would need only to define the functions in terms of normal arguments and return values and provide them to the interpreter, and the details of handling registers/the stack are abstracted away completely.
The functions can be passed in as a hash from function names to implementations during the call to initialize-state. These external functions will be queried with procedure-arity to determine their separate arities, and then converted into functions that can read the appropriate number of arguments from the registers and stack and which will push their results onto the stack at the end. Client compilers will still need to declare the functions' existence via an Extern instruction for no reason other than enforcing good code style for implementing the compiler in other environments. (The Extern instructions could be automatically generated based on the input hash otherwise.)
To-do
- Extend AST definition to include
Externlabels for functions defined in the runtime environment. - Implement function-conversion functions.
- Use
procedure-arityto determine the number of arguments to read from registers/the stack. - Read registers for arguments.
- Read memory for additional arguments.
- Correctly return from converted function.
- The passed-in function's return value should be checked to ensure it can be encoded properly. Maybe implement an
encodefunction for handling native Racket values?
- Use
- Extend
Stateto hold ahashin a field namedruntime(or something like it). - Extend
initialize-stateto read thishashand convert each of the functions into an assembly-compatible function. - Update
stepfunction.- Handle
Externfunction labels. (Just checks that the label corresponds to a function defined in the runtimehash.) - Handle calls to external functions appropriately in
Callinstructions.
- Handle
- Implement basic tests.
-
read-byte -
write-byte - A function that requires reading values from the stack (beyond the maximum number of registers).
-
Observational Inequality of Register Modification
In a traditional compilation environment, modification of the registers performed by external functions is visible to the client code, even if such values are not considered "returned" values. In our runtime implementation, such modifications will be invisible to the client code because it will happen in Racket natively instead of passing through the interpreter. Although this means our interpreter will deviate observationally from traditionally compiled code, I think the difference is unlikely to have significant impact in student projects since students are expected to follow standard calling conventions. Maybe make a note in the code about it, though.