1 |
#!/opt/bin/perl |
2 |
|
3 |
{ |
4 |
package Coro::State; |
5 |
|
6 |
use common::sense; |
7 |
|
8 |
my @insn; |
9 |
|
10 |
$insn[0][1] = "\x0f\xb6"; # movzbl mem -> rax |
11 |
$insn[0][2] = "\x0f\xb7"; # movzwl mem -> rax |
12 |
$insn[0][4] = "\x8b"; # movl mem -> rax |
13 |
$insn[0][8] = "\x48\x8b"; # movq mem -> rax |
14 |
$insn[1][1] = "\x88"; # movb rax -> mem |
15 |
$insn[1][2] = "\x66\x89"; # movw rax -> mem |
16 |
$insn[1][4] = "\x89"; # movl rax -> mem |
17 |
$insn[1][8] = "\x48\x89"; # movq rax -> mem |
18 |
|
19 |
my $modrm_disp8 = 0x40; |
20 |
my $modrm_disp16 = 0x80; |
21 |
my $modrm_rsi = 0x06; |
22 |
my $modrm_rdi = 0x07; |
23 |
|
24 |
my @vars; |
25 |
|
26 |
my $mov_ind = sub { |
27 |
my ($size, $mod_reg, $store, $offset) = @_; |
28 |
|
29 |
my $mod_rm = $mod_reg; |
30 |
|
31 |
if ($offset < -128 || $offset > 127) { |
32 |
$mod_rm |= $modrm_disp16; |
33 |
$offset = pack "V", $offset; |
34 |
} elsif ($offset) { |
35 |
$mod_rm |= $modrm_disp8; |
36 |
$offset = pack "c", $offset; |
37 |
} else { |
38 |
$offset = ""; |
39 |
} |
40 |
|
41 |
$insn[$store][$size] . (chr $mod_rm) . $offset |
42 |
}; |
43 |
|
44 |
my $gencopy = sub { |
45 |
my ($save) = shift; |
46 |
|
47 |
# all perl variables must be within 32-bits of this address |
48 |
my $curbase = $vars[$#vars >> 1][0]; |
49 |
|
50 |
my $code = "\x48\xbe" . pack "Q", $curbase; # mov imm64, %rsi |
51 |
|
52 |
my $curslot = 0; |
53 |
|
54 |
for (@vars) { |
55 |
my ($addr, $slot, $size) = @$_; |
56 |
|
57 |
my $slotofs = $slot - $curslot; |
58 |
|
59 |
# the sort ensures that this condition and adjustment suffice |
60 |
if ($slotofs > 127) { |
61 |
my $adj = 256; |
62 |
$code .= "\x48\x81\xc7" . pack "i", $adj; # add imm32, %rdi |
63 |
$curslot += $adj; |
64 |
$slotofs -= $adj; |
65 |
} |
66 |
|
67 |
if ($save) { |
68 |
$code .= $mov_ind->($size, $modrm_rsi, 0, $addr - $curbase); |
69 |
$code .= $mov_ind->($size, $modrm_rdi, 1, $slotofs); |
70 |
} else { |
71 |
$code .= $mov_ind->($size, $modrm_rdi, 0, $slotofs); |
72 |
$code .= $mov_ind->($size, $modrm_rsi, 1, $addr - $curbase); |
73 |
} |
74 |
} |
75 |
|
76 |
$code .= "\xc3"; # retq |
77 |
|
78 |
$code |
79 |
}; |
80 |
|
81 |
sub _jit { |
82 |
@vars = @_; |
83 |
|
84 |
# sort all variables into 256 byte blocks, biased by -128 |
85 |
# so gencopy can += 256 occasionally. within those blocks, |
86 |
# sort by address so we can play further tricks. |
87 |
@vars = sort { |
88 |
(($a->[1] + 128) & ~255) <=> (($b->[1] + 128) & ~255) |
89 |
or $a->[0] <=> $b->[0] |
90 |
} @vars; |
91 |
|
92 |
# we *could* combine adjacent vars, but this is not very common |
93 |
|
94 |
$vars[-1][0] - $vars[0][0] <= 0x7fffffff |
95 |
or die "JIT failed, perl var spread >31 bit\n"; |
96 |
|
97 |
my $load = $gencopy->(0); |
98 |
my $save = $gencopy->(1); |
99 |
|
100 |
#open my $fh, ">dat"; syswrite $fh, $save; system "objdump -b binary -m i386 -M x86-64 -D dat"; |
101 |
#warn length $load; |
102 |
#warn length $save; |
103 |
|
104 |
($load, $save) |
105 |
} |
106 |
} |
107 |
|
108 |
1 |