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