src/java.base/share/classes/java/lang/invoke/AbstractConstantGroup.java
changeset 48826 c4d9d1b08e2e
child 59201 b24f4caa1411
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/invoke/AbstractConstantGroup.java	Fri Sep 08 10:46:46 2017 -0700
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2017, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 java.lang.invoke;
+
+import java.util.*;
+import jdk.internal.vm.annotation.Stable;
+
+import static java.lang.invoke.MethodHandleStatics.rangeCheck1;
+import static java.lang.invoke.MethodHandleStatics.rangeCheck2;
+
+/** Utility class for implementing ConstantGroup. */
+/*non-public*/
+abstract class AbstractConstantGroup implements ConstantGroup {
+    /** The size of this constant group, set permanently by the constructor. */
+    protected final int size;
+
+    /** The constructor requires the size of the constant group being represented.
+     * @param size the size of this constant group, set permanently by the constructor
+     */
+    AbstractConstantGroup(int size) {
+        this.size = size;
+    }
+
+    @Override public final int size() {
+        return size;
+    }
+
+    public abstract Object get(int index) throws LinkageError;
+
+    public abstract Object get(int index, Object ifNotPresent);
+
+    public abstract boolean isPresent(int index);
+
+    // Do not override equals or hashCode, since this type is stateful.
+
+    /**
+     * Produce a string using the non-resolving list view,
+     * where unresolved elements are presented as asterisks.
+     * @return {@code this.asList("*").toString()}
+     */
+    @Override public String toString() {
+        return asList("*").toString();
+    }
+
+    static class AsIterator implements Iterator<Object> {
+        private final ConstantGroup self;
+        private final int end;
+        private final boolean resolving;
+        private final Object ifNotPresent;
+
+        // Mutable state:
+        private int index;
+
+        private AsIterator(ConstantGroup self, int start, int end,
+                         boolean resolving, Object ifNotPresent) {
+            this.self = self;
+            this.end = end;
+            this.index = start;
+            this.resolving = resolving;
+            this.ifNotPresent = ifNotPresent;
+        }
+        AsIterator(ConstantGroup self, int start, int end) {
+            this(self, start, end, true, null);
+        }
+        AsIterator(ConstantGroup self, int start, int end,
+                 Object ifNotPresent) {
+            this(self, start, end, false, ifNotPresent);
+        }
+
+        @Override
+        public boolean hasNext() {
+            return index < end;
+        }
+
+        @Override
+        public Object next() {
+            int i = bumpIndex();
+            if (resolving)
+                return self.get(i);
+            else
+                return self.get(i, ifNotPresent);
+        }
+
+        private int bumpIndex() {
+            int i = index;
+            if (i >= end)  throw new NoSuchElementException();
+            index = i+1;
+            return i;
+        }
+    }
+
+    static class SubGroup extends AbstractConstantGroup {
+        private final ConstantGroup self;  // the real CG
+        private final int offset;  // offset within myself
+        SubGroup(ConstantGroup self, int start, int end) {
+            super(end - start);
+            this.self = self;
+            this.offset = start;
+            rangeCheck2(start, end, size);
+        }
+
+        private int mapIndex(int index) {
+            return rangeCheck1(index, size) + offset;
+        }
+
+        @Override
+        public Object get(int index) {
+            return self.get(mapIndex(index));
+        }
+
+        @Override
+        public Object get(int index, Object ifNotPresent) {
+            return self.get(mapIndex(index), ifNotPresent);
+        }
+
+        @Override
+        public boolean isPresent(int index) {
+            return self.isPresent(mapIndex(index));
+        }
+
+        @Override
+        public ConstantGroup subGroup(int start, int end) {
+            rangeCheck2(start, end, size);
+            return new SubGroup(self, offset + start, offset + end);
+        }
+
+        @Override
+        public List<Object> asList() {
+            return new AsList(self, offset, offset + size);
+        }
+
+        @Override
+        public List<Object> asList(Object ifNotPresent) {
+            return new AsList(self, offset, offset + size, ifNotPresent);
+        }
+
+        @Override
+        public int copyConstants(int start, int end,
+                                  Object[] buf, int pos) throws LinkageError {
+            rangeCheck2(start, end, size);
+            return self.copyConstants(offset + start, offset + end,
+                                      buf, pos);
+        }
+
+        @Override
+        public int copyConstants(int start, int end,
+                                  Object[] buf, int pos,
+                                  Object ifNotPresent) {
+            rangeCheck2(start, end, size);
+            return self.copyConstants(offset + start, offset + end,
+                                      buf, pos, ifNotPresent);
+        }
+    }
+
+    static class AsList extends AbstractList<Object> {
+        private final ConstantGroup self;
+        private final int size;
+        private final int offset;
+        private final boolean resolving;
+        private final Object ifNotPresent;
+
+        private AsList(ConstantGroup self, int start, int end,
+                       boolean resolving, Object ifNotPresent) {
+            this.self = self;
+            this.size = end - start;
+            this.offset = start;
+            this.resolving = resolving;
+            this.ifNotPresent = ifNotPresent;
+            rangeCheck2(start, end, self.size());
+        }
+        AsList(ConstantGroup self, int start, int end) {
+            this(self, start, end, true, null);
+        }
+        AsList(ConstantGroup self, int start, int end,
+               Object ifNotPresent) {
+            this(self, start, end, false, ifNotPresent);
+        }
+
+        private int mapIndex(int index) {
+            return rangeCheck1(index, size) + offset;
+        }
+
+        @Override public final int size() {
+            return size;
+        }
+
+        @Override public Object get(int index) {
+            if (resolving)
+                return self.get(mapIndex(index));
+            else
+                return self.get(mapIndex(index), ifNotPresent);
+        }
+
+        @Override
+        public Iterator<Object> iterator() {
+            if (resolving)
+                return new AsIterator(self, offset, offset + size);
+            else
+                return new AsIterator(self, offset, offset + size, ifNotPresent);
+        }
+
+        @Override public List<Object> subList(int start, int end) {
+            rangeCheck2(start, end, size);
+            return new AsList(self, offset + start, offset + end,
+                              resolving, ifNotPresent);
+        }
+
+        @Override public Object[] toArray() {
+            return toArray(new Object[size]);
+        }
+        @Override public <T> T[] toArray(T[] a) {
+            int pad = a.length - size;
+            if (pad < 0) {
+                pad = 0;
+                a = Arrays.copyOf(a, size);
+            }
+            if (resolving)
+                self.copyConstants(offset, offset + size, a, 0);
+            else
+                self.copyConstants(offset, offset + size, a, 0,
+                                   ifNotPresent);
+            if (pad > 0)  a[size] = null;
+            return a;
+        }
+    }
+
+    static abstract
+    class WithCache extends AbstractConstantGroup {
+        @Stable final Object[] cache;
+
+        WithCache(int size) {
+            super(size);
+            // It is caller's responsibility to initialize the cache.
+            // Initial contents are all-null, which means nothing is present.
+            cache = new Object[size];
+        }
+
+        void initializeCache(List<Object> cacheContents, Object ifNotPresent) {
+            // Replace ifNotPresent with NOT_PRESENT,
+            // and null with RESOLVED_TO_NULL.
+            // Then forget about the user-provided ifNotPresent.
+            for (int i = 0; i < cache.length; i++) {
+                Object x = cacheContents.get(i);
+                if (x == ifNotPresent)
+                    continue;  // leave the null in place
+                if (x == null)
+                    x = RESOLVED_TO_NULL;
+                cache[i] = x;
+            }
+        }
+
+        @Override public Object get(int i) {
+            Object x = cache[i];
+            // @Stable array must use null for sentinel
+            if (x == null)  x = fillCache(i);
+            return unwrapNull(x);
+        }
+
+        @Override public Object get(int i, Object ifNotAvailable) {
+            Object x = cache[i];
+            // @Stable array must use null for sentinel
+            if (x == null)  return ifNotAvailable;
+            return unwrapNull(x);
+        }
+
+        @Override
+        public boolean isPresent(int i) {
+            return cache[i] != null;
+        }
+
+        /** hook for local subclasses */
+        Object fillCache(int i) {
+            throw new NoSuchElementException("constant group does not contain element #"+i);
+        }
+
+        /// routines for mapping between null sentinel and true resolved null
+
+        static Object wrapNull(Object x) {
+            return x == null ? RESOLVED_TO_NULL : x;
+        }
+
+        static Object unwrapNull(Object x) {
+            assert(x != null);
+            return x == RESOLVED_TO_NULL ? null : x;
+        }
+
+        // secret sentinel for an actual null resolved value, in the cache
+        static final Object RESOLVED_TO_NULL = new Object();
+
+        // secret sentinel for a "hole" in the cache:
+        static final Object NOT_PRESENT = new Object();
+
+    }
+
+    /** Skeleton implementation of BootstrapCallInfo. */
+    static
+    class BSCIWithCache<T> extends WithCache implements BootstrapCallInfo<T> {
+        private final MethodHandle bsm;
+        private final String name;
+        private final T type;
+
+        @Override public String toString() {
+            return bsm+"/"+name+":"+type+super.toString();
+        }
+
+        BSCIWithCache(MethodHandle bsm, String name, T type, int size) {
+            super(size);
+            this.type = type;
+            this.bsm = bsm;
+            this.name = name;
+            assert(type instanceof Class || type instanceof MethodType);
+        }
+
+        @Override public MethodHandle bootstrapMethod() { return bsm; }
+        @Override public String invocationName() { return name; }
+        @Override public T invocationType() { return type; }
+    }
+}