Merge
This commit is contained in:
commit
1884df90bb
nashorn
src/jdk.scripting.nashorn/share/classes/jdk
internal/dynalink
nashorn/internal/runtime
test
script/basic
src/jdk/nashorn
7
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/AbstractJavaLinker.java
7
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/AbstractJavaLinker.java
@ -491,8 +491,9 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
|||||||
|
|
||||||
// We want setters that conform to "Object(O, V)". Note, we aren't doing "R(O, V)" as it might not be
|
// We want setters that conform to "Object(O, V)". Note, we aren't doing "R(O, V)" as it might not be
|
||||||
// valid for us to convert return values proactively. Also, since we don't know what setters will be
|
// valid for us to convert return values proactively. Also, since we don't know what setters will be
|
||||||
// invoked, we'll conservatively presume Object return type.
|
// invoked, we'll conservatively presume Object return type. The one exception is void return.
|
||||||
final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class);
|
final MethodType origType = callSiteDescriptor.getMethodType();
|
||||||
|
final MethodType type = origType.returnType() == void.class ? origType : origType.changeReturnType(Object.class);
|
||||||
|
|
||||||
// What's below is basically:
|
// What's below is basically:
|
||||||
// foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation),
|
// foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation),
|
||||||
@ -508,7 +509,7 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
|||||||
// Bind property setter handle to the expected setter type and linker services. Type is
|
// Bind property setter handle to the expected setter type and linker services. Type is
|
||||||
// MethodHandle(Object, String, Object)
|
// MethodHandle(Object, String, Object)
|
||||||
final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0,
|
final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0,
|
||||||
CallSiteDescriptorFactory.dropParameterTypes(callSiteDescriptor, 1, 2), linkerServices);
|
callSiteDescriptor.changeMethodType(setterType), linkerServices);
|
||||||
|
|
||||||
// Cast getter to MethodHandle(O, N, V)
|
// Cast getter to MethodHandle(O, N, V)
|
||||||
final MethodHandle typedGetter = linkerServices.asType(boundGetter, type.changeReturnType(
|
final MethodHandle typedGetter = linkerServices.asType(boundGetter, type.changeReturnType(
|
||||||
|
@ -123,7 +123,6 @@ class OverloadedMethod {
|
|||||||
varArgMethods = new ArrayList<>(methodHandles.size());
|
varArgMethods = new ArrayList<>(methodHandles.size());
|
||||||
final int argNum = callSiteType.parameterCount();
|
final int argNum = callSiteType.parameterCount();
|
||||||
for(MethodHandle mh: methodHandles) {
|
for(MethodHandle mh: methodHandles) {
|
||||||
mh = mh.asType(mh.type().changeReturnType(commonRetType));
|
|
||||||
if(mh.isVarargsCollector()) {
|
if(mh.isVarargsCollector()) {
|
||||||
final MethodHandle asFixed = mh.asFixedArity();
|
final MethodHandle asFixed = mh.asFixedArity();
|
||||||
if(argNum == asFixed.type().parameterCount()) {
|
if(argNum == asFixed.type().parameterCount()) {
|
||||||
|
@ -118,17 +118,13 @@ public class TypeUtilities {
|
|||||||
public static Class<?> getCommonLosslessConversionType(final Class<?> c1, final Class<?> c2) {
|
public static Class<?> getCommonLosslessConversionType(final Class<?> c1, final Class<?> c2) {
|
||||||
if(c1 == c2) {
|
if(c1 == c2) {
|
||||||
return c1;
|
return c1;
|
||||||
|
} else if (c1 == void.class || c2 == void.class) {
|
||||||
|
return Object.class;
|
||||||
} else if(isConvertibleWithoutLoss(c2, c1)) {
|
} else if(isConvertibleWithoutLoss(c2, c1)) {
|
||||||
return c1;
|
return c1;
|
||||||
} else if(isConvertibleWithoutLoss(c1, c2)) {
|
} else if(isConvertibleWithoutLoss(c1, c2)) {
|
||||||
return c2;
|
return c2;
|
||||||
}
|
} else if(c1.isPrimitive() && c2.isPrimitive()) {
|
||||||
if(c1 == void.class) {
|
|
||||||
return c2;
|
|
||||||
} else if(c2 == void.class) {
|
|
||||||
return c1;
|
|
||||||
}
|
|
||||||
if(c1.isPrimitive() && c2.isPrimitive()) {
|
|
||||||
if((c1 == byte.class && c2 == char.class) || (c1 == char.class && c2 == byte.class)) {
|
if((c1 == byte.class && c2 == char.class) || (c1 == char.class && c2 == byte.class)) {
|
||||||
// byte + char = int
|
// byte + char = int
|
||||||
return int.class;
|
return int.class;
|
||||||
@ -268,20 +264,24 @@ public class TypeUtilities {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether a type can be converted to another without losing any
|
* Determines whether a type can be converted to another without losing any precision. As a special case,
|
||||||
* precision.
|
* void is considered convertible only to Object and void, while anything can be converted to void. This
|
||||||
|
* is because a target type of void means we don't care about the value, so the conversion is always
|
||||||
|
* permissible.
|
||||||
*
|
*
|
||||||
* @param sourceType the source type
|
* @param sourceType the source type
|
||||||
* @param targetType the target type
|
* @param targetType the target type
|
||||||
* @return true if lossless conversion is possible
|
* @return true if lossless conversion is possible
|
||||||
*/
|
*/
|
||||||
public static boolean isConvertibleWithoutLoss(final Class<?> sourceType, final Class<?> targetType) {
|
public static boolean isConvertibleWithoutLoss(final Class<?> sourceType, final Class<?> targetType) {
|
||||||
if(targetType.isAssignableFrom(sourceType)) {
|
if(targetType.isAssignableFrom(sourceType) || targetType == void.class) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if(sourceType.isPrimitive()) {
|
if(sourceType.isPrimitive()) {
|
||||||
if(sourceType == void.class) {
|
if(sourceType == void.class) {
|
||||||
return false; // Void can't be losslessly represented by any type
|
// Void should be losslessly representable by Object, either as null or as a custom value that
|
||||||
|
// can be set with DynamicLinkerFactory.setAutoConversionStrategy.
|
||||||
|
return targetType == Object.class;
|
||||||
}
|
}
|
||||||
if(targetType.isPrimitive()) {
|
if(targetType.isPrimitive()) {
|
||||||
return isProperPrimitiveLosslessSubtype(sourceType, targetType);
|
return isProperPrimitiveLosslessSubtype(sourceType, targetType);
|
||||||
|
@ -703,7 +703,7 @@ public final class Context {
|
|||||||
final ScriptFunction func = getProgramFunction(clazz, scope);
|
final ScriptFunction func = getProgramFunction(clazz, scope);
|
||||||
Object evalThis;
|
Object evalThis;
|
||||||
if (directEval) {
|
if (directEval) {
|
||||||
evalThis = callThis instanceof ScriptObject || strictFlag ? callThis : global;
|
evalThis = (callThis != UNDEFINED && callThis != null) || strictFlag ? callThis : global;
|
||||||
} else {
|
} else {
|
||||||
evalThis = global;
|
evalThis = global;
|
||||||
}
|
}
|
||||||
|
8
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/Bootstrap.java
8
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/Bootstrap.java
@ -68,6 +68,8 @@ public final class Bootstrap {
|
|||||||
|
|
||||||
private static final MethodHandleFunctionality MH = MethodHandleFactory.getFunctionality();
|
private static final MethodHandleFunctionality MH = MethodHandleFactory.getFunctionality();
|
||||||
|
|
||||||
|
private static final MethodHandle VOID_TO_OBJECT = MH.constant(Object.class, ScriptRuntime.UNDEFINED);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default dynalink relink threshold for megamorphisism is 8. In the case
|
* The default dynalink relink threshold for megamorphisism is 8. In the case
|
||||||
* of object fields only, it is fine. However, with dual fields, in order to get
|
* of object fields only, it is fine. However, with dual fields, in order to get
|
||||||
@ -189,7 +191,7 @@ public final class Bootstrap {
|
|||||||
* @return true if the obj is an instance of @FunctionalInterface interface
|
* @return true if the obj is an instance of @FunctionalInterface interface
|
||||||
*/
|
*/
|
||||||
public static boolean isFunctionalInterfaceObject(final Object obj) {
|
public static boolean isFunctionalInterfaceObject(final Object obj) {
|
||||||
return !JSType.isPrimitive(obj) && (NashornBottomLinker.getFunctionalInterfaceMethod(obj.getClass()) != null);
|
return !JSType.isPrimitive(obj) && (NashornBeansLinker.getFunctionalInterfaceMethod(obj.getClass()) != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -481,14 +483,16 @@ public final class Bootstrap {
|
|||||||
private static MethodHandle unboxReturnType(final MethodHandle target, final MethodType newType) {
|
private static MethodHandle unboxReturnType(final MethodHandle target, final MethodType newType) {
|
||||||
final MethodType targetType = target.type();
|
final MethodType targetType = target.type();
|
||||||
final Class<?> oldReturnType = targetType.returnType();
|
final Class<?> oldReturnType = targetType.returnType();
|
||||||
|
final Class<?> newReturnType = newType.returnType();
|
||||||
if (TypeUtilities.isWrapperType(oldReturnType)) {
|
if (TypeUtilities.isWrapperType(oldReturnType)) {
|
||||||
final Class<?> newReturnType = newType.returnType();
|
|
||||||
if (newReturnType.isPrimitive()) {
|
if (newReturnType.isPrimitive()) {
|
||||||
// The contract of setAutoConversionStrategy is such that the difference between newType and targetType
|
// The contract of setAutoConversionStrategy is such that the difference between newType and targetType
|
||||||
// can only be JLS method invocation conversions.
|
// can only be JLS method invocation conversions.
|
||||||
assert TypeUtilities.isMethodInvocationConvertible(oldReturnType, newReturnType);
|
assert TypeUtilities.isMethodInvocationConvertible(oldReturnType, newReturnType);
|
||||||
return MethodHandles.explicitCastArguments(target, targetType.changeReturnType(newReturnType));
|
return MethodHandles.explicitCastArguments(target, targetType.changeReturnType(newReturnType));
|
||||||
}
|
}
|
||||||
|
} else if (oldReturnType == void.class && newReturnType == Object.class) {
|
||||||
|
return MethodHandles.filterReturnValue(target, VOID_TO_OBJECT);
|
||||||
}
|
}
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
@ -25,20 +25,29 @@
|
|||||||
|
|
||||||
package jdk.nashorn.internal.runtime.linker;
|
package jdk.nashorn.internal.runtime.linker;
|
||||||
|
|
||||||
|
import static jdk.nashorn.internal.lookup.Lookup.MH;
|
||||||
|
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandle;
|
import java.lang.invoke.MethodHandle;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.lang.invoke.MethodType;
|
import java.lang.invoke.MethodType;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import jdk.internal.dynalink.CallSiteDescriptor;
|
||||||
import jdk.internal.dynalink.beans.BeansLinker;
|
import jdk.internal.dynalink.beans.BeansLinker;
|
||||||
import jdk.internal.dynalink.linker.ConversionComparator.Comparison;
|
import jdk.internal.dynalink.linker.ConversionComparator.Comparison;
|
||||||
import jdk.internal.dynalink.linker.GuardedInvocation;
|
import jdk.internal.dynalink.linker.GuardedInvocation;
|
||||||
import jdk.internal.dynalink.linker.GuardingDynamicLinker;
|
import jdk.internal.dynalink.linker.GuardingDynamicLinker;
|
||||||
import jdk.internal.dynalink.linker.LinkRequest;
|
import jdk.internal.dynalink.linker.LinkRequest;
|
||||||
import jdk.internal.dynalink.linker.LinkerServices;
|
import jdk.internal.dynalink.linker.LinkerServices;
|
||||||
|
import jdk.internal.dynalink.support.Guards;
|
||||||
import jdk.internal.dynalink.support.Lookup;
|
import jdk.internal.dynalink.support.Lookup;
|
||||||
import jdk.nashorn.api.scripting.ScriptUtils;
|
import jdk.nashorn.api.scripting.ScriptUtils;
|
||||||
import jdk.nashorn.internal.objects.NativeArray;
|
import jdk.nashorn.internal.objects.NativeArray;
|
||||||
import jdk.nashorn.internal.runtime.ConsString;
|
import jdk.nashorn.internal.runtime.ConsString;
|
||||||
|
import jdk.nashorn.internal.runtime.Context;
|
||||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||||
|
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||||
import jdk.nashorn.internal.runtime.options.Options;
|
import jdk.nashorn.internal.runtime.options.Options;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,19 +77,49 @@ public class NashornBeansLinker implements GuardingDynamicLinker {
|
|||||||
FILTER_CONSSTRING = lookup.findOwnStatic("consStringFilter", Object.class, Object.class);
|
FILTER_CONSSTRING = lookup.findOwnStatic("consStringFilter", Object.class, Object.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cache of @FunctionalInterface method of implementor classes
|
||||||
|
private static final ClassValue<Method> FUNCTIONAL_IFACE_METHOD = new ClassValue<Method>() {
|
||||||
|
@Override
|
||||||
|
protected Method computeValue(final Class<?> type) {
|
||||||
|
return findFunctionalInterfaceMethod(type);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private final BeansLinker beansLinker = new BeansLinker();
|
private final BeansLinker beansLinker = new BeansLinker();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
|
public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
|
||||||
if (linkRequest.getReceiver() instanceof ConsString) {
|
final Object self = linkRequest.getReceiver();
|
||||||
|
final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor();
|
||||||
|
if (self instanceof ConsString) {
|
||||||
// In order to treat ConsString like a java.lang.String we need a link request with a string receiver.
|
// In order to treat ConsString like a java.lang.String we need a link request with a string receiver.
|
||||||
final Object[] arguments = linkRequest.getArguments();
|
final Object[] arguments = linkRequest.getArguments();
|
||||||
arguments[0] = "";
|
arguments[0] = "";
|
||||||
final LinkRequest forgedLinkRequest = linkRequest.replaceArguments(linkRequest.getCallSiteDescriptor(), arguments);
|
final LinkRequest forgedLinkRequest = linkRequest.replaceArguments(desc, arguments);
|
||||||
final GuardedInvocation invocation = getGuardedInvocation(beansLinker, forgedLinkRequest, linkerServices);
|
final GuardedInvocation invocation = getGuardedInvocation(beansLinker, forgedLinkRequest, linkerServices);
|
||||||
// If an invocation is found we add a filter that makes it work for both Strings and ConsStrings.
|
// If an invocation is found we add a filter that makes it work for both Strings and ConsStrings.
|
||||||
return invocation == null ? null : invocation.filterArguments(0, FILTER_CONSSTRING);
|
return invocation == null ? null : invocation.filterArguments(0, FILTER_CONSSTRING);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (self != null && "call".equals(desc.getNameToken(CallSiteDescriptor.OPERATOR))) {
|
||||||
|
// Support dyn:call on any object that supports some @FunctionalInterface
|
||||||
|
// annotated interface. This way Java method, constructor references or
|
||||||
|
// implementations of java.util.function.* interfaces can be called as though
|
||||||
|
// those are script functions.
|
||||||
|
final Method m = getFunctionalInterfaceMethod(self.getClass());
|
||||||
|
if (m != null) {
|
||||||
|
final MethodType callType = desc.getMethodType();
|
||||||
|
// 'callee' and 'thiz' passed from script + actual arguments
|
||||||
|
if (callType.parameterCount() != m.getParameterCount() + 2) {
|
||||||
|
throw typeError("no.method.matches.args", ScriptRuntime.safeToString(self));
|
||||||
|
}
|
||||||
|
return new GuardedInvocation(
|
||||||
|
// drop 'thiz' passed from the script.
|
||||||
|
MH.dropArguments(desc.getLookup().unreflect(m), 1, callType.parameterType(1)),
|
||||||
|
Guards.getInstanceOfGuard(m.getDeclaringClass())).asTypeSafeReturn(
|
||||||
|
new NashornBeansLinkerServices(linkerServices), callType);
|
||||||
|
}
|
||||||
|
}
|
||||||
return getGuardedInvocation(beansLinker, linkRequest, linkerServices);
|
return getGuardedInvocation(beansLinker, linkRequest, linkerServices);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,6 +176,38 @@ public class NashornBeansLinker implements GuardingDynamicLinker {
|
|||||||
return arg instanceof ConsString ? arg.toString() : arg;
|
return arg instanceof ConsString ? arg.toString() : arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Method findFunctionalInterfaceMethod(final Class<?> clazz) {
|
||||||
|
if (clazz == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final Class<?> iface : clazz.getInterfaces()) {
|
||||||
|
// check accessiblity up-front
|
||||||
|
if (! Context.isAccessibleClass(iface)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for @FunctionalInterface
|
||||||
|
if (iface.isAnnotationPresent(FunctionalInterface.class)) {
|
||||||
|
// return the first abstract method
|
||||||
|
for (final Method m : iface.getMethods()) {
|
||||||
|
if (Modifier.isAbstract(m.getModifiers())) {
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// did not find here, try super class
|
||||||
|
return findFunctionalInterfaceMethod(clazz.getSuperclass());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns @FunctionalInterface annotated interface's single abstract
|
||||||
|
// method. If not found, returns null.
|
||||||
|
static Method getFunctionalInterfaceMethod(final Class<?> clazz) {
|
||||||
|
return FUNCTIONAL_IFACE_METHOD.get(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
private static class NashornBeansLinkerServices implements LinkerServices {
|
private static class NashornBeansLinkerServices implements LinkerServices {
|
||||||
private final LinkerServices linkerServices;
|
private final LinkerServices linkerServices;
|
||||||
|
|
||||||
|
@ -30,9 +30,6 @@ import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
|
|||||||
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
|
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandle;
|
import java.lang.invoke.MethodHandle;
|
||||||
import java.lang.invoke.MethodType;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import jdk.internal.dynalink.CallSiteDescriptor;
|
import jdk.internal.dynalink.CallSiteDescriptor;
|
||||||
@ -45,7 +42,6 @@ import jdk.internal.dynalink.linker.LinkRequest;
|
|||||||
import jdk.internal.dynalink.linker.LinkerServices;
|
import jdk.internal.dynalink.linker.LinkerServices;
|
||||||
import jdk.internal.dynalink.support.Guards;
|
import jdk.internal.dynalink.support.Guards;
|
||||||
import jdk.nashorn.internal.codegen.types.Type;
|
import jdk.nashorn.internal.codegen.types.Type;
|
||||||
import jdk.nashorn.internal.runtime.Context;
|
|
||||||
import jdk.nashorn.internal.runtime.JSType;
|
import jdk.nashorn.internal.runtime.JSType;
|
||||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||||
import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
|
import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
|
||||||
@ -95,22 +91,6 @@ final class NashornBottomLinker implements GuardingDynamicLinker, GuardingTypeCo
|
|||||||
}
|
}
|
||||||
throw typeError("not.a.function", ScriptRuntime.safeToString(self));
|
throw typeError("not.a.function", ScriptRuntime.safeToString(self));
|
||||||
case "call":
|
case "call":
|
||||||
// Support dyn:call on any object that supports some @FunctionalInterface
|
|
||||||
// annotated interface. This way Java method, constructor references or
|
|
||||||
// implementations of java.util.function.* interfaces can be called as though
|
|
||||||
// those are script functions.
|
|
||||||
final Method m = getFunctionalInterfaceMethod(self.getClass());
|
|
||||||
if (m != null) {
|
|
||||||
final MethodType callType = desc.getMethodType();
|
|
||||||
// 'callee' and 'thiz' passed from script + actual arguments
|
|
||||||
if (callType.parameterCount() != m.getParameterCount() + 2) {
|
|
||||||
throw typeError("no.method.matches.args", ScriptRuntime.safeToString(self));
|
|
||||||
}
|
|
||||||
return Bootstrap.asTypeSafeReturn(new GuardedInvocation(
|
|
||||||
// drop 'thiz' passed from the script.
|
|
||||||
MH.dropArguments(desc.getLookup().unreflect(m), 1, callType.parameterType(1)),
|
|
||||||
Guards.getInstanceOfGuard(m.getDeclaringClass())), linkerServices, desc);
|
|
||||||
}
|
|
||||||
if(BeansLinker.isDynamicConstructor(self)) {
|
if(BeansLinker.isDynamicConstructor(self)) {
|
||||||
throw typeError("constructor.requires.new", ScriptRuntime.safeToString(self));
|
throw typeError("constructor.requires.new", ScriptRuntime.safeToString(self));
|
||||||
}
|
}
|
||||||
@ -218,44 +198,4 @@ final class NashornBottomLinker implements GuardingDynamicLinker, GuardingTypeCo
|
|||||||
}
|
}
|
||||||
return ScriptRuntime.safeToString(linkRequest.getArguments()[1]);
|
return ScriptRuntime.safeToString(linkRequest.getArguments()[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// cache of @FunctionalInterface method of implementor classes
|
|
||||||
private static final ClassValue<Method> FUNCTIONAL_IFACE_METHOD = new ClassValue<Method>() {
|
|
||||||
@Override
|
|
||||||
protected Method computeValue(final Class<?> type) {
|
|
||||||
return findFunctionalInterfaceMethod(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Method findFunctionalInterfaceMethod(final Class<?> clazz) {
|
|
||||||
if (clazz == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (final Class<?> iface : clazz.getInterfaces()) {
|
|
||||||
// check accessiblity up-front
|
|
||||||
if (! Context.isAccessibleClass(iface)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for @FunctionalInterface
|
|
||||||
if (iface.isAnnotationPresent(FunctionalInterface.class)) {
|
|
||||||
// return the first abstract method
|
|
||||||
for (final Method m : iface.getMethods()) {
|
|
||||||
if (Modifier.isAbstract(m.getModifiers())) {
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// did not find here, try super class
|
|
||||||
return findFunctionalInterfaceMethod(clazz.getSuperclass());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Returns @FunctionalInterface annotated interface's single abstract
|
|
||||||
// method. If not found, returns null.
|
|
||||||
static Method getFunctionalInterfaceMethod(final Class<?> clazz) {
|
|
||||||
return FUNCTIONAL_IFACE_METHOD.get(clazz);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ bean.readWrite: 17
|
|||||||
bean.readWrite = 18: 18
|
bean.readWrite = 18: 18
|
||||||
obj1.readWrite: 18
|
obj1.readWrite: 18
|
||||||
obj1.getReadWrite(): 18
|
obj1.getReadWrite(): 18
|
||||||
obj1.setReadWrite(19): null
|
obj1.setReadWrite(19): undefined
|
||||||
obj1.readWrite: 19
|
obj1.readWrite: 19
|
||||||
bean.readWrite: 19
|
bean.readWrite: 19
|
||||||
|
|
||||||
@ -52,7 +52,7 @@ PropertyBind.staticReadWrite: 25
|
|||||||
PropertyBind.staticReadWrite = 26: 26
|
PropertyBind.staticReadWrite = 26: 26
|
||||||
obj2.staticReadWrite: 26
|
obj2.staticReadWrite: 26
|
||||||
obj2.getStaticReadWrite(): 26
|
obj2.getStaticReadWrite(): 26
|
||||||
obj2.setStaticReadWrite(27): null
|
obj2.setStaticReadWrite(27): undefined
|
||||||
obj2.staticReadWrite: 27
|
obj2.staticReadWrite: 27
|
||||||
PropertyBind.staticReadWrite: 27
|
PropertyBind.staticReadWrite: 27
|
||||||
|
|
||||||
|
57
nashorn/test/script/basic/JDK-8068573.js
Normal file
57
nashorn/test/script/basic/JDK-8068573.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014 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-8068573: POJO setter using [] syntax throws an exception
|
||||||
|
*
|
||||||
|
* @test
|
||||||
|
* @run
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Invoke a setter using []. It's important that the setter returns void.
|
||||||
|
var pb = new (Java.type("jdk.nashorn.test.models.PropertyBind"))
|
||||||
|
var n = "writeOnly";
|
||||||
|
pb[n] = 2;
|
||||||
|
Assert.assertEquals(pb.peekWriteOnly(), 2);
|
||||||
|
|
||||||
|
// Invoke an overloaded setter using []. It's important that one of the
|
||||||
|
// overloads returns void.
|
||||||
|
var os = new (Java.type("jdk.nashorn.test.models.OverloadedSetter"))
|
||||||
|
var n2 = "color";
|
||||||
|
os[n2] = 3; // exercise int overload
|
||||||
|
Assert.assertEquals(os.peekColor(), "3");
|
||||||
|
os[n2] = "blue"; // exercise string overload
|
||||||
|
Assert.assertEquals(os.peekColor(), "blue");
|
||||||
|
for each(var x in [42, "42"]) {
|
||||||
|
os[n2] = x; // exercise both overloads in the same call site
|
||||||
|
Assert.assertEquals(os.peekColor(), "42");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoke an overloaded method using [], repeatedly in the same call
|
||||||
|
// site. It's important that one of the overloads returns void.
|
||||||
|
var n3="foo";
|
||||||
|
var param=["xyz", 1, "zyx", 2];
|
||||||
|
var expected=["boo", void 0, "boo", void 0];
|
||||||
|
for(var i in param) {
|
||||||
|
Assert.assertEquals(os[n3](param[i]), expected[i]);
|
||||||
|
}
|
51
nashorn/test/script/basic/JDK-8068985.js
Normal file
51
nashorn/test/script/basic/JDK-8068985.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2015 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-8068985: Wrong 'this' bound to eval call within a function when caller's 'this' is a Java object
|
||||||
|
*
|
||||||
|
* @test
|
||||||
|
* @run
|
||||||
|
*/
|
||||||
|
|
||||||
|
function func(arg) {
|
||||||
|
(function() { print(eval('this')); }).call(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// primitives
|
||||||
|
func(undefined);
|
||||||
|
func(null);
|
||||||
|
func(34.23);
|
||||||
|
func("hello");
|
||||||
|
func(false);
|
||||||
|
|
||||||
|
// script objects
|
||||||
|
func(this);
|
||||||
|
func({});
|
||||||
|
func({ toString: function() { return "foo" } });
|
||||||
|
|
||||||
|
// java objects
|
||||||
|
func(new java.util.Vector());
|
||||||
|
var m = new java.util.HashMap();
|
||||||
|
m.put("foo", "bar");
|
||||||
|
func(m);
|
10
nashorn/test/script/basic/JDK-8068985.js.EXPECTED
Normal file
10
nashorn/test/script/basic/JDK-8068985.js.EXPECTED
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[object global]
|
||||||
|
[object global]
|
||||||
|
34.23
|
||||||
|
hello
|
||||||
|
false
|
||||||
|
[object global]
|
||||||
|
[object Object]
|
||||||
|
foo
|
||||||
|
[]
|
||||||
|
{foo=bar}
|
35
nashorn/test/script/basic/JDK-8069002.js
Normal file
35
nashorn/test/script/basic/JDK-8069002.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014 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-8069002: NPE on invoking null (8068889 regression)
|
||||||
|
*
|
||||||
|
* @test
|
||||||
|
* @run
|
||||||
|
*/
|
||||||
|
|
||||||
|
try {
|
||||||
|
null();
|
||||||
|
} catch (e) {
|
||||||
|
Assert.assertTrue(e instanceof TypeError);
|
||||||
|
}
|
@ -30,12 +30,16 @@ import static org.testng.Assert.assertNotNull;
|
|||||||
import static org.testng.Assert.assertNull;
|
import static org.testng.Assert.assertNull;
|
||||||
import static org.testng.Assert.assertTrue;
|
import static org.testng.Assert.assertTrue;
|
||||||
import static org.testng.Assert.fail;
|
import static org.testng.Assert.fail;
|
||||||
|
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.lang.reflect.InvocationHandler;
|
import java.lang.reflect.InvocationHandler;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Proxy;
|
import java.lang.reflect.Proxy;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
import javax.script.Compilable;
|
import javax.script.Compilable;
|
||||||
import javax.script.CompiledScript;
|
import javax.script.CompiledScript;
|
||||||
import javax.script.Invocable;
|
import javax.script.Invocable;
|
||||||
@ -680,6 +684,41 @@ public class ScriptEngineTest {
|
|||||||
assertNull(value);
|
assertNull(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @bug JDK-8068889: ConsString arguments to a functional interface wasn't converted to string.
|
||||||
|
@Test
|
||||||
|
public void functionalInterfaceStringTest() throws Exception {
|
||||||
|
final ScriptEngineManager manager = new ScriptEngineManager();
|
||||||
|
final ScriptEngine e = manager.getEngineByName("nashorn");
|
||||||
|
final AtomicBoolean invoked = new AtomicBoolean(false);
|
||||||
|
e.put("f", new Function<String, String>() {
|
||||||
|
@Override
|
||||||
|
public String apply(String t) {
|
||||||
|
invoked.set(true);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
assertEquals(e.eval("var x = 'a'; x += 'b'; f(x)"), "ab");
|
||||||
|
assertTrue(invoked.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
// @bug JDK-8068889: ScriptObject arguments to a functional interface wasn't converted to a mirror.
|
||||||
|
@Test
|
||||||
|
public void functionalInterfaceObjectTest() throws Exception {
|
||||||
|
final ScriptEngineManager manager = new ScriptEngineManager();
|
||||||
|
final ScriptEngine e = manager.getEngineByName("nashorn");
|
||||||
|
final AtomicBoolean invoked = new AtomicBoolean(false);
|
||||||
|
e.put("c", new Consumer<Object>() {
|
||||||
|
@Override
|
||||||
|
public void accept(Object t) {
|
||||||
|
assertTrue(t instanceof ScriptObjectMirror);
|
||||||
|
assertEquals(((ScriptObjectMirror)t).get("a"), "xyz");
|
||||||
|
invoked.set(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
e.eval("var x = 'xy'; x += 'z';c({a:x})");
|
||||||
|
assertTrue(invoked.get());
|
||||||
|
}
|
||||||
|
|
||||||
private static void checkProperty(final ScriptEngine e, final String name)
|
private static void checkProperty(final ScriptEngine e, final String name)
|
||||||
throws ScriptException {
|
throws ScriptException {
|
||||||
final String value = System.getProperty(name);
|
final String value = System.getProperty(name);
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
package jdk.nashorn.test.models;
|
||||||
|
|
||||||
|
public class OverloadedSetter {
|
||||||
|
private String color;
|
||||||
|
|
||||||
|
public void setColor(final int x) {
|
||||||
|
this.color = Integer.toString(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColor(final String x) {
|
||||||
|
this.color = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String peekColor() {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void foo(final int x) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public String foo(final String x) {
|
||||||
|
return "boo";
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user