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