BufferIndexingLinkerExporter.java revision 1786:80120e9b3273
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 java.lang.invoke.MethodHandle; 33import java.lang.invoke.MethodType; 34import java.nio.Buffer; 35import java.nio.ByteBuffer; 36import java.nio.CharBuffer; 37import java.nio.DoubleBuffer; 38import java.nio.FloatBuffer; 39import java.nio.IntBuffer; 40import java.nio.LongBuffer; 41import java.nio.ShortBuffer; 42import java.util.ArrayList; 43import java.util.List; 44import jdk.dynalink.CallSiteDescriptor; 45import jdk.dynalink.CompositeOperation; 46import jdk.dynalink.NamedOperation; 47import jdk.dynalink.Operation; 48import jdk.dynalink.StandardOperation; 49import jdk.dynalink.linker.GuardedInvocation; 50import jdk.dynalink.linker.GuardingDynamicLinker; 51import jdk.dynalink.linker.GuardingDynamicLinkerExporter; 52import jdk.dynalink.linker.LinkRequest; 53import jdk.dynalink.linker.LinkerServices; 54import jdk.dynalink.linker.TypeBasedGuardingDynamicLinker; 55import jdk.dynalink.linker.support.Guards; 56import jdk.dynalink.linker.support.Lookup; 57 58/** 59 * This is a dynalink pluggable linker (see http://openjdk.java.net/jeps/276). 60 * This linker adds array-like indexing and "length" property to nio Buffer objects. 61 */ 62public final class BufferIndexingLinkerExporter extends GuardingDynamicLinkerExporter { 63 static { 64 System.out.println("pluggable dynalink buffer indexing linker loaded"); 65 } 66 67 private static final MethodHandle BUFFER_LIMIT; 68 private static final MethodHandle BYTEBUFFER_GET; 69 private static final MethodHandle BYTEBUFFER_PUT; 70 private static final MethodHandle CHARBUFFER_GET; 71 private static final MethodHandle CHARBUFFER_PUT; 72 private static final MethodHandle SHORTBUFFER_GET; 73 private static final MethodHandle SHORTBUFFER_PUT; 74 private static final MethodHandle INTBUFFER_GET; 75 private static final MethodHandle INTBUFFER_PUT; 76 private static final MethodHandle LONGBUFFER_GET; 77 private static final MethodHandle LONGBUFFER_PUT; 78 private static final MethodHandle FLOATBUFFER_GET; 79 private static final MethodHandle FLOATBUFFER_PUT; 80 private static final MethodHandle DOUBLEBUFFER_GET; 81 private static final MethodHandle DOUBLEBUFFER_PUT; 82 83 // guards 84 private static final MethodHandle IS_BUFFER; 85 private static final MethodHandle IS_BYTEBUFFER; 86 private static final MethodHandle IS_CHARBUFFER; 87 private static final MethodHandle IS_SHORTBUFFER; 88 private static final MethodHandle IS_INTBUFFER; 89 private static final MethodHandle IS_LONGBUFFER; 90 private static final MethodHandle IS_FLOATBUFFER; 91 private static final MethodHandle IS_DOUBLEBUFFER; 92 93 private static final MethodType GUARD_TYPE; 94 95 static { 96 final Lookup look = Lookup.PUBLIC; 97 BUFFER_LIMIT = look.findVirtual(Buffer.class, "limit", MethodType.methodType(int.class)); 98 BYTEBUFFER_GET = look.findVirtual(ByteBuffer.class, "get", 99 MethodType.methodType(byte.class, int.class)); 100 BYTEBUFFER_PUT = look.findVirtual(ByteBuffer.class, "put", 101 MethodType.methodType(ByteBuffer.class, int.class, byte.class)); 102 CHARBUFFER_GET = look.findVirtual(CharBuffer.class, "get", 103 MethodType.methodType(char.class, int.class)); 104 CHARBUFFER_PUT = look.findVirtual(CharBuffer.class, "put", 105 MethodType.methodType(CharBuffer.class, int.class, char.class)); 106 SHORTBUFFER_GET = look.findVirtual(ShortBuffer.class, "get", 107 MethodType.methodType(short.class, int.class)); 108 SHORTBUFFER_PUT = look.findVirtual(ShortBuffer.class, "put", 109 MethodType.methodType(ShortBuffer.class, int.class, short.class)); 110 INTBUFFER_GET = look.findVirtual(IntBuffer.class, "get", 111 MethodType.methodType(int.class, int.class)); 112 INTBUFFER_PUT = look.findVirtual(IntBuffer.class, "put", 113 MethodType.methodType(IntBuffer.class, int.class, int.class)); 114 LONGBUFFER_GET = look.findVirtual(LongBuffer.class, "get", 115 MethodType.methodType(long.class, int.class)); 116 LONGBUFFER_PUT = look.findVirtual(LongBuffer.class, "put", 117 MethodType.methodType(LongBuffer.class, int.class, long.class)); 118 FLOATBUFFER_GET = look.findVirtual(FloatBuffer.class, "get", 119 MethodType.methodType(float.class, int.class)); 120 FLOATBUFFER_PUT = look.findVirtual(FloatBuffer.class, "put", 121 MethodType.methodType(FloatBuffer.class, int.class, float.class)); 122 DOUBLEBUFFER_GET = look.findVirtual(DoubleBuffer.class, "get", 123 MethodType.methodType(double.class, int.class)); 124 DOUBLEBUFFER_PUT = look.findVirtual(DoubleBuffer.class, "put", 125 MethodType.methodType(DoubleBuffer.class, int.class, double.class)); 126 127 GUARD_TYPE = MethodType.methodType(boolean.class, Object.class); 128 IS_BUFFER = Guards.isInstance(Buffer.class, GUARD_TYPE); 129 IS_BYTEBUFFER = Guards.isInstance(ByteBuffer.class, GUARD_TYPE); 130 IS_CHARBUFFER = Guards.isInstance(CharBuffer.class, GUARD_TYPE); 131 IS_SHORTBUFFER = Guards.isInstance(ShortBuffer.class, GUARD_TYPE); 132 IS_INTBUFFER = Guards.isInstance(IntBuffer.class, GUARD_TYPE); 133 IS_LONGBUFFER = Guards.isInstance(LongBuffer.class, GUARD_TYPE); 134 IS_FLOATBUFFER = Guards.isInstance(FloatBuffer.class, GUARD_TYPE); 135 IS_DOUBLEBUFFER = Guards.isInstance(DoubleBuffer.class, GUARD_TYPE); 136 } 137 138 // locate the first standard operation from the call descriptor 139 private static StandardOperation getFirstStandardOperation(final CallSiteDescriptor desc) { 140 final Operation base = NamedOperation.getBaseOperation(desc.getOperation()); 141 if (base instanceof StandardOperation) { 142 return (StandardOperation)base; 143 } else if (base instanceof CompositeOperation) { 144 final CompositeOperation cop = (CompositeOperation)base; 145 for(int i = 0; i < cop.getOperationCount(); ++i) { 146 final Operation op = cop.getOperation(i); 147 if (op instanceof StandardOperation) { 148 return (StandardOperation)op; 149 } 150 } 151 } 152 return null; 153 } 154 155 @Override 156 public List<GuardingDynamicLinker> get() { 157 final ArrayList<GuardingDynamicLinker> linkers = new ArrayList<>(); 158 linkers.add(new TypeBasedGuardingDynamicLinker() { 159 @Override 160 public boolean canLinkType(final Class<?> type) { 161 return Buffer.class.isAssignableFrom(type); 162 } 163 164 @Override 165 public GuardedInvocation getGuardedInvocation(final LinkRequest request, 166 final LinkerServices linkerServices) throws Exception { 167 final Object self = request.getReceiver(); 168 if (self == null || !canLinkType(self.getClass())) { 169 return null; 170 } 171 172 final CallSiteDescriptor desc = request.getCallSiteDescriptor(); 173 final StandardOperation op = getFirstStandardOperation(desc); 174 if (op == null) { 175 return null; 176 } 177 178 switch (op) { 179 case GET_ELEMENT: 180 return linkGetElement(self); 181 case SET_ELEMENT: 182 return linkSetElement(self); 183 case GET_PROPERTY: { 184 final Object name = NamedOperation.getName(desc.getOperation()); 185 if ("length".equals(name)) { 186 return linkLength(); 187 } 188 } 189 } 190 191 return null; 192 } 193 }); 194 return linkers; 195 } 196 197 private static GuardedInvocation linkGetElement(final Object self) { 198 MethodHandle method = null; 199 MethodHandle guard = null; 200 if (self instanceof ByteBuffer) { 201 method = BYTEBUFFER_GET; 202 guard = IS_BYTEBUFFER; 203 } else if (self instanceof CharBuffer) { 204 method = CHARBUFFER_GET; 205 guard = IS_CHARBUFFER; 206 } else if (self instanceof ShortBuffer) { 207 method = SHORTBUFFER_GET; 208 guard = IS_SHORTBUFFER; 209 } else if (self instanceof IntBuffer) { 210 method = INTBUFFER_GET; 211 guard = IS_INTBUFFER; 212 } else if (self instanceof LongBuffer) { 213 method = LONGBUFFER_GET; 214 guard = IS_LONGBUFFER; 215 } else if (self instanceof FloatBuffer) { 216 method = FLOATBUFFER_GET; 217 guard = IS_FLOATBUFFER; 218 } else if (self instanceof DoubleBuffer) { 219 method = DOUBLEBUFFER_GET; 220 guard = IS_DOUBLEBUFFER; 221 } 222 223 return method != null? new GuardedInvocation(method, guard) : null; 224 } 225 226 private static GuardedInvocation linkSetElement(final Object self) { 227 MethodHandle method = null; 228 MethodHandle guard = null; 229 if (self instanceof ByteBuffer) { 230 method = BYTEBUFFER_PUT; 231 guard = IS_BYTEBUFFER; 232 } else if (self instanceof CharBuffer) { 233 method = CHARBUFFER_PUT; 234 guard = IS_CHARBUFFER; 235 } else if (self instanceof ShortBuffer) { 236 method = SHORTBUFFER_PUT; 237 guard = IS_SHORTBUFFER; 238 } else if (self instanceof IntBuffer) { 239 method = INTBUFFER_PUT; 240 guard = IS_INTBUFFER; 241 } else if (self instanceof LongBuffer) { 242 method = LONGBUFFER_PUT; 243 guard = IS_LONGBUFFER; 244 } else if (self instanceof FloatBuffer) { 245 method = FLOATBUFFER_PUT; 246 guard = IS_FLOATBUFFER; 247 } else if (self instanceof DoubleBuffer) { 248 method = DOUBLEBUFFER_PUT; 249 guard = IS_DOUBLEBUFFER; 250 } 251 252 return method != null? new GuardedInvocation(method, guard) : null; 253 } 254 255 private static GuardedInvocation linkLength() { 256 return new GuardedInvocation(BUFFER_LIMIT, IS_BUFFER); 257 } 258} 259