This commit is contained in:
Lana Steuck 2016-03-15 14:50:09 -07:00
commit aae0b79f80
22 changed files with 440 additions and 115 deletions

@ -83,7 +83,6 @@
package jdk.dynalink;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.util.Objects;
@ -105,28 +104,28 @@ import java.util.Objects;
* descriptors (typically, values passed in additional parameters to the
* bootstrap method. Since the descriptors must be immutable, you can set up a
* cache for equivalent descriptors to have the call sites share them.
* <p>
* The class extends {@link SecureLookupSupplier} for security-checked access to
* the {@code MethodHandles.Lookup} object it carries. This lookup should be used
* to find method handles to set as targets of the call site described by this
* descriptor.
*/
public class CallSiteDescriptor {
private final MethodHandles.Lookup lookup;
public class CallSiteDescriptor extends SecureLookupSupplier {
private final Operation operation;
private final MethodType methodType;
/**
* The name of a runtime permission to invoke the {@link #getLookup()}
* method.
*/
public static final String GET_LOOKUP_PERMISSION_NAME = "dynalink.getLookup";
private static final RuntimePermission GET_LOOKUP_PERMISSION = new RuntimePermission(GET_LOOKUP_PERMISSION_NAME);
/**
* Creates a new call site descriptor.
* @param lookup the lookup object describing the class the call site belongs to.
* When creating descriptors from a {@link java.lang.invoke} bootstrap method,
* it should be the lookup passed to the bootstrap.
* @param operation the dynamic operation at the call site.
* @param methodType the method type of the call site.
* @param methodType the method type of the call site. When creating
* descriptors from a {@link java.lang.invoke} bootstrap method, it should be
* the method type passed to the bootstrap.
*/
public CallSiteDescriptor(final Lookup lookup, final Operation operation, final MethodType methodType) {
this.lookup = Objects.requireNonNull(lookup, "lookup");
super(lookup);
this.operation = Objects.requireNonNull(operation, "name");
this.methodType = Objects.requireNonNull(methodType, "methodType");
}
@ -148,34 +147,6 @@ public class CallSiteDescriptor {
return methodType;
}
/**
* Returns the lookup that should be used to find method handles to set as
* targets of the call site described by this descriptor. When creating
* descriptors from a {@link java.lang.invoke} bootstrap method, it should
* be the lookup passed to the bootstrap.
* @return the lookup that should be used to find method handles to set as
* targets of the call site described by this descriptor.
* @throws SecurityException if the lookup isn't the
* {@link MethodHandles#publicLookup()} and a security manager is present,
* and a check for {@code RuntimePermission("dynalink.getLookup")} fails.
*/
public final Lookup getLookup() {
final SecurityManager sm = System.getSecurityManager();
if (sm != null && lookup != MethodHandles.publicLookup()) {
sm.checkPermission(GET_LOOKUP_PERMISSION);
}
return lookup;
}
/**
* Returns the value of {@link #getLookup()} without a security check. Can
* be used by subclasses to access the lookup quickly.
* @return same as returned value of {@link #getLookup()}.
*/
protected final Lookup getLookupPrivileged() {
return lookup;
}
/**
* Creates a new call site descriptor from this descriptor, which is
* identical to this, except it changes the method type. Invokes
@ -211,7 +182,7 @@ public class CallSiteDescriptor {
* @return a new call site descriptor, with the method type changed.
*/
protected CallSiteDescriptor changeMethodTypeInternal(final MethodType newMethodType) {
return new CallSiteDescriptor(lookup, operation, newMethodType);
return new CallSiteDescriptor(getLookupPrivileged(), operation, newMethodType);
}
/**
@ -233,7 +204,7 @@ public class CallSiteDescriptor {
final CallSiteDescriptor other = (CallSiteDescriptor)obj;
return operation.equals(other.operation) &&
methodType.equals(other.methodType) &&
lookupsEqual(lookup, other.lookup);
lookupsEqual(getLookupPrivileged(), other.getLookupPrivileged());
}
/**
@ -257,7 +228,7 @@ public class CallSiteDescriptor {
*/
@Override
public int hashCode() {
return operation.hashCode() + 31 * methodType.hashCode() + 31 * 31 * lookupHashCode(lookup);
return operation.hashCode() + 31 * methodType.hashCode() + 31 * 31 * lookupHashCode(getLookupPrivileged());
}
/**
@ -279,7 +250,7 @@ public class CallSiteDescriptor {
@Override
public String toString() {
final String mt = methodType.toString();
final String l = lookup.toString();
final String l = getLookupPrivileged().toString();
final String o = operation.toString();
final StringBuilder b = new StringBuilder(o.length() + mt.length() + 1 + l.length());
return b.append(o).append(mt).append('@').append(l).toString();

@ -85,7 +85,10 @@ package jdk.dynalink;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.util.Objects;
import java.util.function.Supplier;
import jdk.dynalink.linker.ConversionComparator.Comparison;
import jdk.dynalink.linker.GuardedInvocation;
import jdk.dynalink.linker.GuardingDynamicLinker;
@ -97,7 +100,7 @@ import jdk.dynalink.linker.MethodHandleTransformer;
* Default implementation of the {@link LinkerServices} interface.
*/
final class LinkerServicesImpl implements LinkerServices {
private static final ThreadLocal<LinkRequest> threadLinkRequest = new ThreadLocal<>();
private static final ThreadLocal<SecureLookupSupplier> threadLookupSupplier = new ThreadLocal<>();
private final TypeConverterFactory typeConverterFactory;
private final GuardingDynamicLinker topLevelLinker;
@ -138,14 +141,31 @@ final class LinkerServicesImpl implements LinkerServices {
return typeConverterFactory.compareConversion(sourceType, targetType1, targetType2);
}
/**
* Used to marshal a checked exception out of Supplier.get() in getGuardedInvocation.
*/
private static class LinkerException extends RuntimeException {
private static final long serialVersionUID = 1L;
public LinkerException(final Exception cause) {
super(null, cause, true, false);
}
}
@Override
public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest) throws Exception {
final LinkRequest prevLinkRequest = threadLinkRequest.get();
threadLinkRequest.set(linkRequest);
try {
return topLevelLinker.getGuardedInvocation(linkRequest, this);
} finally {
threadLinkRequest.set(prevLinkRequest);
return getWithLookupInternal(() -> {
try {
return topLevelLinker.getGuardedInvocation(linkRequest, this);
} catch (final RuntimeException e) {
throw e;
} catch (final Exception e) {
throw new LinkerException(e);
}
}, linkRequest.getCallSiteDescriptor());
} catch (final LinkerException e) {
throw (Exception)e.getCause();
}
}
@ -154,10 +174,32 @@ final class LinkerServicesImpl implements LinkerServices {
return internalObjectsFilter != null ? internalObjectsFilter.transform(target) : target;
}
static MethodHandles.Lookup getCurrentLookup() {
final LinkRequest currentRequest = threadLinkRequest.get();
if (currentRequest != null) {
return currentRequest.getCallSiteDescriptor().getLookup();
@Override
public <T> T getWithLookup(final Supplier<T> operation, final SecureLookupSupplier lookupSupplier) {
return getWithLookupInternal(
Objects.requireNonNull(operation, "action"),
Objects.requireNonNull(lookupSupplier, "lookupSupplier"));
}
private static <T> T getWithLookupInternal(final Supplier<T> operation, final SecureLookupSupplier lookupSupplier) {
final SecureLookupSupplier prevLookupSupplier = threadLookupSupplier.get();
final boolean differ = prevLookupSupplier != lookupSupplier;
if (differ) {
threadLookupSupplier.set(lookupSupplier);
}
try {
return operation.get();
} finally {
if (differ) {
threadLookupSupplier.set(prevLookupSupplier);
}
}
}
static Lookup getCurrentLookup() {
final SecureLookupSupplier lookupSupplier = threadLookupSupplier.get();
if (lookupSupplier != null) {
return lookupSupplier.getLookup();
}
return MethodHandles.publicLookup();
}

@ -0,0 +1,79 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.dynalink;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.util.Objects;
/**
* Provides security-checked access to a {@code MethodHandles.Lookup} object.
* See {@link #getLookup()} for details.
*/
public class SecureLookupSupplier {
/**
* The name of a runtime permission required to successfully invoke the
* {@link #getLookup()} method.
*/
public static final String GET_LOOKUP_PERMISSION_NAME = "dynalink.getLookup";
private static final RuntimePermission GET_LOOKUP_PERMISSION = new RuntimePermission(SecureLookupSupplier.GET_LOOKUP_PERMISSION_NAME);
private final MethodHandles.Lookup lookup;
/**
* Creates a new secure lookup supplier, securing the passed lookup.
* @param lookup the lookup to secure. Can not be null.
* @throws NullPointerException if null is passed.
*/
public SecureLookupSupplier(final MethodHandles.Lookup lookup) {
this.lookup = Objects.requireNonNull(lookup, "lookup");
}
/**
* Returns the lookup secured by this {@code SecureLookupSupplier}.
* @return the lookup secured by this {@code SecureLookupSupplier}.
* @throws SecurityException if the secured lookup isn't the
* {@link MethodHandles#publicLookup()}, and a security manager is present,
* and a check for {@code RuntimePermission("dynalink.getLookup")} fails.
*/
public final Lookup getLookup() {
final SecurityManager sm = System.getSecurityManager();
if (sm != null && lookup != MethodHandles.publicLookup()) {
sm.checkPermission(GET_LOOKUP_PERMISSION);
}
return lookup;
}
/**
* Returns the value of {@link #getLookup()} without a security check. Can
* be used by subclasses to access the lookup quickly.
* @return same as returned value of {@link #getLookup()}.
*/
protected final Lookup getLookupPrivileged() {
return lookup;
}
}

@ -95,6 +95,7 @@ import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import jdk.dynalink.CallSiteDescriptor;
import jdk.dynalink.SecureLookupSupplier;
import jdk.dynalink.internal.AccessControlContextFactory;
import jdk.dynalink.linker.support.Lookup;
@ -107,7 +108,7 @@ import jdk.dynalink.linker.support.Lookup;
class CallerSensitiveDynamicMethod extends SingleDynamicMethod {
private static final AccessControlContext GET_LOOKUP_CONTEXT =
AccessControlContextFactory.createAccessControlContext(
CallSiteDescriptor.GET_LOOKUP_PERMISSION_NAME);
SecureLookupSupplier.GET_LOOKUP_PERMISSION_NAME);
// Typed as "AccessibleObject" as it can be either a method or a constructor.
// If we were Java8-only, we could use java.lang.reflect.Executable

@ -84,7 +84,6 @@
package jdk.dynalink.beans;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import jdk.dynalink.beans.GuardedInvocationComponent.ValidationType;
import jdk.dynalink.linker.support.Lookup;

@ -27,6 +27,8 @@ package jdk.dynalink.beans;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.util.function.Supplier;
import jdk.dynalink.SecureLookupSupplier;
import jdk.dynalink.linker.ConversionComparator.Comparison;
import jdk.dynalink.linker.GuardedInvocation;
import jdk.dynalink.linker.LinkRequest;
@ -77,4 +79,9 @@ final class LinkerServicesWithMissingMemberHandlerFactory implements LinkerServi
public MethodHandle filterInternalObjects(final MethodHandle target) {
return linkerServices.filterInternalObjects(target);
}
@Override
public <T> T getWithLookup(final Supplier<T> operation, final SecureLookupSupplier lookupSupplier) {
return linkerServices.getWithLookup(operation, lookupSupplier);
}
}

@ -98,6 +98,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import jdk.dynalink.CallSiteDescriptor;
import jdk.dynalink.SecureLookupSupplier;
import jdk.dynalink.beans.ApplicableOverloadedMethods.ApplicabilityTest;
import jdk.dynalink.internal.AccessControlContextFactory;
import jdk.dynalink.internal.InternalTypeUtilities;
@ -148,7 +149,7 @@ class OverloadedDynamicMethod extends DynamicMethod {
}
@Override
public MethodHandle getInvocation(final CallSiteDescriptor callSiteDescriptor, final LinkerServices linkerServices) {
MethodHandle getInvocation(final CallSiteDescriptor callSiteDescriptor, final LinkerServices linkerServices) {
final MethodType callSiteType = callSiteDescriptor.getMethodType();
// First, find all methods applicable to the call site by subtyping (JLS 15.12.2.2)
final ApplicableOverloadedMethods subtypingApplicables = getApplicables(callSiteType,
@ -218,14 +219,14 @@ class OverloadedDynamicMethod extends DynamicMethod {
for(final SingleDynamicMethod method: invokables) {
methodHandles.add(method.getTarget(callSiteDescriptor));
}
return new OverloadedMethod(methodHandles, this, getCallSiteClassLoader(callSiteDescriptor), callSiteType, linkerServices).getInvoker();
return new OverloadedMethod(methodHandles, this, getCallSiteClassLoader(callSiteDescriptor), callSiteType, linkerServices, callSiteDescriptor).getInvoker();
}
}
}
private static final AccessControlContext GET_CALL_SITE_CLASS_LOADER_CONTEXT =
AccessControlContextFactory.createAccessControlContext(
"getClassLoader", CallSiteDescriptor.GET_LOOKUP_PERMISSION_NAME);
"getClassLoader", SecureLookupSupplier.GET_LOOKUP_PERMISSION_NAME);
private static ClassLoader getCallSiteClassLoader(final CallSiteDescriptor callSiteDescriptor) {
return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {

@ -91,6 +91,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import jdk.dynalink.SecureLookupSupplier;
import jdk.dynalink.internal.InternalTypeUtilities;
import jdk.dynalink.linker.LinkerServices;
import jdk.dynalink.linker.support.Lookup;
@ -108,6 +109,7 @@ class OverloadedMethod {
private final MethodType callSiteType;
private final MethodHandle invoker;
private final LinkerServices linkerServices;
private final SecureLookupSupplier lookupSupplier;
private final ArrayList<MethodHandle> fixArgMethods;
private final ArrayList<MethodHandle> varArgMethods;
@ -115,12 +117,14 @@ class OverloadedMethod {
final OverloadedDynamicMethod parent,
final ClassLoader callSiteClassLoader,
final MethodType callSiteType,
final LinkerServices linkerServices) {
final LinkerServices linkerServices,
final SecureLookupSupplier lookupSupplier) {
this.parent = parent;
this.callSiteClassLoader = callSiteClassLoader;
final Class<?> commonRetType = getCommonReturnType(methodHandles);
this.callSiteType = callSiteType.changeReturnType(commonRetType);
this.linkerServices = linkerServices;
this.lookupSupplier = lookupSupplier;
fixArgMethods = new ArrayList<>(methodHandles.size());
varArgMethods = new ArrayList<>(methodHandles.size());
@ -173,11 +177,14 @@ class OverloadedMethod {
break;
}
case 1: {
method = SingleDynamicMethod.getInvocation(methods.get(0), callSiteType, linkerServices);
final List<MethodHandle> fmethods = methods;
method = linkerServices.getWithLookup(
()->SingleDynamicMethod.getInvocation(fmethods.get(0), callSiteType, linkerServices),
lookupSupplier);
break;
}
default: {
// This is unfortunate - invocation time ambiguity. We can still save the day if
// This is unfortunate - invocation time ambiguity.
method = getAmbiguousMethodThrower(argTypes, methods);
break;
}

@ -99,7 +99,6 @@ import jdk.dynalink.linker.support.Lookup;
* arity).
*/
abstract class SingleDynamicMethod extends DynamicMethod {
private static final MethodHandle CAN_CONVERT_TO = Lookup.findOwnStatic(MethodHandles.lookup(), "canConvertTo", boolean.class, LinkerServices.class, Class.class, Object.class);
SingleDynamicMethod(final String name) {
@ -129,8 +128,8 @@ abstract class SingleDynamicMethod extends DynamicMethod {
@Override
MethodHandle getInvocation(final CallSiteDescriptor callSiteDescriptor, final LinkerServices linkerServices) {
return getInvocation(getTarget(callSiteDescriptor), callSiteDescriptor.getMethodType(),
linkerServices);
return linkerServices.getWithLookup(()->getInvocation(getTarget(callSiteDescriptor),
callSiteDescriptor.getMethodType(), linkerServices), callSiteDescriptor);
}
@Override

@ -1,25 +0,0 @@
# Copyright 2009-2013 Attila Szegedi
#
# Licensed under either the Apache License, Version 2.0 (the "Apache
# License") or the BSD License (the "BSD License"), with licensee
# being free to choose either of the two at their discretion.
#
# You may not use this file except in compliance with either the Apache
# License or the BSD License.
#
# A copy of the BSD License is available in the root directory of the
# source distribution of the project under the file name
# "Dynalink-License-BSD.txt".
#
# A copy of the Apache License is available in the root directory of the
# source distribution of the project under the file name
# "Dynalink-License-Apache-2.0.txt". Alternatively, you may obtain a
# copy of the Apache License at <http://www.apache.org/licenses/LICENSE-2.0>
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See your chosen License for the specific language governing permissions
# and limitations under that License.
couldNotDiscoverAccessibleMethods=Could not discover accessible methods of class {0}, trying its superclasses and interfaces.

@ -85,7 +85,7 @@ package jdk.dynalink.linker;
import java.lang.invoke.MethodHandles;
import java.util.function.Supplier;
import jdk.dynalink.CallSiteDescriptor;
import jdk.dynalink.SecureLookupSupplier;
import jdk.dynalink.beans.BeansLinker;
import jdk.dynalink.linker.support.TypeUtilities;
@ -132,7 +132,7 @@ public interface GuardingTypeConverterFactory {
* (e.g. to convert some object from the dynamic language into a Java
* interface for interoperability). Invoking the {@link Supplier#get()}
* method on the passed supplier will be subject to the same security checks
* as {@link CallSiteDescriptor#getLookup()}. An implementation should avoid
* as {@link SecureLookupSupplier#getLookup()}. An implementation should avoid
* retrieving the lookup if it is not needed so as to avoid the expense of
* {@code AccessController.doPrivileged} call.
* @return a guarded invocation that can take an object (if it passes guard)
@ -142,6 +142,7 @@ public interface GuardingTypeConverterFactory {
* can always handle the conversion, it can return an unconditional
* invocation (one whose guard is null).
* @throws Exception if there was an error during creation of the converter
* @see LinkerServices#getWithLookup(Supplier, SecureLookupSupplier)
*/
public GuardedInvocation convertToType(Class<?> sourceType, Class<?> targetType, Supplier<MethodHandles.Lookup> lookupSupplier) throws Exception;
}

@ -86,8 +86,10 @@ package jdk.dynalink.linker;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.function.Supplier;
import jdk.dynalink.DynamicLinker;
import jdk.dynalink.DynamicLinkerFactory;
import jdk.dynalink.SecureLookupSupplier;
import jdk.dynalink.linker.ConversionComparator.Comparison;
import jdk.dynalink.linker.support.TypeUtilities;
@ -217,4 +219,34 @@ public interface LinkerServices {
* filtered for wrapping and unwrapping.
*/
public MethodHandle filterInternalObjects(final MethodHandle target);
/**
* Executes an operation within the context of a particular
* {@code MethodHandles.Lookup} lookup object. Normally, methods on
* {@code LinkerServices} are invoked as part of the linking mechanism in
* which case Dynalink internally maintains a per-thread current lookup
* (the one belonging to the descriptor of the call site being linked). This
* lookup can be retrieved by any {@link GuardingTypeConverterFactory}
* involved in linking if it needs to generate lookup-sensitive converters.
* However, linker services' methods can be invoked outside the linking
* process too when implementing invocation-time dispatch schemes, invoking
* conversions at runtime, etc. If it becomes necessary to use any type
* converter in this situation, and it needs a lookup, it will normally only
* get {@link MethodHandles#publicLookup()} as the thread is not engaged in
* a linking operation. If there is a way to meaningfully associate the
* operation to the context of some caller class, consider performing it
* within an invocation of this method and passing a full-strength lookup
* for that class, as it will associate that lookup with the current thread
* for the duration of the operation. Note that since you are passing a
* {@link SecureLookupSupplier}, any invoked type converter factories will
* still need to hold the necessary runtime permission to be able to get the
* lookup should they need it.
* @param <T> the type of the return value provided by the passed-in supplier.
* @param operation the operation to execute in context of the specified lookup.
* @param lookupSupplier secure supplier of the lookup
* @return the return value of the action
* @throws NullPointerException if either action or lookupSupplier are null.
* @see GuardingTypeConverterFactory#convertToType(Class, Class, Supplier)
*/
public <T> T getWithLookup(final Supplier<T> operation, final SecureLookupSupplier lookupSupplier);
}

@ -171,7 +171,7 @@ public final class ScriptUtils {
final LinkerServices linker = Bootstrap.getLinkerServices();
final Object objToConvert = unwrap(obj);
final MethodHandle converter = linker.getTypeConverter(objToConvert.getClass(), clazz);
final MethodHandle converter = linker.getTypeConverter(objToConvert.getClass(), clazz);
if (converter == null) {
// no supported conversion!
throw new UnsupportedOperationException("conversion not supported");

@ -1057,6 +1057,9 @@ public final class Global extends Scope {
private ScriptObject builtinArrayIteratorPrototype;
private ScriptObject builtinStringIteratorPrototype;
private ScriptFunction builtInJavaExtend;
private ScriptFunction builtInJavaTo;
/*
* ECMA section 13.2.3 The [[ThrowTypeError]] Function Object
*/
@ -2085,10 +2088,39 @@ public final class Global extends Scope {
private synchronized ScriptObject getBuiltinJavaApi() {
if (this.builtinJavaApi == null) {
this.builtinJavaApi = initConstructor("Java", ScriptObject.class);
this.builtInJavaExtend = (ScriptFunction)builtinJavaApi.get("extend");
this.builtInJavaTo = (ScriptFunction)builtinJavaApi.get("to");
}
return this.builtinJavaApi;
}
/**
* Returns true if the passed function is the built-in "Java.extend".
* @param fn the function in question
* @return true if the function is built-in "Java.extend"
*/
public static boolean isBuiltInJavaExtend(final ScriptFunction fn) {
if(!"extend".equals(fn.getName())) {
// Avoid hitting the thread local if the name doesn't match.
return false;
}
return fn == Context.getGlobal().builtInJavaExtend;
}
/**
* Returns true if the passed function is the built-in "Java.to".
* @param fn the function in question
* @return true if the function is built-in "Java.to"
*/
public static boolean isBuiltInJavaTo(final ScriptFunction fn) {
if(!"to".equals(fn.getName())) {
// Avoid hitting the thread local if the name doesn't match.
return false;
}
return fn == Context.getGlobal().builtInJavaTo;
}
private synchronized ScriptFunction getBuiltinRangeError() {
if (this.builtinRangeError == null) {
this.builtinRangeError = initErrorSubtype("RangeError", getErrorPrototype());

@ -37,6 +37,7 @@ import java.util.Deque;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import jdk.dynalink.SecureLookupSupplier;
import jdk.dynalink.beans.BeansLinker;
import jdk.dynalink.beans.StaticClass;
import jdk.dynalink.linker.support.TypeUtilities;
@ -64,7 +65,6 @@ import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory;
*/
@ScriptClass("Java")
public final class NativeJava {
// initialized by nasgen
@SuppressWarnings("unused")
private static PropertyMap $nasgenmap$;
@ -391,6 +391,9 @@ public final class NativeJava {
if(targetClass.isArray()) {
try {
if (self instanceof SecureLookupSupplier) {
return JSType.toJavaArrayWithLookup(obj, targetClass.getComponentType(), (SecureLookupSupplier)self);
}
return JSType.toJavaArray(obj, targetClass.getComponentType());
} catch (final Exception exp) {
throw typeError(exp, "java.array.conversion.failed", targetClass.getName());
@ -468,7 +471,7 @@ public final class NativeJava {
// Usually writable properties are a subset as 'write-only' properties are rare
props.addAll(BeansLinker.getReadableStaticPropertyNames(clazz));
props.addAll(BeansLinker.getStaticMethodNames(clazz));
} catch (Exception ignored) {}
} catch (final Exception ignored) {}
return props;
} else if (object instanceof JSObject) {
final JSObject jsObj = ((JSObject)object);
@ -484,7 +487,7 @@ public final class NativeJava {
// Usually writable properties are a subset as 'write-only' properties are rare
props.addAll(BeansLinker.getReadableInstancePropertyNames(clazz));
props.addAll(BeansLinker.getInstanceMethodNames(clazz));
} catch (Exception ignored) {}
} catch (final Exception ignored) {}
return props;
}

@ -35,6 +35,7 @@ import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import jdk.dynalink.SecureLookupSupplier;
import jdk.dynalink.beans.StaticClass;
import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
@ -175,6 +176,9 @@ public enum JSType {
/** Method handle to convert a JS Object to a Java array. */
public static final Call TO_JAVA_ARRAY = staticCall(JSTYPE_LOOKUP, JSType.class, "toJavaArray", Object.class, Object.class, Class.class);
/** Method handle to convert a JS Object to a Java array. */
public static final Call TO_JAVA_ARRAY_WITH_LOOKUP = staticCall(JSTYPE_LOOKUP, JSType.class, "toJavaArrayWithLookup", Object.class, Object.class, Class.class, SecureLookupSupplier.class);
/** Method handle for void returns. */
public static final Call VOID_RETURN = staticCall(JSTYPE_LOOKUP, JSType.class, "voidReturn", void.class);
@ -798,7 +802,7 @@ public enum JSType {
* @return the value converted to Integer or Double
*/
public static Number toNarrowestNumber(final long l) {
return isRepresentableAsInt(l) ? Integer.valueOf((int) l) : Double.valueOf((double) l);
return isRepresentableAsInt(l) ? Integer.valueOf((int) l) : Double.valueOf(l);
}
/**
@ -1108,7 +1112,7 @@ public enum JSType {
* @return the uint32 value as double
*/
public static double toUint32Double(final int num) {
return (double) toUint32(num);
return toUint32(num);
}
/**
@ -1318,6 +1322,20 @@ public enum JSType {
}
}
/**
* Script object to Java array conversion.
*
* @param obj script object to be converted to Java array
* @param componentType component type of the destination array required
* @param lookupSupplier supplier for the lookup of the class invoking the
* conversion. Can be used to use protection-domain specific converters
* if the target type is a SAM.
* @return converted Java array
*/
public static Object toJavaArrayWithLookup(final Object obj, final Class<?> componentType, final SecureLookupSupplier lookupSupplier) {
return Bootstrap.getLinkerServices().getWithLookup(()->toJavaArray(obj, componentType), lookupSupplier);
}
/**
* Java array to java array conversion - but using type conversions implemented by linker.
*
@ -1744,9 +1762,9 @@ public enum JSType {
public static MethodHandle unboxConstant(final Object o) {
if (o != null) {
if (o.getClass() == Integer.class) {
return MH.constant(int.class, ((Integer)o));
return MH.constant(int.class, o);
} else if (o.getClass() == Double.class) {
return MH.constant(double.class, ((Double)o));
return MH.constant(double.class, o);
}
}
return MH.constant(Object.class, o);

@ -29,6 +29,7 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
@ -45,6 +46,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.concurrent.atomic.LongAdder;
import jdk.dynalink.CallSiteDescriptor;
import jdk.dynalink.SecureLookupSupplier;
import jdk.dynalink.linker.GuardedInvocation;
import jdk.dynalink.linker.LinkRequest;
import jdk.dynalink.linker.support.Guards;
@ -129,7 +131,7 @@ public class ScriptFunction extends ScriptObject {
private static final Object LAZY_PROTOTYPE = new Object();
private static final AccessControlContext GET_LOOKUP_PERMISSION_CONTEXT =
AccessControlContextFactory.createAccessControlContext(CallSiteDescriptor.GET_LOOKUP_PERMISSION_NAME);
AccessControlContextFactory.createAccessControlContext(SecureLookupSupplier.GET_LOOKUP_PERMISSION_NAME);
private static PropertyMap createStrictModeMap(final PropertyMap map) {
final int flags = Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE;
@ -955,10 +957,14 @@ public class ScriptFunction extends ScriptObject {
// It's already (callee, this, args...), just what we need
boundHandle = callHandle;
}
} else if (data.isBuiltin() && "extend".equals(data.getName())) {
// NOTE: the only built-in named "extend" is NativeJava.extend. As a special-case we're binding the
// current lookup as its "this" so it can do security-sensitive creation of adapter classes.
} else if (data.isBuiltin() && Global.isBuiltInJavaExtend(this)) {
// We're binding the current lookup as "self" so the function can do
// security-sensitive creation of adapter classes.
boundHandle = MH.dropArguments(MH.bindTo(callHandle, getLookupPrivileged(desc)), 0, type.parameterType(0), type.parameterType(1));
} else if (data.isBuiltin() && Global.isBuiltInJavaTo(this)) {
// We're binding the current call site descriptor as "self" so the function can do
// security-sensitive creation of adapter classes.
boundHandle = MH.dropArguments(MH.bindTo(callHandle, desc), 0, type.parameterType(0), type.parameterType(1));
} else if (scopeCall && needsWrappedThis()) {
// Make a handle that drops the passed "this" argument and substitutes either Global or Undefined
// (this, args...) => ([this], args...)

@ -32,8 +32,10 @@ import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.function.Supplier;
import jdk.dynalink.CallSiteDescriptor;
import jdk.dynalink.NamedOperation;
import jdk.dynalink.SecureLookupSupplier;
import jdk.dynalink.StandardOperation;
import jdk.dynalink.beans.BeansLinker;
import jdk.dynalink.linker.ConversionComparator.Comparison;
@ -153,7 +155,7 @@ public class NashornBeansLinker implements GuardingDynamicLinker {
if (arg instanceof ConsString) {
return arg.toString();
} else if (mirrorAlways && arg instanceof ScriptObject) {
return ScriptUtils.wrap((ScriptObject)arg);
return ScriptUtils.wrap(arg);
} else {
return arg;
}
@ -250,5 +252,10 @@ public class NashornBeansLinker implements GuardingDynamicLinker {
public MethodHandle filterInternalObjects(final MethodHandle target) {
return linkerServices.filterInternalObjects(target);
}
@Override
public <T> T getWithLookup(final Supplier<T> operation, final SecureLookupSupplier lookupSupplier) {
return linkerServices.getWithLookup(operation, lookupSupplier);
}
}
}

@ -43,6 +43,7 @@ import jdk.dynalink.CallSiteDescriptor;
import jdk.dynalink.CompositeOperation;
import jdk.dynalink.NamedOperation;
import jdk.dynalink.Operation;
import jdk.dynalink.SecureLookupSupplier;
import jdk.dynalink.StandardOperation;
import jdk.nashorn.internal.ir.debug.NashornTextifier;
import jdk.nashorn.internal.runtime.AccessControlContextFactory;
@ -161,7 +162,7 @@ public final class NashornCallSiteDescriptor extends CallSiteDescriptor {
};
private static final AccessControlContext GET_LOOKUP_PERMISSION_CONTEXT =
AccessControlContextFactory.createAccessControlContext(CallSiteDescriptor.GET_LOOKUP_PERMISSION_NAME);
AccessControlContextFactory.createAccessControlContext(SecureLookupSupplier.GET_LOOKUP_PERMISSION_NAME);
@SuppressWarnings("unchecked")
private static final Map<String, Reference<NamedOperation>>[] NAMED_OPERATIONS =

@ -42,6 +42,7 @@ import java.util.Queue;
import java.util.function.Supplier;
import javax.script.Bindings;
import jdk.dynalink.CallSiteDescriptor;
import jdk.dynalink.SecureLookupSupplier;
import jdk.dynalink.linker.ConversionComparator;
import jdk.dynalink.linker.GuardedInvocation;
import jdk.dynalink.linker.GuardingTypeConverterFactory;
@ -53,6 +54,7 @@ import jdk.dynalink.linker.support.Lookup;
import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.api.scripting.ScriptUtils;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
import jdk.nashorn.internal.objects.NativeArray;
import jdk.nashorn.internal.runtime.AccessControlContextFactory;
import jdk.nashorn.internal.runtime.JSType;
@ -67,7 +69,7 @@ import jdk.nashorn.internal.runtime.Undefined;
*/
final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTypeConverterFactory, ConversionComparator {
private static final AccessControlContext GET_LOOKUP_PERMISSION_CONTEXT =
AccessControlContextFactory.createAccessControlContext(CallSiteDescriptor.GET_LOOKUP_PERMISSION_NAME);
AccessControlContextFactory.createAccessControlContext(SecureLookupSupplier.GET_LOOKUP_PERMISSION_NAME);
private static final ClassValue<MethodHandle> ARRAY_CONVERTERS = new ClassValue<MethodHandle>() {
@Override
@ -111,7 +113,7 @@ final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTyp
@Override
public GuardedInvocation convertToType(final Class<?> sourceType, final Class<?> targetType, final Supplier<MethodHandles.Lookup> lookupSupplier) throws Exception {
GuardedInvocation gi = convertToTypeNoCast(sourceType, targetType);
GuardedInvocation gi = convertToTypeNoCast(sourceType, targetType, lookupSupplier);
if(gi == null) {
gi = getSamTypeConverter(sourceType, targetType, lookupSupplier);
}
@ -128,13 +130,13 @@ final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTyp
* @return a guarded invocation that converts from the source type to the target type.
* @throws Exception if something goes wrong
*/
private static GuardedInvocation convertToTypeNoCast(final Class<?> sourceType, final Class<?> targetType) throws Exception {
private static GuardedInvocation convertToTypeNoCast(final Class<?> sourceType, final Class<?> targetType, final Supplier<MethodHandles.Lookup> lookupSupplier) throws Exception {
final MethodHandle mh = JavaArgumentConverters.getConverter(targetType);
if (mh != null) {
return new GuardedInvocation(mh, canLinkTypeStatic(sourceType) ? null : IS_NASHORN_OR_UNDEFINED_TYPE);
}
final GuardedInvocation arrayConverter = getArrayConverter(sourceType, targetType);
final GuardedInvocation arrayConverter = getArrayConverter(sourceType, targetType, lookupSupplier);
if(arrayConverter != null) {
return arrayConverter;
}
@ -183,7 +185,7 @@ final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTyp
* either the source type is neither NativeArray, nor a superclass of it, or if the target type is not an array
* type, List, Queue, Deque, or Collection.
*/
private static GuardedInvocation getArrayConverter(final Class<?> sourceType, final Class<?> targetType) {
private static GuardedInvocation getArrayConverter(final Class<?> sourceType, final Class<?> targetType, final Supplier<MethodHandles.Lookup> lookupSupplier) {
final boolean isSourceTypeNativeArray = sourceType == NativeArray.class;
// If source type is more generic than NativeArray class, we'll need to use a guard
final boolean isSourceTypeGeneric = !isSourceTypeNativeArray && sourceType.isAssignableFrom(NativeArray.class);
@ -191,7 +193,25 @@ final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTyp
if (isSourceTypeNativeArray || isSourceTypeGeneric) {
final MethodHandle guard = isSourceTypeGeneric ? IS_NATIVE_ARRAY : null;
if(targetType.isArray()) {
return new GuardedInvocation(ARRAY_CONVERTERS.get(targetType), guard);
final MethodHandle mh = ARRAY_CONVERTERS.get(targetType);
final MethodHandle mhWithLookup;
if (mh.type().parameterCount() == 2) {
assert mh.type().parameterType(1) == SecureLookupSupplier.class;
// We enter this branch when the array's ultimate component
// type is a SAM type; we use a handle to JSType.toJavaArrayWithLookup
// for these in the converter MH and must bind it here with
// a secure supplier for the current lookup. By retrieving
// the lookup, we'll also (correctly) inform the type
// converter that this array converter is lookup specific.
// We then need to wrap the returned lookup into a
// new SecureLookupSupplier in order to bind it to the
// JSType.toJavaArrayWithLookup() parameter.
mhWithLookup = MH.insertArguments(mh, 1,
new SecureLookupSupplier(getCurrentLookup(lookupSupplier)));
} else {
mhWithLookup = mh;
}
return new GuardedInvocation(mhWithLookup, guard);
} else if(targetType == List.class) {
return new GuardedInvocation(TO_LIST, guard);
} else if(targetType == Deque.class) {
@ -207,8 +227,24 @@ final class NashornLinker implements TypeBasedGuardingDynamicLinker, GuardingTyp
private static MethodHandle createArrayConverter(final Class<?> type) {
assert type.isArray();
final MethodHandle converter = MH.insertArguments(JSType.TO_JAVA_ARRAY.methodHandle(), 1, type.getComponentType());
return MH.asType(converter, converter.type().changeReturnType(type));
final Class<?> componentType = type.getComponentType();
final Call converterCall;
// Is the ultimate component type of this array a SAM type?
if (isComponentTypeAutoConvertibleFromFunction(componentType)) {
converterCall = JSType.TO_JAVA_ARRAY_WITH_LOOKUP;
} else {
converterCall = JSType.TO_JAVA_ARRAY;
}
final MethodHandle typeBoundConverter = MH.insertArguments(converterCall.methodHandle(), 1, componentType);
return MH.asType(typeBoundConverter, typeBoundConverter.type().changeReturnType(type));
}
private static boolean isComponentTypeAutoConvertibleFromFunction(final Class<?> targetType) {
if (targetType.isArray()) {
return isComponentTypeAutoConvertibleFromFunction(targetType.getComponentType());
}
return isAutoConvertibleFromFunction(targetType);
}
private static GuardedInvocation getMirrorConverter(final Class<?> sourceType, final Class<?> targetType) {

@ -0,0 +1,63 @@
/*
* Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* JDK-8150218: Autoconversion SAM adapters sometimes don't get privileges
*
* @test
* @run
*/
function f() {
java.lang.System.getProperty("user.dir")
}
java.security.AccessController.doPrivileged(new java.security.PrivilegedAction(function () {
// Control: this used to work even before this improvement
new java.lang.Runnable(f).run()
// SAM type explicitly created through an array needs to get the right permissions too
Java.to([f], Java.type("java.lang.Runnable[]"))[0].run()
// Even when more deeply nested
Java.to([[[f]]], Java.type("java.lang.Runnable[][][]"))[0][0][0].run()
var rt = new (Java.type("jdk.dynalink.test.ArrayRunnableTest"))
var n = "runnables"
// Explicit array passed to vararg setter chosen at run time
rt[n] = [f]
rt.firstRunnable.run()
// Automatically packed one-element array passed to vararg setter chosen at run time
rt[n] = f
rt.firstRunnable.run()
// Explicit array passed to vararg method overload chosen at run time
rt.setRunnablesOverloaded([f])
rt.firstRunnable.run()
// Automatically packed one-element array passed to vararg method overload chosen at run time
rt.setRunnablesOverloaded(f)
rt.firstRunnable.run()
}))

@ -0,0 +1,45 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.dynalink.test;
public class ArrayRunnableTest {
private Runnable[] r;
public void setRunnables(final Runnable... r) {
this.r = r;
}
public Runnable getFirstRunnable() {
return r[0];
}
public void setRunnablesOverloaded(final Runnable... r) {
this.r = r;
}
public void setRunnablesOverloaded(final Object... r) {
throw new UnsupportedOperationException();
}
}