8010946: AccessControl.doPrivileged is broken when called from js script
Reviewed-by: jlaskey, sundar
This commit is contained in:
parent
6dfb638284
commit
92bcfea39a
nashorn
make
src/jdk
internal/dynalink
beans
AbstractJavaLinker.javaApplicableOverloadedMethods.javaCallerSensitiveDetector.javaCallerSensitiveDynamicMethod.javaClassString.javaDynamicMethod.javaDynamicMethodLinker.javaFacetIntrospector.javaMaximallySpecific.javaOverloadedDynamicMethod.javaOverloadedMethod.javaSimpleDynamicMethod.javaSingleDynamicMethod.javaStaticClassIntrospector.javaStaticClassLinker.java
support
nashorn/internal/runtime/linker
test/script/basic
@ -235,44 +235,31 @@
|
||||
</target>
|
||||
|
||||
<target name="generate-policy-file" depends="prepare">
|
||||
<!-- Generating nashorn.policy file -->
|
||||
<echo file="${build.dir}/nashorn.policy">
|
||||
|
||||
<!-- nashorn internal tests jar requires AllPermission -->
|
||||
<echo message="grant codeBase "file:/${basedir}/${nashorn.internal.tests.jar}" {" file="${build.dir}/nashorn.policy"/>
|
||||
<echo message="" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message=" permission java.security.AllPermission;" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="};" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
grant codeBase "file:/${basedir}/${nashorn.internal.tests.jar}" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
<!-- TestNG framework jar needs AllPermission -->
|
||||
<echo message="grant codeBase "file:/${basedir}/${file.reference.testng.jar}" {" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message=" permission java.security.AllPermission;" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="};" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
grant codeBase "file:/${basedir}/${file.reference.testng.jar}" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
<!-- AllPermission to test/script/trusted tests -->
|
||||
<echo message="grant codeBase "file:/${basedir}/test/script/trusted/*" {" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message=" permission java.security.AllPermission;" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="};" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
grant codeBase "file:/${basedir}/test/script/trusted/*" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
<echo message="grant codeBase "file:/${basedir}/test/script/basic/*" {" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<!-- test/script/basic .js scripts load other script tests -->
|
||||
<echo message=" permission java.io.FilePermission "${basedir}/test/script/-", "read";" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message=" permission java.io.FilePermission "user.dir", "read";" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message=" permission java.util.PropertyPermission "user.dir", "read";" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<!-- test/script/basic .js scripts can read nashorn.test.* properties -->
|
||||
<echo message=" permission java.util.PropertyPermission "nashorn.test.*", "read";" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="};" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
<echo message="" file="${build.dir}/nashorn.policy" append="true"/>
|
||||
grant codeBase "file:/${basedir}/test/script/basic/*" {
|
||||
permission java.io.FilePermission "${basedir}/test/script/-", "read";
|
||||
permission java.io.FilePermission "$${user.dir}", "read";
|
||||
permission java.util.PropertyPermission "user.dir", "read";
|
||||
permission java.util.PropertyPermission "nashorn.test.*", "read";
|
||||
};
|
||||
|
||||
grant codeBase "file:/${basedir}/test/script/basic/JDK-8010946-privileged.js" {
|
||||
permission java.util.PropertyPermission "java.security.policy", "read";
|
||||
};
|
||||
</echo>
|
||||
|
||||
<replace file="${build.dir}/nashorn.policy"><replacetoken>\</replacetoken><replacevalue>/</replacevalue></replace> <!--hack for Windows - to make URLs with normal path separators -->
|
||||
<replace file="${build.dir}/nashorn.policy"><replacetoken>//</replacetoken><replacevalue>/</replacevalue></replace> <!--hack for Unix - to avoid leading // in URLs -->
|
||||
|
@ -86,7 +86,10 @@ package jdk.internal.dynalink.beans;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.HashMap;
|
||||
@ -109,10 +112,11 @@ import jdk.internal.dynalink.support.Lookup;
|
||||
* @author Attila Szegedi
|
||||
*/
|
||||
abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||
|
||||
final Class<?> clazz;
|
||||
private final MethodHandle classGuard;
|
||||
private final MethodHandle assignableGuard;
|
||||
private final Map<String, AnnotatedMethodHandle> propertyGetters = new HashMap<>();
|
||||
private final Map<String, AnnotatedDynamicMethod> propertyGetters = new HashMap<>();
|
||||
private final Map<String, DynamicMethod> propertySetters = new HashMap<>();
|
||||
private final Map<String, DynamicMethod> methods = new HashMap<>();
|
||||
|
||||
@ -129,22 +133,19 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||
// Add methods and properties
|
||||
for(Method method: introspector.getMethods()) {
|
||||
final String name = method.getName();
|
||||
final MethodHandle methodHandle = introspector.unreflect(method);
|
||||
// Add method
|
||||
addMember(name, methodHandle, methods);
|
||||
addMember(name, method, methods);
|
||||
// Add the method as a property getter and/or setter
|
||||
if(name.startsWith("get") && name.length() > 3 && method.getParameterTypes().length == 0) {
|
||||
// Property getter
|
||||
setPropertyGetter(decapitalize(name.substring(3)), introspector.unreflect(
|
||||
getMostGenericGetter(method)), ValidationType.INSTANCE_OF);
|
||||
setPropertyGetter(method, 3);
|
||||
} else if(name.startsWith("is") && name.length() > 2 && method.getParameterTypes().length == 0 &&
|
||||
method.getReturnType() == boolean.class) {
|
||||
// Boolean property getter
|
||||
setPropertyGetter(decapitalize(name.substring(2)), introspector.unreflect(
|
||||
getMostGenericGetter(method)), ValidationType.INSTANCE_OF);
|
||||
setPropertyGetter(method, 2);
|
||||
} else if(name.startsWith("set") && name.length() > 3 && method.getParameterTypes().length == 1) {
|
||||
// Property setter
|
||||
addMember(decapitalize(name.substring(3)), methodHandle, propertySetters);
|
||||
addMember(decapitalize(name.substring(3)), method, propertySetters);
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,7 +157,8 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||
setPropertyGetter(name, introspector.unreflectGetter(field), ValidationType.EXACT_CLASS);
|
||||
}
|
||||
if(!(Modifier.isFinal(field.getModifiers()) || propertySetters.containsKey(name))) {
|
||||
addMember(name, introspector.unreflectSetter(field), propertySetters);
|
||||
addMember(name, new SimpleDynamicMethod(introspector.unreflectSetter(field), clazz, name),
|
||||
propertySetters);
|
||||
}
|
||||
}
|
||||
|
||||
@ -192,38 +194,119 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||
|
||||
abstract FacetIntrospector createFacetIntrospector();
|
||||
|
||||
void setPropertyGetter(String name, MethodHandle handle, ValidationType validationType) {
|
||||
propertyGetters.put(name, new AnnotatedMethodHandle(handle, validationType));
|
||||
/**
|
||||
* Sets the specified dynamic method to be the property getter for the specified property. Note that you can only
|
||||
* use this when you're certain that the method handle does not belong to a caller-sensitive method. For properties
|
||||
* that are caller-sensitive, you must use {@link #setPropertyGetter(String, SingleDynamicMethod, ValidationType)}
|
||||
* instead.
|
||||
* @param name name of the property
|
||||
* @param handle the method handle that implements the property getter
|
||||
* @param validationType the validation type for the property
|
||||
*/
|
||||
private void setPropertyGetter(String name, SingleDynamicMethod handle, ValidationType validationType) {
|
||||
propertyGetters.put(name, new AnnotatedDynamicMethod(handle, validationType));
|
||||
}
|
||||
|
||||
private void addMember(String name, MethodHandle mh, Map<String, DynamicMethod> methodMap) {
|
||||
/**
|
||||
* Sets the specified reflective method to be the property getter for the specified property.
|
||||
* @param getter the getter method
|
||||
* @param prefixLen the getter prefix in the method name; should be 3 for getter names starting with "get" and 2 for
|
||||
* names starting with "is".
|
||||
*/
|
||||
private void setPropertyGetter(Method getter, int prefixLen) {
|
||||
setPropertyGetter(decapitalize(getter.getName().substring(prefixLen)), createDynamicMethod(
|
||||
getMostGenericGetter(getter)), ValidationType.INSTANCE_OF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the specified method handle to be the property getter for the specified property. Note that you can only
|
||||
* use this when you're certain that the method handle does not belong to a caller-sensitive method. For properties
|
||||
* that are caller-sensitive, you must use {@link #setPropertyGetter(String, SingleDynamicMethod, ValidationType)}
|
||||
* instead.
|
||||
* @param name name of the property
|
||||
* @param handle the method handle that implements the property getter
|
||||
* @param validationType the validation type for the property
|
||||
*/
|
||||
void setPropertyGetter(String name, MethodHandle handle, ValidationType validationType) {
|
||||
setPropertyGetter(name, new SimpleDynamicMethod(handle, clazz, name), validationType);
|
||||
}
|
||||
|
||||
private void addMember(String name, AccessibleObject ao, Map<String, DynamicMethod> methodMap) {
|
||||
addMember(name, createDynamicMethod(ao), methodMap);
|
||||
}
|
||||
|
||||
private void addMember(String name, SingleDynamicMethod method, Map<String, DynamicMethod> methodMap) {
|
||||
final DynamicMethod existingMethod = methodMap.get(name);
|
||||
final DynamicMethod newMethod = addMember(mh, existingMethod, clazz, name);
|
||||
final DynamicMethod newMethod = mergeMethods(method, existingMethod, clazz, name);
|
||||
if(newMethod != existingMethod) {
|
||||
methodMap.put(name, newMethod);
|
||||
}
|
||||
}
|
||||
|
||||
static DynamicMethod createDynamicMethod(Iterable<MethodHandle> methodHandles, Class<?> clazz, String name) {
|
||||
/**
|
||||
* Given one or more reflective methods or constructors, creates a dynamic method that represents them all. The
|
||||
* methods should represent all overloads of the same name (or all constructors of the class).
|
||||
* @param members the reflective members
|
||||
* @param clazz the class declaring the reflective members
|
||||
* @param name the common name of the reflective members.
|
||||
* @return a dynamic method representing all the specified reflective members.
|
||||
*/
|
||||
static DynamicMethod createDynamicMethod(Iterable<? extends AccessibleObject> members, Class<?> clazz, String name) {
|
||||
DynamicMethod dynMethod = null;
|
||||
for(MethodHandle methodHandle: methodHandles) {
|
||||
dynMethod = addMember(methodHandle, dynMethod, clazz, name);
|
||||
for(AccessibleObject method: members) {
|
||||
dynMethod = mergeMethods(createDynamicMethod(method), dynMethod, clazz, name);
|
||||
}
|
||||
return dynMethod;
|
||||
}
|
||||
|
||||
private static DynamicMethod addMember(MethodHandle mh, DynamicMethod existing, Class<?> clazz, String name) {
|
||||
/**
|
||||
* Given a reflective method or a constructor, creates a dynamic method that represents it. This method will
|
||||
* distinguish between caller sensitive and ordinary methods/constructors, and create appropriate caller sensitive
|
||||
* dynamic method when needed.
|
||||
* @param m the reflective member
|
||||
* @return the single dynamic method representing the reflective member
|
||||
*/
|
||||
private static SingleDynamicMethod createDynamicMethod(AccessibleObject m) {
|
||||
if(CallerSensitiveDetector.isCallerSensitive(m)) {
|
||||
return new CallerSensitiveDynamicMethod(m);
|
||||
}
|
||||
final Member member = (Member)m;
|
||||
return new SimpleDynamicMethod(unreflectSafely(m), member.getDeclaringClass(), member.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Unreflects a method handle from a Method or a Constructor using safe (zero-privilege) unreflection. Should be
|
||||
* only used for methods and constructors that are not caller sensitive. If a caller sensitive method were
|
||||
* unreflected through this mechanism, it would not be a security issue, but would be bound to the zero-privilege
|
||||
* unreflector as its caller, and thus completely useless.
|
||||
* @param m the method or constructor
|
||||
* @return the method handle
|
||||
*/
|
||||
private static MethodHandle unreflectSafely(AccessibleObject m) {
|
||||
if(m instanceof Method) {
|
||||
final Method reflMethod = (Method)m;
|
||||
final MethodHandle handle = SafeUnreflector.unreflect(reflMethod);
|
||||
if(Modifier.isStatic(reflMethod.getModifiers())) {
|
||||
return StaticClassIntrospector.editStaticMethodHandle(handle);
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
return StaticClassIntrospector.editConstructorMethodHandle(SafeUnreflector.unreflectConstructor(
|
||||
(Constructor<?>)m));
|
||||
}
|
||||
|
||||
private static DynamicMethod mergeMethods(SingleDynamicMethod method, DynamicMethod existing, Class<?> clazz, String name) {
|
||||
if(existing == null) {
|
||||
return new SimpleDynamicMethod(mh, clazz, name);
|
||||
} else if(existing.contains(mh)) {
|
||||
return method;
|
||||
} else if(existing.contains(method)) {
|
||||
return existing;
|
||||
} else if(existing instanceof SimpleDynamicMethod) {
|
||||
} else if(existing instanceof SingleDynamicMethod) {
|
||||
final OverloadedDynamicMethod odm = new OverloadedDynamicMethod(clazz, name);
|
||||
odm.addMethod(((SimpleDynamicMethod)existing));
|
||||
odm.addMethod(mh);
|
||||
odm.addMethod(((SingleDynamicMethod)existing));
|
||||
odm.addMethod(method);
|
||||
return odm;
|
||||
} else if(existing instanceof OverloadedDynamicMethod) {
|
||||
((OverloadedDynamicMethod)existing).addMethod(mh);
|
||||
((OverloadedDynamicMethod)existing).addMethod(method);
|
||||
return existing;
|
||||
}
|
||||
throw new AssertionError();
|
||||
@ -296,7 +379,7 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||
private GuardedInvocation getCallPropWithThis(CallSiteDescriptor callSiteDescriptor, LinkerServices linkerServices) {
|
||||
switch(callSiteDescriptor.getNameTokenCount()) {
|
||||
case 3: {
|
||||
return createGuardedDynamicMethodInvocation(callSiteDescriptor.getMethodType(), linkerServices,
|
||||
return createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices,
|
||||
callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), methods);
|
||||
}
|
||||
default: {
|
||||
@ -305,16 +388,16 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||
}
|
||||
}
|
||||
|
||||
private GuardedInvocation createGuardedDynamicMethodInvocation(MethodType callSiteType,
|
||||
private GuardedInvocation createGuardedDynamicMethodInvocation(CallSiteDescriptor callSiteDescriptor,
|
||||
LinkerServices linkerServices, String methodName, Map<String, DynamicMethod> methodMap){
|
||||
final MethodHandle inv = getDynamicMethodInvocation(callSiteType, linkerServices, methodName, methodMap);
|
||||
return inv == null ? null : new GuardedInvocation(inv, getClassGuard(callSiteType));
|
||||
final MethodHandle inv = getDynamicMethodInvocation(callSiteDescriptor, linkerServices, methodName, methodMap);
|
||||
return inv == null ? null : new GuardedInvocation(inv, getClassGuard(callSiteDescriptor.getMethodType()));
|
||||
}
|
||||
|
||||
private static MethodHandle getDynamicMethodInvocation(MethodType callSiteType, LinkerServices linkerServices,
|
||||
String methodName, Map<String, DynamicMethod> methodMap) {
|
||||
private static MethodHandle getDynamicMethodInvocation(CallSiteDescriptor callSiteDescriptor,
|
||||
LinkerServices linkerServices, String methodName, Map<String, DynamicMethod> methodMap) {
|
||||
final DynamicMethod dynaMethod = getDynamicMethod(methodName, methodMap);
|
||||
return dynaMethod != null ? dynaMethod.getInvocation(callSiteType, linkerServices) : null;
|
||||
return dynaMethod != null ? dynaMethod.getInvocation(callSiteDescriptor, linkerServices) : null;
|
||||
}
|
||||
|
||||
private static DynamicMethod getDynamicMethod(String methodName, Map<String, DynamicMethod> methodMap) {
|
||||
@ -322,13 +405,13 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||
return dynaMethod != null ? dynaMethod : getExplicitSignatureDynamicMethod(methodName, methodMap);
|
||||
}
|
||||
|
||||
private static SimpleDynamicMethod getExplicitSignatureDynamicMethod(String methodName,
|
||||
private static SingleDynamicMethod getExplicitSignatureDynamicMethod(String methodName,
|
||||
Map<String, DynamicMethod> methodsMap) {
|
||||
// What's below is meant to support the "name(type, type, ...)" syntax that programmers can use in a method name
|
||||
// to manually pin down an exact overloaded variant. This is not usually required, as the overloaded method
|
||||
// resolution works correctly in almost every situation. However, in presence of many language-specific
|
||||
// conversions with a radically dynamic language, most overloaded methods will end up being constantly selected
|
||||
// at invocation time, so a programmer knowledgable of the situation might choose to pin down an exact overload
|
||||
// at invocation time, so a programmer knowledgeable of the situation might choose to pin down an exact overload
|
||||
// for performance reasons.
|
||||
|
||||
// Is the method name lexically of the form "name(types)"?
|
||||
@ -377,8 +460,8 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||
final MethodType setterType = type.dropParameterTypes(1, 2);
|
||||
// Bind property setter handle to the expected setter type and linker services. Type is
|
||||
// MethodHandle(Object, String, Object)
|
||||
final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0, setterType,
|
||||
linkerServices);
|
||||
final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0,
|
||||
CallSiteDescriptorFactory.dropParameterTypes(callSiteDescriptor, 1, 2), linkerServices);
|
||||
|
||||
// Cast getter to MethodHandle(O, N, V)
|
||||
final MethodHandle typedGetter = linkerServices.asType(boundGetter, type.changeReturnType(
|
||||
@ -415,9 +498,8 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||
case 3: {
|
||||
// Must have two arguments: target object and property value
|
||||
assertParameterCount(callSiteDescriptor, 2);
|
||||
final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor.getMethodType(),
|
||||
linkerServices, callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND),
|
||||
propertySetters);
|
||||
final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices,
|
||||
callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), propertySetters);
|
||||
// If we have a property setter with this name, this composite operation will always stop here
|
||||
if(gi != null) {
|
||||
return new GuardedInvocationComponent(gi, clazz, ValidationType.EXACT_CLASS);
|
||||
@ -435,14 +517,13 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||
|
||||
private static final Lookup privateLookup = new Lookup(MethodHandles.lookup());
|
||||
|
||||
private static final MethodHandle IS_ANNOTATED_HANDLE_NOT_NULL = Guards.isNotNull().asType(MethodType.methodType(
|
||||
boolean.class, AnnotatedMethodHandle.class));
|
||||
private static final MethodHandle CONSTANT_NULL_DROP_ANNOTATED_HANDLE = MethodHandles.dropArguments(
|
||||
MethodHandles.constant(Object.class, null), 0, AnnotatedMethodHandle.class);
|
||||
private static final MethodHandle GET_ANNOTATED_HANDLE = privateLookup.findGetter(AnnotatedMethodHandle.class,
|
||||
"handle", MethodHandle.class);
|
||||
private static final MethodHandle GENERIC_PROPERTY_GETTER_HANDLER_INVOKER = MethodHandles.filterArguments(
|
||||
MethodHandles.invoker(MethodType.methodType(Object.class, Object.class)), 0, GET_ANNOTATED_HANDLE);
|
||||
private static final MethodHandle IS_ANNOTATED_METHOD_NOT_NULL = Guards.isNotNull().asType(MethodType.methodType(
|
||||
boolean.class, AnnotatedDynamicMethod.class));
|
||||
private static final MethodHandle CONSTANT_NULL_DROP_ANNOTATED_METHOD = MethodHandles.dropArguments(
|
||||
MethodHandles.constant(Object.class, null), 0, AnnotatedDynamicMethod.class);
|
||||
private static final MethodHandle GET_ANNOTATED_METHOD = privateLookup.findVirtual(AnnotatedDynamicMethod.class,
|
||||
"getTarget", MethodType.methodType(MethodHandle.class, MethodHandles.Lookup.class));
|
||||
private static final MethodHandle GETTER_INVOKER = MethodHandles.invoker(MethodType.methodType(Object.class, Object.class));
|
||||
|
||||
private GuardedInvocationComponent getPropertyGetter(CallSiteDescriptor callSiteDescriptor,
|
||||
LinkerServices linkerServices, List<String> ops) throws Exception {
|
||||
@ -455,16 +536,20 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||
// What's below is basically:
|
||||
// foldArguments(guardWithTest(isNotNull, invoke(get_handle), null|nextComponent.invocation), get_getter_handle)
|
||||
// only with a bunch of method signature adjustments. Basically, retrieve method getter
|
||||
// AnnotatedMethodHandle; if it is non-null, invoke its "handle" field, otherwise either return null,
|
||||
// AnnotatedDynamicMethod; if it is non-null, invoke its "handle" field, otherwise either return null,
|
||||
// or delegate to next component's invocation.
|
||||
|
||||
final MethodHandle typedGetter = linkerServices.asType(getPropertyGetterHandle, type.changeReturnType(
|
||||
AnnotatedMethodHandle.class));
|
||||
// Object(AnnotatedMethodHandle, Object)->R(AnnotatedMethodHandle, T0)
|
||||
final MethodHandle invokeHandleTyped = linkerServices.asType(GENERIC_PROPERTY_GETTER_HANDLER_INVOKER,
|
||||
MethodType.methodType(type.returnType(), AnnotatedMethodHandle.class, type.parameterType(0)));
|
||||
AnnotatedDynamicMethod.class));
|
||||
final MethodHandle callSiteBoundMethodGetter = MethodHandles.insertArguments(
|
||||
GET_ANNOTATED_METHOD, 1, callSiteDescriptor.getLookup());
|
||||
final MethodHandle callSiteBoundInvoker = MethodHandles.filterArguments(GETTER_INVOKER, 0,
|
||||
callSiteBoundMethodGetter);
|
||||
// Object(AnnotatedDynamicMethod, Object)->R(AnnotatedDynamicMethod, T0)
|
||||
final MethodHandle invokeHandleTyped = linkerServices.asType(callSiteBoundInvoker,
|
||||
MethodType.methodType(type.returnType(), AnnotatedDynamicMethod.class, type.parameterType(0)));
|
||||
// Since it's in the target of a fold, drop the unnecessary second argument
|
||||
// R(AnnotatedMethodHandle, T0)->R(AnnotatedMethodHandle, T0, T1)
|
||||
// R(AnnotatedDynamicMethod, T0)->R(AnnotatedDynamicMethod, T0, T1)
|
||||
final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandleTyped, 2,
|
||||
type.parameterType(1));
|
||||
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
|
||||
@ -472,19 +557,19 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||
|
||||
final MethodHandle fallbackFolded;
|
||||
if(nextComponent == null) {
|
||||
// Object(AnnotatedMethodHandle)->R(AnnotatedMethodHandle, T0, T1); returns constant null
|
||||
fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_ANNOTATED_HANDLE, 1,
|
||||
type.parameterList()).asType(type.insertParameterTypes(0, AnnotatedMethodHandle.class));
|
||||
// Object(AnnotatedDynamicMethod)->R(AnnotatedDynamicMethod, T0, T1); returns constant null
|
||||
fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_ANNOTATED_METHOD, 1,
|
||||
type.parameterList()).asType(type.insertParameterTypes(0, AnnotatedDynamicMethod.class));
|
||||
} else {
|
||||
// R(T0, T1)->R(AnnotatedMethodHAndle, T0, T1); adapts the next component's invocation to drop the
|
||||
// R(T0, T1)->R(AnnotatedDynamicMethod, T0, T1); adapts the next component's invocation to drop the
|
||||
// extra argument resulting from fold
|
||||
fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(),
|
||||
0, AnnotatedMethodHandle.class);
|
||||
0, AnnotatedDynamicMethod.class);
|
||||
}
|
||||
|
||||
// fold(R(AnnotatedMethodHandle, T0, T1), AnnotatedMethodHandle(T0, T1))
|
||||
// fold(R(AnnotatedDynamicMethod, T0, T1), AnnotatedDynamicMethod(T0, T1))
|
||||
final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
|
||||
IS_ANNOTATED_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
|
||||
IS_ANNOTATED_METHOD_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
|
||||
if(nextComponent == null) {
|
||||
return getClassGuardedInvocationComponent(compositeGetter, type);
|
||||
}
|
||||
@ -494,13 +579,13 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||
// Must have exactly one argument: receiver
|
||||
assertParameterCount(callSiteDescriptor, 1);
|
||||
// Fixed name
|
||||
final AnnotatedMethodHandle annGetter = propertyGetters.get(callSiteDescriptor.getNameToken(
|
||||
final AnnotatedDynamicMethod annGetter = propertyGetters.get(callSiteDescriptor.getNameToken(
|
||||
CallSiteDescriptor.NAME_OPERAND));
|
||||
if(annGetter == null) {
|
||||
// We have no such property, always delegate to the next component operation
|
||||
return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops);
|
||||
}
|
||||
final MethodHandle getter = annGetter.handle;
|
||||
final MethodHandle getter = annGetter.getInvocation(callSiteDescriptor, linkerServices);
|
||||
// NOTE: since property getters (not field getters!) are no-arg, we don't have to worry about them being
|
||||
// overloaded in a subclass. Therefore, we can discover the most abstract superclass that has the
|
||||
// method, and use that as the guard with Guards.isInstance() for a more stably linked call site. If
|
||||
@ -508,6 +593,7 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||
// NOTE: No delegation to the next component operation if we have a property with this name, even if its
|
||||
// value is null.
|
||||
final ValidationType validationType = annGetter.validationType;
|
||||
// TODO: we aren't using the type that declares the most generic getter here!
|
||||
return new GuardedInvocationComponent(linkerServices.asType(getter, type), getGuard(validationType,
|
||||
type), clazz, validationType);
|
||||
}
|
||||
@ -623,14 +709,15 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||
// args are dropped; this makes handles with first three args conform to "Object, String, Object" though, which is
|
||||
// a typical property setter with variable name signature (target, name, value).
|
||||
private static final MethodHandle GET_PROPERTY_SETTER_HANDLE = MethodHandles.dropArguments(MethodHandles.dropArguments(
|
||||
privateLookup.findOwnSpecial("getPropertySetterHandle", MethodHandle.class, MethodType.class,
|
||||
privateLookup.findOwnSpecial("getPropertySetterHandle", MethodHandle.class, CallSiteDescriptor.class,
|
||||
LinkerServices.class, Object.class), 3, Object.class), 5, Object.class);
|
||||
// Type is MethodHandle(MethodType, LinkerServices, Object, String, Object)
|
||||
private final MethodHandle getPropertySetterHandle = GET_PROPERTY_SETTER_HANDLE.bindTo(this);
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private MethodHandle getPropertySetterHandle(MethodType setterType, LinkerServices linkerServices, Object id) {
|
||||
return getDynamicMethodInvocation(setterType, linkerServices, String.valueOf(id), propertySetters);
|
||||
private MethodHandle getPropertySetterHandle(CallSiteDescriptor setterDescriptor, LinkerServices linkerServices,
|
||||
Object id) {
|
||||
return getDynamicMethodInvocation(setterDescriptor, linkerServices, String.valueOf(id), propertySetters);
|
||||
}
|
||||
|
||||
private static MethodHandle GET_DYNAMIC_METHOD = MethodHandles.dropArguments(privateLookup.findOwnSpecial(
|
||||
@ -689,13 +776,24 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final class AnnotatedMethodHandle {
|
||||
final MethodHandle handle;
|
||||
private static final class AnnotatedDynamicMethod {
|
||||
private final SingleDynamicMethod method;
|
||||
/*private*/ final ValidationType validationType;
|
||||
|
||||
AnnotatedMethodHandle(MethodHandle handle, ValidationType validationType) {
|
||||
this.handle = handle;
|
||||
AnnotatedDynamicMethod(SingleDynamicMethod method, ValidationType validationType) {
|
||||
this.method = method;
|
||||
this.validationType = validationType;
|
||||
}
|
||||
|
||||
MethodHandle getInvocation(CallSiteDescriptor callSiteDescriptor, LinkerServices linkerServices) {
|
||||
return method.getInvocation(callSiteDescriptor, linkerServices);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
MethodHandle getTarget(MethodHandles.Lookup lookup) {
|
||||
MethodHandle inv = method.getTarget(lookup);
|
||||
assert inv != null;
|
||||
return inv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -83,7 +83,6 @@
|
||||
|
||||
package jdk.internal.dynalink.beans;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
@ -95,7 +94,7 @@ import jdk.internal.dynalink.support.TypeUtilities;
|
||||
* @author Attila Szegedi
|
||||
*/
|
||||
class ApplicableOverloadedMethods {
|
||||
private final List<MethodHandle> methods;
|
||||
private final List<SingleDynamicMethod> methods;
|
||||
private final boolean varArgs;
|
||||
|
||||
/**
|
||||
@ -106,10 +105,10 @@ class ApplicableOverloadedMethods {
|
||||
* @param test applicability test. One of {@link #APPLICABLE_BY_SUBTYPING},
|
||||
* {@link #APPLICABLE_BY_METHOD_INVOCATION_CONVERSION}, or {@link #APPLICABLE_BY_VARIABLE_ARITY}.
|
||||
*/
|
||||
ApplicableOverloadedMethods(final List<MethodHandle> methods, final MethodType callSiteType,
|
||||
ApplicableOverloadedMethods(final List<SingleDynamicMethod> methods, final MethodType callSiteType,
|
||||
final ApplicabilityTest test) {
|
||||
this.methods = new LinkedList<>();
|
||||
for(MethodHandle m: methods) {
|
||||
for(SingleDynamicMethod m: methods) {
|
||||
if(test.isApplicable(callSiteType, m)) {
|
||||
this.methods.add(m);
|
||||
}
|
||||
@ -122,7 +121,7 @@ class ApplicableOverloadedMethods {
|
||||
*
|
||||
* @return list of all methods.
|
||||
*/
|
||||
List<MethodHandle> getMethods() {
|
||||
List<SingleDynamicMethod> getMethods() {
|
||||
return methods;
|
||||
}
|
||||
|
||||
@ -131,12 +130,12 @@ class ApplicableOverloadedMethods {
|
||||
*
|
||||
* @return a list of maximally specific methods.
|
||||
*/
|
||||
List<MethodHandle> findMaximallySpecificMethods() {
|
||||
List<SingleDynamicMethod> findMaximallySpecificMethods() {
|
||||
return MaximallySpecific.getMaximallySpecificMethods(methods, varArgs);
|
||||
}
|
||||
|
||||
abstract static class ApplicabilityTest {
|
||||
abstract boolean isApplicable(MethodType callSiteType, MethodHandle method);
|
||||
abstract boolean isApplicable(MethodType callSiteType, SingleDynamicMethod method);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -144,8 +143,8 @@ class ApplicableOverloadedMethods {
|
||||
*/
|
||||
static final ApplicabilityTest APPLICABLE_BY_SUBTYPING = new ApplicabilityTest() {
|
||||
@Override
|
||||
boolean isApplicable(MethodType callSiteType, MethodHandle method) {
|
||||
final MethodType methodType = method.type();
|
||||
boolean isApplicable(MethodType callSiteType, SingleDynamicMethod method) {
|
||||
final MethodType methodType = method.getMethodType();
|
||||
final int methodArity = methodType.parameterCount();
|
||||
if(methodArity != callSiteType.parameterCount()) {
|
||||
return false;
|
||||
@ -166,8 +165,8 @@ class ApplicableOverloadedMethods {
|
||||
*/
|
||||
static final ApplicabilityTest APPLICABLE_BY_METHOD_INVOCATION_CONVERSION = new ApplicabilityTest() {
|
||||
@Override
|
||||
boolean isApplicable(MethodType callSiteType, MethodHandle method) {
|
||||
final MethodType methodType = method.type();
|
||||
boolean isApplicable(MethodType callSiteType, SingleDynamicMethod method) {
|
||||
final MethodType methodType = method.getMethodType();
|
||||
final int methodArity = methodType.parameterCount();
|
||||
if(methodArity != callSiteType.parameterCount()) {
|
||||
return false;
|
||||
@ -189,11 +188,11 @@ class ApplicableOverloadedMethods {
|
||||
*/
|
||||
static final ApplicabilityTest APPLICABLE_BY_VARIABLE_ARITY = new ApplicabilityTest() {
|
||||
@Override
|
||||
boolean isApplicable(MethodType callSiteType, MethodHandle method) {
|
||||
if(!method.isVarargsCollector()) {
|
||||
boolean isApplicable(MethodType callSiteType, SingleDynamicMethod method) {
|
||||
if(!method.isVarArgs()) {
|
||||
return false;
|
||||
}
|
||||
final MethodType methodType = method.type();
|
||||
final MethodType methodType = method.getMethodType();
|
||||
final int methodArity = methodType.parameterCount();
|
||||
final int fixArity = methodArity - 1;
|
||||
final int callSiteArity = callSiteType.parameterCount();
|
||||
|
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file, and Oracle licenses the original version of this file under the BSD
|
||||
* license:
|
||||
*/
|
||||
/*
|
||||
Copyright 2009-2013 Attila Szegedi
|
||||
|
||||
Licensed under both the Apache License, Version 2.0 (the "Apache License")
|
||||
and 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.
|
||||
|
||||
If you choose to use this file in compliance with the Apache License, the
|
||||
following notice applies to you:
|
||||
|
||||
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 the License for the specific language governing
|
||||
permissions and limitations under the License.
|
||||
|
||||
If you choose to use this file in compliance with the BSD License, the
|
||||
following notice applies to you:
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the names of
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
|
||||
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jdk.internal.dynalink.beans;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import sun.reflect.CallerSensitive;
|
||||
|
||||
/**
|
||||
* Utility class that determines if a method or constructor is caller sensitive. It actually encapsulates two different
|
||||
* strategies for determining caller sensitivity; a more robust one that works if Dynalink runs as code with access
|
||||
* to {@code sun.reflect} package, and an unprivileged one that is used when Dynalink doesn't have access to that
|
||||
* package. Note that even the unprivileged strategy is ordinarily robust, but it relies on the {@code toString} method
|
||||
* of the annotation. If an attacker were to use a different annotation to spoof the string representation of the
|
||||
* {@code CallerSensitive} annotation, they could designate their own methods as caller sensitive. This however does not
|
||||
* escalate privileges, only causes Dynalink to never cache method handles for such methods, so all it would do would
|
||||
* decrease the performance in linking such methods. In the opposite case when an attacker could trick Dynalink into not
|
||||
* recognizing genuine {@code CallerSensitive} annotations, Dynalink would treat caller sensitive methods as ordinary
|
||||
* methods, and would cache them bound to a zero-privilege delegate as the caller (just what Dynalink did before it
|
||||
* could handle caller-sensitive methods). That would practically render caller-sensitive methods exposed through
|
||||
* Dynalink unusable, but again, can not lead to any privilege escalations. Therefore, even the less robust unprivileged
|
||||
* strategy is safe; the worst thing a successful attack against it can achieve is slight reduction in Dynalink-exposed
|
||||
* functionality or performance.
|
||||
*/
|
||||
public class CallerSensitiveDetector {
|
||||
|
||||
private static final DetectionStrategy DETECTION_STRATEGY = getDetectionStrategy();
|
||||
|
||||
static boolean isCallerSensitive(AccessibleObject ao) {
|
||||
return DETECTION_STRATEGY.isCallerSensitive(ao);
|
||||
}
|
||||
|
||||
private static DetectionStrategy getDetectionStrategy() {
|
||||
try {
|
||||
return new PrivilegedDetectionStrategy();
|
||||
} catch(Throwable t) {
|
||||
return new UnprivilegedDetectionStrategy();
|
||||
}
|
||||
}
|
||||
|
||||
private abstract static class DetectionStrategy {
|
||||
abstract boolean isCallerSensitive(AccessibleObject ao);
|
||||
}
|
||||
|
||||
private static class PrivilegedDetectionStrategy extends DetectionStrategy {
|
||||
private static final Class<? extends Annotation> CALLER_SENSITIVE_ANNOTATION_CLASS = CallerSensitive.class;
|
||||
|
||||
@Override
|
||||
boolean isCallerSensitive(AccessibleObject ao) {
|
||||
return ao.getAnnotation(CALLER_SENSITIVE_ANNOTATION_CLASS) != null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class UnprivilegedDetectionStrategy extends DetectionStrategy {
|
||||
private static final String CALLER_SENSITIVE_ANNOTATION_STRING = "@sun.reflect.CallerSensitive()";
|
||||
|
||||
@Override
|
||||
boolean isCallerSensitive(AccessibleObject o) {
|
||||
for(Annotation a: o.getAnnotations()) {
|
||||
if(String.valueOf(a).equals(CALLER_SENSITIVE_ANNOTATION_STRING)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file, and Oracle licenses the original version of this file under the BSD
|
||||
* license:
|
||||
*/
|
||||
/*
|
||||
Copyright 2009-2013 Attila Szegedi
|
||||
|
||||
Licensed under both the Apache License, Version 2.0 (the "Apache License")
|
||||
and 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.
|
||||
|
||||
If you choose to use this file in compliance with the Apache License, the
|
||||
following notice applies to you:
|
||||
|
||||
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 the License for the specific language governing
|
||||
permissions and limitations under the License.
|
||||
|
||||
If you choose to use this file in compliance with the BSD License, the
|
||||
following notice applies to you:
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the names of
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
|
||||
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jdk.internal.dynalink.beans;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import jdk.internal.dynalink.support.Lookup;
|
||||
|
||||
/**
|
||||
* A dynamic method bound to exactly one Java method or constructor that is caller sensitive. Since the target method is
|
||||
* caller sensitive, it doesn't cache a method handle but rather uses the passed lookup object in
|
||||
* {@link #getTarget(java.lang.invoke.MethodHandles.Lookup)} to unreflect a method handle from the reflective member on
|
||||
* every request.
|
||||
*
|
||||
* @author Attila Szegedi
|
||||
*/
|
||||
class CallerSensitiveDynamicMethod extends SingleDynamicMethod {
|
||||
// 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
|
||||
private final AccessibleObject target;
|
||||
private final MethodType type;
|
||||
|
||||
public CallerSensitiveDynamicMethod(AccessibleObject target) {
|
||||
super(getName(target));
|
||||
this.target = target;
|
||||
this.type = getMethodType(target);
|
||||
}
|
||||
|
||||
private static String getName(AccessibleObject target) {
|
||||
final Member m = (Member)target;
|
||||
return getMethodNameWithSignature(getMethodType(target), getClassAndMethodName(m.getDeclaringClass(),
|
||||
m.getName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
MethodType getMethodType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
private static MethodType getMethodType(AccessibleObject ao) {
|
||||
final boolean isMethod = ao instanceof Method;
|
||||
final Class<?> rtype = isMethod ? ((Method)ao).getReturnType() : ((Constructor<?>)ao).getDeclaringClass();
|
||||
final Class<?>[] ptypes = isMethod ? ((Method)ao).getParameterTypes() : ((Constructor<?>)ao).getParameterTypes();
|
||||
final MethodType type = MethodType.methodType(rtype, ptypes);
|
||||
final Member m = (Member)ao;
|
||||
return type.insertParameterTypes(0,
|
||||
isMethod ?
|
||||
Modifier.isStatic(m.getModifiers()) ?
|
||||
Object.class :
|
||||
m.getDeclaringClass() :
|
||||
StaticClass.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isVarArgs() {
|
||||
return target instanceof Method ? ((Method)target).isVarArgs() : ((Constructor<?>)target).isVarArgs();
|
||||
}
|
||||
|
||||
@Override
|
||||
MethodHandle getTarget(MethodHandles.Lookup lookup) {
|
||||
if(target instanceof Method) {
|
||||
final MethodHandle mh = Lookup.unreflect(lookup, (Method)target);
|
||||
if(Modifier.isStatic(((Member)target).getModifiers())) {
|
||||
return StaticClassIntrospector.editStaticMethodHandle(mh);
|
||||
}
|
||||
return mh;
|
||||
}
|
||||
return StaticClassIntrospector.editConstructorMethodHandle(Lookup.unreflectConstructor(lookup,
|
||||
(Constructor<?>)target));
|
||||
}
|
||||
}
|
@ -155,8 +155,8 @@ final class ClassString {
|
||||
}
|
||||
|
||||
List<MethodHandle> getMaximallySpecifics(List<MethodHandle> methods, LinkerServices linkerServices, boolean varArg) {
|
||||
return MaximallySpecific.getMaximallySpecificMethods(getApplicables(methods, linkerServices, varArg), varArg,
|
||||
classes, linkerServices);
|
||||
return MaximallySpecific.getMaximallySpecificMethodHandles(getApplicables(methods, linkerServices, varArg),
|
||||
varArg, classes, linkerServices);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -84,8 +84,7 @@
|
||||
package jdk.internal.dynalink.beans;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.StringTokenizer;
|
||||
import jdk.internal.dynalink.CallSiteDescriptor;
|
||||
import jdk.internal.dynalink.linker.LinkerServices;
|
||||
|
||||
/**
|
||||
@ -116,45 +115,28 @@ abstract class DynamicMethod {
|
||||
* is a variable arguments (vararg) method, it will pack the extra arguments in an array before the invocation of
|
||||
* the underlying method if it is not already done.
|
||||
*
|
||||
* @param callSiteType the method type at a call site
|
||||
* @param callSiteDescriptor the descriptor of the call site
|
||||
* @param linkerServices linker services. Used for language-specific type conversions.
|
||||
* @return an invocation suitable for calling the method from the specified call site.
|
||||
*/
|
||||
abstract MethodHandle getInvocation(MethodType callSiteType, LinkerServices linkerServices);
|
||||
abstract MethodHandle getInvocation(CallSiteDescriptor callSiteDescriptor, LinkerServices linkerServices);
|
||||
|
||||
/**
|
||||
* Returns a simple dynamic method representing a single underlying Java method (possibly selected among several
|
||||
* Returns a single dynamic method representing a single underlying Java method (possibly selected among several
|
||||
* overloads) with formal parameter types exactly matching the passed signature.
|
||||
* @param paramTypes the comma-separated list of requested parameter type names. The names will match both
|
||||
* qualified and unqualified type names.
|
||||
* @return a simple dynamic method representing a single underlying Java method, or null if none of the Java methods
|
||||
* @return a single dynamic method representing a single underlying Java method, or null if none of the Java methods
|
||||
* behind this dynamic method exactly match the requested parameter types.
|
||||
*/
|
||||
abstract SimpleDynamicMethod getMethodForExactParamTypes(String paramTypes);
|
||||
abstract SingleDynamicMethod getMethodForExactParamTypes(String paramTypes);
|
||||
|
||||
/**
|
||||
* True if this dynamic method already contains a method handle with an identical signature as the passed in method
|
||||
* handle.
|
||||
* @param mh the method handle to check
|
||||
* @return true if it already contains an equivalent method handle.
|
||||
* True if this dynamic method already contains a method with an identical signature as the passed in method.
|
||||
* @param method the method to check
|
||||
* @return true if it already contains an equivalent method.
|
||||
*/
|
||||
abstract boolean contains(MethodHandle mh);
|
||||
|
||||
static boolean typeMatchesDescription(String paramTypes, MethodType type) {
|
||||
final StringTokenizer tok = new StringTokenizer(paramTypes, ", ");
|
||||
for(int i = 1; i < type.parameterCount(); ++i) { // i = 1 as we ignore the receiver
|
||||
if(!(tok.hasMoreTokens() && typeNameMatches(tok.nextToken(), type.parameterType(i)))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return !tok.hasMoreTokens();
|
||||
}
|
||||
|
||||
private static boolean typeNameMatches(String typeName, Class<?> type) {
|
||||
final int lastDot = typeName.lastIndexOf('.');
|
||||
final String fullTypeName = type.getCanonicalName();
|
||||
return lastDot != -1 && fullTypeName.endsWith(typeName.substring(lastDot)) || typeName.equals(fullTypeName);
|
||||
}
|
||||
abstract boolean contains(SingleDynamicMethod method);
|
||||
|
||||
static String getClassAndMethodName(Class<?> clazz, String name) {
|
||||
final String clazzName = clazz.getCanonicalName();
|
||||
|
@ -85,12 +85,12 @@ package jdk.internal.dynalink.beans;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import jdk.internal.dynalink.CallSiteDescriptor;
|
||||
import jdk.internal.dynalink.linker.GuardedInvocation;
|
||||
import jdk.internal.dynalink.linker.LinkRequest;
|
||||
import jdk.internal.dynalink.linker.LinkerServices;
|
||||
import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
|
||||
import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
|
||||
import jdk.internal.dynalink.support.Guards;
|
||||
|
||||
/**
|
||||
@ -110,19 +110,18 @@ class DynamicMethodLinker implements TypeBasedGuardingDynamicLinker {
|
||||
return null;
|
||||
}
|
||||
final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor();
|
||||
if(desc.getNameTokenCount() != 2 && desc.getNameToken(CallSiteDescriptor.SCHEME) != "dyn") {
|
||||
if(desc.getNameTokenCount() != 2 && desc.getNameToken(CallSiteDescriptor.SCHEME) != "dyn") {
|
||||
return null;
|
||||
}
|
||||
final String operator = desc.getNameToken(CallSiteDescriptor.OPERATOR);
|
||||
if(operator == "call") {
|
||||
final MethodType type = desc.getMethodType();
|
||||
final MethodHandle invocation = ((DynamicMethod)receiver).getInvocation(type.dropParameterTypes(0, 1),
|
||||
linkerServices);
|
||||
final MethodHandle invocation = ((DynamicMethod)receiver).getInvocation(
|
||||
CallSiteDescriptorFactory.dropParameterTypes(desc, 0, 1), linkerServices);
|
||||
if(invocation == null) {
|
||||
return null;
|
||||
}
|
||||
return new GuardedInvocation(MethodHandles.dropArguments(invocation, 0, type.parameterType(0)),
|
||||
Guards.getIdentityGuard(receiver));
|
||||
return new GuardedInvocation(MethodHandles.dropArguments(invocation, 0,
|
||||
desc.getMethodType().parameterType(0)), Guards.getIdentityGuard(receiver));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -167,10 +167,6 @@ abstract class FacetIntrospector {
|
||||
return editMethodHandle(SafeUnreflector.unreflectSetter(field));
|
||||
}
|
||||
|
||||
MethodHandle unreflect(Method method) {
|
||||
return editMethodHandle(SafeUnreflector.unreflect(method));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an edited method handle. A facet might need to edit an unreflected method handle before it is usable with
|
||||
* the facet. By default, returns the passed method handle unchanged. The class' static facet will introduce a
|
||||
|
@ -105,10 +105,58 @@ class MaximallySpecific {
|
||||
* @param varArgs whether to assume the methods are varargs
|
||||
* @return the list of maximally specific methods.
|
||||
*/
|
||||
static List<MethodHandle> getMaximallySpecificMethods(List<MethodHandle> methods, boolean varArgs) {
|
||||
return getMaximallySpecificMethods(methods, varArgs, null, null);
|
||||
static List<SingleDynamicMethod> getMaximallySpecificMethods(List<SingleDynamicMethod> methods, boolean varArgs) {
|
||||
return getMaximallySpecificSingleDynamicMethods(methods, varArgs, null, null);
|
||||
}
|
||||
|
||||
private abstract static class MethodTypeGetter<T> {
|
||||
abstract MethodType getMethodType(T t);
|
||||
}
|
||||
|
||||
private static final MethodTypeGetter<MethodHandle> METHOD_HANDLE_TYPE_GETTER =
|
||||
new MethodTypeGetter<MethodHandle>() {
|
||||
@Override
|
||||
MethodType getMethodType(MethodHandle t) {
|
||||
return t.type();
|
||||
}
|
||||
};
|
||||
|
||||
private static final MethodTypeGetter<SingleDynamicMethod> DYNAMIC_METHOD_TYPE_GETTER =
|
||||
new MethodTypeGetter<SingleDynamicMethod>() {
|
||||
@Override
|
||||
MethodType getMethodType(SingleDynamicMethod t) {
|
||||
return t.getMethodType();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Given a list of methods handles, returns a list of maximally specific methods, applying language-runtime
|
||||
* specific conversion preferences.
|
||||
*
|
||||
* @param methods the list of method handles
|
||||
* @param varArgs whether to assume the method handles are varargs
|
||||
* @param argTypes concrete argument types for the invocation
|
||||
* @return the list of maximally specific method handles.
|
||||
*/
|
||||
static List<MethodHandle> getMaximallySpecificMethodHandles(List<MethodHandle> methods, boolean varArgs,
|
||||
Class<?>[] argTypes, LinkerServices ls) {
|
||||
return getMaximallySpecificMethods(methods, varArgs, argTypes, ls, METHOD_HANDLE_TYPE_GETTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a list of methods, returns a list of maximally specific methods, applying language-runtime specific
|
||||
* conversion preferences.
|
||||
*
|
||||
* @param methods the list of methods
|
||||
* @param varArgs whether to assume the methods are varargs
|
||||
* @param argTypes concrete argument types for the invocation
|
||||
* @return the list of maximally specific methods.
|
||||
*/
|
||||
static List<SingleDynamicMethod> getMaximallySpecificSingleDynamicMethods(List<SingleDynamicMethod> methods,
|
||||
boolean varArgs, Class<?>[] argTypes, LinkerServices ls) {
|
||||
return getMaximallySpecificMethods(methods, varArgs, argTypes, ls, DYNAMIC_METHOD_TYPE_GETTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a list of methods, returns a list of maximally specific methods, applying language-runtime specific
|
||||
* conversion preferences.
|
||||
@ -118,18 +166,18 @@ class MaximallySpecific {
|
||||
* @param argTypes concrete argument types for the invocation
|
||||
* @return the list of maximally specific methods.
|
||||
*/
|
||||
static List<MethodHandle> getMaximallySpecificMethods(List<MethodHandle> methods, boolean varArgs,
|
||||
Class<?>[] argTypes, LinkerServices ls) {
|
||||
private static <T> List<T> getMaximallySpecificMethods(List<T> methods, boolean varArgs,
|
||||
Class<?>[] argTypes, LinkerServices ls, MethodTypeGetter<T> methodTypeGetter) {
|
||||
if(methods.size() < 2) {
|
||||
return methods;
|
||||
}
|
||||
final LinkedList<MethodHandle> maximals = new LinkedList<>();
|
||||
for(MethodHandle m: methods) {
|
||||
final MethodType methodType = m.type();
|
||||
final LinkedList<T> maximals = new LinkedList<>();
|
||||
for(T m: methods) {
|
||||
final MethodType methodType = methodTypeGetter.getMethodType(m);
|
||||
boolean lessSpecific = false;
|
||||
for(Iterator<MethodHandle> maximal = maximals.iterator(); maximal.hasNext();) {
|
||||
final MethodHandle max = maximal.next();
|
||||
switch(isMoreSpecific(methodType, max.type(), varArgs, argTypes, ls)) {
|
||||
for(Iterator<T> maximal = maximals.iterator(); maximal.hasNext();) {
|
||||
final T max = maximal.next();
|
||||
switch(isMoreSpecific(methodType, methodTypeGetter.getMethodType(max), varArgs, argTypes, ls)) {
|
||||
case TYPE_1_BETTER: {
|
||||
maximal.remove();
|
||||
break;
|
||||
|
@ -84,16 +84,21 @@
|
||||
package jdk.internal.dynalink.beans;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import jdk.internal.dynalink.CallSiteDescriptor;
|
||||
import jdk.internal.dynalink.beans.ApplicableOverloadedMethods.ApplicabilityTest;
|
||||
import jdk.internal.dynalink.linker.LinkerServices;
|
||||
import jdk.internal.dynalink.support.TypeUtilities;
|
||||
|
||||
/**
|
||||
* Represents an overloaded method.
|
||||
* Represents a group of {@link SingleDynamicMethod} objects that represents all overloads of a particular name (or all
|
||||
* constructors) for a particular class. Correctly handles overload resolution, variable arity methods, and caller
|
||||
* sensitive methods within the overloads.
|
||||
*
|
||||
* @author Attila Szegedi
|
||||
*/
|
||||
@ -101,7 +106,7 @@ class OverloadedDynamicMethod extends DynamicMethod {
|
||||
/**
|
||||
* Holds a list of all methods.
|
||||
*/
|
||||
private final LinkedList<MethodHandle> methods;
|
||||
private final LinkedList<SingleDynamicMethod> methods;
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
/**
|
||||
@ -111,21 +116,22 @@ class OverloadedDynamicMethod extends DynamicMethod {
|
||||
* @param name the name of the method
|
||||
*/
|
||||
OverloadedDynamicMethod(Class<?> clazz, String name) {
|
||||
this(new LinkedList<MethodHandle>(), clazz.getClassLoader(), getClassAndMethodName(clazz, name));
|
||||
this(new LinkedList<SingleDynamicMethod>(), clazz.getClassLoader(), getClassAndMethodName(clazz, name));
|
||||
}
|
||||
|
||||
private OverloadedDynamicMethod(LinkedList<MethodHandle> methods, ClassLoader classLoader, String name) {
|
||||
private OverloadedDynamicMethod(LinkedList<SingleDynamicMethod> methods, ClassLoader classLoader, String name) {
|
||||
super(name);
|
||||
this.methods = methods;
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
SimpleDynamicMethod getMethodForExactParamTypes(String paramTypes) {
|
||||
final LinkedList<MethodHandle> matchingMethods = new LinkedList<>();
|
||||
for(MethodHandle method: methods) {
|
||||
if(typeMatchesDescription(paramTypes, method.type())) {
|
||||
matchingMethods.add(method);
|
||||
SingleDynamicMethod getMethodForExactParamTypes(String paramTypes) {
|
||||
final LinkedList<SingleDynamicMethod> matchingMethods = new LinkedList<>();
|
||||
for(SingleDynamicMethod method: methods) {
|
||||
final SingleDynamicMethod matchingMethod = method.getMethodForExactParamTypes(paramTypes);
|
||||
if(matchingMethod != null) {
|
||||
matchingMethods.add(matchingMethod);
|
||||
}
|
||||
}
|
||||
switch(matchingMethods.size()) {
|
||||
@ -133,8 +139,7 @@ class OverloadedDynamicMethod extends DynamicMethod {
|
||||
return null;
|
||||
}
|
||||
case 1: {
|
||||
final MethodHandle target = matchingMethods.get(0);
|
||||
return new SimpleDynamicMethod(target, SimpleDynamicMethod.getMethodNameWithSignature(target, getName()));
|
||||
return matchingMethods.getFirst();
|
||||
}
|
||||
default: {
|
||||
throw new BootstrapMethodError("Can't choose among " + matchingMethods + " for argument types "
|
||||
@ -144,7 +149,8 @@ class OverloadedDynamicMethod extends DynamicMethod {
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodHandle getInvocation(final MethodType callSiteType, final LinkerServices linkerServices) {
|
||||
public 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,
|
||||
ApplicableOverloadedMethods.APPLICABLE_BY_SUBTYPING);
|
||||
@ -156,7 +162,7 @@ class OverloadedDynamicMethod extends DynamicMethod {
|
||||
ApplicableOverloadedMethods.APPLICABLE_BY_VARIABLE_ARITY);
|
||||
|
||||
// Find the methods that are maximally specific based on the call site signature
|
||||
List<MethodHandle> maximallySpecifics = subtypingApplicables.findMaximallySpecificMethods();
|
||||
List<SingleDynamicMethod> maximallySpecifics = subtypingApplicables.findMaximallySpecificMethods();
|
||||
if(maximallySpecifics.isEmpty()) {
|
||||
maximallySpecifics = methodInvocationApplicables.findMaximallySpecificMethods();
|
||||
if(maximallySpecifics.isEmpty()) {
|
||||
@ -171,12 +177,12 @@ class OverloadedDynamicMethod extends DynamicMethod {
|
||||
// (Object, Object), and we have a method whose parameter types are (String, int). None of the JLS applicability
|
||||
// rules will trigger, but we must consider the method, as it can be the right match for a concrete invocation.
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
final List<MethodHandle> invokables = (List)methods.clone();
|
||||
final List<SingleDynamicMethod> invokables = (List)methods.clone();
|
||||
invokables.removeAll(subtypingApplicables.getMethods());
|
||||
invokables.removeAll(methodInvocationApplicables.getMethods());
|
||||
invokables.removeAll(variableArityApplicables.getMethods());
|
||||
for(final Iterator<MethodHandle> it = invokables.iterator(); it.hasNext();) {
|
||||
final MethodHandle m = it.next();
|
||||
for(final Iterator<SingleDynamicMethod> it = invokables.iterator(); it.hasNext();) {
|
||||
final SingleDynamicMethod m = it.next();
|
||||
if(!isApplicableDynamically(linkerServices, callSiteType, m)) {
|
||||
it.remove();
|
||||
}
|
||||
@ -199,54 +205,45 @@ class OverloadedDynamicMethod extends DynamicMethod {
|
||||
}
|
||||
case 1: {
|
||||
// Very lucky, we ended up with a single candidate method handle based on the call site signature; we
|
||||
// can link it very simply by delegating to a SimpleDynamicMethod.
|
||||
final MethodHandle mh = invokables.iterator().next();
|
||||
return new SimpleDynamicMethod(mh).getInvocation(callSiteType, linkerServices);
|
||||
// can link it very simply by delegating to the SingleDynamicMethod.
|
||||
invokables.iterator().next().getInvocation(callSiteDescriptor, linkerServices);
|
||||
}
|
||||
default: {
|
||||
// We have more than one candidate. We have no choice but to link to a method that resolves overloads on
|
||||
// every invocation (alternatively, we could opportunistically link the one method that resolves for the
|
||||
// current arguments, but we'd need to install a fairly complex guard for that and when it'd fail, we'd
|
||||
// go back all the way to candidate selection.
|
||||
// TODO: cache per call site type
|
||||
return new OverloadedMethod(invokables, this, callSiteType, linkerServices).getInvoker();
|
||||
// go back all the way to candidate selection. Note that we're resolving any potential caller sensitive
|
||||
// methods here to their handles, as the OverloadedMethod instance is specific to a call site, so it
|
||||
// has an already determined Lookup.
|
||||
final List<MethodHandle> methodHandles = new ArrayList<>(invokables.size());
|
||||
final MethodHandles.Lookup lookup = callSiteDescriptor.getLookup();
|
||||
for(SingleDynamicMethod method: invokables) {
|
||||
methodHandles.add(method.getTarget(lookup));
|
||||
}
|
||||
return new OverloadedMethod(methodHandles, this, callSiteType, linkerServices).getInvoker();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(MethodHandle mh) {
|
||||
final MethodType type = mh.type();
|
||||
for(MethodHandle method: methods) {
|
||||
if(typesEqualNoReceiver(type, method.type())) {
|
||||
public boolean contains(SingleDynamicMethod m) {
|
||||
for(SingleDynamicMethod method: methods) {
|
||||
if(method.contains(m)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean typesEqualNoReceiver(MethodType type1, MethodType type2) {
|
||||
final int pc = type1.parameterCount();
|
||||
if(pc != type2.parameterCount()) {
|
||||
return false;
|
||||
}
|
||||
for(int i = 1; i < pc; ++i) { // i = 1: ignore receiver
|
||||
if(type1.parameterType(i) != type2.parameterType(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ClassLoader getClassLoader() {
|
||||
return classLoader;
|
||||
}
|
||||
|
||||
private static boolean isApplicableDynamically(LinkerServices linkerServices, MethodType callSiteType,
|
||||
MethodHandle m) {
|
||||
final MethodType methodType = m.type();
|
||||
final boolean varArgs = m.isVarargsCollector();
|
||||
SingleDynamicMethod m) {
|
||||
final MethodType methodType = m.getMethodType();
|
||||
final boolean varArgs = m.isVarArgs();
|
||||
final int fixedArgLen = methodType.parameterCount() - (varArgs ? 1 : 0);
|
||||
final int callSiteArgLen = callSiteType.parameterCount();
|
||||
|
||||
@ -300,21 +297,12 @@ class OverloadedDynamicMethod extends DynamicMethod {
|
||||
return new ApplicableOverloadedMethods(methods, callSiteType, test);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a method identified by a {@link SimpleDynamicMethod} to this overloaded method's set.
|
||||
*
|
||||
* @param method the method to add.
|
||||
*/
|
||||
void addMethod(SimpleDynamicMethod method) {
|
||||
addMethod(method.getTarget());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a method to this overloaded method's set.
|
||||
*
|
||||
* @param method a method to add
|
||||
*/
|
||||
public void addMethod(MethodHandle method) {
|
||||
public void addMethod(SingleDynamicMethod method) {
|
||||
methods.add(method);
|
||||
}
|
||||
}
|
||||
|
@ -135,7 +135,7 @@ class OverloadedMethod {
|
||||
varArgMethods.trimToSize();
|
||||
|
||||
final MethodHandle bound = SELECT_METHOD.bindTo(this);
|
||||
final MethodHandle collecting = SimpleDynamicMethod.collectArguments(bound, argNum).asType(
|
||||
final MethodHandle collecting = SingleDynamicMethod.collectArguments(bound, argNum).asType(
|
||||
callSiteType.changeReturnType(MethodHandle.class));
|
||||
invoker = MethodHandles.foldArguments(MethodHandles.exactInvoker(callSiteType), collecting);
|
||||
}
|
||||
@ -167,7 +167,7 @@ class OverloadedMethod {
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
method = new SimpleDynamicMethod(methods.get(0)).getInvocation(callSiteType, linkerServices);
|
||||
method = SingleDynamicMethod.getInvocation(methods.get(0), callSiteType, linkerServices);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
@ -84,28 +84,21 @@
|
||||
package jdk.internal.dynalink.beans;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodHandles.Lookup;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Array;
|
||||
import jdk.internal.dynalink.linker.LinkerServices;
|
||||
import jdk.internal.dynalink.support.Guards;
|
||||
|
||||
/**
|
||||
* A dynamic method bound to exactly one, non-overloaded Java method. Handles varargs.
|
||||
* A dynamic method bound to exactly one Java method or constructor that is not caller sensitive. Since its target is
|
||||
* not caller sensitive, this class pre-caches its method handle and always returns it from the call to
|
||||
* {@link #getTarget(Lookup)}. Can be used in general to represents dynamic methods bound to a single method handle,
|
||||
* even if that handle is not mapped to a Java method, i.e. as a wrapper around field getters/setters, array element
|
||||
* getters/setters, etc.
|
||||
*
|
||||
* @author Attila Szegedi
|
||||
*/
|
||||
class SimpleDynamicMethod extends DynamicMethod {
|
||||
class SimpleDynamicMethod extends SingleDynamicMethod {
|
||||
private final MethodHandle target;
|
||||
|
||||
/**
|
||||
* Creates a simple dynamic method with no name.
|
||||
* @param target the target method handle
|
||||
*/
|
||||
SimpleDynamicMethod(MethodHandle target) {
|
||||
this(target, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new simple dynamic method, with a name constructed from the class name, method name, and handle
|
||||
* signature.
|
||||
@ -115,125 +108,26 @@ class SimpleDynamicMethod extends DynamicMethod {
|
||||
* @param name the simple name of the method
|
||||
*/
|
||||
SimpleDynamicMethod(MethodHandle target, Class<?> clazz, String name) {
|
||||
this(target, getName(target, clazz, name));
|
||||
}
|
||||
|
||||
SimpleDynamicMethod(MethodHandle target, String name) {
|
||||
super(name);
|
||||
super(getName(target, clazz, name));
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
private static String getName(MethodHandle target, Class<?> clazz, String name) {
|
||||
return getMethodNameWithSignature(target, getClassAndMethodName(clazz, name));
|
||||
return getMethodNameWithSignature(target.type(), getClassAndMethodName(clazz, name));
|
||||
}
|
||||
|
||||
static String getMethodNameWithSignature(MethodHandle target, String methodName) {
|
||||
final String typeStr = target.type().toString();
|
||||
final int retTypeIndex = typeStr.lastIndexOf(')') + 1;
|
||||
int secondParamIndex = typeStr.indexOf(',') + 1;
|
||||
if(secondParamIndex == 0) {
|
||||
secondParamIndex = retTypeIndex - 1;
|
||||
}
|
||||
return typeStr.substring(retTypeIndex) + " " + methodName + "(" + typeStr.substring(secondParamIndex, retTypeIndex);
|
||||
@Override
|
||||
boolean isVarArgs() {
|
||||
return target.isVarargsCollector();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the target of this dynamic method
|
||||
*
|
||||
* @return the target of this dynamic method
|
||||
*/
|
||||
MethodHandle getTarget() {
|
||||
@Override
|
||||
MethodType getMethodType() {
|
||||
return target.type();
|
||||
}
|
||||
|
||||
@Override
|
||||
MethodHandle getTarget(Lookup lookup) {
|
||||
return target;
|
||||
}
|
||||
|
||||
@Override
|
||||
SimpleDynamicMethod getMethodForExactParamTypes(String paramTypes) {
|
||||
return typeMatchesDescription(paramTypes, target.type()) ? this : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
MethodHandle getInvocation(MethodType callSiteType, LinkerServices linkerServices) {
|
||||
final MethodType methodType = target.type();
|
||||
final int paramsLen = methodType.parameterCount();
|
||||
final boolean varArgs = target.isVarargsCollector();
|
||||
final MethodHandle fixTarget = varArgs ? target.asFixedArity() : target;
|
||||
final int fixParamsLen = varArgs ? paramsLen - 1 : paramsLen;
|
||||
final int argsLen = callSiteType.parameterCount();
|
||||
if(argsLen < fixParamsLen) {
|
||||
// Less actual arguments than number of fixed declared arguments; can't invoke.
|
||||
return null;
|
||||
}
|
||||
// Method handle has the same number of fixed arguments as the call site type
|
||||
if(argsLen == fixParamsLen) {
|
||||
// Method handle that matches the number of actual arguments as the number of fixed arguments
|
||||
final MethodHandle matchedMethod;
|
||||
if(varArgs) {
|
||||
// If vararg, add a zero-length array of the expected type as the last argument to signify no variable
|
||||
// arguments.
|
||||
matchedMethod = MethodHandles.insertArguments(fixTarget, fixParamsLen, Array.newInstance(
|
||||
methodType.parameterType(fixParamsLen).getComponentType(), 0));
|
||||
} else {
|
||||
// Otherwise, just use the method
|
||||
matchedMethod = fixTarget;
|
||||
}
|
||||
return createConvertingInvocation(matchedMethod, linkerServices, callSiteType);
|
||||
}
|
||||
|
||||
// What's below only works for varargs
|
||||
if(!varArgs) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Class<?> varArgType = methodType.parameterType(fixParamsLen);
|
||||
// Handle a somewhat sinister corner case: caller passes exactly one argument in the vararg position, and we
|
||||
// must handle both a prepacked vararg array as well as a genuine 1-long vararg sequence.
|
||||
if(argsLen == paramsLen) {
|
||||
final Class<?> callSiteLastArgType = callSiteType.parameterType(fixParamsLen);
|
||||
if(varArgType.isAssignableFrom(callSiteLastArgType)) {
|
||||
// Call site signature guarantees we'll always be passed a single compatible array; just link directly
|
||||
// to the method.
|
||||
return createConvertingInvocation(fixTarget, linkerServices, callSiteType);
|
||||
}
|
||||
if(!linkerServices.canConvert(callSiteLastArgType, varArgType)) {
|
||||
// Call site signature guarantees the argument can definitely not be an array (i.e. it is primitive);
|
||||
// link immediately to a vararg-packing method handle.
|
||||
return createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType);
|
||||
}
|
||||
// Call site signature makes no guarantees that the single argument in the vararg position will be
|
||||
// compatible across all invocations. Need to insert an appropriate guard and fall back to generic vararg
|
||||
// method when it is not.
|
||||
return MethodHandles.guardWithTest(Guards.isInstance(varArgType, fixParamsLen, callSiteType),
|
||||
createConvertingInvocation(fixTarget, linkerServices, callSiteType),
|
||||
createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType));
|
||||
}
|
||||
|
||||
// Remaining case: more than one vararg.
|
||||
return createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(MethodHandle mh) {
|
||||
return target.type().parameterList().equals(mh.type().parameterList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a method handle out of the original target that will collect the varargs for the exact component type of
|
||||
* the varArg array. Note that this will nicely trigger language-specific type converters for exactly those varargs
|
||||
* for which it is necessary when later passed to linkerServices.convertArguments().
|
||||
*
|
||||
* @param target the original method handle
|
||||
* @param parameterCount the total number of arguments in the new method handle
|
||||
* @return a collecting method handle
|
||||
*/
|
||||
static MethodHandle collectArguments(MethodHandle target, final int parameterCount) {
|
||||
final MethodType methodType = target.type();
|
||||
final int fixParamsLen = methodType.parameterCount() - 1;
|
||||
final Class<?> arrayType = methodType.parameterType(fixParamsLen);
|
||||
return target.asCollector(arrayType, parameterCount - fixParamsLen);
|
||||
}
|
||||
|
||||
private static MethodHandle createConvertingInvocation(final MethodHandle sizedMethod,
|
||||
final LinkerServices linkerServices, final MethodType callSiteType) {
|
||||
return linkerServices.asType(sizedMethod, callSiteType);
|
||||
}
|
||||
}
|
||||
|
255
nashorn/src/jdk/internal/dynalink/beans/SingleDynamicMethod.java
Normal file
255
nashorn/src/jdk/internal/dynalink/beans/SingleDynamicMethod.java
Normal file
@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file, and Oracle licenses the original version of this file under the BSD
|
||||
* license:
|
||||
*/
|
||||
/*
|
||||
Copyright 2009-2013 Attila Szegedi
|
||||
|
||||
Licensed under both the Apache License, Version 2.0 (the "Apache License")
|
||||
and 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.
|
||||
|
||||
If you choose to use this file in compliance with the Apache License, the
|
||||
following notice applies to you:
|
||||
|
||||
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 the License for the specific language governing
|
||||
permissions and limitations under the License.
|
||||
|
||||
If you choose to use this file in compliance with the BSD License, the
|
||||
following notice applies to you:
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the names of
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
|
||||
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jdk.internal.dynalink.beans;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.StringTokenizer;
|
||||
import jdk.internal.dynalink.CallSiteDescriptor;
|
||||
import jdk.internal.dynalink.linker.LinkerServices;
|
||||
import jdk.internal.dynalink.support.Guards;
|
||||
|
||||
/**
|
||||
* Base class for dynamic methods that dispatch to a single target Java method or constructor. Handles adaptation of the
|
||||
* target method to a call site type (including mapping variable arity methods to a call site signature with different
|
||||
* arity).
|
||||
* @author Attila Szegedi
|
||||
* @version $Id: $
|
||||
*/
|
||||
abstract class SingleDynamicMethod extends DynamicMethod {
|
||||
SingleDynamicMethod(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this method is variable arity.
|
||||
* @return true if this method is variable arity.
|
||||
*/
|
||||
abstract boolean isVarArgs();
|
||||
|
||||
/**
|
||||
* Returns this method's native type.
|
||||
* @return this method's native type.
|
||||
*/
|
||||
abstract MethodType getMethodType();
|
||||
|
||||
/**
|
||||
* Given a specified lookup, returns a method handle to this method's target.
|
||||
* @param lookup the lookup to use.
|
||||
* @return the handle to this method's target method.
|
||||
*/
|
||||
abstract MethodHandle getTarget(MethodHandles.Lookup lookup);
|
||||
|
||||
@Override
|
||||
MethodHandle getInvocation(CallSiteDescriptor callSiteDescriptor, LinkerServices linkerServices) {
|
||||
return getInvocation(getTarget(callSiteDescriptor.getLookup()), callSiteDescriptor.getMethodType(),
|
||||
linkerServices);
|
||||
}
|
||||
|
||||
@Override
|
||||
SingleDynamicMethod getMethodForExactParamTypes(String paramTypes) {
|
||||
return typeMatchesDescription(paramTypes, getMethodType()) ? this : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean contains(SingleDynamicMethod method) {
|
||||
return getMethodType().parameterList().equals(method.getMethodType().parameterList());
|
||||
}
|
||||
|
||||
static String getMethodNameWithSignature(MethodType type, String methodName) {
|
||||
final String typeStr = type.toString();
|
||||
final int retTypeIndex = typeStr.lastIndexOf(')') + 1;
|
||||
int secondParamIndex = typeStr.indexOf(',') + 1;
|
||||
if(secondParamIndex == 0) {
|
||||
secondParamIndex = retTypeIndex - 1;
|
||||
}
|
||||
return typeStr.substring(retTypeIndex) + " " + methodName + "(" + typeStr.substring(secondParamIndex, retTypeIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a method handle and a call site type, adapts the method handle to the call site type. Performs type
|
||||
* conversions as needed using the specified linker services, and in case that the method handle is a vararg
|
||||
* collector, matches it to the arity of the call site.
|
||||
* @param target the method handle to adapt
|
||||
* @param callSiteType the type of the call site
|
||||
* @param linkerServices the linker services used for type conversions
|
||||
* @return the adapted method handle.
|
||||
*/
|
||||
static MethodHandle getInvocation(MethodHandle target, MethodType callSiteType, LinkerServices linkerServices) {
|
||||
final MethodType methodType = target.type();
|
||||
final int paramsLen = methodType.parameterCount();
|
||||
final boolean varArgs = target.isVarargsCollector();
|
||||
final MethodHandle fixTarget = varArgs ? target.asFixedArity() : target;
|
||||
final int fixParamsLen = varArgs ? paramsLen - 1 : paramsLen;
|
||||
final int argsLen = callSiteType.parameterCount();
|
||||
if(argsLen < fixParamsLen) {
|
||||
// Less actual arguments than number of fixed declared arguments; can't invoke.
|
||||
return null;
|
||||
}
|
||||
// Method handle has the same number of fixed arguments as the call site type
|
||||
if(argsLen == fixParamsLen) {
|
||||
// Method handle that matches the number of actual arguments as the number of fixed arguments
|
||||
final MethodHandle matchedMethod;
|
||||
if(varArgs) {
|
||||
// If vararg, add a zero-length array of the expected type as the last argument to signify no variable
|
||||
// arguments.
|
||||
matchedMethod = MethodHandles.insertArguments(fixTarget, fixParamsLen, Array.newInstance(
|
||||
methodType.parameterType(fixParamsLen).getComponentType(), 0));
|
||||
} else {
|
||||
// Otherwise, just use the method
|
||||
matchedMethod = fixTarget;
|
||||
}
|
||||
return createConvertingInvocation(matchedMethod, linkerServices, callSiteType);
|
||||
}
|
||||
|
||||
// What's below only works for varargs
|
||||
if(!varArgs) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Class<?> varArgType = methodType.parameterType(fixParamsLen);
|
||||
// Handle a somewhat sinister corner case: caller passes exactly one argument in the vararg position, and we
|
||||
// must handle both a prepacked vararg array as well as a genuine 1-long vararg sequence.
|
||||
if(argsLen == paramsLen) {
|
||||
final Class<?> callSiteLastArgType = callSiteType.parameterType(fixParamsLen);
|
||||
if(varArgType.isAssignableFrom(callSiteLastArgType)) {
|
||||
// Call site signature guarantees we'll always be passed a single compatible array; just link directly
|
||||
// to the method, introducing necessary conversions. Also, preserve it being a variable arity method.
|
||||
return createConvertingInvocation(target, linkerServices, callSiteType).asVarargsCollector(
|
||||
callSiteLastArgType);
|
||||
}
|
||||
if(!linkerServices.canConvert(callSiteLastArgType, varArgType)) {
|
||||
// Call site signature guarantees the argument can definitely not be an array (i.e. it is primitive);
|
||||
// link immediately to a vararg-packing method handle.
|
||||
return createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType);
|
||||
}
|
||||
// Call site signature makes no guarantees that the single argument in the vararg position will be
|
||||
// compatible across all invocations. Need to insert an appropriate guard and fall back to generic vararg
|
||||
// method when it is not.
|
||||
return MethodHandles.guardWithTest(Guards.isInstance(varArgType, fixParamsLen, callSiteType),
|
||||
createConvertingInvocation(fixTarget, linkerServices, callSiteType),
|
||||
createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType));
|
||||
}
|
||||
|
||||
// Remaining case: more than one vararg.
|
||||
return createConvertingInvocation(collectArguments(fixTarget, argsLen), linkerServices, callSiteType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a method handle out of the original target that will collect the varargs for the exact component type of
|
||||
* the varArg array. Note that this will nicely trigger language-specific type converters for exactly those varargs
|
||||
* for which it is necessary when later passed to linkerServices.convertArguments().
|
||||
*
|
||||
* @param target the original method handle
|
||||
* @param parameterCount the total number of arguments in the new method handle
|
||||
* @return a collecting method handle
|
||||
*/
|
||||
static MethodHandle collectArguments(MethodHandle target, final int parameterCount) {
|
||||
final MethodType methodType = target.type();
|
||||
final int fixParamsLen = methodType.parameterCount() - 1;
|
||||
final Class<?> arrayType = methodType.parameterType(fixParamsLen);
|
||||
return target.asCollector(arrayType, parameterCount - fixParamsLen);
|
||||
}
|
||||
|
||||
private static MethodHandle createConvertingInvocation(final MethodHandle sizedMethod,
|
||||
final LinkerServices linkerServices, final MethodType callSiteType) {
|
||||
return linkerServices.asType(sizedMethod, callSiteType);
|
||||
}
|
||||
|
||||
private static boolean typeMatchesDescription(String paramTypes, MethodType type) {
|
||||
final StringTokenizer tok = new StringTokenizer(paramTypes, ", ");
|
||||
for(int i = 1; i < type.parameterCount(); ++i) { // i = 1 as we ignore the receiver
|
||||
if(!(tok.hasMoreTokens() && typeNameMatches(tok.nextToken(), type.parameterType(i)))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return !tok.hasMoreTokens();
|
||||
}
|
||||
|
||||
private static boolean typeNameMatches(String typeName, Class<?> type) {
|
||||
return typeName.equals(typeName.indexOf('.') == -1 ? type.getSimpleName() : type.getCanonicalName());
|
||||
}
|
||||
}
|
@ -106,10 +106,18 @@ class StaticClassIntrospector extends FacetIntrospector {
|
||||
|
||||
@Override
|
||||
MethodHandle editMethodHandle(MethodHandle mh) {
|
||||
return editStaticMethodHandle(mh);
|
||||
}
|
||||
|
||||
static MethodHandle editStaticMethodHandle(MethodHandle mh) {
|
||||
return dropReceiver(mh, Object.class);
|
||||
}
|
||||
|
||||
static MethodHandle dropReceiver(final MethodHandle mh, final Class<?> receiverClass) {
|
||||
static MethodHandle editConstructorMethodHandle(MethodHandle cmh) {
|
||||
return dropReceiver(cmh, StaticClass.class);
|
||||
}
|
||||
|
||||
private static MethodHandle dropReceiver(final MethodHandle mh, final Class<?> receiverClass) {
|
||||
MethodHandle newHandle = MethodHandles.dropArguments(mh, 0, receiverClass);
|
||||
// NOTE: this is a workaround for the fact that dropArguments doesn't preserve vararg collector state.
|
||||
if(mh.isVarargsCollector() && !newHandle.isVarargsCollector()) {
|
||||
|
@ -87,9 +87,7 @@ import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Arrays;
|
||||
import jdk.internal.dynalink.CallSiteDescriptor;
|
||||
import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType;
|
||||
import jdk.internal.dynalink.linker.GuardedInvocation;
|
||||
@ -131,20 +129,11 @@ class StaticClassLinker implements TypeBasedGuardingDynamicLinker {
|
||||
private static DynamicMethod createConstructorMethod(Class<?> clazz) {
|
||||
if(clazz.isArray()) {
|
||||
final MethodHandle boundArrayCtor = ARRAY_CTOR.bindTo(clazz.getComponentType());
|
||||
return new SimpleDynamicMethod(drop(boundArrayCtor.asType(boundArrayCtor.type().changeReturnType(
|
||||
clazz))), clazz, "<init>");
|
||||
return new SimpleDynamicMethod(StaticClassIntrospector.editConstructorMethodHandle(
|
||||
boundArrayCtor.asType(boundArrayCtor.type().changeReturnType(clazz))), clazz, "<init>");
|
||||
}
|
||||
|
||||
final Constructor<?>[] ctrs = clazz.getConstructors();
|
||||
final List<MethodHandle> mhs = new ArrayList<>(ctrs.length);
|
||||
for(int i = 0; i < ctrs.length; ++i) {
|
||||
mhs.add(drop(SafeUnreflector.unreflectConstructor(ctrs[i])));
|
||||
}
|
||||
return createDynamicMethod(mhs, clazz, "<init>");
|
||||
}
|
||||
|
||||
private static MethodHandle drop(MethodHandle mh) {
|
||||
return StaticClassIntrospector.dropReceiver(mh, StaticClass.class);
|
||||
return createDynamicMethod(Arrays.asList(clazz.getConstructors()), clazz, "<init>");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -161,11 +150,10 @@ class StaticClassLinker implements TypeBasedGuardingDynamicLinker {
|
||||
}
|
||||
final CallSiteDescriptor desc = request.getCallSiteDescriptor();
|
||||
final String op = desc.getNameToken(CallSiteDescriptor.OPERATOR);
|
||||
final MethodType methodType = desc.getMethodType();
|
||||
if("new" == op && constructor != null) {
|
||||
final MethodHandle ctorInvocation = constructor.getInvocation(methodType, linkerServices);
|
||||
final MethodHandle ctorInvocation = constructor.getInvocation(desc, linkerServices);
|
||||
if(ctorInvocation != null) {
|
||||
return new GuardedInvocation(ctorInvocation, getClassGuard(methodType));
|
||||
return new GuardedInvocation(ctorInvocation, getClassGuard(desc.getMethodType()));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -139,8 +139,9 @@ public abstract class AbstractCallSiteDescriptor implements CallSiteDescriptor {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final MethodHandles.Lookup lookup = getLookup();
|
||||
int h = lookup.lookupClass().hashCode() + 31 * lookup.lookupModes();
|
||||
final int c = getNameTokenCount();
|
||||
int h = 0;
|
||||
for(int i = 0; i < c; ++i) {
|
||||
h = h * 31 + getNameToken(i).hashCode();
|
||||
}
|
||||
|
@ -122,6 +122,18 @@ public class Lookup {
|
||||
* @return the unreflected method handle.
|
||||
*/
|
||||
public MethodHandle unreflect(Method m) {
|
||||
return unreflect(lookup, m);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflect(Method)}, converting any encountered
|
||||
* {@link IllegalAccessException} into an {@link IllegalAccessError}.
|
||||
*
|
||||
* @param lookup the lookup used to unreflect
|
||||
* @param m the method to unreflect
|
||||
* @return the unreflected method handle.
|
||||
*/
|
||||
public static MethodHandle unreflect(MethodHandles.Lookup lookup, Method m) {
|
||||
try {
|
||||
return lookup.unreflect(m);
|
||||
} catch(IllegalAccessException e) {
|
||||
@ -131,7 +143,6 @@ public class Lookup {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectGetter(Field)}, converting any encountered
|
||||
* {@link IllegalAccessException} into an {@link IllegalAccessError}.
|
||||
@ -202,6 +213,18 @@ public class Lookup {
|
||||
* @return the unreflected constructor handle.
|
||||
*/
|
||||
public MethodHandle unreflectConstructor(Constructor<?> c) {
|
||||
return unreflectConstructor(lookup, c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectConstructor(Constructor)}, converting any
|
||||
* encountered {@link IllegalAccessException} into an {@link IllegalAccessError}.
|
||||
*
|
||||
* @param lookup the lookup used to unreflect
|
||||
* @param c the constructor to unreflect
|
||||
* @return the unreflected constructor handle.
|
||||
*/
|
||||
public static MethodHandle unreflectConstructor(MethodHandles.Lookup lookup, Constructor<?> c) {
|
||||
try {
|
||||
return lookup.unreflectConstructor(c);
|
||||
} catch(IllegalAccessException e) {
|
||||
|
@ -78,7 +78,7 @@ public final class Bootstrap {
|
||||
* @return CallSite with MethodHandle to appropriate method or null if not found.
|
||||
*/
|
||||
public static CallSite bootstrap(final Lookup lookup, final String opDesc, final MethodType type, final int flags) {
|
||||
return dynamicLinker.link(LinkerCallSite.newLinkerCallSite(opDesc, type, flags));
|
||||
return dynamicLinker.link(LinkerCallSite.newLinkerCallSite(lookup, opDesc, type, flags));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -94,12 +94,12 @@ public final class Bootstrap {
|
||||
return new RuntimeCallSite(type, initialName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a dynamic invoker for a specified dynamic operation. You can use this method to create a method handle
|
||||
* that when invoked acts completely as if it were a Nashorn-linked call site. An overview of available dynamic
|
||||
* operations can be found in the <a href="https://github.com/szegedi/dynalink/wiki/User-Guide-0.4">Dynalink User Guide</a>,
|
||||
* but we'll show few examples here:
|
||||
* Returns a dynamic invoker for a specified dynamic operation using the public lookup. You can use this method to
|
||||
* create a method handle that when invoked acts completely as if it were a Nashorn-linked call site. An overview of
|
||||
* available dynamic operations can be found in the
|
||||
* <a href="https://github.com/szegedi/dynalink/wiki/User-Guide-0.6">Dynalink User Guide</a>, but we'll show few
|
||||
* examples here:
|
||||
* <ul>
|
||||
* <li>Get a named property with fixed name:
|
||||
* <pre>
|
||||
@ -196,7 +196,7 @@ public final class Bootstrap {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a dynamic invoker for a specified dynamic operation. Similar to
|
||||
* Returns a dynamic invoker for a specified dynamic operation using the public lookup. Similar to
|
||||
* {@link #createDynamicInvoker(String, Class, Class...)} but with return and parameter types composed into a
|
||||
* method type in the signature. See the discussion of that method for details.
|
||||
* @param opDesc Dynalink dynamic operation descriptor.
|
||||
@ -204,7 +204,7 @@ public final class Bootstrap {
|
||||
* @return MethodHandle for invoking the operation.
|
||||
*/
|
||||
public static MethodHandle createDynamicInvoker(final String opDesc, final MethodType type) {
|
||||
return bootstrap(null, opDesc, type, 0).dynamicInvoker();
|
||||
return bootstrap(MethodHandles.publicLookup(), opDesc, type, 0).dynamicInvoker();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -28,6 +28,7 @@ package jdk.nashorn.internal.runtime.linker;
|
||||
import static jdk.nashorn.internal.lookup.Lookup.MH;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.security.AccessController;
|
||||
@ -39,7 +40,6 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import jdk.internal.dynalink.beans.StaticClass;
|
||||
import jdk.internal.dynalink.support.LinkRequestImpl;
|
||||
import jdk.nashorn.internal.objects.NativeJava;
|
||||
@ -119,9 +119,12 @@ public final class JavaAdapterFactory {
|
||||
return AccessController.doPrivileged(new PrivilegedExceptionAction<MethodHandle>() {
|
||||
@Override
|
||||
public MethodHandle run() throws Exception {
|
||||
return MH.bindTo(Bootstrap.getLinkerServices().getGuardedInvocation(new LinkRequestImpl(NashornCallSiteDescriptor.get(
|
||||
"dyn:new", MethodType.methodType(targetType, StaticClass.class, sourceType), 0), false,
|
||||
adapterClass, null)).getInvocation(), adapterClass);
|
||||
// NOTE: we use publicLookup(), but none of our adapter constructors are caller sensitive, so this is
|
||||
// okay, we won't artificially limit access.
|
||||
return MH.bindTo(Bootstrap.getLinkerServices().getGuardedInvocation(new LinkRequestImpl(
|
||||
NashornCallSiteDescriptor.get(MethodHandles.publicLookup(), "dyn:new",
|
||||
MethodType.methodType(targetType, StaticClass.class, sourceType), 0), false,
|
||||
adapterClass, null)).getInvocation(), adapterClass);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -25,7 +25,6 @@
|
||||
|
||||
package jdk.nashorn.internal.runtime.linker;
|
||||
|
||||
import jdk.nashorn.internal.lookup.MethodHandleFactory;
|
||||
import static jdk.nashorn.internal.lookup.Lookup.MH;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
@ -47,6 +46,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
import jdk.internal.dynalink.ChainedCallSite;
|
||||
import jdk.internal.dynalink.DynamicLinker;
|
||||
import jdk.internal.dynalink.linker.GuardedInvocation;
|
||||
import jdk.nashorn.internal.lookup.MethodHandleFactory;
|
||||
import jdk.nashorn.internal.runtime.Context;
|
||||
import jdk.nashorn.internal.runtime.Debug;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
@ -79,8 +79,9 @@ public class LinkerCallSite extends ChainedCallSite {
|
||||
* @param flags Call site specific flags.
|
||||
* @return New LinkerCallSite.
|
||||
*/
|
||||
static LinkerCallSite newLinkerCallSite(final String name, final MethodType type, final int flags) {
|
||||
final NashornCallSiteDescriptor desc = NashornCallSiteDescriptor.get(name, type, flags);
|
||||
static LinkerCallSite newLinkerCallSite(final MethodHandles.Lookup lookup, final String name, final MethodType type,
|
||||
final int flags) {
|
||||
final NashornCallSiteDescriptor desc = NashornCallSiteDescriptor.get(lookup, name, type, flags);
|
||||
|
||||
if (desc.isProfile()) {
|
||||
return ProfilingLinkerCallSite.newProfilingLinkerCallSite(desc);
|
||||
|
@ -25,9 +25,12 @@
|
||||
|
||||
package jdk.nashorn.internal.runtime.linker;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodHandles.Lookup;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import jdk.internal.dynalink.CallSiteDescriptor;
|
||||
import jdk.internal.dynalink.support.AbstractCallSiteDescriptor;
|
||||
import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
|
||||
@ -70,9 +73,15 @@ public class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor {
|
||||
* set. */
|
||||
public static final int CALLSITE_TRACE_SCOPE = 0x200;
|
||||
|
||||
private static final WeakHashMap<NashornCallSiteDescriptor, WeakReference<NashornCallSiteDescriptor>> canonicals =
|
||||
new WeakHashMap<>();
|
||||
private static final ClassValue<ConcurrentMap<NashornCallSiteDescriptor, NashornCallSiteDescriptor>> canonicals =
|
||||
new ClassValue<ConcurrentMap<NashornCallSiteDescriptor,NashornCallSiteDescriptor>>() {
|
||||
@Override
|
||||
protected ConcurrentMap<NashornCallSiteDescriptor, NashornCallSiteDescriptor> computeValue(Class<?> type) {
|
||||
return new ConcurrentHashMap<>();
|
||||
}
|
||||
};
|
||||
|
||||
private final MethodHandles.Lookup lookup;
|
||||
private final String operator;
|
||||
private final String operand;
|
||||
private final MethodType methodType;
|
||||
@ -81,39 +90,35 @@ public class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor {
|
||||
/**
|
||||
* Retrieves a Nashorn call site descriptor with the specified values. Since call site descriptors are immutable
|
||||
* this method is at liberty to retrieve canonicalized instances (although it is not guaranteed it will do so).
|
||||
* @param lookup the lookup describing the script
|
||||
* @param name the name at the call site, e.g. {@code "dyn:getProp|getElem|getMethod:color"}.
|
||||
* @param methodType the method type at the call site
|
||||
* @param flags Nashorn-specific call site flags
|
||||
* @return a call site descriptor with the specified values.
|
||||
*/
|
||||
public static NashornCallSiteDescriptor get(final String name, final MethodType methodType, final int flags) {
|
||||
public static NashornCallSiteDescriptor get(final MethodHandles.Lookup lookup, final String name,
|
||||
final MethodType methodType, final int flags) {
|
||||
final String[] tokenizedName = CallSiteDescriptorFactory.tokenizeName(name);
|
||||
assert tokenizedName.length == 2 || tokenizedName.length == 3;
|
||||
assert "dyn".equals(tokenizedName[0]);
|
||||
assert tokenizedName[1] != null;
|
||||
// TODO: see if we can move mangling/unmangling into Dynalink
|
||||
return get(tokenizedName[1], tokenizedName.length == 3 ? tokenizedName[2].intern() : null,
|
||||
return get(lookup, tokenizedName[1], tokenizedName.length == 3 ? tokenizedName[2].intern() : null,
|
||||
methodType, flags);
|
||||
}
|
||||
|
||||
private static NashornCallSiteDescriptor get(final String operator, final String operand, final MethodType methodType, final int flags) {
|
||||
final NashornCallSiteDescriptor csd = new NashornCallSiteDescriptor(operator, operand, methodType, flags);
|
||||
private static NashornCallSiteDescriptor get(final MethodHandles.Lookup lookup, final String operator, final String operand, final MethodType methodType, final int flags) {
|
||||
final NashornCallSiteDescriptor csd = new NashornCallSiteDescriptor(lookup, operator, operand, methodType, flags);
|
||||
// Many of these call site descriptors are identical (e.g. every getter for a property color will be
|
||||
// "dyn:getProp:color(Object)Object", so it makes sense canonicalizing them in a weak map
|
||||
synchronized(canonicals) {
|
||||
final WeakReference<NashornCallSiteDescriptor> ref = canonicals.get(csd);
|
||||
if(ref != null) {
|
||||
final NashornCallSiteDescriptor canonical = ref.get();
|
||||
if(canonical != null) {
|
||||
return canonical;
|
||||
}
|
||||
}
|
||||
canonicals.put(csd, new WeakReference<>(csd));
|
||||
}
|
||||
return csd;
|
||||
// "dyn:getProp:color(Object)Object", so it makes sense canonicalizing them.
|
||||
final Map<NashornCallSiteDescriptor, NashornCallSiteDescriptor> classCanonicals = canonicals.get(lookup.lookupClass());
|
||||
final NashornCallSiteDescriptor canonical = classCanonicals.putIfAbsent(csd, csd);
|
||||
return canonical != null ? canonical : csd;
|
||||
}
|
||||
|
||||
private NashornCallSiteDescriptor(final String operator, final String operand, final MethodType methodType, final int flags) {
|
||||
private NashornCallSiteDescriptor(final MethodHandles.Lookup lookup, final String operator, final String operand,
|
||||
final MethodType methodType, final int flags) {
|
||||
this.lookup = lookup;
|
||||
this.operator = operator;
|
||||
this.operand = operand;
|
||||
this.methodType = methodType;
|
||||
@ -141,6 +146,11 @@ public class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor {
|
||||
throw new IndexOutOfBoundsException(String.valueOf(i));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Lookup getLookup() {
|
||||
return lookup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final CallSiteDescriptor csd) {
|
||||
return super.equals(csd) && flags == getFlags(csd);
|
||||
@ -279,6 +289,6 @@ public class NashornCallSiteDescriptor extends AbstractCallSiteDescriptor {
|
||||
|
||||
@Override
|
||||
public CallSiteDescriptor changeMethodType(final MethodType newMethodType) {
|
||||
return get(operator, operand, newMethodType, flags);
|
||||
return get(getLookup(), operator, operand, newMethodType, flags);
|
||||
}
|
||||
}
|
||||
|
38
nashorn/test/script/basic/JDK-8010946-2.js
Normal file
38
nashorn/test/script/basic/JDK-8010946-2.js
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, 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-8010946: AccessController.doPrivileged() doesn't work as expected.
|
||||
* This is actually a broader issue of having Dynalink correctly handle
|
||||
* caller-sensitive methods.
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
// Ensure these are CallerSensitiveDynamicMethods
|
||||
print(java.security.AccessController["doPrivileged(PrivilegedAction)"])
|
||||
print(java.lang.Class["forName(String)"])
|
||||
|
||||
// Ensure this is not
|
||||
print(java.lang.String["valueOf(char)"])
|
3
nashorn/test/script/basic/JDK-8010946-2.js.EXPECTED
Normal file
3
nashorn/test/script/basic/JDK-8010946-2.js.EXPECTED
Normal file
@ -0,0 +1,3 @@
|
||||
[jdk.internal.dynalink.beans.CallerSensitiveDynamicMethod Object java.security.AccessController.doPrivileged(PrivilegedAction)]
|
||||
[jdk.internal.dynalink.beans.CallerSensitiveDynamicMethod Class java.lang.Class.forName(String)]
|
||||
[jdk.internal.dynalink.beans.SimpleDynamicMethod String java.lang.String.valueOf(char)]
|
47
nashorn/test/script/basic/JDK-8010946-privileged.js
Normal file
47
nashorn/test/script/basic/JDK-8010946-privileged.js
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, 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-8010946: AccessController.doPrivileged() doesn't work as expected.
|
||||
* This is actually a broader issue of having Dynalink correctly handle
|
||||
* caller-sensitive methods.
|
||||
*
|
||||
* NOTE: This is not a standalone test file, it is loaded by JDK-801946.js
|
||||
* @subtest
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var getProperty = java.lang.System.getProperty
|
||||
var doPrivileged = java.security.AccessController["doPrivileged(PrivilegedAction)"]
|
||||
|
||||
this.executeUnprivileged = function() {
|
||||
var x = getProperty("java.security.policy")
|
||||
if(x != null) {
|
||||
print("Successfully retrieved restricted system property.")
|
||||
}
|
||||
}
|
||||
|
||||
this.executePrivileged = function() {
|
||||
doPrivileged(executeUnprivileged)
|
||||
}
|
||||
})();
|
51
nashorn/test/script/basic/JDK-8010946.js
Normal file
51
nashorn/test/script/basic/JDK-8010946.js
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2013, 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-8010946: AccessController.doPrivileged() doesn't work as expected.
|
||||
* This is actually a broader issue of having Dynalink correctly handle
|
||||
* caller-sensitive methods.
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
// This is unprivileged code that loads privileged code.
|
||||
load(__DIR__ + "JDK-8010946-privileged.js")
|
||||
|
||||
try {
|
||||
// This should fail, even though the code itself resides in the
|
||||
// privileged script, as we're invoking it without going through
|
||||
// doPrivileged()
|
||||
print("Attempting unprivileged execution...")
|
||||
executeUnprivileged()
|
||||
print("FAIL: Unprivileged execution succeeded!")
|
||||
} catch(e) {
|
||||
print("Unprivileged execution failed with " + e)
|
||||
}
|
||||
|
||||
print()
|
||||
|
||||
// This should succeed, as it's going through doPrivileged().
|
||||
print("Attempting privileged execution...")
|
||||
executePrivileged()
|
5
nashorn/test/script/basic/JDK-8010946.js.EXPECTED
Normal file
5
nashorn/test/script/basic/JDK-8010946.js.EXPECTED
Normal file
@ -0,0 +1,5 @@
|
||||
Attempting unprivileged execution...
|
||||
Unprivileged execution failed with java.security.AccessControlException: access denied ("java.util.PropertyPermission" "java.security.policy" "read")
|
||||
|
||||
Attempting privileged execution...
|
||||
Successfully retrieved restricted system property.
|
Loading…
x
Reference in New Issue
Block a user