8010946: AccessControl.doPrivileged is broken when called from js script

Reviewed-by: jlaskey, sundar
This commit is contained in:
Attila Szegedi 2013-07-03 12:39:28 +02:00
parent 6dfb638284
commit 92bcfea39a
27 changed files with 1133 additions and 403 deletions

@ -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 &quot;file:/${basedir}/${nashorn.internal.tests.jar}&quot; {" 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 &quot;file:/${basedir}/${file.reference.testng.jar}&quot; {" 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 &quot;file:/${basedir}/test/script/trusted/*&quot; {" 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 &quot;file:/${basedir}/test/script/basic/*&quot; {" 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 &quot;${basedir}/test/script/-&quot;, &quot;read&quot;;" file="${build.dir}/nashorn.policy" append="true"/>
<echo message=" permission java.io.FilePermission &quot;user.dir&quot;, &quot;read&quot;;" file="${build.dir}/nashorn.policy" append="true"/>
<echo message=" permission java.util.PropertyPermission &quot;user.dir&quot;, &quot;read&quot;;" 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 &quot;nashorn.test.*&quot;, &quot;read&quot;;" 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);
}
}

@ -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);
}
}

@ -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)"])

@ -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)]

@ -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)
}
})();

@ -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()

@ -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.