I suppose I can have a single class for variable states, I could also just
merge the stack and locals into one single list so that the visible state of
all operations are combined as one. I would only have to maintain a single
state, but it would have to be able to handle the stack and such. It would
have to be like my old one, where variable types and such are implicit.
Although this time instead of being actually existing and forced into memory
it is instead cached fully. Thinking about other things, I likely do not need
to do the program output as I can use the
JVMByteProgram class and use that
for translation and such. This class would be handling the SSA and such and
it could be combined into an interpreter of sorts also.
The program will have an initial input state which is determined by the method
signature and if it is an instance method or not. When the
read in the future it will instead of modifying the state of an instruction
like I have done before, it will become a sort of "checked" state which when
a check is done, it must be the result for a given operation. This way I do
not have to juggle setting that state and having derivations of it. Essentially
there would be no derivations so to speak as the output of an instruction would
be run through the instruction. It would be cached of course. In the end,
although using caches much will increase the CPU requirements, it will allow
the interpreter to run on tighter constrained systems. However since the code
blocks of all classes must be in memory it is unlikely that the interpreter
will run at all on constrained systems. Thus on said systems it will likely
only be AOT only or a JIT of sorts which compiles as needed.
For input and output chaining, they can share the same objects so to speak.
The initial method inputs will be the input for the first instruction. The
output of the first instruction will be the input of the next instruction (or
any points it jumps to). So, I will have to scan the code for jumping points
so that can correctly be determined. However, the only jumping around
instructions are literal
gotos and comparison branches. Exception handlers
would also have to be known too.
I will need an efficient way to store the control flow graph, most of the flow is implied as it always goes forwards. All of the other parts depend on comparisons and such. I need a fast and and an efficent way to store all the information. I could use a map. However I believe what I will do is have a map of destinations which are then sourced. When evaluating instructions, it is known what it jumps to however in general processing sources are not known until the entire program is parsed. So it will contain a set of jump sources which are either normal, conditional, or exceptional. I should probably move the program stuff to its own package also.
I will need a prefix for the program though, not
JVM but something else.
For program sources, all instructions can have it. If there is none in the
source mapping then it is an implied previous instruction. I would have to
build it around places where there is no natural flow to the instruction. For
example an instruction after
athrow with no other jump sources
would need to be initialized with a blank jump source because it is not
reachable, otherwise if none is set then the implied one will be used instead.
Going to need a good way to represent the state of variables in the program. Ones which are both implicit and explicit. Something similar to the operator links but a bit better perhaps.
It would be nice to generate some documentation of the source code (i.e. the JavaDoc) and then host it somewhere.
I suppose states would be based on the initial instruction as input. The first
instruction would always return the method input state, while other
instructions for input will pull from one of the sources it has. If there are
multiple entry points for an instruction, then an intersection of the base
outputs would be used instead (they must be compatible however). The
StackMapTable and other attributed details can instead be something different
and act as an input verification state rather than actually being state. This
means that the states do not have to stick around if they are not needed, it
also simplifies things also.
Better to split off the operations before it gets too large.