Browse Source

Merge branch 'master' into master

tags/rel_3_29_0_ga
Shigeru Chiba 2 years ago
parent
commit
da39aa8050
No account linked to committer's email address
85 changed files with 1246 additions and 56 deletions
  1. 28
    0
      .github/workflows/maven.yml
  2. 3
    1
      README.md
  3. 24
    5
      Readme.html
  4. 14
    1
      build.xml
  5. BIN
      javassist.jar
  6. 5
    4
      pom.xml
  7. 1
    1
      src/main/META-INF/MANIFEST.MF
  8. 3
    3
      src/main/javassist/CtClass.java
  9. 19
    6
      src/main/javassist/CtClassType.java
  10. 1
    0
      src/main/javassist/Loader.java
  11. 22
    0
      src/main/javassist/bytecode/AnnotationDefaultAttribute.java
  12. 1
    1
      src/main/javassist/bytecode/AttributeInfo.java
  13. 16
    0
      src/main/javassist/bytecode/LocalVariableAttribute.java
  14. 8
    0
      src/main/javassist/bytecode/MethodParametersAttribute.java
  15. 3
    2
      src/main/javassist/bytecode/SignatureAttribute.java
  16. 14
    5
      src/main/javassist/bytecode/StackMapTable.java
  17. 11
    11
      src/main/javassist/bytecode/analysis/Type.java
  18. 25
    0
      src/main/javassist/bytecode/annotation/ArrayMemberValue.java
  19. 15
    0
      src/main/javassist/bytecode/annotation/ClassMemberValue.java
  20. 15
    0
      src/main/javassist/bytecode/annotation/EnumMemberValue.java
  21. 9
    0
      src/main/javassist/bytecode/annotation/MemberValue.java
  22. 12
    2
      src/main/javassist/bytecode/stackmap/TypeData.java
  23. 1
    1
      src/main/javassist/compiler/MemberCodeGen.java
  24. 1
    1
      src/main/javassist/compiler/TypeChecker.java
  25. 0
    1
      src/main/javassist/util/proxy/SecurityActions.java
  26. 1
    0
      src/test/javassist/JvstTest.java
  27. 2
    4
      src/test/javassist/JvstTest2.java
  28. 4
    0
      src/test/javassist/JvstTest4.java
  29. 11
    4
      src/test/javassist/bytecode/BytecodeTest.java
  30. 170
    0
      src/test/javassist/bytecode/StackMapTest.java
  31. 21
    0
      src/test/test/javassist/convert/ArrayAccessReplaceTest2.java
  32. 761
    0
      src/test/test/javassist/convert/InstrumentationTarget.java
  33. BIN
      src/test/test2/AddCatchForConstructor.class
  34. BIN
      src/test/test2/AddLocalVar.class
  35. BIN
      src/test/test2/ArrayInit.class
  36. BIN
      src/test/test2/ArrayLenTest.class
  37. BIN
      src/test/test2/ArrayLength.class
  38. BIN
      src/test/test2/Brennan.class
  39. BIN
      src/test/test2/CodeGen.class
  40. BIN
      src/test/test2/CodeGen2.class
  41. BIN
      src/test/test2/ConstBody.class
  42. BIN
      src/test/test2/ConstField.class
  43. BIN
      src/test/test2/DotClass.class
  44. BIN
      src/test/test2/DotClass2.class
  45. BIN
      src/test/test2/DotClass4.class
  46. BIN
      src/test/test2/Finally.class
  47. BIN
      src/test/test2/Imported.class
  48. BIN
      src/test/test2/Importer.class
  49. BIN
      src/test/test2/IncOp.class
  50. BIN
      src/test/test2/Inherit.class
  51. BIN
      src/test/test2/Inner.class
  52. 2
    3
      src/test/test2/Inner.java
  53. 23
    0
      src/test/test2/Inner2.java
  54. BIN
      src/test/test2/InsertAt.class
  55. BIN
      src/test/test2/InsertLocal.class
  56. BIN
      src/test/test2/LocalVar.class
  57. BIN
      src/test/test2/MakeStaticMethod.class
  58. BIN
      src/test/test2/MethodCall.class
  59. BIN
      src/test/test2/Nested$Inner3.class
  60. BIN
      src/test/test2/Nested.class
  61. BIN
      src/test/test2/Nested2$Inner.class
  62. BIN
      src/test/test2/Nested2.class
  63. BIN
      src/test/test2/Nested3$Inner.class
  64. BIN
      src/test/test2/Nested3.class
  65. BIN
      src/test/test2/Nested4$Inner.class
  66. BIN
      src/test/test2/Nested4.class
  67. BIN
      src/test/test2/NewArray.class
  68. BIN
      src/test/test2/NewExprInTry.class
  69. BIN
      src/test/test2/NewExprTry.class
  70. BIN
      src/test/test2/NewOp.class
  71. BIN
      src/test/test2/NullArgTest.class
  72. BIN
      src/test/test2/Remove.class
  73. BIN
      src/test/test2/RemoveCall.class
  74. BIN
      src/test/test2/ReplaceClassName.class
  75. BIN
      src/test/test2/SetExceptions.class
  76. BIN
      src/test/test2/SetSuper.class
  77. BIN
      src/test/test2/SetSuperIntf.class
  78. BIN
      src/test/test2/SetSuperParent.class
  79. BIN
      src/test/test2/StaticFinal.class
  80. BIN
      src/test/test2/StaticMember.class
  81. BIN
      src/test/test2/StaticMember2.class
  82. BIN
      src/test/test2/SuperCall.class
  83. BIN
      src/test/test2/SuperInterface3.class
  84. BIN
      src/test/test2/Switch.class
  85. BIN
      src/test/test2/Synch.class

+ 28
- 0
.github/workflows/maven.yml View File

@@ -0,0 +1,28 @@
# This workflow will build a Java project with Maven
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven

name: Java CI with Maven

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
build:

runs-on: ubuntu-latest
strategy:
matrix:
os: [ ubuntu-latest ]
java-version: [ 11.0.3, 11 ]
steps:
- uses: actions/checkout@v2
- name: Set up JDK ${{ matrix.java-version }}
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java-version }}
distribution: 'zulu'
- name: Build with Maven
run: mvn -B package --file pom.xml

+ 3
- 1
README.md View File

