Browse Source

minor improvements

tags/V1_9_8_M1
Dmitry Mikhaylov 2 years ago
parent
commit
91024728dc

+ 10
- 3
bcel-builder/src/main/java/org/aspectj/apache/bcel/classfile/LocalVariableTable.java View File

return buf.toString(); return buf.toString();
} }


@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
/**
* Returns copy of this attribute using same packed state. Used in unit tests.
*/
public synchronized LocalVariableTable copyFromPackedState() {
if (!isInPackedState) throw new IllegalStateException("No in packed state");
try {
return new LocalVariableTable(nameIndex, length, new DataInputStream(new ByteArrayInputStream(data)), getConstantPool());
} catch (IOException e) {
throw new RuntimeException("Failed to unpack clone", e);
}
} }


/** /**

+ 19
- 18
bcel-builder/src/test/java/org/aspectj/apache/bcel/classfile/tests/LocalVariableTableConcurrencyTest.java View File

* http://www.eclipse.org/legal/epl-v10.html * http://www.eclipse.org/legal/epl-v10.html
* *
* Contributors: * Contributors:
* Andy Clement - initial implementation
* Dmitry Mikhaylov - initial implementation
* ******************************************************************/ * ******************************************************************/


package org.aspectj.apache.bcel.classfile.tests; package org.aspectj.apache.bcel.classfile.tests;
import org.aspectj.apache.bcel.classfile.JavaClass; import org.aspectj.apache.bcel.classfile.JavaClass;
import org.aspectj.apache.bcel.classfile.LocalVariableTable; import org.aspectj.apache.bcel.classfile.LocalVariableTable;
import org.aspectj.apache.bcel.classfile.Method; import org.aspectj.apache.bcel.classfile.Method;
import org.aspectj.apache.bcel.classfile.tests.BcelTestCase;


import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;


protected void setUp() throws Exception { protected void setUp() throws Exception {
super.setUp(); super.setUp();

for (int i = 0; i < nThreads; i++) workers[i] = Executors.newSingleThreadExecutor(); for (int i = 0; i < nThreads; i++) workers[i] = Executors.newSingleThreadExecutor();


JavaClass clazz = getClassFromJar("SimpleGenericsProgram"); JavaClass clazz = getClassFromJar("SimpleGenericsProgram");

Method mainMethod = getMethod(clazz,"main"); Method mainMethod = getMethod(clazz,"main");
Code codeAttr = (Code) findAttribute("Code",mainMethod.getAttributes()); Code codeAttr = (Code) findAttribute("Code",mainMethod.getAttributes());

reference =
(LocalVariableTable) findAttribute("LocalVariableTable",codeAttr.getAttributes());
}

private LocalVariableTable createReferenceCopy() {
try {
return (LocalVariableTable) reference.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException("Faileed to clone LocalVariableTable", e);
}
reference = (LocalVariableTable) findAttribute("LocalVariableTable",codeAttr.getAttributes());
} }


/**
* Try to hit concurrency bug in org.aspectj.apache.bcel.classfile.LocalVariableTable.unpack().
* We do so by running unpack() on same instance with multiple threads, and artificially
* delaying all threads but first so that they enter unpack() the moment first thread is about to leave it.
*
* Since this test relies on empirically obtained access pattern and number of iterations,
* it never has 100% probability of hitting the bug. If it fails - there is certainly a bug.
* If it passes, it could mean anything - fully correct code or slightly changed execution order preventing
* threads to collide at problematic location.
*
* As such, it is not really good for unit testing.
*/
public void testLocalVariableTableAttributeConcurrency() throws RuntimeException, InterruptedException { public void testLocalVariableTableAttributeConcurrency() throws RuntimeException, InterruptedException {
final AtomicReference<RuntimeException> error = new AtomicReference<>(); final AtomicReference<RuntimeException> error = new AtomicReference<>();
for (int i = 0; i < 100000; i++) {
LocalVariableTable sharedInstance = createReferenceCopy();
for (int i = 0; i < 10000; i++) {
LocalVariableTable sharedInstance = reference.copyFromPackedState();
CountDownLatch preStart = new CountDownLatch(nThreads); CountDownLatch preStart = new CountDownLatch(nThreads);
Semaphore start = new Semaphore(0); Semaphore start = new Semaphore(0);
CountDownLatch finish = new CountDownLatch(nThreads); CountDownLatch finish = new CountDownLatch(nThreads);
workers[j].execute(() -> { workers[j].execute(() -> {
preStart.countDown(); preStart.countDown();
start.acquireUninterruptibly(); start.acquireUninterruptibly();
// trying to trigger concurrent unpacking - one tread should enter unpack() when other is about to leave it
if (needsDelay) createReferenceCopy().getTableLength();
// trying to trigger concurrent unpacking bug - one tread should enter unpack() when other is about to leave it
if (needsDelay) reference.copyFromPackedState().getTableLength();
try { try {
sharedInstance.getTableLength(); sharedInstance.getTableLength();
} }

Loading…
Cancel
Save