BoundCallableLinker.java revision 1477:dd36e980905b
12702Swollman/* 22702Swollman * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 369315Scharnier * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 42702Swollman * 52702Swollman * This code is free software; you can redistribute it and/or modify it 62702Swollman * under the terms of the GNU General Public License version 2 only, as 730829Scharnier * published by the Free Software Foundation. Oracle designates this 830829Scharnier * particular file as subject to the "Classpath" exception as provided 950479Speter * by Oracle in the LICENSE file that accompanied this code. 1030829Scharnier * 1130829Scharnier * This code is distributed in the hope that it will be useful, but WITHOUT 122702Swollman * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 132702Swollman * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1430829Scharnier * version 2 for more details (a copy is included in the LICENSE file that 1530829Scharnier * accompanied this code). 169937Swollman * 179937Swollman * You should have received a copy of the GNU General Public License version 189937Swollman * 2 along with this work; if not, write to the Free Software Foundation, 192702Swollman * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2017214Swollman * 2117214Swollman * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2217214Swollman * or visit www.oracle.com if you need additional information or have any 2317214Swollman * questions. 2469315Scharnier */ 2517214Swollman 2617214Swollmanpackage jdk.nashorn.internal.runtime.linker; 2717214Swollman 2817214Swollmanimport java.lang.invoke.MethodHandle; 2917214Swollmanimport java.lang.invoke.MethodHandles; 3017214Swollmanimport java.lang.invoke.MethodType; 3117214Swollmanimport java.util.Arrays; 3217214Swollmanimport jdk.internal.dynalink.CallSiteDescriptor; 332702Swollmanimport jdk.internal.dynalink.linker.GuardedInvocation; 342702Swollmanimport jdk.internal.dynalink.linker.LinkRequest; 352702Swollmanimport jdk.internal.dynalink.linker.LinkerServices; 362702Swollmanimport jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; 372702Swollmanimport jdk.internal.dynalink.linker.support.Guards; 382702Swollman 392702Swollman/** 402702Swollman * Links {@link BoundCallable} objects. Passes through to linker services for linking a callable (for either 412702Swollman * "dyn:call" or "dyn:new"), and modifies the returned invocation to deal with the receiver and argument binding. 422702Swollman */ 432702Swollmanfinal class BoundCallableLinker implements TypeBasedGuardingDynamicLinker { 442702Swollman @Override 452702Swollman public boolean canLinkType(final Class<?> type) { 462702Swollman return type == BoundCallable.class; 472702Swollman } 482702Swollman 492702Swollman @Override 502702Swollman public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception { 519937Swollman final Object objBoundCallable = linkRequest.getReceiver(); 529937Swollman if(!(objBoundCallable instanceof BoundCallable)) { 532702Swollman return null; 542702Swollman } 552702Swollman 562702Swollman final CallSiteDescriptor descriptor = linkRequest.getCallSiteDescriptor(); 572702Swollman if (descriptor.getNameTokenCount() < 2 || !"dyn".equals(descriptor.getNameToken(CallSiteDescriptor.SCHEME))) { 582702Swollman return null; 592702Swollman } 602702Swollman final String operation = descriptor.getNameToken(CallSiteDescriptor.OPERATOR); 612702Swollman // We need to distinguish "dyn:new" from "dyn:call" because "dyn:call" sites have parameter list of the form 622702Swollman // "callee, this, args", while "dyn:call" sites have "callee, args" -- they lack the "this" parameter. 632702Swollman final boolean isCall; 642702Swollman if ("new".equals(operation)) { 652702Swollman isCall = false; 662702Swollman } else if ("call".equals(operation)) { 672702Swollman isCall = true; 682702Swollman } else { 692702Swollman // Only dyn:call and dyn:new are supported. 702702Swollman return null; 712702Swollman } 722702Swollman final BoundCallable boundCallable = (BoundCallable)objBoundCallable; 732702Swollman final Object callable = boundCallable.getCallable(); 742702Swollman final Object boundThis = boundCallable.getBoundThis(); 752702Swollman 762702Swollman // We need to ask the linker services for a delegate invocation on the target callable. 772702Swollman 782702Swollman // Replace arguments (boundCallable[, this], args) => (callable[, boundThis], boundArgs, args) when delegating 792702Swollman final Object[] args = linkRequest.getArguments(); 802702Swollman final Object[] boundArgs = boundCallable.getBoundArgs(); 812702Swollman final int argsLen = args.length; 822702Swollman final int boundArgsLen = boundArgs.length; 832702Swollman final Object[] newArgs = new Object[argsLen + boundArgsLen]; 842702Swollman newArgs[0] = callable; 852702Swollman final int firstArgIndex; 862702Swollman if (isCall) { 872702Swollman newArgs[1] = boundThis; 889937Swollman firstArgIndex = 2; 892702Swollman } else { 902702Swollman firstArgIndex = 1; 912702Swollman } 922702Swollman System.arraycopy(boundArgs, 0, newArgs, firstArgIndex, boundArgsLen); 932702Swollman System.arraycopy(args, firstArgIndex, newArgs, firstArgIndex + boundArgsLen, argsLen - firstArgIndex); 942702Swollman 959937Swollman // Use R(T0, T1, T2, ...) => R(callable.class, boundThis.class, boundArg0.class, ..., boundArgn.class, T2, ...) 969937Swollman // call site type when delegating to underlying linker (for dyn:new, there's no this). 972702Swollman final MethodType type = descriptor.getMethodType(); 982702Swollman // Use R(T0, ...) => R(callable.class, ...) 992702Swollman MethodType newMethodType = descriptor.getMethodType().changeParameterType(0, callable.getClass()); 1002702Swollman if (isCall) { 1012702Swollman // R(callable.class, T1, ...) => R(callable.class, boundThis.class, ...) 1022702Swollman newMethodType = newMethodType.changeParameterType(1, boundThis == null? Object.class : boundThis.getClass()); 1032702Swollman } 1042702Swollman // R(callable.class[, boundThis.class], T2, ...) => R(callable.class[, boundThis.class], boundArg0.class, ..., boundArgn.class, T2, ...) 1052702Swollman for(int i = boundArgs.length; i-- > 0;) { 1062702Swollman newMethodType = newMethodType.insertParameterTypes(firstArgIndex, boundArgs[i] == null ? Object.class : boundArgs[i].getClass()); 1072702Swollman } 1082702Swollman final CallSiteDescriptor newDescriptor = descriptor.changeMethodType(newMethodType); 1092702Swollman 1102702Swollman // Delegate to target's linker 1112702Swollman final GuardedInvocation inv = linkerServices.getGuardedInvocation(linkRequest.replaceArguments(newDescriptor, newArgs)); 1122702Swollman if(inv == null) { 1132702Swollman return null; 1142702Swollman } 1152702Swollman 1162702Swollman // Bind (callable[, boundThis], boundArgs) to the delegate handle 1172702Swollman final MethodHandle boundHandle = MethodHandles.insertArguments(inv.getInvocation(), 0, 1182702Swollman Arrays.copyOf(newArgs, firstArgIndex + boundArgs.length)); 1192702Swollman final Class<?> p0Type = type.parameterType(0); 1202702Swollman final MethodHandle droppingHandle; 1219937Swollman if (isCall) { 1222702Swollman // Ignore incoming boundCallable and this 1232702Swollman droppingHandle = MethodHandles.dropArguments(boundHandle, 0, p0Type, type.parameterType(1)); 1249937Swollman } else { 1259937Swollman // Ignore incoming boundCallable 1269937Swollman droppingHandle = MethodHandles.dropArguments(boundHandle, 0, p0Type); 1272702Swollman } 12842997Swollman // Identity guard on boundCallable object 12942997Swollman final MethodHandle newGuard = Guards.getIdentityGuard(boundCallable); 1302702Swollman return inv.replaceMethods(droppingHandle, newGuard.asType(newGuard.type().changeParameterType(0, p0Type))); 1312702Swollman } 1322702Swollman} 1332702Swollman