# HG changeset patch # User attila # Date 1372847968 -7200 # Node ID 9bbc4b8832b26334b2819a6f4ba8aa6e033693cf # Parent 3e7bff1b7b59f0961355d533f5c958dac88b7c23 8010946: AccessControl.doPrivileged is broken when called from js script Reviewed-by: jlaskey, sundar diff -r 3e7bff1b7b59 -r 9bbc4b8832b2 nashorn/make/build.xml --- a/nashorn/make/build.xml Wed Jul 03 14:08:00 2013 +0530 +++ b/nashorn/make/build.xml Wed Jul 03 12:39:28 2013 +0200 @@ -235,44 +235,31 @@ - + - - - - - - - +grant codeBase "file:/${basedir}/${nashorn.internal.tests.jar}" { + permission java.security.AllPermission; +}; - - - - - - - +grant codeBase "file:/${basedir}/${file.reference.testng.jar}" { + permission java.security.AllPermission; +}; - - - - - - - +grant codeBase "file:/${basedir}/test/script/trusted/*" { + permission java.security.AllPermission; +}; - - - - - - - - - - - - +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"; +}; + \/ /// diff -r 3e7bff1b7b59 -r 9bbc4b8832b2 nashorn/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java --- a/nashorn/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java Wed Jul 03 14:08:00 2013 +0530 +++ b/nashorn/src/jdk/internal/dynalink/beans/AbstractJavaLinker.java Wed Jul 03 12:39:28 2013 +0200 @@ -86,7 +86,10 @@ 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 @@ * @author Attila Szegedi */ abstract class AbstractJavaLinker implements GuardingDynamicLinker { + final Class clazz; private final MethodHandle classGuard; private final MethodHandle assignableGuard; - private final Map propertyGetters = new HashMap<>(); + private final Map propertyGetters = new HashMap<>(); private final Map propertySetters = new HashMap<>(); private final Map methods = new HashMap<>(); @@ -129,22 +133,19 @@ // 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 @@ 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 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 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 methodMap) { + addMember(name, createDynamicMethod(ao), methodMap); + } + + private void addMember(String name, SingleDynamicMethod method, Map 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 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 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 @@ 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 @@ } } - private GuardedInvocation createGuardedDynamicMethodInvocation(MethodType callSiteType, + private GuardedInvocation createGuardedDynamicMethodInvocation(CallSiteDescriptor callSiteDescriptor, LinkerServices linkerServices, String methodName, Map 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 methodMap) { + private static MethodHandle getDynamicMethodInvocation(CallSiteDescriptor callSiteDescriptor, + LinkerServices linkerServices, String methodName, Map 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 methodMap) { @@ -322,13 +405,13 @@ return dynaMethod != null ? dynaMethod : getExplicitSignatureDynamicMethod(methodName, methodMap); } - private static SimpleDynamicMethod getExplicitSignatureDynamicMethod(String methodName, + private static SingleDynamicMethod getExplicitSignatureDynamicMethod(String methodName, Map 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 @@ 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 @@ 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 @@ 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 ops) throws Exception { @@ -455,16 +536,20 @@ // 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 @@ 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 @@ // 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 @@ // 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 @@ // 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 @@ 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; + } } } diff -r 3e7bff1b7b59 -r 9bbc4b8832b2 nashorn/src/jdk/internal/dynalink/beans/ApplicableOverloadedMethods.java --- a/nashorn/src/jdk/internal/dynalink/beans/ApplicableOverloadedMethods.java Wed Jul 03 14:08:00 2013 +0530 +++ b/nashorn/src/jdk/internal/dynalink/beans/ApplicableOverloadedMethods.java Wed Jul 03 12:39:28 2013 +0200 @@ -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 @@ * @author Attila Szegedi */ class ApplicableOverloadedMethods { - private final List methods; + private final List methods; private final boolean varArgs; /** @@ -106,10 +105,10 @@ * @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 methods, final MethodType callSiteType, + ApplicableOverloadedMethods(final List 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 @@ * * @return list of all methods. */ - List getMethods() { + List getMethods() { return methods; } @@ -131,12 +130,12 @@ * * @return a list of maximally specific methods. */ - List findMaximallySpecificMethods() { + List 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 @@ */ 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 @@ */ 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 @@ */ 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(); diff -r 3e7bff1b7b59 -r 9bbc4b8832b2 nashorn/src/jdk/internal/dynalink/beans/CallerSensitiveDetector.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/src/jdk/internal/dynalink/beans/CallerSensitiveDetector.java Wed Jul 03 12:39:28 2013 +0200 @@ -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 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; + } + } +} diff -r 3e7bff1b7b59 -r 9bbc4b8832b2 nashorn/src/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/src/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java Wed Jul 03 12:39:28 2013 +0200 @@ -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)); + } +} diff -r 3e7bff1b7b59 -r 9bbc4b8832b2 nashorn/src/jdk/internal/dynalink/beans/ClassString.java --- a/nashorn/src/jdk/internal/dynalink/beans/ClassString.java Wed Jul 03 14:08:00 2013 +0530 +++ b/nashorn/src/jdk/internal/dynalink/beans/ClassString.java Wed Jul 03 12:39:28 2013 +0200 @@ -155,8 +155,8 @@ } List getMaximallySpecifics(List 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); } /** diff -r 3e7bff1b7b59 -r 9bbc4b8832b2 nashorn/src/jdk/internal/dynalink/beans/DynamicMethod.java --- a/nashorn/src/jdk/internal/dynalink/beans/DynamicMethod.java Wed Jul 03 14:08:00 2013 +0530 +++ b/nashorn/src/jdk/internal/dynalink/beans/DynamicMethod.java Wed Jul 03 12:39:28 2013 +0200 @@ -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 @@ * 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(); diff -r 3e7bff1b7b59 -r 9bbc4b8832b2 nashorn/src/jdk/internal/dynalink/beans/DynamicMethodLinker.java --- a/nashorn/src/jdk/internal/dynalink/beans/DynamicMethodLinker.java Wed Jul 03 14:08:00 2013 +0530 +++ b/nashorn/src/jdk/internal/dynalink/beans/DynamicMethodLinker.java Wed Jul 03 12:39:28 2013 +0200 @@ -85,12 +85,12 @@ 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 @@ 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; } diff -r 3e7bff1b7b59 -r 9bbc4b8832b2 nashorn/src/jdk/internal/dynalink/beans/FacetIntrospector.java --- a/nashorn/src/jdk/internal/dynalink/beans/FacetIntrospector.java Wed Jul 03 14:08:00 2013 +0530 +++ b/nashorn/src/jdk/internal/dynalink/beans/FacetIntrospector.java Wed Jul 03 12:39:28 2013 +0200 @@ -167,10 +167,6 @@ 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 diff -r 3e7bff1b7b59 -r 9bbc4b8832b2 nashorn/src/jdk/internal/dynalink/beans/MaximallySpecific.java --- a/nashorn/src/jdk/internal/dynalink/beans/MaximallySpecific.java Wed Jul 03 14:08:00 2013 +0530 +++ b/nashorn/src/jdk/internal/dynalink/beans/MaximallySpecific.java Wed Jul 03 12:39:28 2013 +0200 @@ -105,10 +105,58 @@ * @param varArgs whether to assume the methods are varargs * @return the list of maximally specific methods. */ - static List getMaximallySpecificMethods(List methods, boolean varArgs) { - return getMaximallySpecificMethods(methods, varArgs, null, null); + static List getMaximallySpecificMethods(List methods, boolean varArgs) { + return getMaximallySpecificSingleDynamicMethods(methods, varArgs, null, null); + } + + private abstract static class MethodTypeGetter { + abstract MethodType getMethodType(T t); } + private static final MethodTypeGetter METHOD_HANDLE_TYPE_GETTER = + new MethodTypeGetter() { + @Override + MethodType getMethodType(MethodHandle t) { + return t.type(); + } + }; + + private static final MethodTypeGetter DYNAMIC_METHOD_TYPE_GETTER = + new MethodTypeGetter() { + @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 getMaximallySpecificMethodHandles(List 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 getMaximallySpecificSingleDynamicMethods(List 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 @@ * @param argTypes concrete argument types for the invocation * @return the list of maximally specific methods. */ - static List getMaximallySpecificMethods(List methods, boolean varArgs, - Class[] argTypes, LinkerServices ls) { + private static List getMaximallySpecificMethods(List methods, boolean varArgs, + Class[] argTypes, LinkerServices ls, MethodTypeGetter methodTypeGetter) { if(methods.size() < 2) { return methods; } - final LinkedList maximals = new LinkedList<>(); - for(MethodHandle m: methods) { - final MethodType methodType = m.type(); + final LinkedList maximals = new LinkedList<>(); + for(T m: methods) { + final MethodType methodType = methodTypeGetter.getMethodType(m); boolean lessSpecific = false; - for(Iterator maximal = maximals.iterator(); maximal.hasNext();) { - final MethodHandle max = maximal.next(); - switch(isMoreSpecific(methodType, max.type(), varArgs, argTypes, ls)) { + for(Iterator 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; diff -r 3e7bff1b7b59 -r 9bbc4b8832b2 nashorn/src/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java --- a/nashorn/src/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java Wed Jul 03 14:08:00 2013 +0530 +++ b/nashorn/src/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java Wed Jul 03 12:39:28 2013 +0200 @@ -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 @@ /** * Holds a list of all methods. */ - private final LinkedList methods; + private final LinkedList methods; private final ClassLoader classLoader; /** @@ -111,21 +116,22 @@ * @param name the name of the method */ OverloadedDynamicMethod(Class clazz, String name) { - this(new LinkedList(), clazz.getClassLoader(), getClassAndMethodName(clazz, name)); + this(new LinkedList(), clazz.getClassLoader(), getClassAndMethodName(clazz, name)); } - private OverloadedDynamicMethod(LinkedList methods, ClassLoader classLoader, String name) { + private OverloadedDynamicMethod(LinkedList methods, ClassLoader classLoader, String name) { super(name); this.methods = methods; this.classLoader = classLoader; } @Override - SimpleDynamicMethod getMethodForExactParamTypes(String paramTypes) { - final LinkedList matchingMethods = new LinkedList<>(); - for(MethodHandle method: methods) { - if(typeMatchesDescription(paramTypes, method.type())) { - matchingMethods.add(method); + SingleDynamicMethod getMethodForExactParamTypes(String paramTypes) { + final LinkedList 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 @@ 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 @@ } @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 @@ ApplicableOverloadedMethods.APPLICABLE_BY_VARIABLE_ARITY); // Find the methods that are maximally specific based on the call site signature - List maximallySpecifics = subtypingApplicables.findMaximallySpecificMethods(); + List maximallySpecifics = subtypingApplicables.findMaximallySpecificMethods(); if(maximallySpecifics.isEmpty()) { maximallySpecifics = methodInvocationApplicables.findMaximallySpecificMethods(); if(maximallySpecifics.isEmpty()) { @@ -171,12 +177,12 @@ // (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 invokables = (List)methods.clone(); + final List invokables = (List)methods.clone(); invokables.removeAll(subtypingApplicables.getMethods()); invokables.removeAll(methodInvocationApplicables.getMethods()); invokables.removeAll(variableArityApplicables.getMethods()); - for(final Iterator it = invokables.iterator(); it.hasNext();) { - final MethodHandle m = it.next(); + for(final Iterator it = invokables.iterator(); it.hasNext();) { + final SingleDynamicMethod m = it.next(); if(!isApplicableDynamically(linkerServices, callSiteType, m)) { it.remove(); } @@ -199,54 +205,45 @@ } 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 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(); @@ -301,20 +298,11 @@ } /** - * 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); } } diff -r 3e7bff1b7b59 -r 9bbc4b8832b2 nashorn/src/jdk/internal/dynalink/beans/OverloadedMethod.java --- a/nashorn/src/jdk/internal/dynalink/beans/OverloadedMethod.java Wed Jul 03 14:08:00 2013 +0530 +++ b/nashorn/src/jdk/internal/dynalink/beans/OverloadedMethod.java Wed Jul 03 12:39:28 2013 +0200 @@ -135,7 +135,7 @@ 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 @@ break; } case 1: { - method = new SimpleDynamicMethod(methods.get(0)).getInvocation(callSiteType, linkerServices); + method = SingleDynamicMethod.getInvocation(methods.get(0), callSiteType, linkerServices); break; } default: { diff -r 3e7bff1b7b59 -r 9bbc4b8832b2 nashorn/src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java --- a/nashorn/src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java Wed Jul 03 14:08:00 2013 +0530 +++ b/nashorn/src/jdk/internal/dynalink/beans/SimpleDynamicMethod.java Wed Jul 03 12:39:28 2013 +0200 @@ -84,29 +84,22 @@ 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 @@ * @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)); - } - - 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); - } - - /** - * Returns the target of this dynamic method - * - * @return the target of this dynamic method - */ - MethodHandle getTarget() { - return target; + return getMethodNameWithSignature(target.type(), getClassAndMethodName(clazz, name)); } @Override - SimpleDynamicMethod getMethodForExactParamTypes(String paramTypes) { - return typeMatchesDescription(paramTypes, target.type()) ? this : null; + boolean isVarArgs() { + return target.isVarargsCollector(); } @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); + MethodType getMethodType() { + return target.type(); } @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); + MethodHandle getTarget(Lookup lookup) { + return target; } } diff -r 3e7bff1b7b59 -r 9bbc4b8832b2 nashorn/src/jdk/internal/dynalink/beans/SingleDynamicMethod.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nashorn/src/jdk/internal/dynalink/beans/SingleDynamicMethod.java Wed Jul 03 12:39:28 2013 +0200 @@ -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()); + } +} diff -r 3e7bff1b7b59 -r 9bbc4b8832b2 nashorn/src/jdk/internal/dynalink/beans/StaticClassIntrospector.java --- a/nashorn/src/jdk/internal/dynalink/beans/StaticClassIntrospector.java Wed Jul 03 14:08:00 2013 +0530 +++ b/nashorn/src/jdk/internal/dynalink/beans/StaticClassIntrospector.java Wed Jul 03 12:39:28 2013 +0200 @@ -106,10 +106,18 @@ @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()) { diff -r 3e7bff1b7b59 -r 9bbc4b8832b2 nashorn/src/jdk/internal/dynalink/beans/StaticClassLinker.java --- a/nashorn/src/jdk/internal/dynalink/beans/StaticClassLinker.java Wed Jul 03 14:08:00 2013 +0530 +++ b/nashorn/src/jdk/internal/dynalink/beans/StaticClassLinker.java Wed Jul 03 12:39:28 2013 +0200 @@ -87,9 +87,7 @@ 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 @@ 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, ""); + return new SimpleDynamicMethod(StaticClassIntrospector.editConstructorMethodHandle( + boundArrayCtor.asType(boundArrayCtor.type().changeReturnType(clazz))), clazz, ""); } - final Constructor[] ctrs = clazz.getConstructors(); - final List mhs = new ArrayList<>(ctrs.length); - for(int i = 0; i < ctrs.length; ++i) { - mhs.add(drop(SafeUnreflector.unreflectConstructor(ctrs[i]))); - } - return createDynamicMethod(mhs, clazz, ""); - } - - private static MethodHandle drop(MethodHandle mh) { - return StaticClassIntrospector.dropReceiver(mh, StaticClass.class); + return createDynamicMethod(Arrays.asList(clazz.getConstructors()), clazz, ""); } @Override @@ -161,11 +150,10 @@ } 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; diff -r 3e7bff1b7b59 -r 9bbc4b8832b2 nashorn/src/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java --- a/nashorn/src/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java Wed Jul 03 14:08:00 2013 +0530 +++ b/nashorn/src/jdk/internal/dynalink/support/AbstractCallSiteDescriptor.java Wed Jul 03 12:39:28 2013 +0200 @@ -139,8 +139,9 @@ @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(); } diff -r 3e7bff1b7b59 -r 9bbc4b8832b2 nashorn/src/jdk/internal/dynalink/support/Lookup.java --- a/nashorn/src/jdk/internal/dynalink/support/Lookup.java Wed Jul 03 14:08:00 2013 +0530 +++ b/nashorn/src/jdk/internal/dynalink/support/Lookup.java Wed Jul 03 12:39:28 2013 +0200 @@ -122,6 +122,18 @@ * @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 @@ } } - /** * Performs a {@link java.lang.invoke.MethodHandles.Lookup#unreflectGetter(Field)}, converting any encountered * {@link IllegalAccessException} into an {@link IllegalAccessError}. @@ -202,6 +213,18 @@ * @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) { diff -r 3e7bff1b7b59 -r 9bbc4b8832b2 nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Wed Jul 03 14:08:00 2013 +0530 +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Wed Jul 03 12:39:28 2013 +0200 @@ -78,7 +78,7 @@ * @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 @@ 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 Dynalink User Guide, - * 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 + * Dynalink User Guide, but we'll show few + * examples here: *
    *
  • Get a named property with fixed name: *
    @@ -196,7 +196,7 @@
         }
     
         /**
    -     * 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 @@
          * @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();
         }
     
         /**
    diff -r 3e7bff1b7b59 -r 9bbc4b8832b2 nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java
    --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java	Wed Jul 03 14:08:00 2013 +0530
    +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java	Wed Jul 03 12:39:28 2013 +0200
    @@ -28,6 +28,7 @@
     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.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 @@
             return AccessController.doPrivileged(new PrivilegedExceptionAction() {
                 @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);
                 }
             });
         }
    diff -r 3e7bff1b7b59 -r 9bbc4b8832b2 nashorn/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java
    --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java	Wed Jul 03 14:08:00 2013 +0530
    +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java	Wed Jul 03 12:39:28 2013 +0200
    @@ -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 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 @@
          * @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);
    diff -r 3e7bff1b7b59 -r 9bbc4b8832b2 nashorn/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java
    --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java	Wed Jul 03 14:08:00 2013 +0530
    +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java	Wed Jul 03 12:39:28 2013 +0200
    @@ -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 @@
          * set. */
         public static final int CALLSITE_TRACE_SCOPE      = 0x200;
     
    -    private static final WeakHashMap> canonicals =
    -            new WeakHashMap<>();
    +    private static final ClassValue> canonicals =
    +            new ClassValue>() {
    +        @Override
    +        protected ConcurrentMap 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 @@
         /**
          * 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 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 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;
    @@ -142,6 +147,11 @@
         }
     
         @Override
    +    public Lookup getLookup() {
    +        return lookup;
    +    }
    +
    +    @Override
         public boolean equals(final CallSiteDescriptor csd) {
             return super.equals(csd) && flags == getFlags(csd);
         }
    @@ -279,6 +289,6 @@
     
         @Override
         public CallSiteDescriptor changeMethodType(final MethodType newMethodType) {
    -        return get(operator, operand, newMethodType, flags);
    +        return get(getLookup(), operator, operand, newMethodType, flags);
         }
     }
    diff -r 3e7bff1b7b59 -r 9bbc4b8832b2 nashorn/test/script/basic/JDK-8010946-2.js
    --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    +++ b/nashorn/test/script/basic/JDK-8010946-2.js	Wed Jul 03 12:39:28 2013 +0200
    @@ -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)"])
    diff -r 3e7bff1b7b59 -r 9bbc4b8832b2 nashorn/test/script/basic/JDK-8010946-2.js.EXPECTED
    --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    +++ b/nashorn/test/script/basic/JDK-8010946-2.js.EXPECTED	Wed Jul 03 12:39:28 2013 +0200
    @@ -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)]
    diff -r 3e7bff1b7b59 -r 9bbc4b8832b2 nashorn/test/script/basic/JDK-8010946-privileged.js
    --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    +++ b/nashorn/test/script/basic/JDK-8010946-privileged.js	Wed Jul 03 12:39:28 2013 +0200
    @@ -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)
    +    }
    +})();
    diff -r 3e7bff1b7b59 -r 9bbc4b8832b2 nashorn/test/script/basic/JDK-8010946.js
    --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    +++ b/nashorn/test/script/basic/JDK-8010946.js	Wed Jul 03 12:39:28 2013 +0200
    @@ -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()
    diff -r 3e7bff1b7b59 -r 9bbc4b8832b2 nashorn/test/script/basic/JDK-8010946.js.EXPECTED
    --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    +++ b/nashorn/test/script/basic/JDK-8010946.js.EXPECTED	Wed Jul 03 12:39:28 2013 +0200
    @@ -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.