BufferIndexingLinkerExporter.java revision 1565:c779bd47d648
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.MethodHandles;
34import java.lang.invoke.MethodType;
35import java.util.ArrayList;
36import java.util.List;
37import java.nio.Buffer;
38import java.nio.ByteBuffer;
39import java.nio.CharBuffer;
40import java.nio.DoubleBuffer;
41import java.nio.FloatBuffer;
42import java.nio.IntBuffer;
43import java.nio.LongBuffer;
44import java.nio.ShortBuffer;
45import jdk.dynalink.CallSiteDescriptor;
46import jdk.dynalink.CompositeOperation;
47import jdk.dynalink.NamedOperation;
48import jdk.dynalink.Operation;
49import jdk.dynalink.StandardOperation;
50import jdk.dynalink.linker.GuardingDynamicLinker;
51import jdk.dynalink.linker.GuardingDynamicLinkerExporter;
52import jdk.dynalink.linker.GuardedInvocation;
53import jdk.dynalink.linker.TypeBasedGuardingDynamicLinker;
54import jdk.dynalink.linker.LinkRequest;
55import jdk.dynalink.linker.LinkerServices;
56import jdk.dynalink.linker.support.Guards;
57import 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 */
63public 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}
260