• 沒有找到結果。

Local Variable

Step 2: Sort the edges of the access gr

descending order) into set E;

ick up the edge e in E with th

If adding the edge e to P (i) does not form a cycle in P , and (ii) does not increase the degree of any node in P to more than 2, then it is included in P .

Repeat Steps 2 a

a

re 3-7.An Path Cover Obtained Largest-Weight-First Algo b

According to the JVM specification [9], some local variables can not be relocated, such as “this pointer” at local variable 0 or parameters, which must be placed in consecutive addresses start from local variable 0 or after “this pointer”.

To deal with that, the initialization step in the “Largest Weight First” algorithm must be modified: while deciding the layout of local variables, these variables that can not be relocated are connected into a path according to their predetermined placement sequence and we put it in the path cover P at the step one. The rest of the algorithm is remained to build up the path cover.

The process of local variable relocation is also influenced by whether the register allocator of the JIT compiler is designed to allocate right register numbers and to eliminate the name dependences for consecutive variable accesses. If the register allocator will try to eliminate the name dependences between the consecutive variable accesses and other instructions, it is assumed the all the name dependences are removed and only the true dependences remain during the instruction group construction in the first phase. If results of the register allocation are independent to the locations of variables, we use the directed edge to represent the register number order between grouped local variable access instructions during the access graph construction in phase two. In addition, the weight calculation is also slightly modified to takes the register number constraint into account.

3.4 Modification of Register Allocator

The goal of modifying register allocator is to make more load/store instructions replaceable by making the order of register numbers right and avoiding name-dependences to. We use a simple example in Figure 3-8 to explain how to achieve this goal.

A dependence graph of a basic block in JIT compiled code is showed in Figure 3-8. These instructions can be divided into two groups: the consecutive address access instructions and the other instructions, as the dotted lines separated.

The consecutive address accesses are grouping candidates that might be replaced by LDM/STM later.

To make the order of register numbers right, we can simply allocating ascending register numbers for consecutive address accesses that sorted in ascending order.

However, some dependences between the consecutive address accesses and other instructions still make some loads/stores non-replaceable. For example, the name dependence between “ADD” and “LD mem[n+1]” in Figure3-8 making the

“LD mem[n]” and “LD mem[n+1]” dependent and non-groupable. To avoid that,

Inst.

Use other registers as destination register rather than Ri, Rj, Rk

LD mem[n] LD mem[n+1] LD mem[n+2]

ADD

Figure 3-8.A Dependence Graph of a Basic Block in JIT Compiled Code

we can allocate other registers for other instructions as destination registers rather then those allocated for consecutive address accesses.

The scope of register allocation in the JIT compiler of our embedded mixed-mode JVM is extended basic block, which is code sequence with a unique entry point and possibly many exits points. The original register is two-pass register tracking, similar to the register allocator in [14]. The first pass is live-ness analysis; the second pass is sequentially allocating registers and generating instructions for each IR.

Modified register allocator is still a 2-pass scheme. The first pass is modified to find out consecutive address accesses within basic block along with the live-ness analysis and generate hints (preserved register and address pairs) for them. The register allocation in second pass would be guided by these hints later.

A simple example of hint generation in first pass is illustrated in Figure 3-9.

First, we scan through the IR of EBB and log the read/written addresses for each basic block. If there are consecutive addresses to be read/written within a basic block, we preserve ascending register numbers for loading/storing these memory addresses as hints to register allocator.

:Top of stack

Local variable array Operand Stack

Bytecode IR

Preserved register for Load:

Preserved register for Store:

Access log:

Hints for register allocator

Figure 3-9. An Example of Hint Generation

The register allocation in second pass is also modified to follow the hint. The modified register allocation policy described as below.

The modified allocation policy follows the hints in conservative way: if the preserved register is occupied at step 1, we do not spill that register but try to find another available one to allocate. The reason of the conservatism is that the overhead of the extra register spill is usually greater then the benefits of replacing more load/store by LDM/STM. Although the conservative policy might tend to failed to follow hints at step 1 (because the preserved register for m is occupied) when register pressure is high, but we found that the register pressure is rarely get high in JIT compiled code since the size of EBB is usually small.

When spilling register, the register with the lowest spill cost, which represents the estimated number of extra instructions to be generated because of the register spilling, is chosen to spill in the original policy. The modified policy still use the original metric to choose the register, but if both non-preserved and preserved register are chosen, spill the non-preserved first to avoid the name dependences

Allocation policy

When allocating register for memory address m:

相關文件