-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdetect-bytecode-features-OLDJEP181.pl
More file actions
executable file
·71 lines (59 loc) · 2.72 KB
/
detect-bytecode-features-OLDJEP181.pl
File metadata and controls
executable file
·71 lines (59 loc) · 2.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#!/usr/bin/perl
use strict;
use warnings;
my $currentClass;
my %has;
my $inFunction = 0;
my $initialDigitRegex = ''; # Will find both (as was the case originally)
if ($ARGV[0] eq '--first-digit-zero') {
$initialDigitRegex = '0'; # We think this indicates "forward direction" accesses (from inner class to outer class private method/member) that will become NestMembers in JDK >= 11
shift;
} elsif ($ARGV[0] eq '--first-digit-nonzero') {
$initialDigitRegex = '[1-9]'; # We think this indicates "reverse direction" accesses (from outer class to inner class) that will never change
shift;
}
print STDERR "Initial digit regex: <$initialDigitRegex>\n";
sub outputClass() {
print join("\t", $currentClass, sort grep { $has{$_} } keys %has), "\n";
}
sub getClassesInJar($) {
my ($jarFName) = @_;
my @classes = map { m|202\d-\d\d-\d\d \d\d:\d\d (.*)\.class$| ? $1 : () } `unzip -l "$jarFName"`; # Exclude '.class' from the end, since that's what javap wants with -cp jarfile.jar
}
my $jarFName;
my @classes = @ARGV;
if (@ARGV == 1) {
if ($ARGV[0] =~ /\.jar$/) {
# Jar mode
$jarFName = $ARGV[0];
@classes = getClassesInJar($ARGV[0]);
print STDERR "Using jar mode, found " . scalar(@classes) . " classes in $jarFName.\n";
}
}
open JAVAP, "-|", "javap", "-c", "-v", (defined $jarFName ? ("-cp", $jarFName) : ()), @classes or die; # Open a pipe from javap, passing all other command-line args to it
while (<JAVAP>) {
if (/^Classfile (.*)/) {
outputClass() if defined $currentClass;
my $newClass = $1;
while (@classes && $newClass !~ /\Q$classes[0]\E(?:\.class)?$/) {
print STDERR "Missing javap output for $classes[0] -- presumably it hit an error. Ignoring.\n";
shift @classes;
}
$currentClass = shift @classes;
%has = ();
$inFunction = 0;
} else {
# JDK >= 11 uses "nests" to allow inner classes to access private members of outer classes directly, instead of creating synthetic methods in the outer class: https://openjdk.org/jeps/181
# A positive detection (exit code 0) means the *old* (JDK < 11) behaviour, since this is easier to test for.
if (/^ ([^ ].*);$/ && $1 =~ /static .* access\$$initialDigitRegex[0-9]+\(/) {
$inFunction = 1;
} elsif (/^}?\s*$/) {
$inFunction = 0;
}
$has{JEP181} = 1 if $inFunction && /ACC_SYNTHETIC|Synthetic: true/;
# JDK >= 9 uses special invokedynamic calls to concatenate string literals instead of StringBuilder: https://openjdk.org/jeps/280, https://docs.oracle.com/javase/9/docs/api/java/lang/invoke/StringConcatFactory.html
# A positive detection (exit code 0) means the *new* (JDK >= 9) behaviour, since this is easier to test for.
$has{JEP280} = 1 if m!^ *#[0-9]+ = Class +#[0-9]+ +// java/lang/invoke/StringConcatFactory$!;
}
}
outputClass() if defined $currentClass;