@@ -1,7 +1,9 @@
[![Java CI with Maven](https://github.com/jboss-javassist/javassist/actions/workflows/maven.yml/badge.svg)](https://github.com/jboss-javassist/javassist/actions/workflows/maven.yml)

Java bytecode engineering toolkit
### [Javassist version 3](http://www.javassist.org)

Copyright (C) 1999-2019 by Shigeru Chiba, All rights reserved.
Copyright (C) 1999-2021 by Shigeru Chiba, All rights reserved.

Javassist (JAVA programming ASSISTant) makes Java bytecode manipulation
simple. It is a class library for editing bytecodes in Java; it enables Java

+ 24
- 5
Readme.html View File

@@ -7,7 +7,7 @@

<h1>Javassist version 3</h1>

<h3>Copyright (C) 1999-2019 by Shigeru Chiba, All rights reserved.</h3>
<h3>Copyright (C) 1999-2021 by Shigeru Chiba, All rights reserved.</h3>

<p><br></p>

@@ -277,11 +277,31 @@ To run, first type the following commands:
<p>Javassist provides a class file viewer for debugging. For more details,
see javassist.Dump.

<p><br>
<h2>Release</h2>

<p></p>When you want to upload a new release to Sonatype, do the following steps:</p>
<ul>
<li>1. Switch to jdk11 in bash shell</li>
<li>2. pull latest from git master branch</li>
<li>3. <code>mvn -P centralRelease javadoc:jar deploy</code></li>
<li>4. close and release via <a href="https://oss.sonatype.org/index.html#stagingRepositories">https://oss.sonatype.org/index.html#stagingRepositories</a></li>
</ul>

<p><br/></p>

<h2>Changes</h2>

<p>-version 3.27
<p>-version 3.29
<ul>
<li>GitHub Issue #378.
</li>

<p>-version 3.28 on May 8, 2021
<ul>
<li>GitHub Issue #305, #328, #339, #350, #357, and PR #363.
</ul>

<p>-version 3.27 on March 19, 2020
<ul>
<li>GitHub Issue #271 (PR #279), #280 (PR #281), #282, and PR #294.
</ul>
@@ -300,7 +320,7 @@ see javassist.Dump.
<p>-version 3.24.1 on December 9, 2018
<ul>
<li>GitHub Issue #228, #229</li>
<ul>
</ul>
</p>

<p>-version 3.24 on November 1, 2018
@@ -889,7 +909,6 @@ and all other contributors for their contributions.

<hr>
<a href="http://www.javassist.org">Shigeru Chiba</a>
(Email: <tt>chiba@javassist.org</tt>)

</body>
</html>

+ 14
- 1
build.xml View File

@@ -6,7 +6,7 @@

<project name="javassist" default="jar" basedir=".">

<property name="dist-version" value="javassist-3.26.0-GA"/>
<property name="dist-version" value="javassist-3.28.0-GA"/>

<property environment="env"/>
<property name="target.jar" value="javassist.jar"/>
@@ -102,6 +102,19 @@
</target>

<target name="runtest" depends="jar,test-compile">
<copy file="${test.lib.dir}/empty.jar"
tofile="${test.lib.dir}/emptyorig.jar"
preservelastmodified="true" />
<junit fork="true" printsummary="true" dir="${test.run.dir}">
<classpath refid="test.classpath"/>
<formatter type="xml" extension=".xml"/>
<test name="javassist.JvstTest" outfile="TestLog" />
</junit>
<move file="${test.lib.dir}/emptyorig.jar"
tofile="${test.lib.dir}/empty.jar" />
</target>

<target name="runtest8" depends="jar,test-compile">
<copy file="${test.lib.dir}/empty.jar"
tofile="${test.lib.dir}/emptyorig.jar"
preservelastmodified="true" />

BIN
javassist.jar View File


+ 5
- 4
pom.xml View File

@@ -7,7 +7,7 @@
Javassist (JAVA programming ASSISTant) makes Java bytecode manipulation
simple. It is a class library for editing bytecodes in Java.
</description>
<version>3.26.0-GA</version>
<version>3.28.0-GA</version>
<name>Javassist</name>
<url>http://www.javassist.org/</url>

@@ -40,7 +40,7 @@
-->
<license>
<name>Apache License 2.0</name>
<url>http://www.apache.org/licenses/</url>
<url>https://www.apache.org/licenses/LICENSE-2.0</url>
</license>
</licenses>

@@ -202,7 +202,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.0.1</version>
<version>3.2.0</version>
<configuration>
<attach>true</attach>
<excludePackageNames>javassist.compiler:javassist.convert:javassist.scopedpool:javassist.bytecode.stackmap</excludePackageNames>
@@ -211,6 +211,7 @@ Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.</i>]]></bottom>
<show>public</show>
<nohelp>true</nohelp>
<doclint>none</doclint>
<source>8</source>
</configuration>
</plugin>
<plugin>
@@ -320,7 +321,7 @@ Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.</i>]]></bottom>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<version>[4.13.1,)</version>
<scope>test</scope>
</dependency>
<dependency>

+ 1
- 1
src/main/META-INF/MANIFEST.MF View File

@@ -1,5 +1,5 @@
Specification-Title: Javassist
Specification-Vendor: Shigeru Chiba, www.javassist.org
Specification-Version: 3.26.0-GA
Specification-Version: 3.29.0-SNAPSHOT
Main-Class: javassist.CtClass
Automatic-Module-Name: org.javassist

+ 3
- 3
src/main/javassist/CtClass.java View File

