1 /* 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.nashorn.internal.runtime.linker; 27 28 import java.lang.invoke.MethodHandle; 29 import java.lang.invoke.MethodType; 30 import java.nio.Buffer; 31 import java.nio.ByteBuffer; 32 import java.nio.CharBuffer; 33 import java.nio.DoubleBuffer; 34 import java.nio.FloatBuffer; 35 import java.nio.IntBuffer; 36 import java.nio.LongBuffer; 37 import java.nio.ShortBuffer; 38 import jdk.internal.dynalink.CallSiteDescriptor; 39 import jdk.internal.dynalink.linker.GuardedInvocation; 40 import jdk.internal.dynalink.linker.LinkRequest; 41 import jdk.internal.dynalink.linker.LinkerServices; 42 import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; 43 import jdk.internal.dynalink.support.CallSiteDescriptorFactory; 44 import jdk.internal.dynalink.support.Guards; 45 import jdk.internal.dynalink.support.Lookup; 46 47 /** 48 * Linker to support indexed access of nio Buffer objects. 49 */ 50 final class NioBufferLinker implements TypeBasedGuardingDynamicLinker { 51 52 @Override 53 public boolean canLinkType(final Class<?> type) { 54 return canLinkTypeStatic(type); 55 } 56 57 static boolean canLinkTypeStatic(final Class<?> type) { 58 // can link nio Buffer 59 return Buffer.class.isAssignableFrom(type); 60 } 61 62 @Override 63 public GuardedInvocation getGuardedInvocation(final LinkRequest request, final LinkerServices linkerServices) throws Exception { 64 final LinkRequest requestWithoutContext = request.withoutRuntimeContext(); // Nashorn has no runtime context 65 final Object self = requestWithoutContext.getReceiver(); 66 final CallSiteDescriptor desc = requestWithoutContext.getCallSiteDescriptor(); 67 68 if (desc.getNameTokenCount() < 2 || !"dyn".equals(desc.getNameToken(CallSiteDescriptor.SCHEME))) { 69 // We only support standard "dyn:*[:*]" operations 70 return null; 71 } 72 73 final GuardedInvocation inv; 74 if (self instanceof Buffer) { 75 inv = lookup(desc, self); 76 } else { 77 throw new AssertionError(); // Should never reach here. 78 } 79 80 return Bootstrap.asType(inv, linkerServices, desc); 81 } 82 83 private static GuardedInvocation lookup(final CallSiteDescriptor desc, final Object self) { 84 final String operator = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0); 85 switch (operator) { 86 case "getElem": 87 return findGetIndexMethod(self); 88 case "setElem": 89 return findSetIndexMethod(self); 90 default: 91 return null; 92 } 93 } 94 95 // Buffer guards 96 private static MethodHandle BYTEBUFFER_GUARD = Guards.getInstanceOfGuard(ByteBuffer.class); 97 private static MethodHandle SHORTBUFFER_GUARD = Guards.getInstanceOfGuard(ShortBuffer.class); 98 private static MethodHandle INTBUFFER_GUARD = Guards.getInstanceOfGuard(IntBuffer.class); 99 private static MethodHandle LONGBUFFER_GUARD = Guards.getInstanceOfGuard(LongBuffer.class); 100 private static MethodHandle FLOATBUFFER_GUARD = Guards.getInstanceOfGuard(FloatBuffer.class); 101 private static MethodHandle DOUBLEBUFFER_GUARD = Guards.getInstanceOfGuard(DoubleBuffer.class); 102 private static MethodHandle CHARBUFFER_GUARD = Guards.getInstanceOfGuard(CharBuffer.class); 103 104 // Buffer get, put element methods 105 private static MethodHandle GET_BYTEBUFFER_ELEMENT = Lookup.PUBLIC.findVirtual(ByteBuffer.class, "get", 106 MethodType.methodType(byte.class, int.class)); 107 private static MethodHandle PUT_BYTEBUFFER_ELEMENT = Lookup.PUBLIC.findVirtual(ByteBuffer.class, "put", 108 MethodType.methodType(ByteBuffer.class, int.class, byte.class)); 109 private static MethodHandle GET_SHORTBUFFER_ELEMENT = Lookup.PUBLIC.findVirtual(ShortBuffer.class, "get", 110 MethodType.methodType(short.class, int.class)); 111 private static MethodHandle PUT_SHORTBUFFER_ELEMENT = Lookup.PUBLIC.findVirtual(ShortBuffer.class, "put", 112 MethodType.methodType(ShortBuffer.class, int.class, short.class)); 113 private static MethodHandle GET_INTBUFFER_ELEMENT = Lookup.PUBLIC.findVirtual(IntBuffer.class, "get", 114 MethodType.methodType(int.class, int.class)); 115 private static MethodHandle PUT_INTBUFFER_ELEMENT = Lookup.PUBLIC.findVirtual(IntBuffer.class, "put", 116 MethodType.methodType(IntBuffer.class, int.class, int.class)); 117 private static MethodHandle GET_LONGBUFFER_ELEMENT = Lookup.PUBLIC.findVirtual(LongBuffer.class, "get", 118 MethodType.methodType(long.class, int.class)); 119 private static MethodHandle PUT_LONGBUFFER_ELEMENT = Lookup.PUBLIC.findVirtual(LongBuffer.class, "put", 120 MethodType.methodType(LongBuffer.class, int.class, long.class)); 121 private static MethodHandle GET_FLOATBUFFER_ELEMENT = Lookup.PUBLIC.findVirtual(FloatBuffer.class, "get", 122 MethodType.methodType(float.class, int.class)); 123 private static MethodHandle PUT_FLOATBUFFER_ELEMENT = Lookup.PUBLIC.findVirtual(FloatBuffer.class, "put", 124 MethodType.methodType(FloatBuffer.class, int.class, float.class)); 125 private static MethodHandle GET_DOUBLEBUFFER_ELEMENT = Lookup.PUBLIC.findVirtual(DoubleBuffer.class, "get", 126 MethodType.methodType(double.class, int.class)); 127 private static MethodHandle PUT_DOUBLEBUFFER_ELEMENT = Lookup.PUBLIC.findVirtual(DoubleBuffer.class, "put", 128 MethodType.methodType(DoubleBuffer.class, int.class, double.class)); 129 private static MethodHandle GET_CHARBUFFER_ELEMENT = Lookup.PUBLIC.findVirtual(CharBuffer.class, "get", 130 MethodType.methodType(char.class, int.class)); 131 private static MethodHandle PUT_CHARBUFFER_ELEMENT = Lookup.PUBLIC.findVirtual(CharBuffer.class, "put", 132 MethodType.methodType(CharBuffer.class, int.class, char.class)); 133 134 private static GuardedInvocation findGetIndexMethod(final Object self) { 135 if (self instanceof ByteBuffer) { 136 return new GuardedInvocation(GET_BYTEBUFFER_ELEMENT, BYTEBUFFER_GUARD); 137 } else if (self instanceof ShortBuffer) { 138 return new GuardedInvocation(GET_SHORTBUFFER_ELEMENT, SHORTBUFFER_GUARD); 139 } else if (self instanceof IntBuffer) { 140 return new GuardedInvocation(GET_INTBUFFER_ELEMENT, INTBUFFER_GUARD); 141 } else if (self instanceof LongBuffer) { 142 return new GuardedInvocation(GET_LONGBUFFER_ELEMENT, LONGBUFFER_GUARD); 143 } else if (self instanceof FloatBuffer) { 144 return new GuardedInvocation(GET_FLOATBUFFER_ELEMENT, FLOATBUFFER_GUARD); 145 } else if (self instanceof DoubleBuffer) { 146 return new GuardedInvocation(GET_DOUBLEBUFFER_ELEMENT, DOUBLEBUFFER_GUARD); 147 } else if (self instanceof CharBuffer) { 148 return new GuardedInvocation(GET_CHARBUFFER_ELEMENT, CHARBUFFER_GUARD); 149 } 150 151 return null; 152 } 153 154 private static GuardedInvocation findSetIndexMethod(final Object self) { 155 if (self instanceof ByteBuffer) { 156 return new GuardedInvocation(PUT_BYTEBUFFER_ELEMENT, BYTEBUFFER_GUARD); 157 } else if (self instanceof ShortBuffer) { 158 return new GuardedInvocation(PUT_SHORTBUFFER_ELEMENT, SHORTBUFFER_GUARD); 159 } else if (self instanceof IntBuffer) { 160 return new GuardedInvocation(PUT_INTBUFFER_ELEMENT, INTBUFFER_GUARD); 161 } else if (self instanceof LongBuffer) { 162 return new GuardedInvocation(PUT_LONGBUFFER_ELEMENT, LONGBUFFER_GUARD); 163 } else if (self instanceof FloatBuffer) { 164 return new GuardedInvocation(PUT_FLOATBUFFER_ELEMENT, FLOATBUFFER_GUARD); 165 } else if (self instanceof DoubleBuffer) { 166 return new GuardedInvocation(PUT_DOUBLEBUFFER_ELEMENT, DOUBLEBUFFER_GUARD); 167 } else if (self instanceof CharBuffer) { 168 return new GuardedInvocation(PUT_CHARBUFFER_ELEMENT, CHARBUFFER_GUARD); 169 } 170 171 return null; 172 } 173 }