diff --git a/doc/soot_options.htm b/doc/soot_options.htm
index 953691238d5..79c1a03d4a6 100644
--- a/doc/soot_options.htm
+++ b/doc/soot_options.htm
@@ -597,7 +597,9 @@
-src-prec format
|
- c
+ cache
+ only-cache
+ c
class
only-class
J
diff --git a/eclipse/ca.mcgill.sable.soot/src/ca/mcgill/sable/soot/ui/PhaseOptionsDialog.java b/eclipse/ca.mcgill.sable.soot/src/ca/mcgill/sable/soot/ui/PhaseOptionsDialog.java
index 3b7d69cc04a..f0695d81bb9 100644
--- a/eclipse/ca.mcgill.sable.soot/src/ca/mcgill/sable/soot/ui/PhaseOptionsDialog.java
+++ b/eclipse/ca.mcgill.sable.soot/src/ca/mcgill/sable/soot/ui/PhaseOptionsDialog.java
@@ -8772,6 +8772,14 @@ private Composite Input_OptionsCreate(Composite parent) {
data = new OptionData [] {
+ new OptionData("Cache",
+ "cache",
+ "\nTry to resolve classes first from the shared class cache found \nin the Soot classpath. Fall back to .class and then .jimple \nfiles only when unable to find a class in the cache.",
+ false),
+ new OptionData("Only Cache Source",
+ "only-cache",
+ "\nTry to resolve classes first from the shared class cache found \nin the Soot classpath. Do not try any other types of files even \nwhen unable to find a class in the cache.",
+ false),
new OptionData("Class File",
"c class",
"\nTry to resolve classes first from .class files found in the Soot \nclasspath. Fall back to .jimple files only when unable to find a \n.class file.",
diff --git a/pom.xml b/pom.xml
index d3cd5eed855..72df988a72c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -52,6 +52,8 @@
https://github.com/soot-oss/soot
+ /root/openj9-openjdk-jdk8/build/linux-x86_64-normal-server-release
+ cp.txt
1.8
1.8
1.0.2
@@ -78,6 +80,42 @@
sootclasses-trunk
+
+ org.codehaus.gmaven
+ gmaven-plugin
+ 1.4
+
+
+ generate-resources
+
+ execute
+
+
+
+ def file = new File(project.properties.cpfile)
+ project.properties.cp = file.getText()
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+ 2.9
+
+
+ build-classpath
+ generate-sources
+
+ build-classpath
+
+
+ ${cpfile}
+
+
+
+
org.codehaus.mojo
xml-maven-plugin
@@ -255,8 +293,23 @@
maven-compiler-plugin
${maven-compiler-plugin.version}
- ${maven.compiler.source}
- ${maven.compiler.target}
+ true
+ true
+ ${openj9-build-root}/images/j2sdk-image/bin/javac
+ 1.8
+
+ -classpath${cp}:${openj9-build-root}/images/j2sdk-image/jre/lib/ddr/j9ddr.jar
+ -d${basedir}/target/classes
+ -s${basedir}/target/generated-sources/annotations
+ -g
+ -verbose
+ -nowarn
+ -target1.8
+ -source1.8
+ -encodingUTF-8
+
+ ${maven.compiler.source}
+ ${maven.compiler.target}
diff --git a/src/main/generated/options/soot/AntTask.java b/src/main/generated/options/soot/AntTask.java
index 4475909e4b9..0cd68456b29 100644
--- a/src/main/generated/options/soot/AntTask.java
+++ b/src/main/generated/options/soot/AntTask.java
@@ -253,6 +253,8 @@ public void setast_metrics(boolean arg) {
public void setsrc_prec(String arg) {
if(false
+ || arg.equals( "cache" )
+ || arg.equals( "only-cache" )
|| arg.equals( "c" )
|| arg.equals( "class" )
|| arg.equals( "only-class" )
diff --git a/src/main/generated/options/soot/options/Options.java b/src/main/generated/options/soot/options/Options.java
index decdc944e25..f37219a874a 100644
--- a/src/main/generated/options/soot/options/Options.java
+++ b/src/main/generated/options/soot/options/Options.java
@@ -42,15 +42,17 @@ public static Options v() {
return G.v().soot_options_Options();
}
- public static final int src_prec_c = 1;
- public static final int src_prec_class = 1;
- public static final int src_prec_only_class = 2;
- public static final int src_prec_J = 3;
- public static final int src_prec_jimple = 3;
- public static final int src_prec_java = 4;
- public static final int src_prec_apk = 5;
- public static final int src_prec_apk_class_jimple = 6;
- public static final int src_prec_apk_c_j = 6;
+ public static final int src_prec_cache = 1;
+ public static final int src_prec_only_cache = 2;
+ public static final int src_prec_c = 3;
+ public static final int src_prec_class = 3;
+ public static final int src_prec_only_class = 4;
+ public static final int src_prec_J = 5;
+ public static final int src_prec_jimple = 5;
+ public static final int src_prec_java = 6;
+ public static final int src_prec_apk = 7;
+ public static final int src_prec_apk_class_jimple = 8;
+ public static final int src_prec_apk_c_j = 8;
public static final int output_format_J = 1;
public static final int output_format_jimple = 1;
public static final int output_format_j = 2;
@@ -368,6 +370,24 @@ else if (false
String value = nextOption();
if (false);
+ else if (false
+ || value.equals("cache")
+ ) {
+ if (src_prec != 0 && src_prec != src_prec_cache) {
+ G.v().out.println("Multiple values given for option " + option);
+ return false;
+ }
+ src_prec = src_prec_cache;
+ }
+ else if (false
+ || value.equals("only-cache")
+ ) {
+ if (src_prec != 0 && src_prec != src_prec_only_cache) {
+ G.v().out.println("Multiple values given for option " + option);
+ return false;
+ }
+ src_prec = src_prec_only_cache;
+ }
else if (false
|| value.equals("c")
|| value.equals("class")
@@ -1742,6 +1762,8 @@ public String getUsage() {
+ padOpt("-force-android-jar ARG", "Force Soot to use ARG as the path for the android.jar file.")
+ padOpt("-ast-metrics", "Compute AST Metrics if performing java to jimple")
+ padOpt("-src-prec ARG", "Sets source precedence to ARG files")
+ + padVal("cache", "Favour shared class cache as Soot source")
+ + padVal("only-cache", "Use only shared class cache as Soot source")
+ padVal("c class (default)", "Favour class files as Soot source")
+ padVal("only-class", "Use only class files as Soot source")
+ padVal("J jimple", "Favour Jimple files as Soot source")
diff --git a/src/main/java/soot/SourceLocator.java b/src/main/java/soot/SourceLocator.java
index 721bc8df1cd..ae46af76d3e 100755
--- a/src/main/java/soot/SourceLocator.java
+++ b/src/main/java/soot/SourceLocator.java
@@ -49,6 +49,7 @@
import soot.JavaClassProvider.JarException;
import soot.asm.AsmClassProvider;
import soot.asm.AsmJava9ClassProvider;
+import soot.cache.CacheClassProvider;
import soot.dexpler.DexFileProvider;
import soot.options.Options;
@@ -245,6 +246,17 @@ protected void setupClassProviders() {
classProviders.add(new AsmJava9ClassProvider());
}
switch (Options.v().src_prec()) {
+ case Options.src_prec_cache:
+ System.out.println("Using the cache with default source provider chain.");
+ classProviders.add(new CacheClassProvider());
+ classProviders.add(classFileClassProvider);
+ classProviders.add(new JimpleClassProvider());
+ classProviders.add(new JavaClassProvider());
+ break;
+ case Options.src_prec_only_cache:
+ System.out.println("Using the cache only source provider chain.");
+ classProviders.add(new CacheClassProvider());
+ break;
case Options.src_prec_class:
classProviders.add(classFileClassProvider);
classProviders.add(new JimpleClassProvider());
diff --git a/src/main/java/soot/asm/SootClassBuilder.java b/src/main/java/soot/asm/SootClassBuilder.java
index 3b68588bbe9..e999ef3f3bf 100644
--- a/src/main/java/soot/asm/SootClassBuilder.java
+++ b/src/main/java/soot/asm/SootClassBuilder.java
@@ -79,7 +79,7 @@ public class SootClassBuilder extends ClassVisitor {
* @param klass
* Soot class to build.
*/
- protected SootClassBuilder(SootClass klass) {
+ public SootClassBuilder(SootClass klass) {
super(Opcodes.ASM8);
this.klass = klass;
this.deps = new HashSet();
@@ -97,6 +97,10 @@ protected SootClass getKlass() {
return klass;
}
+ public Set getDeps() {
+ return deps;
+ }
+
void addDep(String s) {
String className = AsmUtil.baseTypeName(s);
RefType refType = makeRefType(className);
diff --git a/src/main/java/soot/cache/CacheClassProvider.java b/src/main/java/soot/cache/CacheClassProvider.java
new file mode 100644
index 00000000000..dc1ec1a9588
--- /dev/null
+++ b/src/main/java/soot/cache/CacheClassProvider.java
@@ -0,0 +1,156 @@
+package soot.cache;
+
+/*-
+ * #%L
+ * Soot - a J*va Optimization Framework
+ * %%
+ * Copyright (C) 2020 Kristen Newbury
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU General Lesser Public
+ * License along with this program. If not, see
+ * .
+ * #L%
+ */
+
+import com.ibm.oti.shared.HelperAlreadyDefinedException;
+import com.ibm.oti.shared.Shared;
+import com.ibm.oti.shared.SharedClassHelperFactory;
+import com.ibm.oti.shared.SharedClassURLClasspathHelper;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import soot.ClassProvider;
+import soot.ClassSource;
+
+/**
+ * OpenJ9 Shared Cache Class class provider.
+ *
+ * @author Kristen Newbury
+ */
+
+public class CacheClassProvider implements ClassProvider {
+
+ private static URL testClassUrl;
+
+ public CacheClassProvider() {
+ if (!System.getProperty("java.vm.name").contains("OpenJ9")) {
+ throw new RuntimeException("CacheClassProvider feature only works with OpenJ9 JVM running Soot");
+ }
+ }
+
+ public static void setTestClassUrl(String url) {
+ try {
+ testClassUrl = new URL("file://" + url);
+ System.out.println("CacheClassProvider: setting testClassUrl: " + url);
+ } catch (MalformedURLException e) {
+ System.out.println("Bad URL provided, not using url: " + url);
+ e.printStackTrace();
+ }
+ }
+
+ public ClassSource find(String cls) {
+
+ byte[] romCookie = null;
+ CacheMemorySingleton cacheMem = null;
+ ByteBuffer wrapper = null;
+
+ SharedClassHelperFactory factory = Shared.getSharedClassHelperFactory();
+ if (factory != null) {
+ URL[] urlsForRuntime = null;
+ URL[] urlsForApp = null;
+ URL[] urlsForJCE = null;
+ URL jceurl = null;
+ URL rturl = null;
+ SharedClassURLClasspathHelper helperForAppClasses = null;
+ SharedClassURLClasspathHelper helperForRuntimeClasses = null;
+ SharedClassURLClasspathHelper helperForJCE = null;
+ try {
+ rturl = new URL("file://" + System.getProperty("java.home") + File.separator + "lib" + File.separator + "rt.jar");
+ jceurl = new URL("file://" + System.getProperty("java.home") + File.separator + "lib" + File.separator + "jce.jar");
+ urlsForRuntime = new URL[] { rturl };
+ if (testClassUrl != null) {
+ urlsForApp = new URL[] { testClassUrl };
+ } else {
+ System.out.println("No test class url set");
+ return null;
+ }
+
+ urlsForJCE = new URL[] { jceurl };
+ } catch (MalformedURLException e) {
+ System.out.println("Bad URL provided");
+ e.printStackTrace();
+ }
+ URLClassLoader loaderForRuntime = new URLClassLoader(urlsForRuntime);
+ URLClassLoader loaderForApp = new URLClassLoader(urlsForApp);
+ URLClassLoader loaderForJCE = new URLClassLoader(urlsForJCE);
+
+ // get helper to find classes in cache
+ try {
+ helperForRuntimeClasses = factory.getURLClasspathHelper(loaderForRuntime, urlsForRuntime);
+ helperForAppClasses = factory.getURLClasspathHelper(loaderForApp, urlsForApp);
+ helperForJCE = factory.getURLClasspathHelper(loaderForJCE, urlsForJCE);
+ } catch (HelperAlreadyDefinedException e) {
+ System.out.println("Helper already defined?" + e.getMessage());
+ e.printStackTrace();
+ }
+
+ helperForAppClasses.confirmAllEntries();
+ helperForRuntimeClasses.confirmAllEntries();
+ helperForJCE.confirmAllEntries();
+
+ try {
+ // for now this part happens every time
+ // maybe consider avoiding that later
+ byte[] cacheInfo = helperForAppClasses.findSharedCache();
+ if (cacheInfo != null) {
+ wrapper = ByteBuffer.wrap(cacheInfo);
+ // jni filled byte array
+ wrapper.order(ByteOrder.nativeOrder());
+ cacheMem = CacheMemorySingleton.getInstance();
+ } else {
+ System.out.println("Cannot get cache start");
+ }
+ } catch (Exception e) {
+ System.out.println(e.getMessage());
+ e.printStackTrace();
+ }
+
+ romCookie = helperForAppClasses.findSharedClass(cls, null);
+ if (romCookie == null) {
+ romCookie = helperForRuntimeClasses.findSharedClass(cls, null);
+ if (romCookie == null) {
+ romCookie = helperForJCE.findSharedClass(cls, null);
+ if (romCookie == null) {
+ System.out.println("Cannot find class in cache: " + cls);
+ } else {
+ System.out.println("Located the class in the cache: " + cls);
+ }
+ } else {
+ System.out.println("Located the class in the cache: " + cls);
+ }
+ } else {
+ System.out.println("Located the class in the cache: " + cls);
+ }
+
+ } else {
+ System.out.println("Cache helper null, cannot find class in cache: " + cls);
+ System.out.println("Is Shared Class Cache enabled on command line?");
+ }
+ return romCookie == null ? null : new CacheClassSource(cls, romCookie, cacheMem, wrapper.getLong(), wrapper.getInt());
+ }
+}
diff --git a/src/main/java/soot/cache/CacheClassSource.java b/src/main/java/soot/cache/CacheClassSource.java
new file mode 100644
index 00000000000..e1f2f342c8e
--- /dev/null
+++ b/src/main/java/soot/cache/CacheClassSource.java
@@ -0,0 +1,125 @@
+package soot.cache;
+
+/*-
+ * #%L
+ * Soot - a J*va Optimization Framework
+ * %%
+ * Copyright (C) 2020 Kristen Newbury
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU General Lesser Public
+ * License along with this program. If not, see
+ * .
+ * #L%
+ */
+
+import com.ibm.j9ddr.IVMData;
+import com.ibm.j9ddr.VMDataFactory;
+import com.ibm.j9ddr.corereaders.memory.IProcess;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import soot.ClassSource;
+import soot.SootClass;
+import soot.asm.SootClassBuilder;
+import soot.javaToJimple.IInitialResolver.Dependencies;
+
+/**
+ * Cache class source implementation.
+ *
+ * @author Kristen Newbury
+ */
+
+public class CacheClassSource extends ClassSource {
+
+ private byte[] cookiesource;
+ private byte[] classsource;
+ private CacheMemorySingleton memory;
+ private long cacheaddr;
+ private int cachesize;
+
+ /**
+ * Constructs a new Cache class source.
+ *
+ * @param cls
+ * fully qualified name of the class.
+ * @param data
+ * stream containing data for class.
+ */
+ CacheClassSource(String cls, byte[] source, CacheMemorySingleton memory, long cacheaddr, int cachesize) {
+ super(cls);
+ if (source == null) {
+ throw new IllegalStateException("Error: The class source must not be null.");
+ }
+ this.cookiesource = source;
+ this.memory = memory;
+ this.cacheaddr = cacheaddr;
+ this.cachesize = cachesize;
+ }
+
+ @Override
+ public Dependencies resolve(SootClass sc) {
+ InputStream d = null;
+ try {
+
+ // ideally replace index (24) into cookie with the runtime val for offset of romclass address
+ // but no current way to know that value from the scc/jvm side
+ long addr = 0;
+ for (int i = 0; i < 8; i++) {
+ addr += ((long) cookiesource[i + 24] & 0xffL) << (8 * i);
+ }
+
+ Dependencies deps = new Dependencies();
+ SootClassBuilder scb = new SootClassBuilder(sc);
+ tryWithMemModel(addr, scb);
+ deps.typesToSignature.addAll(scb.getDeps());
+ return deps;
+ } catch (Exception e) {
+ throw new RuntimeException("Error: Failed to create class reader from class source.", e);
+ } finally {
+ try {
+ if (d != null) {
+ d.close();
+ d = null;
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("Error: Failed to close source input stream.", e);
+ } finally {
+ close();
+ }
+ }
+ }
+
+ void tryWithMemModel(long addr, SootClassBuilder scb) {
+
+ IProcess proc = (IProcess) memory.getMemory();
+ try {
+ // setup DDR - init datatype
+ assert proc != null : "Process should not be null";
+ IVMData aVMData = VMDataFactory.getVMData(proc);
+ assert aVMData != null : "VMDATA should not be null";
+
+ // now add the memory source
+ memory.addMemorySource(this.cacheaddr, this.cachesize);
+
+ // can force our wrapper to be loaded by J9DDRClassLoader
+ // additionally, this is why this must be built with OpenJ9 JVM
+ aVMData.bootstrap("com.ibm.j9ddr.vm29.ROMClassWrapper", new Object[] { addr, scb, memory });
+
+ } catch (Exception e) {
+ System.out.println("Could not setup ddr" + e.getMessage());
+ e.printStackTrace(System.out);
+ }
+
+ }
+}
diff --git a/src/main/java/soot/cache/CacheMemorySingleton.java b/src/main/java/soot/cache/CacheMemorySingleton.java
new file mode 100644
index 00000000000..84892f5f59a
--- /dev/null
+++ b/src/main/java/soot/cache/CacheMemorySingleton.java
@@ -0,0 +1,97 @@
+package soot.cache;
+
+/*-
+ * #%L
+ * Soot - a J*va Optimization Framework
+ * %%
+ * Copyright (C) 2020 Kristen Newbury
+ * %%
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU General Lesser Public
+ * License along with this program. If not, see
+ * .
+ * #L%
+ */
+
+import com.ibm.j9ddr.corereaders.memory.BufferedMemory;
+import com.ibm.j9ddr.corereaders.memory.BufferedMemorySource;
+
+import java.lang.reflect.Field;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+//@author Kristen Newbury
+
+public class CacheMemorySingleton {
+
+ // this singleton can only have one memory source ever added to it
+ private static CacheMemorySingleton cacheMemorySingleton;
+ private BufferedMemory memory;
+ private BufferedMemorySource memorySource;
+
+ private CacheMemorySingleton() {
+ memory = new BufferedMemory(ByteOrder.nativeOrder());
+ }
+
+ public static CacheMemorySingleton getInstance() {
+ if (cacheMemorySingleton == null) {
+ cacheMemorySingleton = new CacheMemorySingleton();
+ }
+ return cacheMemorySingleton;
+ }
+
+ public BufferedMemory getMemory() {
+ return memory;
+ }
+
+ public BufferedMemorySource getMemorySource() {
+ return memorySource;
+ }
+
+ public void addMemorySource(long addr, int size) {
+ if (cacheMemorySingleton != null && memorySource == null) {
+ ByteBuffer bb = makeCacheBuffer(addr, size);
+ memorySource = new BufferedMemorySource(addr, bb);
+ memory.addMemorySource(memorySource);
+ }
+ }
+
+ static final Field address;
+ static final Field capacity;
+
+ static {
+ // first set the buffer to be configurable
+ try {
+ address = Buffer.class.getDeclaredField("address");
+ address.setAccessible(true);
+ capacity = Buffer.class.getDeclaredField("capacity");
+ capacity.setAccessible(true);
+ } catch (NoSuchFieldException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ private ByteBuffer makeCacheBuffer(long addr, int size) {
+ // then set it up
+ try {
+ ByteBuffer bb = ByteBuffer.allocateDirect(0).order(ByteOrder.nativeOrder());
+ address.setLong(bb, addr);
+ capacity.setInt(bb, size);
+ bb.clear();
+ return bb;
+ } catch (IllegalAccessException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+}
diff --git a/src/main/java/soot/cache/ROMClassWrapper.java b/src/main/java/soot/cache/ROMClassWrapper.java
new file mode 100644
index 00000000000..a3eaba87d28
--- /dev/null
+++ b/src/main/java/soot/cache/ROMClassWrapper.java
@@ -0,0 +1,947 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2019 IBM Corp. and others
+ *
+ * This program and the accompanying materials are made available under
+ * the terms of the Eclipse Public License 2.0 which accompanies this
+ * distribution and is available at https://www.eclipse.org/legal/epl-2.0/
+ * or the Apache License, Version 2.0 which accompanies this distribution and
+ * is available at https://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * This Source Code may also be made available under the following
+ * Secondary Licenses when the conditions for such availability set
+ * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
+ * General Public License, version 2 with the GNU Classpath
+ * Exception [1] and GNU General Public License, version 2 with the
+ * OpenJDK Assembly Exception [2].
+ *
+ * [1] https://www.gnu.org/software/classpath/license.html
+ * [2] http://openjdk.java.net/legal/assembly-exception.html
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
+ *******************************************************************************/
+package com.ibm.j9ddr.vm29;
+
+import com.ibm.j9ddr.CorruptDataException;
+import com.ibm.j9ddr.IBootstrapRunnable;
+import com.ibm.j9ddr.IVMData;
+import com.ibm.j9ddr.InvalidDataTypeException;
+import com.ibm.j9ddr.corereaders.memory.BufferedMemorySource;
+import com.ibm.j9ddr.corereaders.memory.MemoryFault;
+import com.ibm.j9ddr.vm29.j9.BCNames;
+import com.ibm.j9ddr.vm29.j9.ConstantPoolHelpers;
+import com.ibm.j9ddr.vm29.j9.J9ROMFieldShapeIterator;
+import com.ibm.j9ddr.vm29.j9.ROMHelp;
+import com.ibm.j9ddr.vm29.pointer.FloatPointer;
+import com.ibm.j9ddr.vm29.pointer.I64Pointer;
+import com.ibm.j9ddr.vm29.pointer.SelfRelativePointer;
+import com.ibm.j9ddr.vm29.pointer.U16Pointer;
+import com.ibm.j9ddr.vm29.pointer.U32Pointer;
+import com.ibm.j9ddr.vm29.pointer.generated.J9ExceptionInfoPointer;
+import com.ibm.j9ddr.vm29.pointer.generated.J9ROMClassPointer;
+import com.ibm.j9ddr.vm29.pointer.generated.J9ROMClassRefPointer;
+import com.ibm.j9ddr.vm29.pointer.generated.J9ROMConstantPoolItemPointer;
+import com.ibm.j9ddr.vm29.pointer.generated.J9ROMFieldRefPointer;
+import com.ibm.j9ddr.vm29.pointer.generated.J9ROMFieldShapePointer;
+import com.ibm.j9ddr.vm29.pointer.generated.J9ROMMethodHandleRefPointer;
+import com.ibm.j9ddr.vm29.pointer.generated.J9ROMMethodPointer;
+import com.ibm.j9ddr.vm29.pointer.generated.J9ROMMethodRefPointer;
+import com.ibm.j9ddr.vm29.pointer.generated.J9ROMMethodTypeRefPointer;
+import com.ibm.j9ddr.vm29.pointer.generated.J9ROMNameAndSignaturePointer;
+import com.ibm.j9ddr.vm29.pointer.generated.J9ROMSingleSlotConstantRefPointer;
+import com.ibm.j9ddr.vm29.pointer.generated.J9ROMStaticFieldShapePointer;
+import com.ibm.j9ddr.vm29.pointer.generated.J9ROMStringRefPointer;
+import com.ibm.j9ddr.vm29.pointer.generated.J9UTF8Pointer;
+import com.ibm.j9ddr.vm29.pointer.helper.J9ROMClassHelper;
+import com.ibm.j9ddr.vm29.pointer.helper.J9ROMMethodHelper;
+import com.ibm.j9ddr.vm29.pointer.helper.J9UTF8Helper;
+import com.ibm.j9ddr.vm29.types.UDATA;
+
+import java.nio.ByteOrder;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Handle;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+import soot.asm.SootClassBuilder;
+import soot.cache.CacheMemorySingleton;
+
+/*
+ * This implementation strongly relies upon the visitor invoke pattern defined in ASM Classreader:
+ * https://gitlab.ow2.org/asm/asm/blob/ASM_5_2/src/org/objectweb/asm/ClassReader.java
+ * HOWEVER, did not want inheritance bc need to avoid asm ClassReader constructor behaviour which relies upon
+ * many hardcoded indices
+ */
+
+public class ROMClassWrapper implements IBootstrapRunnable {
+
+ // might want to fix. currently stolen hardcode from
+ // https://github.com/eclipse/openj9/blob/v0.14.0-release/runtime/oti/j9nonbuilder.h#L1965
+ // the reason is that these are only defined in: com.ibm.j9ddr.vm29.structure.J9BCTranslationData
+ // and only sizeof is exposed in:
+ // openj9/debugtools/DDR_VM/src/com/ibm/j9ddr/vm29/pointer/generated/J9DescriptionBitsPointer.java
+ // though somehow bytecode dumper can use ...
+ // https://github.com/eclipse/openj9/blob/v0.14.0-release/debugtools/DDR_VM/src/com/ibm/j9ddr/vm29/tools/ddrinteractive/commands/ByteCodeDumper.java#L96
+ // but we are using the structure file, not a loaded class... so this may be the reason...
+
+ private int BCT_J9DescriptionCpTypeScalar = 0;
+ private int BCT_J9DescriptionCpTypeObject = 1;
+ private int BCT_J9DescriptionCpTypeClass = 2;
+ private int J9DescriptionCpTypeShift = 4;
+ private int J9AccStatic = 8;
+
+ private int J9CPTYPE_CLASS = 1;
+ private int J9CPTYPE_STRING = 2;
+ private int J9CPTYPE_INT = 3;
+ private int J9CPTYPE_FLOAT = 4;
+ private int J9CPTYPE_LONG = 5;
+ private int J9CPTYPE_DOUBLE = 6;
+ private int J9CPTYPE_FIELD = 7;
+ private int J9CPTYPE_INSTANCE_METHOD = 9;
+ private int J9CPTYPE_STATIC_METHOD = 10;
+ private int J9CPTYPE_HANDLE_METHOD = 11;
+ private int J9CPTYPE_INTERFACE_METHOD = 12;
+ private int J9CPTYPE_METHOD_TYPE = 13;
+ private int J9CPTYPE_METHODHANDLE = 14;
+
+ // https://github.com/eclipse/openj9/blob/master/runtime/oti/cfr.h
+ // CFR_ACC_PUBLIC | CFR_ACC_PRIVATE | CFR_ACC_PROTECTED | CFR_ACC_STATIC | CFR_ACC_FINAL | CFR_ACC_SYNCHRONIZED |
+ // CFR_ACC_BRIDGE | CFR_ACC_VARARGS | CFR_ACC_NATIVE | CFR_ACC_STRICT | CFR_ACC_ABSTRACT | CFR_ACC_SYNTHETIC)
+ private int METHOD_ACCESS_MASK = 0x00000001 | 0x00000002 | 0x00000004 | 0x00000008 | 0x00000010 | 0x00000020 | 0x00000040
+ | 0x00000080 | 0x00000100 | 0x00000800 | 0x00000400 | 0x00001000;
+
+ // J9FieldFlagConstant 0x400000
+ // J9FieldTypeDouble 0x180000
+ // J9FieldTypeLong 0x380000
+ // J9FieldTypeFloat 0x100000
+ // J9FieldFlagObject 0x20000
+ // J9FieldTypeByte 0x200000
+
+ // likely less efficient than hardcoding the ints, but this is easier to read and check since the vals in nonbuilder
+ // are in hex
+ private int J9FieldTypeDouble = Integer.parseInt("180000", 16);
+ private int J9FieldTypeLong = Integer.parseInt("380000", 16);
+ private int J9FieldFlagObject = Integer.parseInt("20000", 16);
+ private int J9FieldFlagConstant = Integer.parseInt("400000", 16);
+ private int J9FieldTypeFloat = Integer.parseInt("100000", 16);
+ private int J9FieldTypeMask = Integer.parseInt("380000", 16);
+ private int J9FieldTypeByte = Integer.parseInt("200000", 16);
+ /////////////////////////////////////
+
+ private J9ROMClassPointer pointer;
+ private CacheMemorySingleton cacheMem;
+ private static ClassVisitor classVisitor;
+
+ // classreader specific attributes
+ static final boolean FRAMES = true;
+
+ public void run(IVMData vmData, Object[] userData) {
+
+ Long addr = new Long((long) userData[0]);
+ this.pointer = J9ROMClassPointer.cast(addr);
+
+ this.classVisitor = (SootClassBuilder) userData[1];
+
+ // need this for method iter, getting a bit much to have everyone here
+ this.cacheMem = (CacheMemorySingleton) userData[2];
+
+ accept(this.classVisitor);
+ }
+
+ public static ClassVisitor getClassVisitor() {
+ return classVisitor;
+ }
+
+ public void accept(final ClassVisitor classVisitor) {
+
+ try {
+ int version = pointer.majorVersion().intValue();
+ int classModifiers = pointer.modifiers().intValue();
+ String classname = J9UTF8Helper.stringValue(pointer.className());
+ J9UTF8Pointer superclassPointer = pointer.superclassName();
+ String superclassname;
+ // java.lang.Object has no superclass
+ if (superclassPointer == J9UTF8Pointer.NULL) {
+ superclassname = null;
+ } else {
+ superclassname = J9UTF8Helper.stringValue(superclassPointer);
+ }
+
+ // reference to constant pool
+ J9ROMConstantPoolItemPointer constantPool = J9ROMClassHelper.constantPool(pointer);
+
+ // header class info
+ // version, int access, String name, String signature, String superName, String[] interfaces
+ classVisitor.visit(version, classModifiers, classname, "", superclassname, new String[] {});
+
+ readFields(classVisitor, constantPool);
+
+ // method handling
+ int methodCount = pointer.romMethodCount().intValue();
+ J9ROMMethodPointer romMethod = pointer.romMethods();
+ for (int i = 0; i < methodCount; i++) {
+ readMethod(romMethod, constantPool);
+ romMethod = ROMHelp.nextROMMethod(romMethod);
+ }
+
+ } catch (Exception e) {
+ System.out.println("Issue in visitor pattern driving: " + e.getMessage());
+ e.printStackTrace(System.out);
+ }
+ // finish up
+ classVisitor.visitEnd();
+ }
+
+ void readFields(ClassVisitor classVisitor, J9ROMConstantPoolItemPointer constantPool) throws CorruptDataException {
+
+ FieldVisitor fv = null;
+ Object value = null;
+
+ // FieldVisitor visitField(int access, String name, String desc, String signature, Object value
+ UDATA romFieldCount = pointer.romFieldCount();
+ J9ROMFieldShapeIterator iterator = new J9ROMFieldShapeIterator(pointer.romFields(), romFieldCount);
+ J9ROMFieldShapePointer currentField = null;
+
+ while (iterator.hasNext()) {
+ currentField = (J9ROMFieldShapePointer) iterator.next();
+
+ String name = J9UTF8Helper.stringValue(currentField.nameAndSignature().name());
+ String signature = J9UTF8Helper.stringValue(currentField.nameAndSignature().signature());
+
+ if (!currentField.modifiers().bitAnd(J9AccStatic).eq(0)) {
+
+ // if its static, we should get its initial value:
+ // https://github.com/eclipse/openj9/blob/v0.14.0-release/runtime/oti/j9nonbuilder.h#L686
+
+ value = getStaticFieldValue(currentField.modifiers(), J9ROMStaticFieldShapePointer.cast(currentField), constantPool);
+
+ }
+
+ // visitField(int access, String name, String desc, String signature, Object value)
+ fv = classVisitor.visitField(currentField.modifiers().intValue(), name, signature, signature, value);
+ fv.visitEnd();
+ value = null;
+ }
+
+ }
+
+ void readMethod(J9ROMMethodPointer romMethod, J9ROMConstantPoolItemPointer constantPool) throws CorruptDataException {
+ // method info
+
+ int methodModifiers = romMethod.modifiers().intValue();
+ J9ROMNameAndSignaturePointer nameAndSignature = romMethod.nameAndSignature();
+ String name = J9UTF8Helper.stringValue(nameAndSignature.name());
+ String signature = J9UTF8Helper.stringValue(nameAndSignature.signature());
+
+ // for debugging only
+ /*
+ * if(name.contains("insert-some-method-name-here")){ System.out.println("---------------------------------");
+ * System.out.println("DUMPING copyof"); long dumpFlags = (this.cacheMem.getMemorySource().getByteOrder() ==
+ * ByteOrder.BIG_ENDIAN) ? 1 : 0; J9BCUtil.j9bcutil_dumpRomMethod(System.out, romMethod, pointer, dumpFlags,
+ * J9BCUtil.BCUtil_DumpAnnotations); System.out.println("---------------------------------"); }
+ */
+
+ int maxStack = romMethod.maxStack().intValue();
+ int maxLocals = romMethod.tempCount().intValue() + romMethod.argCount().intValue();
+ int argCount = romMethod.argCount().intValue();
+
+ int romMethodSize = J9ROMMethodHelper.bytecodeSize(romMethod).intValue();
+
+ long bytecodeSt = J9ROMMethodHelper.bytecodes(romMethod).longValue();
+ long bytecodeEnd = J9ROMMethodHelper.bytecodeEnd(romMethod).longValue();
+ char returnType = signature.charAt(signature.lastIndexOf(")") + 1);
+
+ String[] exceptions = getExceptions(romMethod);
+
+ MethodVisitor mv
+ = classVisitor.visitMethod(methodModifiers & METHOD_ACCESS_MASK, name, signature, signature, exceptions);
+ readMethodBody(bytecodeSt, bytecodeEnd, mv, constantPool, returnType);
+ // for now
+ mv.visitMaxs(maxStack, maxLocals);
+ mv.visitEnd();
+ }
+
+ String[] getExceptions(J9ROMMethodPointer romMethod) throws CorruptDataException {
+
+ if (J9ROMMethodHelper.hasExceptionInfo(romMethod)) {
+
+ J9ExceptionInfoPointer exceptionData = ROMHelp.J9_EXCEPTION_DATA_FROM_ROM_METHOD(romMethod);
+ long throwCount = exceptionData.throwCount().longValue();
+ String[] exceptions = new String[(int) throwCount];
+
+ if (throwCount > 0) {
+ SelfRelativePointer currentThrowName = ROMHelp.J9EXCEPTIONINFO_THROWNAMES(exceptionData);
+ for (int i = 0; i < throwCount; i++) {
+ exceptions[i] = J9UTF8Helper.stringValue(J9UTF8Pointer.cast(currentThrowName.get()));
+ }
+ }
+ return exceptions;
+ }
+ return new String[] {};
+ }
+
+ Object getStaticFieldValue(UDATA modsFull, J9ROMStaticFieldShapePointer field, J9ROMConstantPoolItemPointer constantPool)
+ throws CorruptDataException {
+
+ // get just the type portion of the mods
+ int mods = modsFull.intValue() & J9FieldTypeMask;
+
+ // aka if not a null static
+ if (modsFull.anyBitsIn(J9FieldFlagConstant)) {
+
+ if (mods == J9FieldTypeLong) {
+ return new Long(field.initialValue().longValue());
+
+ } else if (mods == J9FieldTypeDouble) {
+
+ // field.initialValue is setup like a cp entry, even longValue() +double cast cannot get this as double
+ // so we manually read it, even though that relies on hard offsets
+ BufferedMemorySource src = this.cacheMem.getMemorySource();
+ long first = I64Pointer.cast(field.add(1)).at(0).longValue();
+ long second = I64Pointer.cast(field.add(2)).at(0).longValue();
+ // This is honestly the opposite of what we expect it to be, completely unsure of why
+ long constantvalue = (src.getByteOrder() == ByteOrder.BIG_ENDIAN) ? (second << 32) | (first & 0xffffffffL)
+ : (first << 32) | (second & 0xffffffffL);
+
+ return new Double(Double.longBitsToDouble(constantvalue));
+ }
+
+ else if (modsFull.allBitsIn(J9FieldFlagObject)) {
+ // this initial value is actually an index into the constant pool
+ J9ROMConstantPoolItemPointer info = constantPool.add(field.initialValue().intValue());
+ String value = J9UTF8Helper.stringValue(J9ROMStringRefPointer.cast(info).utf8Data());
+ return value;
+
+ } else {
+
+ /* by default, type is anything that can be read as an int, except for float */
+ if (mods == J9FieldTypeFloat) {
+ return new Float(Float.intBitsToFloat((int) field.initialValue().longValue()));
+ } else if (mods == J9FieldTypeByte) {
+ return new Byte(field.initialValue().byteValue());
+ } else {
+ try {
+ return new Integer(field.initialValue().intValue());
+ } catch (InvalidDataTypeException e) {
+ return new Integer((int) field.initialValue().longValue());
+ }
+ }
+ }
+ } else {
+ return null;
+ }
+
+ }
+
+ void readMethodBody(long bytecodeSt, long bytecodeEnd, MethodVisitor mv, J9ROMConstantPoolItemPointer constantPool,
+ char returnType) throws CorruptDataException {
+ // drives the visitor to define the body of the method
+ BufferedMemorySource src = this.cacheMem.getMemorySource();
+ long ptr = bytecodeSt;
+
+ // for our targets, as we find them
+ Label[] labels = findLabels(bytecodeSt, bytecodeEnd, ptr, src);
+
+ while (ptr < bytecodeEnd) {
+ int offset = (int) (ptr - bytecodeSt);
+ int opcode = (int) (src.getByte(ptr) & 0xFF);
+
+ // visit a label if there is one
+ Label l = labels[offset];
+ if (l != null) {
+ mv.visitLabel(l);
+ }
+
+ if ((opcode == BCNames.JBnop) || (opcode == BCNames.JBinvokeinterface2)) {
+ ptr += 1;
+ } else if ((opcode == BCNames.JBdefaultvalue) || (opcode == BCNames.JBwithfield)) {
+ // these only exist for #if defined(J9VM_OPT_VALHALLA_VALUE_TYPES)?
+ ptr += 2;
+ } else if (opcode == BCNames.JBiinc) {
+ int LVAindex = src.getByte(ptr + 1);
+ int increment = src.getByte(ptr + 2);
+ mv.visitIincInsn(LVAindex, increment);
+ ptr += 3;
+ } else if (opcode == BCNames.JBiincw) {
+ int LVAindex = src.getShort(ptr + 1);
+ int increment = src.getShort(ptr + 3);
+ mv.visitIincInsn(LVAindex, increment);
+ ptr += 6;
+ } else if (opcode == BCNames.JBmultianewarray) {
+
+ int index = src.getShort(ptr + 1);
+
+ J9ROMConstantPoolItemPointer info = constantPool.add(index);
+
+ int dim = src.getByte(ptr + 3) & 0xFF;
+
+ String arrName = J9UTF8Helper.stringValue(J9ROMStringRefPointer.cast(info).utf8Data());
+ mv.visitMultiANewArrayInsn(arrName, dim);
+ ptr += 4;
+ }
+ // maybe don't expect to see the returnFromConstructor:
+ // https://github.com/eclipse/openj9/blob/v0.14.0-release/runtime/compiler/ilgen/J9ByteCode.hpp
+ else if ((opcode == BCNames.JBreturnFromConstructor) || (opcode == BCNames.JBgenericReturn)
+ || (opcode == BCNames.JBreturn0)) {
+ mv.visitInsn(Opcodes.RETURN);
+ ptr += 1;
+ } else if ((opcode == BCNames.JBreturnC) || (opcode == BCNames.JBreturnS) || (opcode == BCNames.JBreturnB)
+ || (opcode == BCNames.JBreturnZ)) {
+ mv.visitInsn(Opcodes.IRETURN);
+ ptr += 1;
+ } else if ((opcode == BCNames.JBreturn1) || (opcode == BCNames.JBreturn2)) {
+ // return0,1,2 correspond to return(pop 0 slots), return(pop 1 slot) and return(pop 2 slots)
+ opcode = getReturnType(returnType);
+ mv.visitInsn(opcode);
+ ptr += 1;
+ } else if ((opcode == BCNames.JBinvokehandle) || (opcode == BCNames.JBinvokehandlegeneric)
+ || (opcode == BCNames.JBinvokestaticsplit) || (opcode == BCNames.JBinvokespecialsplit)) {
+ // TODO handle
+ ptr += 3;
+ } else if ((opcode == BCNames.JBiload0) || (opcode == BCNames.JBiload1) || (opcode == BCNames.JBiload2)
+ || (opcode == BCNames.JBiload3) || (opcode == BCNames.JBlload0) || (opcode == BCNames.JBlload1)
+ || (opcode == BCNames.JBlload2) || (opcode == BCNames.JBlload3) || (opcode == BCNames.JBfload0)
+ || (opcode == BCNames.JBfload1) || (opcode == BCNames.JBfload2) || (opcode == BCNames.JBfload3)
+ || (opcode == BCNames.JBdload0) || (opcode == BCNames.JBdload1) || (opcode == BCNames.JBdload2)
+ || (opcode == BCNames.JBdload3) || (opcode == BCNames.JBaload0) || (opcode == BCNames.JBaload1)
+ || (opcode == BCNames.JBaload2) || (opcode == BCNames.JBaload3) ||
+
+ (opcode == BCNames.JBistore0) || (opcode == BCNames.JBistore1) || (opcode == BCNames.JBistore2)
+ || (opcode == BCNames.JBistore3) || (opcode == BCNames.JBlstore0) || (opcode == BCNames.JBlstore1)
+ || (opcode == BCNames.JBlstore2) || (opcode == BCNames.JBlstore3) || (opcode == BCNames.JBfstore0)
+ || (opcode == BCNames.JBfstore1) || (opcode == BCNames.JBfstore2) || (opcode == BCNames.JBfstore3)
+ || (opcode == BCNames.JBdstore0) || (opcode == BCNames.JBdstore1) || (opcode == BCNames.JBdstore2)
+ || (opcode == BCNames.JBdstore3) || (opcode == BCNames.JBastore0) || (opcode == BCNames.JBastore1)
+ || (opcode == BCNames.JBastore2) || (opcode == BCNames.JBastore3)) {
+ if (opcode > Opcodes.ISTORE) {
+
+ opcode -= 59; // ISTORE_0
+ mv.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), opcode & 0x3);
+ } else {
+
+ opcode -= 26;
+ mv.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), opcode & 0x3);
+ }
+ ptr += 1;
+ } else if (opcode == BCNames.JBaload0getfield) {
+ // handle this as an aload0, followed by a getfield (where the index is 2 bytes in?)
+ // https://github.com/eclipse/openj9/blob/v0.14.0-release/runtime/vm/BytecodeInterpreter.hpp#L6480
+ mv.visitVarInsn(25, 0);
+ int index = src.getUnsignedShort(ptr + 2);
+ J9ROMConstantPoolItemPointer info = constantPool.add(index);
+
+ J9ROMFieldRefPointer romFieldRef = J9ROMFieldRefPointer.cast(info);
+ String owner
+ = J9UTF8Helper.stringValue(J9ROMClassRefPointer.cast(constantPool.add(romFieldRef.classRefCPIndex())).name());
+
+ J9ROMNameAndSignaturePointer nameAndSig = romFieldRef.nameAndSignature();
+ String name = J9UTF8Helper.stringValue(nameAndSig.name());
+ String desc = J9UTF8Helper.stringValue(nameAndSig.signature());
+ mv.visitFieldInsn(180, owner, name, desc);
+ ptr += 4;
+ } else if ((opcode == BCNames.JBifeq) || (opcode == BCNames.JBifne) || (opcode == BCNames.JBiflt)
+ || (opcode == BCNames.JBifge) || (opcode == BCNames.JBifgt) || (opcode == BCNames.JBifle)
+ || (opcode == BCNames.JBificmpeq) || (opcode == BCNames.JBificmpne) || (opcode == BCNames.JBificmplt)
+ || (opcode == BCNames.JBificmpge) || (opcode == BCNames.JBificmpgt) || (opcode == BCNames.JBificmple)
+ || (opcode == BCNames.JBifacmpeq) || (opcode == BCNames.JBifacmpne) || (opcode == BCNames.JBgoto)
+ || (opcode == BCNames.JBifnull) || (opcode == BCNames.JBifnonnull)) {
+ mv.visitJumpInsn(opcode, labels[offset + src.getShort(ptr + 1)]);
+ ptr += 3;
+ } else if (opcode == BCNames.JBgotow) {
+ mv.visitJumpInsn(opcode, labels[offset + src.getInt(ptr + 1)]);
+ ptr += 5;
+ } else if (opcode == 196) {
+ // 196 == WIDE
+ // BCNames does not have a wide opcode...
+ // but both Walker https://github.com/eclipse/openj9/blob/v0.14.0-release/runtime/compiler/ilgen/Walker.cpp#L1494
+ // and ilgen maybe expect it to exist
+ // https://github.com/eclipse/openj9/blob/v0.14.0-release/runtime/compiler/ilgen/J9ByteCode.hpp#L111
+ opcode = src.getInt(ptr + 1);
+ if (opcode == BCNames.JBiinc) {
+ mv.visitIincInsn(src.getUnsignedShort(ptr + 2), src.getShort(ptr + 4));
+ ptr += 6;
+ } else {
+ mv.visitVarInsn(opcode, src.getUnsignedShort(ptr + 2));
+ ptr += 4;
+ }
+ } else if (opcode == BCNames.JBtableswitch) {
+ ptr = ptr + 4 - (offset & 3);
+ // reads instruction
+ int label = offset + src.getInt(ptr);
+ int min = src.getInt(ptr + 4);
+ int max = src.getInt(ptr + 8);
+ Label[] table = new Label[max - min + 1];
+ ptr += 12;
+ for (int i = 0; i < table.length; ++i) {
+ table[i] = labels[offset + src.getInt(ptr)];
+ ptr += 4;
+ }
+ mv.visitTableSwitchInsn(min, max, labels[label], table);
+ } else if (opcode == BCNames.JBlookupswitch) {
+ // skips 0 to 3 padding bytes
+ ptr = ptr + 4 - (offset & 3);
+ // reads instruction
+ int label = offset + src.getInt(ptr);
+ int len = src.getInt(ptr + 4);
+ int[] keys = new int[len];
+ Label[] values = new Label[len];
+ ptr += 8;
+ for (int i = 0; i < len; ++i) {
+ keys[i] = src.getInt(ptr);
+ values[i] = labels[offset + src.getInt(ptr + 4)];
+ ptr += 8;
+ }
+ mv.visitLookupSwitchInsn(labels[label], keys, values);
+ } else if (opcode == BCNames.JBiloadw) {
+ mv.visitVarInsn(Opcodes.ILOAD, src.getInt(ptr + 1));
+ ptr += 3;
+ } else if (opcode == BCNames.JBlloadw) {
+ mv.visitVarInsn(Opcodes.LLOAD, src.getInt(ptr + 1));
+ ptr += 3;
+ } else if (opcode == BCNames.JBfloadw) {
+ mv.visitVarInsn(Opcodes.FLOAD, src.getInt(ptr + 1));
+ ptr += 3;
+ } else if (opcode == BCNames.JBdloadw) {
+ mv.visitVarInsn(Opcodes.DLOAD, src.getInt(ptr + 1));
+ ptr += 3;
+ } else if (opcode == BCNames.JBaloadw) {
+ mv.visitVarInsn(Opcodes.ALOAD, src.getInt(ptr + 1));
+ ptr += 3;
+ } else if (opcode == BCNames.JBistorew) {
+ mv.visitVarInsn(Opcodes.ISTORE, src.getInt(ptr + 1));
+ ptr += 3;
+ } else if (opcode == BCNames.JBlstorew) {
+ mv.visitVarInsn(Opcodes.LSTORE, src.getInt(ptr + 1));
+ ptr += 3;
+ } else if (opcode == BCNames.JBfstorew) {
+ mv.visitVarInsn(Opcodes.FSTORE, src.getInt(ptr + 1));
+ ptr += 3;
+ } else if (opcode == BCNames.JBdstorew) {
+ mv.visitVarInsn(Opcodes.DSTORE, src.getInt(ptr + 1));
+ ptr += 3;
+ } else if (opcode == BCNames.JBastorew) {
+ mv.visitVarInsn(Opcodes.ASTORE, src.getInt(ptr + 1));
+ ptr += 3;
+ } else if ((opcode == BCNames.JBistore) || (opcode == BCNames.JBlstore) || (opcode == BCNames.JBfstore)
+ || (opcode == BCNames.JBdstore) || (opcode == BCNames.JBastore) || (opcode == BCNames.JBiload)
+ || (opcode == BCNames.JBlload) || (opcode == BCNames.JBfload) || (opcode == BCNames.JBdload)
+ || (opcode == BCNames.JBaload)) {
+ mv.visitVarInsn(opcode, src.getByte(ptr + 1) & 0xFF);
+ ptr += 2;
+ } else if ((opcode == BCNames.JBnewarray) || (opcode == BCNames.JBbipush)) {
+ mv.visitIntInsn(opcode, src.getByte(ptr + 1));
+ ptr += 2;
+ } else if (opcode == BCNames.JBsipush) {
+ mv.visitIntInsn(opcode, src.getShort(ptr + 1));
+ ptr += 3;
+ }
+ // not sure if its most readable to handle all separate or do a immediate double check on op val
+ else if (opcode == BCNames.JBldc) {
+
+ mv.visitLdcInsn(readConst(src.getByte(ptr + 1) & 0xFF, constantPool));
+ ptr += 2;
+ } else if (opcode == BCNames.JBldcw) {
+ mv.visitLdcInsn(readConst(src.getShort(ptr + 1), constantPool));
+ ptr += 3;
+ } else if (opcode == BCNames.JBldc2lw) {
+
+ int index = src.getShort(ptr + 1);
+ J9ROMConstantPoolItemPointer info = constantPool.add(index);
+
+ // since we are working with infoslots the order check is a bit ugly against the mem model, but must do
+ long constantvalue = (src.getByteOrder() == ByteOrder.BIG_ENDIAN)
+ ? ((info.slot1().longValue()) << 32) | (info.slot2().longValue() & 0xffffffffL)
+ : ((info.slot2().longValue()) << 32) | (info.slot1().longValue() & 0xffffffffL);
+
+ mv.visitLdcInsn(constantvalue);
+ ptr += 3;
+ } else if (opcode == BCNames.JBldc2dw) {
+
+ int index = src.getShort(ptr + 1);
+ J9ROMConstantPoolItemPointer info = constantPool.add(index);
+
+ // since we are working with infoslots the order check is a bit ugly against the mem model, but must do
+ long constantvalue = (src.getByteOrder() == ByteOrder.BIG_ENDIAN)
+ ? ((info.slot1().longValue()) << 32) | (info.slot2().longValue() & 0xffffffffL)
+ : ((info.slot2().longValue()) << 32) | (info.slot1().longValue() & 0xffffffffL);
+ mv.visitLdcInsn(Double.longBitsToDouble(constantvalue));
+ ptr += 3;
+ } else if ((opcode == BCNames.JBgetstatic) || (opcode == BCNames.JBputstatic) || (opcode == BCNames.JBgetfield)
+ || (opcode == BCNames.JBputfield)) {
+
+ int index = src.getUnsignedShort(ptr + 1);
+ J9ROMConstantPoolItemPointer info = constantPool.add(index);
+
+ J9ROMFieldRefPointer romFieldRef = J9ROMFieldRefPointer.cast(info);
+ String owner
+ = J9UTF8Helper.stringValue(J9ROMClassRefPointer.cast(constantPool.add(romFieldRef.classRefCPIndex())).name());
+
+ J9ROMNameAndSignaturePointer nameAndSig = romFieldRef.nameAndSignature();
+ String name = J9UTF8Helper.stringValue(nameAndSig.name());
+ String desc = J9UTF8Helper.stringValue(nameAndSig.signature());
+ mv.visitFieldInsn(opcode, owner, name, desc);
+
+ ptr += 3;
+
+ // this has a strong duplication with the prev case except pointer types
+ // maybe can be cleaner
+ } else if ((opcode == BCNames.JBinvokevirtual) || (opcode == BCNames.JBinvokespecial)
+ || (opcode == BCNames.JBinvokestatic) || (opcode == BCNames.JBinvokeinterface)) {
+
+ int index = src.getUnsignedShort(ptr + 1);
+ J9ROMConstantPoolItemPointer info = constantPool.add(index);
+
+ J9ROMMethodRefPointer romMethodRef = J9ROMMethodRefPointer.cast(info);
+ UDATA classRefCPIndex = romMethodRef.classRefCPIndex();
+ J9ROMConstantPoolItemPointer cpItem = constantPool.add(classRefCPIndex);
+ J9ROMClassRefPointer romClassRef = J9ROMClassRefPointer.cast(cpItem);
+
+ String owner = J9UTF8Helper.stringValue(romClassRef.name());
+
+ J9ROMNameAndSignaturePointer nameAndSig = romMethodRef.nameAndSignature();
+ String name = J9UTF8Helper.stringValue(nameAndSig.name());
+ String desc = J9UTF8Helper.stringValue(nameAndSig.signature());
+
+ boolean itf = (opcode == BCNames.JBinvokeinterface);
+
+ mv.visitMethodInsn(opcode, owner, name, desc, itf);
+
+ // if (itf) {
+ // ptr += 5;
+ // } else {
+ ptr += 3;
+ // }
+ } else if (opcode == BCNames.JBinvokedynamic) {
+
+ int index = src.getShort(ptr + 1);
+
+ long callSiteCount = pointer.callSiteCount().longValue();
+ SelfRelativePointer callSiteData = SelfRelativePointer.cast(pointer.callSiteData());
+ U16Pointer bsmIndices = U16Pointer.cast(callSiteData.addOffset(4 * callSiteCount));
+
+ J9ROMNameAndSignaturePointer invokedNameAndSig = J9ROMNameAndSignaturePointer.cast(callSiteData.add(index).get());
+ String invokedName = J9UTF8Helper.stringValue(invokedNameAndSig.name());
+ String invokedDesc = J9UTF8Helper.stringValue(invokedNameAndSig.signature());
+
+ // gets a pointer to the exact entry in the callSiteData table to the bsm data of this invoked method
+ long bsmIndex = bsmIndices.at(index).longValue(); // Bootstrap method index
+
+ // get beginning of bsmData section, then the relevant entry
+ U16Pointer bsmDataCursor = bsmIndices.add(callSiteCount);
+ int currentBsmDataItem = 0;
+ // need to traverse to the point in the bootStrapMethodData array where this bsmIndex
+ // refers to, problem is that these are variable length since the contain unknown number args each
+ while (currentBsmDataItem != bsmIndex) {
+ // skip methodhandleref right off, just need to read num args
+ long bsmArgumentCount = bsmDataCursor.at(1).longValue();
+ bsmDataCursor = bsmDataCursor.add(2 + bsmArgumentCount);
+ currentBsmDataItem += 1;
+ }
+
+ J9ROMMethodHandleRefPointer methodHandleRef
+ = J9ROMMethodHandleRefPointer.cast(constantPool.add(bsmDataCursor.at(0).longValue()));
+
+ bsmDataCursor = bsmDataCursor.add(1);
+ J9ROMMethodRefPointer methodRef
+ = J9ROMMethodRefPointer.cast(constantPool.add(methodHandleRef.methodOrFieldRefIndex().longValue()));
+
+ // callee
+ J9ROMNameAndSignaturePointer nameAndSig = methodRef.nameAndSignature();
+ String name = J9UTF8Helper.stringValue(nameAndSig.name());
+ String desc = J9UTF8Helper.stringValue(nameAndSig.signature());
+
+ long bsmArgCount = bsmDataCursor.at(0).longValue();
+ bsmDataCursor = bsmDataCursor.add(1);
+
+ // map this info into the asm understanding of a handle
+ int methodType = methodHandleRef.handleTypeAndCpType().rightShift((int) J9DescriptionCpTypeShift).intValue();
+ J9ROMClassRefPointer classRef = J9ROMClassRefPointer.cast(constantPool.add(methodRef.classRefCPIndex().longValue()));
+ String owner = J9UTF8Helper.stringValue(classRef.name());
+ // public Handle(int tag, String owner, String name, String desc, boolean itf)
+ Handle bsm = new Handle(methodType, owner, name, desc, false);
+ Object[] bsmArgs = new Object[(int) bsmArgCount];
+
+ // populate the invoked method args array
+ for (int i = 0; i < bsmArgCount; i++) {
+ long argCPIndex = bsmDataCursor.at(0).longValue();
+ bsmArgs[i] = readConst((int) argCPIndex, constantPool);
+ bsmDataCursor = bsmDataCursor.add(1);
+ }
+
+ // how is providing name+desc not redundant with the bsm handle also haing those...
+ mv.visitInvokeDynamicInsn(invokedName, invokedDesc, bsm, bsmArgs);
+ ptr += 5;
+ } else if ((opcode == BCNames.JBnewdup) || (opcode == BCNames.JBnew) || (opcode == BCNames.JBanewarray)
+ || (opcode == BCNames.JBcheckcast) || (opcode == BCNames.JBinstanceof)) {
+ // newdup is the only openj9 specific
+ if (opcode == BCNames.JBnewdup) {
+ opcode = Opcodes.NEW;
+ }
+ int index = src.getShort(ptr + 1);
+ J9ROMConstantPoolItemPointer info = constantPool.add(index);
+ String classname = J9UTF8Helper.stringValue(J9ROMStringRefPointer.cast(info).utf8Data());
+ mv.visitTypeInsn(opcode, classname);
+ ptr += 3;
+ } else if (opcode == BCNames.JBsyncReturn0) {
+ mv.visitInsn(Opcodes.RETURN);
+ ptr += 1;
+ } else if ((opcode == BCNames.JBsyncReturn1) || (opcode == BCNames.JBsyncReturn2)) {
+ opcode = getReturnType(returnType);
+ mv.visitInsn(opcode);
+ ptr += 1;
+ } else {
+ try {
+ mv.visitInsn(opcode);
+ } catch (Exception e) {
+ System.out.println("Encountered some not handled openj9 specific opcode: " + opcode);
+ }
+ ptr += 1;
+ }
+ }
+ }
+
+ public int getReturnType(char returnType) {
+
+ // default is void return
+ int opcode = 177;
+
+ switch (returnType) {
+ case 'Z':
+ case 'B':
+ case 'C':
+ case 'S':
+ case 'I':
+ opcode = 172; // ireturn
+ break;
+ case 'J':
+ opcode = 173; // lreturn
+ break;
+ case 'F':
+ opcode = 174; // freturn
+ break;
+ case 'D':
+ opcode = 175; // dreturn
+ break;
+ case 'L':
+ case '[':
+ opcode = 176; // areturn
+ break;
+ default:
+ break; // void
+ }
+
+ return opcode;
+ }
+
+ // need to find labels before everything else
+ public Label[] findLabels(long bytecodeSt, long bytecodeEnd, long ptr, BufferedMemorySource src) throws MemoryFault {
+ Label[] labels = new Label[(int) (bytecodeEnd - bytecodeSt)];
+ while (ptr < bytecodeEnd) {
+ int offset = (int) (ptr - bytecodeSt);
+ int opcode = (int) (src.getByte(ptr) & 0xFF);
+
+ if ((opcode == BCNames.JBifeq) || (opcode == BCNames.JBifne) || (opcode == BCNames.JBiflt)
+ || (opcode == BCNames.JBifge) || (opcode == BCNames.JBifgt) || (opcode == BCNames.JBifle)
+ || (opcode == BCNames.JBificmpeq) || (opcode == BCNames.JBificmpne) || (opcode == BCNames.JBificmplt)
+ || (opcode == BCNames.JBificmpge) || (opcode == BCNames.JBificmpgt) || (opcode == BCNames.JBificmple)
+ || (opcode == BCNames.JBifacmpeq) || (opcode == BCNames.JBifacmpne) || (opcode == BCNames.JBgoto)
+ || (opcode == BCNames.JBifnull) || (opcode == BCNames.JBifnonnull)) {
+
+ createLabel(opcode, ptr, labels, src, bytecodeSt);
+ ptr += 3;
+ } else if (opcode == BCNames.JBgotow) {
+ createLabel(opcode, ptr, labels, src, bytecodeSt);
+ ptr += 5;
+ } else if (opcode == 196) {
+ // 196 == WIDE
+ // BCNames does not have a wide opcode...
+ // but both Walker https://github.com/eclipse/openj9/blob/v0.14.0-release/runtime/compiler/ilgen/Walker.cpp#L1494
+ // and ilgen maybe expect it to exist
+ // https://github.com/eclipse/openj9/blob/v0.14.0-release/runtime/compiler/ilgen/J9ByteCode.hpp#L111
+ opcode = src.getInt(ptr + 1);
+ if (opcode == BCNames.JBiinc) {
+ ptr += 6;
+ } else {
+ ptr += 4;
+ }
+ } else if ((opcode == BCNames.JBdefaultvalue) || (opcode == BCNames.JBwithfield) || (opcode == BCNames.JBiinc)
+ || (opcode == BCNames.JBistore) || (opcode == BCNames.JBlstore) || (opcode == BCNames.JBfstore)
+ || (opcode == BCNames.JBdstore) || (opcode == BCNames.JBastore) || (opcode == BCNames.JBiload)
+ || (opcode == BCNames.JBlload) || (opcode == BCNames.JBfload) || (opcode == BCNames.JBdload)
+ || (opcode == BCNames.JBaload) || (opcode == BCNames.JBnewarray) || (opcode == BCNames.JBbipush)
+ || (opcode == BCNames.JBldc)) {
+ ptr += 2;
+ }
+
+ else if (opcode == BCNames.JBiincw) {
+ ptr += 6;
+ } else if (opcode == BCNames.JBmultianewarray) {
+ ptr += 4;
+ }
+
+ else if ((opcode == BCNames.JBnewdup) || (opcode == BCNames.JBnew) || (opcode == BCNames.JBanewarray)
+ || (opcode == BCNames.JBcheckcast) || (opcode == BCNames.JBinstanceof) || (opcode == BCNames.JBiinc)
+ || (opcode == BCNames.JBnewdup) || (opcode == BCNames.JBinvokehandle) || (opcode == BCNames.JBinvokehandlegeneric)
+ || (opcode == BCNames.JBinvokestaticsplit) || (opcode == BCNames.JBinvokespecialsplit)
+ || (opcode == BCNames.JBiloadw) || (opcode == BCNames.JBistorew) || (opcode == BCNames.JBlloadw)
+ || (opcode == BCNames.JBlstorew) || (opcode == BCNames.JBdloadw) || (opcode == BCNames.JBfloadw)
+ || (opcode == BCNames.JBaloadw) || (opcode == BCNames.JBfstorew) || (opcode == BCNames.JBdstorew)
+ || (opcode == BCNames.JBastorew) || (opcode == BCNames.JBsipush) || (opcode == BCNames.JBldcw)
+ || (opcode == BCNames.JBldc2lw) || (opcode == BCNames.JBldc2dw) || (opcode == BCNames.JBgetstatic)
+ || (opcode == BCNames.JBputstatic) || (opcode == BCNames.JBgetfield) || (opcode == BCNames.JBputfield)
+ || (opcode == BCNames.JBinvokevirtual) || (opcode == BCNames.JBinvokespecial) || (opcode == BCNames.JBinvokestatic)
+ || (opcode == BCNames.JBinvokeinterface)) {
+ ptr += 3;
+ } else if (opcode == BCNames.JBinvokedynamic) {
+ ptr += 5;
+ }
+
+ else if (opcode == BCNames.JBtableswitch) {
+ ptr = ptr + 4 - (offset & 3);
+ // reads the default
+ addLabel(labels, offset + src.getInt(ptr));
+ int min = src.getInt(ptr + 4);
+ int max = src.getInt(ptr + 8);
+ Label[] table = new Label[max - min + 1];
+ ptr += 12;
+ for (int i = 0; i < table.length; ++i) {
+ addLabel(labels, offset + src.getInt(ptr));
+ ptr += 4;
+ }
+ } else if (opcode == BCNames.JBlookupswitch) {
+ // skips 0 to 3 padding bytes
+ ptr = ptr + 4 - (offset & 3);
+ // reads instruction
+ addLabel(labels, offset + src.getInt(ptr));
+ int len = src.getInt(ptr + 4);
+ int[] keys = new int[len];
+ Label[] values = new Label[len];
+ ptr += 8;
+ for (int i = 0; i < len; ++i) {
+ addLabel(labels, offset + src.getInt(ptr + 4));
+ ptr += 8;
+ }
+ } else {
+ ptr += 1;
+ }
+
+ }
+ return labels;
+ }
+
+ // populates a label table for us, to use later, that represent targets of jumps
+ public void createLabel(int opcode, long ptr, Label[] labels, BufferedMemorySource src, long methodSt) throws MemoryFault {
+ int offset;
+ if (opcode == BCNames.JBgotow) {
+ offset = src.getInt(ptr + 1);
+ } else {
+ offset = src.getShort(ptr + 1);
+ }
+ long target = ptr + offset;
+ int labelIndex = (int) (target - methodSt);
+
+ addLabel(labels, labelIndex);
+ }
+
+ public void addLabel(Label[] labels, int labelIndex) {
+ if (labels[labelIndex] == null) {
+ labels[labelIndex] = new Label();
+ }
+
+ }
+
+ /*
+ * Reads a constant pool info entry
+ *
+ */
+
+ public Object readConst(final int index, J9ROMConstantPoolItemPointer constantPool) throws CorruptDataException {
+
+ int HEX_RADIX = 16;
+ U32Pointer cpShapeDescription = J9ROMClassHelper.cpShapeDescription(pointer);
+ long shapeDesc = ConstantPoolHelpers.J9_CP_TYPE(cpShapeDescription, index);
+ BufferedMemorySource src = this.cacheMem.getMemorySource();
+
+ J9ROMConstantPoolItemPointer item = constantPool.add(index);
+
+ if (shapeDesc == J9CPTYPE_CLASS) {
+ J9ROMClassRefPointer romClassRef = J9ROMClassRefPointer.cast(item);
+ return J9UTF8Helper.stringValue(romClassRef.name());
+ } else if (shapeDesc == J9CPTYPE_STRING) {
+ J9ROMStringRefPointer romStringRef = J9ROMStringRefPointer.cast(item);
+ return J9UTF8Helper.stringValue(romStringRef.utf8Data());
+ } else if (shapeDesc == J9CPTYPE_INT) {
+ J9ROMSingleSlotConstantRefPointer singleSlotConstantRef = J9ROMSingleSlotConstantRefPointer.cast(item);
+ return new Integer((int) singleSlotConstantRef.data().longValue());
+ } else if (shapeDesc == J9CPTYPE_FLOAT) {
+ J9ROMSingleSlotConstantRefPointer singleSlotConstantRef = J9ROMSingleSlotConstantRefPointer.cast(item);
+ FloatPointer floatPtr = FloatPointer.cast(singleSlotConstantRef.dataEA());
+ return new Float(floatPtr.floatAt(0));
+ } else if (shapeDesc == J9CPTYPE_LONG) {
+ String hexValue = "";
+ if (src.getByteOrder() == ByteOrder.BIG_ENDIAN) {
+ hexValue += item.slot1().getHexValue();
+ hexValue += item.slot2().getHexValue().substring(2);
+ } else {
+ hexValue += item.slot2().getHexValue();
+ hexValue += item.slot1().getHexValue().substring(2);
+ }
+ long longValue = Long.parseLong(hexValue.substring(2), HEX_RADIX);
+ return new Long(longValue);
+ } else if (shapeDesc == J9CPTYPE_DOUBLE) {
+ String hexValue = "";
+ if (src.getByteOrder() == ByteOrder.BIG_ENDIAN) {
+ hexValue += item.slot1().getHexValue();
+ hexValue += item.slot2().getHexValue().substring(2);
+ } else {
+ hexValue += item.slot2().getHexValue();
+ hexValue += item.slot1().getHexValue().substring(2);
+ }
+ long longValue = Long.parseLong(hexValue.substring(2), HEX_RADIX);
+ double doubleValue = Double.longBitsToDouble(longValue);
+ return new Double(doubleValue);
+ } else if (shapeDesc == J9CPTYPE_FIELD) {
+ J9ROMFieldRefPointer romFieldRef = J9ROMFieldRefPointer.cast(item);
+ J9ROMClassRefPointer classRef = J9ROMClassRefPointer.cast(constantPool.add(romFieldRef.classRefCPIndex()));
+ J9ROMNameAndSignaturePointer nameAndSig = romFieldRef.nameAndSignature();
+ return J9UTF8Helper.stringValue(nameAndSig.name());
+ } else if ((shapeDesc == J9CPTYPE_INSTANCE_METHOD) || (shapeDesc == J9CPTYPE_STATIC_METHOD)
+ || (shapeDesc == J9CPTYPE_HANDLE_METHOD) || (shapeDesc == J9CPTYPE_INTERFACE_METHOD)) {
+ J9ROMMethodRefPointer romMethodRef = J9ROMMethodRefPointer.cast(item);
+ J9ROMClassRefPointer classRef = J9ROMClassRefPointer.cast(constantPool.add(romMethodRef.classRefCPIndex()));
+ J9ROMNameAndSignaturePointer nameAndSig = romMethodRef.nameAndSignature();
+ return J9UTF8Helper.stringValue(nameAndSig.name());
+ } else if (shapeDesc == J9CPTYPE_METHOD_TYPE) {
+ J9ROMMethodTypeRefPointer romMethodTypeRef = J9ROMMethodTypeRefPointer.cast(item);
+ return Type.getType(J9UTF8Helper.stringValue(J9UTF8Pointer.cast(romMethodTypeRef.signature())));
+ } else if (shapeDesc == J9CPTYPE_METHODHANDLE) {
+ J9ROMMethodHandleRefPointer methodHandleRef = J9ROMMethodHandleRefPointer.cast(item);
+ J9ROMMethodRefPointer methodRef
+ = J9ROMMethodRefPointer.cast(constantPool.add(methodHandleRef.methodOrFieldRefIndex()));
+ J9ROMClassRefPointer classRef = J9ROMClassRefPointer.cast(constantPool.add(methodRef.classRefCPIndex()));
+ J9ROMNameAndSignaturePointer nameAndSig = methodRef.nameAndSignature();
+ String owner = J9UTF8Helper.stringValue(classRef.name());
+ String name = J9UTF8Helper.stringValue(nameAndSig.name());
+ String signature = J9UTF8Helper.stringValue(nameAndSig.signature());
+
+ // for once, asm and romclass constants are fully aligned
+ // https://gitlab.ow2.org/asm/asm/blob/ASM_5_2/src/org/objectweb/asm/Opcodes.java#L101
+ // https://github.com/eclipse/openj9/blob/v0.14.0-release/runtime/oti/j9nonbuilder.h#L2165
+ long methodType = methodHandleRef.handleTypeAndCpType().rightShift((int) J9DescriptionCpTypeShift).longValue();
+
+ boolean itf = false;
+ if (methodType == Opcodes.H_INVOKEINTERFACE) {
+ itf = true;
+ }
+ // public Handle(int tag, String owner, String name, String desc, boolean itf)
+ return new Handle((int) methodType, owner, name, signature, itf);
+ } else {
+ System.out.println(" ");
+ return null;
+ }
+ }
+
+}
diff --git a/src/main/java/soot/options/OptionsBase.java b/src/main/java/soot/options/OptionsBase.java
index 6274038fa52..92b29321d76 100644
--- a/src/main/java/soot/options/OptionsBase.java
+++ b/src/main/java/soot/options/OptionsBase.java
@@ -115,6 +115,11 @@ public LinkedList classes() {
return classes;
}
+ public void addArgClass(String classname) {
+ classes.add(classname);
+ System.out.println("The classes in optionBase are: " + classes.toString());
+ }
+
public boolean setPhaseOption(String phase, String option) {
return PhaseOptions.v().processPhaseOptions(phase, option);
}
diff --git a/src/main/xml/options/soot_options.xml b/src/main/xml/options/soot_options.xml
index d8d3fd21f5e..713c12df295 100644
--- a/src/main/xml/options/soot_options.xml
+++ b/src/main/xml/options/soot_options.xml
@@ -680,6 +680,26 @@
as Soot's preference for the type of source files to read when
it looks for a class.
+
+ Cache
+ cache
+ Favour shared class cache as Soot source
+
+ Try to resolve classes first from the shared class cache found in
+ the Soot classpath. Fall back to .class and then .jimple files
+ only when unable to find a class in the cache.
+
+
+
+ Only Cache Source
+ only-cache
+ Use only shared class cache as Soot source
+
+ Try to resolve classes first from the shared class cache found in
+ the Soot classpath. Do not try any other types of files even when
+ unable to find a class in the cache.
+
+
Class File
c
| |