@@ -69,7 +69,7 @@ public abstract class CtClass {
/**
* The version number of this release.
*/
public static final String version = "3.26.0-GA";
public static final String version = "3.29.0-SNAPSHOT";

/**
* Prints the version number and the copyright notice.
@@ -80,7 +80,7 @@ public abstract class CtClass {
*/
public static void main(String[] args) {
System.out.println("Javassist version " + CtClass.version);
System.out.println("Copyright (C) 1999-2019 Shigeru Chiba."
System.out.println("Copyright (C) 1999-2021 Shigeru Chiba."
+ " All Rights Reserved.");
}

@@ -1423,7 +1423,7 @@ public abstract class CtClass {
public void detach() {
ClassPool cp = getClassPool();
CtClass obj = cp.removeCached(getName());
if (obj != this)
if (obj != null && obj != this)
cp.cacheCtClass(getName(), obj, false);
}


+ 19
- 6
src/main/javassist/CtClassType.java View File

@@ -179,6 +179,7 @@ class CtClassType extends CtClass {
}

public ClassFile getClassFile3(boolean doCompress) {
// quick path - no locking
ClassFile cfile = classfile;
if (cfile != null)
return cfile;
@@ -186,17 +187,29 @@ class CtClassType extends CtClass {
if (doCompress)
classPool.compress();

if (rawClassfile != null) {
byte[] rcfile;
synchronized (this) {
// repeat under lock to make sure we get a consistent result (classfile might have been set by another thread)
cfile = classfile;
if (cfile != null)
return cfile;

rcfile = rawClassfile;
}

if (rcfile != null) {
final ClassFile cf;
try {
ClassFile cf = new ClassFile(new DataInputStream(
new ByteArrayInputStream(rawClassfile)));
rawClassfile = null;
getCount = GET_THRESHOLD;
return setClassFile(cf);
cf = new ClassFile(new DataInputStream(new ByteArrayInputStream(rcfile)));
}
catch (IOException e) {
throw new RuntimeException(e.toString(), e);
}
getCount = GET_THRESHOLD;
synchronized (this) {
rawClassfile = null;
return setClassFile(cf);
}
}

InputStream fin = null;

+ 1
- 0
src/main/javassist/Loader.java View File

@@ -444,6 +444,7 @@ public class Loader extends ClassLoader {
if (doDelegation)
if (name.startsWith("java.")
|| name.startsWith("javax.")
|| name.startsWith("jdk.internal.")
|| name.startsWith("sun.")
|| name.startsWith("com.sun.")
|| name.startsWith("org.w3c.")

+ 22
- 0
src/main/javassist/bytecode/AnnotationDefaultAttribute.java View File

@@ -117,6 +117,28 @@ public class AnnotationDefaultAttribute extends AttributeInfo {
}
}

@Override
void renameClass(String oldname, String newname) {
try {
MemberValue defaultValue = getDefaultValue();
defaultValue.renameClass(oldname, newname);
setDefaultValue(defaultValue);
} catch (Exception e) {
// ignore
}
}

@Override
void renameClass(Map<String, String> classnames) {
try {
MemberValue defaultValue = getDefaultValue();
defaultValue.renameClass(classnames);
setDefaultValue(defaultValue);
} catch (Exception e) {
// ignore
}
}

/**
* Obtains the default value represented by this attribute.
*/

+ 1
- 1
src/main/javassist/bytecode/AttributeInfo.java View File

@@ -254,7 +254,7 @@ public class AttributeInfo {
/* The following two methods are used to implement
* ClassFile.renameClass().
* Only CodeAttribute, LocalVariableAttribute,
* AnnotationsAttribute, and SignatureAttribute
* AnnotationDefaultAttribute, AnnotationsAttribute, and SignatureAttribute
* override these methods.
*/
void renameClass(String oldname, String newname) {}

+ 16
- 0
src/main/javassist/bytecode/LocalVariableAttribute.java View File

@@ -217,6 +217,22 @@ public class LocalVariableAttribute extends AttributeInfo {
return getConstPool().getUtf8Info(nameIndex(i));
}

/**
* Returns the name of the local variable with given index.
* If you want to get the parameter name of method with correct order,
* you should using this method.
*
* @param index the index of the local variable.
*/
public String variableNameByIndex(int index) {
for (int i = 0; i < tableLength(); i++) {
if (index(i) == index) {
return variableName(i);
}
}
throw new ArrayIndexOutOfBoundsException();
}

/**
* Returns the value of
* <code>local_variable_table[i].descriptor_index</code>.

+ 8
- 0
src/main/javassist/bytecode/MethodParametersAttribute.java View File

@@ -56,6 +56,14 @@ public class MethodParametersAttribute extends AttributeInfo {
return ByteArray.readU16bit(info, i * 4 + 1);
}

/**
* Returns the name of the i-th element of <code>parameters</code>.
* @param i the position of the parameter.
*/
public String parameterName(int i) {
return getConstPool().getUtf8Info(name(i));
}

/**
* Returns the value of <code>access_flags</code> of the i-th element of <code>parameters</code>.
*

+ 3
- 2
src/main/javassist/bytecode/SignatureAttribute.java View File

@@ -150,8 +150,9 @@ public class SignatureAttribute extends AttributeInfo {
}
}
catch (IndexOutOfBoundsException e) { break; }
nameBufs.add(nameBuf);
genericParamBufs.add(genericParamBuf);

nameBufs.add(nameBuf);
genericParamBufs.add(genericParamBuf);
i = k + 1;
String name = String.join("$", nameBufs.toArray(new StringBuilder[0]));

+ 14
- 5
src/main/javassist/bytecode/StackMapTable.java View File

@@ -204,8 +204,11 @@ public class StackMapTable extends AttributeInfo {
}
else if (type < 128)
pos = sameLocals(pos, type);
else if (type < 247)
throw new BadBytecode("bad frame_type in StackMapTable");
else if (type < 247) {
throw new BadBytecode(
"bad frame_type " + type + " in StackMapTable (pos: "
+ pos + ", frame no.:" + nth + ")");
}
else if (type == 247) // SAME_LOCALS_1_STACK_ITEM_EXTENDED
pos = sameLocals(pos, type);
else if (type < 251) {
@@ -881,16 +884,21 @@ public class StackMapTable extends AttributeInfo {
position = oldPos + offsetDelta + (oldPos == 0 ? 0 : 1);
boolean match;
if (exclusive)
match = oldPos < where && where <= position;
// We optimize this expression by hand:
// match = (oldPos == 0 && where == 0 && (0 < position || 0 == position))
// || oldPos < where && where <= position;
match = (oldPos == 0 && where == 0)
|| oldPos < where && where <= position;
else
match = oldPos <= where && where < position;

if (match) {
int current = info[pos] & 0xff;
int newDelta = offsetDelta + gap;
position += gap;
if (newDelta < 64)
info[pos] = (byte)(newDelta + base);
else if (offsetDelta < 64) {
else if (offsetDelta < 64 && current != entry) {
byte[] newinfo = insertGap(info, pos, 2);
newinfo[pos] = (byte)entry;
ByteArray.write16bit(newDelta, newinfo, pos + 1);
@@ -931,7 +939,8 @@ public class StackMapTable extends AttributeInfo {
position = oldPos + offsetDelta + (oldPos == 0 ? 0 : 1);
boolean match;
if (exclusive)
match = oldPos < where && where <= position;
match = (oldPos == 0 && where == 0)
|| oldPos < where && where <= position;
else
match = oldPos <= where && where < position;


+ 11
- 11
src/main/javassist/bytecode/analysis/Type.java View File

@@ -15,9 +15,7 @@
*/
package javassist.bytecode.analysis;

import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.*;

import javassist.ClassPool;
import javassist.CtClass;
@@ -496,24 +494,26 @@ public class Type {
if (typeMap == null||typeMap.isEmpty())
alterMap.clear();

for (String name:alterMap.keySet())
Iterator<String> it = alterMap.keySet().iterator();
while (it.hasNext()) {
String name = it.next();
if (!typeMap.containsKey(name))
alterMap.remove(name);
it.remove();
}

// Reduce to subinterfaces
// This does not need to be recursive since we make a copy,
// and that copy contains all super types for the whole hierarchy
for (CtClass intf:alterMap.values()) {
CtClass[] interfaces;
Collection<CtClass> interfaces = new ArrayList<>();
for (CtClass intf : alterMap.values()) {
try {
interfaces = intf.getInterfaces();
interfaces.addAll(Arrays.asList(intf.getInterfaces()));
} catch (NotFoundException e) {
throw new RuntimeException(e);
}

for (CtClass c:interfaces)
alterMap.remove(c.getName());
}
for (CtClass c : interfaces)
alterMap.remove(c.getName());

return alterMap;
}

+ 25
- 0
src/main/javassist/bytecode/annotation/ArrayMemberValue.java View File

@@ -18,6 +18,7 @@ package javassist.bytecode.annotation;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.Map;

import javassist.ClassPool;
import javassist.bytecode.ConstPool;
@@ -87,6 +88,30 @@ public class ArrayMemberValue extends MemberValue {
return a.getClass();
}

@Override
public void renameClass(String oldname, String newname) {
if (type != null) {
type.renameClass(oldname, newname);
}
if (values != null) {
for (MemberValue value : values) {
value.renameClass(oldname, newname);
}
}
}

@Override
public void renameClass(Map<String, String> classnames) {
if (type != null) {
type.renameClass(classnames);
}
if (values != null) {
for (MemberValue value : values) {
value.renameClass(classnames);
}
}
}

/**
* Obtains the type of the elements.
*

+ 15
- 0
src/main/javassist/bytecode/annotation/ClassMemberValue.java View File

@@ -18,6 +18,7 @@ package javassist.bytecode.annotation;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Map;

import javassist.ClassPool;
import javassist.bytecode.BadBytecode;
@@ -95,6 +96,20 @@ public class ClassMemberValue extends MemberValue {
return loadClass(cl, "java.lang.Class");
}

@Override
public void renameClass(String oldname, String newname) {
String value = cp.getUtf8Info(valueIndex);
String newValue = Descriptor.rename(value, oldname, newname);
setValue(Descriptor.toClassName(newValue));
}

@Override
public void renameClass(Map<String, String> classnames) {
String value = cp.getUtf8Info(valueIndex);
String newValue = Descriptor.rename(value, classnames);
setValue(Descriptor.toClassName(newValue));
}

/**
* Obtains the value of the member.
*

+ 15
- 0
src/main/javassist/bytecode/annotation/EnumMemberValue.java View File

@@ -18,6 +18,7 @@ package javassist.bytecode.annotation;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Map;

import javassist.ClassPool;
import javassist.bytecode.ConstPool;
@@ -76,6 +77,20 @@ public class EnumMemberValue extends MemberValue {
return loadClass(cl, getType());
}

@Override
public void renameClass(String oldname, String newname) {
String type = cp.getUtf8Info(typeIndex);
String newType = Descriptor.rename(type, oldname, newname);
setType(Descriptor.toClassName(newType));
}

@Override
public void renameClass(Map<String, String> classnames) {
String type = cp.getUtf8Info(typeIndex);
String newType = Descriptor.rename(type, classnames);
setType(Descriptor.toClassName(newType));
}

/**
* Obtains the enum type name.
*

+ 9
- 0
src/main/javassist/bytecode/annotation/MemberValue.java View File

@@ -18,6 +18,7 @@ package javassist.bytecode.annotation;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Map;

import javassist.ClassPool;
import javassist.bytecode.ConstPool;
@@ -74,6 +75,14 @@ public abstract class MemberValue {
return classname;
}

/* The following two methods are used to implement
* ClassFile.renameClass().
* Only ArrayMemberValue, ClassMemberValue, EnumMemberValue
* override these methods.
*/
public void renameClass(String oldname, String newname) {}
public void renameClass(Map<String, String> classnames) {}

/**
* Accepts a visitor.
*/

+ 12
- 2
src/main/javassist/bytecode/stackmap/TypeData.java View File

@@ -206,7 +206,12 @@ public abstract class TypeData {
}

@Override
public boolean eq(TypeData d) { return getName().equals(d.getName()); }
public boolean eq(TypeData d) {
if (d.isUninit())
return d.eq(this);
else
return getName().equals(d.getName());
}
}

/* a type variable representing a class type or a basic type.
@@ -853,7 +858,12 @@ public abstract class TypeData {
}

@Override
public boolean eq(TypeData d) { return name.equals(d.getName()); }
public boolean eq(TypeData d) {
if (d.isUninit())
return d.eq(this);
else
return name.equals(d.getName());
}

@Override
public void setType(String typeName, ClassPool cp) throws BadBytecode {}

+ 1
- 1
src/main/javassist/compiler/MemberCodeGen.java View File

@@ -648,7 +648,7 @@ public class MemberCodeGen extends CodeGen {
throw new CompileError("no such constructor: " + targetClass.getName());

if (declClass != thisClass && AccessFlag.isPrivate(acc)) {
if (declClass.getClassFile().getMajorVersion() < ClassFile.JAVA_11
if (declClass.getClassFile().getMajorVersion() < ClassFile.JAVA_8
|| !isFromSameDeclaringClass(declClass, thisClass)) {
desc = getAccessibleConstructor(desc, declClass, minfo);
bytecode.addOpcode(Opcode.ACONST_NULL); // the last parameter

+ 1
- 1
src/main/javassist/compiler/TypeChecker.java View File

@@ -933,7 +933,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
}
}

throw new CompileError("bad filed access");
throw new CompileError("bad field access");
}

private CtField fieldAccess2(Expr e, String jvmClassName) throws CompileError {

+ 0
- 1
src/main/javassist/util/proxy/SecurityActions.java View File

@@ -213,7 +213,6 @@ class SecurityActions extends SecurityManager
if (e.getCause() instanceof NoSuchFieldException)
throw new ClassNotFoundException("No such instance.", e.getCause());
if (e.getCause() instanceof IllegalAccessException
|| e.getCause() instanceof IllegalAccessException
|| e.getCause() instanceof SecurityException)
throw new ClassNotFoundException("Security denied access.", e.getCause());
throw new RuntimeException(e.getCause());

+ 1
- 0
src/test/javassist/JvstTest.java View File

@@ -1179,6 +1179,7 @@ public class JvstTest extends JvstTestRoot {
suite.addTestSuite(test.javassist.proxy.ProxySimpleTest.class);
suite.addTestSuite(test.javassist.bytecode.analysis.AnalyzerTest.class);
suite.addTestSuite(test.javassist.convert.ArrayAccessReplaceTest.class);
suite.addTestSuite(test.javassist.convert.ArrayAccessReplaceTest2.class);
suite.addTestSuite(test.javassist.bytecode.analysis.DomTreeTest.class);
return suite;
}

+ 2
- 4
src/test/javassist/JvstTest2.java View File

@@ -275,10 +275,8 @@ public class JvstTest2 extends JvstTestRoot {
String src =
"public void sampleMethod() throws Exception {"
+ "java.util.Properties props = new java.util.Properties();"
+ "java.rmi.activation.ActivationGroupDesc.CommandEnvironment ace "
+ " = null;"
+ "java.rmi.activation.ActivationGroupDesc agd "
+ " = new java.rmi.activation.ActivationGroupDesc(props,ace);}";
+ "test2.Inner2.Child ace = null;"
+ "test2.Inner2 agd = new test2.Inner2(props, ace);}";
CtMethod newmethod = CtNewMethod.make(src, target);
target.addMethod(newmethod);


+ 4
- 0
src/test/javassist/JvstTest4.java View File

@@ -1019,11 +1019,15 @@ public class JvstTest4 extends JvstTestRoot {
assertEquals(2, attr.size());
assertEquals("i", cp.getUtf8Info(attr.name(0)));
assertEquals("s", cp.getUtf8Info(attr.name(1)));
assertEquals("i", attr.parameterName(0));
assertEquals("s", attr.parameterName(1));

attr = (MethodParametersAttribute)attr.copy(cp, null);
assertEquals(2, attr.size());
assertEquals("i", cp.getUtf8Info(attr.name(0)));
assertEquals("s", cp.getUtf8Info(attr.name(1)));
assertEquals("i", attr.parameterName(0));
assertEquals("s", attr.parameterName(1));
}

// JIRA JASSIST-220

+ 11
- 4
src/test/javassist/bytecode/BytecodeTest.java View File

@@ -354,6 +354,9 @@ public class BytecodeTest extends TestCase {
assertEquals("I", ainfo2.descriptor(i));
}
print("**** end ***");

assertEquals("this", ainfo2.variableNameByIndex(0));
assertEquals("i", ainfo2.variableNameByIndex(1));
}

public void testAnnotations() throws Exception {
@@ -472,10 +475,14 @@ public class BytecodeTest extends TestCase {
changeMsig2("<S:Ljava/lang/Object;>(TS;[TS;)Ljava/lang/Objec;", "java/lang/Object",
"<S:Ljava/lang/Object2;>(TS;[TS;)Ljava/lang/Objec;", "java/lang/Object2");
String sig = "<T:Ljava/lang/Exception;>LPoi$Foo<Ljava/lang/String;>;LBar;LBar2;";
//String res = "<T:Ljava/lang/Exception;>LPoi$Foo<Ljava/lang/String2;>;LBar;LBar2;";
changeMsig(sig, "java/lang/String", sig, "java/lang/String2");
changeMsig2(sig, "java/lang/String", sig, "java/lang/String2");
changeMsig("Ltest<TE;>.List;", "ist", "Ltest<TE;>.List;", "IST");
String res = "<T:Ljava/lang/Exception;>LPoi$Foo<Ljava/lang/String2;>;LBar;LBar2;";
changeMsig(sig, "java/lang/String", res, "java/lang/String2");
changeMsig2(sig, "java/lang/String", res, "java/lang/String2");
//changeMsig("Ltest<TE;>.List;", "ist", "Ltest<TE;>.List;", "IST");
changeMsig("Ljava/lang/String<Ljava/lang/Object;>;", "java/lang/String",
"Ljava/lang/String2<Ljava/lang/Object;>;", "java/lang/String2");
changeMsig2("Ljava/lang/String<Ljava/lang/Object;>;", "java/lang/String",
"Ljava/lang/String2<Ljava/lang/Object;>;", "java/lang/String2");
}

private void changeMsig(String old, String oldname, String result, String newname) {

+ 170
- 0
src/test/javassist/bytecode/StackMapTest.java View File

@@ -12,6 +12,7 @@ import java.lang.reflect.Method;
import javassist.ClassPool;
import javassist.CodeConverter;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtMethod;
import javassist.CtNewConstructor;
import javassist.CtNewMethod;
@@ -830,4 +831,173 @@ public class StackMapTest extends TestCase {

return null;
}

public static class C7 {
public int value;
public static int value2;
public C7() { this(3); }
public C7(int i) {
value = i;
}
}

public void testIssue328() throws Exception {
CtClass cc = loader.get("javassist.bytecode.StackMapTest$C7");
CtConstructor cons = cc.getDeclaredConstructor(new CtClass[] { CtClass.intType });
cons.insertBefore("if ($1 < 0) { super(); if (value2 > 0) { value2++; } return; }");
cc.writeFile();
Object t1 = make(cc.getName());
}

public static class C8 {
int value = 0;
int loop = 0;
int loop2 = 1;
public void foo(int i) { value += i; }
public void bar(int i) { value += i; }
public void foo2(int i) { value += i; }
public void bar2(int i) { value += i; }
}

public static class C9 extends C8 {
public void foo(int i) {
while(true) {
loop--;
if (loop < 0)
break;
}
value += i;
}
public void bar(int i) {
value += i;
for (int k = 0; i < 10; k++)
loop += k;
}
public void foo2(int i) {
while(true) {
loop2--;
if (loop2 < 0)
break;
}
value += i;
for (int k = 0; k < 3; k++)
loop2--;
}
public void bar2(int i) {
value += i;
for (int k = 0; i < 10; k++)
loop += k;
}
public int run() {
foo(1);
bar(10);
foo2(100);
bar2(1000);
return value;
}
}

public void testIssue339() throws Exception {
CtClass cc0 = loader.get("javassist.bytecode.StackMapTest$C8");
CtClass cc = loader.get("javassist.bytecode.StackMapTest$C9");

testIssue339b(cc, cc0, "foo", true);
testIssue339b(cc, cc0, "bar", true);
testIssue339b(cc, cc0, "foo2", false);
testIssue339b(cc, cc0, "bar2", false);

cc.writeFile();
Object t1 = make(cc.getName());
assertEquals(2322, invoke(t1, "run"));
}

public void testIssue339b(CtClass cc, CtClass cc0, String name, boolean exclusive) throws Exception {
Bytecode newCode = new Bytecode(cc.getClassFile().constPool);
newCode.addAload(0); // Loads 'this'
newCode.addIload(1); // Loads method param 1 (int)
newCode.addInvokespecial(cc0.getName(), name, "(I)V");
CodeAttribute ca = cc.getDeclaredMethod(name).getMethodInfo().getCodeAttribute();
CodeIterator ci = ca.iterator();
if (exclusive)
ci.insertEx(newCode.get());
else
ci.insert(newCode.get());
}

public void testIssue350() throws Exception {
byte sameLocals1StackItemFrameExtended = 247 - 256;
byte sameFrameExtended = 251 - 256;
byte appendFrame = 252 - 256;
ConstPool cp = new ConstPool("Test");
StackMapTable stmt;
int originalLength;

stmt = new StackMapTable(cp, new byte[] {
0, 1,
sameLocals1StackItemFrameExtended, 0, 63, 1
});
originalLength = stmt.info.length;
assertEquals(63, stmt.info[4]);
stmt.shiftPc(0, 2, false);
assertEquals(originalLength, stmt.info.length);
assertEquals(65, stmt.info[4]);

stmt = new StackMapTable(cp, new byte[] {
0, 1,
sameFrameExtended, 0, 63
});
originalLength = stmt.info.length;
assertEquals(63, stmt.info[4]);
stmt.shiftPc(0, 2, false);
assertEquals(originalLength, stmt.info.length);
assertEquals(65, stmt.info[4]);

stmt = new StackMapTable(cp, new byte[] {
0, 2,
sameLocals1StackItemFrameExtended, 0, 63, 1,
sameFrameExtended, 0, 63
});
originalLength = stmt.info.length;
assertEquals(63, stmt.info[4]);
assertEquals(63, stmt.info[8]);
stmt.shiftPc(0, 2, false);
assertEquals(originalLength, stmt.info.length);
assertEquals(65, stmt.info[4]);
assertEquals(63, stmt.info[8]);
stmt.shiftPc(100, 2, false);
assertEquals(65, stmt.info[4]);
assertEquals(65, stmt.info[8]);

// Actual StackMapTable reported in https://github.com/jboss-javassist/javassist/issues/350.
stmt = new StackMapTable(cp, new byte[] {
0, 7, // size
sameLocals1StackItemFrameExtended, 0, 76, 7, 2, 206 - 256,
sameLocals1StackItemFrameExtended, 0, 63, 7, 2, 221 - 256,
appendFrame, 0, 63, 7, 0, 14,
appendFrame, 0, 43, 7, 2, 225 - 256, 1,
74, 7, 0, 19, // same_locals_1_stack_item_frame (not extended)
appendFrame, 0, 23, 7, 0, 19,
66, 7, 2, 225 - 256 // same_locals_1_stack_item_frame (not extended)
});
assertEquals(63, stmt.info[10]);
originalLength = stmt.info.length;

stmt.shiftPc(100, 2, false);
assertEquals(originalLength, stmt.info.length);
assertEquals(65, stmt.info[10]);
}

public static void dump(byte[] content) {
final int bytesPerLine = 16;
for (int i = 0; i < content.length; i += bytesPerLine) {
for (int j = 0; j < bytesPerLine && i + j < content.length; j++) {
int unsignedByte = content[i + j];
if (unsignedByte < 0) {
unsignedByte = 256 + unsignedByte;
}
System.out.print(unsignedByte + ", ");
}
System.out.println();
}
}
}

+ 21
- 0
src/test/test/javassist/convert/ArrayAccessReplaceTest2.java View File

@@ -0,0 +1,21 @@
package test.javassist.convert;

import javassist.ClassPool;
import javassist.CodeConverter;
import javassist.CtClass;
import junit.framework.TestCase;

public class ArrayAccessReplaceTest2 extends TestCase {

public void testAdvancedInstrumentation() throws Exception {
ClassPool pool = new ClassPool(true);
CtClass monitoringClass = pool.get(ArrayAccessReplaceTest2.class.getName());
CtClass targetClass = pool.get(InstrumentationTarget.class.getName());
CodeConverter converter = new CodeConverter();
// we just test if the instrumentation works, the monitoring class does not need to actually contain the replacer methods
// what is only relevant when code gets executed
converter.replaceArrayAccess(monitoringClass, new CodeConverter.DefaultArrayAccessReplacementMethodNames());
targetClass.instrument(converter);
}

}

+ 761
- 0
src/test/test/javassist/convert/InstrumentationTarget.java View File

@@ -0,0 +1,761 @@
package test.javassist.convert;

import java.util.AbstractQueue;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;


/**
* A clone of java.util.concurrent.ArrayBlockingQueue as target for testing
*/
public class InstrumentationTarget<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
/**
* Serialization ID. This class relies on default serialization
* even for the items array, which is default-serialized, even if
* it is empty. Otherwise it could not be declared final, which is
* necessary here.
*/
private static final long serialVersionUID = -817911632652898426L;

/**
* The queued items
*/
final Object[] items;

/**
* items index for next take, poll, peek or remove
*/
int takeIndex;

/**
* items index for next put, offer, or add
*/
int putIndex;

/**
* Number of elements in the queue
*/
int count;

/*
* Concurrency control uses the classic two-condition algorithm
* found in any textbook.
*/

/**
* Main lock guarding all access
*/
final ReentrantLock lock;
/**
* Condition for waiting takes
*/
private final Condition notEmpty;
/**
* Condition for waiting puts
*/
private final Condition notFull;

// Internal helper methods

/**
* Circularly increment i.
*/
final int inc(int i) {
return (++i == items.length) ? 0 : i;
}

/**
* Circularly decrement i.
*/
final int dec(int i) {
return ((i == 0) ? items.length : i) - 1;
}

@SuppressWarnings("unchecked")
static <E> E cast(Object item) {
return (E) item;
}

/**
* Returns item at index i.
*/
final E itemAt(int i) {
return this.<E>cast(items[i]);
}

/**
* Throws NullPointerException if argument is null.
*
* @param v the element
*/
private static void checkNotNull(Object v) {
if (v == null)
throw new NullPointerException();
}

/**
* Inserts element at current put position, advances, and signals.
* Call only when holding lock.
*/
private void insert(E x) {
items[putIndex] = x;
putIndex = inc(putIndex);
++count;
notEmpty.signal();
}

/**
* Extracts element at current take position, advances, and signals.
* Call only when holding lock.
*/
private E extract() {
final Object[] items = this.items;
E x = this.<E>cast(items[takeIndex]);
items[takeIndex] = null;
takeIndex = inc(takeIndex);
--count;
notFull.signal();
return x;
}

/**
* Deletes item at position i.
* Utility for remove and iterator.remove.
* Call only when holding lock.
*/
void removeAt(int i) {
final Object[] items = this.items;
// if removing front item, just advance
if (i == takeIndex) {
items[takeIndex] = null;
takeIndex = inc(takeIndex);
} else {
// slide over all others up through putIndex.
for (; ; ) {
int nexti = inc(i);
if (nexti != putIndex) {
items[i] = items[nexti];
i = nexti;
} else {
items[i] = null;
putIndex = i;
break;
}
}
}
--count;
notFull.signal();
}

/**
* Creates an {@code Target} with the given (fixed)
* capacity and default access policy.
*
* @param capacity the capacity of this queue
* @throws IllegalArgumentException if {@code capacity < 1}
*/
public InstrumentationTarget(int capacity) {
this(capacity, false);
}

/**
* Creates an {@code Target} with the given (fixed)
* capacity and the specified access policy.
*
* @param capacity the capacity of this queue
* @param fair if {@code true} then queue accesses for threads blocked
* on insertion or removal, are processed in FIFO order;
* if {@code false} the access order is unspecified.
* @throws IllegalArgumentException if {@code capacity < 1}
*/
public InstrumentationTarget(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity];
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}

/**
* Creates an {@code Target} with the given (fixed)
* capacity, the specified access policy and initially containing the
* elements of the given collection,
* added in traversal order of the collection's iterator.
*
* @param capacity the capacity of this queue
* @param fair if {@code true} then queue accesses for threads blocked
* on insertion or removal, are processed in FIFO order;
* if {@code false} the access order is unspecified.
* @param c the collection of elements to initially contain
* @throws IllegalArgumentException if {@code capacity} is less than
* {@code c.size()}, or less than 1.
* @throws NullPointerException if the specified collection or any
* of its elements are null
*/
public InstrumentationTarget(int capacity, boolean fair,
Collection<? extends E> c) {
this(capacity, fair);

final ReentrantLock lock = this.lock;
lock.lock(); // Lock only for visibility, not mutual exclusion
try {
int i = 0;
try {
for (E e : c) {
checkNotNull(e);
items[i++] = e;
}
} catch (ArrayIndexOutOfBoundsException ex) {
throw new IllegalArgumentException();
}
count = i;
putIndex = (i == capacity) ? 0 : i;
} finally {
lock.unlock();
}
}

/**
* Inserts the specified element at the tail of this queue if it is
* possible to do so immediately without exceeding the queue's capacity,
* returning {@code true} upon success and throwing an
* {@code IllegalStateException} if this queue is full.
*
* @param e the element to add
* @return {@code true} (as specified by {@link Collection#add})
* @throws IllegalStateException if this queue is full
* @throws NullPointerException if the specified element is null
*/
public boolean add(E e) {
return super.add(e);
}

/**
* Inserts the specified element at the tail of this queue if it is
* possible to do so immediately without exceeding the queue's capacity,
* returning {@code true} upon success and {@code false} if this queue
* is full. This method is generally preferable to method {@link #add},
* which can fail to insert an element only by throwing an exception.
*
* @throws NullPointerException if the specified element is null
*/
public boolean offer(E e) {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count == items.length)
return false;
else {
insert(e);
return true;
}
} finally {
lock.unlock();
}
}

/**
* Inserts the specified element at the tail of this queue, waiting
* for space to become available if the queue is full.
*
* @throws InterruptedException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
public void put(E e) throws InterruptedException {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length)
notFull.await();
insert(e);
} finally {
lock.unlock();
}
}

/**
* Inserts the specified element at the tail of this queue, waiting
* up to the specified wait time for space to become available if
* the queue is full.
*
* @throws InterruptedException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException {

checkNotNull(e);
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length) {
if (nanos <= 0)
return false;
nanos = notFull.awaitNanos(nanos);
}
insert(e);
return true;
} finally {
lock.unlock();
}
}

public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (count == 0) ? null : extract();
} finally {
lock.unlock();
}
}

public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
notEmpty.await();
return extract();
} finally {
lock.unlock();
}
}

public E poll(long timeout, TimeUnit unit) throws InterruptedException {
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0) {
if (nanos <= 0)
return null;
nanos = notEmpty.awaitNanos(nanos);
}
return extract();
} finally {
lock.unlock();
}
}

public E peek() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (count == 0) ? null : itemAt(takeIndex);
} finally {
lock.unlock();
}
}

// this doc comment is overridden to remove the reference to collections
// greater in size than Integer.MAX_VALUE

/**
* Returns the number of elements in this queue.
*
* @return the number of elements in this queue
*/
public int size() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return count;
} finally {
lock.unlock();
}
}

// this doc comment is a modified copy of the inherited doc comment,
// without the reference to unlimited queues.

/**
* Returns the number of additional elements that this queue can ideally
* (in the absence of memory or resource constraints) accept without
* blocking. This is always equal to the initial capacity of this queue
* less the current {@code size} of this queue.
*
* <p>Note that you <em>cannot</em> always tell if an attempt to insert
* an element will succeed by inspecting {@code remainingCapacity}
* because it may be the case that another thread is about to
* insert or remove an element.
*/
public int remainingCapacity() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return items.length - count;
} finally {
lock.unlock();
}
}

/**
* Removes a single instance of the specified element from this queue,
* if it is present. More formally, removes an element {@code e} such
* that {@code o.equals(e)}, if this queue contains one or more such
* elements.
* Returns {@code true} if this queue contained the specified element
* (or equivalently, if this queue changed as a result of the call).
*
* <p>Removal of interior elements in circular array based queues
* is an intrinsically slow and disruptive operation, so should
* be undertaken only in exceptional circumstances, ideally
* only when the queue is known not to be accessible by other
* threads.
*
* @param o element to be removed from this queue, if present
* @return {@code true} if this queue changed as a result of the call
*/
public boolean remove(Object o) {
if (o == null) return false;
final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
for (int i = takeIndex, k = count; k > 0; i = inc(i), k--) {
if (o.equals(items[i])) {
removeAt(i);
return true;
}
}
return false;
} finally {
lock.unlock();
}
}

