BufferIndexingLinkerExporter.java revision 1805:7caf1f762f1d
1/* 2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * - Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * - Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * - Neither the name of Oracle nor the names of its 16 * contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32import static jdk.dynalink.StandardNamespace.ELEMENT; 33import static jdk.dynalink.StandardNamespace.PROPERTY; 34import static jdk.dynalink.StandardOperation.GET; 35import static jdk.dynalink.StandardOperation.SET; 36 37import java.lang.invoke.MethodHandle; 38import java.lang.invoke.MethodType; 39import java.nio.Buffer; 40import java.nio.ByteBuffer; 41import java.nio.CharBuffer; 42import java.nio.DoubleBuffer; 43import java.nio.FloatBuffer; 44import java.nio.IntBuffer; 45import java.nio.LongBuffer; 46import java.nio.ShortBuffer; 47import java.util.ArrayList; 48import java.util.List; 49import jdk.dynalink.CallSiteDescriptor; 50import jdk.dynalink.NamedOperation; 51import jdk.dynalink.NamespaceOperation; 52import jdk.dynalink.Operation; 53import jdk.dynalink.StandardNamespace; 54import jdk.dynalink.linker.GuardedInvocation; 55import jdk.dynalink.linker.GuardingDynamicLinker; 56import jdk.dynalink.linker.GuardingDynamicLinkerExporter; 57import jdk.dynalink.linker.LinkRequest; 58import jdk.dynalink.linker.LinkerServices; 59import jdk.dynalink.linker.TypeBasedGuardingDynamicLinker; 60import jdk.dynalink.linker.support.Guards; 61import jdk.dynalink.linker.support.Lookup; 62 63/** 64 * This is a dynalink pluggable linker (see http://openjdk.java.net/jeps/276). 65 * This linker adds array-like indexing and "length" property to nio Buffer objects. 66 */ 67public final class BufferIndexingLinkerExporter extends GuardingDynamicLinkerExporter { 68 static { 69 System.out.println("pluggable dynalink buffer indexing linker loaded"); 70 } 71 72 private static final MethodHandle BUFFER_LIMIT; 73 private static final MethodHandle BYTEBUFFER_GET; 74 private static final MethodHandle BYTEBUFFER_PUT; 75 private static final MethodHandle CHARBUFFER_GET; 76 private static final MethodHandle CHARBUFFER_PUT; 77 private static final MethodHandle SHORTBUFFER_GET; 78 private static final MethodHandle SHORTBUFFER_PUT; 79 private static final MethodHandle INTBUFFER_GET; 80 private static final MethodHandle INTBUFFER_PUT; 81 private static final MethodHandle LONGBUFFER_GET; 82 private static final MethodHandle LONGBUFFER_PUT; 83 private static final MethodHandle FLOATBUFFER_GET; 84 private static final MethodHandle FLOATBUFFER_PUT; 85 private static final MethodHandle DOUBLEBUFFER_GET; 86 private static final MethodHandle DOUBLEBUFFER_PUT; 87 88 // guards 89 private static final MethodHandle IS_BUFFER; 90 private static final MethodHandle IS_BYTEBUFFER; 91 private static final MethodHandle IS_CHARBUFFER; 92 private static final MethodHandle IS_SHORTBUFFER; 93 private static final MethodHandle IS_INTBUFFER; 94 private static final MethodHandle IS_LONGBUFFER; 95 private static final MethodHandle IS_FLOATBUFFER; 96 private static final MethodHandle IS_DOUBLEBUFFER; 97 98 private static final MethodType GUARD_TYPE; 99 100 static { 101 final Lookup look = Lookup.PUBLIC; 102 BUFFER_LIMIT = look.findVirtual(Buffer.class, "limit", MethodType.methodType(int.class)); 103 BYTEBUFFER_GET = look.findVirtual(ByteBuffer.class, "get", 104 MethodType.methodType(byte.class, int.class)); 105 BYTEBUFFER_PUT = look.findVirtual(ByteBuffer.class, "put", 106 MethodType.methodType(ByteBuffer.class, int.class, byte.class)); 107 CHARBUFFER_GET = look.findVirtual(CharBuffer.class, "get", 108 MethodType.methodType(char.class, int.class)); 109 CHARBUFFER_PUT = look.findVirtual(CharBuffer.class, "put", 110 MethodType.methodType(CharBuffer.class, int.class, char.class)); 111 SHORTBUFFER_GET = look.findVirtual(ShortBuffer.class, "get", 112 MethodType.methodType(short.class, int.class)); 113 SHORTBUFFER_PUT = look.findVirtual(ShortBuffer.class, "put", 114 MethodType.methodType(ShortBuffer.class, int.class, short.class)); 115 INTBUFFER_GET = look.findVirtual(IntBuffer.class, "get", 116 MethodType.methodType(int.class, int.class)); 117 INTBUFFER_PUT = look.findVirtual(IntBuffer.class, "put", 118 MethodType.methodType(IntBuffer.class, int.class, int.class)); 119 LONGBUFFER_GET = look.findVirtual(LongBuffer.class, "get", 120 MethodType.methodType(long.class, int.class)); 121 LONGBUFFER_PUT = look.findVirtual(LongBuffer.class, "put", 122 MethodType.methodType(LongBuffer.class, int.class, long.class)); 123 FLOATBUFFER_GET = look.findVirtual(FloatBuffer.class, "get", 124 MethodType.methodType(float.class, int.class)); 125 FLOATBUFFER_PUT = look.findVirtual(FloatBuffer.class, "put", 126 MethodType.methodType(FloatBuffer.class, int.class, float.class)); 127 DOUBLEBUFFER_GET = look.findVirtual(DoubleBuffer.class, "get", 128 MethodType.methodType(double.class, int.class)); 129 DOUBLEBUFFER_PUT = look.findVirtual(DoubleBuffer.class, "put", 130 MethodType.methodType(DoubleBuffer.class, int.class, double.class)); 131 132 GUARD_TYPE = MethodType.methodType(boolean.class, Object.class); 133 IS_BUFFER = Guards.isInstance(Buffer.class, GUARD_TYPE); 134 IS_BYTEBUFFER = Guards.isInstance(ByteBuffer.class, GUARD_TYPE); 135 IS_CHARBUFFER = Guards.isInstance(CharBuffer.class, GUARD_TYPE); 136 IS_SHORTBUFFER = Guards.isInstance(ShortBuffer.class, GUARD_TYPE); 137 IS_INTBUFFER = Guards.isInstance(IntBuffer.class, GUARD_TYPE); 138 IS_LONGBUFFER = Guards.isInstance(LongBuffer.class, GUARD_TYPE); 139 IS_FLOATBUFFER = Guards.isInstance(FloatBuffer.class, GUARD_TYPE); 140 IS_DOUBLEBUFFER = Guards.isInstance(DoubleBuffer.class, GUARD_TYPE); 141 } 142 143 @Override 144 public List<GuardingDynamicLinker> get() { 145 final ArrayList<GuardingDynamicLinker> linkers = new ArrayList<>(); 146 linkers.add(new TypeBasedGuardingDynamicLinker() { 147 @Override 148 public boolean canLinkType(final Class<?> type) { 149 return Buffer.class.isAssignableFrom(type); 150 } 151 152 @Override 153 public GuardedInvocation getGuardedInvocation(final LinkRequest request, 154 final LinkerServices linkerServices) throws Exception { 155 final Object self = request.getReceiver(); 156 if (self == null || !canLinkType(self.getClass())) { 157 return null; 158 } 159 160 final CallSiteDescriptor desc = request.getCallSiteDescriptor(); 161 final Operation namedOp = desc.getOperation(); 162 final Operation namespaceOp = NamedOperation.getBaseOperation(namedOp); 163 final Operation op = NamespaceOperation.getBaseOperation(namespaceOp); 164 final StandardNamespace ns = StandardNamespace.findFirst(namespaceOp); 165 if (ns == null) { 166 return null; 167 } 168 169 if (op == GET) { 170 if (ns == ELEMENT) { 171 return linkGetElement(self); 172 } else if (ns == PROPERTY) { 173 final Object name = NamedOperation.getName(desc.getOperation()); 174 if ("length".equals(name)) { 175 return linkLength(); 176 } 177 } 178 } else if (op == SET && ns == ELEMENT) { 179 return linkSetElement(self); 180 } 181 182 return null; 183 } 184 }); 185 return linkers; 186 } 187 188 private static GuardedInvocation linkGetElement(final Object self) { 189 MethodHandle method = null; 190 MethodHandle guard = null; 191 if (self instanceof ByteBuffer) { 192 method = BYTEBUFFER_GET; 193 guard = IS_BYTEBUFFER; 194 } else if (self instanceof CharBuffer) { 195 method = CHARBUFFER_GET; 196 guard = IS_CHARBUFFER; 197 } else if (self instanceof ShortBuffer) { 198 method = SHORTBUFFER_GET; 199 guard = IS_SHORTBUFFER; 200 } else if (self instanceof IntBuffer) { 201 method = INTBUFFER_GET; 202 guard = IS_INTBUFFER; 203 } else if (self instanceof LongBuffer) { 204 method = LONGBUFFER_GET; 205 guard = IS_LONGBUFFER; 206 } else if (self instanceof FloatBuffer) { 207 method = FLOATBUFFER_GET; 208 guard = IS_FLOATBUFFER; 209 } else if (self instanceof DoubleBuffer) { 210 method = DOUBLEBUFFER_GET; 211 guard = IS_DOUBLEBUFFER; 212 } 213 214 return method != null? new GuardedInvocation(method, guard) : null; 215 } 216 217 private static GuardedInvocation linkSetElement(final Object self) { 218 MethodHandle method = null; 219 MethodHandle guard = null; 220 if (self instanceof ByteBuffer) { 221 method = BYTEBUFFER_PUT; 222 guard = IS_BYTEBUFFER; 223 } else if (self instanceof CharBuffer) { 224 method = CHARBUFFER_PUT; 225 guard = IS_CHARBUFFER; 226 } else if (self instanceof ShortBuffer) { 227 method = SHORTBUFFER_PUT; 228 guard = IS_SHORTBUFFER; 229 } else if (self instanceof IntBuffer) { 230 method = INTBUFFER_PUT; 231 guard = IS_INTBUFFER; 232 } else if (self instanceof LongBuffer) { 233 method = LONGBUFFER_PUT; 234 guard = IS_LONGBUFFER; 235 } else if (self instanceof FloatBuffer) { 236 method = FLOATBUFFER_PUT; 237 guard = IS_FLOATBUFFER; 238 } else if (self instanceof DoubleBuffer) { 239 method = DOUBLEBUFFER_PUT; 240 guard = IS_DOUBLEBUFFER; 241 } 242 243 return method != null? new GuardedInvocation(method, guard) : null; 244 } 245 246 private static GuardedInvocation linkLength() { 247 return new GuardedInvocation(BUFFER_LIMIT, IS_BUFFER); 248 } 249} 250