changeset 22236:179db500f6e5

Add Java code for reading the constant pool cache plus sun.reflect.ConstantPool substitutions.
author twisti
date Thu, 16 Jul 2015 07:47:07 -0700
parents 47172ee39101
children 8c2f3922bb9e
files graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ConstantPoolSubstitutionsTests.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ConstantPoolSubstitutions.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/CompilerToVMImpl.java jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotConstantPool.java jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotSymbol.java jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotVMConfig.java jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotVmSymbols.java make/defs.make src/share/vm/jvmci/jvmciCompilerToVM.cpp src/share/vm/runtime/handles.hpp src/share/vm/runtime/vmStructs.cpp
diffstat 13 files changed, 883 insertions(+), 42 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ConstantPoolSubstitutionsTests.java	Thu Jul 16 07:47:07 2015 -0700
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.hotspot.test;
+
+import org.junit.*;
+
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.*;
+
+import jdk.internal.jvmci.debug.*;
+import jdk.internal.jvmci.debug.Debug.*;
+import sun.misc.*;
+import sun.reflect.*;
+
+public class ConstantPoolSubstitutionsTests extends GraalCompilerTest {
+
+    protected StructuredGraph test(final String snippet) {
+        try (Scope s = Debug.scope("ConstantPoolSubstitutionsTests", getMetaAccess().lookupJavaMethod(getMethod(snippet)))) {
+            StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
+            compile(graph.method(), graph);
+            assertNotInGraph(graph, Invoke.class);
+            Debug.dump(graph, snippet);
+            return graph;
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    protected static StructuredGraph assertNotInGraph(StructuredGraph graph, Class<?> clazz) {
+        for (Node node : graph.getNodes()) {
+            if (clazz.isInstance(node)) {
+                fail(node.toString());
+            }
+        }
+        return graph;
+    }
+
+    @Test
+    public void testGetSize() {
+        ConstantPool cp = SharedSecrets.getJavaLangAccess().getConstantPool(Object.class);
+        test("getSize", cp);
+    }
+
+    @Test
+    public void testGetIntAt() {
+        test("getIntAt");
+    }
+
+    @Test
+    public void testGetLongAt() {
+        test("getLongAt");
+    }
+
+    @Test
+    public void testGetFloatAt() {
+        test("getFloatAt");
+    }
+
+    @Test
+    public void testGetDoubleAt() {
+        test("getDoubleAt");
+    }
+
+    // @Test
+    public void testGetUTF8At() {
+        test("getUTF8At");
+    }
+
+    public int getSize(ConstantPool cp) {
+        return cp.getSize();
+    }
+
+    public int getIntAt(ConstantPool cp) {
+        return cp.getIntAt(0);
+    }
+
+    public long getLongAt(ConstantPool cp) {
+        return cp.getLongAt(0);
+    }
+
+    public float getFloatAt(ConstantPool cp) {
+        return cp.getFloatAt(0);
+    }
+
+    public double getDoubleAt(ConstantPool cp) {
+        return cp.getDoubleAt(0);
+    }
+
+    public String getUTF8At(ConstantPool cp) {
+        return cp.getUTF8At(0);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ConstantPoolSubstitutions.java	Thu Jul 16 07:47:07 2015 -0700
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.replacements;
+
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.hotspot.word.*;
+import com.oracle.graal.word.*;
+
+import sun.reflect.*;
+
+/**
+ * Substitutions for {@link sun.reflect.ConstantPool} methods.
+ */
+@ClassSubstitution(sun.reflect.ConstantPool.class)
+public class ConstantPoolSubstitutions {
+
+    /**
+     * Get the metaspace {@code ConstantPool} pointer for the given holder class.
+     *
+     * @param constantPoolOop the holder class as {@link Object}
+     * @return a metaspace {@code ConstantPool} pointer
+     */
+    private static Word metaspaceConstantPool(Object constantPoolOop) {
+        // ConstantPool.constantPoolOop is in fact the holder class.
+        Class<?> constantPoolHolder = (Class<?>) constantPoolOop;
+        KlassPointer klass = ClassGetHubNode.readClass(constantPoolHolder);
+        return klass.readWord(instanceKlassConstantsOffset(), INSTANCE_KLASS_CONSTANTS);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    private static int getSize0(@SuppressWarnings("unused") final ConstantPool thisObj, Object constantPoolOop) {
+        return metaspaceConstantPool(constantPoolOop).readInt(constantPoolLengthOffset());
+    }
+
+    @MethodSubstitution(isStatic = false)
+    private static int getIntAt0(@SuppressWarnings("unused") final ConstantPool thisObj, Object constantPoolOop, int index) {
+        return metaspaceConstantPool(constantPoolOop).readInt(constantPoolSize() + index * wordSize());
+    }
+
+    @MethodSubstitution(isStatic = false)
+    private static long getLongAt0(@SuppressWarnings("unused") final ConstantPool thisObj, Object constantPoolOop, int index) {
+        return metaspaceConstantPool(constantPoolOop).readLong(constantPoolSize() + index * wordSize());
+    }
+
+    @MethodSubstitution(isStatic = false)
+    private static float getFloatAt0(@SuppressWarnings("unused") final ConstantPool thisObj, Object constantPoolOop, int index) {
+        return metaspaceConstantPool(constantPoolOop).readFloat(constantPoolSize() + index * wordSize());
+    }
+
+    @MethodSubstitution(isStatic = false)
+    private static double getDoubleAt0(@SuppressWarnings("unused") final ConstantPool thisObj, Object constantPoolOop, int index) {
+        return metaspaceConstantPool(constantPoolOop).readDouble(constantPoolSize() + index * wordSize());
+    }
+
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Thu Jul 16 13:48:47 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Thu Jul 16 07:47:07 2015 -0700
@@ -620,6 +620,13 @@
         return config().instanceKlassStateFullyInitialized;
     }
 
+    public static final LocationIdentity INSTANCE_KLASS_CONSTANTS = NamedLocationIdentity.immutable("InstanceKlass::_constants");
+
+    @Fold
+    public static int instanceKlassConstantsOffset() {
+        return config().instanceKlassConstantsOffset;
+    }
+
     /**
      *
      * @param hub the hub of an InstanceKlass
@@ -661,6 +668,21 @@
         return config().classMirrorOffset;
     }
 
+    @Fold
+    public static int constantPoolSize() {
+        return config().constantPoolSize;
+    }
+
+    @Fold
+    public static int constantPoolHolderOffset() {
+        return config().constantPoolHolderOffset;
+    }
+
+    @Fold
+    public static int constantPoolLengthOffset() {
+        return config().constantPoolLengthOffset;
+    }
+
     public static final LocationIdentity HEAP_TOP_LOCATION = NamedLocationIdentity.mutable("HeapTop");
 
     @Fold
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Thu Jul 16 13:48:47 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Thu Jul 16 07:47:07 2015 -0700
@@ -27,6 +27,7 @@
 import jdk.internal.jvmci.meta.*;
 import jdk.internal.jvmci.service.*;
 import sun.reflect.*;
+import sun.reflect.ConstantPool;
 
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.nodes.spi.*;
@@ -39,6 +40,7 @@
         replacements.registerSubstitutions(System.class, SystemSubstitutions.class);
         replacements.registerSubstitutions(Thread.class, ThreadSubstitutions.class);
         replacements.registerSubstitutions(Reflection.class, ReflectionSubstitutions.class);
+        replacements.registerSubstitutions(ConstantPool.class, ConstantPoolSubstitutions.class);
         replacements.registerSubstitutions(CompilerToVMImpl.class, CompilerToVMImplSubstitutions.class);
     }
 }
--- a/jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/CompilerToVMImpl.java	Thu Jul 16 13:48:47 2015 +0200
+++ b/jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/CompilerToVMImpl.java	Thu Jul 16 07:47:07 2015 -0700
@@ -25,6 +25,7 @@
 
 import static jdk.internal.jvmci.hotspot.InitTimer.*;
 import jdk.internal.jvmci.code.*;
+import jdk.internal.jvmci.common.*;
 import jdk.internal.jvmci.meta.*;
 
 /**
@@ -72,19 +73,39 @@
 
     public native Object resolveConstantInPool(long metaspaceConstantPool, int cpi);
 
-    public native Object resolvePossiblyCachedConstantInPool(long metaspaceConstantPool, int cpi);
+    public Object resolvePossiblyCachedConstantInPool(long metaspaceConstantPool, int cpi) {
+        JVMCIError.guarantee(!HotSpotConstantPool.Options.UseConstantPoolCacheJavaCode.getValue(), "");
+        return resolvePossiblyCachedConstantInPool0(metaspaceConstantPool, cpi);
+    }
+
+    private native Object resolvePossiblyCachedConstantInPool0(long metaspaceConstantPool, int cpi);
 
     @Override
     public native int lookupNameAndTypeRefIndexInPool(long metaspaceConstantPool, int cpi);
 
     @Override
-    public native String lookupNameRefInPool(long metaspaceConstantPool, int cpi);
+    public String lookupNameRefInPool(long metaspaceConstantPool, int cpi) {
+        JVMCIError.guarantee(!HotSpotConstantPool.Options.UseConstantPoolCacheJavaCode.getValue(), "");
+        return lookupNameRefInPool0(metaspaceConstantPool, cpi);
+    }
+
+    private native String lookupNameRefInPool0(long metaspaceConstantPool, int cpi);
 
     @Override
-    public native String lookupSignatureRefInPool(long metaspaceConstantPool, int cpi);
+    public String lookupSignatureRefInPool(long metaspaceConstantPool, int cpi) {
+        JVMCIError.guarantee(!HotSpotConstantPool.Options.UseConstantPoolCacheJavaCode.getValue(), "");
+        return lookupSignatureRefInPool0(metaspaceConstantPool, cpi);
+    }
+
+    private native String lookupSignatureRefInPool0(long metaspaceConstantPool, int cpi);
 
     @Override
-    public native int lookupKlassRefIndexInPool(long metaspaceConstantPool, int cpi);
+    public int lookupKlassRefIndexInPool(long metaspaceConstantPool, int cpi) {
+        JVMCIError.guarantee(!HotSpotConstantPool.Options.UseConstantPoolCacheJavaCode.getValue(), "");
+        return lookupKlassRefIndexInPool0(metaspaceConstantPool, cpi);
+    }
+
+    private native int lookupKlassRefIndexInPool0(long metaspaceConstantPool, int cpi);
 
     public native long constantPoolKlassAt(long metaspaceConstantPool, int cpi);
 
@@ -97,10 +118,20 @@
     @Override
     public native long resolveField(long metaspaceConstantPool, int cpi, byte opcode, long[] info);
 
-    public native int constantPoolRemapInstructionOperandFromCache(long metaspaceConstantPool, int cpi);
+    public int constantPoolRemapInstructionOperandFromCache(long metaspaceConstantPool, int cpi) {
+        JVMCIError.guarantee(!HotSpotConstantPool.Options.UseConstantPoolCacheJavaCode.getValue(), "");
+        return constantPoolRemapInstructionOperandFromCache0(metaspaceConstantPool, cpi);
+    }
+
+    private native int constantPoolRemapInstructionOperandFromCache0(long metaspaceConstantPool, int cpi);
 
     @Override
-    public native Object lookupAppendixInPool(long metaspaceConstantPool, int cpi);
+    public Object lookupAppendixInPool(long metaspaceConstantPool, int cpi) {
+        JVMCIError.guarantee(!HotSpotConstantPool.Options.UseConstantPoolCacheJavaCode.getValue(), "");
+        return lookupAppendixInPool0(metaspaceConstantPool, cpi);
+    }
+
+    private native Object lookupAppendixInPool0(long metaspaceConstantPool, int cpi);
 
     @Override
     public native void initializeConfiguration(HotSpotVMConfig config);
@@ -191,7 +222,12 @@
 
     public native long getTimeStamp();
 
-    public native String getSymbol(long metaspaceSymbol);
+    public String getSymbol(long metaspaceSymbol) {
+        JVMCIError.guarantee(!HotSpotConstantPool.Options.UseConstantPoolCacheJavaCode.getValue(), "");
+        return getSymbol0(metaspaceSymbol);
+    }
+
+    private native String getSymbol0(long metaspaceSymbol);
 
     public native void resolveInvokeDynamic(long metaspaceConstantPool, int index);
 
--- a/jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotConstantPool.java	Thu Jul 16 13:48:47 2015 +0200
+++ b/jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotConstantPool.java	Thu Jul 16 07:47:07 2015 -0700
@@ -26,15 +26,24 @@
 import static jdk.internal.jvmci.hotspot.HotSpotJVMCIRuntime.*;
 
 import java.lang.invoke.*;
+import java.util.*;
 
 import jdk.internal.jvmci.common.*;
 import jdk.internal.jvmci.meta.*;
+import jdk.internal.jvmci.options.*;
 
 /**
  * Implementation of {@link ConstantPool} for HotSpot.
  */
 public class HotSpotConstantPool implements ConstantPool, HotSpotProxified {
 
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Use Java code to access the constant pool cache and resolved references array", type = OptionType.Expert)
+        public static final OptionValue<Boolean> UseConstantPoolCacheJavaCode = new OptionValue<>(false);
+        // @formatter:on
+    }
+
     /**
      * Subset of JVM bytecode opcodes used by {@link HotSpotConstantPool}.
      */
@@ -179,8 +188,232 @@
     private final long metaspaceConstantPool;
     private volatile LookupTypeCacheElement lastLookupType;
 
+    /**
+     * The constant pool cache of this constant pool.
+     */
+    private final Cache cache;
+
+    /**
+     * Represents a {@code ConstantPoolCache}. The cache needs to be lazy since the constant pool
+     * cache is created when the methods of this class are rewritten and rewriting happens when the
+     * class is linked.
+     */
+    private final class Cache {
+
+        private long address;
+
+        public Cache() {
+            // Maybe the constant pool cache already exists...
+            queryAddress();
+        }
+
+        /**
+         * Queries the current value of {@code ConstantPool::_cache} if the current address is null.
+         */
+        private void queryAddress() {
+            if (address == 0) {
+                address = unsafe.getAddress(metaspaceConstantPool + runtime().getConfig().constantPoolCacheOffset);
+            }
+        }
+
+        /**
+         * Returns whether a constant pool cache for this constant pool exists.
+         *
+         * @return true if it exists, false otherwise
+         */
+        public boolean exists() {
+            queryAddress();
+            return address != 0;
+        }
+
+        /**
+         * Represents a {@code ConstantPoolCacheEntry}.
+         */
+        private final class Entry {
+
+            private final long address;
+
+            public Entry(final long address) {
+                this.address = address;
+            }
+
+            /**
+             * {@code ConstantPoolCacheEntry::_indices} is volatile of type {@code intx}.
+             *
+             * @return value of field {@code _indices}
+             */
+            private long getIndices() {
+                assert runtime().getHostJVMCIBackend().getTarget().wordSize == 8 : "port to non-64-bit platform";
+                return unsafe.getLongVolatile(null, address + runtime().getConfig().constantPoolCacheEntryIndicesOffset);
+            }
+
+            /**
+             * {@code ConstantPoolCacheEntry::_f1} is volatile of type {@code Metadata*}.
+             *
+             * @return value of field {@code _f1}
+             */
+            private long getF1() {
+                assert runtime().getHostJVMCIBackend().getTarget().wordSize == 8 : "port to non-64-bit platform";
+                return unsafe.getLongVolatile(null, address + runtime().getConfig().constantPoolCacheEntryF1Offset);
+            }
+
+            /**
+             * {@code ConstantPoolCacheEntry::_f2} is volatile of type {@code intx}.
+             *
+             * @return value of field {@code _f2}
+             */
+            private long getF2() {
+                assert runtime().getHostJVMCIBackend().getTarget().wordSize == 8 : "port to non-64-bit platform";
+                return unsafe.getLongVolatile(null, address + runtime().getConfig().constantPoolCacheEntryF2Offset);
+            }
+
+            /**
+             * {@code ConstantPoolCacheEntry::_flags} is volatile of type {@code intx}.
+             *
+             * @return flag bits
+             */
+            private long flags() {
+                assert runtime().getHostJVMCIBackend().getTarget().wordSize == 8 : "port to non-64-bit platform";
+                return unsafe.getLongVolatile(null, address + runtime().getConfig().constantPoolCacheEntryFlagsOffset);
+            }
+
+            private boolean isF1Null() {
+                final long f1 = getF1();
+                return f1 == 0;
+            }
+
+            /**
+             * Returns the constant pool index for this entry. See
+             * {@code ConstantPoolCacheEntry::constant_pool_index()}
+             *
+             * @return the constant pool index for this entry
+             */
+            public int getConstantPoolIndex() {
+                return ((int) getIndices()) & runtime().getConfig().constantPoolCacheEntryCpIndexMask;
+            }
+
+            /**
+             * See {@code ConstantPoolCache::has_appendix()}.
+             *
+             * @return true if there is an appendix, false otherwise
+             */
+            private boolean hasAppendix() {
+                return (!isF1Null()) && (flags() & (1 << runtime().getConfig().constantPoolCacheEntryHasAppendixShift)) != 0;
+            }
+
+            /**
+             * See {@code ConstantPoolCache::appendix_if_resolved()}.
+             */
+            public Object getAppendixIfResolved() {
+                if (!hasAppendix()) {
+                    return null;
+                }
+                final int index = ((int) getF2()) + runtime().getConfig().constantPoolCacheEntryIndyResolvedReferencesAppendixOffset;
+                return resolvedReferences.getArray()[index];
+            }
+        }
+
+        /**
+         * Get the constant pool cache entry at index {@code index}.
+         *
+         * @param index index of entry to return
+         * @return constant pool cache entry at given index
+         */
+        public Entry getEntryAt(int index) {
+            queryAddress();
+            assert exists();
+            HotSpotVMConfig config = runtime().getConfig();
+            return new Entry(address + config.constantPoolCacheSize + config.constantPoolCacheEntrySize * index);
+        }
+
+        /**
+         * Maps the constant pool cache index back to a constant pool index. See
+         * {@code ConstantPool::remap_instruction_operand_from_cache}.
+         *
+         * @param index the constant pool cache index
+         * @return constant pool index
+         */
+        public int constantPoolCacheIndexToConstantPoolIndex(int index) {
+            final int cacheIndex = index - runtime().getConfig().constantPoolCpCacheIndexTag;
+            return getEntryAt(cacheIndex).getConstantPoolIndex();
+        }
+
+    }
+
+    /**
+     * Resolved references of this constant pool.
+     */
+    private final ResolvedReferences resolvedReferences = new ResolvedReferences();
+
+    /**
+     * Hide the resolved references array in a private class so it cannot be accessed directly. The
+     * reason is the resolved references array is created when the constant pool cache is created.
+     *
+     * @see Cache
+     */
+    private final class ResolvedReferences {
+
+        /**
+         * Pointer to the {@code ConstantPool::_resolved_references} array.
+         */
+        private Object[] resolvedReferences;
+
+        /**
+         * Map of constant pool indexes to {@code ConstantPool::_resolved_references} indexes.
+         */
+        private final HashMap<Integer, Integer> referenceMap = new HashMap<>();
+
+        /**
+         * Returns the {@code ConstantPool::_resolved_references} array for this constant pool.
+         *
+         * @return resolved references array if exists, null otherwise
+         */
+        public Object[] getArray() {
+            if (resolvedReferences == null) {
+                final long handle = unsafe.getAddress(metaspaceConstantPool + runtime().getConfig().constantPoolResolvedReferencesOffset);
+                if (handle != 0) {
+                    resolvedReferences = (Object[]) runtime().getCompilerToVM().readUncompressedOop(handle + runtime().getConfig().handleHandleOffset);
+                    fillReferenceMap();
+                }
+            }
+            return resolvedReferences;
+        }
+
+        /**
+         * Fills the {@link #referenceMap} with all the values from
+         * {@code ConstantPool::_reference_map} for faster lookup.
+         */
+        private void fillReferenceMap() {
+            // It is possible there is a resolved references array but no reference map.
+            final long address = unsafe.getAddress(metaspaceConstantPool + runtime().getConfig().constantPoolReferenceMapOffset);
+            if (address != 0) {
+                final int length = unsafe.getInt(null, address + runtime().getConfig().arrayU1LengthOffset);
+                for (int i = 0; i < length; i++) {
+                    final int value = unsafe.getShort(address + runtime().getConfig().arrayU2DataOffset + i * Short.BYTES);
+                    referenceMap.put(value, i);
+                }
+            }
+        }
+
+        /**
+         * See {@code ConstantPool::cp_to_object_index}.
+         *
+         * @param cpi constant pool index
+         * @return resolved references array index
+         */
+        public int constantPoolIndexToResolvedReferencesIndex(int cpi) {
+            final Integer index = referenceMap.get(cpi);
+            // We might not find the index for jsr292 call.
+            return (index == null) ? -1 : index;
+        }
+
+    }
+
     public HotSpotConstantPool(long metaspaceConstantPool) {
         this.metaspaceConstantPool = metaspaceConstantPool;
+
+        // Cache constructor needs metaspaceConstantPool.
+        cache = new Cache();
     }
 
     /**
@@ -201,7 +434,7 @@
      * @param opcode bytecode to convert the index for
      * @return constant pool index
      */
-    private static int toConstantPoolIndex(int rawIndex, int opcode) {
+    private static int rawIndexToConstantPoolIndex(int rawIndex, int opcode) {
         int index;
         if (opcode == Bytecodes.INVOKEDYNAMIC) {
             index = rawIndex;
@@ -348,7 +581,12 @@
      * @return name as {@link String}
      */
     private String getNameRefAt(int index) {
-        return runtime().getCompilerToVM().lookupNameRefInPool(metaspaceConstantPool, index);
+        if (Options.UseConstantPoolCacheJavaCode.getValue()) {
+            final int nameRefIndex = getNameRefIndexAt(getNameAndTypeRefIndexAt(index));
+            return new HotSpotSymbol(getEntryAt(nameRefIndex)).asString();
+        } else {
+            return runtime().getCompilerToVM().lookupNameRefInPool(metaspaceConstantPool, index);
+        }
     }
 
     /**
@@ -372,7 +610,12 @@
      * @return signature as {@link String}
      */
     private String getSignatureRefAt(int index) {
-        return runtime().getCompilerToVM().lookupSignatureRefInPool(metaspaceConstantPool, index);
+        if (Options.UseConstantPoolCacheJavaCode.getValue()) {
+            final int signatureRefIndex = getSignatureRefIndexAt(getNameAndTypeRefIndexAt(index));
+            return new HotSpotSymbol(getEntryAt(signatureRefIndex)).asString();
+        } else {
+            return runtime().getCompilerToVM().lookupSignatureRefInPool(metaspaceConstantPool, index);
+        }
     }
 
     /**
@@ -389,13 +632,38 @@
     }
 
     /**
-     * Gets the klass reference index constant pool entry at index {@code index}.
+     * Gets the klass reference index constant pool entry at index {@code index}. See
+     * {@code ConstantPool::klass_ref_index_at}.
+     *
+     * @param index constant pool index
+     * @param cached whether to go through the constant pool cache
+     * @return klass reference index
+     */
+    private int getKlassRefIndexAt(int index, boolean cached) {
+        int cpi = index;
+        if (cached && cache.exists()) {
+            // change byte-ordering and go via cache
+            cpi = cache.constantPoolCacheIndexToConstantPoolIndex(index);
+        }
+        assertTagIsFieldOrMethod(cpi);
+        final int refIndex = unsafe.getInt(metaspaceConstantPool + runtime().getConfig().constantPoolSize + cpi * runtime().getHostJVMCIBackend().getTarget().wordSize);
+        // klass ref index is in the low 16-bits.
+        return refIndex & 0xFFFF;
+    }
+
+    /**
+     * Gets the klass reference index constant pool entry at index {@code index}. See
+     * {@code ConstantPool::klass_ref_index_at}.
      *
      * @param index constant pool index
      * @return klass reference index
      */
     private int getKlassRefIndexAt(int index) {
-        return runtime().getCompilerToVM().lookupKlassRefIndexInPool(metaspaceConstantPool, index);
+        if (Options.UseConstantPoolCacheJavaCode.getValue()) {
+            return getKlassRefIndexAt(index, true);
+        } else {
+            return runtime().getCompilerToVM().lookupKlassRefIndexInPool(metaspaceConstantPool, index);
+        }
     }
 
     /**
@@ -406,10 +674,14 @@
      * @return klass reference index
      */
     private int getUncachedKlassRefIndexAt(int index) {
-        assert getTagAt(index) == JVM_CONSTANT.Fieldref || getTagAt(index) == JVM_CONSTANT.MethodRef || getTagAt(index) == JVM_CONSTANT.InterfaceMethodref;
-        final int refIndex = unsafe.getInt(metaspaceConstantPool + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize);
-        // klass ref index is in the low 16-bits.
-        return refIndex & 0xFFFF;
+        if (Options.UseConstantPoolCacheJavaCode.getValue()) {
+            return getKlassRefIndexAt(index, false);
+        } else {
+            assertTagIsFieldOrMethod(index);
+            final int refIndex = unsafe.getInt(metaspaceConstantPool + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize);
+            // klass ref index is in the low 16-bits.
+            return refIndex & 0xFFFF;
+        }
     }
 
     /**
@@ -428,7 +700,19 @@
      * @param tag expected tag
      */
     private void assertTag(int index, JVM_CONSTANT tag) {
-        assert getTagAt(index) == tag : "constant pool tag at index " + index + " is " + getTagAt(index) + " but expected " + tag;
+        final JVM_CONSTANT tagAt = getTagAt(index);
+        assert tagAt == tag : "constant pool tag at index " + index + " is " + tagAt + " but expected " + tag;
+    }
+
+    /**
+     * Asserts that the constant pool tag at index {@code index} is a {@link JVM_CONSTANT#Fieldref},
+     * or a {@link JVM_CONSTANT#MethodRef}, or a {@link JVM_CONSTANT#InterfaceMethodref}.
+     *
+     * @param index constant pool index
+     */
+    private void assertTagIsFieldOrMethod(int index) {
+        final JVM_CONSTANT tagAt = getTagAt(index);
+        assert tagAt == JVM_CONSTANT.Fieldref || tagAt == JVM_CONSTANT.MethodRef || tagAt == JVM_CONSTANT.InterfaceMethodref : tagAt;
     }
 
     @Override
@@ -455,7 +739,34 @@
                 final int opcode = -1;  // opcode is not used
                 return lookupType(cpi, opcode);
             case String:
-                Object string = runtime().getCompilerToVM().resolvePossiblyCachedConstantInPool(metaspaceConstantPool, cpi);
+                String string;
+                if (Options.UseConstantPoolCacheJavaCode.getValue()) {
+                    // See: ConstantPool::resolve_constant_at_impl
+                    /*
+                     * Note: Call getArray() before constantPoolIndexToResolvedReferencesIndex()
+                     * because it fills the map if the array exists.
+                     */
+                    Object[] localResolvedReferences = resolvedReferences.getArray();
+                    final int index = resolvedReferences.constantPoolIndexToResolvedReferencesIndex(cpi);
+                    if (index >= 0) {
+                        string = (String) localResolvedReferences[index];
+                        if (string != null) {
+                            return HotSpotObjectConstantImpl.forObject(string);
+                        }
+                    }
+                    assert index != -1;
+                    // See: ConstantPool::string_at_impl
+                    string = (String) localResolvedReferences[index];
+                    if (string == null) {
+                        final long metaspaceSymbol = getEntryAt(cpi);
+                        HotSpotSymbol symbol = new HotSpotSymbol(metaspaceSymbol);
+                        string = symbol.asString().intern();
+                        // See: ConstantPool::string_at_put
+                        localResolvedReferences[index] = string;
+                    }
+                } else {
+                    string = (String) runtime().getCompilerToVM().resolvePossiblyCachedConstantInPool(metaspaceConstantPool, cpi);
+                }
                 return HotSpotObjectConstantImpl.forObject(string);
             case MethodHandle:
             case MethodHandleInError:
@@ -471,7 +782,18 @@
     @Override
     public String lookupUtf8(int cpi) {
         assertTag(cpi, JVM_CONSTANT.Utf8);
-        return runtime().getCompilerToVM().getSymbol(getEntryAt(cpi));
+        String s;
+        if (Options.UseConstantPoolCacheJavaCode.getValue()) {
+            HotSpotSymbol symbol = new HotSpotSymbol(getEntryAt(cpi));
+            s = symbol.asString();
+            // It shouldn't but just in case something went wrong...
+            if (s == null) {
+                throw JVMCIError.shouldNotReachHere("malformed UTF-8 string in constant pool");
+            }
+        } else {
+            s = runtime().getCompilerToVM().getSymbol(getEntryAt(cpi));
+        }
+        return s;
     }
 
     @Override
@@ -482,12 +804,26 @@
     @Override
     public JavaConstant lookupAppendix(int cpi, int opcode) {
         assert Bytecodes.isInvoke(opcode);
-        final int index = toConstantPoolIndex(cpi, opcode);
-        Object result = runtime().getCompilerToVM().lookupAppendixInPool(metaspaceConstantPool, index);
-        if (result == null) {
+        final int index = rawIndexToConstantPoolIndex(cpi, opcode);
+
+        Object appendix = null;
+
+        if (Options.UseConstantPoolCacheJavaCode.getValue()) {
+            if (!cache.exists()) {
+                // Nothing to load yet.
+                return null;
+            }
+            final int cacheIndex = decodeConstantPoolCacheIndex(index);
+            Cache.Entry entry = cache.getEntryAt(cacheIndex);
+            appendix = entry.getAppendixIfResolved();
+        } else {
+            appendix = runtime().getCompilerToVM().lookupAppendixInPool(metaspaceConstantPool, index);
+        }
+
+        if (appendix == null) {
             return null;
         } else {
-            return HotSpotObjectConstantImpl.forObject(result);
+            return HotSpotObjectConstantImpl.forObject(appendix);
         }
     }
 
@@ -502,7 +838,17 @@
         HotSpotVMConfig config = runtime.getConfig();
         if ((metaspacePointer & config.compilerToVMSymbolTag) != 0) {
             final long metaspaceSymbol = metaspacePointer & ~config.compilerToVMSymbolTag;
-            String name = runtime.getCompilerToVM().getSymbol(metaspaceSymbol);
+            String name;
+            if (Options.UseConstantPoolCacheJavaCode.getValue()) {
+                HotSpotSymbol symbol = new HotSpotSymbol(metaspaceSymbol);
+                name = symbol.asString();
+                // It shouldn't but just in case something went wrong...
+                if (name == null) {
+                    throw JVMCIError.shouldNotReachHere("malformed UTF-8 string in constant pool");
+                }
+            } else {
+                name = runtime.getCompilerToVM().getSymbol(metaspaceSymbol);
+            }
             return HotSpotUnresolvedJavaType.create(runtime(), "L" + name + ";");
         } else {
             assert (metaspacePointer & config.compilerToVMKlassTag) == 0;
@@ -512,7 +858,7 @@
 
     @Override
     public JavaMethod lookupMethod(int cpi, int opcode) {
-        final int index = toConstantPoolIndex(cpi, opcode);
+        final int index = rawIndexToConstantPoolIndex(cpi, opcode);
         final long metaspaceMethod = runtime().getCompilerToVM().lookupMethodInPool(metaspaceConstantPool, index, (byte) opcode);
         if (metaspaceMethod != 0L) {
             HotSpotResolvedJavaMethod result = HotSpotResolvedJavaMethodImpl.fromMetaspace(metaspaceMethod);
@@ -550,7 +896,7 @@
 
     @Override
     public JavaField lookupField(int cpi, int opcode) {
-        final int index = toConstantPoolIndex(cpi, opcode);
+        final int index = rawIndexToConstantPoolIndex(cpi, opcode);
         final int nameAndTypeIndex = getNameAndTypeRefIndexAt(index);
         final int nameIndex = getNameRefIndexAt(nameAndTypeIndex);
         String name = lookupUtf8(nameIndex);
@@ -597,14 +943,44 @@
             case Bytecodes.LDC2_W:
                 index = cpi;
                 break;
-            case Bytecodes.INVOKEDYNAMIC:
+            case Bytecodes.INVOKEDYNAMIC: {
                 // invokedynamic instructions point to a constant pool cache entry.
-                index = decodeConstantPoolCacheIndex(cpi) + runtime().getConfig().constantPoolCpCacheIndexTag;
-                index = runtime().getCompilerToVM().constantPoolRemapInstructionOperandFromCache(metaspaceConstantPool, index);
+                if (Options.UseConstantPoolCacheJavaCode.getValue()) {
+                    // index = decodeConstantPoolCacheIndex(cpi) +
+                    // runtime().getConfig().constantPoolCpCacheIndexTag;
+                    // index = cache.constantPoolCacheIndexToConstantPoolIndex(index);
+                    final int cacheIndex = cpi;
+                    index = cache.getEntryAt(decodeInvokedynamicIndex(cacheIndex)).getConstantPoolIndex();
+                    // JVMCIError.guarantee(index == x, index + " != " + x);
+                } else {
+                    index = decodeConstantPoolCacheIndex(cpi) + runtime().getConfig().constantPoolCpCacheIndexTag;
+                    index = runtime().getCompilerToVM().constantPoolRemapInstructionOperandFromCache(metaspaceConstantPool, index);
+                }
                 break;
+            }
+            case Bytecodes.GETSTATIC:
+            case Bytecodes.PUTSTATIC:
+            case Bytecodes.GETFIELD:
+            case Bytecodes.PUTFIELD:
+            case Bytecodes.INVOKEVIRTUAL:
+            case Bytecodes.INVOKESPECIAL:
+            case Bytecodes.INVOKESTATIC:
+            case Bytecodes.INVOKEINTERFACE: {
+                // invoke and field instructions point to a constant pool cache entry.
+                if (Options.UseConstantPoolCacheJavaCode.getValue()) {
+                    // index = rawIndexToConstantPoolIndex(cpi, opcode);
+                    // index = cache.constantPoolCacheIndexToConstantPoolIndex(index);
+                    final int cacheIndex = cpi;
+                    index = cache.getEntryAt(cacheIndex).getConstantPoolIndex();
+                    // JVMCIError.guarantee(index == x, index + " != " + x);
+                } else {
+                    index = rawIndexToConstantPoolIndex(cpi, opcode);
+                    index = runtime().getCompilerToVM().constantPoolRemapInstructionOperandFromCache(metaspaceConstantPool, index);
+                }
+                break;
+            }
             default:
-                index = toConstantPoolIndex(cpi, opcode);
-                index = runtime().getCompilerToVM().constantPoolRemapInstructionOperandFromCache(metaspaceConstantPool, index);
+                throw JVMCIError.shouldNotReachHere("Unexpected opcode " + opcode);
         }
 
         final JVM_CONSTANT tag = getTagAt(index);
@@ -633,7 +1009,7 @@
                 switch (tag) {
                     case MethodRef:
                         if (Bytecodes.isInvokeHandleAlias(opcode)) {
-                            final int methodRefCacheIndex = toConstantPoolIndex(cpi, opcode);
+                            final int methodRefCacheIndex = rawIndexToConstantPoolIndex(cpi, opcode);
                             if (isInvokeHandle(methodRefCacheIndex, type)) {
                                 runtime().getCompilerToVM().resolveInvokeHandle(metaspaceConstantPool, methodRefCacheIndex);
                             }
@@ -652,7 +1028,13 @@
     }
 
     private boolean isInvokeHandle(int methodRefCacheIndex, HotSpotResolvedObjectTypeImpl klass) {
-        assertTag(runtime().getCompilerToVM().constantPoolRemapInstructionOperandFromCache(metaspaceConstantPool, methodRefCacheIndex), JVM_CONSTANT.MethodRef);
+        int index;
+        if (Options.UseConstantPoolCacheJavaCode.getValue()) {
+            index = cache.constantPoolCacheIndexToConstantPoolIndex(methodRefCacheIndex);
+        } else {
+            index = runtime().getCompilerToVM().constantPoolRemapInstructionOperandFromCache(metaspaceConstantPool, methodRefCacheIndex);
+        }
+        assertTag(index, JVM_CONSTANT.MethodRef);
         return ResolvedJavaMethod.isSignaturePolymorphic(klass, getNameRefAt(methodRefCacheIndex), runtime().getHostJVMCIBackend().getMetaAccess());
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotSymbol.java	Thu Jul 16 07:47:07 2015 -0700
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.jvmci.hotspot;
+
+import static jdk.internal.jvmci.common.UnsafeAccess.*;
+import static jdk.internal.jvmci.hotspot.HotSpotJVMCIRuntime.*;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * Represents a metaspace {@code Symbol}.
+ */
+public class HotSpotSymbol {
+
+    private final long metaspaceSymbol;
+
+    public HotSpotSymbol(long metaspaceSymbol) {
+        assert metaspaceSymbol != 0;
+        this.metaspaceSymbol = metaspaceSymbol;
+    }
+
+    /**
+     * Decodes this {@code Symbol} and returns the symbol string as {@link java.lang.String}.
+     *
+     * @return the decoded string, or null if there was a decoding error
+     */
+    public String asString() {
+        return readModifiedUTF8(asByteArray());
+    }
+
+    /**
+     * Reads the modified UTF-8 string in {@code buf} and converts it to a {@link String}. The
+     * implementation is taken from {@link java.io.DataInputStream#readUTF(DataInput)} and adapted
+     * to operate on a {@code byte} array directly for performance reasons.
+     *
+     * @see java.io.DataInputStream#readUTF(DataInput)
+     */
+    private static String readModifiedUTF8(byte[] buf) {
+        final int utflen = buf.length;
+        byte[] bytearr = null;
+        char[] chararr = new char[utflen];
+
+        int c;
+        int char2;
+        int char3;
+        int count = 0;
+        int chararrCount = 0;
+
+        bytearr = buf;
+
+        while (count < utflen) {
+            c = bytearr[count] & 0xff;
+            if (c > 127) {
+                break;
+            }
+            count++;
+            chararr[chararrCount++] = (char) c;
+        }
+
+        while (count < utflen) {
+            c = bytearr[count] & 0xff;
+            switch (c >> 4) {
+                case 0:
+                case 1:
+                case 2:
+                case 3:
+                case 4:
+                case 5:
+                case 6:
+                case 7:
+                    /* 0xxxxxxx */
+                    count++;
+                    chararr[chararrCount++] = (char) c;
+                    break;
+                case 12:
+                case 13:
+                    /* 110x xxxx 10xx xxxx */
+                    count += 2;
+                    if (count > utflen) {
+                        // malformed input: partial character at end
+                        return null;
+                    }
+                    char2 = bytearr[count - 1];
+                    if ((char2 & 0xC0) != 0x80) {
+                        // malformed input around byte
+                        return null;
+                    }
+                    chararr[chararrCount++] = (char) (((c & 0x1F) << 6) | (char2 & 0x3F));
+                    break;
+                case 14:
+                    /* 1110 xxxx 10xx xxxx 10xx xxxx */
+                    count += 3;
+                    if (count > utflen) {
+                        // malformed input: partial character at end
+                        return null;
+                    }
+                    char2 = bytearr[count - 2];
+                    char3 = bytearr[count - 1];
+                    if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) {
+                        // malformed input around byte
+                        return null;
+                    }
+                    chararr[chararrCount++] = (char) (((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0));
+                    break;
+                default:
+                    /* 10xx xxxx, 1111 xxxx */
+                    // malformed input around byte
+                    return null;
+            }
+        }
+        // The number of chars produced may be less than utflen
+        char[] value = Arrays.copyOf(chararr, chararrCount);
+        return new String(value);
+    }
+
+    private byte[] asByteArray() {
+        final int length = getLength();
+        byte[] result = new byte[length];
+        for (int index = 0; index < length; index++) {
+            result[index] = getByteAt(index);
+        }
+        return result;
+    }
+
+    private int getLength() {
+        return unsafe.getShort(metaspaceSymbol + runtime().getConfig().symbolLengthOffset);
+    }
+
+    private byte getByteAt(int index) {
+        return unsafe.getByte(metaspaceSymbol + runtime().getConfig().symbolBodyOffset + index);
+    }
+}
--- a/jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotVMConfig.java	Thu Jul 16 13:48:47 2015 +0200
+++ b/jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotVMConfig.java	Thu Jul 16 07:47:07 2015 -0700
@@ -808,6 +808,8 @@
     @HotSpotVMField(name = "oopDesc::_mark", type = "markOop", get = HotSpotVMField.Type.OFFSET) @Stable public int markOffset;
     @HotSpotVMField(name = "oopDesc::_metadata._klass", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int hubOffset;
 
+    @HotSpotVMField(name = "Handle::_handle", type = "oop*", get = HotSpotVMField.Type.OFFSET) @Stable public int handleHandleOffset;
+
     @HotSpotVMField(name = "Klass::_prototype_header", type = "markOop", get = HotSpotVMField.Type.OFFSET) @Stable public int prototypeMarkWordOffset;
     @HotSpotVMField(name = "Klass::_subklass", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int subklassOffset;
     @HotSpotVMField(name = "Klass::_next_sibling", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int nextSiblingOffset;
@@ -1090,11 +1092,29 @@
 
     @HotSpotVMType(name = "ConstantPool", get = HotSpotVMType.Type.SIZE) @Stable public int constantPoolSize;
     @HotSpotVMField(name = "ConstantPool::_tags", type = "Array<u1>*", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolTagsOffset;
+    @HotSpotVMField(name = "ConstantPool::_cache", type = "ConstantPoolCache*", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolCacheOffset;
     @HotSpotVMField(name = "ConstantPool::_pool_holder", type = "InstanceKlass*", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolHolderOffset;
     @HotSpotVMField(name = "ConstantPool::_length", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolLengthOffset;
+    @HotSpotVMField(name = "ConstantPool::_resolved_references", type = "jobject", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolResolvedReferencesOffset;
+    @HotSpotVMField(name = "ConstantPool::_reference_map", type = "Array<u2>*", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolReferenceMapOffset;
 
     @HotSpotVMConstant(name = "ConstantPool::CPCACHE_INDEX_TAG") @Stable public int constantPoolCpCacheIndexTag;
 
+    @HotSpotVMType(name = "ConstantPoolCache", get = HotSpotVMType.Type.SIZE) @Stable public int constantPoolCacheSize;
+    @HotSpotVMField(name = "ConstantPoolCache::_length", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolCacheLengthOffset;
+
+    @HotSpotVMType(name = "ConstantPoolCacheEntry", get = HotSpotVMType.Type.SIZE) @Stable public int constantPoolCacheEntrySize;
+    @HotSpotVMField(name = "ConstantPoolCacheEntry::_indices", type = "intx", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolCacheEntryIndicesOffset;
+    @HotSpotVMField(name = "ConstantPoolCacheEntry::_f1", type = "volatile Metadata*", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolCacheEntryF1Offset;
+    @HotSpotVMField(name = "ConstantPoolCacheEntry::_f2", type = "intx", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolCacheEntryF2Offset;
+    @HotSpotVMField(name = "ConstantPoolCacheEntry::_flags", type = "intx", get = HotSpotVMField.Type.OFFSET) @Stable public int constantPoolCacheEntryFlagsOffset;
+
+    @HotSpotVMConstant(name = "ConstantPoolCacheEntry::has_appendix_shift") @Stable public int constantPoolCacheEntryHasAppendixShift;
+
+    @HotSpotVMConstant(name = "ConstantPoolCacheEntry::cp_index_mask") @Stable public int constantPoolCacheEntryCpIndexMask;
+
+    @HotSpotVMConstant(name = "ConstantPoolCacheEntry::_indy_resolved_references_appendix_offset") @Stable public int constantPoolCacheEntryIndyResolvedReferencesAppendixOffset;
+
     @HotSpotVMConstant(name = "JVM_CONSTANT_Utf8") @Stable public int jvmConstantUtf8;
     @HotSpotVMConstant(name = "JVM_CONSTANT_Integer") @Stable public int jvmConstantInteger;
     @HotSpotVMConstant(name = "JVM_CONSTANT_Long") @Stable public int jvmConstantLong;
--- a/jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotVmSymbols.java	Thu Jul 16 13:48:47 2015 +0200
+++ b/jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotVmSymbols.java	Thu Jul 16 07:47:07 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,8 @@
 
 import static jdk.internal.jvmci.common.UnsafeAccess.*;
 import static jdk.internal.jvmci.hotspot.HotSpotJVMCIRuntime.*;
+
+import jdk.internal.jvmci.common.*;
 import sun.misc.*;
 
 /**
@@ -43,6 +45,17 @@
         HotSpotVMConfig config = runtime.getConfig();
         assert config.vmSymbolsFirstSID <= index && index < config.vmSymbolsSIDLimit : "index " + index + " is out of bounds";
         assert config.symbolPointerSize == Unsafe.ADDRESS_SIZE : "the following address read is broken";
-        return runtime.getCompilerToVM().getSymbol(unsafe.getAddress(config.vmSymbolsSymbols + index * config.symbolPointerSize));
+        final long metaspaceSymbol = unsafe.getAddress(config.vmSymbolsSymbols + index * config.symbolPointerSize);
+        if (HotSpotConstantPool.Options.UseConstantPoolCacheJavaCode.getValue()) {
+            HotSpotSymbol symbol = new HotSpotSymbol(metaspaceSymbol);
+            String s = symbol.asString();
+            // It shouldn't but just in case something went wrong...
+            if (s == null) {
+                throw JVMCIError.shouldNotReachHere("malformed UTF-8 string in constant pool");
+            }
+            return s;
+        } else {
+            return runtime.getCompilerToVM().getSymbol(metaspaceSymbol);
+        }
     }
 }
--- a/make/defs.make	Thu Jul 16 13:48:47 2015 +0200
+++ b/make/defs.make	Thu Jul 16 07:47:07 2015 -0700
@@ -376,6 +376,7 @@
 CONDITIONAL_EXPORT_LIST += $(EXPORT_JRE_LIB_JVMCI_SERVICES_DIR)/jdk.internal.jvmci.hotspot.events.EventProvider
 endif
 
+EXPORT_LIST += $(EXPORT_JRE_LIB_JVMCI_OPTIONS_DIR)/jdk.internal.jvmci.hotspot.HotSpotConstantPool
 EXPORT_LIST += $(EXPORT_JRE_LIB_JVMCI_OPTIONS_DIR)/jdk.internal.jvmci.hotspot.HotSpotConstantReflectionProvider
 EXPORT_LIST += $(EXPORT_JRE_LIB_JVMCI_OPTIONS_DIR)/jdk.internal.jvmci.hotspot.HotSpotJVMCIRuntime
 EXPORT_LIST += $(EXPORT_JRE_LIB_JVMCI_OPTIONS_DIR)/jdk.internal.jvmci.hotspot.HotSpotResolvedJavaFieldImpl
--- a/src/share/vm/jvmci/jvmciCompilerToVM.cpp	Thu Jul 16 13:48:47 2015 +0200
+++ b/src/share/vm/jvmci/jvmciCompilerToVM.cpp	Thu Jul 16 07:47:07 2015 -0700
@@ -1072,16 +1072,16 @@
   {CC"shouldInlineMethod",                           CC"("METASPACE_METHOD")Z",                                                FN_PTR(shouldInlineMethod)},
   {CC"lookupType",                                   CC"("STRING CLASS"Z)"METASPACE_KLASS,                                     FN_PTR(lookupType)},
   {CC"resolveConstantInPool",                        CC"("METASPACE_CONSTANT_POOL"I)"OBJECT,                                   FN_PTR(resolveConstantInPool)},
-  {CC"resolvePossiblyCachedConstantInPool",          CC"("METASPACE_CONSTANT_POOL"I)"OBJECT,                                   FN_PTR(resolvePossiblyCachedConstantInPool)},
-  {CC"lookupNameRefInPool",                          CC"("METASPACE_CONSTANT_POOL"I)"STRING,                                   FN_PTR(lookupNameRefInPool)},
+  {CC"resolvePossiblyCachedConstantInPool0",         CC"("METASPACE_CONSTANT_POOL"I)"OBJECT,                                   FN_PTR(resolvePossiblyCachedConstantInPool)},
+  {CC"lookupNameRefInPool0",                         CC"("METASPACE_CONSTANT_POOL"I)"STRING,                                   FN_PTR(lookupNameRefInPool)},
   {CC"lookupNameAndTypeRefIndexInPool",              CC"("METASPACE_CONSTANT_POOL"I)I",                                        FN_PTR(lookupNameAndTypeRefIndexInPool)},
-  {CC"lookupSignatureRefInPool",                     CC"("METASPACE_CONSTANT_POOL"I)"STRING,                                   FN_PTR(lookupSignatureRefInPool)},
-  {CC"lookupKlassRefIndexInPool",                    CC"("METASPACE_CONSTANT_POOL"I)I",                                        FN_PTR(lookupKlassRefIndexInPool)},
+  {CC"lookupSignatureRefInPool0",                    CC"("METASPACE_CONSTANT_POOL"I)"STRING,                                   FN_PTR(lookupSignatureRefInPool)},
+  {CC"lookupKlassRefIndexInPool0",                   CC"("METASPACE_CONSTANT_POOL"I)I",                                        FN_PTR(lookupKlassRefIndexInPool)},
   {CC"constantPoolKlassAt",                          CC"("METASPACE_CONSTANT_POOL"I)"METASPACE_KLASS,                          FN_PTR(constantPoolKlassAt)},
   {CC"lookupKlassInPool",                            CC"("METASPACE_CONSTANT_POOL"I)"METASPACE_KLASS,                          FN_PTR(lookupKlassInPool)},
-  {CC"lookupAppendixInPool",                         CC"("METASPACE_CONSTANT_POOL"I)"OBJECT,                                   FN_PTR(lookupAppendixInPool)},
+  {CC"lookupAppendixInPool0",                        CC"("METASPACE_CONSTANT_POOL"I)"OBJECT,                                   FN_PTR(lookupAppendixInPool)},
   {CC"lookupMethodInPool",                           CC"("METASPACE_CONSTANT_POOL"IB)"METASPACE_METHOD,                        FN_PTR(lookupMethodInPool)},
-  {CC"constantPoolRemapInstructionOperandFromCache", CC"("METASPACE_CONSTANT_POOL"I)I",                                        FN_PTR(constantPoolRemapInstructionOperandFromCache)},
+  {CC"constantPoolRemapInstructionOperandFromCache0",CC"("METASPACE_CONSTANT_POOL"I)I",                                        FN_PTR(constantPoolRemapInstructionOperandFromCache)},
   {CC"resolveField",                                 CC"("METASPACE_CONSTANT_POOL"IB[J)"METASPACE_KLASS,                       FN_PTR(resolveField)},
   {CC"resolveInvokeDynamic",                         CC"("METASPACE_CONSTANT_POOL"I)V",                                        FN_PTR(resolveInvokeDynamic)},
   {CC"resolveInvokeHandle",                          CC"("METASPACE_CONSTANT_POOL"I)V",                                        FN_PTR(resolveInvokeHandle)},
@@ -1109,7 +1109,7 @@
   {CC"allocateCompileId",                            CC"("METASPACE_METHOD"I)I",                                               FN_PTR(allocateCompileId)},
   {CC"isMature",                                     CC"("METASPACE_METHOD_DATA")Z",                                           FN_PTR(isMature)},
   {CC"hasCompiledCodeForOSR",                        CC"("METASPACE_METHOD"II)Z",                                              FN_PTR(hasCompiledCodeForOSR)},
-  {CC"getSymbol",                                    CC"(J)"STRING,                                                            FN_PTR(getSymbol)},
+  {CC"getSymbol0",                                   CC"(J)"STRING,                                                            FN_PTR(getSymbol)},
   {CC"getTimeStamp",                                 CC"()J",                                                                  FN_PTR(getTimeStamp)},
   {CC"getNextStackFrame",                            CC"("HS_STACK_FRAME_REF "[JI)"HS_STACK_FRAME_REF,                         FN_PTR(getNextStackFrame)},
   {CC"materializeVirtualObjects",                    CC"("HS_STACK_FRAME_REF"Z)V",                                             FN_PTR(materializeVirtualObjects)},
--- a/src/share/vm/runtime/handles.hpp	Thu Jul 16 13:48:47 2015 +0200
+++ b/src/share/vm/runtime/handles.hpp	Thu Jul 16 07:47:07 2015 -0700
@@ -62,6 +62,7 @@
 // used operators for ease of use.
 
 class Handle VALUE_OBJ_CLASS_SPEC {
+  friend class VMStructs;
  private:
   oop* _handle;
 
--- a/src/share/vm/runtime/vmStructs.cpp	Thu Jul 16 13:48:47 2015 +0200
+++ b/src/share/vm/runtime/vmStructs.cpp	Thu Jul 16 07:47:07 2015 -0700
@@ -1010,6 +1010,9 @@
   /*********************************/                                                                                                \
   /* JNIHandles and JNIHandleBlock */                                                                                                \
   /*********************************/                                                                                                \
+                                                                                                                                     \
+  nonstatic_field(Handle,                      _handle,                                       oop*)                                  \
+                                                                                                                                     \
      static_field(JNIHandles,                  _global_handles,                               JNIHandleBlock*)                       \
      static_field(JNIHandles,                  _weak_global_handles,                          JNIHandleBlock*)                       \
      static_field(JNIHandles,                  _deleted_handle,                               oop)                                   \
@@ -1742,6 +1745,8 @@
   /* JNIHandles and JNIHandleBlock */                                     \
   /*********************************/                                     \
                                                                           \
+  declare_toplevel_type(Handle)                                           \
+                                                                          \
   declare_toplevel_type(JNIHandles)                                       \
   declare_toplevel_type(JNIHandleBlock)                                   \
   declare_toplevel_type(jobject)                                          \
@@ -2538,9 +2543,22 @@
   declare_constant(ConstantPoolCacheEntry::is_final_shift)                \
   declare_constant(ConstantPoolCacheEntry::is_forced_virtual_shift)       \
   declare_constant(ConstantPoolCacheEntry::is_vfinal_shift)               \
+  declare_constant(ConstantPoolCacheEntry::has_appendix_shift)            \
+  declare_constant(ConstantPoolCacheEntry::has_method_type_shift)         \
   declare_constant(ConstantPoolCacheEntry::is_field_entry_shift)          \
   declare_constant(ConstantPoolCacheEntry::tos_state_shift)               \
                                                                           \
+  declare_constant(ConstantPoolCacheEntry::cp_index_bits)                 \
+  declare_constant(ConstantPoolCacheEntry::cp_index_mask)                 \
+  declare_constant(ConstantPoolCacheEntry::bytecode_1_shift)              \
+  declare_constant(ConstantPoolCacheEntry::bytecode_1_mask)               \
+  declare_constant(ConstantPoolCacheEntry::bytecode_2_shift)              \
+  declare_constant(ConstantPoolCacheEntry::bytecode_2_mask)               \
+                                                                          \
+  declare_constant(ConstantPoolCacheEntry::_indy_resolved_references_appendix_offset) \
+  declare_constant(ConstantPoolCacheEntry::_indy_resolved_references_method_type_offset) \
+  declare_constant(ConstantPoolCacheEntry::_indy_resolved_references_entries) \
+                                                                          \
   /***************************************/                               \
   /* java_lang_Thread::ThreadStatus enum */                               \
   /***************************************/                               \