/**
* Returns {@code true} if this queue contains the specified element.
* More formally, returns {@code true} if and only if this queue contains
* at least one element {@code e} such that {@code o.equals(e)}.
*
* @param o object to be checked for containment in this queue
* @return {@code true} if this queue contains the specified element
*/
public boolean contains(Object o) {
if (o == null) return false;
final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
for (int i = takeIndex, k = count; k > 0; i = inc(i), k--)
if (o.equals(items[i]))
return true;
return false;
} finally {
lock.unlock();
}
}

/**
* Returns an array containing all of the elements in this queue, in
* proper sequence.
*
* <p>The returned array will be "safe" in that no references to it are
* maintained by this queue. (In other words, this method must allocate
* a new array). The caller is thus free to modify the returned array.
*
* <p>This method acts as bridge between array-based and collection-based
* APIs.
*
* @return an array containing all of the elements in this queue
*/
public Object[] toArray() {
final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
final int count = this.count;
Object[] a = new Object[count];
for (int i = takeIndex, k = 0; k < count; i = inc(i), k++)
a[k] = items[i];
return a;
} finally {
lock.unlock();
}
}

/**
* Returns an array containing all of the elements in this queue, in
* proper sequence; the runtime type of the returned array is that of
* the specified array. If the queue fits in the specified array, it
* is returned therein. Otherwise, a new array is allocated with the
* runtime type of the specified array and the size of this queue.
*
* <p>If this queue fits in the specified array with room to spare
* (i.e., the array has more elements than this queue), the element in
* the array immediately following the end of the queue is set to
* {@code null}.
*
* <p>Like the {@link #toArray()} method, this method acts as bridge between
* array-based and collection-based APIs. Further, this method allows
* precise control over the runtime type of the output array, and may,
* under certain circumstances, be used to save allocation costs.
*
* <p>Suppose {@code x} is a queue known to contain only strings.
* The following code can be used to dump the queue into a newly
* allocated array of {@code String}:
*
* <pre>
* String[] y = x.toArray(new String[0]);</pre>
* <p>
* Note that {@code toArray(new Object[0])} is identical in function to
* {@code toArray()}.
*
* @param a the array into which the elements of the queue are to
* be stored, if it is big enough; otherwise, a new array of the
* same runtime type is allocated for this purpose
* @return an array containing all of the elements in this queue
* @throws ArrayStoreException if the runtime type of the specified array
* is not a supertype of the runtime type of every element in
* this queue
* @throws NullPointerException if the specified array is null
*/
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
final int count = this.count;
final int len = a.length;
if (len < count)
a = (T[]) java.lang.reflect.Array.newInstance(
a.getClass().getComponentType(), count);
for (int i = takeIndex, k = 0; k < count; i = inc(i), k++)
a[k] = (T) items[i];
if (len > count)
a[count] = null;
return a;
} finally {
lock.unlock();
}
}

