Skip to content

Commit 0b4960c

Browse files
committed
experimental support find-lambda flag
1 parent 6c4e633 commit 0b4960c

File tree

4 files changed

+60
-15
lines changed

4 files changed

+60
-15
lines changed

cmd/emc/main.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ func main() {
3838
threadCount := app.Flag("thread-count", "thread count").Default("250").Int64()
3939
javaOpts := app.Flag("java-options", "JVM Options").Envar("JAVA_OPTS").Default("").String()
4040
headRoom := app.Flag("head-room", "Percentage of total memory available which will be left unallocated to cover JVM overhead").Default("0").Int()
41+
findLambda := app.Flag("find-lambda", "find lambda").Default("false").Hidden().Bool() // experimental
4142
javaVersion := app.Flag("java-version", "Java version").Default("11").Int()
4243
jarOrDirectory := app.Arg("jarOrDirectory", "jar or directory").File()
4344
app.Action(func(c *kingpin.ParseContext) error {
@@ -65,7 +66,7 @@ func main() {
6566
if err != nil {
6667
return err
6768
}
68-
actualClassCount, err := emc.CountClassFile(j, fi)
69+
actualClassCount, err := emc.CountClassFile(j, fi, *findLambda)
6970
if err != nil {
7071
return err
7172
}

countclass.go

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@ import (
44
"archive/zip"
55
"bytes"
66
"fmt"
7+
"io"
78
"io/ioutil"
9+
810
"log"
911
"os"
1012
"strings"
1113

1214
"github.com/saracen/walker"
15+
classfileParser "github.com/wreulicke/go-java-class-parser/classfile"
1316
)
1417

1518
func CountClassInStandardLibrary(version int) int64 {
@@ -22,50 +25,63 @@ func CountClassInStandardLibrary(version int) int64 {
2225
return 30554 // OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.6+10, mixed mode)
2326
}
2427

25-
func CountClassFileInDir(dir *os.File) (int64, error) {
26-
var c int64 = 0
28+
func CountClassFileInDir(dir *os.File, findLambda bool) (int64, error) {
29+
var count int64 = 0
2730
walkfn := func(pathname string, fi os.FileInfo) error {
2831
if fi.IsDir() {
2932
return nil
3033
}
3134
if shouldCount(pathname) {
32-
c++
35+
log.Println("found", pathname)
36+
count++
37+
if findLambda && strings.HasPrefix(pathname, ".class") {
38+
c, err := countLambdaClass(os.Open(pathname))
39+
if err == nil {
40+
count += c
41+
}
42+
}
3343
return nil
3444
}
3545
f, err := os.Open(pathname)
3646
if err != nil {
3747
return err
3848
}
3949
defer f.Close()
40-
r, err := CountClassFile(f, fi)
50+
r, err := CountClassFile(f, fi, findLambda)
4151
if err == nil {
42-
c += r
52+
count += r
4353
}
4454
return nil
4555
}
4656
err := walker.Walk(dir.Name(), walkfn)
47-
return c, err
57+
return count, err
4858
}
4959

50-
func CountClassFile(file *os.File, fi os.FileInfo) (int64, error) {
60+
func CountClassFile(file *os.File, fi os.FileInfo, findLambda bool) (int64, error) {
5161
if fi.IsDir() {
52-
return CountClassFileInDir(file)
62+
return CountClassFileInDir(file, findLambda)
5363
} else if strings.HasSuffix(file.Name(), ".jar") || strings.HasSuffix(file.Name(), ".jmods") {
5464
z, err := zip.NewReader(file, fi.Size())
5565
if err != nil {
5666
return -1, fmt.Errorf("cannot create zip reader. file=%s err=%v", file.Name(), err)
5767
}
58-
return CountClassFileInJar(z, file.Name()+"!")
68+
return CountClassFileInJar(z, file.Name()+"!", findLambda)
5969
}
6070
return 0, fmt.Errorf("file is not directory or jar. file=%s", file.Name())
6171
}
6272

63-
func CountClassFileInJar(z *zip.Reader, pathPrefix string) (int64, error) {
73+
func CountClassFileInJar(z *zip.Reader, pathPrefix string, findLambda bool) (int64, error) {
6474
var count int64 = 0
6575
for _, f := range z.File {
6676
if shouldCount(f.Name) {
6777
log.Println("found", pathPrefix+f.Name)
6878
count++
79+
if findLambda && strings.HasPrefix(f.Name, ".class") {
80+
c, err := countLambdaClass(f.Open())
81+
if err == nil {
82+
count += c
83+
}
84+
}
6985
}
7086
if strings.HasSuffix(f.Name, ".jar") || strings.HasSuffix(f.Name, ".jmods") {
7187
r, err := f.Open()
@@ -80,7 +96,7 @@ func CountClassFileInJar(z *zip.Reader, pathPrefix string) (int64, error) {
8096
if err != nil {
8197
return -1, fmt.Errorf("cannot create zip reader %s err=%v", f.Name, err)
8298
}
83-
c, err := CountClassFileInJar(z, pathPrefix+f.Name+"!")
99+
c, err := CountClassFileInJar(z, pathPrefix+f.Name+"!", findLambda)
84100
if err != nil {
85101
return -1, err
86102
}
@@ -93,3 +109,31 @@ func CountClassFileInJar(z *zip.Reader, pathPrefix string) (int64, error) {
93109
func shouldCount(fileName string) bool {
94110
return strings.HasSuffix(fileName, ".class") || strings.HasSuffix(fileName, ".groovy")
95111
}
112+
113+
func countLambdaClass(r io.ReadCloser, err error) (int64, error) {
114+
if err != nil {
115+
return -1, err
116+
}
117+
defer r.Close()
118+
bs, err := ioutil.ReadAll(r)
119+
if err != nil {
120+
return -1, err
121+
}
122+
var count int64 = 0
123+
classFile := classfileParser.Parse(bs)
124+
for _, a := range classFile.Attributes() {
125+
if v, ok := a.(*classfileParser.BootstrapMethodsAttribute); ok {
126+
for _, m := range v.BootstrapMethods {
127+
className := m.ClassName()
128+
methodName, _ := m.NameAndDescriptor()
129+
if className == "java/lang/invoke/LambdaMetafactory" && methodName == "metafactory" {
130+
count++
131+
}
132+
}
133+
}
134+
}
135+
if count > 0 {
136+
log.Printf("found lambda %d", count)
137+
}
138+
return count, nil
139+
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ require (
77
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d
88
github.com/cloudfoundry/java-buildpack-memory-calculator v0.0.0-20190501234420-5148668b0710
99
github.com/saracen/walker v0.0.0-20191201085201-324a081bae7e
10-
golang.org/x/sys v0.0.0-20190410235845-0ad05ae3009d // indirect
10+
github.com/wreulicke/go-java-class-parser v0.0.0-20200210000755-ea0c5bba6606
1111
gopkg.in/alecthomas/kingpin.v2 v2.2.6
1212
)

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
3333
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
3434
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
3535
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
36+
github.com/wreulicke/go-java-class-parser v0.0.0-20200210000755-ea0c5bba6606 h1:Hk5USgnCYCxzejsEJx1qApWrgHkM/F/rUwQyZ+4dehA=
37+
github.com/wreulicke/go-java-class-parser v0.0.0-20200210000755-ea0c5bba6606/go.mod h1:rH+Ei3TGttVxPLRncqJW32rwlo9lKP9lYs8rw6JRAFE=
3638
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
3739
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
3840
golang.org/x/net v0.0.0-20181217023233-e147a9138326/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -47,8 +49,6 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h
4749
golang.org/x/sys v0.0.0-20181218192612-074acd46bca6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
4850
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
4951
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
50-
golang.org/x/sys v0.0.0-20190410235845-0ad05ae3009d h1:+9jagSGtlJZAaZGdRvJikXNpc5lh2/rq9eyMN/5kmwA=
51-
golang.org/x/sys v0.0.0-20190410235845-0ad05ae3009d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
5252
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
5353
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
5454
golang.org/x/tools v0.0.0-20191011211836-4c025a95b26e h1:1o2bDs9pCd2xFhdwqJTrCIswAeEsn4h/PCNelWpfcsI=

0 commit comments

Comments
 (0)