aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Watson2018-06-11 14:42:35 -0400
committerThomas Watson2018-08-10 10:17:28 -0400
commitdceb34eef2316ee15a3442e6b853af9be06861f7 (patch)
tree4931d3ac2aff3944e6fd9359a9b70ede2f5308a7
parentf90ab848bdcac80a46b82e1d2e85d818d77630ef (diff)
downloadrt.equinox.framework-dceb34eef2316ee15a3442e6b853af9be06861f7.tar.gz
rt.equinox.framework-dceb34eef2316ee15a3442e6b853af9be06861f7.tar.xz
rt.equinox.framework-dceb34eef2316ee15a3442e6b853af9be06861f7.zip
Bug 537505 - Support OpenJ9 CDS directly in the frameworkI20180812-2000I20180811-1500I20180810-2000
Change-Id: Ib93dd9ab8306b4ba89f9de1b93ea48b654e5bff8 Signed-off-by: Thomas Watson <tjwatson@us.ibm.com>
-rw-r--r--bundles/org.eclipse.osgi/build.properties3
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/cds/CDSBundleEntry.java102
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/cds/CDSBundleFile.java120
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/cds/CDSHookConfigurator.java52
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/cds/CDSHookImpls.java244
-rw-r--r--bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hookregistry/HookRegistry.java9
-rw-r--r--bundles/org.eclipse.osgi/osgi/j9stubs.jarbin0 -> 4081 bytes
7 files changed, 528 insertions, 2 deletions
diff --git a/bundles/org.eclipse.osgi/build.properties b/bundles/org.eclipse.osgi/build.properties
index 9ddb3ad0b..a3031af88 100644
--- a/bundles/org.eclipse.osgi/build.properties
+++ b/bundles/org.eclipse.osgi/build.properties
@@ -33,5 +33,6 @@ output.. = bin/
javacWarnings..=-raw,unchecked,hiding,unused,warningToken
jars.extra.classpath = osgi/osgi.annotation.jar,\
- osgi/function.interface.jar
+ osgi/function.interface.jar,\
+ osgi/j9stubs.jar
jre.compilation.profile = JavaSE-1.7
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/cds/CDSBundleEntry.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/cds/CDSBundleEntry.java
new file mode 100644
index 000000000..9e92911ef
--- /dev/null
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/cds/CDSBundleEntry.java
@@ -0,0 +1,102 @@
+/***********************************************************************
+ * IBM Confidential
+ * OCO Source Materials
+ *
+ * (C) Copyright IBM Corp. 2006, 2014
+ *
+ * The source code for this program is not published or otherwise divested
+ * of its trade secrets, irrespective of what has been deposited with the
+ * U.S. Copyright Office.
+ ************************************************************************/
+
+package org.eclipse.osgi.internal.cds;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import org.eclipse.osgi.storage.bundlefile.BundleEntry;
+
+/**
+ * A bundle entry for a class that is found in the shared classes cache
+ */
+public class CDSBundleEntry extends BundleEntry {
+ String path;
+ byte[] classbytes;
+ BundleEntry wrapped;
+
+ /**
+ * The constructor
+ * @param path the path to the class file
+ * @param classbytes the magic cookie bytes for the class in the shared cache
+ * @param wrapped the actual bundleEntry where the class comes from
+ */
+ public CDSBundleEntry(String path, byte[] classbytes, BundleEntry wrapped) {
+ super();
+ this.path = path;
+ this.classbytes = classbytes;
+ this.wrapped = wrapped;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry#getFileURL()
+ * uses the wrapped bundle file to get the actual file url to the content of
+ * the class on disk.
+ *
+ * This should is likely never to be called.
+ */
+ public URL getFileURL() {
+ return wrapped.getFileURL();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry#getInputStream()
+ * wraps the classbytes into a ByteArrayInputStream. This should not be used
+ * by classloading.
+ */
+ public InputStream getInputStream() throws IOException {
+ // someone is trying to get the real bytes of the class file!!
+ // just return the entry from the wrapped file instead of the magic cookie
+ return wrapped.getInputStream();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry#getBytes()
+ * if classbytes is not null, it returns the magic cookie for the shared class. This is used to define
+ * the class during class loading.
+ * if classbytes is null, it gets the contents from actual BundleEntry and caches it in classbytes.
+ */
+ public byte[] getBytes() throws IOException {
+ if (classbytes == null) {
+ classbytes = wrapped.getBytes();
+ }
+ return classbytes;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.osgi.baseadaptor.bundlefile.BundleEntry#getLocalURL()
+ * uses the wrapped bundle file to get the actual local url to the content of
+ * the class on disk.
+ *
+ * This should is likely never to be called.
+ */
+ public URL getLocalURL() {
+ return wrapped.getLocalURL();
+ }
+
+ public String getName() {
+ return path;
+ }
+
+ public long getSize() {
+ return wrapped.getSize();
+ }
+
+ public long getTime() {
+ return wrapped.getTime();
+ }
+}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/cds/CDSBundleFile.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/cds/CDSBundleFile.java
new file mode 100644
index 000000000..33769533f
--- /dev/null
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/cds/CDSBundleFile.java
@@ -0,0 +1,120 @@
+/***********************************************************************
+ * IBM Confidential
+ * OCO Source Materials
+ *
+ * (C) Copyright IBM Corp. 2006, 2014
+ *
+ * The source code for this program is not published or otherwise divested
+ * of its trade secrets, irrespective of what has been deposited with the
+ * U.S. Copyright Office.
+ ************************************************************************/
+
+package org.eclipse.osgi.internal.cds;
+
+import com.ibm.oti.shared.SharedClassURLHelper;
+import java.net.MalformedURLException;
+import java.net.URL;
+import org.eclipse.osgi.storage.bundlefile.BundleEntry;
+import org.eclipse.osgi.storage.bundlefile.BundleFile;
+import org.eclipse.osgi.storage.bundlefile.BundleFileWrapper;
+
+/**
+ * Wraps an actual BundleFile object for purposes of loading classes from the
+ * shared classes cache.
+ */
+public class CDSBundleFile extends BundleFileWrapper {
+ private URL url; // the URL to the content of the real bundle file
+ private SharedClassURLHelper urlHelper; // the url helper set by the classloader
+ private boolean primed = false;
+
+ /**
+ * The constructor
+ * @param wrapped the real bundle file
+ */
+ public CDSBundleFile(BundleFile wrapped) {
+ super(wrapped);
+ // get the url to the content of the real bundle file
+ try {
+ this.url = new URL("file", "", wrapped.getBaseFile().getAbsolutePath()); //$NON-NLS-1$ //$NON-NLS-2$
+ } catch (MalformedURLException e) {
+ // do nothing
+ }
+ }
+
+ public CDSBundleFile(BundleFile bundleFile, SharedClassURLHelper urlHelper) {
+ this(bundleFile);
+ this.urlHelper = urlHelper;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.osgi.storage.bundlefile.BundleFile#getEntry(java.lang.String)
+ *
+ * If path is not for a class then just use the wrapped bundle file to answer the call.
+ * If the path is for a class, it returns a CDSBundleEntry object.
+ * If the path is for a class, it will look for the magic cookie in the
+ * shared classes cache. If found, the bytes representing the magic cookie are stored in CDSBundleEntry object.
+ */
+ public BundleEntry getEntry(String path) {
+ String classFileExt = ".class"; //$NON-NLS-1$
+ BundleEntry wrappedEntry = super.getEntry(path);
+ if (wrappedEntry == null) {
+ return null;
+ }
+ if ((false == primed) || (false == path.endsWith(classFileExt))) {
+ return wrappedEntry;
+ }
+
+ byte[] classbytes = getClassBytes(path.substring(0, path.length() - classFileExt.length()));
+ BundleEntry be = new CDSBundleEntry(path, classbytes, wrappedEntry);
+ return be;
+ }
+
+ /**
+ * Returns the file url to the content of the actual bundle file
+ * @return the file url to the content of the actual bundle file
+ */
+ URL getURL() {
+ return url;
+ }
+
+ /**
+ * Returns the url helper for this bundle file. This is set by the
+ * class loading hook
+ * @return the url helper for this bundle file
+ */
+ SharedClassURLHelper getURLHelper() {
+ return urlHelper;
+ }
+
+ /**
+ * Sets the url helper for this bundle file. This is called by the
+ * class loading hook.
+ * @param urlHelper the url helper
+ */
+ void setURLHelper(SharedClassURLHelper urlHelper) {
+ this.urlHelper = urlHelper;
+ this.primed = false; // always unprime when a new urlHelper is set
+ }
+
+ /**
+ * Sets the primed flag for the bundle file. This is called by the
+ * class loading hook after the first class has been loaded from disk for
+ * this bundle file.
+ * @param primed the primed flag
+ */
+ void setPrimed(boolean primed) {
+ this.primed = primed;
+ }
+
+ /**
+ * Searches in the shared classes cache for the specified class name.
+ * @param name the name of the class
+ * @return the magic cookie to the shared class or null if the class is not in the cache.
+ */
+ private byte[] getClassBytes(String name) {
+ if (urlHelper == null || url == null)
+ return null;
+ return urlHelper.findSharedClass(null, url, name);
+ }
+}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/cds/CDSHookConfigurator.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/cds/CDSHookConfigurator.java
new file mode 100644
index 000000000..98f671178
--- /dev/null
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/cds/CDSHookConfigurator.java
@@ -0,0 +1,52 @@
+/***********************************************************************
+ * IBM Confidential
+ * OCO Source Materials
+ *
+ * (C) Copyright IBM Corp. 2006
+ *
+ * The source code for this program is not published or otherwise divested
+ * of its trade secrets, irrespective of what has been deposited with the
+ * U.S. Copyright Office.
+ ************************************************************************/
+
+package org.eclipse.osgi.internal.cds;
+
+import org.eclipse.osgi.internal.hookregistry.HookConfigurator;
+import org.eclipse.osgi.internal.hookregistry.HookRegistry;
+
+public class CDSHookConfigurator implements HookConfigurator {
+
+ private static final String SUPPRESS_ERRORS = "j9.cds.suppresserrors"; //$NON-NLS-1$
+ private static final String DISABLE_CDS = "j9.cds.disable"; //$NON-NLS-1$
+ private static final String OLD_CDS_CONFIGURATOR = "com.ibm.cds.CDSHookConfigurator"; //$NON-NLS-1$
+ private static final String J9_SHARED_CLASS_HELPER_CLASS = "com.ibm.oti.shared.SharedClassHelperFactory"; //$NON-NLS-1$
+
+ public void addHooks(HookRegistry hookRegistry) {
+ boolean disableCDS = "true".equals(hookRegistry.getConfiguration().getProperty(DISABLE_CDS)); //$NON-NLS-1$
+ if (disableCDS) {
+ return;
+ }
+ // check for the external com.ibm.cds system.bundle fragment
+ try {
+ Class.forName(OLD_CDS_CONFIGURATOR);
+ // the old com.ibm.cds fragment is installed; disable build-in one
+ return;
+ } catch (ClassNotFoundException e) {
+ // expected
+ }
+ try {
+ Class.forName(J9_SHARED_CLASS_HELPER_CLASS);
+ } catch (ClassNotFoundException e) {
+ boolean reportErrors = "false".equals(hookRegistry.getConfiguration().getProperty(SUPPRESS_ERRORS)); //$NON-NLS-1$
+ // not running on J9
+ if (reportErrors) {
+ System.err.println("The J9 Class Sharing Adaptor will not work in this configuration."); //$NON-NLS-1$
+ System.err.println("You are not running on a J9 Java VM."); //$NON-NLS-1$
+ }
+ return;
+ }
+
+ new CDSHookImpls().registerHooks(hookRegistry);
+ }
+
+}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/cds/CDSHookImpls.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/cds/CDSHookImpls.java
new file mode 100644
index 000000000..6e7bcb054
--- /dev/null
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/cds/CDSHookImpls.java
@@ -0,0 +1,244 @@
+/***********************************************************************
+ * IBM Confidential
+ * OCO Source Materials
+ *
+ * (C) Copyright IBM Corp. 2006
+ *
+ * The source code for this program is not published or otherwise divested
+ * of its trade secrets, irrespective of what has been deposited with the
+ * U.S. Copyright Office.
+ ************************************************************************/
+
+package org.eclipse.osgi.internal.cds;
+
+import com.ibm.oti.shared.HelperAlreadyDefinedException;
+import com.ibm.oti.shared.Shared;
+import com.ibm.oti.shared.SharedClassHelperFactory;
+import com.ibm.oti.shared.SharedClassURLHelper;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import org.eclipse.osgi.internal.hookregistry.BundleFileWrapperFactoryHook;
+import org.eclipse.osgi.internal.hookregistry.ClassLoaderHook;
+import org.eclipse.osgi.internal.hookregistry.HookRegistry;
+import org.eclipse.osgi.internal.loader.ModuleClassLoader;
+import org.eclipse.osgi.internal.loader.classpath.ClasspathEntry;
+import org.eclipse.osgi.internal.loader.classpath.ClasspathManager;
+import org.eclipse.osgi.storage.BundleInfo.Generation;
+import org.eclipse.osgi.storage.bundlefile.BundleEntry;
+import org.eclipse.osgi.storage.bundlefile.BundleFile;
+import org.eclipse.osgi.storage.bundlefile.BundleFileWrapper;
+import org.eclipse.osgi.storage.bundlefile.BundleFileWrapperChain;
+
+public class CDSHookImpls extends ClassLoaderHook implements BundleFileWrapperFactoryHook {
+ private static SharedClassHelperFactory factory = Shared.getSharedClassHelperFactory();
+ private static java.lang.reflect.Method minimizeMethod = null;
+ private static boolean hasMinimizeMethod = true; /* Assume true to begin with */
+
+ // With Equinox bug 226038 (v3.4), the framework will now pass an instance
+ // of BundleFileWrapperChain rather than the wrapped BundleFile. This is
+ // so that multiple wrapping hooks can each wrap the BundleFile and all
+ // wrappers are accessible.
+ //
+ // The Wrapper chain will look like below:
+ // WrapperChain -> Wrapper<N> -> WrapperChain -> CDSBundleFile -> WrapperChain -> BundleFile
+ //
+ private static CDSBundleFile getCDSBundleFile(BundleFile bundleFile) {
+ CDSBundleFile cdsBundleFile = null;
+
+ if (bundleFile instanceof BundleFileWrapperChain) {
+ // Equinox > 3.4
+ BundleFile wrapped = null;
+ do {
+ wrapped = ((BundleFileWrapperChain) bundleFile).getWrapped();
+ if (wrapped instanceof CDSBundleFile) {
+ cdsBundleFile = (CDSBundleFile) wrapped;
+ break;
+ }
+
+ //Go to next wrapper chain.
+ bundleFile = ((BundleFileWrapperChain) bundleFile).getNext();
+ } while (wrapped != null);
+ }
+ return cdsBundleFile;
+ }
+
+ public void recordClassDefine(String name, Class<?> clazz, byte[] classbytes, ClasspathEntry classpathEntry, BundleEntry entry, ClasspathManager manager) { // only attempt to record the class define if:
+ // 1) the class was found (clazz != null)
+ // 2) the class has the magic class number CAFEBABE indicating a real class
+ // 3) the bundle file for the classpath entry is of type CDSBundleFile
+ // 4) class bytes is same as passed to weaving hook i.e. weaving hook did not modify the class bytes
+ if ((null == clazz) || (false == hasMagicClassNumber(classbytes)) || (null == getCDSBundleFile(classpathEntry.getBundleFile()))) {
+ return;
+ }
+ try {
+ // check if weaving hook modified the class bytes
+ byte originalClassBytes[] = entry.getBytes();
+ if (originalClassBytes != classbytes) {
+ // weaving hook has potentially modified the class bytes
+ boolean modified = false;
+ if (originalClassBytes.length == classbytes.length) {
+ // do a byte-by-byte comparison
+ modified = !Arrays.equals(classbytes, originalClassBytes);
+ } else {
+ modified = true;
+ }
+ if (modified) {
+ // Class bytes have been modified by weaving hooks.
+ // Such classes need to be stored as Orphans, so skip the call to storeSharedClass()
+ return;
+ }
+ }
+ } catch (IOException e) {
+ // this should never happen, but in case it does, its safe to return
+ return;
+ }
+
+ CDSBundleFile cdsFile = getCDSBundleFile(classpathEntry.getBundleFile());
+
+ if (null == cdsFile.getURL()) {
+ // something went wrong trying to determine the url to the real bundle file
+ return;
+ }
+
+ // look for the urlHelper; if it does not exist then we are not sharing for this class loader
+ SharedClassURLHelper urlHelper = cdsFile.getURLHelper();
+ if (urlHelper == null) {
+ // this should never happen but just in case get the helper from the base host bundle file.
+ CDSBundleFile hostBundleFile = getCDSBundleFile(manager.getGeneration().getBundleFile());
+ if (null != hostBundleFile) {
+ // try getting the helper from the host base cdsFile
+ urlHelper = hostBundleFile.getURLHelper();
+ }
+
+ if (null != urlHelper) {
+ cdsFile.setURLHelper(urlHelper);
+ }
+ }
+ if (null != urlHelper) {
+ // store the class in the cache
+ urlHelper.storeSharedClass(null, cdsFile.getURL(), clazz);
+ cdsFile.setPrimed(true);
+ }
+ }
+
+ /* Calling setMinimizeUpdateChecks() on the urlHelper tells it to only check the plugin jar for updates
+ * once on startup. This removes the need to "prime" plugins by always cacheing the first class from the jar.
+ *
+ * Java5 does not have a runMinimizeUpdateChecks method, but Java6 does. The text below explains why.
+ *
+ * Java6 has an improved jar update detection mechanism which is event-driven and listens for
+ * real jar open and close events. It will check jar timestamps on every class-load for closed jars (when
+ * loading cached classes from those jars) and not check them if it knows the jars are open.
+ *
+ * Java5 didn't know about jar open/close events so simply assumed that the first class to be stored by
+ * a plugin implied that its jar was opened indefinitely. This is why it helps to "prime" a plugin when
+ * running under Java5 - by storing a class, the jar is opened and the JVM stops checking its timestamp
+ * which results in faster startup.
+ *
+ * While the Java6 behaviour is more correct (it will pick up changes if a jar is closed after having been opened),
+ * if the jars are not opened or "primed", then it will perform constant checks on their timestamps which hurts startup times.
+ * This is why setMinimizeUpdateChecks was introduced - it's a means of saying to the urlHelper - regardless of
+ * whether my container(s) is open or closed, I only want you to check it once for updates.
+ *
+ * The consequence of this is that less file handles are open on startup in Java6.
+ *
+ * This has been written in such a way that this adaptor will continue to work exactly the same with Java5, but
+ * will adapt its behaviour when used with Java6 to do the right thing.
+ */
+ private boolean runMinimizeMethod(SharedClassURLHelper urlHelper) {
+ if (hasMinimizeMethod && (urlHelper != null)) {
+ if (minimizeMethod == null) {
+ hasMinimizeMethod = false; /* Assume failure - prove success below */
+ try {
+ Class<?> c = urlHelper.getClass();
+ minimizeMethod = c.getMethod("setMinimizeUpdateChecks"); //$NON-NLS-1$
+ minimizeMethod.setAccessible(true);
+ hasMinimizeMethod = true;
+ } catch (Exception e) {
+ /* hasMinimizeMethod will be false and we won't try this again */
+ }
+ }
+ if (minimizeMethod != null) {
+ try {
+ minimizeMethod.invoke(urlHelper);
+ return true;
+ } catch (Exception e) {
+ hasMinimizeMethod = false;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean hasMagicClassNumber(byte[] classbytes) {
+ if (classbytes == null || classbytes.length < 4)
+ return false;
+ // TODO maybe there is a better way to do this? I'm not sure why I had to AND each byte with the value I was checking ...
+ return (classbytes[0] & 0xCA) == 0xCA && (classbytes[1] & 0xFE) == 0xFE && (classbytes[2] & 0xBA) == 0xBA && (classbytes[3] & 0xBE) == 0xBE;
+ }
+
+ public void classLoaderCreated(ModuleClassLoader classLoader) {
+ // try to get the url helper for this class loader
+ if (factory == null) {
+ return;
+ }
+ CDSBundleFile hostFile = null;
+ try {
+ SharedClassURLHelper urlHelper = factory.getURLHelper(classLoader);
+ boolean minimizeSucceeded = runMinimizeMethod(urlHelper);
+ // set the url helper for the host base CDSBundleFile
+ hostFile = getCDSBundleFile(classLoader.getClasspathManager().getGeneration().getBundleFile());
+ if (hostFile != null) {
+ hostFile.setURLHelper(urlHelper);
+ if (minimizeSucceeded) {
+ /* In Java6, there is no longer a requirement to "prime" plugins */
+ hostFile.setPrimed(true);
+ }
+ }
+ } catch (HelperAlreadyDefinedException e) {
+ // We should never get here.
+ // If we do, we simply won't share for this ClassLoader
+ }
+ }
+
+ public boolean addClassPathEntry(ArrayList<ClasspathEntry> cpEntries, String cp, ClasspathManager hostmanager, Generation sourceGeneration) {
+ CDSBundleFile hostFile = getCDSBundleFile(hostmanager.getGeneration().getBundleFile());
+ CDSBundleFile sourceFile = getCDSBundleFile(sourceGeneration.getBundleFile());
+ if ((hostFile != sourceFile) && (null != hostFile) && (null != sourceFile)) {
+ // set the helper that got set on the host base bundle file in initializedClassLoader
+ SharedClassURLHelper urlHelper = hostFile.getURLHelper();
+ sourceFile.setURLHelper(urlHelper);
+ }
+
+ return false;
+ }
+
+ //////////////// BundleFileWrapperFactoryHook //////////////
+ public BundleFileWrapper wrapBundleFile(BundleFile bundleFile, Generation generation, boolean base) {
+ // wrap the real bundle file for purposes of loading shared classes.
+ CDSBundleFile newBundleFile;
+ if (!base && generation.getBundleInfo().getBundleId() != 0) {
+ // initialize the urlHelper from the base one.
+ SharedClassURLHelper urlHelper = null;
+ BundleFile baseFile = generation.getBundleFile();
+ if ((baseFile = getCDSBundleFile(baseFile)) != null) {
+ urlHelper = ((CDSBundleFile) baseFile).getURLHelper();
+ }
+ newBundleFile = new CDSBundleFile(bundleFile, urlHelper);
+ } else {
+ newBundleFile = new CDSBundleFile(bundleFile);
+ }
+
+ return newBundleFile;
+ }
+
+ void registerHooks(HookRegistry hookRegistry) {
+ // only register if sharing is enabled
+ if (!Shared.isSharingEnabled()) {
+ return;
+ }
+ hookRegistry.addClassLoaderHook(this);
+ hookRegistry.addBundleFileWrapperFactoryHook(this);
+ }
+}
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hookregistry/HookRegistry.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hookregistry/HookRegistry.java
index f9d881dd4..7bd34c99c 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hookregistry/HookRegistry.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/hookregistry/HookRegistry.java
@@ -14,8 +14,14 @@ package org.eclipse.osgi.internal.hookregistry;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
import org.eclipse.osgi.framework.log.FrameworkLogEntry;
+import org.eclipse.osgi.internal.cds.CDSHookConfigurator;
import org.eclipse.osgi.internal.framework.EquinoxConfiguration;
import org.eclipse.osgi.internal.framework.EquinoxContainer;
import org.eclipse.osgi.internal.hooks.DevClassLoadingHook;
@@ -103,6 +109,7 @@ public final class HookRegistry {
addClassLoaderHook(new EclipseLazyStarter(container));
addClassLoaderHook(new WeavingHookConfigurator(container));
configurators.add(SignedBundleHook.class.getName());
+ configurators.add(CDSHookConfigurator.class.getName());
loadConfigurators(configurators, errors);
// set to read-only
initialized = true;
diff --git a/bundles/org.eclipse.osgi/osgi/j9stubs.jar b/bundles/org.eclipse.osgi/osgi/j9stubs.jar
new file mode 100644
index 000000000..597a2d4b6
--- /dev/null
+++ b/bundles/org.eclipse.osgi/osgi/j9stubs.jar
Binary files differ