public String toString() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
int k = count;
if (k == 0)
return "[]";

StringBuilder sb = new StringBuilder();
sb.append('[');
for (int i = takeIndex; ; i = inc(i)) {
Object e = items[i];
sb.append(e == this ? "(this Collection)" : e);
if (--k == 0)
return sb.append(']').toString();
sb.append(',').append(' ');
}
} finally {
lock.unlock();
}
}

/**
* Atomically removes all of the elements from this queue.
* The queue will be empty after this call returns.
*/
public void clear() {
final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
for (int i = takeIndex, k = count; k > 0; i = inc(i), k--)
items[i] = null;
count = 0;
putIndex = 0;
takeIndex = 0;
notFull.signalAll();
} finally {
lock.unlock();
}
}

/**
* @throws UnsupportedOperationException {@inheritDoc}
* @throws ClassCastException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
*/
public int drainTo(Collection<? super E> c) {
checkNotNull(c);
if (c == this)
throw new IllegalArgumentException();
final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
int i = takeIndex;
int n = 0;
int max = count;
while (n < max) {
c.add(this.<E>cast(items[i]));
items[i] = null;
i = inc(i);
++n;
}
if (n > 0) {
count = 0;
putIndex = 0;
takeIndex = 0;
notFull.signalAll();
}
return n;
} finally {
lock.unlock();
}
}

