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_disp32 = 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_rm, $store, $offset) = @_; |
28 |
|
29 |
if ($offset < -128 || $offset > 127) { |
30 |
$mod_rm |= $modrm_disp16; |
31 |
$offset = pack "V", $offset; |
32 |
} elsif ($offset) { |
33 |
$mod_rm |= $modrm_disp8; |
34 |
$offset = pack "c", $offset; |
35 |
} else { |
36 |
$offset = ""; |
37 |
} |
38 |
|
39 |
$insn[$store][$size] . (chr $mod_rm) . $offset |
40 |
}; |
41 |
|
42 |
my $gencopy = sub { |
43 |
my ($save) = shift; |
44 |
|
45 |
# all perl variables must be within 32-bits of this address |
46 |
my $curbase = $vars[$#vars >> 1][0]; |
47 |
|
48 |
my $code = "\x48\xbe" . pack "Q", $curbase; # mov imm64, %rsi |
49 |
|
50 |
my $curslot = 0; |
51 |
|
52 |
for (@vars) { |
53 |
my ($addr, $slot, $size) = @$_; |
54 |
|
55 |
my $slotofs = $slot - $curslot; |
56 |
|
57 |
# the sort ensures that this condition and adjustment suffices |
58 |
if ($slotofs > 127) { |
59 |
my $adj = 256; |
60 |
$code .= "\x48\x81\xc7" . pack "i", $adj; # add imm32, %rdi |
61 |
$curslot += $adj; |
62 |
$slotofs -= $adj; |
63 |
} |
64 |
|
65 |
if ($save) { |
66 |
$code .= $mov_ind->($size, $modrm_rsi, 0, $addr - $curbase); |
67 |
$code .= $mov_ind->($size, $modrm_rdi, 1, $slotofs); |
68 |
} else { |
69 |
$code .= $mov_ind->($size, $modrm_rdi, 0, $slotofs); |
70 |
$code .= $mov_ind->($size, $modrm_rsi, 1, $addr - $curbase); |
71 |
} |
72 |
} |
73 |
|
74 |
$code .= "\xc3"; # retq |
75 |
|
76 |
$code |
77 |
}; |
78 |
|
79 |
sub _jit { |
80 |
@vars = @_; |
81 |
|
82 |
# sort all variables into 256 byte blocks, biased by -128 |
83 |
# so gencopy can += 256 occasionally. within those blocks, |
84 |
# sort by address so we can play further tricks. |
85 |
@vars = sort { |
86 |
(($a->[1] + 128) & ~255) <=> (($b->[1] + 128) & ~255) |
87 |
or $a->[0] <=> $b->[0] |
88 |
} @vars; |
89 |
|
90 |
# we *could* combine adjacent vars, but this is not very common |
91 |
|
92 |
$vars[-1][0] - $vars[0][0] <= 0x7fffffff |
93 |
or die "JIT failed, perl var spread >31 bit\n"; |
94 |
|
95 |
my $load = $gencopy->(0); |
96 |
my $save = $gencopy->(1); |
97 |
|
98 |
#open my $fh, ">dat"; syswrite $fh, $save; system "objdump -b binary -m i386 -M x86-64 -D dat"; |
99 |
#warn length $load; |
100 |
#warn length $save; |
101 |
|
102 |
($load, $save) |
103 |
} |
104 |
} |
105 |
|
106 |
1 |