| /* |
| * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * - Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * - Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * - Neither the name of Oracle nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
| * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| import static jdk.dynalink.StandardNamespace.ELEMENT; |
| import static jdk.dynalink.StandardNamespace.PROPERTY; |
| import static jdk.dynalink.StandardOperation.GET; |
| import static jdk.dynalink.StandardOperation.SET; |
| |
| import java.lang.invoke.MethodHandle; |
| import java.lang.invoke.MethodType; |
| import java.nio.Buffer; |
| import java.nio.ByteBuffer; |
| import java.nio.CharBuffer; |
| import java.nio.DoubleBuffer; |
| import java.nio.FloatBuffer; |
| import java.nio.IntBuffer; |
| import java.nio.LongBuffer; |
| import java.nio.ShortBuffer; |
| import java.util.ArrayList; |
| import java.util.List; |
| import jdk.dynalink.CallSiteDescriptor; |
| import jdk.dynalink.NamedOperation; |
| import jdk.dynalink.NamespaceOperation; |
| import jdk.dynalink.Operation; |
| import jdk.dynalink.StandardNamespace; |
| import jdk.dynalink.linker.GuardedInvocation; |
| import jdk.dynalink.linker.GuardingDynamicLinker; |
| import jdk.dynalink.linker.GuardingDynamicLinkerExporter; |
| import jdk.dynalink.linker.LinkRequest; |
| import jdk.dynalink.linker.LinkerServices; |
| import jdk.dynalink.linker.TypeBasedGuardingDynamicLinker; |
| import jdk.dynalink.linker.support.Guards; |
| import jdk.dynalink.linker.support.Lookup; |
| |
| /** |
| * This is a dynalink pluggable linker (see http://openjdk.java.net/jeps/276). |
| * This linker adds array-like indexing and "length" property to nio Buffer objects. |
| */ |
| public final class BufferIndexingLinkerExporter extends GuardingDynamicLinkerExporter { |
| static { |
| System.out.println("pluggable dynalink buffer indexing linker loaded"); |
| } |
| |
| private static final MethodHandle BUFFER_LIMIT; |
| private static final MethodHandle BYTEBUFFER_GET; |
| private static final MethodHandle BYTEBUFFER_PUT; |
| private static final MethodHandle CHARBUFFER_GET; |
| private static final MethodHandle CHARBUFFER_PUT; |
| private static final MethodHandle SHORTBUFFER_GET; |
| private static final MethodHandle SHORTBUFFER_PUT; |
| private static final MethodHandle INTBUFFER_GET; |
| private static final MethodHandle INTBUFFER_PUT; |
| private static final MethodHandle LONGBUFFER_GET; |
| private static final MethodHandle LONGBUFFER_PUT; |
| private static final MethodHandle FLOATBUFFER_GET; |
| private static final MethodHandle FLOATBUFFER_PUT; |
| private static final MethodHandle DOUBLEBUFFER_GET; |
| private static final MethodHandle DOUBLEBUFFER_PUT; |
| |
| // guards |
| private static final MethodHandle IS_BUFFER; |
| private static final MethodHandle IS_BYTEBUFFER; |
| private static final MethodHandle IS_CHARBUFFER; |
| private static final MethodHandle IS_SHORTBUFFER; |
| private static final MethodHandle IS_INTBUFFER; |
| private static final MethodHandle IS_LONGBUFFER; |
| private static final MethodHandle IS_FLOATBUFFER; |
| private static final MethodHandle IS_DOUBLEBUFFER; |
| |
| private static final MethodType GUARD_TYPE; |
| |
| static { |
| final Lookup look = Lookup.PUBLIC; |
| BUFFER_LIMIT = look.findVirtual(Buffer.class, "limit", MethodType.methodType(int.class)); |
| BYTEBUFFER_GET = look.findVirtual(ByteBuffer.class, "get", |
| MethodType.methodType(byte.class, int.class)); |
| BYTEBUFFER_PUT = look.findVirtual(ByteBuffer.class, "put", |
| MethodType.methodType(ByteBuffer.class, int.class, byte.class)); |
| CHARBUFFER_GET = look.findVirtual(CharBuffer.class, "get", |
| MethodType.methodType(char.class, int.class)); |
| CHARBUFFER_PUT = look.findVirtual(CharBuffer.class, "put", |
| MethodType.methodType(CharBuffer.class, int.class, char.class)); |
| SHORTBUFFER_GET = look.findVirtual(ShortBuffer.class, "get", |
| MethodType.methodType(short.class, int.class)); |
| SHORTBUFFER_PUT = look.findVirtual(ShortBuffer.class, "put", |
| MethodType.methodType(ShortBuffer.class, int.class, short.class)); |
| INTBUFFER_GET = look.findVirtual(IntBuffer.class, "get", |
| MethodType.methodType(int.class, int.class)); |
| INTBUFFER_PUT = look.findVirtual(IntBuffer.class, "put", |
| MethodType.methodType(IntBuffer.class, int.class, int.class)); |
| LONGBUFFER_GET = look.findVirtual(LongBuffer.class, "get", |
| MethodType.methodType(long.class, int.class)); |
| LONGBUFFER_PUT = look.findVirtual(LongBuffer.class, "put", |
| MethodType.methodType(LongBuffer.class, int.class, long.class)); |
| FLOATBUFFER_GET = look.findVirtual(FloatBuffer.class, "get", |
| MethodType.methodType(float.class, int.class)); |
| FLOATBUFFER_PUT = look.findVirtual(FloatBuffer.class, "put", |
| MethodType.methodType(FloatBuffer.class, int.class, float.class)); |
| DOUBLEBUFFER_GET = look.findVirtual(DoubleBuffer.class, "get", |
| MethodType.methodType(double.class, int.class)); |
| DOUBLEBUFFER_PUT = look.findVirtual(DoubleBuffer.class, "put", |
| MethodType.methodType(DoubleBuffer.class, int.class, double.class)); |
| |
| GUARD_TYPE = MethodType.methodType(boolean.class, Object.class); |
| IS_BUFFER = Guards.isInstance(Buffer.class, GUARD_TYPE); |
| IS_BYTEBUFFER = Guards.isInstance(ByteBuffer.class, GUARD_TYPE); |
| IS_CHARBUFFER = Guards.isInstance(CharBuffer.class, GUARD_TYPE); |
| IS_SHORTBUFFER = Guards.isInstance(ShortBuffer.class, GUARD_TYPE); |
| IS_INTBUFFER = Guards.isInstance(IntBuffer.class, GUARD_TYPE); |
| IS_LONGBUFFER = Guards.isInstance(LongBuffer.class, GUARD_TYPE); |
| IS_FLOATBUFFER = Guards.isInstance(FloatBuffer.class, GUARD_TYPE); |
| IS_DOUBLEBUFFER = Guards.isInstance(DoubleBuffer.class, GUARD_TYPE); |
| } |
| |
| @Override |
| public List<GuardingDynamicLinker> get() { |
| final ArrayList<GuardingDynamicLinker> linkers = new ArrayList<>(); |
| linkers.add(new TypeBasedGuardingDynamicLinker() { |
| @Override |
| public boolean canLinkType(final Class<?> type) { |
| return Buffer.class.isAssignableFrom(type); |
| } |
| |
| @Override |
| public GuardedInvocation getGuardedInvocation(final LinkRequest request, |
| final LinkerServices linkerServices) throws Exception { |
| final Object self = request.getReceiver(); |
| if (self == null || !canLinkType(self.getClass())) { |
| return null; |
| } |
| |
| final CallSiteDescriptor desc = request.getCallSiteDescriptor(); |
| final Operation namedOp = desc.getOperation(); |
| final Operation namespaceOp = NamedOperation.getBaseOperation(namedOp); |
| final Operation op = NamespaceOperation.getBaseOperation(namespaceOp); |
| final StandardNamespace ns = StandardNamespace.findFirst(namespaceOp); |
| if (ns == null) { |
| return null; |
| } |
| |
| if (op == GET) { |
| if (ns == ELEMENT) { |
| return linkGetElement(self); |
| } else if (ns == PROPERTY) { |
| final Object name = NamedOperation.getName(desc.getOperation()); |
| if ("length".equals(name)) { |
| return linkLength(); |
| } |
| } |
| } else if (op == SET && ns == ELEMENT) { |
| return linkSetElement(self); |
| } |
| |
| return null; |
| } |
| }); |
| return linkers; |
| } |
| |
| private static GuardedInvocation linkGetElement(final Object self) { |
| MethodHandle method = null; |
| MethodHandle guard = null; |
| if (self instanceof ByteBuffer) { |
| method = BYTEBUFFER_GET; |
| guard = IS_BYTEBUFFER; |
| } else if (self instanceof CharBuffer) { |
| method = CHARBUFFER_GET; |
| guard = IS_CHARBUFFER; |
| } else if (self instanceof ShortBuffer) { |
| method = SHORTBUFFER_GET; |
| guard = IS_SHORTBUFFER; |
| } else if (self instanceof IntBuffer) { |
| method = INTBUFFER_GET; |
| guard = IS_INTBUFFER; |
| } else if (self instanceof LongBuffer) { |
| method = LONGBUFFER_GET; |
| guard = IS_LONGBUFFER; |
| } else if (self instanceof FloatBuffer) { |
| method = FLOATBUFFER_GET; |
| guard = IS_FLOATBUFFER; |
| } else if (self instanceof DoubleBuffer) { |
| method = DOUBLEBUFFER_GET; |
| guard = IS_DOUBLEBUFFER; |
| } |
| |
| return method != null? new GuardedInvocation(method, guard) : null; |
| } |
| |
| private static GuardedInvocation linkSetElement(final Object self) { |
| MethodHandle method = null; |
| MethodHandle guard = null; |
| if (self instanceof ByteBuffer) { |
| method = BYTEBUFFER_PUT; |
| guard = IS_BYTEBUFFER; |
| } else if (self instanceof CharBuffer) { |
| method = CHARBUFFER_PUT; |
| guard = IS_CHARBUFFER; |
| } else if (self instanceof ShortBuffer) { |
| method = SHORTBUFFER_PUT; |
| guard = IS_SHORTBUFFER; |
| } else if (self instanceof IntBuffer) { |
| method = INTBUFFER_PUT; |
| guard = IS_INTBUFFER; |
| } else if (self instanceof LongBuffer) { |
| method = LONGBUFFER_PUT; |
| guard = IS_LONGBUFFER; |
| } else if (self instanceof FloatBuffer) { |
| method = FLOATBUFFER_PUT; |
| guard = IS_FLOATBUFFER; |
| } else if (self instanceof DoubleBuffer) { |
| method = DOUBLEBUFFER_PUT; |
| guard = IS_DOUBLEBUFFER; |
| } |
| |
| return method != null? new GuardedInvocation(method, guard) : null; |
| } |
| |
| private static GuardedInvocation linkLength() { |
| return new GuardedInvocation(BUFFER_LIMIT, IS_BUFFER); |
| } |
| } |