/**
* @throws UnsupportedOperationException {@inheritDoc}
* @throws ClassCastException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
*/
public int drainTo(Collection<? super E> c, int maxElements) {
checkNotNull(c);
if (c == this)
throw new IllegalArgumentException();
if (maxElements <= 0)
return 0;
final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
int i = takeIndex;
int n = 0;
int max = (maxElements < count) ? maxElements : count;
while (n < max) {
c.add(this.<E>cast(items[i]));
items[i] = null;
i = inc(i);
++n;
}
if (n > 0) {
count -= n;
takeIndex = i;
notFull.signalAll();
}
return n;
} finally {
lock.unlock();
}
}

/**
* Returns an iterator over the elements in this queue in proper sequence.
* The elements will be returned in order from first (head) to last (tail).
*
* <p>The returned {@code Iterator} is a "weakly consistent" iterator that
* will never throw {@link java.util.ConcurrentModificationException
* ConcurrentModificationException},
* and guarantees to traverse elements as they existed upon
* construction of the iterator, and may (but is not guaranteed to)
* reflect any modifications subsequent to construction.
*
* @return an iterator over the elements in this queue in proper sequence
*/
public Iterator<E> iterator() {
return new Itr();
}

/**
* Iterator for Target. To maintain weak consistency
* with respect to puts and takes, we (1) read ahead one slot, so
* as to not report hasNext true but then not have an element to
* return -- however we later recheck this slot to use the most
* current value; (2) ensure that each array slot is traversed at
* most once (by tracking "remaining" elements); (3) skip over
* null slots, which can occur if takes race ahead of iterators.
* However, for circular array-based queues, we cannot rely on any
* well established definition of what it means to be weakly
* consistent with respect to interior removes since these may
* require slot overwrites in the process of sliding elements to
* cover gaps. So we settle for resiliency, operating on
* established apparent nexts, which may miss some elements that
* have moved between calls to next.
*/
private class Itr implements Iterator<E> {
private int remaining; // Number of elements yet to be returned
private int nextIndex; // Index of element to be returned by next
private E nextItem; // Element to be returned by next call to next
private E lastItem; // Element returned by last call to next
private int lastRet; // Index of last element returned, or -1 if none

Itr() {
final ReentrantLock lock = InstrumentationTarget.this.lock;
lock.lock();
try {
lastRet = -1;
if ((remaining = count) > 0)
nextItem = itemAt(nextIndex = takeIndex);
} finally {
lock.unlock();
}
}

public boolean hasNext() {
return remaining > 0;
}

public E next() {
final ReentrantLock lock = InstrumentationTarget.this.lock;
lock.lock();
try {
if (remaining <= 0)
throw new NoSuchElementException();
lastRet = nextIndex;
E x = itemAt(nextIndex); // check for fresher value
if (x == null) {
x = nextItem; // we are forced to report old value
lastItem = null; // but ensure remove fails
} else
lastItem = x;
while (--remaining > 0 && // skip over nulls
(nextItem = itemAt(nextIndex = inc(nextIndex))) == null)
;
return x;
} finally {
lock.unlock();
}
}

public void remove() {
final ReentrantLock lock = InstrumentationTarget.this.lock;
lock.lock();
try {
int i = lastRet;
if (i == -1)
throw new IllegalStateException();
lastRet = -1;
E x = lastItem;
lastItem = null;
// only remove if item still at index
if (x != null && x == items[i]) {
boolean removingHead = (i == takeIndex);
removeAt(i);
if (!removingHead)
nextIndex = dec(nextIndex);
}
} finally {
lock.unlock();
}
}
}

}


