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