5 I believe I like this new class decoding code straight in the JIT much better.
6 It just gets right to the point.
10 One thing I need to consider are virtual method calls. Due to the default by
11 nature execution of methods. It would either be a read of a field or a double
12 jump to the correct method area. So basically any call to a virtual method
13 will read some kind of offset and then read the pointer at that offset which
14 then points to a method that should be the one that is executed. That is a way
15 to easily implement virtual calls. Static and special calls however can just
16 directly execute methods.
20 Interfaces would require interface tables. But interface lookup should be
21 fast. I want to completely avoid having linear checks for classes and
22 interfaces. Just want it to be a simple jump.
26 Another thing that can exist in the cards is the check and comparison nature
27 of values. So if a null pointer was checked then it does not have to be
28 checked. But if there is a jump from an unchecked position to a checked one
29 then the check will have to be performed or delayed at that point. That can
30 lead to inconsistent exceptions around branches around code which should
31 execute, so that is a no-go. Unless I have a potential alternative path.
32 But actually I can generate all of those checks and then optimize them away
33 for example. There can be a dependency detection of things and such to
34 determine which checks could be potentially removed. This would then mean
35 that I am definitely going for an IL. So then faces which implement IL
36 operations should be abstract classes which are extended by the architecture
37 specific code. So there is an addition face for example. Then the MIPS one
38 just knows how to generate a machine code instruction from that. I could
39 however take a hybrid approach. Have a default face set that utilizes
40 registers and such. Then have faces that are architecture specific such as
41 clearing interrupts or whatever. But it would probably be the simplest to
42 just have standard cards which perform standard operations on registers. Then
43 on output to machine code, just translate those cards to native operations
44 as needed. That would make the JIT implementations simple as they would just
45 translate the faces to machine code accordingly. The faces would be modeled
46 after MIPS because that is the simplest. Other architectures would map well
47 to it. The faces used for one target will not be compatible with another
48 target however. This is because of the registers and data types. This would
49 allow me to support many architectures more easily because I would only have
50 to write the final stage. But for final stage reusing, the standard cards will
51 be replaced by architecture specific cards. That way there can be a final
52 architecture specific optimization pass. Then it would also enable me to use
53 the card system like I plan to when generating internal use methods.
57 As for `invokeinterface`. I could do a large number of static references. For
58 example say method `a` from class `A` invokes the method `z` in interface `Z`.
59 This can be determined at linking time. Basically `a` would do something
60 similar to the virtual invoke. But would link to a special dispatcher. But
61 pretty much a dispatcher must be used. However every class would have
62 interface tables which point to associated interfaces. Also since tons of
63 objects will use the same virtual method links, they will be in the class
64 export table for those classes. So class `B` replacing a method in `A`. For
65 `A`'s class table that points to the code for that method, while for class `B`
66 in that same index (in `A`'s part of the code) will point to the method it is
67 replaced by. So every class would have unique export tables.
71 The deck should be completely type safe with known program control flow in the
72 cards. This would mean that no cards can dangle. Future cards in the chain
73 would morph based on the previous cards. This means for state though, there
74 would be recursive state determination based on registers and such however. I
75 would basically have basic blocks in a way. I would need backlinks, aliases,
76 and some other things too. If state is stored then I would have to check if
77 any dependency has changed before returning it, which would be insanely slow.
78 And that would require lots of code and compution time to calculate. I will
79 need multiple parts of methods. prolog, epilog, main body, exception jumpers.
80 Then whenever a card is placed in the output it becomes fixed and cannot be
81 changed. So once a card is placed it is immutable and has a purely fixed
82 state that will never change. Forward jumps to undeclared cards define state
83 while backward jumps to declared cards must forward state. So the exception
84 jumpers would purely be state cycling. The state cyclers would have a given
85 input set of registers and a given set of target registers.
89 If an existing transition from one state does not match another then a new
90 one will be created. The prolog would require that the state of the input at
91 the end of all of its execution matches the main body entry point. Jumps to
92 the prolog and epilog would be illegal. The epilog may only be jumped to in
93 the main body or the exception checks. I would need an exception check for
94 instances. Then if no exceptions are handled it would just go straight into
95 the epilog and return the exception for handling by the calling method. So
96 once card is placed, it is immutable. The prolog state can be checked at the
97 end to make sure it is valid. I then also continue the route of treating
98 exceptions as just another variable to be checked along with the secondary
103 Immutibility would be easier for states, less compicated.
107 Ok so for removing things such as bounds checks and null pointer checks, I can
112 Basically, when a variable is modified there can be a bye chain for each
113 variable representation which has a source value. This means getting rid of
114 aliases and having it completely being value based. So basically on entry of a
115 method, variables are completely washed away and everything is just a value
116 and where it is located. So you could for example copy a local variable to the
117 stack then set the local variable to some other value, or duplicate it. That
118 value is never actually lost. So arguments are called by value. Then each
119 value at a specific position has flags which determine if the value as changed
120 or similar. However, code generated has to be done in a way where byes do not
121 exist. The removing of operations is only a final step optimization.
125 So if there is a jump back where the value is not compatible then it will
126 perform those checks. This means that loops would have many many fewer checks
127 if the inputs are correct. I would also need to make sure that variables get
128 keyed with lengths also. So there would be branch conditions where a variable
129 is always less than a given amount. Then if some values are associated, then
130 the checks can be removed.
134 So this is much more complex now. There would still be weak bindings to
135 variable slots because that is how Java operates, via the stack, rather than
136 discreet values. Because jump backs can modify variables as they are placed.
137 So unless the value is copied back, it would have to split and make it
142 So actually I do not have to worry about the slots in a way. Basically the
143 slots are windows to values.
147 So basically the accessing of values is done via pointers and such in a way.
151 I believe for interfaces that calls should be treated as if they were
152 virtual, but there would be virtualized methods for each method in the
153 interface which dispatches them accordingly.