Skip to content

Add support for external runtime functions #1

@pdarragh

Description

@pdarragh

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 Extern labels for functions defined in the runtime environment.
  • Implement function-conversion functions.
    • Use procedure-arity to 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 encode function for handling native Racket values?
  • Extend State to hold a hash in a field named runtime (or something like it).
  • Extend initialize-state to read this hash and convert each of the functions into an assembly-compatible function.
  • Update step function.
    • Handle Extern function labels. (Just checks that the label corresponds to a function defined in the runtime hash.)
    • Handle calls to external functions appropriately in Call instructions.
  • 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.

Metadata

Metadata

Assignees

Labels

coreIssues for the core functionalityenhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions