├── .gitignore
├── .travis.yml
├── LICENSE
├── LICENSE.md
├── README.md
├── deployment
├── deploy.sh
├── settings.xml
└── signingkey.asc.enc
├── pom.xml
├── vmvm-ant-junit-formatter
├── .gitignore
├── pom.xml
└── src
│ └── main
│ └── java
│ └── edu
│ └── columbia
│ └── cs
│ └── psl
│ └── vmvm
│ ├── AntJUnitTestListener.java
│ ├── MvnReportingListener.java
│ ├── MvnVMVMListener.java
│ └── TestReportingListener.java
├── vmvm-internal-static-detector
├── bin
│ └── log4j.properties
├── lib
│ ├── asm-all-4.0.jar
│ ├── asm-src.zip
│ └── log4j-1.2.16.jar
├── pom.xml
├── src
│ └── main
│ │ ├── java
│ │ └── edu
│ │ │ └── columbia
│ │ │ └── cs
│ │ │ └── psl
│ │ │ └── vmvm
│ │ │ └── util
│ │ │ └── StaticPutDetector.java
│ │ └── resources
│ │ └── log4j.properties
├── static-mod
└── vmvm-internal-static-detector.iml
└── vmvm
├── .gitignore
├── pom.xml
└── src
├── main
├── java
│ ├── edu
│ │ └── columbia
│ │ │ └── cs
│ │ │ └── psl
│ │ │ └── vmvm
│ │ │ └── runtime
│ │ │ ├── AdditionalInterfaceClassloader.java
│ │ │ ├── ConsumerUtils.java
│ │ │ ├── FieldReflectionWrapper.java
│ │ │ ├── Instrumenter.java
│ │ │ ├── JUnitInterceptingClassVisitor.java
│ │ │ ├── PreMain.java
│ │ │ ├── VMVMClassFileTransformer.java
│ │ │ └── inst
│ │ │ ├── ClassReinitCV.java
│ │ │ ├── Constants.java
│ │ │ ├── LabelRemappingMV.java
│ │ │ ├── PlaceholderClasswriter.java
│ │ │ ├── PutStaticHelperMV.java
│ │ │ ├── ReflectionFixingCV.java
│ │ │ ├── ReflectionFixingMV.java
│ │ │ ├── ReinitCheckForceMV.java
│ │ │ ├── SystemPropertyLogger.java
│ │ │ └── Utils.java
│ └── java
│ │ └── edu
│ │ └── columbia
│ │ └── cs
│ │ └── psl
│ │ └── vmvm
│ │ └── runtime
│ │ ├── InterfaceReinitializer.java
│ │ ├── MutableInstance.java
│ │ ├── ReflectionWrapper.java
│ │ ├── Reinitializer.java
│ │ └── VMVMInstrumented.java
└── resources
│ └── java
│ └── edu
│ └── columbia
│ └── cs
│ └── psl
│ └── vmvm
│ └── runtime
│ ├── ignored-clinits
│ └── internal-statics
└── test
└── java
└── edu
└── columbia
└── cs
└── psl
├── test
└── vmvm
│ ├── EnumITCase.java
│ ├── EvilInterface.java
│ ├── InternalStaticITCase.java
│ ├── OtherClass.java
│ ├── OtherOtherClass.java
│ ├── ReflectionITCase.java
│ ├── ReinitializerITCase.java
│ ├── SystemPropertiesITCase.java
│ └── classes
│ ├── ClassWithNoInterfaces.java
│ ├── ClassWithOneSField.java
│ ├── EEnum.java
│ ├── Foo.java
│ ├── IFace.java
│ ├── LaterClass.java
│ ├── SubClassWithAnotherSField.java
│ └── TryCatchInInitClass.java
└── vmvm
└── testsupport
└── FieldGetter.java
/.gitignore:
--------------------------------------------------------------------------------
1 | framework/bin
2 | exp
3 | *.class
4 | *.log
5 | /bin
6 | experiments/
7 | **/target
8 |
9 | # Eclipse files
10 | **/.settings/
11 | **/.project
12 | **/.classpath
13 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | sudo: false
3 | jdk: oraclejdk8
4 | script: mvn verify
5 | deploy:
6 | provider: script
7 | skip_cleanup: true
8 | script: cd $TRAVIS_BUILD_DIR; bash deployment/deploy.sh
9 | on:
10 | branch: master
11 | env:
12 | global:
13 | - secure: jKeinjZsevIWoUvHDrgDE4gfkQR6Z4rB5vIF0QQEltWcWOHZXLGhxE7ecy6/ff1Z5gzZtCTeneLsthkzqrbzm8FzVAhbYJ9WwpENz0spVVyjnHUU7W72tI5AKlLNTonJDJOogENhT95ivgZ3/cAPMYw1qnDKCNfdBwfT3Il39UY=
14 | - secure: G4admxhpOLcuQ6kpUtMNW44VPkg01/Emb4geuZQ7fnHuMJ/G1bkRemtP1/7eLeoBNjTWAATKWt9uHdv9PwsqvoYVxndstxZ6lhjdaPL4KHvxbfhnckm+h4ZBMHH1li8pDX6T0GB1uH/SAx/ML/v3w5+XKZfqtsYS1EPRt0ylQbM=
15 | - secure: TGMDGOLnCg1X04Binmg9QSPxdjo77iwJN3A1qfCAPa+uM6IaYHoIUBXZr8z9nX6gDaVPxmjErlpByDYMt/Uh8sNEY8+L85PAF1L4Fg94GO5edWgYUUGMvwcqAIwVwvZZSteXqJpUaWAlVC1lxUn7AsiJ+wdonGHREzO++SxeZYo=
16 | before_install:
17 | - openssl aes-256-cbc -K $encrypted_df4dabc64bbd_key -iv $encrypted_df4dabc64bbd_iv
18 | -in deployment/signingkey.asc.enc -out deployment/signingkey.asc -d
19 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Programming-Systems-Lab/vmvm/07a36dc21373147c50ceacd7bff2b2e7a86c8780/LICENSE
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | This software is released under the MIT license:
2 |
3 | Copyright © 2013, by The Trustees of Columbia University in the City of New York.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
11 |
12 |
13 | This project makes use of the following libraries:
14 | * [ASM](http://asm.ow2.org/license.html), (c) 2000-2011 INRIA, France Telecom, [license](http://asm.ow2.org/license.html)
15 | * [Log4j](http://logging.apache.org/log4j/), (c) 1999-2012, Apache Software Foundation, released under the Apache License 2.0
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #VMVM - Unit Test Virtualization for Java [](https://travis-ci.org/Programming-Systems-Lab/vmvm)
2 | ==========
3 | **VMVM** is a system for isolating unit tests with very low overhead.
4 |
5 | This repository contains the source and a [runnable binary](http://jonbell.net/vmvm/vmvm.jar) for **VMVM**.
6 |
7 |
8 | ###For more information
9 | Please refer to our [ICSE '14 Paper](http://jonbell.net/publications/vmvm) or email [Jonathan Bell](mailto:jbell@cs.columbia.edu). Note that this new version of VMVM (VMVM 2) is somewhat different in architecture than described in our publication: we have removed the need for the pre-instrumentation phase, which makes using it in practice significantly easier. VMVM 2 requires you to use a Java 8 JRE (or newer) when running tests (but is compatible with older code).
10 |
11 | Running
12 | -----
13 |
14 | ### Modifying your build scripts
15 | To automatically have VMVM be called by ant, modify the `junit` task of your `build.xml` file to add the following elements:
16 |
17 | ```xml
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | ```
26 |
27 | Make sure that the paths are correct to [vmvm.jar](http://jonbell.net/vmvm/vmvm.jar) and [ant-mvn-formatter.jar](http://jonbell.net/vmvm/ant-mvn-formatter.jar). Also be sure that your `junit` task has the argument `forkMode="once"` (e.g. that it won't fork a new process for each test, defating the purpose of VMVM).
28 |
29 | That's it.
30 |
31 | To automatically have VMVM be called by mvn, modify the `pom.xml` file for your project as follows:
32 |
33 | 1. Make sure that you are using a recent version of the surefire plugin (e.g., 2.15)
34 | 2. Declare the VMVM dependencies:
35 |
36 | ```xml
37 |
38 | edu.columbia.cs.psl.vmvm
39 | vmvm
40 | 1.0.0-SNAPSHOT
41 | test
42 |
43 |
44 | edu.columbia.cs.psl.vmvm
45 | vmvm-ant-junit-formatter
46 | 1.0.0-SNAPSHOT
47 | test
48 |
49 | ```
50 |
51 | 3. Register the VMVM test listener with surefire. If you don't have any other properties set for the surefire plugin, then that would look like this:
52 |
53 | ```xml
54 |
55 | -Xbootclasspath/p:vmvm.jar -javaagent:vmvm.jar
56 |
57 |
58 | listener
59 | edu.columbia.cs.psl.vmvm.MvnVMVMListener
60 |
61 |
62 |
63 | ```
64 |
65 | Here's an example of a mininal `pom.xml` block declaring the Maven Surefire plugin using the VMVM with it:
66 |
67 | ```xml
68 |
69 | org.apache.maven.plugins
70 | maven-surefire-plugin
71 | 2.18.1
72 |
73 | -Xbootclasspath/p:vmvm.jar -javaagent:vmvm.jar
74 |
75 |
76 | listener
77 | edu.columbia.cs.psl.vmvm.MvnVMVMListener
78 |
79 |
80 |
81 |
82 | ```
83 |
84 | Citing
85 | -----
86 | If you would like to reference VMVM in an academic publication, please cite our ICSE '14 publication:
87 | ```
88 |
89 | @inproceedings{vmvm,
90 | Title = {Unit Test Virtualization with VMVM},
91 | Author = {\textbf{Bell, Jonathan} and Kaiser, Gail},
92 | Booktitle = {Proceedings of the 2014 International Conference on Software Engineering},
93 | Location = {Hyderabad, India},
94 | Month = {Jun},
95 | Publisher = {IEEE Press},
96 | Series = {ICSE 2014},
97 | Url = {http://jonbell.net/publications/vmvm},
98 | Year = {2014}
99 | }
100 | ```
101 |
102 |
103 | In case of problems..
104 | -----
105 | We have verified that VMVM works with the following applications. If you notice any incompatibilities with it, please email [Jonathan Bell](mailto:jbell@cs.columbia.edu), (or, fix the bug yourself and send a patch :P).
106 |
107 | Applications that we have tested with VMVM (and are known to work):
108 | * [Apache Ivy](http://ant.apache.org/ivy/)
109 | * [Apache Nutch](http://nutch.apache.org/)
110 | * [Apache River](http://river.apache.org/)
111 | * [Apache Tomcat](http://tomcat.apache.org/)
112 | * [betterFORM](http://www.betterform.de/en/index.html)
113 | * [Bristlecone](http://www.ohloh.net/p/bristlecone)
114 | * [btrace](https://kenai.com/projects/btrace)
115 | * [Closure Compiler](http://commons.apache.org/proper/commons-jci/)
116 | * [Commons Codec](http://commons.apache.org/proper/commons-codec/)
117 | * [Commons IO](http://commons.apache.org/proper/commons-io/)
118 | * [Commons Validator](http://commons.apache.org/proper/commons-validator/)
119 | * [FreeRapid Downloader](http://wordrider.net/freerapid/)
120 | * [gedcom4j](http://gedcom4j.org/main/)
121 | * [JAXX](http://nuiton.org/projects/jaxx)
122 | * [Jetty](http://www.eclipse.org/jetty/jtor* )
123 | * [JTor](https://github.com/brl/JTor)
124 | * [mkgmap](http://wiki.openstreetmap.org/wiki/Mkgmap)
125 | * [Openfire](http://www.igniterealtime.org/projects/openfire/)
126 | * [Trove, for Java](http://trove.starlight-systems.com/)
127 | * [Universal Password Mananager (UPM)](http://upm.sourceforge.net/)
128 |
129 | License
130 | ------
131 | This software is released under the MIT license.
132 |
133 | Copyright (c) 2013, by The Trustees of Columbia University in the City of New York.
134 |
135 | Permission is hereby granted, free of charge, to any person obtaining
136 | a copy of this software and associated documentation files (the
137 | "Software"), to deal in the Software without restriction, including
138 | without limitation the rights to use, copy, modify, merge, publish,
139 | distribute, sublicense, and/or sell copies of the Software, and to
140 | permit persons to whom the Software is furnished to do so, subject to
141 | the following conditions:
142 |
143 | The above copyright notice and this permission notice shall be
144 | included in all copies or substantial portions of the Software.
145 |
146 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
147 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
148 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
149 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
150 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
151 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
152 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
153 |
154 |
155 | Acknowledgements
156 | -----
157 | This project makes use of the following libraries:
158 | * [ASM](http://asm.ow2.org/license.html), (c) 2000-2011 INRIA, France Telecom, [license](http://asm.ow2.org/license.html)
159 | * [Log4j](http://logging.apache.org/log4j/), (c) 1999-2012, Apache Software Foundation, released under the Apache License 2.0
160 |
161 | The authors of this software are [Jonathan Bell](http://jonbell.net) and [Gail Kaiser](http://www.cs.columbia.edu/~kaiser/). The authors are members of the [Programming Systems Laboratory](http://www.psl.cs.columbia.edu/), funded in part by NSF CCF-1161079, NSF CNS-0905246, and NIH U54 CA121852.
162 |
163 | [](http://githalytics.com/Programming-Systems-Lab/vmvm)
164 |
--------------------------------------------------------------------------------
/deployment/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | gpg2 --keyring=$TRAVIS_BUILD_DIR/pubring.gpg --no-default-keyring --import $TRAVIS_BUILD_DIR/deployment/signingkey.asc;
4 | gpg2 --allow-secret-key-import --keyring=$TRAVIS_BUILD_DIR/secring.gpg --no-default-keyring --import $TRAVIS_BUILD_DIR/deployment/signingkey.asc;
5 | cd $TRAVIS_BUILD_DIR;
6 | mvn -DskipTests deploy --settings $TRAVIS_BUILD_DIR/deployment/settings.xml -Dgpg.executable=gpg2 -Dgpg.keyname=77787D71ED65A50488D41B82E876C482DFB8D3EB -Dgpg.passphrase=$PASSPHRASE -Dgpg.publicKeyring=$TRAVIS_BUILD_DIR/pubring.gpg -Dgpg.secretKeyring=$TRAVIS_BUILD_DIR/secring.gpg
7 |
--------------------------------------------------------------------------------
/deployment/settings.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 | ossrh
7 | ${env.SONATYPE_USERNAME}
8 | ${env.SONATYPE_PASSWORD}
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/deployment/signingkey.asc.enc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Programming-Systems-Lab/vmvm/07a36dc21373147c50ceacd7bff2b2e7a86c8780/deployment/signingkey.asc.enc
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | 4.0.0
6 | edu.gmu.swe.vmvm
7 | vmvm-base-pom
8 | ${project.groupId}::${project.artifactId}
9 | 2.0.0-SNAPSHOT
10 | pom
11 |
12 |
13 | Unit Test Virtualization for Java(tm)
14 |
15 |
16 |
17 |
18 | MIT license
19 | http://opensource.org/licenses/MIT
20 | repo
21 |
22 |
23 |
24 |
25 | scm:git:git://github.com/Programming-Systems-Lab/vmvm.git
26 | scm:git:git@github.com:Programming-Systems-Lab/vmvm.git
27 | https://github.com/Programming-Systems-Lab/vmvm
28 |
29 |
30 |
31 | UTF-8
32 | UTF-8
33 | 1.7
34 | ${java.source.version}
35 | 150
36 |
37 | ${project.basedir}/LICENSE.md
38 | 4.11
39 | 1.7.0
40 | 1.9.4
41 | 5.1.34
42 | 1.2.16
43 | 4.0
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | edu.gmu.swe.vmvm
53 | vmvm
54 | ${project.version}
55 |
56 |
57 |
58 | edu.gmu.swe.vmvm
59 | vmvm-ant-junit-formatter
60 | ${project.version}
61 |
62 |
63 |
64 | edu.gmu.swe.vmvm
65 | vmvm-internal-static-detector
66 | ${project.version}
67 |
68 |
69 |
70 |
71 | junit
72 | junit
73 | ${junit.version}
74 |
75 |
76 |
77 | ant
78 | ant
79 | ${ant.version}
80 |
81 |
82 |
83 | org.apache.ant
84 | ant-junit
85 | ${ant.junit.version}
86 |
87 |
88 |
89 | mysql
90 | mysql-connector-java
91 | ${mysql.connector.java.version}
92 |
93 |
94 |
95 | log4j
96 | log4j
97 | ${log4j.version}
98 |
99 |
100 |
101 | org.ow2.asm
102 | asm-all
103 | ${asm.all.version}
104 |
105 |
106 |
107 |
108 |
109 |
110 | vmvm
111 | vmvm-ant-junit-formatter
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 | org.apache.maven.plugins
121 | maven-jar-plugin
122 | 2.6
123 |
124 |
125 |
126 | true
127 | true
128 | true
129 |
130 |
131 |
132 |
133 |
134 | jar
135 |
136 | jar
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 | org.apache.maven.plugins
147 | maven-resources-plugin
148 | 2.7
149 | true
150 |
151 | ${project.build.sourceEncoding}
152 |
153 |
154 |
155 |
156 | org.apache.maven.plugins
157 | maven-compiler-plugin
158 | 3.2
159 | true
160 |
161 | ${project.build.sourceEncoding}
162 | ${java.source.version}
163 | ${java.target.version}
164 | true
165 | true
166 | ${java.source.line.length}
167 | false
168 | true
169 | -Xlint:all
170 |
171 |
172 |
173 |
174 | org.apache.maven.plugins
175 | maven-jar-plugin
176 | true
177 |
178 |
179 |
180 | true
181 | true
182 | true
183 |
184 |
185 |
186 |
187 |
188 | jar
189 |
190 | jar
191 |
192 |
193 |
194 |
195 |
196 |
197 | org.apache.maven.plugins
198 | maven-source-plugin
199 | 2.4
200 | true
201 |
202 |
203 | attach-sources
204 | verify
205 |
206 | jar-no-fork
207 |
208 |
209 |
210 |
211 |
212 |
213 | org.apache.maven.plugins
214 | maven-javadoc-plugin
215 | 2.10.2
216 | true
217 |
218 |
219 | attach-sources
220 | verify
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 | release-sign-artifacts
229 |
230 |
231 | gpg.passphrase
232 |
233 |
234 |
235 |
236 |
237 | org.apache.maven.plugins
238 | maven-gpg-plugin
239 | 1.4
240 |
241 |
242 | sign-artifacts
243 | verify
244 |
245 | sign
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 | ossrh
257 | https://oss.sonatype.org/content/repositories/snapshots
258 |
259 |
260 | ossrh
261 | https://oss.sonatype.org/service/local/staging/deploy/maven2/
262 |
263 |
264 |
265 |
266 |
--------------------------------------------------------------------------------
/vmvm-ant-junit-formatter/.gitignore:
--------------------------------------------------------------------------------
1 | /bin
2 |
--------------------------------------------------------------------------------
/vmvm-ant-junit-formatter/pom.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 | edu.gmu.swe.vmvm
6 | vmvm-base-pom
7 | 2.0.0-SNAPSHOT
8 |
9 |
10 | 4.0.0
11 | vmvm-ant-junit-formatter
12 | jar
13 | ${project.groupId}::${project.artifactId}
14 |
15 |
16 | ${project.basedir}/../LICENSE.md
17 |
18 |
19 |
20 |
21 |
22 | ${project.groupId}
23 | vmvm
24 |
25 |
26 |
27 | junit
28 | junit
29 |
30 |
31 |
32 | ant
33 | ant
34 |
35 |
36 |
37 | org.apache.ant
38 | ant-junit
39 |
40 |
41 |
42 | mysql
43 | mysql-connector-java
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/vmvm-ant-junit-formatter/src/main/java/edu/columbia/cs/psl/vmvm/AntJUnitTestListener.java:
--------------------------------------------------------------------------------
1 | package edu.columbia.cs.psl.vmvm;
2 |
3 | import java.io.OutputStream;
4 |
5 | import junit.framework.AssertionFailedError;
6 | import junit.framework.Test;
7 |
8 | import org.apache.tools.ant.BuildException;
9 | import org.apache.tools.ant.taskdefs.optional.junit.JUnitResultFormatter;
10 | import org.apache.tools.ant.taskdefs.optional.junit.JUnitTest;
11 |
12 | import java.edu.columbia.cs.psl.vmvm.runtime.Reinitializer;
13 |
14 | public class AntJUnitTestListener implements JUnitResultFormatter {
15 |
16 | @Override
17 | public void endTestSuite(JUnitTest arg0) throws BuildException {
18 | Reinitializer.markAllClassesForReinit();
19 | }
20 |
21 | @Override
22 | public void setOutput(OutputStream arg0) {
23 | // TODO Auto-generated method stub
24 |
25 | }
26 |
27 | @Override
28 | public void setSystemError(String arg0) {
29 | // TODO Auto-generated method stub
30 |
31 | }
32 |
33 | @Override
34 | public void setSystemOutput(String arg0) {
35 | // TODO Auto-generated method stub
36 |
37 | }
38 |
39 | @Override
40 | public void startTestSuite(JUnitTest arg0) throws BuildException {
41 | }
42 |
43 | @Override
44 | public void addError(Test arg0, Throwable arg1) {
45 | // TODO Auto-generated method stub
46 |
47 | }
48 |
49 | @Override
50 | public void addFailure(Test arg0, AssertionFailedError arg1) {
51 | // TODO Auto-generated method stub
52 |
53 | }
54 |
55 | @Override
56 | public void endTest(Test arg0) {
57 | // TODO Auto-generated method stub
58 | }
59 |
60 | @Override
61 | public void startTest(Test arg0) {
62 | // TODO Auto-generated method stub
63 |
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/vmvm-ant-junit-formatter/src/main/java/edu/columbia/cs/psl/vmvm/MvnReportingListener.java:
--------------------------------------------------------------------------------
1 | package edu.columbia.cs.psl.vmvm;
2 |
3 | import java.io.File;
4 | import java.io.FileNotFoundException;
5 | import java.sql.Connection;
6 | import java.sql.DriverManager;
7 | import java.sql.PreparedStatement;
8 | import java.sql.SQLException;
9 | import java.util.Arrays;
10 | import java.util.Scanner;
11 |
12 | import org.junit.runner.Description;
13 | import org.junit.runner.Result;
14 | import org.junit.runner.notification.Failure;
15 | import org.junit.runner.notification.RunListener;
16 |
17 | import edu.columbia.cs.psl.vmvm.TestReportingListener.TestResult;
18 |
19 | public class MvnReportingListener extends RunListener {
20 | static final Connection db = getConnection();
21 | static int testID;
22 | static {
23 | try {
24 | testID = Integer.valueOf(System.getProperty("vmvm.study.testID"));
25 | } catch (NumberFormatException ex) {
26 | Scanner s;
27 | try {
28 | s = new Scanner(new File("vmvm.study.testID"));
29 | testID = s.nextInt();
30 | s.close();
31 | } catch (FileNotFoundException e) {
32 | throw new IllegalStateException("No test id set!", e);
33 | }
34 |
35 | }
36 | Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
37 |
38 | @Override
39 | public void run() {
40 | try {
41 | db.close();
42 | } catch (SQLException e) {
43 | // TODO Auto-generated catch block
44 | e.printStackTrace();
45 | }
46 | }
47 | }));
48 | }
49 |
50 | static Connection getConnection() {
51 | try {
52 | Class.forName("com.mysql.jdbc.Driver");
53 | return DriverManager.getConnection("jdbc:mysql://127.0.0.1/foss?user=foss&password=f055");
54 | } catch (Exception ex) {
55 | ex.printStackTrace();
56 | }
57 | return null;
58 | }
59 |
60 | private String getClassName(Description desc)
61 | {
62 | if(desc == null)
63 | return "null";
64 | if(desc.getClassName() == null)
65 | return desc.getTestClass().getName();
66 | else
67 | return desc.getClassName();
68 | }
69 | int nFailures;
70 | String lastTestClass = null;
71 | @Override
72 | public void testRunStarted(Description description) throws Exception {
73 | if (!getClassName(description).equals(lastTestClass)) {
74 | //we are doing another test class
75 | if (res != null)
76 | finishedClass();
77 | res = new TestResult(getClassName(description));
78 | lastTestClass = getClassName(description);
79 | if(description.getChildren() != null && description.getChildren().size() == 1)
80 | {
81 | Description child = description.getChildren().get(0);
82 | long time = Long.valueOf(child.getDisplayName());
83 | res.startTime = time;
84 | }
85 | }
86 | }
87 | /**
88 | * Called when an atomic test is about to be started.
89 | * */
90 | public void testStarted(Description description) throws java.lang.Exception {
91 | if (!getClassName(description).equals(lastTestClass)) {
92 | //we are doing another test class
93 | if (res != null)
94 | finishedClass();
95 | res = new TestResult(getClassName(description));
96 | lastTestClass = getClassName(description);
97 | }
98 | if(res.startTime == 0 && description.getChildren() != null && description.getChildren().size() == 1)
99 | {
100 | Description child = description.getChildren().get(0);
101 | long time = Long.valueOf(child.getDisplayName());
102 | res.startTime = time;
103 |
104 | }
105 | res.nMethods++;
106 | }
107 |
108 | @Override
109 | public void testFinished(Description description) throws Exception {
110 | res.stdout.append(description.getDisplayName() + "Finished\n");
111 | if(description.getChildren() != null && description.getChildren().size() == 1)
112 | {
113 | Description child = description.getChildren().get(0);
114 | long time = Long.valueOf(child.getDisplayName());
115 | res.finished = time;
116 | }
117 | }
118 |
119 | int nErrors;
120 |
121 | String lastFinishedClass = null;
122 | @Override
123 | public void testRunFinished(Result result) throws Exception {
124 |
125 | nFailures = result.getFailureCount();
126 | if(!lastTestClass.equals(lastFinishedClass))
127 | finishedClass();
128 | lastFinishedClass = lastTestClass;
129 | }
130 |
131 | private void finishedClass() {
132 | if(res.reported)
133 | return;
134 | res.reported = true;
135 | if(res.finished == 0)
136 | res.finished = System.currentTimeMillis();
137 | if(res.startTime == 0 && res.nMethods == 0)
138 | res.startTime = res.finished;
139 | try {
140 | PreparedStatement ps = db.prepareStatement("INSERT INTO test_result_test (test_execution_id,test,time,output,success,nTestMethods,start,end,nFailures) VALUES (?,?,?,?,?,?,?,?,?)");
141 | ps.setInt(1, testID);
142 | ps.setString(2, res.name);
143 | ps.setLong(3, (int) (res.finished - res.startTime));
144 | ps.setString(4, "Stdout:\n" + res.stdout.toString() + "\n\nStderr:\n" + res.stderr.toString());
145 | ps.setInt(5, nFailures > 0 ? 0 : 1);
146 | ps.setInt(6, res.nMethods);
147 | ps.setLong(7, res.startTime);
148 | ps.setLong(8, res.finished);
149 | ps.setInt(9, nFailures);
150 | ps.executeUpdate();
151 | } catch (SQLException ex) {
152 | ex.printStackTrace();
153 | }
154 |
155 | }
156 |
157 | /**
158 | * Called when an atomic test fails.
159 | * */
160 | public void testFailure(Failure failure) throws java.lang.Exception {
161 | nFailures++;
162 | res.failed = true;
163 | res.stderr.append("Failed on " + failure.getTestHeader() + ": " + failure.getMessage() + Arrays.toString(failure.getException().getStackTrace()));
164 | }
165 |
166 | public void testAssumptionFailure(Failure failure) {
167 | nFailures++;
168 | res.failed = true;
169 | res.stderr.append("Failed on " + failure.getTestHeader() + ": " + failure.getMessage() + Arrays.toString(failure.getException().getStackTrace()));
170 | }
171 | TestResult res;
172 |
173 | /**
174 | * Called when a test will not be run, generally because a test method is
175 | * annotated with Ignore.
176 | * */
177 | public void testIgnored(Description description) throws java.lang.Exception {
178 | System.out.println("Execution of test case ignored : " + description.getMethodName());
179 | }
180 |
181 | class TestResult {
182 | public long endTime;
183 | StringBuffer stdout = new StringBuffer();
184 | StringBuffer stderr = new StringBuffer();
185 | int nMethods = 0;
186 | long startTime = System.currentTimeMillis();
187 | long finished;
188 | boolean failed;
189 | String name;
190 | boolean reported;
191 |
192 | public TestResult(String name) {
193 | this.name = name;
194 | }
195 | }
196 | }
197 |
--------------------------------------------------------------------------------
/vmvm-ant-junit-formatter/src/main/java/edu/columbia/cs/psl/vmvm/MvnVMVMListener.java:
--------------------------------------------------------------------------------
1 | package edu.columbia.cs.psl.vmvm;
2 |
3 | import org.junit.runner.Description;
4 | import org.junit.runner.notification.RunListener;
5 |
6 | import java.edu.columbia.cs.psl.vmvm.runtime.Reinitializer;
7 |
8 | public class MvnVMVMListener extends RunListener {
9 |
10 | @Override
11 | public void testStarted(Description description) throws Exception {
12 | Reinitializer.newTestClassHit(description.getClassName());
13 | }
14 |
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/vmvm-ant-junit-formatter/src/main/java/edu/columbia/cs/psl/vmvm/TestReportingListener.java:
--------------------------------------------------------------------------------
1 | package edu.columbia.cs.psl.vmvm;
2 |
3 | import java.io.File;
4 | import java.io.FileNotFoundException;
5 | import java.io.OutputStream;
6 | import java.sql.Connection;
7 | import java.sql.DriverManager;
8 | import java.sql.PreparedStatement;
9 | import java.sql.ResultSet;
10 | import java.sql.SQLException;
11 | import java.sql.Statement;
12 | import java.util.Arrays;
13 | import java.util.LinkedList;
14 | import java.util.Scanner;
15 |
16 | import junit.framework.AssertionFailedError;
17 | import junit.framework.Test;
18 |
19 | import org.apache.tools.ant.BuildException;
20 | import org.apache.tools.ant.taskdefs.optional.junit.JUnitResultFormatter;
21 | import org.apache.tools.ant.taskdefs.optional.junit.JUnitTest;
22 |
23 |
24 | public class TestReportingListener implements JUnitResultFormatter {
25 |
26 | static Connection db = getConnection();
27 | static int testID;
28 |
29 | static
30 | {
31 | try{
32 | testID = Integer.valueOf(System.getProperty("vmvm.study.testID"));
33 | }
34 | catch(NumberFormatException ex)
35 | {
36 | Scanner s;
37 | try {
38 | s = new Scanner(new File("vmvm.study.testID"));
39 | testID = s.nextInt();
40 | s.close();
41 | } catch (FileNotFoundException e) {
42 | throw new IllegalStateException("No test id set!", e);
43 | }
44 |
45 | }
46 | Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
47 |
48 | @Override
49 | public void run() {
50 | try {
51 | db.close();
52 | } catch (SQLException e) {
53 | // TODO Auto-generated catch block
54 | e.printStackTrace();
55 | }
56 | }
57 | }));
58 | }
59 | static Connection getConnection() {
60 | try {
61 | Class.forName("com.mysql.jdbc.Driver");
62 | return DriverManager.getConnection("jdbc:mysql://127.0.0.1/foss?user=foss&password=f055");
63 | } catch (Exception ex) {
64 | ex.printStackTrace();
65 | }
66 | return null;
67 | }
68 | int nFailures;
69 | @Override
70 | public void addError(Test arg0, Throwable arg1) {
71 | nErrors++;
72 | res.failed = true;
73 | res.stderr.append("Failed on "+arg0+": " + arg1.getMessage()+Arrays.toString(arg1.getStackTrace()));
74 | }
75 | TestResult res;
76 | @Override
77 | public void addFailure(Test arg0, AssertionFailedError arg1) {
78 | {
79 | nFailures++;
80 | res.failed = true;
81 | res.stderr.append("Failed: " + arg1.getMessage());
82 | }
83 | }
84 |
85 | @Override
86 | public void endTest(Test arg0) {
87 |
88 | }
89 |
90 | @Override
91 | public void startTest(Test arg0) {
92 | res.nMethods++;
93 | }
94 | static int nErrors;
95 | static boolean done = false;
96 | @Override
97 | public void endTestSuite(JUnitTest arg0) throws BuildException {
98 | res.finished = System.currentTimeMillis();
99 | if(done)
100 | return;
101 | done = true;
102 | try{
103 | if(db == null)
104 | db =getConnection();
105 | PreparedStatement ps = db.prepareStatement("INSERT INTO test_result_test (test_execution_id,test,time,output,success,nTestMethods,start,end,nFailures,nErrors) VALUES (?,?,?,?,?,?,?,?,?,?)");
106 | ps.setInt(1, testID);
107 | ps.setString(2, res.name);
108 | ps.setLong(3, arg0.getRunTime());
109 | ps.setString(4, "Stdout:\n"+res.stdout.toString()+"\n\nStderr:\n"+res.stderr.toString());
110 | ps.setInt(5, nFailures>0?0:1);
111 | ps.setInt(6, res.nMethods);
112 | ps.setLong(7, res.startTime);
113 | ps.setLong(8,res.finished);
114 | ps.setInt(9, nFailures);
115 | ps.setInt(10,nErrors);
116 | ps.executeUpdate();
117 | }
118 | catch(SQLException ex)
119 | {
120 | ex.printStackTrace();
121 | }
122 | }
123 |
124 | @Override
125 | public void setOutput(OutputStream arg0) {
126 | // TODO Auto-generated method stub
127 |
128 | }
129 |
130 | @Override
131 | public void setSystemError(String arg0) {
132 | res.stderr.append(arg0);
133 | }
134 |
135 | @Override
136 | public void setSystemOutput(String arg0) {
137 | res.stdout.append(arg0);
138 | }
139 |
140 | @Override
141 | public void startTestSuite(JUnitTest arg0) throws BuildException {
142 | done = false;
143 | nFailures=0;
144 | nErrors=0;
145 | res = (new TestResult(arg0.getName()));
146 | if(arg0.getProperties() == null || arg0.getProperties().getProperty("workerStartTime") == null)
147 | res.startTime = System.currentTimeMillis();
148 | else
149 | res.startTime = Long.valueOf(arg0.getProperties().getProperty("workerStartTime"));
150 | }
151 |
152 | class TestResult
153 | {
154 | StringBuffer stdout = new StringBuffer();
155 | StringBuffer stderr = new StringBuffer();
156 | int nMethods=0;
157 | long startTime = System.currentTimeMillis();
158 | long finished;
159 | boolean failed;
160 | String name;
161 | public TestResult(String name)
162 | {
163 | this.name=name;
164 | }
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/vmvm-internal-static-detector/bin/log4j.properties:
--------------------------------------------------------------------------------
1 |
2 | log4j.rootCategory=INFO, stderr, file
3 |
4 | # Pattern to output the caller's file name and line number.
5 | log4j.appender.stderr=org.apache.log4j.ConsoleAppender
6 | log4j.appender.stderr.target=System.err
7 | log4j.appender.stderr.layout=org.apache.log4j.PatternLayout
8 | log4j.appender.stderr.layout.ConversionPattern=[sd %d{HH:mm:ss}] %p [%t] %C{1}.%M(%L) | %m%n
9 |
10 | #[native-detector %d] %p [%t] %C.%M(%L) | %m%n
11 |
12 | log4j.appender.file=org.apache.log4j.RollingFileAppender
13 | log4j.appender.file.File=native-detector.log
14 | log4j.appender.file.MaxFileSize=100000KB
15 | log4j.appender.file.MaxBackupIndex=10
16 | log4j.appender.file.layout=org.apache.log4j.PatternLayout
17 | log4j.appender.file.layout.ConversionPattern=[sd %d{HH:mm:ss}] %p [%t] %C{1}.%M(%L) | %m%n
18 |
--------------------------------------------------------------------------------
/vmvm-internal-static-detector/lib/asm-all-4.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Programming-Systems-Lab/vmvm/07a36dc21373147c50ceacd7bff2b2e7a86c8780/vmvm-internal-static-detector/lib/asm-all-4.0.jar
--------------------------------------------------------------------------------
/vmvm-internal-static-detector/lib/asm-src.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Programming-Systems-Lab/vmvm/07a36dc21373147c50ceacd7bff2b2e7a86c8780/vmvm-internal-static-detector/lib/asm-src.zip
--------------------------------------------------------------------------------
/vmvm-internal-static-detector/lib/log4j-1.2.16.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Programming-Systems-Lab/vmvm/07a36dc21373147c50ceacd7bff2b2e7a86c8780/vmvm-internal-static-detector/lib/log4j-1.2.16.jar
--------------------------------------------------------------------------------
/vmvm-internal-static-detector/pom.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 | edu.gmu.swe.vmvm
6 | vmvm-base-pom
7 | 2.0.0-SNAPSHOT
8 |
9 |
10 | 4.0.0
11 | vmvm-internal-static-detector
12 | jar
13 | ${project.groupId}::${project.artifactId}
14 |
15 |
16 | ${project.basedir}/../LICENSE.md
17 |
18 |
19 |
20 |
21 |
22 | ${project.groupId}
23 | vmvm
24 |
25 |
26 |
27 | log4j
28 | log4j
29 |
30 |
31 |
32 | org.ow2.asm
33 | asm-all
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/vmvm-internal-static-detector/src/main/java/edu/columbia/cs/psl/vmvm/util/StaticPutDetector.java:
--------------------------------------------------------------------------------
1 | package edu.columbia.cs.psl.vmvm.util;
2 |
3 | import java.io.File;
4 | import java.io.FileWriter;
5 | import java.io.IOException;
6 | import java.util.Enumeration;
7 | import java.util.HashSet;
8 | import java.util.jar.JarEntry;
9 | import java.util.jar.JarFile;
10 |
11 | import org.apache.log4j.Logger;
12 | import org.objectweb.asm.ClassReader;
13 | import org.objectweb.asm.ClassVisitor;
14 | import org.objectweb.asm.ClassWriter;
15 | import org.objectweb.asm.MethodVisitor;
16 | import org.objectweb.asm.Opcodes;
17 |
18 | import edu.columbia.cs.psl.vmvm.Instrumenter;
19 | import edu.columbia.cs.psl.vmvm.asm.struct.MethodListClassNode;
20 |
21 |
22 | public class StaticPutDetector {
23 | private static final Logger logger = Logger.getLogger(StaticPutDetector.class);
24 | private static FileWriter fw;
25 | public static void main(String[] args) throws Throwable {
26 | File f = new File("static-mod-methods.txt");
27 | if (f.exists())
28 | f.delete();
29 | // fw = new FileWriter(f);
30 | Instrumenter.pass_number = 0;
31 | Instrumenter.MAX_CLASSES = Integer.valueOf(args[1]);
32 | long start = System.currentTimeMillis();
33 | Instrumenter.processJar(new File(args[0]),null);
34 | Instrumenter.finishedPass();
35 | long end = System.currentTimeMillis();
36 | System.err.println(Instrumenter.classesInstrumented +"\t"+(end-start));
37 | // for(MethodListClassNode cn : Instrumenter.instrumentedClasses.values())
38 | // {
39 | // if(cn.clInitCalculatedNecessary && (cn.name.startsWith("java") || cn.name.startsWith("System")))
40 | // {
41 | // System.err.println(cn.name);
42 | // }
43 | // }
44 | // fw.close();
45 | // findAllStatics("/Library/Java/JavaVirtualMachines/1.7.0.jdk/Contents/Home/jre/lib/rt.jar");
46 | }
47 | private static void findAllStatics(String path)
48 | {
49 | JarFile classJar;
50 | try {
51 | classJar = new JarFile(path);
52 |
53 | Enumeration jarContents = classJar.entries();
54 | int i = 0;
55 | while (jarContents.hasMoreElements()) {
56 | String name = jarContents.nextElement().getName();
57 | if (!name.endsWith(".class"))
58 | continue;
59 | name = name.substring(0, name.length() - 6);
60 | try{
61 | ClassReader cr = new ClassReader(name);
62 | StaticFinderCV ccv = new StaticFinderCV(Opcodes.ASM4)
63 | ; cr.accept(ccv, 0);
64 | }
65 | catch(IOException ex)
66 | {
67 | System.out.println(name);
68 | ex.printStackTrace();
69 | }
70 | i++;
71 | if (i % 5000 == 0)
72 | logger.info(i + " classes processed");
73 | }
74 | classJar.close();
75 | } catch (IOException e) {
76 | // TODO Auto-generated catch block
77 | e.printStackTrace();
78 | }
79 |
80 | }
81 | static class StaticFinderCV extends ClassVisitor{
82 | private String className;
83 | public StaticFinderCV(int api) {
84 | super(api);
85 | }
86 | @Override
87 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
88 | this.className = name;
89 | }
90 | @Override
91 | public void visitEnd() {
92 | if(isBad && className.startsWith("java") && (sets.size() >0 || adds.size() >0))
93 | System.err.println(className + adds + "." + removes + "."+sets+"."+gets);
94 | super.visitEnd();
95 | }
96 | private boolean isBad = false;
97 | private HashSet adds = new HashSet();
98 | private HashSet sets = new HashSet();
99 | private HashSet gets = new HashSet();
100 | private HashSet removes = new HashSet();
101 | @Override
102 | public MethodVisitor visitMethod(int access, final String methodName, final String methodDesc, String signature, String[] exceptions) {
103 | if((access & Opcodes.ACC_STATIC) != 0 && (methodName.startsWith("set") || methodName.startsWith("add") || methodName.startsWith("remove") || methodName.startsWith("get")))
104 | {
105 | if((access & Opcodes.ACC_PUBLIC) == 0)
106 | return null;
107 | if(methodName.startsWith("add"))
108 | adds.add(methodName);
109 | if(methodName.startsWith("remove"))
110 | removes.add(methodName);
111 | if(methodName.startsWith("set"))
112 | sets.add(methodName);
113 | if(methodName.startsWith("get"))
114 | gets.add(methodName);
115 |
116 | isBad = true;
117 | }
118 | return null;
119 | }
120 |
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/vmvm-internal-static-detector/src/main/resources/log4j.properties:
--------------------------------------------------------------------------------
1 |
2 | log4j.rootCategory=INFO, stderr, file
3 |
4 | # Pattern to output the caller's file name and line number.
5 | log4j.appender.stderr=org.apache.log4j.ConsoleAppender
6 | log4j.appender.stderr.target=System.err
7 | log4j.appender.stderr.layout=org.apache.log4j.PatternLayout
8 | log4j.appender.stderr.layout.ConversionPattern=[sd %d{HH:mm:ss}] %p [%t] %C{1}.%M(%L) | %m%n
9 |
10 | #[native-detector %d] %p [%t] %C.%M(%L) | %m%n
11 |
12 | log4j.appender.file=org.apache.log4j.RollingFileAppender
13 | log4j.appender.file.File=native-detector.log
14 | log4j.appender.file.MaxFileSize=100000KB
15 | log4j.appender.file.MaxBackupIndex=10
16 | log4j.appender.file.layout=org.apache.log4j.PatternLayout
17 | log4j.appender.file.layout.ConversionPattern=[sd %d{HH:mm:ss}] %p [%t] %C{1}.%M(%L) | %m%n
18 |
--------------------------------------------------------------------------------
/vmvm-internal-static-detector/vmvm-internal-static-detector.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/vmvm/.gitignore:
--------------------------------------------------------------------------------
1 | debug
2 | dependency-reduced-pom.xml
3 | .classpath
4 | .settings
5 | .project
6 | target
7 | .cproject
8 |
--------------------------------------------------------------------------------
/vmvm/pom.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 | edu.gmu.swe.vmvm
6 | vmvm-base-pom
7 | 2.0.0-SNAPSHOT
8 |
9 |
10 | 4.0.0
11 | vmvm
12 | jar
13 | ${project.groupId}::${project.artifactId}
14 |
15 | ${project.basedir}/../LICENSE.md
16 | edu.columbia.cs.psl.vmvm.runtime.PreMain
17 | ${premain.class.name}
18 |
19 |
20 |
21 |
22 |
23 | org.apache.maven.plugins
24 | maven-jar-plugin
25 | true
26 |
27 |
28 |
29 | true
30 | true
31 | true
32 | ${main.class.name}
33 |
34 |
35 | ${buildNumber}
36 | ${premain.class.name}
37 | ${agent.class.name}
38 | true
39 | true
40 |
41 |
42 |
43 |
44 |
45 | jar
46 |
47 | jar
48 |
49 |
50 |
51 |
52 |
53 | maven-compiler-plugin
54 | 3.1
55 |
56 | 1.8
57 | 1.8
58 |
59 |
60 |
61 | org.apache.maven.plugins
62 | maven-failsafe-plugin
63 | 2.18.1
64 |
65 |
66 |
67 | integration-test
68 | verify
69 |
70 |
71 |
72 |
73 | -Xbootclasspath/p:${project.build.directory}/${project.build.finalName}.jar
74 |
75 | -javaagent:${project.build.directory}/${project.build.finalName}.jar
76 |
77 |
78 |
79 | org.apache.maven.plugins
80 | maven-shade-plugin
81 | 2.3
82 |
83 |
84 | package
85 |
86 | shade
87 |
88 |
89 |
90 |
91 | org.apache.commons.cli
92 | edu.columbia.cs.psl.vmvm.org.apache.commons.cli
93 |
94 |
95 | org.objectweb.asm
96 | edu.columbia.cs.psl.vmvm.org.objectweb.asm
97 |
98 |
99 | false
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | junit
110 | junit
111 | 4.11
112 | test
113 |
114 |
115 | commons-cli
116 | commons-cli
117 | 1.2
118 |
119 |
120 | org.ow2.asm
121 | asm-all
122 | 5.0.3
123 |
124 |
125 |
126 |
--------------------------------------------------------------------------------
/vmvm/src/main/java/edu/columbia/cs/psl/vmvm/runtime/AdditionalInterfaceClassloader.java:
--------------------------------------------------------------------------------
1 | package edu.columbia.cs.psl.vmvm.runtime;
2 |
3 | import java.util.HashMap;
4 |
5 | public class AdditionalInterfaceClassloader extends ClassLoader {
6 | HashMap definedClasses = new HashMap();
7 |
8 | public void addClass(String name, byte[] b) {
9 | definedClasses.put(name, b);
10 | }
11 |
12 | protected java.lang.Class> findClass(String name) throws ClassNotFoundException {
13 | if (definedClasses.containsKey(name)) {
14 | byte[] b = definedClasses.remove(name);
15 | Class> c = defineClass(name, b, 0, b.length);
16 | resolveClass(c);
17 | return c;
18 | }
19 | return null;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/vmvm/src/main/java/edu/columbia/cs/psl/vmvm/runtime/ConsumerUtils.java:
--------------------------------------------------------------------------------
1 | package edu.columbia.cs.psl.vmvm.runtime;
2 |
3 | import edu.columbia.cs.psl.vmvm.runtime.inst.Utils;
4 |
5 | public class ConsumerUtils {
6 | public boolean isIgnoredClass(String internalName) {
7 | return Utils.ignorePattern != null && internalName.startsWith(Utils.ignorePattern);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/vmvm/src/main/java/edu/columbia/cs/psl/vmvm/runtime/FieldReflectionWrapper.java:
--------------------------------------------------------------------------------
1 | package edu.columbia.cs.psl.vmvm.runtime;
2 |
3 | import java.edu.columbia.cs.psl.vmvm.runtime.ReflectionWrapper;
4 | import java.lang.reflect.Field;
5 | import java.lang.reflect.Modifier;
6 |
7 | public class FieldReflectionWrapper {
8 |
9 | public static Field tryToInit(Field f, Object obj)
10 | {
11 | if (Modifier.isStatic(f.getModifiers()))
12 | ReflectionWrapper.tryToInit(f.getDeclaringClass());
13 | return f;
14 | }
15 |
16 | public static Field tryToInit(Field f) throws IllegalArgumentException, IllegalAccessException {
17 | if (Modifier.isStatic(f.getModifiers()))
18 | ReflectionWrapper.tryToInit(f.getDeclaringClass());
19 | return f;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/vmvm/src/main/java/edu/columbia/cs/psl/vmvm/runtime/Instrumenter.java:
--------------------------------------------------------------------------------
1 | package edu.columbia.cs.psl.vmvm.runtime;
2 |
3 | import java.io.ByteArrayOutputStream;
4 | import java.io.File;
5 | import java.io.FileInputStream;
6 | import java.io.FileNotFoundException;
7 | import java.io.FileOutputStream;
8 | import java.io.IOException;
9 | import java.io.InputStream;
10 | import java.nio.channels.FileChannel;
11 | import java.util.Enumeration;
12 | import java.util.Scanner;
13 | import java.util.jar.JarEntry;
14 | import java.util.jar.JarFile;
15 | import java.util.jar.JarOutputStream;
16 | import java.util.zip.ZipEntry;
17 | import java.util.zip.ZipException;
18 | import java.util.zip.ZipFile;
19 | import java.util.zip.ZipOutputStream;
20 |
21 | import org.apache.commons.cli.BasicParser;
22 | import org.apache.commons.cli.CommandLine;
23 | import org.apache.commons.cli.CommandLineParser;
24 | import org.apache.commons.cli.HelpFormatter;
25 | import org.apache.commons.cli.Option;
26 | import org.apache.commons.cli.Options;
27 | import org.objectweb.asm.ClassReader;
28 | import org.objectweb.asm.ClassWriter;
29 | import org.objectweb.asm.util.CheckClassAdapter;
30 |
31 | public class Instrumenter {
32 | public static ClassLoader loader;
33 |
34 | static String curPath;
35 |
36 | static int n = 0;
37 |
38 | public static byte[] instrumentClass(String name, InputStream is, boolean renameInterfaces) {
39 | try {
40 | n++;
41 | if (n % 1000 == 0)
42 | System.out.println("Processed: " + n);
43 | curPath = name;
44 | ByteArrayOutputStream buffer = new ByteArrayOutputStream();
45 |
46 | int nRead;
47 | byte[] data = new byte[16384];
48 |
49 | while ((nRead = is.read(data, 0, data.length)) != -1) {
50 | buffer.write(data, 0, nRead);
51 | }
52 |
53 | buffer.flush();
54 | VMVMClassFileTransformer transformer = new VMVMClassFileTransformer();
55 | ClassReader cr = new ClassReader(buffer.toByteArray());
56 |
57 | byte[] ret = transformer.transform(Instrumenter.loader, cr.getClassName(), null, null, buffer.toByteArray());
58 | curPath = null;
59 | return ret;
60 | } catch (Exception ex) {
61 | curPath = null;
62 | ex.printStackTrace();
63 | return null;
64 | }
65 | }
66 |
67 | static Option help = new Option("help", "print this message");
68 |
69 | public static void main(String[] args) {
70 |
71 | Options options = new Options();
72 | options.addOption(help);
73 |
74 | CommandLineParser parser = new BasicParser();
75 | CommandLine line = null;
76 | try {
77 | line = parser.parse(options, args);
78 | } catch (org.apache.commons.cli.ParseException exp) {
79 |
80 | HelpFormatter formatter = new HelpFormatter();
81 | formatter.printHelp("java -jar instrumenter.jar [OPTIONS] [input] [output]", options);
82 | System.err.println(exp.getMessage());
83 | return;
84 | }
85 | if (line.hasOption("help") || line.getArgs().length != 2) {
86 | HelpFormatter formatter = new HelpFormatter();
87 | formatter.printHelp("java -jar instrumenter.jar [OPTIONS] [input] [output]", options);
88 | return;
89 | }
90 |
91 | PreMain.IS_RUNTIME_INST = false;
92 | instrumentDir(line.getArgs()[0], line.getArgs()[1]);
93 | }
94 |
95 | static File rootOutputDir;
96 |
97 | public static void instrumentDir(String inputFolder, String outputFolder) {
98 |
99 | rootOutputDir = new File(outputFolder);
100 | if (!rootOutputDir.exists())
101 | rootOutputDir.mkdir();
102 | File f = new File(inputFolder);
103 | if (!f.exists()) {
104 | System.err.println("Unable to read path " + inputFolder);
105 | System.exit(-1);
106 | }
107 | if (f.isDirectory())
108 | processDirectory(f, rootOutputDir, true);
109 | else if (inputFolder.endsWith(".jar") || inputFolder.endsWith(".war"))
110 | processJar(f, rootOutputDir);
111 | else if (inputFolder.endsWith(".class"))
112 | try {
113 | processClass(f.getName(), new FileInputStream(f), rootOutputDir);
114 | } catch (FileNotFoundException e) {
115 | e.printStackTrace();
116 | }
117 | else if (inputFolder.endsWith(".zip")) {
118 | processZip(f, rootOutputDir);
119 | } else {
120 | System.err.println("Unknown type for path " + inputFolder);
121 | System.exit(-1);
122 | }
123 | }
124 |
125 | static String lastInstrumentedClass;
126 |
127 | private static void processClass(String name, InputStream is, File outputDir) {
128 |
129 | try {
130 | FileOutputStream fos = new FileOutputStream(outputDir.getPath() + File.separator + name);
131 | ByteArrayOutputStream bos = new ByteArrayOutputStream();
132 | lastInstrumentedClass = outputDir.getPath() + File.separator + name;
133 |
134 | byte[] c = instrumentClass(outputDir.getAbsolutePath(), is, true);
135 | bos.write(c);
136 | bos.writeTo(fos);
137 | fos.close();
138 | is.close();
139 |
140 | } catch (Exception ex) {
141 | ex.printStackTrace();
142 | }
143 | }
144 |
145 | private static void processDirectory(File f, File parentOutputDir, boolean isFirstLevel) {
146 | File thisOutputDir;
147 | if (isFirstLevel) {
148 | thisOutputDir = parentOutputDir;
149 | } else {
150 | thisOutputDir = new File(parentOutputDir.getAbsolutePath() + File.separator + f.getName());
151 | thisOutputDir.mkdir();
152 | }
153 | for (File fi : f.listFiles()) {
154 | if (fi.isDirectory())
155 | processDirectory(fi, thisOutputDir, false);
156 | else if (fi.getName().endsWith(".class"))
157 | try {
158 | processClass(fi.getName(), new FileInputStream(fi), thisOutputDir);
159 | } catch (FileNotFoundException e) {
160 | e.printStackTrace();
161 | }
162 | else if (fi.getName().endsWith(".jar") || fi.getName().endsWith(".war"))
163 | processJar(fi, thisOutputDir);
164 | else if (fi.getName().endsWith(".zip"))
165 | processZip(fi, thisOutputDir);
166 | else {
167 | File dest = new File(thisOutputDir.getPath() + File.separator + fi.getName());
168 | FileChannel source = null;
169 | FileChannel destination = null;
170 |
171 | try {
172 | source = new FileInputStream(fi).getChannel();
173 | destination = new FileOutputStream(dest).getChannel();
174 | destination.transferFrom(source, 0, source.size());
175 | } catch (Exception ex) {
176 | System.err.println("error copying file " + fi);
177 | ex.printStackTrace();
178 | } finally {
179 | if (source != null) {
180 | try {
181 | source.close();
182 | } catch (IOException e) {
183 | e.printStackTrace();
184 | }
185 | }
186 | if (destination != null) {
187 | try {
188 | destination.close();
189 | } catch (IOException e) {
190 | e.printStackTrace();
191 | }
192 | }
193 | }
194 |
195 | }
196 | }
197 |
198 | }
199 |
200 | public static void processJar(File f, File outputDir) {
201 | try {
202 | JarFile jar = new JarFile(f);
203 | JarOutputStream jos = null;
204 | jos = new JarOutputStream(new FileOutputStream(outputDir.getPath() + File.separator + f.getName()));
205 | Enumeration entries = jar.entries();
206 | while (entries.hasMoreElements()) {
207 | JarEntry e = entries.nextElement();
208 | if (e.getName().endsWith(".class")) {
209 | {
210 |
211 | try {
212 | JarEntry outEntry = new JarEntry(e.getName());
213 | jos.putNextEntry(outEntry);
214 | byte[] clazz = instrumentClass(f.getAbsolutePath(), jar.getInputStream(e), true);
215 | if (clazz == null) {
216 | System.out.println("Failed to instrument " + e.getName() + " in " + f.getName());
217 | InputStream is = jar.getInputStream(e);
218 | byte[] buffer = new byte[1024];
219 | while (true) {
220 | int count = is.read(buffer);
221 | if (count == -1)
222 | break;
223 | jos.write(buffer, 0, count);
224 | }
225 | } else {
226 | jos.write(clazz);
227 | }
228 | jos.closeEntry();
229 | } catch (ZipException ex) {
230 | ex.printStackTrace();
231 | continue;
232 | }
233 |
234 | }
235 |
236 | } else {
237 | JarEntry outEntry = new JarEntry(e.getName());
238 | if (e.isDirectory()) {
239 | try {
240 | jos.putNextEntry(outEntry);
241 | jos.closeEntry();
242 | } catch (ZipException exxx) {
243 | System.out.println("Ignoring exception: " + exxx);
244 | }
245 | } else if (e.getName().startsWith("META-INF") && (e.getName().endsWith(".SF") || e.getName().endsWith(".RSA"))) {
246 | // don't copy this
247 | } else if (e.getName().equals("META-INF/MANIFEST.MF")) {
248 | Scanner s = new Scanner(jar.getInputStream(e));
249 | jos.putNextEntry(outEntry);
250 |
251 | String curPair = "";
252 | while (s.hasNextLine()) {
253 | String line = s.nextLine();
254 | if (line.equals("")) {
255 | curPair += "\n";
256 | if (!curPair.contains("SHA1-Digest:"))
257 | jos.write(curPair.getBytes());
258 | curPair = "";
259 | } else {
260 | curPair += line + "\n";
261 | }
262 | }
263 | s.close();
264 | jos.closeEntry();
265 | } else {
266 | try {
267 | jos.putNextEntry(outEntry);
268 | InputStream is = jar.getInputStream(e);
269 | byte[] buffer = new byte[1024];
270 | while (true) {
271 | int count = is.read(buffer);
272 | if (count == -1)
273 | break;
274 | jos.write(buffer, 0, count);
275 | }
276 | jos.closeEntry();
277 | } catch (ZipException ex) {
278 | if (!ex.getMessage().contains("duplicate entry")) {
279 | ex.printStackTrace();
280 | System.out.println("Ignoring above warning from improper source zip...");
281 | }
282 | }
283 | }
284 |
285 | }
286 |
287 | }
288 | if (jos != null) {
289 | jos.close();
290 |
291 | }
292 | jar.close();
293 | } catch (Exception e) {
294 | System.err.println("Unable to process jar: " + f.getAbsolutePath());
295 | e.printStackTrace();
296 | File dest = new File(outputDir.getPath() + File.separator + f.getName());
297 | FileChannel source = null;
298 | FileChannel destination = null;
299 |
300 | try {
301 | source = new FileInputStream(f).getChannel();
302 | destination = new FileOutputStream(dest).getChannel();
303 | destination.transferFrom(source, 0, source.size());
304 | } catch (Exception ex) {
305 | System.err.println("Unable to copy file: " + f.getAbsolutePath());
306 | ex.printStackTrace();
307 | } finally {
308 | if (source != null) {
309 | try {
310 | source.close();
311 | } catch (IOException e2) {
312 | e2.printStackTrace();
313 | }
314 | }
315 | if (destination != null) {
316 | try {
317 | destination.close();
318 | } catch (IOException e2) {
319 | e2.printStackTrace();
320 | }
321 | }
322 | }
323 | }
324 |
325 | }
326 |
327 | private static void processZip(File f, File outputDir) {
328 | try {
329 | ZipFile zip = new ZipFile(f);
330 | ZipOutputStream zos = null;
331 | zos = new ZipOutputStream(new FileOutputStream(outputDir.getPath() + File.separator + f.getName()));
332 | Enumeration extends ZipEntry> entries = zip.entries();
333 | while (entries.hasMoreElements()) {
334 | ZipEntry e = entries.nextElement();
335 |
336 | if (e.getName().endsWith(".class")) {
337 | {
338 | ZipEntry outEntry = new ZipEntry(e.getName());
339 | zos.putNextEntry(outEntry);
340 |
341 | byte[] clazz = instrumentClass(f.getAbsolutePath(), zip.getInputStream(e), true);
342 | if (clazz == null) {
343 | InputStream is = zip.getInputStream(e);
344 | byte[] buffer = new byte[1024];
345 | while (true) {
346 | int count = is.read(buffer);
347 | if (count == -1)
348 | break;
349 | zos.write(buffer, 0, count);
350 | }
351 | } else
352 | zos.write(clazz);
353 | zos.closeEntry();
354 |
355 | }
356 |
357 | } else if (e.getName().endsWith(".jar")) {
358 | ZipEntry outEntry = new ZipEntry(e.getName());
359 | File tmp = new File("/tmp/classfile");
360 | if (tmp.exists())
361 | tmp.delete();
362 | FileOutputStream fos = new FileOutputStream(tmp);
363 | byte buf[] = new byte[1024];
364 | int len;
365 | InputStream is = zip.getInputStream(e);
366 | while ((len = is.read(buf)) > 0) {
367 | fos.write(buf, 0, len);
368 | }
369 | is.close();
370 | fos.close();
371 |
372 | File tmp2 = new File("tmp2");
373 | if (!tmp2.exists())
374 | tmp2.mkdir();
375 | processJar(tmp, new File("tmp2"));
376 |
377 | zos.putNextEntry(outEntry);
378 | is = new FileInputStream("tmp2/classfile");
379 | byte[] buffer = new byte[1024];
380 | while (true) {
381 | int count = is.read(buffer);
382 | if (count == -1)
383 | break;
384 | zos.write(buffer, 0, count);
385 | }
386 | is.close();
387 | zos.closeEntry();
388 | } else {
389 | ZipEntry outEntry = new ZipEntry(e.getName());
390 | if (e.isDirectory()) {
391 | try {
392 | zos.putNextEntry(outEntry);
393 | zos.closeEntry();
394 | } catch (ZipException exxxx) {
395 | System.out.println("Ignoring exception: " + exxxx.getMessage());
396 | }
397 | } else if (e.getName().startsWith("META-INF") && (e.getName().endsWith(".SF") || e.getName().endsWith(".RSA"))) {
398 | // don't copy this
399 | } else if (e.getName().equals("META-INF/MANIFEST.MF")) {
400 | Scanner s = new Scanner(zip.getInputStream(e));
401 | zos.putNextEntry(outEntry);
402 |
403 | String curPair = "";
404 | while (s.hasNextLine()) {
405 | String line = s.nextLine();
406 | if (line.equals("")) {
407 | curPair += "\n";
408 | if (!curPair.contains("SHA1-Digest:"))
409 | zos.write(curPair.getBytes());
410 | curPair = "";
411 | } else {
412 | curPair += line + "\n";
413 | }
414 | }
415 | s.close();
416 | zos.write("\n".getBytes());
417 | zos.closeEntry();
418 | } else {
419 | zos.putNextEntry(outEntry);
420 | InputStream is = zip.getInputStream(e);
421 | byte[] buffer = new byte[1024];
422 | while (true) {
423 | int count = is.read(buffer);
424 | if (count == -1)
425 | break;
426 | zos.write(buffer, 0, count);
427 | }
428 | zos.closeEntry();
429 | }
430 | }
431 |
432 | }
433 | zos.close();
434 | zip.close();
435 | } catch (Exception e) {
436 | System.err.println("Unable to process zip: " + f.getAbsolutePath());
437 | e.printStackTrace();
438 | File dest = new File(outputDir.getPath() + File.separator + f.getName());
439 | FileChannel source = null;
440 | FileChannel destination = null;
441 |
442 | try {
443 | source = new FileInputStream(f).getChannel();
444 | destination = new FileOutputStream(dest).getChannel();
445 | destination.transferFrom(source, 0, source.size());
446 | } catch (Exception ex) {
447 | System.err.println("Unable to copy zip: " + f.getAbsolutePath());
448 | ex.printStackTrace();
449 | } finally {
450 | if (source != null) {
451 | try {
452 | source.close();
453 | } catch (IOException e2) {
454 | e2.printStackTrace();
455 | }
456 | }
457 | if (destination != null) {
458 | try {
459 | destination.close();
460 | } catch (IOException e2) {
461 | e2.printStackTrace();
462 | }
463 | }
464 | }
465 | }
466 |
467 | }
468 |
469 | }
--------------------------------------------------------------------------------
/vmvm/src/main/java/edu/columbia/cs/psl/vmvm/runtime/JUnitInterceptingClassVisitor.java:
--------------------------------------------------------------------------------
1 | package edu.columbia.cs.psl.vmvm.runtime;
2 |
3 | import org.objectweb.asm.ClassVisitor;
4 | import org.objectweb.asm.MethodVisitor;
5 | import org.objectweb.asm.Opcodes;
6 | import org.objectweb.asm.Type;
7 |
8 | import java.edu.columbia.cs.psl.vmvm.runtime.Reinitializer;
9 |
10 | public class JUnitInterceptingClassVisitor extends ClassVisitor {
11 | /*
12 | org.junit.internal.requests.ClassRequest(Class, boolean) <-- here
13 | */
14 | public JUnitInterceptingClassVisitor(ClassVisitor cv) {
15 | super(Opcodes.ASM5, cv);
16 | }
17 |
18 | @Override
19 | public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
20 |
21 | MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
22 | if (name.equals("") && desc.equals("(Ljava/lang/Class;Z)V")) {
23 | mv = new MethodVisitor(Opcodes.ASM5, mv) {
24 | boolean intercepted = false;
25 |
26 | @Override
27 | public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
28 | super.visitMethodInsn(opcode, owner, name, desc, itf);
29 |
30 | if (!intercepted && name.equals("")) {
31 | intercepted = true;
32 | super.visitVarInsn(Opcodes.ALOAD, 1);
33 | super.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Reinitializer.class), "newTestClassHit", "(Ljava/lang/Class;)V", false);
34 | }
35 | }
36 | };
37 | }
38 | return mv;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/vmvm/src/main/java/edu/columbia/cs/psl/vmvm/runtime/PreMain.java:
--------------------------------------------------------------------------------
1 | package edu.columbia.cs.psl.vmvm.runtime;
2 |
3 | import edu.columbia.cs.psl.vmvm.runtime.inst.Utils;
4 |
5 | import java.edu.columbia.cs.psl.vmvm.runtime.Reinitializer;
6 | import java.lang.instrument.Instrumentation;
7 | import java.lang.instrument.UnmodifiableClassException;
8 |
9 | public class PreMain {
10 | public static boolean IS_RUNTIME_INST = true;
11 |
12 | public static void premain(String args, Instrumentation inst) {
13 | Reinitializer.inst = inst;
14 | if(args != null)
15 | Utils.ignorePattern = args;
16 | for(Class c : inst.getAllLoadedClasses()){
17 | VMVMClassFileTransformer.ignoredClasses.add(c.getName().replace('.','/'));
18 | }
19 | inst.addTransformer(new VMVMClassFileTransformer(), true);
20 | for(Class c : inst.getAllLoadedClasses()){
21 | try {
22 | inst.retransformClasses(c);
23 | } catch (UnmodifiableClassException e) {
24 | } catch(Throwable t){
25 | t.printStackTrace();
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/vmvm/src/main/java/edu/columbia/cs/psl/vmvm/runtime/VMVMClassFileTransformer.java:
--------------------------------------------------------------------------------
1 | package edu.columbia.cs.psl.vmvm.runtime;
2 |
3 | import java.edu.columbia.cs.psl.vmvm.runtime.InterfaceReinitializer;
4 | import java.edu.columbia.cs.psl.vmvm.runtime.VMVMInstrumented;
5 | import edu.columbia.cs.psl.vmvm.runtime.inst.ClassReinitCV;
6 | import edu.columbia.cs.psl.vmvm.runtime.inst.Constants;
7 | import edu.columbia.cs.psl.vmvm.runtime.inst.ReflectionFixingCV;
8 | import org.objectweb.asm.*;
9 | import org.objectweb.asm.tree.ClassNode;
10 | import org.objectweb.asm.tree.MethodNode;
11 | import org.objectweb.asm.util.CheckClassAdapter;
12 | import sun.misc.Unsafe;
13 |
14 | import java.io.File;
15 | import java.io.FileOutputStream;
16 | import java.io.IOException;
17 | import java.lang.instrument.ClassFileTransformer;
18 | import java.lang.instrument.IllegalClassFormatException;
19 | import java.lang.reflect.Field;
20 | import java.security.ProtectionDomain;
21 | import java.util.HashSet;
22 |
23 | public class VMVMClassFileTransformer implements ClassFileTransformer {
24 |
25 | public static HashSet ignoredClasses = new HashSet<>();
26 | public static boolean isIgnoredClass(String internalName) {
27 | internalName = internalName.replace('.','/');
28 | if (isWhitelistedClass(internalName))
29 | return false;
30 | if(ignoredClasses.contains(internalName))
31 | return true;
32 | return
33 | internalName.startsWith("java")
34 | || internalName.startsWith("jdk")
35 | || internalName.startsWith("sun/misc")
36 | || internalName.startsWith("sun/reflect")
37 | || internalName.equals("sun/java2d/opengl/OGLRenderQueue")
38 | || internalName.startsWith("sun")
39 | || internalName.startsWith("com/sun/java/util/jar")
40 | || internalName.startsWith("edu/columbia/cs/psl/vmvm/runtime")
41 | || internalName.startsWith("org/junit")
42 | || internalName.startsWith("junit/")
43 | || internalName.startsWith("java/edu/columbia/cs/psl/vmvm")
44 | || internalName.startsWith("edu/columbia/cs/psl/vmvm/")
45 | || internalName.startsWith("org/apache/maven/surefire") || internalName.startsWith("org/apache/tools/")
46 | || internalName.startsWith("org/mockito") || internalName.startsWith("mockit")
47 | || internalName.startsWith("org/powermock")
48 | || internalName.startsWith("com/jprofiler");
49 | }
50 |
51 | public static boolean isWhitelistedClass(String internalName) {
52 | return internalName.startsWith("javax/servlet") || internalName.startsWith("com/sun/jini") || internalName.startsWith("java/awt") || internalName.startsWith("javax/swing") || internalName.startsWith("javax/xml") || internalName.startsWith("sun/awt");
53 | }
54 |
55 | public static boolean isClassThatNeedsReflectionHacked(String internalName) {
56 | return ignoredClasses.contains(internalName) || internalName.startsWith("java/io/ObjectOutputStream") || internalName.startsWith("java/io/ObjectStream")
57 | || internalName.startsWith("sun/reflect/annotation/AnnotationInvocationHandler");
58 | // return internalName.startsWith("java/") && !internalName.startsWith("java/lang/reflect") && !internalName.equals("java/lang/Class");
59 | }
60 |
61 | public static AdditionalInterfaceClassloader cl = new AdditionalInterfaceClassloader();
62 |
63 | public static HashSet instrumentedClasses = new HashSet();
64 | public static final boolean DEBUG = System.getProperty("vmvm.debug") != null;
65 | public static final boolean ALWAYS_REOPT = false;
66 | public static final boolean HOTSPOT_REOPT = false;
67 |
68 | @SuppressWarnings("restriction")
69 | static sun.misc.Unsafe theUnsafe;
70 |
71 | @SuppressWarnings("restriction")
72 | public static sun.misc.Unsafe getUnsafe() {
73 | if (theUnsafe == null) {
74 | try {
75 | Field f = Unsafe.class.getDeclaredField("theUnsafe");
76 | f.setAccessible(true);
77 | theUnsafe = (Unsafe) f.get(null);
78 | }catch(NoSuchFieldException | IllegalAccessException ex){
79 | ex.printStackTrace();
80 | }
81 | }
82 | return theUnsafe;
83 | }
84 |
85 | public static Class> generateResetter(Class> hostClass)
86 | {
87 |
88 | String hostName = hostClass.getName().replace(".","/");
89 | String newName = hostName + Constants.VMVM_RESET_FIELD;
90 | ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
91 | Integer version = ClassReinitCV.reClinitClassHelperVersions.remove(hostName);
92 | if(version == null)
93 | version = Opcodes.V1_8;
94 | cw.visit(version, Opcodes.ACC_PUBLIC, newName , null, InterfaceReinitializer.INTERNAL_NAME, null);
95 | cw.visitSource(null, null);
96 | MethodNode clinitMethod = ClassReinitCV.reClinitMethods.remove(hostName);
97 | if(clinitMethod != null)
98 | {
99 | cw.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, Constants.VMVM_RESET_IN_PROGRESS, "Ljava/lang/Thread;", null, null);
100 | clinitMethod.accept(cw);
101 | }
102 | else{
103 | MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC, "__vmvmReClinit", "()V", null, null);
104 | mv.visitCode();
105 | mv.visitMethodInsn(Opcodes.INVOKESTATIC, hostName, "__vmvmReClinit", "()V", false);
106 | mv.visitInsn(Opcodes.RETURN);
107 | mv.visitMaxs(0, 0);
108 | mv.visitEnd();
109 | }
110 | MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "", "()V", null, null);
111 | mv.visitCode();
112 | mv.visitVarInsn(Opcodes.ALOAD, 0);
113 | mv.visitMethodInsn(Opcodes.INVOKESPECIAL, InterfaceReinitializer.INTERNAL_NAME, "", "()V", false);
114 | mv.visitInsn(Opcodes.RETURN);
115 | mv.visitMaxs(0, 0);
116 | mv.visitEnd();
117 | cw.visitEnd();
118 | byte[] b = cw.toByteArray();
119 | if (DEBUG) {
120 | File debugDir = new File("debug");
121 | if (!debugDir.exists())
122 | debugDir.mkdir();
123 | File f = new File("debug/" + newName.replace("/",".") +".class");
124 | FileOutputStream fos = null;
125 | try {
126 | fos = new FileOutputStream(f);
127 | fos.write(cw.toByteArray());
128 | fos.close();
129 | } catch (IOException e) {
130 | e.printStackTrace();
131 | }
132 | }
133 | if (DEBUG) {
134 | ClassReader cr2 = new ClassReader(b);
135 | cr2.accept(new CheckClassAdapter(new ClassWriter(0)), 0);
136 | }
137 | return getUnsafe().defineAnonymousClass(hostClass, b, new Object[0]);
138 | }
139 | private void generateResetter(ClassReader cr, ClassReinitCV cv, String className, ClassLoader loader, ProtectionDomain protectionDomain) {
140 | if (
141 | ((instrumentedClasses.contains(className))
142 | )) //|| hasClass(loader, className + Constants.VMVM_RESET_FIELD)))
143 | return;
144 | String newName = cr.getClassName() + Constants.VMVM_RESET_FIELD;
145 | // System.out.println("Generating " + newName);
146 | instrumentedClasses.add(className);
147 |
148 | try {
149 | ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
150 | cw.visitSource(null, null);
151 |
152 |
153 |
154 | cw.visitEnd();
155 | if (DEBUG) {
156 | File debugDir = new File("debug");
157 | if (!debugDir.exists())
158 | debugDir.mkdir();
159 | File f = new File("debug/" + newName.replace("/", ".") + ".class");
160 | FileOutputStream fos = new FileOutputStream(f);
161 | fos.write(cw.toByteArray());
162 | fos.close();
163 | }
164 | byte[] b = cw.toByteArray();
165 | if (DEBUG) {
166 | ClassReader cr2 = new ClassReader(b);
167 | cr2.accept(new CheckClassAdapter(new ClassWriter(0)), 0);
168 | }
169 | if(alwaysLoadInBootCP(newName))
170 | {
171 | loader = null;
172 | protectionDomain = null;
173 | }
174 | // System.out.println("Done with " + newName + " in " + System.identityHashCode(loader) + ", " + System.identityHashCode(protectionDomain));
175 | getUnsafe().defineClass(newName.replace("/", "."), b, 0, b.length, loader, protectionDomain);
176 |
177 | } catch (Exception ex) {
178 | System.err.println("Problem while creating " + newName);
179 | ex.printStackTrace();
180 |
181 | System.exit(-1);
182 | }
183 | }
184 |
185 | private boolean alwaysLoadInBootCP(String newName) {
186 | return newName.startsWith("org/xml")
187 | || newName.startsWith("org/w3c")
188 | || newName.startsWith("java/")
189 | || newName.startsWith("javax/");
190 | }
191 |
192 | private static HashSet instrumentedInterfaces = new HashSet();
193 |
194 | @SuppressWarnings("restriction")
195 | @Override
196 | public synchronized byte[] transform(ClassLoader loader, String className, Class> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
197 | // if(DEBUG)
198 | // System.err.println("VMVMClassfiletransformer PLAIN1 " + className + " " + loader + " " + classBeingRedefined);
199 | if(className == null)
200 | return null;
201 | if(className.equals("org/junit/internal/requests/ClassRequest"))
202 | {
203 | try {
204 | ClassReader cr = new ClassReader(classfileBuffer);
205 | ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
206 | JUnitInterceptingClassVisitor cv = new JUnitInterceptingClassVisitor(cw);
207 | cr.accept(cv, 0);
208 | if (DEBUG) {
209 | File debugDir = new File("debug");
210 | if (!debugDir.exists())
211 | debugDir.mkdir();
212 | File f = new File("debug/" + className.replace("/", ".") + ".class");
213 | FileOutputStream fos = new FileOutputStream(f);
214 | fos.write(cw.toByteArray());
215 | fos.close();
216 | }
217 | return cw.toByteArray();
218 | } catch (Throwable t) {
219 | t.printStackTrace();
220 | }
221 | }
222 | if (classBeingRedefined == null && isClassThatNeedsReflectionHacked(className)) {
223 | try {
224 | ClassReader cr = new ClassReader(classfileBuffer);
225 | ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
226 | ReflectionFixingCV cv = new ReflectionFixingCV(cw);
227 | cr.accept(cv, 0);
228 | if (DEBUG) {
229 | File debugDir = new File("debug");
230 | if (!debugDir.exists())
231 | debugDir.mkdir();
232 | File f = new File("debug/" + className.replace("/", ".") + ".class");
233 | FileOutputStream fos = new FileOutputStream(f);
234 | fos.write(cw.toByteArray());
235 | fos.close();
236 | }
237 | return cw.toByteArray();
238 | } catch (Throwable t) {
239 | t.printStackTrace();
240 | }
241 | }
242 | if (isIgnoredClass(className)) {
243 | // System.out.println("Skip " + className);
244 | return null;
245 | }
246 | if (classBeingRedefined != null) {
247 | // System.err.println("Redefine!");
248 | // return null;
249 | }
250 | // System.out.println("Inst " + className);
251 | try {
252 | // if(DEBUG)
253 | // System.err.println("VMVMClassfiletransformer PLAIN " + className + " in " + loader);
254 | // new Exception().printStackTrace();
255 | ClassReader cr = new ClassReader(classfileBuffer);
256 |
257 | if(DEBUG)
258 | {
259 | if (DEBUG) {
260 | File debugDir = new File("debug-uninst");
261 | if (!debugDir.exists())
262 | debugDir.mkdir();
263 | File f = new File("debug-uninst/" + className.replace("/", ".") + ".class");
264 | try{
265 | FileOutputStream fos = new FileOutputStream(f);
266 | fos.write(classfileBuffer);
267 | fos.close();
268 | }
269 | catch(Throwable t)
270 | {
271 | t.printStackTrace();
272 | }
273 | }
274 | }
275 | if (DEBUG) {
276 | ClassNode cn = new ClassNode();
277 | cr.accept(cn, 0);
278 | for (Object s : cn.interfaces) {
279 | if (s.equals(Type.getInternalName(VMVMInstrumented.class)))
280 | return null;
281 | // throw new IllegalArgumentException();
282 | }
283 | }
284 | ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
285 | ClassVisitor _cv = cw;
286 | if(DEBUG)
287 | _cv = new CheckClassAdapter(_cv, false);
288 | ClassReinitCV cv = new ClassReinitCV(_cv);
289 | cr.accept(cv, ClassReader.EXPAND_FRAMES);
290 | byte[] ret = cw.toByteArray();
291 |
292 | if (DEBUG) {
293 | File debugDir = new File("debug-plain");
294 | if (!debugDir.exists())
295 | debugDir.mkdir();
296 | File f = new File("debug-plain/" + className.replace("/", ".") + ".class");
297 | FileOutputStream fos = new FileOutputStream(f);
298 | fos.write(ret);
299 | fos.close();
300 | }
301 | if (DEBUG) {
302 | ClassReader cr2 = new ClassReader(ret);
303 | cr2.accept(new CheckClassAdapter(new ClassWriter(0)), 0);
304 | }
305 |
306 | if (DEBUG) {
307 | File debugDir = new File("debug");
308 | if (!debugDir.exists())
309 | debugDir.mkdir();
310 | File f = new File("debug/" + className.replace("/", ".") + ".class");
311 | FileOutputStream fos = new FileOutputStream(f);
312 | fos.write(ret);
313 | fos.close();
314 | }
315 | return ret;
316 | } catch (Throwable t) {
317 | //Make sure that an exception in instrumentation gets printed, rather than squelched
318 | System.err.println("In transformation for " + className + ":");
319 | t.printStackTrace();
320 | return null;
321 | }
322 |
323 | }
324 |
325 | private boolean hasClass(ClassLoader loader, String string) {
326 | try{
327 | if(loader == null)
328 | Class.forName(string.replace("/", "."));
329 | else
330 | loader.loadClass(string.replace("/", "."));
331 | return true;
332 | }
333 | catch(Exception ex)
334 | {
335 | // System.out.println("Couldn't find " + string.replace("/", ".") + " in " + loader);
336 | return false;
337 | }
338 | }
339 |
340 | }
341 |
--------------------------------------------------------------------------------
/vmvm/src/main/java/edu/columbia/cs/psl/vmvm/runtime/inst/ClassReinitCV.java:
--------------------------------------------------------------------------------
1 | package edu.columbia.cs.psl.vmvm.runtime.inst;
2 |
3 | import java.edu.columbia.cs.psl.vmvm.runtime.InterfaceReinitializer;
4 | import java.edu.columbia.cs.psl.vmvm.runtime.Reinitializer;
5 | import edu.columbia.cs.psl.vmvm.runtime.VMVMClassFileTransformer;
6 | import org.objectweb.asm.*;
7 | import org.objectweb.asm.commons.AnalyzerAdapter;
8 | import org.objectweb.asm.commons.JSRInlinerAdapter;
9 | import org.objectweb.asm.tree.FieldNode;
10 | import org.objectweb.asm.tree.MethodNode;
11 | import org.objectweb.asm.tree.TryCatchBlockNode;
12 | import org.objectweb.asm.util.CheckClassAdapter;
13 |
14 | import java.util.HashSet;
15 | import java.util.LinkedList;
16 | import java.util.concurrent.ConcurrentHashMap;
17 |
18 | public class ClassReinitCV extends ClassVisitor {
19 |
20 |
21 | public ClassReinitCV(ClassVisitor parent) {
22 | super(Opcodes.ASM5, new CheckClassAdapter(parent,false));
23 |
24 | }
25 |
26 | private boolean isInterface;
27 | private String className;
28 | private boolean skipFrames;
29 | private LinkedList allStaticFields = new LinkedList();
30 | private HashSet finalFields = new HashSet();
31 | private boolean fixLdcClass;
32 | private boolean isEnum;
33 |
34 | public static ConcurrentHashMap reClinitMethods = new ConcurrentHashMap<>();
35 | public static ConcurrentHashMap reClinitClassHelperVersions = new ConcurrentHashMap<>();
36 |
37 | public HashSet getFinalFields() {
38 | return finalFields;
39 | }
40 | public LinkedList getAllStaticFields() {
41 | return allStaticFields;
42 | }
43 | public MethodNode getReClinitMethod() {
44 | return reClinitMethod;
45 | }
46 |
47 | public int version;
48 |
49 | private HashSet ownersOfStaticFields = new HashSet();
50 |
51 | public HashSet getOwnersOfStaticFields() {
52 | return ownersOfStaticFields;
53 | }
54 |
55 | private HashSet ignoredFields = new HashSet<>();
56 | private boolean isIgnoredField(int acc, String name){
57 | if(name.equals("serialVersionUID"))
58 | return true;
59 | if(name.equals("$VALUES") && isEnum) {
60 | ignoredFields.add(name);
61 | return true;
62 | }
63 | if((acc & Opcodes.ACC_ENUM) != 0) {
64 | ignoredFields.add(name);
65 | return true;
66 | }
67 | return false;
68 | }
69 | @Override
70 | public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
71 | if(!isInterface && !isIgnoredField(access, name))
72 | access = access & ~Opcodes.ACC_FINAL;
73 | if((access & Opcodes.ACC_STATIC) != 0 && !isIgnoredField(access, name)) {
74 | access = access & ~Opcodes.ACC_PRIVATE;
75 | access = access & ~Opcodes.ACC_PROTECTED;
76 | access = access | Opcodes.ACC_PUBLIC;
77 | allStaticFields.add(new FieldNode(access, name, desc, signature, value));
78 | }
79 | return super.visitField(access, name, desc, signature, value);
80 | }
81 |
82 | String[] interfaces;
83 | String superName;
84 |
85 | @Override
86 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
87 | this.isInterface = (access & Opcodes.ACC_INTERFACE) != 0;
88 | this.isEnum = (access & Opcodes.ACC_ENUM) != 0;
89 | this.className = name;
90 | this.fixLdcClass = (version & 0xFFFF) < Opcodes.V1_5;
91 | this.version = version;
92 | this.interfaces = interfaces;
93 | this.superName = superName;
94 | skipFrames = false;
95 | if (version >= 100 || version <= 50)
96 | skipFrames = true;
97 | if ((access & Opcodes.ACC_PUBLIC) == 0) {
98 | access = access & ~Opcodes.ACC_PROTECTED;
99 | access = access & ~Opcodes.ACC_PRIVATE;
100 | access = access | Opcodes.ACC_PUBLIC;
101 | }
102 | reClinitClassHelperVersions.put(this.className, this.version);
103 | //Add signal interface
104 | String[] newInterfaces = new String[interfaces.length + 1];
105 | System.arraycopy(interfaces, 0, newInterfaces, 0, interfaces.length);
106 | newInterfaces[interfaces.length] = "java/edu/columbia/cs/psl/vmvm/runtime/VMVMInstrumented";
107 | super.visit(version, access, name, signature, superName, newInterfaces);
108 | }
109 |
110 | MethodNode clinitMethod;
111 |
112 | @Override
113 | public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
114 | MethodVisitor mv;
115 | if (name.equals("")) {
116 | clinitMethod = new MethodNode(access, name, desc, signature, exceptions);
117 | mv = clinitMethod;
118 | } else
119 | mv = super.visitMethod(access, name, desc, signature, exceptions);
120 | mv = new SystemPropertyLogger(mv);
121 | mv = new ReflectionFixingMV(mv, fixLdcClass, className);
122 | AnalyzerAdapter an = new AnalyzerAdapter(className, access, name, desc, mv);
123 | mv = new ReinitCheckForceMV(an, an, className, name, (access & Opcodes.ACC_STATIC) != 0, fixLdcClass, skipFrames);
124 | mv = new JSRInlinerAdapter(mv, access, name, desc, signature, exceptions);
125 |
126 | return mv;
127 | }
128 |
129 | private MethodNode reClinitMethod;
130 |
131 | @Override
132 | public void visitEnd() {
133 | String classNameWField = className;
134 | if (isInterface)
135 | classNameWField = className + "$$VMVM_RESETTER";
136 |
137 | if (!isInterface) {
138 | super.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_TRANSIENT, Constants.VMVM_RESET_IN_PROGRESS, "Ljava/lang/Thread;", null, null);
139 | super.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_TRANSIENT, Constants.VMVM_NEEDS_RESET, "Z", null, 0);
140 | super.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_TRANSIENT, Constants.VMVM_RESET_FIELD, "L"+ InterfaceReinitializer.INTERNAL_NAME +";", null, null);
141 | }
142 | else
143 | {
144 | super.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL | Opcodes.ACC_SYNTHETIC, Constants.VMVM_RESET_FIELD, "L"+ InterfaceReinitializer.INTERNAL_NAME +";", null, null);
145 | super.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL | Opcodes.ACC_SYNTHETIC, Constants.VMVM_NEEDS_RESET, "Z", null, 0);
146 | }
147 |
148 | //Create a new
149 | MethodVisitor mv = super.visitMethod(Opcodes.ACC_STATIC, "", "()V", null, null);
150 | mv.visitCode();
151 |
152 | if (fixLdcClass) {
153 | mv.visitLdcInsn(className.replace("/", "."));
154 | mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false);
155 | } else
156 | mv.visitLdcInsn(Type.getObjectType(className));
157 | mv.visitMethodInsn(Opcodes.INVOKESTATIC, Reinitializer.INTERNAL_NAME, "clinitCalled", "(Ljava/lang/Class;)L" + InterfaceReinitializer.INTERNAL_NAME + ";", false);
158 | mv.visitFieldInsn(Opcodes.PUTSTATIC, className, Constants.VMVM_RESET_FIELD, "L" + InterfaceReinitializer.INTERNAL_NAME + ";");
159 |
160 | if (!VMVMClassFileTransformer.isIgnoredClass(superName))
161 | mv.visitMethodInsn(Opcodes.INVOKESTATIC, superName, "__vmvmReClinit", "()V", false);
162 | for(String i : interfaces)
163 | {
164 | if(!VMVMClassFileTransformer.isIgnoredClass(i))
165 | {
166 | mv.visitFieldInsn(Opcodes.GETSTATIC, i, Constants.VMVM_RESET_FIELD,"L"+InterfaceReinitializer.INTERNAL_NAME+";");
167 | mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, InterfaceReinitializer.INTERNAL_NAME, "__vmvmReClinit", "()V", false);
168 |
169 | }
170 | }
171 |
172 | if (clinitMethod != null) {
173 | if (clinitMethod.maxStack < 6)
174 | clinitMethod.maxStack = 6;
175 | clinitMethod.accept(mv);
176 | } else {
177 | mv.visitInsn(Opcodes.RETURN);
178 | mv.visitMaxs(6, 0);
179 | mv.visitEnd();
180 | }
181 |
182 | if (isInterface) {
183 | reClinitMethod = new MethodNode(Opcodes.ACC_PUBLIC, "__vmvmReClinit", "()V", null, null);
184 |
185 | mv = new PutStaticHelperMV(reClinitMethod, className, fixLdcClass);
186 | } else
187 | mv = super.visitMethod(Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC, "__vmvmReClinit", "()V", null, null);
188 |
189 | if(isEnum){
190 | mv = new MethodVisitor(Opcodes.ASM5, mv) {
191 | @Override
192 | public void visitFieldInsn(int opcode, String owner, String name, String desc) {
193 | if(opcode == Opcodes.PUTSTATIC && owner.equals(className) && ignoredFields.contains(name))
194 | super.visitInsn(Opcodes.POP);
195 | else
196 | super.visitFieldInsn(opcode, owner, name, desc);
197 | }
198 | };
199 | }
200 | if(reClinitMethod != null)
201 | {
202 | reClinitMethods.put(className, reClinitMethod);
203 | }
204 | final Label finishedClinitCode = new Label();
205 | LabelRemappingMV reLabeler = new LabelRemappingMV(mv, finishedClinitCode);
206 | mv.visitCode();
207 |
208 | if (clinitMethod != null) {
209 | if (clinitMethod.tryCatchBlocks != null) {
210 | for (Object o : clinitMethod.tryCatchBlocks) {
211 | ((TryCatchBlockNode) o).accept(reLabeler);
212 | }
213 | }
214 | }
215 | Label allDone = new Label();
216 |
217 | Label continu = new Label();
218 |
219 | mv.visitFieldInsn(Opcodes.GETSTATIC, className, Constants.VMVM_NEEDS_RESET, "Z");
220 | mv.visitJumpInsn(Opcodes.IFEQ, allDone);
221 | if (fixLdcClass) {
222 | mv.visitLdcInsn(className.replace("/", "."));
223 | mv.visitInsn(Opcodes.ICONST_0);
224 | mv.visitLdcInsn(className.replace("/", "."));
225 | mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false);
226 | mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;", false);
227 | mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;", false);
228 | } else
229 | mv.visitLdcInsn(Type.getObjectType(className));
230 |
231 | mv.visitInsn(Opcodes.DUP);
232 | mv.visitInsn(Opcodes.MONITORENTER);
233 |
234 | mv.visitFieldInsn(Opcodes.GETSTATIC, classNameWField, Constants.VMVM_RESET_IN_PROGRESS, "Ljava/lang/Thread;");
235 | Label notInInit = new Label();
236 | mv.visitJumpInsn(Opcodes.IFNULL, notInInit);
237 |
238 | mv.visitFieldInsn(Opcodes.GETSTATIC, classNameWField, Constants.VMVM_RESET_IN_PROGRESS, "Ljava/lang/Thread;");
239 | mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false);
240 | mv.visitJumpInsn(Opcodes.IF_ACMPEQ, continu);
241 | //If the Class object for C indicates that initialization is in progress for C by some other thread, then release LC and block the current thread until informed that the in-progress initialization has completed, at which time repeat this procedure.
242 | //If the Class object for C indicates that initialization is in progress for C by the current thread, then this must be a recursive request for initialization. Release LC and complete normally
243 |
244 | mv.visitInsn(Opcodes.DUP);
245 | mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "wait", "()V", false);
246 | //XXX what?
247 | mv.visitLabel(notInInit);
248 | if (!skipFrames)
249 | mv.visitFrame(Opcodes.F_NEW, 0, new Object[0], 1, new Object[] { "java/lang/Class" });
250 | mv.visitFieldInsn(Opcodes.GETSTATIC, className, Constants.VMVM_NEEDS_RESET, "Z");
251 | mv.visitJumpInsn(Opcodes.IFEQ, continu);
252 | mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Thread", "currentThread", "()Ljava/lang/Thread;", false);
253 | mv.visitFieldInsn(Opcodes.PUTSTATIC, classNameWField, Constants.VMVM_RESET_IN_PROGRESS, "Ljava/lang/Thread;");
254 | mv.visitInsn(Opcodes.ICONST_0);
255 | mv.visitFieldInsn(Opcodes.PUTSTATIC, className, Constants.VMVM_NEEDS_RESET, "Z");
256 |
257 |
258 | mv.visitInsn(Opcodes.DUP);
259 | mv.visitInsn(Opcodes.MONITOREXIT);
260 | // mv.visitMethodInsn(Opcodes.INVOKESTATIC, className, Constants.VMVM_STATIC_RESET_METHOD, "()V", false);
261 | //do the init
262 |
263 | // if (fixLdcClass) {
264 | // mv.visitLdcInsn(className.replace("/", "."));
265 | // mv.visitInsn(Opcodes.ICONST_0);
266 | // mv.visitLdcInsn(className.replace("/", "."));
267 | // mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false);
268 | // mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;", false);
269 | // mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;", false);
270 | // } else
271 | // mv.visitLdcInsn(Type.getObjectType(className));
272 |
273 | for (FieldNode fn : allStaticFields) {
274 | if(isInterface & fn.value != null)
275 | continue; //constants dont' need to get reset
276 | if (fn.value != null) {
277 | mv.visitLdcInsn(fn.value);
278 | mv.visitFieldInsn(Opcodes.PUTSTATIC, className, fn.name, fn.desc);
279 | } else {
280 | switch (Type.getType(fn.desc).getSort()) {
281 | case Type.OBJECT:
282 | case Type.ARRAY:
283 | mv.visitInsn(Opcodes.ACONST_NULL);
284 | break;
285 | case Type.DOUBLE:
286 | mv.visitInsn(Opcodes.DCONST_0);
287 | break;
288 | case Type.LONG:
289 | mv.visitInsn(Opcodes.ICONST_0);
290 | mv.visitInsn(Opcodes.I2L);
291 | break;
292 | case Type.FLOAT:
293 | mv.visitInsn(Opcodes.FCONST_0);
294 | break;
295 | default:
296 | mv.visitInsn(Opcodes.ICONST_0);
297 | break;
298 | }
299 | mv.visitFieldInsn(Opcodes.PUTSTATIC, className, fn.name, fn.desc);
300 | }
301 | }
302 |
303 | if (!VMVMClassFileTransformer.isIgnoredClass(superName))
304 | mv.visitMethodInsn(Opcodes.INVOKESTATIC, superName, "__vmvmReClinit", "()V", false);
305 |
306 | for(String i : interfaces)
307 | {
308 | if(!VMVMClassFileTransformer.isIgnoredClass(i))
309 | {
310 | mv.visitFieldInsn(Opcodes.GETSTATIC, i, Constants.VMVM_RESET_FIELD,"L"+InterfaceReinitializer.INTERNAL_NAME+";");
311 | mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, InterfaceReinitializer.INTERNAL_NAME, "__vmvmReClinit", "()V", false);
312 |
313 | }
314 | }
315 | if (fixLdcClass) {
316 | mv.visitLdcInsn(className.replace("/", "."));
317 | mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false);
318 | } else
319 | mv.visitLdcInsn(Type.getObjectType(className));
320 | mv.visitMethodInsn(Opcodes.INVOKESTATIC, Reinitializer.INTERNAL_NAME, "reinitCalled", "(Ljava/lang/Class;)V", false);
321 | if (isEnum) {
322 | if (fixLdcClass) {
323 | mv.visitLdcInsn(className.replace("/", "."));
324 | mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false);
325 | } else
326 | mv.visitLdcInsn(Type.getObjectType(className));
327 | mv.visitMethodInsn(Opcodes.INVOKESTATIC, Reinitializer.INTERNAL_NAME, "fixEnum", "(Ljava/lang/Class;)V", false);
328 |
329 | }
330 | int maxStack = 40;
331 | int maxLocals = 40;
332 | if (clinitMethod != null) {
333 | mv.visitInsn(Opcodes.POP);
334 | maxStack = (clinitMethod.maxStack > 3 ? clinitMethod.maxStack : 0);
335 | maxLocals = (clinitMethod.maxLocals > 2 ? clinitMethod.maxLocals : 0);
336 | clinitMethod.instructions.accept(reLabeler);
337 | mv.visitLabel(finishedClinitCode);
338 | if (!skipFrames)
339 | mv.visitFrame(Opcodes.F_NEW, 0, new Object[] {}, 0, new Object[0]);
340 | if (fixLdcClass) {
341 | mv.visitLdcInsn(classNameWField.replace("/", "."));
342 | mv.visitInsn(Opcodes.ICONST_0);
343 | mv.visitLdcInsn(classNameWField.replace("/", "."));
344 | mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false);
345 | mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;", false);
346 | mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;", false);
347 | } else
348 | mv.visitLdcInsn(Type.getObjectType(classNameWField));
349 | }
350 | //If the execution of the class or interface initialization method completes normally, then acquire LC, label the Class object for C as fully initialized, notify all waiting threads, release LC, and complete this procedure normally.
351 | mv.visitInsn(Opcodes.DUP);
352 | mv.visitInsn(Opcodes.MONITORENTER);
353 | mv.visitInsn(Opcodes.ACONST_NULL);
354 | mv.visitFieldInsn(Opcodes.PUTSTATIC, classNameWField, Constants.VMVM_RESET_IN_PROGRESS, "Ljava/lang/Thread;");
355 | mv.visitInsn(Opcodes.DUP);
356 | mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "notifyAll", "()V", false);
357 | //
358 | mv.visitLabel(continu);
359 | if (!skipFrames)
360 | mv.visitFrame(Opcodes.F_NEW, 0, new Object[] {}, 1, new Object[] { "java/lang/Class" });
361 | mv.visitInsn(Opcodes.MONITOREXIT);
362 | mv.visitLabel(allDone);
363 | if (!skipFrames)
364 | mv.visitFrame(Opcodes.F_NEW, 0, new Object[] {}, 0, new Object[0]);
365 |
366 | mv.visitInsn(Opcodes.RETURN);
367 | mv.visitMaxs(maxStack, maxLocals);
368 | mv.visitEnd();
369 |
370 | super.visitEnd();
371 | }
372 |
373 | public void println(MethodVisitor mv, String toPrint) {
374 | mv.visitLdcInsn(toPrint);
375 | mv.visitMethodInsn(Opcodes.INVOKESTATIC, Reinitializer.INTERNAL_NAME, "logMessage", "(Ljava/lang/String;)V", false);
376 | }
377 | }
378 |
--------------------------------------------------------------------------------
/vmvm/src/main/java/edu/columbia/cs/psl/vmvm/runtime/inst/Constants.java:
--------------------------------------------------------------------------------
1 | package edu.columbia.cs.psl.vmvm.runtime.inst;
2 |
3 | public interface Constants {
4 | public static final String VMVM_RESET_IN_PROGRESS = "VMVM_RESET_IN_PROGRESS";
5 | public static final String VMVM_NEEDS_RESET = "VMVM_NEEDS_RESET";
6 | public static final String VMVM_RESET_FIELD = "$$VMVM_RESETTER";
7 | }
8 |
--------------------------------------------------------------------------------
/vmvm/src/main/java/edu/columbia/cs/psl/vmvm/runtime/inst/LabelRemappingMV.java:
--------------------------------------------------------------------------------
1 | package edu.columbia.cs.psl.vmvm.runtime.inst;
2 |
3 | import org.objectweb.asm.Label;
4 | import org.objectweb.asm.MethodVisitor;
5 | import org.objectweb.asm.Opcodes;
6 |
7 | import java.util.HashMap;
8 |
9 | public class LabelRemappingMV extends MethodVisitor {
10 | private HashMap