BIN
src/test/test2/AddCatchForConstructor.class View File


BIN
src/test/test2/AddLocalVar.class View File


BIN
src/test/test2/ArrayInit.class View File


BIN
src/test/test2/ArrayLenTest.class View File


BIN
src/test/test2/ArrayLength.class View File


BIN
src/test/test2/Brennan.class View File


BIN
src/test/test2/CodeGen.class View File


BIN
src/test/test2/CodeGen2.class View File


BIN
src/test/test2/ConstBody.class View File


BIN
src/test/test2/ConstField.class View File


BIN
src/test/test2/DotClass.class View File


BIN
src/test/test2/DotClass2.class View File


BIN
src/test/test2/DotClass4.class View File


BIN
src/test/test2/Finally.class View File


BIN
src/test/test2/Imported.class View File


BIN
src/test/test2/Importer.class View File


BIN
src/test/test2/IncOp.class View File


BIN
src/test/test2/Inherit.class View File


BIN
src/test/test2/Inner.class View File


+ 2
- 3
src/test/test2/Inner.java View File

@@ -4,9 +4,8 @@ package test2;
public class Inner {
public void sample() throws Exception {
java.util.Properties props = new java.util.Properties();
java.rmi.activation.ActivationGroupDesc.CommandEnvironment ace = null;
java.rmi.activation.ActivationGroupDesc agd = new
java.rmi.activation.ActivationGroupDesc(props,ace);
test2.Inner2.Child ace = null;
test2.Inner2 agd = new test2.Inner2(props, ace);
}
public static void main(String args[]) {
System.out.println("Inner");

+ 23
- 0
src/test/test2/Inner2.java View File

@@ -0,0 +1,23 @@
package test2;

/**
* Used by test2.Inner
*/
public class Inner2 {
public static class Child {
public int value;
}

private java.util.Properties p;
private Child c;

public Inner2(java.util.Properties props, Child child) {
p = props;
c = child;
}

public void print() {
System.out.println(p);
System.out.println(c);
}
}

BIN
src/test/test2/InsertAt.class View File


BIN
src/test/test2/InsertLocal.class View File


BIN
src/test/test2/LocalVar.class View File


BIN
src/test/test2/MakeStaticMethod.class View File


BIN
src/test/test2/MethodCall.class View File


BIN
src/test/test2/Nested$Inner3.class View File


BIN
src/test/test2/Nested.class View File


BIN
src/test/test2/Nested2$Inner.class View File


BIN
src/test/test2/Nested2.class View File


BIN
src/test/test2/Nested3$Inner.class View File


BIN
src/test/test2/Nested3.class View File


BIN
src/test/test2/Nested4$Inner.class View File


BIN
src/test/test2/Nested4.class View File


BIN
src/test/test2/NewArray.class View File


BIN
src/test/test2/NewExprInTry.class View File


BIN
src/test/test2/NewExprTry.class View File


BIN
src/test/test2/NewOp.class View File


BIN
src/test/test2/NullArgTest.class View File


BIN
src/test/test2/Remove.class View File


BIN
src/test/test2/RemoveCall.class View File


BIN
src/test/test2/ReplaceClassName.class View File


BIN
src/test/test2/SetExceptions.class View File


BIN
src/test/test2/SetSuper.class View File


BIN
src/test/test2/SetSuperIntf.class View File


BIN
src/test/test2/SetSuperParent.class View File


BIN
src/test/test2/StaticFinal.class View File


BIN
src/test/test2/StaticMember.class View File


BIN
src/test/test2/StaticMember2.class View File


BIN
src/test/test2/SuperCall.class View File


BIN
src/test/test2/SuperInterface3.class View File


BIN
src/test/test2/Switch.class View File


BIN
src/test/test2/Synch.class View File


Loading…
Cancel
Save