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 }