Merge
This commit is contained in:
commit
7572cf09fa
@ -349,55 +349,121 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||
throws Exception {
|
||||
final CallSiteDescriptor callSiteDescriptor = request.getCallSiteDescriptor();
|
||||
|
||||
final MissingMemberHandlerFactory missingMemberHandlerFactory;
|
||||
final LinkerServices directLinkerServices;
|
||||
if (linkerServices instanceof LinkerServicesWithMissingMemberHandlerFactory) {
|
||||
final LinkerServicesWithMissingMemberHandlerFactory lswmmhf = ((LinkerServicesWithMissingMemberHandlerFactory)linkerServices);
|
||||
missingMemberHandlerFactory = lswmmhf.missingMemberHandlerFactory;
|
||||
directLinkerServices = lswmmhf.linkerServices;
|
||||
} else {
|
||||
missingMemberHandlerFactory = null;
|
||||
directLinkerServices = linkerServices;
|
||||
}
|
||||
|
||||
// Handle NamedOperation(CALL_METHOD, name) separately
|
||||
final Operation operation = callSiteDescriptor.getOperation();
|
||||
if (operation instanceof NamedOperation) {
|
||||
final NamedOperation namedOperation = (NamedOperation)operation;
|
||||
if (namedOperation.getBaseOperation() == StandardOperation.CALL_METHOD) {
|
||||
return createGuardedDynamicMethodInvocation(callSiteDescriptor,
|
||||
linkerServices, namedOperation.getName().toString(), methods);
|
||||
final GuardedInvocation inv =
|
||||
createGuardedDynamicMethodInvocation(callSiteDescriptor,
|
||||
directLinkerServices, namedOperation.getName().toString(), methods);
|
||||
if (inv == null) {
|
||||
return createNoSuchMemberHandler(missingMemberHandlerFactory,
|
||||
request, directLinkerServices).getGuardedInvocation();
|
||||
}
|
||||
return inv;
|
||||
}
|
||||
}
|
||||
|
||||
List<Operation> operations = Arrays.asList(
|
||||
CompositeOperation.getOperations(
|
||||
NamedOperation.getBaseOperation(operation)));
|
||||
final Object name = NamedOperation.getName(operation);
|
||||
final GuardedInvocationComponent gic = getGuardedInvocationComponent(
|
||||
new ComponentLinkRequest(request, directLinkerServices,
|
||||
missingMemberHandlerFactory));
|
||||
return gic != null ? gic.getGuardedInvocation() : null;
|
||||
}
|
||||
|
||||
while(!operations.isEmpty()) {
|
||||
final GuardedInvocationComponent gic =
|
||||
getGuardedInvocationComponent(callSiteDescriptor,
|
||||
linkerServices, operations, name);
|
||||
if(gic != null) {
|
||||
return gic.getGuardedInvocation();
|
||||
static final class ComponentLinkRequest {
|
||||
final LinkRequest linkRequest;
|
||||
final LinkerServices linkerServices;
|
||||
final MissingMemberHandlerFactory missingMemberHandlerFactory;
|
||||
final List<Operation> operations;
|
||||
final Object name;
|
||||
|
||||
ComponentLinkRequest(final LinkRequest linkRequest,
|
||||
final LinkerServices linkerServices,
|
||||
final MissingMemberHandlerFactory missingMemberHandlerFactory) {
|
||||
this.linkRequest = linkRequest;
|
||||
this.linkerServices = linkerServices;
|
||||
this.missingMemberHandlerFactory = missingMemberHandlerFactory;
|
||||
final Operation operation = linkRequest.getCallSiteDescriptor().getOperation();
|
||||
this.operations = Arrays.asList(
|
||||
CompositeOperation.getOperations(
|
||||
NamedOperation.getBaseOperation(operation)));
|
||||
this.name = NamedOperation.getName(operation);
|
||||
}
|
||||
|
||||
private ComponentLinkRequest(final LinkRequest linkRequest,
|
||||
final LinkerServices linkerServices,
|
||||
final MissingMemberHandlerFactory missingMemberHandlerFactory,
|
||||
final List<Operation> operations, final Object name) {
|
||||
this.linkRequest = linkRequest;
|
||||
this.linkerServices = linkerServices;
|
||||
this.missingMemberHandlerFactory = missingMemberHandlerFactory;
|
||||
this.operations = operations;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
CallSiteDescriptor getDescriptor() {
|
||||
return linkRequest.getCallSiteDescriptor();
|
||||
}
|
||||
|
||||
ComponentLinkRequest popOperations() {
|
||||
return new ComponentLinkRequest(linkRequest, linkerServices,
|
||||
missingMemberHandlerFactory,
|
||||
operations.subList(1, operations.size()), name);
|
||||
}
|
||||
}
|
||||
|
||||
protected GuardedInvocationComponent getGuardedInvocationComponent(final ComponentLinkRequest req)
|
||||
throws Exception {
|
||||
final Operation op = req.operations.get(0);
|
||||
if (op instanceof StandardOperation) {
|
||||
switch((StandardOperation)op) {
|
||||
case GET_PROPERTY: return getPropertyGetter(req.popOperations());
|
||||
case SET_PROPERTY: return getPropertySetter(req.popOperations());
|
||||
case GET_METHOD: return getMethodGetter(req.popOperations());
|
||||
default:
|
||||
}
|
||||
operations = pop(operations);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected GuardedInvocationComponent getGuardedInvocationComponent(
|
||||
final CallSiteDescriptor callSiteDescriptor,
|
||||
final LinkerServices linkerServices,
|
||||
final List<Operation> operations, final Object name)
|
||||
throws Exception {
|
||||
if(operations.isEmpty()) {
|
||||
GuardedInvocationComponent getNextComponent(final ComponentLinkRequest req) throws Exception {
|
||||
if (req.operations.isEmpty()) {
|
||||
return createNoSuchMemberHandler(req.missingMemberHandlerFactory,
|
||||
req.linkRequest, req.linkerServices);
|
||||
}
|
||||
final GuardedInvocationComponent gic = getGuardedInvocationComponent(req);
|
||||
if (gic != null) {
|
||||
return gic;
|
||||
}
|
||||
return getNextComponent(req.popOperations());
|
||||
}
|
||||
|
||||
private GuardedInvocationComponent createNoSuchMemberHandler(
|
||||
final MissingMemberHandlerFactory missingMemberHandlerFactory,
|
||||
final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
|
||||
if (missingMemberHandlerFactory == null) {
|
||||
return null;
|
||||
}
|
||||
final Operation op = operations.get(0);
|
||||
// Either GET_PROPERTY:name(this) or GET_PROPERTY(this, name)
|
||||
if(op == StandardOperation.GET_PROPERTY) {
|
||||
return getPropertyGetter(callSiteDescriptor, linkerServices, pop(operations), name);
|
||||
final MethodHandle handler = missingMemberHandlerFactory.createMissingMemberHandler(linkRequest, linkerServices);
|
||||
if (handler == null) {
|
||||
return null;
|
||||
}
|
||||
// Either SET_PROPERTY:name(this, value) or SET_PROPERTY(this, name, value)
|
||||
if(op == StandardOperation.SET_PROPERTY) {
|
||||
return getPropertySetter(callSiteDescriptor, linkerServices, pop(operations), name);
|
||||
}
|
||||
// Either GET_METHOD:name(this), or GET_METHOD(this, name)
|
||||
if(op == StandardOperation.GET_METHOD) {
|
||||
return getMethodGetter(callSiteDescriptor, linkerServices, pop(operations), name);
|
||||
}
|
||||
return null;
|
||||
final MethodType type = linkRequest.getCallSiteDescriptor().getMethodType();
|
||||
// The returned handler is allowed to differ in return type.
|
||||
assert handler.type().changeReturnType(type.returnType()).equals(type);
|
||||
return getClassGuardedInvocationComponent(handler, type);
|
||||
}
|
||||
|
||||
static final <T> List<T> pop(final List<T> l) {
|
||||
@ -483,16 +549,15 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||
private static final MethodHandle CONSTANT_NULL_DROP_METHOD_HANDLE = MethodHandles.dropArguments(
|
||||
MethodHandles.constant(Object.class, null), 0, MethodHandle.class);
|
||||
|
||||
private GuardedInvocationComponent getPropertySetter(final CallSiteDescriptor callSiteDescriptor,
|
||||
final LinkerServices linkerServices, final List<Operation> operations, final Object name) throws Exception {
|
||||
if (name == null) {
|
||||
return getUnnamedPropertySetter(callSiteDescriptor, linkerServices, operations);
|
||||
private GuardedInvocationComponent getPropertySetter(final ComponentLinkRequest req) throws Exception {
|
||||
if (req.name == null) {
|
||||
return getUnnamedPropertySetter(req);
|
||||
}
|
||||
return getNamedPropertySetter(callSiteDescriptor, linkerServices, operations, name);
|
||||
return getNamedPropertySetter(req);
|
||||
}
|
||||
|
||||
private GuardedInvocationComponent getUnnamedPropertySetter(final CallSiteDescriptor callSiteDescriptor,
|
||||
final LinkerServices linkerServices, final List<Operation> operations) throws Exception {
|
||||
private GuardedInvocationComponent getUnnamedPropertySetter(final ComponentLinkRequest req) throws Exception {
|
||||
final CallSiteDescriptor callSiteDescriptor = req.getDescriptor();
|
||||
// Must have three arguments: target object, property name, and property value.
|
||||
assertParameterCount(callSiteDescriptor, 3);
|
||||
|
||||
@ -501,6 +566,7 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||
// invoked, we'll conservatively presume Object return type. The one exception is void return.
|
||||
final MethodType origType = callSiteDescriptor.getMethodType();
|
||||
final MethodType type = origType.returnType() == void.class ? origType : origType.changeReturnType(Object.class);
|
||||
final LinkerServices linkerServices = req.linkerServices;
|
||||
|
||||
// What's below is basically:
|
||||
// foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation),
|
||||
@ -527,11 +593,10 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||
// Handle to invoke the setter, dropping unnecessary fold arguments R(MethodHandle, O, N, V)
|
||||
final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandle, 2, type.parameterType(
|
||||
1));
|
||||
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
|
||||
linkerServices, operations, null);
|
||||
final GuardedInvocationComponent nextComponent = getNextComponent(req);
|
||||
|
||||
final MethodHandle fallbackFolded;
|
||||
if(nextComponent == null) {
|
||||
if (nextComponent == null) {
|
||||
// Object(MethodHandle)->Object(MethodHandle, O, N, V); returns constant null
|
||||
fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_METHOD_HANDLE, 1,
|
||||
type.parameterList()).asType(type.insertParameterTypes(0, MethodHandle.class));
|
||||
@ -551,19 +616,19 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||
return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
|
||||
}
|
||||
|
||||
private GuardedInvocationComponent getNamedPropertySetter(final CallSiteDescriptor callSiteDescriptor,
|
||||
final LinkerServices linkerServices, final List<Operation> operations, final Object name) throws Exception {
|
||||
private GuardedInvocationComponent getNamedPropertySetter(final ComponentLinkRequest req) throws Exception {
|
||||
final CallSiteDescriptor callSiteDescriptor = req.getDescriptor();
|
||||
// Must have two arguments: target object and property value
|
||||
assertParameterCount(callSiteDescriptor, 2);
|
||||
final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices,
|
||||
name.toString(), propertySetters);
|
||||
final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, req.linkerServices,
|
||||
req.name.toString(), 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);
|
||||
}
|
||||
// If we don't have a property setter with this name, always fall back to the next operation in the
|
||||
// composite (if any)
|
||||
return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, operations, name);
|
||||
return getNextComponent(req);
|
||||
}
|
||||
|
||||
private static final Lookup privateLookup = new Lookup(MethodHandles.lookup());
|
||||
@ -576,20 +641,18 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||
"getTarget", MethodType.methodType(MethodHandle.class, CallSiteDescriptor.class, LinkerServices.class));
|
||||
private static final MethodHandle GETTER_INVOKER = MethodHandles.invoker(MethodType.methodType(Object.class, Object.class));
|
||||
|
||||
private GuardedInvocationComponent getPropertyGetter(final CallSiteDescriptor callSiteDescriptor,
|
||||
final LinkerServices linkerServices, final List<Operation> ops, final Object name) throws Exception {
|
||||
if (name == null) {
|
||||
return getUnnamedPropertyGetter(callSiteDescriptor, linkerServices, ops);
|
||||
private GuardedInvocationComponent getPropertyGetter(final ComponentLinkRequest req) throws Exception {
|
||||
if (req.name == null) {
|
||||
return getUnnamedPropertyGetter(req);
|
||||
}
|
||||
|
||||
return getNamedPropertyGetter(callSiteDescriptor, linkerServices, ops, name);
|
||||
return getNamedPropertyGetter(req);
|
||||
}
|
||||
|
||||
private GuardedInvocationComponent getUnnamedPropertyGetter(final CallSiteDescriptor callSiteDescriptor,
|
||||
final LinkerServices linkerServices, final List<Operation> ops) throws Exception {
|
||||
private GuardedInvocationComponent getUnnamedPropertyGetter(final ComponentLinkRequest req) throws Exception {
|
||||
// Since we can't know what kind of a getter we'll get back on different invocations, we'll just
|
||||
// conservatively presume Object. Note we can't just coerce to a narrower call site type as the linking
|
||||
// runtime might not allow coercing at that call site.
|
||||
final CallSiteDescriptor callSiteDescriptor = req.getDescriptor();
|
||||
final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class);
|
||||
// Must have exactly two arguments: receiver and name
|
||||
assertParameterCount(callSiteDescriptor, 2);
|
||||
@ -600,6 +663,7 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||
// AnnotatedDynamicMethod; if it is non-null, invoke its "handle" field, otherwise either return null,
|
||||
// or delegate to next component's invocation.
|
||||
|
||||
final LinkerServices linkerServices = req.linkerServices;
|
||||
final MethodHandle typedGetter = linkerServices.asType(getPropertyGetterHandle, type.changeReturnType(
|
||||
AnnotatedDynamicMethod.class));
|
||||
final MethodHandle callSiteBoundMethodGetter = MethodHandles.insertArguments(
|
||||
@ -613,8 +677,7 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||
// Object(AnnotatedDynamicMethod, T0)->Object(AnnotatedDynamicMethod, T0, T1)
|
||||
final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandleTyped, 2,
|
||||
type.parameterType(1));
|
||||
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
|
||||
linkerServices, ops, null);
|
||||
final GuardedInvocationComponent nextComponent = getNextComponent(req);
|
||||
|
||||
final MethodHandle fallbackFolded;
|
||||
if(nextComponent == null) {
|
||||
@ -639,17 +702,17 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||
return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
|
||||
}
|
||||
|
||||
private GuardedInvocationComponent getNamedPropertyGetter(final CallSiteDescriptor callSiteDescriptor,
|
||||
final LinkerServices linkerServices, final List<Operation> ops, final Object name) throws Exception {
|
||||
private GuardedInvocationComponent getNamedPropertyGetter(final ComponentLinkRequest req) throws Exception {
|
||||
final CallSiteDescriptor callSiteDescriptor = req.getDescriptor();
|
||||
// Must have exactly one argument: receiver
|
||||
assertParameterCount(callSiteDescriptor, 1);
|
||||
// Fixed name
|
||||
final AnnotatedDynamicMethod annGetter = propertyGetters.get(name.toString());
|
||||
final AnnotatedDynamicMethod annGetter = propertyGetters.get(req.name.toString());
|
||||
if(annGetter == null) {
|
||||
// We have no such property, always delegate to the next component operation
|
||||
return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops, name);
|
||||
return getNextComponent(req);
|
||||
}
|
||||
final MethodHandle getter = annGetter.getInvocation(callSiteDescriptor, linkerServices);
|
||||
final MethodHandle getter = annGetter.getInvocation(req);
|
||||
// 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
|
||||
@ -686,28 +749,27 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||
MethodType.methodType(boolean.class, Object.class));
|
||||
private static final MethodHandle OBJECT_IDENTITY = MethodHandles.identity(Object.class);
|
||||
|
||||
private GuardedInvocationComponent getMethodGetter(final CallSiteDescriptor callSiteDescriptor,
|
||||
final LinkerServices linkerServices, final List<Operation> ops, final Object name) throws Exception {
|
||||
// The created method handle will always return a DynamicMethod (or null), but since we don't want that type to
|
||||
// be visible outside of this linker, declare it to return Object.
|
||||
final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class);
|
||||
if (name == null) {
|
||||
return getUnnamedMethodGetter(callSiteDescriptor, linkerServices, ops, type);
|
||||
private GuardedInvocationComponent getMethodGetter(final ComponentLinkRequest req) throws Exception {
|
||||
if (req.name == null) {
|
||||
return getUnnamedMethodGetter(req);
|
||||
}
|
||||
|
||||
return getNamedMethodGetter(callSiteDescriptor, linkerServices, ops, name, type);
|
||||
return getNamedMethodGetter(req);
|
||||
}
|
||||
|
||||
private GuardedInvocationComponent getUnnamedMethodGetter(final CallSiteDescriptor callSiteDescriptor,
|
||||
final LinkerServices linkerServices, final List<Operation> ops, final MethodType type) throws Exception {
|
||||
private static MethodType getMethodGetterType(final ComponentLinkRequest req) {
|
||||
// The created method handle will always return a DynamicMethod (or null), but since we don't want that type to
|
||||
// be visible outside of this linker, declare it to return Object.
|
||||
return req.getDescriptor().getMethodType().changeReturnType(Object.class);
|
||||
}
|
||||
|
||||
private GuardedInvocationComponent getUnnamedMethodGetter(final ComponentLinkRequest req) throws Exception {
|
||||
// Must have exactly two arguments: receiver and name
|
||||
assertParameterCount(callSiteDescriptor, 2);
|
||||
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
|
||||
linkerServices, ops, null);
|
||||
if(nextComponent == null || !InternalTypeUtilities.areAssignable(DynamicMethod.class,
|
||||
nextComponent.getGuardedInvocation().getInvocation().type().returnType())) {
|
||||
// No next component operation, or it can never produce a dynamic method; just return a component
|
||||
// for this operation.
|
||||
assertParameterCount(req.getDescriptor(), 2);
|
||||
final GuardedInvocationComponent nextComponent = getNextComponent(req);
|
||||
final LinkerServices linkerServices = req.linkerServices;
|
||||
final MethodType type = getMethodGetterType(req);
|
||||
if(nextComponent == null) {
|
||||
// No next component operation; just return a component for this operation.
|
||||
return getClassGuardedInvocationComponent(linkerServices.asType(getDynamicMethod, type), type);
|
||||
}
|
||||
|
||||
@ -728,25 +790,28 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||
final MethodHandle nextCombinedInvocation = MethodHandles.dropArguments(nextComponentInvocation, 0,
|
||||
Object.class);
|
||||
// Assemble it all into a fold(guard(isNotNull, identity, nextInvocation), get)
|
||||
// Note that nextCombinedInvocation needs to have its return type changed to Object
|
||||
final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
|
||||
IS_DYNAMIC_METHOD, returnMethodHandle, nextCombinedInvocation), typedGetter);
|
||||
IS_DYNAMIC_METHOD, returnMethodHandle,
|
||||
nextCombinedInvocation.asType(nextCombinedInvocation.type().changeReturnType(Object.class))),
|
||||
typedGetter);
|
||||
|
||||
return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
|
||||
}
|
||||
|
||||
private GuardedInvocationComponent getNamedMethodGetter(final CallSiteDescriptor callSiteDescriptor,
|
||||
final LinkerServices linkerServices, final List<Operation> ops, final Object name, final MethodType type)
|
||||
private GuardedInvocationComponent getNamedMethodGetter(final ComponentLinkRequest req)
|
||||
throws Exception {
|
||||
// Must have exactly one argument: receiver
|
||||
assertParameterCount(callSiteDescriptor, 1);
|
||||
final DynamicMethod method = getDynamicMethod(name.toString());
|
||||
assertParameterCount(req.getDescriptor(), 1);
|
||||
final DynamicMethod method = getDynamicMethod(req.name.toString());
|
||||
if(method == null) {
|
||||
// We have no such method, always delegate to the next component
|
||||
return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops, name);
|
||||
return getNextComponent(req);
|
||||
}
|
||||
// No delegation to the next component of the composite operation; if we have a method with that name,
|
||||
// we'll always return it at this point.
|
||||
return getClassGuardedInvocationComponent(linkerServices.asType(MethodHandles.dropArguments(
|
||||
final MethodType type = getMethodGetterType(req);
|
||||
return getClassGuardedInvocationComponent(req.linkerServices.asType(MethodHandles.dropArguments(
|
||||
MethodHandles.constant(Object.class, method), 0, type.parameterType(0)), type), type);
|
||||
}
|
||||
|
||||
@ -876,8 +941,8 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||
this.validationType = validationType;
|
||||
}
|
||||
|
||||
MethodHandle getInvocation(final CallSiteDescriptor callSiteDescriptor, final LinkerServices linkerServices) {
|
||||
return method.getInvocation(callSiteDescriptor, linkerServices);
|
||||
MethodHandle getInvocation(final ComponentLinkRequest req) {
|
||||
return method.getInvocation(req.getDescriptor(), req.linkerServices);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
|
@ -88,6 +88,7 @@ import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import jdk.dynalink.CallSiteDescriptor;
|
||||
@ -129,25 +130,21 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GuardedInvocationComponent getGuardedInvocationComponent(final CallSiteDescriptor callSiteDescriptor,
|
||||
final LinkerServices linkerServices, final List<Operation> operations, final Object name) throws Exception {
|
||||
final GuardedInvocationComponent superGic = super.getGuardedInvocationComponent(callSiteDescriptor,
|
||||
linkerServices, operations, name);
|
||||
protected GuardedInvocationComponent getGuardedInvocationComponent(final ComponentLinkRequest req) throws Exception {
|
||||
final GuardedInvocationComponent superGic = super.getGuardedInvocationComponent(req);
|
||||
if(superGic != null) {
|
||||
return superGic;
|
||||
}
|
||||
if(operations.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
final Operation op = operations.get(0);
|
||||
if(op == StandardOperation.GET_ELEMENT) {
|
||||
return getElementGetter(callSiteDescriptor, linkerServices, pop(operations), name);
|
||||
}
|
||||
if(op == StandardOperation.SET_ELEMENT) {
|
||||
return getElementSetter(callSiteDescriptor, linkerServices, pop(operations), name);
|
||||
}
|
||||
if(op == StandardOperation.GET_LENGTH) {
|
||||
return getLengthGetter(callSiteDescriptor);
|
||||
if (!req.operations.isEmpty()) {
|
||||
final Operation op = req.operations.get(0);
|
||||
if (op instanceof StandardOperation) {
|
||||
switch ((StandardOperation)op) {
|
||||
case GET_ELEMENT: return getElementGetter(req.popOperations());
|
||||
case SET_ELEMENT: return getElementSetter(req.popOperations());
|
||||
case GET_LENGTH: return getLengthGetter(req.getDescriptor());
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -166,16 +163,31 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
|
||||
private static final MethodHandle LIST_GUARD = Guards.getInstanceOfGuard(List.class);
|
||||
private static final MethodHandle MAP_GUARD = Guards.getInstanceOfGuard(Map.class);
|
||||
|
||||
private static final MethodHandle NULL_GETTER_1;
|
||||
private static final MethodHandle NULL_GETTER_2;
|
||||
static {
|
||||
final MethodHandle constantNull = MethodHandles.constant(Object.class, null);
|
||||
NULL_GETTER_1 = dropObjectArguments(constantNull, 1);
|
||||
NULL_GETTER_2 = dropObjectArguments(constantNull, 2);
|
||||
}
|
||||
|
||||
private static MethodHandle dropObjectArguments(final MethodHandle m, final int n) {
|
||||
return MethodHandles.dropArguments(m, 0, Collections.nCopies(n, Object.class));
|
||||
}
|
||||
|
||||
private enum CollectionType {
|
||||
ARRAY, LIST, MAP
|
||||
};
|
||||
|
||||
private GuardedInvocationComponent getElementGetter(final CallSiteDescriptor callSiteDescriptor,
|
||||
final LinkerServices linkerServices, final List<Operation> operations, final Object name) throws Exception {
|
||||
private GuardedInvocationComponent getElementGetter(final ComponentLinkRequest req) throws Exception {
|
||||
final CallSiteDescriptor callSiteDescriptor = req.getDescriptor();
|
||||
final Object name = req.name;
|
||||
final boolean isFixedKey = name != null;
|
||||
assertParameterCount(callSiteDescriptor, isFixedKey ? 1 : 2);
|
||||
final LinkerServices linkerServices = req.linkerServices;
|
||||
final MethodType callSiteType = callSiteDescriptor.getMethodType();
|
||||
final Class<?> declaredType = callSiteType.parameterType(0);
|
||||
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
|
||||
linkerServices, operations, name);
|
||||
final GuardedInvocationComponent nextComponent = getNextComponent(req);
|
||||
|
||||
// If declared type of receiver at the call site is already an array, a list or map, bind without guard. Thing
|
||||
// is, it'd be quite stupid of a call site creator to go though invokedynamic when it knows in advance they're
|
||||
@ -211,12 +223,14 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
|
||||
|
||||
// Convert the key to a number if we're working with a list or array
|
||||
final Object typedName;
|
||||
if(collectionType != CollectionType.MAP && name != null) {
|
||||
typedName = convertKeyToInteger(name, linkerServices);
|
||||
if(typedName == null) {
|
||||
// key is not numeric, it can never succeed
|
||||
if (collectionType != CollectionType.MAP && isFixedKey) {
|
||||
final Integer integer = convertKeyToInteger(name, linkerServices);
|
||||
if (integer == null || integer.intValue() < 0) {
|
||||
// key is not a non-negative integer, it can never address an
|
||||
// array or list element
|
||||
return nextComponent;
|
||||
}
|
||||
typedName = integer;
|
||||
} else {
|
||||
typedName = name;
|
||||
}
|
||||
@ -225,30 +239,33 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
|
||||
final Binder binder = new Binder(linkerServices, callSiteType, typedName);
|
||||
final MethodHandle invocation = gi.getInvocation();
|
||||
|
||||
if(nextComponent == null) {
|
||||
return gic.replaceInvocation(binder.bind(invocation));
|
||||
}
|
||||
|
||||
final MethodHandle checkGuard;
|
||||
switch(collectionType) {
|
||||
case LIST:
|
||||
checkGuard = convertArgToInt(RANGE_CHECK_LIST, linkerServices, callSiteDescriptor);
|
||||
checkGuard = convertArgToNumber(RANGE_CHECK_LIST, linkerServices, callSiteDescriptor);
|
||||
break;
|
||||
case MAP:
|
||||
// TODO: A more complex solution could be devised for maps, one where we do a get() first, and fold it
|
||||
// into a GWT that tests if it returned null, and if it did, do another GWT with containsKey()
|
||||
// that returns constant null (on true), or falls back to next component (on false)
|
||||
checkGuard = linkerServices.filterInternalObjects(CONTAINS_MAP);
|
||||
break;
|
||||
case ARRAY:
|
||||
checkGuard = convertArgToInt(RANGE_CHECK_ARRAY, linkerServices, callSiteDescriptor);
|
||||
checkGuard = convertArgToNumber(RANGE_CHECK_ARRAY, linkerServices, callSiteDescriptor);
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
// If there's no next component, produce a fixed null-returning one
|
||||
final GuardedInvocationComponent finalNextComponent;
|
||||
if (nextComponent != null) {
|
||||
finalNextComponent = nextComponent;
|
||||
} else {
|
||||
final MethodHandle nullGetterHandle = isFixedKey ? NULL_GETTER_1 : NULL_GETTER_2;
|
||||
finalNextComponent = createGuardedInvocationComponentAsType(nullGetterHandle, callSiteType, linkerServices);
|
||||
}
|
||||
|
||||
final MethodPair matchedInvocations = matchReturnTypes(binder.bind(invocation),
|
||||
nextComponent.getGuardedInvocation().getInvocation());
|
||||
return nextComponent.compose(matchedInvocations.guardWithTest(binder.bindTest(checkGuard)), gi.getGuard(),
|
||||
finalNextComponent.getGuardedInvocation().getInvocation());
|
||||
return finalNextComponent.compose(matchedInvocations.guardWithTest(binder.bindTest(checkGuard)), gi.getGuard(),
|
||||
gic.getValidatorClass(), gic.getValidationType());
|
||||
}
|
||||
|
||||
@ -257,6 +274,11 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
|
||||
return new GuardedInvocationComponent(linkerServices.filterInternalObjects(invocation));
|
||||
}
|
||||
|
||||
private static GuardedInvocationComponent createGuardedInvocationComponentAsType(
|
||||
final MethodHandle invocation, final MethodType fromType, final LinkerServices linkerServices) {
|
||||
return new GuardedInvocationComponent(linkerServices.asType(invocation, fromType));
|
||||
}
|
||||
|
||||
private static GuardedInvocationComponent createInternalFilteredGuardedInvocationComponent(
|
||||
final MethodHandle invocation, final MethodHandle guard, final Class<?> validatorClass,
|
||||
final ValidationType validationType, final LinkerServices linkerServices) {
|
||||
@ -310,7 +332,7 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
|
||||
return intIndex;
|
||||
}
|
||||
|
||||
private static MethodHandle convertArgToInt(final MethodHandle mh, final LinkerServices ls, final CallSiteDescriptor desc) {
|
||||
private static MethodHandle convertArgToNumber(final MethodHandle mh, final LinkerServices ls, final CallSiteDescriptor desc) {
|
||||
final Class<?> sourceType = desc.getMethodType().parameterType(1);
|
||||
if(TypeUtilities.isMethodInvocationConvertible(sourceType, Number.class)) {
|
||||
return mh;
|
||||
@ -366,14 +388,10 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
|
||||
}
|
||||
final Number n = (Number)index;
|
||||
final int intIndex = n.intValue();
|
||||
final double doubleValue = n.doubleValue();
|
||||
if(intIndex != doubleValue && !Double.isInfinite(doubleValue)) { // let infinite trigger IOOBE
|
||||
if (intIndex != n.doubleValue()) {
|
||||
return false;
|
||||
}
|
||||
if(0 <= intIndex && intIndex < Array.getLength(array)) {
|
||||
return true;
|
||||
}
|
||||
throw new ArrayIndexOutOfBoundsException("Array index out of range: " + n);
|
||||
return 0 <= intIndex && intIndex < Array.getLength(array);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@ -383,14 +401,14 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
|
||||
}
|
||||
final Number n = (Number)index;
|
||||
final int intIndex = n.intValue();
|
||||
final double doubleValue = n.doubleValue();
|
||||
if(intIndex != doubleValue && !Double.isInfinite(doubleValue)) { // let infinite trigger IOOBE
|
||||
if (intIndex != n.doubleValue()) {
|
||||
return false;
|
||||
}
|
||||
if(0 <= intIndex && intIndex < list.size()) {
|
||||
return true;
|
||||
}
|
||||
throw new IndexOutOfBoundsException("Index: " + n + ", Size: " + list.size());
|
||||
return 0 <= intIndex && intIndex < list.size();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static void noOpSetter() {
|
||||
}
|
||||
|
||||
private static final MethodHandle SET_LIST_ELEMENT = Lookup.PUBLIC.findVirtual(List.class, "set",
|
||||
@ -399,8 +417,20 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
|
||||
private static final MethodHandle PUT_MAP_ELEMENT = Lookup.PUBLIC.findVirtual(Map.class, "put",
|
||||
MethodType.methodType(Object.class, Object.class, Object.class));
|
||||
|
||||
private GuardedInvocationComponent getElementSetter(final CallSiteDescriptor callSiteDescriptor,
|
||||
final LinkerServices linkerServices, final List<Operation> operations, final Object name) throws Exception {
|
||||
private static final MethodHandle NO_OP_SETTER_2;
|
||||
private static final MethodHandle NO_OP_SETTER_3;
|
||||
static {
|
||||
final MethodHandle noOpSetter = Lookup.findOwnStatic(MethodHandles.lookup(), "noOpSetter", void.class);
|
||||
NO_OP_SETTER_2 = dropObjectArguments(noOpSetter, 2);
|
||||
NO_OP_SETTER_3 = dropObjectArguments(noOpSetter, 3);
|
||||
}
|
||||
|
||||
private GuardedInvocationComponent getElementSetter(final ComponentLinkRequest req) throws Exception {
|
||||
final CallSiteDescriptor callSiteDescriptor = req.getDescriptor();
|
||||
final Object name = req.name;
|
||||
final boolean isFixedKey = name != null;
|
||||
assertParameterCount(callSiteDescriptor, isFixedKey ? 2 : 3);
|
||||
final LinkerServices linkerServices = req.linkerServices;
|
||||
final MethodType callSiteType = callSiteDescriptor.getMethodType();
|
||||
final Class<?> declaredType = callSiteType.parameterType(0);
|
||||
|
||||
@ -441,20 +471,21 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
|
||||
// In contrast to, say, getElementGetter, we only compute the nextComponent if the target object is not a map,
|
||||
// as maps will always succeed in setting the element and will never need to fall back to the next component
|
||||
// operation.
|
||||
final GuardedInvocationComponent nextComponent = collectionType == CollectionType.MAP ? null : getGuardedInvocationComponent(
|
||||
callSiteDescriptor, linkerServices, operations, name);
|
||||
final GuardedInvocationComponent nextComponent = collectionType == CollectionType.MAP ? null : getNextComponent(req);
|
||||
if(gic == null) {
|
||||
return nextComponent;
|
||||
}
|
||||
|
||||
// Convert the key to a number if we're working with a list or array
|
||||
final Object typedName;
|
||||
if(collectionType != CollectionType.MAP && name != null) {
|
||||
typedName = convertKeyToInteger(name, linkerServices);
|
||||
if(typedName == null) {
|
||||
// key is not numeric, it can never succeed
|
||||
if (collectionType != CollectionType.MAP && isFixedKey) {
|
||||
final Integer integer = convertKeyToInteger(name, linkerServices);
|
||||
if (integer == null || integer.intValue() < 0) {
|
||||
// key is not a non-negative integer, it can never address an
|
||||
// array or list element
|
||||
return nextComponent;
|
||||
}
|
||||
typedName = integer;
|
||||
} else {
|
||||
typedName = name;
|
||||
}
|
||||
@ -463,16 +494,27 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
|
||||
final Binder binder = new Binder(linkerServices, callSiteType, typedName);
|
||||
final MethodHandle invocation = gi.getInvocation();
|
||||
|
||||
if(nextComponent == null) {
|
||||
if (collectionType == CollectionType.MAP) {
|
||||
assert nextComponent == null;
|
||||
return gic.replaceInvocation(binder.bind(invocation));
|
||||
}
|
||||
|
||||
assert collectionType == CollectionType.LIST || collectionType == CollectionType.ARRAY;
|
||||
final MethodHandle checkGuard = convertArgToInt(collectionType == CollectionType.LIST ? RANGE_CHECK_LIST :
|
||||
final MethodHandle checkGuard = convertArgToNumber(collectionType == CollectionType.LIST ? RANGE_CHECK_LIST :
|
||||
RANGE_CHECK_ARRAY, linkerServices, callSiteDescriptor);
|
||||
|
||||
// If there's no next component, produce a no-op one.
|
||||
final GuardedInvocationComponent finalNextComponent;
|
||||
if (nextComponent != null) {
|
||||
finalNextComponent = nextComponent;
|
||||
} else {
|
||||
final MethodHandle noOpSetterHandle = isFixedKey ? NO_OP_SETTER_2 : NO_OP_SETTER_3;
|
||||
finalNextComponent = createGuardedInvocationComponentAsType(noOpSetterHandle, callSiteType, linkerServices);
|
||||
}
|
||||
|
||||
final MethodPair matchedInvocations = matchReturnTypes(binder.bind(invocation),
|
||||
nextComponent.getGuardedInvocation().getInvocation());
|
||||
return nextComponent.compose(matchedInvocations.guardWithTest(binder.bindTest(checkGuard)), gi.getGuard(),
|
||||
finalNextComponent.getGuardedInvocation().getInvocation());
|
||||
return finalNextComponent.compose(matchedInvocations.guardWithTest(binder.bindTest(checkGuard)), gi.getGuard(),
|
||||
gic.getValidatorClass(), gic.getValidationType());
|
||||
}
|
||||
|
||||
|
@ -146,7 +146,11 @@ import jdk.dynalink.linker.TypeBasedGuardingDynamicLinker;
|
||||
* are otherwise public and link requests have call site descriptors carrying
|
||||
* full-strength {@link Lookup} objects and not weakened lookups or the public
|
||||
* lookup.</p>
|
||||
* <p>The class also exposes various static methods for discovery of available
|
||||
* <p><strong>The behavior for handling missing members</strong> can be
|
||||
* customized by passing a {@link MissingMemberHandlerFactory} to the
|
||||
* {@link BeansLinker#BeansLinker(MissingMemberHandlerFactory) constructor}.
|
||||
* </p>
|
||||
* <p>The class also exposes various methods for discovery of available
|
||||
* property and method names on classes and class instances, as well as access
|
||||
* to per-class linkers using the {@link #getLinkerForClass(Class)}
|
||||
* method.</p>
|
||||
@ -164,10 +168,27 @@ public class BeansLinker implements GuardingDynamicLinker {
|
||||
}
|
||||
};
|
||||
|
||||
private final MissingMemberHandlerFactory missingMemberHandlerFactory;
|
||||
|
||||
/**
|
||||
* Creates a new beans linker.
|
||||
* Creates a new beans linker. Equivalent to
|
||||
* {@link BeansLinker#BeansLinker(MissingMemberHandlerFactory)} with
|
||||
* {@code null} passed as the missing member handler factory, resulting in
|
||||
* the default behavior for linking and evaluating missing members.
|
||||
*/
|
||||
public BeansLinker() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new beans linker with the specified factory for creating
|
||||
* missing member handlers. The passed factory can be null if the default
|
||||
* behavior is adequate. See {@link MissingMemberHandlerFactory} for details.
|
||||
* @param missingMemberHandlerFactory a factory for creating handlers for
|
||||
* operations on missing members.
|
||||
*/
|
||||
public BeansLinker(final MissingMemberHandlerFactory missingMemberHandlerFactory) {
|
||||
this.missingMemberHandlerFactory = missingMemberHandlerFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -178,7 +199,37 @@ public class BeansLinker implements GuardingDynamicLinker {
|
||||
* @param clazz the class
|
||||
* @return a bean linker for that class
|
||||
*/
|
||||
public static TypeBasedGuardingDynamicLinker getLinkerForClass(final Class<?> clazz) {
|
||||
public TypeBasedGuardingDynamicLinker getLinkerForClass(final Class<?> clazz) {
|
||||
final TypeBasedGuardingDynamicLinker staticLinker = getStaticLinkerForClass(clazz);
|
||||
if (missingMemberHandlerFactory == null) {
|
||||
return staticLinker;
|
||||
}
|
||||
return new NoSuchMemberHandlerBindingLinker(staticLinker, missingMemberHandlerFactory);
|
||||
}
|
||||
|
||||
private static class NoSuchMemberHandlerBindingLinker implements TypeBasedGuardingDynamicLinker {
|
||||
private final TypeBasedGuardingDynamicLinker linker;
|
||||
private final MissingMemberHandlerFactory missingMemberHandlerFactory;
|
||||
|
||||
NoSuchMemberHandlerBindingLinker(final TypeBasedGuardingDynamicLinker linker, final MissingMemberHandlerFactory missingMemberHandlerFactory) {
|
||||
this.linker = linker;
|
||||
this.missingMemberHandlerFactory = missingMemberHandlerFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canLinkType(final Class<?> type) {
|
||||
return linker.canLinkType(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
|
||||
return linker.getGuardedInvocation(linkRequest,
|
||||
LinkerServicesWithMissingMemberHandlerFactory.get(
|
||||
linkerServices, missingMemberHandlerFactory));
|
||||
}
|
||||
}
|
||||
|
||||
static TypeBasedGuardingDynamicLinker getStaticLinkerForClass(final Class<?> clazz) {
|
||||
return linkers.get(clazz);
|
||||
}
|
||||
|
||||
@ -234,7 +285,7 @@ public class BeansLinker implements GuardingDynamicLinker {
|
||||
* @return a set of names of all readable instance properties of a class.
|
||||
*/
|
||||
public static Set<String> getReadableInstancePropertyNames(final Class<?> clazz) {
|
||||
final TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz);
|
||||
final TypeBasedGuardingDynamicLinker linker = getStaticLinkerForClass(clazz);
|
||||
if(linker instanceof BeanLinker) {
|
||||
return ((BeanLinker)linker).getReadablePropertyNames();
|
||||
}
|
||||
@ -247,7 +298,7 @@ public class BeansLinker implements GuardingDynamicLinker {
|
||||
* @return a set of names of all writable instance properties of a class.
|
||||
*/
|
||||
public static Set<String> getWritableInstancePropertyNames(final Class<?> clazz) {
|
||||
final TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz);
|
||||
final TypeBasedGuardingDynamicLinker linker = getStaticLinkerForClass(clazz);
|
||||
if(linker instanceof BeanLinker) {
|
||||
return ((BeanLinker)linker).getWritablePropertyNames();
|
||||
}
|
||||
@ -260,7 +311,7 @@ public class BeansLinker implements GuardingDynamicLinker {
|
||||
* @return a set of names of all instance methods of a class.
|
||||
*/
|
||||
public static Set<String> getInstanceMethodNames(final Class<?> clazz) {
|
||||
final TypeBasedGuardingDynamicLinker linker = getLinkerForClass(clazz);
|
||||
final TypeBasedGuardingDynamicLinker linker = getStaticLinkerForClass(clazz);
|
||||
if(linker instanceof BeanLinker) {
|
||||
return ((BeanLinker)linker).getMethodNames();
|
||||
}
|
||||
@ -302,6 +353,8 @@ public class BeansLinker implements GuardingDynamicLinker {
|
||||
// Can't operate on null
|
||||
return null;
|
||||
}
|
||||
return getLinkerForClass(receiver.getClass()).getGuardedInvocation(request, linkerServices);
|
||||
return getLinkerForClass(receiver.getClass()).getGuardedInvocation(request,
|
||||
LinkerServicesWithMissingMemberHandlerFactory.get(linkerServices,
|
||||
missingMemberHandlerFactory));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.dynalink.beans;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import jdk.dynalink.linker.ConversionComparator.Comparison;
|
||||
import jdk.dynalink.linker.GuardedInvocation;
|
||||
import jdk.dynalink.linker.LinkRequest;
|
||||
import jdk.dynalink.linker.LinkerServices;
|
||||
|
||||
final class LinkerServicesWithMissingMemberHandlerFactory implements LinkerServices {
|
||||
final LinkerServices linkerServices;
|
||||
final MissingMemberHandlerFactory missingMemberHandlerFactory;
|
||||
|
||||
static LinkerServices get(final LinkerServices linkerServices, final MissingMemberHandlerFactory missingMemberHandlerFactory) {
|
||||
if (missingMemberHandlerFactory == null) {
|
||||
return linkerServices;
|
||||
}
|
||||
return new LinkerServicesWithMissingMemberHandlerFactory(linkerServices, missingMemberHandlerFactory);
|
||||
}
|
||||
|
||||
private LinkerServicesWithMissingMemberHandlerFactory(final LinkerServices linkerServices, final MissingMemberHandlerFactory missingMemberHandlerFactory) {
|
||||
this.linkerServices = linkerServices;
|
||||
this.missingMemberHandlerFactory = missingMemberHandlerFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodHandle asType(final MethodHandle handle, final MethodType fromType) {
|
||||
return linkerServices.asType(handle, fromType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodHandle getTypeConverter(final Class<?> sourceType, final Class<?> targetType) {
|
||||
return linkerServices.getTypeConverter(sourceType, targetType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canConvert(final Class<?> from, final Class<?> to) {
|
||||
return linkerServices.canConvert(from, to);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest) throws Exception {
|
||||
return linkerServices.getGuardedInvocation(linkRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Comparison compareConversion(final Class<?> sourceType, final Class<?> targetType1, final Class<?> targetType2) {
|
||||
return linkerServices.compareConversion(sourceType, targetType1, targetType2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodHandle filterInternalObjects(final MethodHandle target) {
|
||||
return linkerServices.filterInternalObjects(target);
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.dynalink.beans;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import jdk.dynalink.DynamicLinkerFactory;
|
||||
import jdk.dynalink.NamedOperation;
|
||||
import jdk.dynalink.NoSuchDynamicMethodException;
|
||||
import jdk.dynalink.StandardOperation;
|
||||
import jdk.dynalink.linker.LinkRequest;
|
||||
import jdk.dynalink.linker.LinkerServices;
|
||||
|
||||
/**
|
||||
* A factory for creating method handles for linking missing member behavior
|
||||
* in {@link BeansLinker}. BeansLinker links these method handles into guarded
|
||||
* invocations for link requests specifying {@code GET_*} and {@code SET_*}
|
||||
* {@link StandardOperation}s when it is either certain or possible that the
|
||||
* requested member (property, method, or element) is missing. They will be
|
||||
* linked both for {@link NamedOperation named} and unnamed operations. The
|
||||
* implementer must ensure that the parameter types of the returned method
|
||||
* handle match the parameter types of the call site described in the link
|
||||
* request. The return types can differ, though, to allow
|
||||
* {@link DynamicLinkerFactory#setPrelinkTransformer(jdk.dynalink.linker.GuardedInvocationTransformer)}
|
||||
* late return type transformations}. It is allowed to return {@code null} for a
|
||||
* method handle if the default behavior is sufficient.
|
||||
* <h2>Default missing member behavior</h2>
|
||||
* When a {@link BeansLinker} is configured without a missing member handler
|
||||
* factory, or the factory returns {@code null} for a particular handler
|
||||
* creation invocation, the default behavior is used. The default behavior is to
|
||||
* return {@code null} from
|
||||
* {@link BeansLinker#getGuardedInvocation(LinkRequest, LinkerServices)} when it
|
||||
* can be determined at link time that the linked operation will never address
|
||||
* an existing member. This lets the {@code DynamicLinker} attempt the next
|
||||
* linker if there is one, or ultimately fail the link request with
|
||||
* {@link NoSuchDynamicMethodException}. For other cases (typically all unnamed
|
||||
* member operations as well as most named operations on collection elements)
|
||||
* {@code BeansLinker} will produce a conditional linkage that will return
|
||||
* {@code null} when invoked at runtime with a name that does not match any
|
||||
* member for getters and silently ignore the passed values for setters.
|
||||
* <h2>Implementing exception-throwing behavior</h2>
|
||||
* Note that if the language-specific behavior for an operation on a missing
|
||||
* member is to throw an exception then the factory should produce a method
|
||||
* handle that throws the exception when invoked, and must not throw an
|
||||
* exception itself, as the linkage for the missing member is often conditional.
|
||||
*
|
||||
* @see BeansLinker#BeansLinker(MissingMemberHandlerFactory)
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface MissingMemberHandlerFactory {
|
||||
/**
|
||||
* Returns a method handle suitable for implementing missing member behavior
|
||||
* for a particular link request. See the class description for details.
|
||||
* @param linkRequest the current link request
|
||||
* @param linkerServices the current link services
|
||||
* @return a method handle that can be invoked if the property, element, or
|
||||
* method being addressed by an operation is missing. The return value can
|
||||
* be null.
|
||||
* @throws Exception if the operation fails for any reason. Please observe
|
||||
* the class documentation notes for implementing exception-throwing
|
||||
* missing member behavior.
|
||||
*/
|
||||
public MethodHandle createMissingMemberHandler(LinkRequest linkRequest, LinkerServices linkerServices) throws Exception;
|
||||
}
|
@ -91,6 +91,7 @@ import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
import jdk.dynalink.CallSiteDescriptor;
|
||||
import jdk.dynalink.NamedOperation;
|
||||
import jdk.dynalink.Operation;
|
||||
import jdk.dynalink.StandardOperation;
|
||||
import jdk.dynalink.beans.GuardedInvocationComponent.ValidationType;
|
||||
import jdk.dynalink.linker.GuardedInvocation;
|
||||
@ -161,6 +162,27 @@ class StaticClassLinker implements TypeBasedGuardingDynamicLinker {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GuardedInvocationComponent getGuardedInvocationComponent(final ComponentLinkRequest req) throws Exception {
|
||||
final GuardedInvocationComponent superGic = super.getGuardedInvocationComponent(req);
|
||||
if (superGic != null) {
|
||||
return superGic;
|
||||
}
|
||||
if (!req.operations.isEmpty()) {
|
||||
final Operation op = req.operations.get(0);
|
||||
if (op instanceof StandardOperation) {
|
||||
switch ((StandardOperation)op) {
|
||||
case GET_ELEMENT:
|
||||
case SET_ELEMENT:
|
||||
// StaticClass doesn't behave as a collection
|
||||
return getNextComponent(req.popOperations());
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
SingleDynamicMethod getConstructorMethod(final String signature) {
|
||||
return constructor != null? constructor.getMethodForExactParamTypes(signature) : null;
|
||||
|
@ -202,6 +202,9 @@ public class GuardedInvocation {
|
||||
this.invocation = Objects.requireNonNull(invocation);
|
||||
this.guard = guard;
|
||||
this.switchPoints = switchPoint == null ? null : new SwitchPoint[] { switchPoint };
|
||||
if (exception != null && !Throwable.class.isAssignableFrom(exception)) {
|
||||
throw new IllegalArgumentException(exception.getName() + " is not assignable from Throwable");
|
||||
}
|
||||
this.exception = exception;
|
||||
}
|
||||
|
||||
@ -228,6 +231,9 @@ public class GuardedInvocation {
|
||||
this.invocation = Objects.requireNonNull(invocation);
|
||||
this.guard = guard;
|
||||
this.switchPoints = switchPoints == null ? null : switchPoints.clone();
|
||||
if (exception != null && !Throwable.class.isAssignableFrom(exception)) {
|
||||
throw new IllegalArgumentException(exception.getName() + " is not assignable from Throwable");
|
||||
}
|
||||
this.exception = exception;
|
||||
}
|
||||
|
||||
|
@ -1133,6 +1133,8 @@ public final class Global extends Scope {
|
||||
return NativeNumber.lookupPrimitive(request, self);
|
||||
} else if (self instanceof Boolean) {
|
||||
return NativeBoolean.lookupPrimitive(request, self);
|
||||
} else if (self instanceof Symbol) {
|
||||
return NativeSymbol.lookupPrimitive(request, self);
|
||||
}
|
||||
throw new IllegalArgumentException("Unsupported primitive: " + self);
|
||||
}
|
||||
|
@ -284,8 +284,8 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
|
||||
// Step 3c and 3d - get new length and convert to long
|
||||
final long newLen = NativeArray.validLength(newLenDesc.getValue());
|
||||
|
||||
// Step 3e
|
||||
newLenDesc.setValue(newLen);
|
||||
// Step 3e - note that we need to convert to int or double as long is not considered a JS number type anymore
|
||||
newLenDesc.setValue(JSType.isRepresentableAsInt(newLen) ? Integer.valueOf((int) newLen) : Double.valueOf((double) newLen));
|
||||
|
||||
// Step 3f
|
||||
// increasing array length - just need to set new length value (and attributes if any) and return
|
||||
@ -908,21 +908,6 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
|
||||
return getContinuousNonEmptyArrayDataCCE(self, IntElements.class).fastPopInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialization of pop for ContinuousArrayData
|
||||
*
|
||||
* Primitive specialization, {@link LinkLogic}
|
||||
*
|
||||
* @param self self reference
|
||||
* @return element popped
|
||||
* @throws ClassCastException if array is empty, facilitating Undefined return value
|
||||
*/
|
||||
@SpecializedFunction(name="pop", linkLogic=PopLinkLogic.class)
|
||||
public static long popLong(final Object self) {
|
||||
//must be non empty Int or LongArrayData
|
||||
return getContinuousNonEmptyArrayDataCCE(self, IntOrLongElements.class).fastPopLong();
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialization of pop for ContinuousArrayData
|
||||
*
|
||||
@ -997,7 +982,7 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
|
||||
* @return array length after push
|
||||
*/
|
||||
@SpecializedFunction(linkLogic=PushLinkLogic.class)
|
||||
public static long push(final Object self, final int arg) {
|
||||
public static double push(final Object self, final int arg) {
|
||||
return getContinuousArrayDataCCE(self, Integer.class).fastPush(arg);
|
||||
}
|
||||
|
||||
@ -1011,7 +996,7 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
|
||||
* @return array length after push
|
||||
*/
|
||||
@SpecializedFunction(linkLogic=PushLinkLogic.class)
|
||||
public static long push(final Object self, final long arg) {
|
||||
public static double push(final Object self, final long arg) {
|
||||
return getContinuousArrayDataCCE(self, Long.class).fastPush(arg);
|
||||
}
|
||||
|
||||
@ -1025,7 +1010,7 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
|
||||
* @return array length after push
|
||||
*/
|
||||
@SpecializedFunction(linkLogic=PushLinkLogic.class)
|
||||
public static long push(final Object self, final double arg) {
|
||||
public static double push(final Object self, final double arg) {
|
||||
return getContinuousArrayDataCCE(self, Double.class).fastPush(arg);
|
||||
}
|
||||
|
||||
@ -1039,7 +1024,7 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
|
||||
* @return array length after push
|
||||
*/
|
||||
@SpecializedFunction(name="push", linkLogic=PushLinkLogic.class)
|
||||
public static long pushObject(final Object self, final Object arg) {
|
||||
public static double pushObject(final Object self, final Object arg) {
|
||||
return getContinuousArrayDataCCE(self, Object.class).fastPush(arg);
|
||||
}
|
||||
|
||||
@ -1081,7 +1066,7 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
|
||||
* @return array after pushes
|
||||
*/
|
||||
@SpecializedFunction
|
||||
public static long push(final Object self, final Object arg) {
|
||||
public static double push(final Object self, final Object arg) {
|
||||
try {
|
||||
final ScriptObject sobj = (ScriptObject)self;
|
||||
final ArrayData arrayData = sobj.getArray();
|
||||
@ -1498,7 +1483,7 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
|
||||
* @return index of element, or -1 if not found
|
||||
*/
|
||||
@Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
|
||||
public static long indexOf(final Object self, final Object searchElement, final Object fromIndex) {
|
||||
public static double indexOf(final Object self, final Object searchElement, final Object fromIndex) {
|
||||
try {
|
||||
final ScriptObject sobj = (ScriptObject)Global.toObject(self);
|
||||
final long len = JSType.toUint32(sobj.getLength());
|
||||
@ -1534,7 +1519,7 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
|
||||
* @return index of element, or -1 if not found
|
||||
*/
|
||||
@Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
|
||||
public static long lastIndexOf(final Object self, final Object... args) {
|
||||
public static double lastIndexOf(final Object self, final Object... args) {
|
||||
try {
|
||||
final ScriptObject sobj = (ScriptObject)Global.toObject(self);
|
||||
final long len = JSType.toUint32(sobj.getLength());
|
||||
|
@ -168,9 +168,9 @@ public final class NativeBoolean extends ScriptObject {
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a native string in a NativeString object.
|
||||
* Wrap a native boolean in a NativeBoolean object.
|
||||
*
|
||||
* @param receiver Native string.
|
||||
* @param receiver Native boolean.
|
||||
* @return Wrapped object.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
|
@ -256,8 +256,9 @@ public final class NativeDate extends ScriptObject {
|
||||
* @return a Date that points to the current moment in time
|
||||
*/
|
||||
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
|
||||
public static long now(final Object self) {
|
||||
return System.currentTimeMillis();
|
||||
public static double now(final Object self) {
|
||||
// convert to double as long does not represent the primitive JS number type
|
||||
return (double) System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -48,6 +48,7 @@ import jdk.nashorn.internal.runtime.PropertyMap;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
import jdk.nashorn.internal.runtime.doubleconv.DoubleConversion;
|
||||
import jdk.nashorn.internal.runtime.linker.NashornGuards;
|
||||
import jdk.nashorn.internal.runtime.linker.PrimitiveLookup;
|
||||
|
||||
/**
|
||||
@ -315,7 +316,7 @@ public final class NativeNumber extends ScriptObject {
|
||||
* @return Link to be invoked at call site.
|
||||
*/
|
||||
public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Object receiver) {
|
||||
return PrimitiveLookup.lookupPrimitive(request, Number.class, new NativeNumber(((Number)receiver).doubleValue()), WRAPFILTER, PROTOFILTER);
|
||||
return PrimitiveLookup.lookupPrimitive(request, NashornGuards.getNumberGuard(), new NativeNumber(((Number)receiver).doubleValue()), WRAPFILTER, PROTOFILTER);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
|
@ -776,7 +776,7 @@ public final class NativeObject {
|
||||
final MethodType getterType = MethodType.methodType(Object.class, clazz);
|
||||
final MethodType setterType = MethodType.methodType(Object.class, clazz, Object.class);
|
||||
|
||||
final GuardingDynamicLinker linker = BeansLinker.getLinkerForClass(clazz);
|
||||
final GuardingDynamicLinker linker = Bootstrap.getBeanLinkerForClass(clazz);
|
||||
|
||||
final List<AccessorProperty> properties = new ArrayList<>(propertyNames.size() + methodNames.size());
|
||||
for(final String methodName: methodNames) {
|
||||
|
@ -74,7 +74,7 @@ public final class NativeRegExpExecResult extends ScriptObject {
|
||||
@Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
|
||||
public static Object length(final Object self) {
|
||||
if (self instanceof ScriptObject) {
|
||||
return JSType.toUint32(((ScriptObject)self).getArray().length());
|
||||
return (double) JSType.toUint32(((ScriptObject)self).getArray().length());
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -146,7 +146,7 @@ public final class NativeString extends ScriptObject implements OptimisticBuilti
|
||||
|
||||
if (returnType == Object.class && JSType.isString(self)) {
|
||||
try {
|
||||
return new GuardedInvocation(MH.findStatic(MethodHandles.lookup(), NativeString.class, "get", desc.getMethodType()), NashornGuards.getInstanceOf2Guard(String.class, ConsString.class));
|
||||
return new GuardedInvocation(MH.findStatic(MethodHandles.lookup(), NativeString.class, "get", desc.getMethodType()), NashornGuards.getStringGuard());
|
||||
} catch (final LookupException e) {
|
||||
//empty. Shouldn't happen. Fall back to super
|
||||
}
|
||||
@ -1235,8 +1235,8 @@ public final class NativeString extends ScriptObject implements OptimisticBuilti
|
||||
* @return Link to be invoked at call site.
|
||||
*/
|
||||
public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Object receiver) {
|
||||
final MethodHandle guard = NashornGuards.getInstanceOf2Guard(String.class, ConsString.class);
|
||||
return PrimitiveLookup.lookupPrimitive(request, guard, new NativeString((CharSequence)receiver), WRAPFILTER, PROTOFILTER);
|
||||
return PrimitiveLookup.lookupPrimitive(request, NashornGuards.getStringGuard(),
|
||||
new NativeString((CharSequence)receiver), WRAPFILTER, PROTOFILTER);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
|
@ -25,8 +25,14 @@
|
||||
|
||||
package jdk.nashorn.internal.objects;
|
||||
|
||||
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.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import jdk.dynalink.linker.GuardedInvocation;
|
||||
import jdk.dynalink.linker.LinkRequest;
|
||||
import jdk.nashorn.internal.WeakValueCache;
|
||||
import jdk.nashorn.internal.objects.annotations.Attribute;
|
||||
import jdk.nashorn.internal.objects.annotations.Constructor;
|
||||
@ -39,6 +45,7 @@ import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
import jdk.nashorn.internal.runtime.Symbol;
|
||||
import jdk.nashorn.internal.runtime.Undefined;
|
||||
import jdk.nashorn.internal.runtime.linker.PrimitiveLookup;
|
||||
|
||||
/**
|
||||
* ECMAScript 6 - 19.4 Symbol Objects
|
||||
@ -48,12 +55,21 @@ public final class NativeSymbol extends ScriptObject {
|
||||
|
||||
private final Symbol symbol;
|
||||
|
||||
/** Method handle to create an object wrapper for a primitive symbol. */
|
||||
static final MethodHandle WRAPFILTER = findOwnMH("wrapFilter", MH.type(NativeSymbol.class, Object.class));
|
||||
/** Method handle to retrieve the Symbol prototype object. */
|
||||
private static final MethodHandle PROTOFILTER = findOwnMH("protoFilter", MH.type(Object.class, Object.class));
|
||||
|
||||
// initialized by nasgen
|
||||
private static PropertyMap $nasgenmap$;
|
||||
|
||||
/** See ES6 19.4.2.1 */
|
||||
private static WeakValueCache<String, Symbol> globalSymbolRegistry = new WeakValueCache<>();
|
||||
|
||||
NativeSymbol(final Symbol symbol) {
|
||||
this(symbol, Global.instance());
|
||||
}
|
||||
|
||||
NativeSymbol(final Symbol symbol, final Global global) {
|
||||
this(symbol, global.getSymbolPrototype(), $nasgenmap$);
|
||||
}
|
||||
@ -73,6 +89,17 @@ public final class NativeSymbol extends ScriptObject {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup the appropriate method for an invoke dynamic call.
|
||||
*
|
||||
* @param request The link request
|
||||
* @param receiver The receiver for the call
|
||||
* @return Link to be invoked at call site.
|
||||
*/
|
||||
public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Object receiver) {
|
||||
return PrimitiveLookup.lookupPrimitive(request, Symbol.class, new NativeSymbol((Symbol)receiver), WRAPFILTER, PROTOFILTER);
|
||||
}
|
||||
|
||||
// ECMA 6 19.4.3.4 Symbol.prototype [ @@toPrimitive ] ( hint )
|
||||
@Override
|
||||
public Object getDefaultValue(final Class<?> typeHint) {
|
||||
@ -149,4 +176,19 @@ public final class NativeSymbol extends ScriptObject {
|
||||
final String name = ((Symbol) arg).getName();
|
||||
return globalSymbolRegistry.get(name) == arg ? name : Undefined.getUndefined();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static NativeSymbol wrapFilter(final Object receiver) {
|
||||
return new NativeSymbol((Symbol)receiver);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static Object protoFilter(final Object object) {
|
||||
return Global.instance().getSymbolPrototype();
|
||||
}
|
||||
|
||||
private static MethodHandle findOwnMH(final String name, final MethodType type) {
|
||||
return MH.findStatic(MethodHandles.lookup(), NativeSymbol.class, name, type);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -178,6 +178,12 @@ public enum JSType {
|
||||
/** Method handle for void returns. */
|
||||
public static final Call VOID_RETURN = staticCall(JSTYPE_LOOKUP, JSType.class, "voidReturn", void.class);
|
||||
|
||||
/** Method handle for isString method */
|
||||
public static final Call IS_STRING = staticCall(JSTYPE_LOOKUP, JSType.class, "isString", boolean.class, Object.class);
|
||||
|
||||
/** Method handle for isNumber method */
|
||||
public static final Call IS_NUMBER = staticCall(JSTYPE_LOOKUP, JSType.class, "isNumber", boolean.class, Object.class);
|
||||
|
||||
/**
|
||||
* The list of available accessor types in width order. This order is used for type guesses narrow{@literal ->} wide
|
||||
* in the dual--fields world
|
||||
@ -280,7 +286,7 @@ public enum JSType {
|
||||
return JSType.STRING;
|
||||
}
|
||||
|
||||
if (obj instanceof Number) {
|
||||
if (isNumber(obj)) {
|
||||
return JSType.NUMBER;
|
||||
}
|
||||
|
||||
@ -322,7 +328,7 @@ public enum JSType {
|
||||
return JSType.STRING;
|
||||
}
|
||||
|
||||
if (obj instanceof Number) {
|
||||
if (isNumber(obj)) {
|
||||
return JSType.NUMBER;
|
||||
}
|
||||
|
||||
@ -434,7 +440,7 @@ public enum JSType {
|
||||
return obj == null ||
|
||||
obj == ScriptRuntime.UNDEFINED ||
|
||||
isString(obj) ||
|
||||
obj instanceof Number ||
|
||||
isNumber(obj) ||
|
||||
obj instanceof Boolean ||
|
||||
obj instanceof Symbol;
|
||||
}
|
||||
@ -609,6 +615,24 @@ public enum JSType {
|
||||
return obj instanceof String || obj instanceof ConsString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if object represents a primitive JavaScript number value. Note that we only
|
||||
* treat wrapper objects of Java primitive number types as objects that can be fully represented
|
||||
* as JavaScript numbers (doubles). This means we exclude {@code long} and special purpose Number
|
||||
* instances such as {@link java.util.concurrent.atomic.AtomicInteger}, as well as arbitrary precision
|
||||
* numbers such as {@link java.math.BigInteger}.
|
||||
*
|
||||
* @param obj the object
|
||||
* @return true if the object represents a primitive JavaScript number value.
|
||||
*/
|
||||
public static boolean isNumber(final Object obj) {
|
||||
if (obj != null) {
|
||||
final Class<?> c = obj.getClass();
|
||||
return c == Integer.class || c == Double.class || c == Float.class || c == Short.class || c == Byte.class;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* JavaScript compliant conversion of integer to String
|
||||
*
|
||||
@ -761,7 +785,7 @@ public enum JSType {
|
||||
if (obj instanceof Double) {
|
||||
return (Double)obj;
|
||||
}
|
||||
if (obj instanceof Number) {
|
||||
if (isNumber(obj)) {
|
||||
return ((Number)obj).doubleValue();
|
||||
}
|
||||
return Double.NaN;
|
||||
@ -1337,7 +1361,7 @@ public enum JSType {
|
||||
return obj.toString();
|
||||
}
|
||||
|
||||
if (obj instanceof Number) {
|
||||
if (isNumber(obj)) {
|
||||
return toString(((Number)obj).doubleValue());
|
||||
}
|
||||
|
||||
|
@ -94,6 +94,9 @@ public final class Undefined extends DefaultPropertyAccess {
|
||||
*/
|
||||
public static GuardedInvocation lookup(final CallSiteDescriptor desc) {
|
||||
final StandardOperation op = NashornCallSiteDescriptor.getFirstStandardOperation(desc);
|
||||
if (op == null) {
|
||||
return null;
|
||||
}
|
||||
switch (op) {
|
||||
case CALL:
|
||||
case NEW:
|
||||
|
@ -287,7 +287,7 @@ public abstract class ContinuousArrayData extends ArrayData {
|
||||
* @param arg argument
|
||||
* @return new array length
|
||||
*/
|
||||
public long fastPush(final int arg) {
|
||||
public double fastPush(final int arg) {
|
||||
throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
|
||||
}
|
||||
|
||||
@ -296,7 +296,7 @@ public abstract class ContinuousArrayData extends ArrayData {
|
||||
* @param arg argument
|
||||
* @return new array length
|
||||
*/
|
||||
public long fastPush(final long arg) {
|
||||
public double fastPush(final long arg) {
|
||||
throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
|
||||
}
|
||||
|
||||
@ -305,7 +305,7 @@ public abstract class ContinuousArrayData extends ArrayData {
|
||||
* @param arg argument
|
||||
* @return new array length
|
||||
*/
|
||||
public long fastPush(final double arg) {
|
||||
public double fastPush(final double arg) {
|
||||
throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
|
||||
}
|
||||
|
||||
@ -314,7 +314,7 @@ public abstract class ContinuousArrayData extends ArrayData {
|
||||
* @param arg argument
|
||||
* @return new array length
|
||||
*/
|
||||
public long fastPush(final Object arg) {
|
||||
public double fastPush(final Object arg) {
|
||||
throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
|
||||
}
|
||||
|
||||
@ -326,14 +326,6 @@ public abstract class ContinuousArrayData extends ArrayData {
|
||||
throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialization - fast pop implementation
|
||||
* @return element value
|
||||
*/
|
||||
public long fastPopLong() {
|
||||
throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialization - fast pop implementation
|
||||
* @return element value
|
||||
|
@ -340,7 +340,7 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
|
||||
}
|
||||
|
||||
@Override
|
||||
public long fastPush(final int arg) {
|
||||
public double fastPush(final int arg) {
|
||||
final int len = (int)length();
|
||||
if (len == array.length) {
|
||||
array = Arrays.copyOf(array, nextSize(len));
|
||||
@ -361,11 +361,6 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
|
||||
return elem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long fastPopLong() {
|
||||
return fastPopInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double fastPopDouble() {
|
||||
return fastPopInt();
|
||||
|
@ -303,17 +303,17 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen
|
||||
}
|
||||
|
||||
@Override
|
||||
public long fastPush(final int arg) {
|
||||
public double fastPush(final int arg) {
|
||||
return fastPush((double)arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long fastPush(final long arg) {
|
||||
public double fastPush(final long arg) {
|
||||
return fastPush((double)arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long fastPush(final double arg) {
|
||||
public double fastPush(final double arg) {
|
||||
final int len = (int)length();
|
||||
if (len == array.length) {
|
||||
//note that fastpush never creates spares arrays, there is nothing to gain by that - it will just use even more memory
|
||||
|
@ -236,22 +236,22 @@ final class ObjectArrayData extends ContinuousArrayData implements AnyElements {
|
||||
}
|
||||
|
||||
@Override
|
||||
public long fastPush(final int arg) {
|
||||
public double fastPush(final int arg) {
|
||||
return fastPush((Object)arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long fastPush(final long arg) {
|
||||
public double fastPush(final long arg) {
|
||||
return fastPush((Object)arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long fastPush(final double arg) {
|
||||
public double fastPush(final double arg) {
|
||||
return fastPush((Object)arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long fastPush(final Object arg) {
|
||||
public double fastPush(final Object arg) {
|
||||
final int len = (int)length();
|
||||
if (len == array.length) {
|
||||
array = Arrays.copyOf(array, nextSize(len));
|
||||
|
@ -40,10 +40,11 @@ import jdk.dynalink.DynamicLinkerFactory;
|
||||
import jdk.dynalink.beans.BeansLinker;
|
||||
import jdk.dynalink.beans.StaticClass;
|
||||
import jdk.dynalink.linker.GuardedInvocation;
|
||||
import jdk.dynalink.linker.GuardedInvocationTransformer;
|
||||
import jdk.dynalink.linker.GuardingDynamicLinker;
|
||||
import jdk.dynalink.linker.LinkRequest;
|
||||
import jdk.dynalink.linker.LinkerServices;
|
||||
import jdk.dynalink.linker.MethodTypeConversionStrategy;
|
||||
import jdk.dynalink.linker.TypeBasedGuardingDynamicLinker;
|
||||
import jdk.dynalink.linker.support.TypeUtilities;
|
||||
import jdk.nashorn.api.scripting.JSObject;
|
||||
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
|
||||
@ -67,6 +68,24 @@ public final class Bootstrap {
|
||||
|
||||
private static final MethodHandle VOID_TO_OBJECT = MH.constant(Object.class, ScriptRuntime.UNDEFINED);
|
||||
|
||||
private static final BeansLinker beansLinker = new BeansLinker(Bootstrap::createMissingMemberHandler);
|
||||
private static final GuardingDynamicLinker[] prioritizedLinkers;
|
||||
private static final GuardingDynamicLinker[] fallbackLinkers;
|
||||
static {
|
||||
final NashornBeansLinker nashornBeansLinker = new NashornBeansLinker(beansLinker);
|
||||
prioritizedLinkers = new GuardingDynamicLinker[] {
|
||||
new NashornLinker(),
|
||||
new NashornPrimitiveLinker(),
|
||||
new NashornStaticClassLinker(beansLinker),
|
||||
new BoundCallableLinker(),
|
||||
new JavaSuperAdapterLinker(beansLinker),
|
||||
new JSObjectLinker(nashornBeansLinker),
|
||||
new BrowserJSObjectLinker(nashornBeansLinker),
|
||||
new ReflectionCheckLinker()
|
||||
};
|
||||
fallbackLinkers = new GuardingDynamicLinker[] {nashornBeansLinker, new NashornBottomLinker() };
|
||||
}
|
||||
|
||||
// do not create me!!
|
||||
private Bootstrap() {
|
||||
}
|
||||
@ -81,31 +100,14 @@ public final class Bootstrap {
|
||||
public static DynamicLinker createDynamicLinker(final ClassLoader appLoader,
|
||||
final int unstableRelinkThreshold) {
|
||||
final DynamicLinkerFactory factory = new DynamicLinkerFactory();
|
||||
final NashornBeansLinker nashornBeansLinker = new NashornBeansLinker();
|
||||
factory.setPrioritizedLinkers(
|
||||
new NashornLinker(),
|
||||
new NashornPrimitiveLinker(),
|
||||
new NashornStaticClassLinker(),
|
||||
new BoundCallableLinker(),
|
||||
new JavaSuperAdapterLinker(),
|
||||
new JSObjectLinker(nashornBeansLinker),
|
||||
new BrowserJSObjectLinker(nashornBeansLinker),
|
||||
new ReflectionCheckLinker());
|
||||
factory.setFallbackLinkers(nashornBeansLinker, new NashornBottomLinker());
|
||||
factory.setPrioritizedLinkers(prioritizedLinkers);
|
||||
factory.setFallbackLinkers(fallbackLinkers);
|
||||
factory.setSyncOnRelink(true);
|
||||
factory.setPrelinkTransformer(new GuardedInvocationTransformer() {
|
||||
@Override
|
||||
public GuardedInvocation filter(final GuardedInvocation inv, final LinkRequest request, final LinkerServices linkerServices) {
|
||||
final CallSiteDescriptor desc = request.getCallSiteDescriptor();
|
||||
return OptimisticReturnFilters.filterOptimisticReturnValue(inv, desc).asType(linkerServices, desc.getMethodType());
|
||||
}
|
||||
});
|
||||
factory.setAutoConversionStrategy(new MethodTypeConversionStrategy() {
|
||||
@Override
|
||||
public MethodHandle asType(final MethodHandle target, final MethodType newType) {
|
||||
return unboxReturnType(target, newType);
|
||||
}
|
||||
factory.setPrelinkTransformer((inv, request, linkerServices) -> {
|
||||
final CallSiteDescriptor desc = request.getCallSiteDescriptor();
|
||||
return OptimisticReturnFilters.filterOptimisticReturnValue(inv, desc).asType(linkerServices, desc.getMethodType());
|
||||
});
|
||||
factory.setAutoConversionStrategy(Bootstrap::unboxReturnType);
|
||||
factory.setInternalObjectsFilter(NashornBeansLinker.createHiddenObjectFilter());
|
||||
factory.setUnstableRelinkThreshold(unstableRelinkThreshold);
|
||||
|
||||
@ -114,6 +116,15 @@ public final class Bootstrap {
|
||||
return factory.createLinker();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a dynamic linker for the specific Java class using beans semantics.
|
||||
* @param clazz the Java class
|
||||
* @return a dynamic linker for the specific Java class using beans semantics.
|
||||
*/
|
||||
public static TypeBasedGuardingDynamicLinker getBeanLinkerForClass(final Class<?> clazz) {
|
||||
return beansLinker.getLinkerForClass(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the given object is a "callable"
|
||||
* @param obj object to be checked for callability
|
||||
@ -475,4 +486,14 @@ public final class Bootstrap {
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
private static MethodHandle createMissingMemberHandler(
|
||||
final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
|
||||
if (BrowserJSObjectLinker.canLinkTypeStatic(linkRequest.getReceiver().getClass())) {
|
||||
// Don't create missing member handlers for the browser JS objects as they
|
||||
// have their own logic.
|
||||
return null;
|
||||
}
|
||||
return NashornBottomLinker.linkMissingBeanMember(linkRequest, linkerServices);
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,6 @@
|
||||
|
||||
package jdk.nashorn.internal.runtime.linker;
|
||||
|
||||
import static jdk.nashorn.internal.lookup.Lookup.EMPTY_GETTER;
|
||||
import static jdk.nashorn.internal.runtime.linker.JavaAdapterBytecodeGenerator.SUPER_PREFIX;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
@ -62,6 +61,12 @@ final class JavaSuperAdapterLinker implements TypeBasedGuardingDynamicLinker {
|
||||
IS_ADAPTER_OF_CLASS = lookup.findOwnStatic("isAdapterOfClass", boolean.class, Class.class, Object.class);
|
||||
}
|
||||
|
||||
private final BeansLinker beansLinker;
|
||||
|
||||
JavaSuperAdapterLinker(final BeansLinker beansLinker) {
|
||||
this.beansLinker = beansLinker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canLinkType(final Class<?> type) {
|
||||
return type == JavaSuperAdapter.class;
|
||||
@ -101,17 +106,13 @@ final class JavaSuperAdapterLinker implements TypeBasedGuardingDynamicLinker {
|
||||
|
||||
// Delegate to BeansLinker
|
||||
final GuardedInvocation guardedInv = NashornBeansLinker.getGuardedInvocation(
|
||||
BeansLinker.getLinkerForClass(adapterClass), linkRequest.replaceArguments(newDescriptor, args),
|
||||
beansLinker, linkRequest.replaceArguments(newDescriptor, args),
|
||||
linkerServices);
|
||||
// Even for non-existent methods, Bootstrap's BeansLinker will link a
|
||||
// noSuchMember handler.
|
||||
assert guardedInv != null;
|
||||
|
||||
final MethodHandle guard = IS_ADAPTER_OF_CLASS.bindTo(adapterClass);
|
||||
if(guardedInv == null) {
|
||||
// Short circuit the lookup here for non-existent methods by linking an empty getter. If we just returned
|
||||
// null instead, BeansLinker would find final methods on the JavaSuperAdapter instead: getClass() and
|
||||
// wait().
|
||||
return new GuardedInvocation(MethodHandles.dropArguments(EMPTY_GETTER, 1,type.parameterList().subList(1,
|
||||
type.parameterCount())), guard).asType(descriptor);
|
||||
}
|
||||
|
||||
final MethodHandle invocation = guardedInv.getInvocation();
|
||||
final MethodType invType = invocation.type();
|
||||
@ -165,7 +166,7 @@ final class JavaSuperAdapterLinker implements TypeBasedGuardingDynamicLinker {
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private static Object bindDynamicMethod(final Object dynamicMethod, final Object boundThis) {
|
||||
return dynamicMethod == null ? ScriptRuntime.UNDEFINED : Bootstrap.bindCallable(dynamicMethod, boundThis, null);
|
||||
return dynamicMethod == ScriptRuntime.UNDEFINED ? ScriptRuntime.UNDEFINED : Bootstrap.bindCallable(dynamicMethod, boundThis, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -85,7 +85,11 @@ public class NashornBeansLinker implements GuardingDynamicLinker {
|
||||
}
|
||||
};
|
||||
|
||||
private final BeansLinker beansLinker = new BeansLinker();
|
||||
private final BeansLinker beansLinker;
|
||||
|
||||
NashornBeansLinker(final BeansLinker beansLinker) {
|
||||
this.beansLinker = beansLinker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
|
||||
|
@ -27,26 +27,27 @@ package jdk.nashorn.internal.runtime.linker;
|
||||
|
||||
import static jdk.nashorn.internal.lookup.Lookup.MH;
|
||||
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
|
||||
import static jdk.nashorn.internal.runtime.JSType.GET_UNDEFINED;
|
||||
import static jdk.nashorn.internal.runtime.JSType.TYPE_OBJECT_INDEX;
|
||||
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
import jdk.dynalink.CallSiteDescriptor;
|
||||
import jdk.dynalink.NamedOperation;
|
||||
import jdk.dynalink.Operation;
|
||||
import jdk.dynalink.StandardOperation;
|
||||
import jdk.dynalink.beans.BeansLinker;
|
||||
import jdk.dynalink.linker.GuardedInvocation;
|
||||
import jdk.dynalink.linker.GuardingDynamicLinker;
|
||||
import jdk.dynalink.linker.GuardingTypeConverterFactory;
|
||||
import jdk.dynalink.linker.LinkRequest;
|
||||
import jdk.dynalink.linker.LinkerServices;
|
||||
import jdk.dynalink.linker.support.Guards;
|
||||
import jdk.dynalink.linker.support.Lookup;
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.runtime.ECMAException;
|
||||
import jdk.nashorn.internal.runtime.JSType;
|
||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
|
||||
@ -73,7 +74,7 @@ final class NashornBottomLinker implements GuardingDynamicLinker, GuardingTypeCo
|
||||
// this point is a generic Java bean. Therefore, reaching here with a ScriptObject is a Nashorn bug.
|
||||
assert isExpectedObject(self) : "Couldn't link " + linkRequest.getCallSiteDescriptor() + " for " + self.getClass().getName();
|
||||
|
||||
return linkBean(linkRequest, linkerServices);
|
||||
return linkBean(linkRequest);
|
||||
}
|
||||
|
||||
private static final MethodHandle EMPTY_PROP_GETTER =
|
||||
@ -85,7 +86,18 @@ final class NashornBottomLinker implements GuardingDynamicLinker, GuardingTypeCo
|
||||
private static final MethodHandle EMPTY_ELEM_SETTER =
|
||||
MH.dropArguments(EMPTY_PROP_SETTER, 0, Object.class);
|
||||
|
||||
private static GuardedInvocation linkBean(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
|
||||
private static final MethodHandle THROW_NO_SUCH_FUNCTION;
|
||||
private static final MethodHandle THROW_STRICT_PROPERTY_SETTER;
|
||||
private static final MethodHandle THROW_OPTIMISTIC_UNDEFINED;
|
||||
|
||||
static {
|
||||
final Lookup lookup = new Lookup(MethodHandles.lookup());
|
||||
THROW_NO_SUCH_FUNCTION = lookup.findOwnStatic("throwNoSuchFunction", Object.class, Object.class, Object.class);
|
||||
THROW_STRICT_PROPERTY_SETTER = lookup.findOwnStatic("throwStrictPropertySetter", void.class, Object.class, Object.class);
|
||||
THROW_OPTIMISTIC_UNDEFINED = lookup.findOwnStatic("throwOptimisticUndefined", Object.class, int.class);
|
||||
}
|
||||
|
||||
private static GuardedInvocation linkBean(final LinkRequest linkRequest) throws Exception {
|
||||
final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor();
|
||||
final Object self = linkRequest.getReceiver();
|
||||
switch (NashornCallSiteDescriptor.getFirstStandardOperation(desc)) {
|
||||
@ -105,35 +117,79 @@ final class NashornBottomLinker implements GuardingDynamicLinker, GuardingTypeCo
|
||||
throw typeError("no.method.matches.args", ScriptRuntime.safeToString(self));
|
||||
}
|
||||
throw typeError("not.a.function", NashornCallSiteDescriptor.getFunctionErrorMessage(desc, self));
|
||||
case CALL_METHOD:
|
||||
throw typeError("no.such.function", getArgument(linkRequest), ScriptRuntime.safeToString(self));
|
||||
case GET_METHOD:
|
||||
// evaluate to undefined, later on Undefined will take care of throwing TypeError
|
||||
return getInvocation(MH.dropArguments(GET_UNDEFINED.get(TYPE_OBJECT_INDEX), 0, Object.class), self, linkerServices, desc);
|
||||
case GET_PROPERTY:
|
||||
case GET_ELEMENT:
|
||||
if(NashornCallSiteDescriptor.isOptimistic(desc)) {
|
||||
throw new UnwarrantedOptimismException(UNDEFINED, NashornCallSiteDescriptor.getProgramPoint(desc), Type.OBJECT);
|
||||
}
|
||||
if (NashornCallSiteDescriptor.getOperand(desc) != null) {
|
||||
return getInvocation(EMPTY_PROP_GETTER, self, linkerServices, desc);
|
||||
}
|
||||
return getInvocation(EMPTY_ELEM_GETTER, self, linkerServices, desc);
|
||||
case SET_PROPERTY:
|
||||
case SET_ELEMENT:
|
||||
final boolean strict = NashornCallSiteDescriptor.isStrict(desc);
|
||||
if (strict) {
|
||||
throw typeError("cant.set.property", getArgument(linkRequest), ScriptRuntime.safeToString(self));
|
||||
}
|
||||
if (NashornCallSiteDescriptor.getOperand(desc) != null) {
|
||||
return getInvocation(EMPTY_PROP_SETTER, self, linkerServices, desc);
|
||||
}
|
||||
return getInvocation(EMPTY_ELEM_SETTER, self, linkerServices, desc);
|
||||
default:
|
||||
// Everything else is supposed to have been already handled by Bootstrap.beansLinker
|
||||
// delegating to linkNoSuchBeanMember
|
||||
throw new AssertionError("unknown call type " + desc);
|
||||
}
|
||||
}
|
||||
|
||||
static MethodHandle linkMissingBeanMember(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
|
||||
final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor();
|
||||
final StandardOperation op = NashornCallSiteDescriptor.getFirstStandardOperation(desc);
|
||||
if (op != null) {
|
||||
final String operand = NashornCallSiteDescriptor.getOperand(desc);
|
||||
switch (op) {
|
||||
case CALL_METHOD:
|
||||
return adaptThrower(bindOperand(THROW_NO_SUCH_FUNCTION, operand), desc);
|
||||
case GET_METHOD:
|
||||
case GET_PROPERTY:
|
||||
case GET_ELEMENT: {
|
||||
if (NashornCallSiteDescriptor.isOptimistic(desc)) {
|
||||
return adaptThrower(MethodHandles.insertArguments(THROW_OPTIMISTIC_UNDEFINED, 0, NashornCallSiteDescriptor.getProgramPoint(desc)), desc);
|
||||
}
|
||||
if (NashornCallSiteDescriptor.getOperand(desc) != null) {
|
||||
return getInvocation(EMPTY_PROP_GETTER, linkerServices, desc);
|
||||
}
|
||||
return getInvocation(EMPTY_ELEM_GETTER, linkerServices, desc);
|
||||
}
|
||||
case SET_PROPERTY:
|
||||
case SET_ELEMENT:
|
||||
final boolean strict = NashornCallSiteDescriptor.isStrict(desc);
|
||||
if (strict) {
|
||||
return adaptThrower(bindOperand(THROW_STRICT_PROPERTY_SETTER, operand), desc);
|
||||
}
|
||||
if (NashornCallSiteDescriptor.getOperand(desc) != null) {
|
||||
return getInvocation(EMPTY_PROP_SETTER, linkerServices, desc);
|
||||
}
|
||||
return getInvocation(EMPTY_ELEM_SETTER, linkerServices, desc);
|
||||
default:
|
||||
}
|
||||
}
|
||||
throw new AssertionError("unknown call type " + desc);
|
||||
}
|
||||
|
||||
private static MethodHandle bindOperand(final MethodHandle handle, final String operand) {
|
||||
return operand == null ? handle : MethodHandles.insertArguments(handle, 1, operand);
|
||||
}
|
||||
|
||||
private static MethodHandle adaptThrower(final MethodHandle handle, final CallSiteDescriptor desc) {
|
||||
final MethodType targetType = desc.getMethodType();
|
||||
final int paramCount = handle.type().parameterCount();
|
||||
return MethodHandles
|
||||
.dropArguments(handle, paramCount, targetType.parameterList().subList(paramCount, targetType.parameterCount()))
|
||||
.asType(targetType);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static Object throwNoSuchFunction(final Object self, final Object name) {
|
||||
throw createTypeError(self, name, "no.such.function");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static void throwStrictPropertySetter(final Object self, final Object name) {
|
||||
throw createTypeError(self, name, "cant.set.property");
|
||||
}
|
||||
|
||||
private static ECMAException createTypeError(final Object self, final Object name, final String msg) {
|
||||
return typeError(msg, String.valueOf(name), ScriptRuntime.safeToString(self));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static Object throwOptimisticUndefined(final int programPoint) {
|
||||
throw new UnwarrantedOptimismException(UNDEFINED, programPoint, Type.OBJECT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuardedInvocation convertToType(final Class<?> sourceType, final Class<?> targetType, final Supplier<MethodHandles.Lookup> lookupSupplier) throws Exception {
|
||||
final GuardedInvocation gi = convertToTypeNoCast(sourceType, targetType);
|
||||
@ -158,8 +214,8 @@ final class NashornBottomLinker implements GuardingDynamicLinker, GuardingTypeCo
|
||||
return null;
|
||||
}
|
||||
|
||||
private static GuardedInvocation getInvocation(final MethodHandle handle, final Object self, final LinkerServices linkerServices, final CallSiteDescriptor desc) {
|
||||
return Bootstrap.asTypeSafeReturn(new GuardedInvocation(handle, Guards.getClassGuard(self.getClass())), linkerServices, desc);
|
||||
private static MethodHandle getInvocation(final MethodHandle handle, final LinkerServices linkerServices, final CallSiteDescriptor desc) {
|
||||
return linkerServices.asTypeLosslessReturn(handle, desc.getMethodType());
|
||||
}
|
||||
|
||||
// Used solely in an assertion to figure out if the object we get here is something we in fact expect. Objects
|
||||
|
@ -34,6 +34,7 @@ import jdk.dynalink.CallSiteDescriptor;
|
||||
import jdk.dynalink.linker.LinkRequest;
|
||||
import jdk.nashorn.api.scripting.JSObject;
|
||||
import jdk.nashorn.internal.objects.Global;
|
||||
import jdk.nashorn.internal.runtime.JSType;
|
||||
import jdk.nashorn.internal.runtime.Property;
|
||||
import jdk.nashorn.internal.runtime.PropertyMap;
|
||||
import jdk.nashorn.internal.runtime.ScriptFunction;
|
||||
@ -46,10 +47,9 @@ import jdk.nashorn.internal.runtime.options.Options;
|
||||
public final class NashornGuards {
|
||||
private static final MethodHandle IS_MAP = findOwnMH("isMap", boolean.class, ScriptObject.class, PropertyMap.class);
|
||||
private static final MethodHandle IS_MAP_SCRIPTOBJECT = findOwnMH("isMap", boolean.class, Object.class, PropertyMap.class);
|
||||
private static final MethodHandle IS_INSTANCEOF_2 = findOwnMH("isInstanceOf2", boolean.class, Object.class, Class.class, Class.class);
|
||||
private static final MethodHandle IS_SCRIPTOBJECT = findOwnMH("isScriptObject", boolean.class, Object.class);
|
||||
private static final MethodHandle IS_NOT_JSOBJECT = findOwnMH("isNotJSObject", boolean.class, Object.class);
|
||||
private static final MethodHandle SAME_OBJECT = findOwnMH("sameObject", boolean.class, Object.class, WeakReference.class);
|
||||
private static final MethodHandle SAME_OBJECT = findOwnMH("sameObject", boolean.class, Object.class, WeakReference.class);
|
||||
//TODO - maybe put this back in ScriptFunction instead of the ClassCastException.class relinkage
|
||||
//private static final MethodHandle IS_SCRIPTFUNCTION = findOwnMH("isScriptFunction", boolean.class, Object.class);
|
||||
|
||||
@ -165,14 +165,21 @@ public final class NashornGuards {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a guard that checks if in item is an instance of either of two classes.
|
||||
* Get a guard that checks if in item is a JS string.
|
||||
*
|
||||
* @param class1 the first class
|
||||
* @param class2 the second class
|
||||
* @return method handle for guard
|
||||
*/
|
||||
public static MethodHandle getInstanceOf2Guard(final Class<?> class1, final Class<?> class2) {
|
||||
return MH.insertArguments(IS_INSTANCEOF_2, 1, class1, class2);
|
||||
public static MethodHandle getStringGuard() {
|
||||
return JSType.IS_STRING.methodHandle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a guard that checks if in item is a JS number.
|
||||
*
|
||||
* @return method handle for guard
|
||||
*/
|
||||
public static MethodHandle getNumberGuard() {
|
||||
return JSType.IS_NUMBER.methodHandle();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -223,11 +230,6 @@ public final class NashornGuards {
|
||||
return self == ref.get();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static boolean isInstanceOf2(final Object self, final Class<?> class1, final Class<?> class2) {
|
||||
return class1.isInstance(self) || class2.isInstance(self);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static boolean isScriptFunction(final Object self) {
|
||||
return self instanceof ScriptFunction;
|
||||
|
@ -41,6 +41,7 @@ import jdk.nashorn.internal.objects.Global;
|
||||
import jdk.nashorn.internal.runtime.ConsString;
|
||||
import jdk.nashorn.internal.runtime.JSType;
|
||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
import jdk.nashorn.internal.runtime.Symbol;
|
||||
|
||||
/**
|
||||
* Internal linker for String, Boolean, and Number objects, only ever used by Nashorn engine and not exposed to other
|
||||
@ -57,7 +58,9 @@ final class NashornPrimitiveLinker implements TypeBasedGuardingDynamicLinker, Gu
|
||||
}
|
||||
|
||||
private static boolean canLinkTypeStatic(final Class<?> type) {
|
||||
return type == String.class || type == Boolean.class || type == ConsString.class || Number.class.isAssignableFrom(type);
|
||||
return type == String.class || type == Boolean.class || type == ConsString.class || type == Integer.class
|
||||
|| type == Double.class || type == Float.class || type == Short.class || type == Byte.class
|
||||
|| type == Symbol.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -167,7 +170,7 @@ final class NashornPrimitiveLinker implements TypeBasedGuardingDynamicLinker, Gu
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static boolean isJavaScriptPrimitive(final Object o) {
|
||||
return JSType.isString(o) || o instanceof Boolean || o instanceof Number || o == null;
|
||||
return JSType.isString(o) || o instanceof Boolean || JSType.isNumber(o) || o == null || o instanceof Symbol;
|
||||
}
|
||||
|
||||
private static final MethodHandle GUARD_PRIMITIVE = findOwnMH("isJavaScriptPrimitive", boolean.class, Object.class);
|
||||
|
@ -53,7 +53,11 @@ import jdk.nashorn.internal.runtime.ECMAErrors;
|
||||
* </pre>
|
||||
*/
|
||||
final class NashornStaticClassLinker implements TypeBasedGuardingDynamicLinker {
|
||||
private static final GuardingDynamicLinker staticClassLinker = BeansLinker.getLinkerForClass(StaticClass.class);
|
||||
private final GuardingDynamicLinker staticClassLinker;
|
||||
|
||||
NashornStaticClassLinker(final BeansLinker beansLinker) {
|
||||
this.staticClassLinker = beansLinker.getLinkerForClass(StaticClass.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canLinkType(final Class<?> type) {
|
||||
@ -100,7 +104,7 @@ final class NashornStaticClassLinker implements TypeBasedGuardingDynamicLinker {
|
||||
return delegate(linkerServices, request);
|
||||
}
|
||||
|
||||
private static GuardedInvocation delegate(final LinkerServices linkerServices, final LinkRequest request) throws Exception {
|
||||
private GuardedInvocation delegate(final LinkerServices linkerServices, final LinkRequest request) throws Exception {
|
||||
return NashornBeansLinker.getGuardedInvocation(staticClassLinker, request, linkerServices);
|
||||
}
|
||||
|
||||
|
@ -33,4 +33,4 @@ print(n);
|
||||
var s = n.toString(5);
|
||||
var m = parseInt(s, 5);
|
||||
print(m === n);
|
||||
print(n);
|
||||
print(m);
|
||||
|
@ -1,10 +1,10 @@
|
||||
abc
|
||||
[jdk.dynalink.beans.SimpleDynamicMethod java.lang.String(char[],int,int)]
|
||||
ava
|
||||
TypeError: null is not a function
|
||||
TypeError: null is not a function
|
||||
TypeError: null is not a function
|
||||
TypeError: Java.type("java.lang.Object")["()xxxxx"] is not a function
|
||||
TypeError: Java.type("java.lang.Object")["("] is not a function
|
||||
TypeError: Java.type("java.lang.Object")[")"] is not a function
|
||||
TypeError: Constructor [jdk.dynalink.beans.SimpleDynamicMethod java.lang.String(char[],int,int)] requires "new".
|
||||
TypeError: null is not a function
|
||||
TypeError: null is not a function
|
||||
TypeError: Java.type("java.lang.Runnable")["()"] is not a function
|
||||
TypeError: Java.type("java.lang.Runnable")["(int)"] is not a function
|
||||
java.lang.InstantiationException: java.io.InputStream
|
||||
|
@ -29,12 +29,13 @@
|
||||
*/
|
||||
|
||||
// Make sure index access on Java objects is working as expected.
|
||||
var map = new java.util.HashMap();
|
||||
var map = new java.util.LinkedHashMap();
|
||||
|
||||
map["foo"] = "bar";
|
||||
map[1] = 2;
|
||||
map[false] = true;
|
||||
map[null] = 0;
|
||||
map["a"] = null;
|
||||
|
||||
print(map);
|
||||
|
||||
@ -49,10 +50,12 @@ print(typeof map["foo"], map["foo"]);
|
||||
print(typeof map[1], map[1]);
|
||||
print(typeof map[false], map[false]);
|
||||
print(typeof map[null], map[null]);
|
||||
print(typeof map["a"], map["a"]);
|
||||
|
||||
print(map.foo);
|
||||
print(map.false);
|
||||
print(map.null);
|
||||
print("map.foo=" + map.foo);
|
||||
print("map.false=" + map.false);
|
||||
print("map.null=" + map.null);
|
||||
print("map.a=" + map.a);
|
||||
|
||||
map.foo = "baz";
|
||||
print(map);
|
||||
|
@ -1,13 +1,16 @@
|
||||
{null=0, 1=2, false=true, foo=bar}
|
||||
object null
|
||||
{foo=bar, 1=2, false=true, null=0, a=null}
|
||||
string foo
|
||||
number 1
|
||||
boolean false
|
||||
string foo
|
||||
object null
|
||||
string a
|
||||
string bar
|
||||
number 2
|
||||
boolean true
|
||||
number 0
|
||||
bar
|
||||
null
|
||||
null
|
||||
{null=0, 1=2, false=true, foo=baz}
|
||||
object null
|
||||
map.foo=bar
|
||||
map.false=undefined
|
||||
map.null=undefined
|
||||
map.a=null
|
||||
{foo=baz, 1=2, false=true, null=0, a=null}
|
||||
|
@ -5,8 +5,8 @@ int array: check widen for false [class java.lang.Boolean]
|
||||
int array: check widen for true [class java.lang.Boolean]
|
||||
int array: check widen for 34 [class java.lang.Byte]
|
||||
int array: check widen for 344454 [class java.lang.Integer]
|
||||
int array: check widen for 454545 [class java.lang.Long]
|
||||
int array: check widen for 2147483648 [class java.lang.Long]
|
||||
int array: check widen for 454545
|
||||
int array: check widen for 2147483648
|
||||
int array: check widen for 34.29999923706055 [class java.lang.Float]
|
||||
int array: check widen for 3.141592653589793 [class java.lang.Double]
|
||||
int array: check widen for s
|
||||
@ -17,8 +17,8 @@ long array: check widen for false [class java.lang.Boolean]
|
||||
long array: check widen for true [class java.lang.Boolean]
|
||||
long array: check widen for 34 [class java.lang.Byte]
|
||||
long array: check widen for 344454 [class java.lang.Integer]
|
||||
long array: check widen for 454545 [class java.lang.Long]
|
||||
long array: check widen for 2147483648 [class java.lang.Long]
|
||||
long array: check widen for 454545
|
||||
long array: check widen for 2147483648
|
||||
long array: check widen for 34.29999923706055 [class java.lang.Float]
|
||||
long array: check widen for 3.141592653589793 [class java.lang.Double]
|
||||
long array: check widen for s
|
||||
@ -29,8 +29,8 @@ number array: check widen for false [class java.lang.Boolean]
|
||||
number array: check widen for true [class java.lang.Boolean]
|
||||
number array: check widen for 34 [class java.lang.Byte]
|
||||
number array: check widen for 344454 [class java.lang.Integer]
|
||||
number array: check widen for 454545 [class java.lang.Long]
|
||||
number array: check widen for 2147483648 [class java.lang.Long]
|
||||
number array: check widen for 454545
|
||||
number array: check widen for 2147483648
|
||||
number array: check widen for 34.29999923706055 [class java.lang.Float]
|
||||
number array: check widen for 3.141592653589793 [class java.lang.Double]
|
||||
number array: check widen for s
|
||||
@ -41,8 +41,8 @@ object array: check widen for false [class java.lang.Boolean]
|
||||
object array: check widen for true [class java.lang.Boolean]
|
||||
object array: check widen for 34 [class java.lang.Byte]
|
||||
object array: check widen for 344454 [class java.lang.Integer]
|
||||
object array: check widen for 454545 [class java.lang.Long]
|
||||
object array: check widen for 2147483648 [class java.lang.Long]
|
||||
object array: check widen for 454545
|
||||
object array: check widen for 2147483648
|
||||
object array: check widen for 34.29999923706055 [class java.lang.Float]
|
||||
object array: check widen for 3.141592653589793 [class java.lang.Double]
|
||||
object array: check widen for s
|
||||
|
107
nashorn/test/script/basic/JDK-8143896.js
Normal file
107
nashorn/test/script/basic/JDK-8143896.js
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8143896: java.lang.Long is implicitly converted to double
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
Assert.assertTrue(java.lang.Long.valueOf("301077366599181567").toString() === "301077366599181567");
|
||||
Assert.assertTrue(java.lang.Long.valueOf("-301077366599181567").toString() === "-301077366599181567");
|
||||
Assert.assertTrue(java.lang.Long.valueOf("301077366599181567") == 301077366599181567);
|
||||
Assert.assertFalse(java.lang.Long.valueOf("301077366599181567") === 301077366599181567);
|
||||
|
||||
Assert.assertTrue(new java.math.BigInteger("301077366599181567").toString() === "301077366599181567");
|
||||
Assert.assertTrue(new java.math.BigInteger("-301077366599181567").toString() === "-301077366599181567");
|
||||
Assert.assertTrue(new java.math.BigInteger("301077366599181567") == 301077366599181567);
|
||||
Assert.assertFalse(new java.math.BigInteger("301077366599181567") === 301077366599181567);
|
||||
|
||||
|
||||
var n = new java.lang.Byte("123");
|
||||
Assert.assertTrue(typeof n === "number");
|
||||
Assert.assertTrue(n + 1 === 124);
|
||||
Assert.assertTrue(n == 123);
|
||||
Assert.assertTrue(n === 123);
|
||||
|
||||
n = new java.lang.Short("123");
|
||||
Assert.assertTrue(typeof n === "number");
|
||||
Assert.assertTrue(n + 1 === 124);
|
||||
Assert.assertTrue(n == 123);
|
||||
Assert.assertTrue(n === 123);
|
||||
|
||||
n = new java.lang.Integer("123");
|
||||
Assert.assertTrue(typeof n === "number");
|
||||
Assert.assertTrue(n + 1 === 124);
|
||||
Assert.assertTrue(n == 123);
|
||||
Assert.assertTrue(n === 123);
|
||||
|
||||
n = new java.lang.Float("123");
|
||||
Assert.assertTrue(typeof n === "number");
|
||||
Assert.assertTrue(n + 1 === 124);
|
||||
Assert.assertTrue(n == 123);
|
||||
Assert.assertTrue(n === 123);
|
||||
|
||||
n = new java.lang.Double("123");
|
||||
Assert.assertTrue(typeof n === "number");
|
||||
Assert.assertTrue(n + 1 === 124);
|
||||
Assert.assertTrue(n == 123);
|
||||
Assert.assertTrue(n === 123);
|
||||
|
||||
n = new java.lang.Long("123");
|
||||
Assert.assertTrue(typeof n === "object");
|
||||
Assert.assertTrue(n + 1 === 124);
|
||||
Assert.assertTrue(n == 123);
|
||||
Assert.assertFalse(n === 123);
|
||||
|
||||
n = new java.util.concurrent.atomic.DoubleAdder();
|
||||
n.add("123");
|
||||
Assert.assertTrue(typeof n === "object");
|
||||
Assert.assertTrue(n + 1 === 124);
|
||||
Assert.assertTrue(n == 123);
|
||||
Assert.assertFalse(n === 123);
|
||||
|
||||
n = new java.util.concurrent.atomic.AtomicInteger(123);
|
||||
Assert.assertTrue(typeof n === "object");
|
||||
Assert.assertTrue(n + 1 === 124);
|
||||
Assert.assertTrue(n == 123);
|
||||
Assert.assertFalse(n === 123);
|
||||
|
||||
n = new java.util.concurrent.atomic.AtomicLong(123);
|
||||
Assert.assertTrue(typeof n === "object");
|
||||
Assert.assertTrue(n + 1 === 124);
|
||||
Assert.assertTrue(n == 123);
|
||||
Assert.assertFalse(n === 123);
|
||||
|
||||
n = new java.math.BigInteger("123");
|
||||
Assert.assertTrue(typeof n === "object");
|
||||
Assert.assertTrue(n + 1 === 124);
|
||||
Assert.assertTrue(n == 123);
|
||||
Assert.assertFalse(n === 123);
|
||||
|
||||
n = new java.math.BigDecimal("123");
|
||||
Assert.assertTrue(typeof n === "object");
|
||||
Assert.assertTrue(n + 1 === 124);
|
||||
Assert.assertTrue(n == 123);
|
||||
Assert.assertFalse(n === 123);
|
@ -40,11 +40,11 @@ Assert.assertTrue(Symbol([1, 2, 3]).toString() === 'Symbol(1,2,3)');
|
||||
Assert.assertTrue(Symbol(null).toString() === 'Symbol(null)');
|
||||
Assert.assertTrue(Symbol(undefined).toString() === 'Symbol()');
|
||||
|
||||
var s1 = Symbol();
|
||||
var s2 = Symbol("s2");
|
||||
const s1 = Symbol();
|
||||
const s2 = Symbol("s2");
|
||||
Assert.assertFalse(s1 instanceof Symbol); // not an object
|
||||
|
||||
var obj = {};
|
||||
let obj = {};
|
||||
obj['foo'] = 'foo';
|
||||
obj[s1] = s1;
|
||||
obj['bar'] = 'bar';
|
||||
@ -57,17 +57,17 @@ Assert.assertTrue(obj['bar'] === 'bar');
|
||||
Assert.assertTrue(obj[1] === 1);
|
||||
Assert.assertTrue(obj[s2] === s2);
|
||||
|
||||
var expectedNames = ['1', 'foo', 'bar'];
|
||||
var expectedSymbols = [s1, s2];
|
||||
var actualNames = Object.getOwnPropertyNames(obj);
|
||||
var actualSymbols = Object.getOwnPropertySymbols(obj);
|
||||
const expectedNames = ['1', 'foo', 'bar'];
|
||||
const expectedSymbols = [s1, s2];
|
||||
const actualNames = Object.getOwnPropertyNames(obj);
|
||||
let actualSymbols = Object.getOwnPropertySymbols(obj);
|
||||
Assert.assertTrue(expectedNames.length == actualNames.length);
|
||||
Assert.assertTrue(expectedSymbols.length == actualSymbols.length);
|
||||
|
||||
for (var key in expectedNames) {
|
||||
for (let key in expectedNames) {
|
||||
Assert.assertTrue(expectedNames[key] === actualNames[key]);
|
||||
}
|
||||
for (var key in expectedSymbols) {
|
||||
for (let key in expectedSymbols) {
|
||||
Assert.assertTrue(expectedSymbols[key] === actualSymbols[key]);
|
||||
}
|
||||
|
||||
@ -114,8 +114,8 @@ try {
|
||||
|
||||
// Symbol.for and Symbol.keyFor
|
||||
|
||||
var uncached = Symbol('foo');
|
||||
var cached = Symbol.for('foo');
|
||||
const uncached = Symbol('foo');
|
||||
const cached = Symbol.for('foo');
|
||||
|
||||
Assert.assertTrue(uncached !== cached);
|
||||
Assert.assertTrue(Symbol.keyFor(uncached) === undefined);
|
||||
@ -123,9 +123,15 @@ Assert.assertTrue(Symbol.keyFor(cached) === 'foo');
|
||||
Assert.assertTrue(cached === Symbol.for('foo'));
|
||||
Assert.assertTrue(cached === Symbol.for('f' + 'oo'));
|
||||
|
||||
// JDK-8147008: Make sure symbols are handled by primitive linker
|
||||
Symbol.prototype.foo = 123;
|
||||
Symbol.prototype[s2] = s2;
|
||||
Assert.assertEquals(s1.foo, 123);
|
||||
Assert.assertEquals(s2[s2], s2);
|
||||
|
||||
// Object wrapper
|
||||
|
||||
var o = Object(s1);
|
||||
const o = Object(s1);
|
||||
obj = {};
|
||||
obj[s1] = "s1";
|
||||
Assert.assertTrue(o == s1);
|
||||
@ -134,6 +140,8 @@ Assert.assertTrue(typeof o === 'object');
|
||||
Assert.assertTrue(o instanceof Symbol);
|
||||
Assert.assertTrue(obj[o] == 's1');
|
||||
Assert.assertTrue(o in obj);
|
||||
Assert.assertEquals(o.foo, 123);
|
||||
Assert.assertEquals(o[s2], s2);
|
||||
|
||||
// various non-strict comparisons that should fail
|
||||
|
||||
|
@ -54,15 +54,14 @@ print("l['blah']=" + l['blah']) // non-number indices don't retrieve anything...
|
||||
var size_name = "size"
|
||||
print("l[size_name]()=" + l[size_name]()) // ... but existing methods can be accessed with []
|
||||
|
||||
expectException(2) // Java lists don't auto-expand to accommodate new indices
|
||||
expectException(java.lang.Double.POSITIVE_INFINITY) // Dynalink will throw IOOBE
|
||||
expectException(java.lang.Double.NEGATIVE_INFINITY) // Dynalink will throw IOOBE
|
||||
// All illegal indices, even those out of bounds, return undefined
|
||||
print("l[2]=" + l[2]);
|
||||
print("l[-1]=" + l[-1]);
|
||||
print("l[2.1]=" + l[2.1]);
|
||||
print("l[-1.1]=" + l[-1.1]);
|
||||
print("l[Infinity]=" + l[Infinity]);
|
||||
print("l[-Infinity]=" + l[-Infinity]);
|
||||
print("l[NaN]=" + l[NaN]);
|
||||
|
||||
function expectException(index) {
|
||||
try {
|
||||
l[index] = "x"
|
||||
print("Not caught out-of-bounds assignment for " + index)
|
||||
} catch(e) {
|
||||
print(e)
|
||||
}
|
||||
}
|
||||
l[1.1]="b"; // should be no-op
|
||||
print("l[0]=" + l[0]);
|
||||
|
@ -9,9 +9,14 @@ bar
|
||||
--for each end--
|
||||
l[0]=foo
|
||||
l[1]=a
|
||||
l[0.9]=null
|
||||
l[0.9]=undefined
|
||||
l['blah']=undefined
|
||||
l[size_name]()=2
|
||||
java.lang.IndexOutOfBoundsException: Index: 2, Size: 2
|
||||
java.lang.IndexOutOfBoundsException: Index: Infinity, Size: 2
|
||||
java.lang.IndexOutOfBoundsException: Index: -Infinity, Size: 2
|
||||
l[2]=undefined
|
||||
l[-1]=undefined
|
||||
l[2.1]=undefined
|
||||
l[-1.1]=undefined
|
||||
l[Infinity]=undefined
|
||||
l[-Infinity]=undefined
|
||||
l[NaN]=undefined
|
||||
l[0]=foo
|
||||
|
@ -44,8 +44,8 @@ print("m.empty = " + m.empty) // prints "false"
|
||||
print("m['empty'] = " + m['empty'])
|
||||
print("m[empty_key] = " + m[empty_key]) // prints "foo"
|
||||
|
||||
print("m.bwah = " + m.bwah) // prints "null"
|
||||
print("m['bwah'] = " + m['bwah']) // prints "null"
|
||||
print("m.bwah = " + m.bwah) // prints "undefined"
|
||||
print("m['bwah'] = " + m['bwah']) // prints "undefined"
|
||||
|
||||
m.put("twonk", "ding")
|
||||
print("m.twonk = " + m.twonk) // prints "ding"
|
||||
|
@ -7,8 +7,8 @@ m = {empty=foo}
|
||||
m.empty = false
|
||||
m['empty'] = foo
|
||||
m[empty_key] = foo
|
||||
m.bwah = null
|
||||
m['bwah'] = null
|
||||
m.bwah = undefined
|
||||
m['bwah'] = undefined
|
||||
m.twonk = ding
|
||||
m['twonk'] = ding
|
||||
m.size()=2
|
||||
|
68
nashorn/test/script/nosecurity/context-dependent-logging.js
Normal file
68
nashorn/test/script/nosecurity/context-dependent-logging.js
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test that logging configuration is per engine, rather than per process.
|
||||
*
|
||||
* @test
|
||||
* @bug 8036977
|
||||
* @run/ignore-std-error
|
||||
* @fork
|
||||
* @option -scripting
|
||||
*/
|
||||
|
||||
// To test, start another engine (testEngine) with a time logger and ensure the
|
||||
// logger exists.
|
||||
|
||||
var NashornFactory = new (Java.type('jdk.nashorn.api.scripting.NashornScriptEngineFactory'))(),
|
||||
testEngine = NashornFactory.getScriptEngine("-scripting", "--log=time")
|
||||
|
||||
if (!testEngine.eval('$OPTIONS._loggers.time')) {
|
||||
throw 'fresh testEngine does not have time logger'
|
||||
}
|
||||
|
||||
// To test further, have the testEngine start yet another engine (e) without
|
||||
// time logging, but with compiler logging. Check the logging is as configured,
|
||||
// and verify the testEngine still has time logging, but no compiler logging.
|
||||
|
||||
var script = <<EOS
|
||||
var F = new (Java.type('jdk.nashorn.api.scripting.NashornScriptEngineFactory'))(),
|
||||
e = F.getScriptEngine('-scripting', '--log=compiler')
|
||||
if (!e.eval('$OPTIONS._loggers.compiler')) {
|
||||
throw 'e does not have compiler logger'
|
||||
}
|
||||
if (e.eval('$OPTIONS._loggers.time')) {
|
||||
throw 'e has time logger'
|
||||
}
|
||||
EOS
|
||||
|
||||
testEngine.eval(script)
|
||||
|
||||
if (!testEngine.eval('$OPTIONS._loggers.time')) {
|
||||
throw 'after-test testEngine does not have time logger'
|
||||
}
|
||||
if (testEngine.eval('$OPTIONS._loggers.compiler')) {
|
||||
throw 'after-test testEngine has compiler logger'
|
||||
}
|
@ -30,8 +30,8 @@
|
||||
*/
|
||||
|
||||
function Parser() {
|
||||
// create nashorn parser
|
||||
this._parser = Parser.create();
|
||||
// create nashorn parser
|
||||
this._parser = Parser.create();
|
||||
}
|
||||
|
||||
// Java types used
|
||||
@ -54,59 +54,60 @@ Parser.create = function() {
|
||||
|
||||
// convert Nashorn parser Tree, Diagnostic as a script friendly object
|
||||
Parser.prototype.convert = function(tree) {
|
||||
if (!tree || typeof tree != 'object') {
|
||||
if (!tree || typeof tree != 'object' || tree instanceof java.lang.Long) {
|
||||
return tree;
|
||||
}
|
||||
|
||||
var obj = Object.bindProperties({}, tree);
|
||||
var result = {};
|
||||
for (var i in obj) {
|
||||
var val = obj[i];
|
||||
if (val instanceof Parser.Tree) {
|
||||
result[i] = this.convert(val);
|
||||
} else if (val instanceof Parser.List) {
|
||||
var arr = new Array(val.size());
|
||||
for (var j in val) {
|
||||
arr[j] = this.convert(val[j]);
|
||||
}
|
||||
|
||||
result[i] = arr;
|
||||
} else {
|
||||
switch (typeof val) {
|
||||
case 'number':
|
||||
case 'string':
|
||||
case 'boolean':
|
||||
result[i] = String(val);
|
||||
default:
|
||||
if (val instanceof Parser.Enum) {
|
||||
result[i] = String(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
var val = obj[i];
|
||||
if (val instanceof Parser.Tree) {
|
||||
result[i] = this.convert(val);
|
||||
} else if (val instanceof Parser.List) {
|
||||
var arr = new Array(val.size());
|
||||
for (var j in val) {
|
||||
arr[j] = this.convert(val[j]);
|
||||
}
|
||||
|
||||
result[i] = arr;
|
||||
} else {
|
||||
switch (typeof val) {
|
||||
case 'number':
|
||||
case 'string':
|
||||
case 'boolean':
|
||||
result[i] = String(val);
|
||||
break;
|
||||
default:
|
||||
if (val instanceof java.lang.Long || val instanceof Parser.Enum) {
|
||||
result[i] = String(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function processFiles(subdir) {
|
||||
var File = Java.type("java.io.File");
|
||||
var files = new File(__DIR__ + subdir).listFiles();
|
||||
java.util.Arrays.sort(files);
|
||||
for each (var file in files) {
|
||||
if (file.name.endsWith(".js")) {
|
||||
var script = readFully(file);
|
||||
var parser = new Parser();
|
||||
var tree = parser.parse(subdir + "/" + file.name, script,
|
||||
function(diagnostic) {
|
||||
print(JSON.stringify(parser.convert(diagnostic), null, 2).replace(/\\r/g, ''));
|
||||
print(",");
|
||||
});
|
||||
var File = Java.type("java.io.File");
|
||||
var files = new File(__DIR__ + subdir).listFiles();
|
||||
java.util.Arrays.sort(files);
|
||||
for each (var file in files) {
|
||||
if (file.name.endsWith(".js")) {
|
||||
var script = readFully(file);
|
||||
var parser = new Parser();
|
||||
var tree = parser.parse(subdir + "/" + file.name, script,
|
||||
function(diagnostic) {
|
||||
print(JSON.stringify(parser.convert(diagnostic), null, 2).replace(/\\r/g, ''));
|
||||
print(",");
|
||||
});
|
||||
|
||||
if (tree != null) {
|
||||
print(JSON.stringify(tree, null, 2));
|
||||
print(",");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tree != null) {
|
||||
print(JSON.stringify(tree, null, 2));
|
||||
print(",");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// parse files in parsertests directory
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,23 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Or1cle 1nd/or its 1ffili1tes. 1ll rights reserved.
|
||||
* DO NOT 1LTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HE1DER.
|
||||
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free softw1re; you c1n redistri2ute it 1nd/or modify it
|
||||
* under the terms of the GNU Gener1l Pu2lic License version 2 only, 1s
|
||||
* pu2lished 2y the Free Softw1re Found1tion.
|
||||
* 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 distri2uted in the hope th1t it will 2e useful, 2ut WITHOUT
|
||||
* 1NY W1RR1NTY; without even the implied w1rr1nty of MERCH1NT12ILITY or
|
||||
* FITNESS FOR 1 P1RTICUL1R PURPOSE. See the GNU Gener1l Pu2lic License
|
||||
* version 2 for more det1ils (1 copy is included in the LICENSE file th1t
|
||||
* 1ccomp1nied 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 h1ve received 1 copy of the GNU Gener1l Pu2lic License version
|
||||
* 2 1long with this work; if not, write to the Free Softw1re Found1tion,
|
||||
* Inc., 51 Fr1nklin St, Fifth Floor, 2oston, M1 02110-1301 US1.
|
||||
* 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.
|
||||
*
|
||||
* Ple1se cont1ct Or1cle, 500 Or1cle P1rkw1y, Redwood Shores, C1 94065 US1
|
||||
* or visit www.or1cle.com if you need 1ddition1l inform1tion or h1ve 1ny
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@ -47,4 +47,4 @@ parse("forloop.js", code, "-nse", new (Java.extend(visitor, {
|
||||
visitForLoop : function (node, obj) {
|
||||
obj.push(convert(node))
|
||||
}
|
||||
})))
|
||||
})))
|
||||
|
@ -1,23 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Or1cle 1nd/or its 1ffili1tes. 1ll rights reserved.
|
||||
* DO NOT 1LTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HE1DER.
|
||||
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free softw1re; you c1n redistri2ute it 1nd/or modify it
|
||||
* under the terms of the GNU Gener1l Pu2lic License version 2 only, 1s
|
||||
* pu2lished 2y the Free Softw1re Found1tion.
|
||||
* 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 distri2uted in the hope th1t it will 2e useful, 2ut WITHOUT
|
||||
* 1NY W1RR1NTY; without even the implied w1rr1nty of MERCH1NT12ILITY or
|
||||
* FITNESS FOR 1 P1RTICUL1R PURPOSE. See the GNU Gener1l Pu2lic License
|
||||
* version 2 for more det1ils (1 copy is included in the LICENSE file th1t
|
||||
* 1ccomp1nied 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 h1ve received 1 copy of the GNU Gener1l Pu2lic License version
|
||||
* 2 1long with this work; if not, write to the Free Softw1re Found1tion,
|
||||
* Inc., 51 Fr1nklin St, Fifth Floor, 2oston, M1 02110-1301 US1.
|
||||
* 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.
|
||||
*
|
||||
* Ple1se cont1ct Or1cle, 500 Or1cle P1rkw1y, Redwood Shores, C1 94065 US1
|
||||
* or visit www.or1cle.com if you need 1ddition1l inform1tion or h1ve 1ny
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@ -45,4 +45,4 @@ parse("forinloop.js", code, "-nse", new (Java.extend(visitor, {
|
||||
visitForInLoop : function (node, obj) {
|
||||
obj.push(convert(node))
|
||||
}
|
||||
})))
|
||||
})))
|
||||
|
@ -1,23 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Or1cle 1nd/or its 1ffili1tes. 1ll rights reserved.
|
||||
* DO NOT 1LTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HE1DER.
|
||||
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free softw1re; you c1n redistri2ute it 1nd/or modify it
|
||||
* under the terms of the GNU Gener1l Pu2lic License version 2 only, 1s
|
||||
* pu2lished 2y the Free Softw1re Found1tion.
|
||||
* 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 distri2uted in the hope th1t it will 2e useful, 2ut WITHOUT
|
||||
* 1NY W1RR1NTY; without even the implied w1rr1nty of MERCH1NT12ILITY or
|
||||
* FITNESS FOR 1 P1RTICUL1R PURPOSE. See the GNU Gener1l Pu2lic License
|
||||
* version 2 for more det1ils (1 copy is included in the LICENSE file th1t
|
||||
* 1ccomp1nied 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 h1ve received 1 copy of the GNU Gener1l Pu2lic License version
|
||||
* 2 1long with this work; if not, write to the Free Softw1re Found1tion,
|
||||
* Inc., 51 Fr1nklin St, Fifth Floor, 2oston, M1 02110-1301 US1.
|
||||
* 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.
|
||||
*
|
||||
* Ple1se cont1ct Or1cle, 500 Or1cle P1rkw1y, Redwood Shores, C1 94065 US1
|
||||
* or visit www.or1cle.com if you need 1ddition1l inform1tion or h1ve 1ny
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@ -51,4 +51,4 @@ parse("functionCall.js", code, "-nse", new (Java.extend(visitor, {
|
||||
visitFunctionCall : function (node, obj) {
|
||||
obj.push(convert(node))
|
||||
}
|
||||
})))
|
||||
})))
|
||||
|
@ -1,23 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Or1cle 1nd/or its 1ffili1tes. 1ll rights reserved.
|
||||
* DO NOT 1LTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HE1DER.
|
||||
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free softw1re; you c1n redistri2ute it 1nd/or modify it
|
||||
* under the terms of the GNU Gener1l Pu2lic License version 2 only, 1s
|
||||
* pu2lished 2y the Free Softw1re Found1tion.
|
||||
* 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 distri2uted in the hope th1t it will 2e useful, 2ut WITHOUT
|
||||
* 1NY W1RR1NTY; without even the implied w1rr1nty of MERCH1NT12ILITY or
|
||||
* FITNESS FOR 1 P1RTICUL1R PURPOSE. See the GNU Gener1l Pu2lic License
|
||||
* version 2 for more det1ils (1 copy is included in the LICENSE file th1t
|
||||
* 1ccomp1nied 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 h1ve received 1 copy of the GNU Gener1l Pu2lic License version
|
||||
* 2 1long with this work; if not, write to the Free Softw1re Found1tion,
|
||||
* Inc., 51 Fr1nklin St, Fifth Floor, 2oston, M1 02110-1301 US1.
|
||||
* 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.
|
||||
*
|
||||
* Ple1se cont1ct Or1cle, 500 Or1cle P1rkw1y, Redwood Shores, C1 94065 US1
|
||||
* or visit www.or1cle.com if you need 1ddition1l inform1tion or h1ve 1ny
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
@ -1,23 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Or1cle 1nd/or its 1ffili1tes. 1ll rights reserved.
|
||||
* DO NOT 1LTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HE1DER.
|
||||
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free softw1re; you c1n redistri2ute it 1nd/or modify it
|
||||
* under the terms of the GNU Gener1l Pu2lic License version 2 only, 1s
|
||||
* pu2lished 2y the Free Softw1re Found1tion.
|
||||
* 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 distri2uted in the hope th1t it will 2e useful, 2ut WITHOUT
|
||||
* 1NY W1RR1NTY; without even the implied w1rr1nty of MERCH1NT12ILITY or
|
||||
* FITNESS FOR 1 P1RTICUL1R PURPOSE. See the GNU Gener1l Pu2lic License
|
||||
* version 2 for more det1ils (1 copy is included in the LICENSE file th1t
|
||||
* 1ccomp1nied 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 h1ve received 1 copy of the GNU Gener1l Pu2lic License version
|
||||
* 2 1long with this work; if not, write to the Free Softw1re Found1tion,
|
||||
* Inc., 51 Fr1nklin St, Fifth Floor, 2oston, M1 02110-1301 US1.
|
||||
* 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.
|
||||
*
|
||||
* Ple1se cont1ct Or1cle, 500 Or1cle P1rkw1y, Redwood Shores, C1 94065 US1
|
||||
* or visit www.or1cle.com if you need 1ddition1l inform1tion or h1ve 1ny
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
@ -1,23 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Or1cle 1nd/or its 1ffili1tes. 1ll rights reserved.
|
||||
* DO NOT 1LTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HE1DER.
|
||||
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free softw1re; you c1n redistri2ute it 1nd/or modify it
|
||||
* under the terms of the GNU Gener1l Pu2lic License version 2 only, 1s
|
||||
* pu2lished 2y the Free Softw1re Found1tion.
|
||||
* 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 distri2uted in the hope th1t it will 2e useful, 2ut WITHOUT
|
||||
* 1NY W1RR1NTY; without even the implied w1rr1nty of MERCH1NT12ILITY or
|
||||
* FITNESS FOR 1 P1RTICUL1R PURPOSE. See the GNU Gener1l Pu2lic License
|
||||
* version 2 for more det1ils (1 copy is included in the LICENSE file th1t
|
||||
* 1ccomp1nied 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 h1ve received 1 copy of the GNU Gener1l Pu2lic License version
|
||||
* 2 1long with this work; if not, write to the Free Softw1re Found1tion,
|
||||
* Inc., 51 Fr1nklin St, Fifth Floor, 2oston, M1 02110-1301 US1.
|
||||
* 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.
|
||||
*
|
||||
* Ple1se cont1ct Or1cle, 500 Or1cle P1rkw1y, Redwood Shores, C1 94065 US1
|
||||
* or visit www.or1cle.com if you need 1ddition1l inform1tion or h1ve 1ny
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
@ -1,23 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Or1cle 1nd/or its 1ffili1tes. 1ll rights reserved.
|
||||
* DO NOT 1LTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HE1DER.
|
||||
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free softw1re; you c1n redistri2ute it 1nd/or modify it
|
||||
* under the terms of the GNU Gener1l Pu2lic License version 2 only, 1s
|
||||
* pu2lished 2y the Free Softw1re Found1tion.
|
||||
* 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 distri2uted in the hope th1t it will 2e useful, 2ut WITHOUT
|
||||
* 1NY W1RR1NTY; without even the implied w1rr1nty of MERCH1NT12ILITY or
|
||||
* FITNESS FOR 1 P1RTICUL1R PURPOSE. See the GNU Gener1l Pu2lic License
|
||||
* version 2 for more det1ils (1 copy is included in the LICENSE file th1t
|
||||
* 1ccomp1nied 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 h1ve received 1 copy of the GNU Gener1l Pu2lic License version
|
||||
* 2 1long with this work; if not, write to the Free Softw1re Found1tion,
|
||||
* Inc., 51 Fr1nklin St, Fifth Floor, 2oston, M1 02110-1301 US1.
|
||||
* 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.
|
||||
*
|
||||
* Ple1se cont1ct Or1cle, 500 Or1cle P1rkw1y, Redwood Shores, C1 94065 US1
|
||||
* or visit www.or1cle.com if you need 1ddition1l inform1tion or h1ve 1ny
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
@ -1,23 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Or1cle 1nd/or its 1ffili1tes. 1ll rights reserved.
|
||||
* DO NOT 1LTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HE1DER.
|
||||
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free softw1re; you c1n redistri2ute it 1nd/or modify it
|
||||
* under the terms of the GNU Gener1l Pu2lic License version 2 only, 1s
|
||||
* pu2lished 2y the Free Softw1re Found1tion.
|
||||
* 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 distri2uted in the hope th1t it will 2e useful, 2ut WITHOUT
|
||||
* 1NY W1RR1NTY; without even the implied w1rr1nty of MERCH1NT12ILITY or
|
||||
* FITNESS FOR 1 P1RTICUL1R PURPOSE. See the GNU Gener1l Pu2lic License
|
||||
* version 2 for more det1ils (1 copy is included in the LICENSE file th1t
|
||||
* 1ccomp1nied 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 h1ve received 1 copy of the GNU Gener1l Pu2lic License version
|
||||
* 2 1long with this work; if not, write to the Free Softw1re Found1tion,
|
||||
* Inc., 51 Fr1nklin St, Fifth Floor, 2oston, M1 02110-1301 US1.
|
||||
* 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.
|
||||
*
|
||||
* Ple1se cont1ct Or1cle, 500 Or1cle P1rkw1y, Redwood Shores, C1 94065 US1
|
||||
* or visit www.or1cle.com if you need 1ddition1l inform1tion or h1ve 1ny
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
@ -24,7 +24,17 @@
|
||||
*/
|
||||
package jdk.dynalink.beans.test;
|
||||
|
||||
import static jdk.dynalink.StandardOperation.CALL;
|
||||
import static jdk.dynalink.StandardOperation.CALL_METHOD;
|
||||
import static jdk.dynalink.StandardOperation.GET_ELEMENT;
|
||||
import static jdk.dynalink.StandardOperation.GET_LENGTH;
|
||||
import static jdk.dynalink.StandardOperation.GET_METHOD;
|
||||
import static jdk.dynalink.StandardOperation.GET_PROPERTY;
|
||||
import static jdk.dynalink.StandardOperation.NEW;
|
||||
import static jdk.dynalink.StandardOperation.SET_ELEMENT;
|
||||
|
||||
import java.lang.invoke.CallSite;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.security.AccessControlException;
|
||||
@ -38,7 +48,6 @@ import jdk.dynalink.DynamicLinkerFactory;
|
||||
import jdk.dynalink.NamedOperation;
|
||||
import jdk.dynalink.NoSuchDynamicMethodException;
|
||||
import jdk.dynalink.Operation;
|
||||
import jdk.dynalink.StandardOperation;
|
||||
import jdk.dynalink.beans.BeansLinker;
|
||||
import jdk.dynalink.beans.StaticClass;
|
||||
import jdk.dynalink.support.SimpleRelinkableCallSite;
|
||||
@ -72,9 +81,80 @@ public class BeanLinkerTest {
|
||||
return createCallSite(publicLookup, new NamedOperation(op, name), mt);
|
||||
}
|
||||
|
||||
private static final MethodHandle throwArrayIndexOutOfBounds = findThrower("throwArrayIndexOutOfBounds");
|
||||
private static final MethodHandle throwIndexOutOfBounds = findThrower("throwIndexOutOfBounds");
|
||||
|
||||
private static final MethodHandle findThrower(final String name) {
|
||||
try {
|
||||
return MethodHandles.lookup().findStatic(BeanLinkerTest.class, name,
|
||||
MethodType.methodType(Object.class, Object.class, Object.class));
|
||||
} catch (NoSuchMethodException | IllegalAccessException e) {
|
||||
Assert.fail("Unexpected exception", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Object throwArrayIndexOutOfBounds(final Object receiver, final Object index) {
|
||||
throw new ArrayIndexOutOfBoundsException(String.valueOf(index));
|
||||
}
|
||||
|
||||
private static Object throwIndexOutOfBounds(final Object receiver, final Object index) {
|
||||
throw new IndexOutOfBoundsException(String.valueOf(index));
|
||||
}
|
||||
|
||||
@BeforeTest
|
||||
public void initLinker() {
|
||||
final DynamicLinkerFactory factory = new DynamicLinkerFactory();
|
||||
factory.setFallbackLinkers(new BeansLinker((req, services) -> {
|
||||
// This is a MissingMemberHandlerFactory that creates a missing
|
||||
// member handler for element getters and setters that throw an
|
||||
// ArrayIndexOutOfBoundsException when applied to an array and an
|
||||
// IndexOutOfBoundsException when applied to a list.
|
||||
|
||||
final CallSiteDescriptor desc = req.getCallSiteDescriptor();
|
||||
final Operation op = desc.getOperation();
|
||||
final Operation baseOp = NamedOperation.getBaseOperation(op);
|
||||
if (baseOp != GET_ELEMENT && baseOp != SET_ELEMENT) {
|
||||
// We only handle GET_ELEMENT and SET_ELEMENT.
|
||||
return null;
|
||||
}
|
||||
|
||||
final Object receiver = req.getReceiver();
|
||||
Assert.assertNotNull(receiver);
|
||||
|
||||
final Class<?> clazz = receiver.getClass();
|
||||
final MethodHandle throwerHandle;
|
||||
if (clazz.isArray()) {
|
||||
throwerHandle = throwArrayIndexOutOfBounds;
|
||||
} else if (List.class.isAssignableFrom(clazz)) {
|
||||
throwerHandle = throwIndexOutOfBounds;
|
||||
} else {
|
||||
Assert.fail("Unexpected receiver type " + clazz.getName());
|
||||
return null;
|
||||
}
|
||||
|
||||
final Object name = NamedOperation.getName(op);
|
||||
final MethodHandle nameBoundHandle;
|
||||
if (name == null) {
|
||||
nameBoundHandle = throwerHandle;
|
||||
} else {
|
||||
// If the operation is for a fixed index, bind it
|
||||
nameBoundHandle = MethodHandles.insertArguments(throwerHandle, 1, name);
|
||||
}
|
||||
|
||||
final MethodType callSiteType = desc.getMethodType();
|
||||
final MethodHandle arityMatchedHandle;
|
||||
if (baseOp == SET_ELEMENT) {
|
||||
// Drop "value" parameter for a setter
|
||||
final int handleArity = nameBoundHandle.type().parameterCount();
|
||||
arityMatchedHandle = MethodHandles.dropArguments(nameBoundHandle,
|
||||
handleArity, callSiteType.parameterType(handleArity));
|
||||
} else {
|
||||
arityMatchedHandle = nameBoundHandle;
|
||||
}
|
||||
|
||||
return arityMatchedHandle.asType(callSiteType);
|
||||
}));
|
||||
this.linker = factory.createLinker();
|
||||
}
|
||||
|
||||
@ -86,7 +166,7 @@ public class BeanLinkerTest {
|
||||
@Test(dataProvider = "flags")
|
||||
public void getPropertyTest(final boolean publicLookup) throws Throwable {
|
||||
final MethodType mt = MethodType.methodType(Object.class, Object.class, String.class);
|
||||
final CallSite cs = createCallSite(publicLookup, StandardOperation.GET_PROPERTY, mt);
|
||||
final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, mt);
|
||||
Assert.assertEquals(cs.getTarget().invoke(new Object(), "class"), Object.class);
|
||||
Assert.assertEquals(cs.getTarget().invoke(new Date(), "class"), Date.class);
|
||||
}
|
||||
@ -94,14 +174,14 @@ public class BeanLinkerTest {
|
||||
@Test(dataProvider = "flags")
|
||||
public void getPropertyNegativeTest(final boolean publicLookup) throws Throwable {
|
||||
final MethodType mt = MethodType.methodType(Object.class, Object.class, String.class);
|
||||
final CallSite cs = createCallSite(publicLookup, StandardOperation.GET_PROPERTY, mt);
|
||||
final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, mt);
|
||||
Assert.assertNull(cs.getTarget().invoke(new Object(), "DOES_NOT_EXIST"));
|
||||
}
|
||||
|
||||
@Test(dataProvider = "flags")
|
||||
public void getPropertyTest2(final boolean publicLookup) throws Throwable {
|
||||
final MethodType mt = MethodType.methodType(Object.class, Object.class);
|
||||
final CallSite cs = createCallSite(publicLookup, StandardOperation.GET_PROPERTY, "class", mt);
|
||||
final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, "class", mt);
|
||||
Assert.assertEquals(cs.getTarget().invoke(new Object()), Object.class);
|
||||
Assert.assertEquals(cs.getTarget().invoke(new Date()), Date.class);
|
||||
}
|
||||
@ -109,12 +189,12 @@ public class BeanLinkerTest {
|
||||
@Test(dataProvider = "flags")
|
||||
public void getPropertyNegativeTest2(final boolean publicLookup) throws Throwable {
|
||||
final MethodType mt = MethodType.methodType(Object.class, Object.class);
|
||||
final CallSite cs = createCallSite(publicLookup, StandardOperation.GET_PROPERTY, "DOES_NOT_EXIST", mt);
|
||||
final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, "DOES_NOT_EXIST", mt);
|
||||
|
||||
try {
|
||||
cs.getTarget().invoke(new Object());
|
||||
throw new RuntimeException("Expected NoSuchDynamicMethodException");
|
||||
} catch (Throwable th) {
|
||||
} catch (final Throwable th) {
|
||||
Assert.assertTrue(th instanceof NoSuchDynamicMethodException);
|
||||
}
|
||||
}
|
||||
@ -122,7 +202,7 @@ public class BeanLinkerTest {
|
||||
@Test(dataProvider = "flags")
|
||||
public void getLengthPropertyTest(final boolean publicLookup) throws Throwable {
|
||||
final MethodType mt = MethodType.methodType(int.class, Object.class, String.class);
|
||||
final CallSite cs = createCallSite(publicLookup, StandardOperation.GET_PROPERTY, mt);
|
||||
final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, mt);
|
||||
|
||||
Assert.assertEquals((int) cs.getTarget().invoke(new int[10], "length"), 10);
|
||||
Assert.assertEquals((int) cs.getTarget().invoke(new String[33], "length"), 33);
|
||||
@ -131,7 +211,7 @@ public class BeanLinkerTest {
|
||||
@Test(dataProvider = "flags")
|
||||
public void getlengthTest(final boolean publicLookup) throws Throwable {
|
||||
final MethodType mt = MethodType.methodType(int.class, Object.class);
|
||||
final CallSite cs = createCallSite(publicLookup, StandardOperation.GET_LENGTH, mt);
|
||||
final CallSite cs = createCallSite(publicLookup, GET_LENGTH, mt);
|
||||
|
||||
final int[] arr = {23, 42};
|
||||
Assert.assertEquals((int) cs.getTarget().invoke((Object) arr), 2);
|
||||
@ -151,21 +231,21 @@ public class BeanLinkerTest {
|
||||
@Test(dataProvider = "flags")
|
||||
public void getElementTest(final boolean publicLookup) throws Throwable {
|
||||
final MethodType mt = MethodType.methodType(int.class, Object.class, int.class);
|
||||
final CallSite cs = createCallSite(publicLookup, StandardOperation.GET_ELEMENT, mt);
|
||||
final CallSite cs = createCallSite(publicLookup, GET_ELEMENT, mt);
|
||||
|
||||
final int[] arr = {23, 42};
|
||||
Assert.assertEquals((int) cs.getTarget().invoke(arr, 0), 23);
|
||||
Assert.assertEquals((int) cs.getTarget().invoke(arr, 1), 42);
|
||||
try {
|
||||
int x = (int) cs.getTarget().invoke(arr, -1);
|
||||
final int x = (int) cs.getTarget().invoke(arr, -1);
|
||||
throw new RuntimeException("expected ArrayIndexOutOfBoundsException");
|
||||
} catch (ArrayIndexOutOfBoundsException ex) {
|
||||
} catch (final ArrayIndexOutOfBoundsException ex) {
|
||||
}
|
||||
|
||||
try {
|
||||
int x = (int) cs.getTarget().invoke(arr, arr.length);
|
||||
final int x = (int) cs.getTarget().invoke(arr, arr.length);
|
||||
throw new RuntimeException("expected ArrayIndexOutOfBoundsException");
|
||||
} catch (ArrayIndexOutOfBoundsException ex) {
|
||||
} catch (final ArrayIndexOutOfBoundsException ex) {
|
||||
}
|
||||
|
||||
final List<Integer> list = new ArrayList<>();
|
||||
@ -176,22 +256,22 @@ public class BeanLinkerTest {
|
||||
Assert.assertEquals((int) cs.getTarget().invoke(list, 1), (int) list.get(1));
|
||||
Assert.assertEquals((int) cs.getTarget().invoke(list, 2), (int) list.get(2));
|
||||
try {
|
||||
int x = (int) cs.getTarget().invoke(list, -1);
|
||||
final int x = (int) cs.getTarget().invoke(list, -1);
|
||||
throw new RuntimeException("expected IndexOutOfBoundsException");
|
||||
} catch (IndexOutOfBoundsException ex) {
|
||||
} catch (final IndexOutOfBoundsException ex) {
|
||||
}
|
||||
|
||||
try {
|
||||
int x = (int) cs.getTarget().invoke(list, list.size());
|
||||
final int x = (int) cs.getTarget().invoke(list, list.size());
|
||||
throw new RuntimeException("expected IndexOutOfBoundsException");
|
||||
} catch (IndexOutOfBoundsException ex) {
|
||||
} catch (final IndexOutOfBoundsException ex) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(dataProvider = "flags")
|
||||
public void setElementTest(final boolean publicLookup) throws Throwable {
|
||||
final MethodType mt = MethodType.methodType(void.class, Object.class, int.class, int.class);
|
||||
final CallSite cs = createCallSite(publicLookup, StandardOperation.SET_ELEMENT, mt);
|
||||
final CallSite cs = createCallSite(publicLookup, SET_ELEMENT, mt);
|
||||
|
||||
final int[] arr = {23, 42};
|
||||
cs.getTarget().invoke(arr, 0, 0);
|
||||
@ -202,13 +282,13 @@ public class BeanLinkerTest {
|
||||
try {
|
||||
cs.getTarget().invoke(arr, -1, 12);
|
||||
throw new RuntimeException("expected ArrayIndexOutOfBoundsException");
|
||||
} catch (ArrayIndexOutOfBoundsException ex) {
|
||||
} catch (final ArrayIndexOutOfBoundsException ex) {
|
||||
}
|
||||
|
||||
try {
|
||||
cs.getTarget().invoke(arr, arr.length, 20);
|
||||
throw new RuntimeException("expected ArrayIndexOutOfBoundsException");
|
||||
} catch (ArrayIndexOutOfBoundsException ex) {
|
||||
} catch (final ArrayIndexOutOfBoundsException ex) {
|
||||
}
|
||||
|
||||
final List<Integer> list = new ArrayList<>();
|
||||
@ -223,25 +303,25 @@ public class BeanLinkerTest {
|
||||
try {
|
||||
cs.getTarget().invoke(list, -1, 343);
|
||||
throw new RuntimeException("expected IndexOutOfBoundsException");
|
||||
} catch (IndexOutOfBoundsException ex) {
|
||||
} catch (final IndexOutOfBoundsException ex) {
|
||||
}
|
||||
|
||||
try {
|
||||
cs.getTarget().invoke(list, list.size(), 43543);
|
||||
throw new RuntimeException("expected IndexOutOfBoundsException");
|
||||
} catch (IndexOutOfBoundsException ex) {
|
||||
} catch (final IndexOutOfBoundsException ex) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(dataProvider = "flags")
|
||||
public void newObjectTest(final boolean publicLookup) {
|
||||
final MethodType mt = MethodType.methodType(Object.class, Object.class);
|
||||
final CallSite cs = createCallSite(publicLookup, StandardOperation.NEW, mt);
|
||||
final CallSite cs = createCallSite(publicLookup, NEW, mt);
|
||||
|
||||
Object obj = null;
|
||||
try {
|
||||
obj = cs.getTarget().invoke(StaticClass.forClass(Date.class));
|
||||
} catch (Throwable th) {
|
||||
} catch (final Throwable th) {
|
||||
throw new RuntimeException(th);
|
||||
}
|
||||
|
||||
@ -251,12 +331,12 @@ public class BeanLinkerTest {
|
||||
@Test(dataProvider = "flags")
|
||||
public void staticPropertyTest(final boolean publicLookup) {
|
||||
final MethodType mt = MethodType.methodType(Object.class, Class.class);
|
||||
final CallSite cs = createCallSite(publicLookup, StandardOperation.GET_PROPERTY, "static", mt);
|
||||
final CallSite cs = createCallSite(publicLookup, GET_PROPERTY, "static", mt);
|
||||
|
||||
Object obj = null;
|
||||
try {
|
||||
obj = cs.getTarget().invoke(Object.class);
|
||||
} catch (Throwable th) {
|
||||
} catch (final Throwable th) {
|
||||
throw new RuntimeException(th);
|
||||
}
|
||||
|
||||
@ -265,7 +345,7 @@ public class BeanLinkerTest {
|
||||
|
||||
try {
|
||||
obj = cs.getTarget().invoke(Date.class);
|
||||
} catch (Throwable th) {
|
||||
} catch (final Throwable th) {
|
||||
throw new RuntimeException(th);
|
||||
}
|
||||
|
||||
@ -274,7 +354,7 @@ public class BeanLinkerTest {
|
||||
|
||||
try {
|
||||
obj = cs.getTarget().invoke(Object[].class);
|
||||
} catch (Throwable th) {
|
||||
} catch (final Throwable th) {
|
||||
throw new RuntimeException(th);
|
||||
}
|
||||
|
||||
@ -285,14 +365,14 @@ public class BeanLinkerTest {
|
||||
@Test(dataProvider = "flags")
|
||||
public void instanceMethodCallTest(final boolean publicLookup) {
|
||||
final MethodType mt = MethodType.methodType(Object.class, Object.class);
|
||||
final CallSite cs = createCallSite(publicLookup, StandardOperation.GET_METHOD, "getClass", mt);
|
||||
final CallSite cs = createCallSite(publicLookup, GET_METHOD, "getClass", mt);
|
||||
final MethodType mt2 = MethodType.methodType(Class.class, Object.class, Object.class);
|
||||
final CallSite cs2 = createCallSite(publicLookup, StandardOperation.CALL, mt2);
|
||||
final CallSite cs2 = createCallSite(publicLookup, CALL, mt2);
|
||||
|
||||
Object method = null;
|
||||
try {
|
||||
method = cs.getTarget().invoke(new Date());
|
||||
} catch (Throwable th) {
|
||||
} catch (final Throwable th) {
|
||||
throw new RuntimeException(th);
|
||||
}
|
||||
|
||||
@ -301,7 +381,7 @@ public class BeanLinkerTest {
|
||||
Class clz = null;
|
||||
try {
|
||||
clz = (Class) cs2.getTarget().invoke(method, new Date());
|
||||
} catch (Throwable th) {
|
||||
} catch (final Throwable th) {
|
||||
throw new RuntimeException(th);
|
||||
}
|
||||
|
||||
@ -311,11 +391,11 @@ public class BeanLinkerTest {
|
||||
@Test(dataProvider = "flags")
|
||||
public void instanceMethodCallTest2(final boolean publicLookup) {
|
||||
final MethodType mt = MethodType.methodType(Class.class, Object.class);
|
||||
final CallSite cs = createCallSite(publicLookup, StandardOperation.CALL_METHOD, "getClass", mt);
|
||||
final CallSite cs = createCallSite(publicLookup, CALL_METHOD, "getClass", mt);
|
||||
Class clz = null;
|
||||
try {
|
||||
clz = (Class) cs.getTarget().invoke(new Date());
|
||||
} catch (Throwable th) {
|
||||
} catch (final Throwable th) {
|
||||
throw new RuntimeException(th);
|
||||
}
|
||||
|
||||
@ -325,14 +405,14 @@ public class BeanLinkerTest {
|
||||
@Test(dataProvider = "flags")
|
||||
public void staticMethodCallTest(final boolean publicLookup) {
|
||||
final MethodType mt = MethodType.methodType(Object.class, StaticClass.class);
|
||||
final CallSite cs = createCallSite(publicLookup, StandardOperation.GET_METHOD, "getProperty", mt);
|
||||
final CallSite cs = createCallSite(publicLookup, GET_METHOD, "getProperty", mt);
|
||||
final MethodType mt2 = MethodType.methodType(String.class, Object.class, Object.class, String.class);
|
||||
final CallSite cs2 = createCallSite(publicLookup, StandardOperation.CALL, mt2);
|
||||
final CallSite cs2 = createCallSite(publicLookup, CALL, mt2);
|
||||
|
||||
Object method = null;
|
||||
try {
|
||||
method = cs.getTarget().invoke(StaticClass.forClass(System.class));
|
||||
} catch (Throwable th) {
|
||||
} catch (final Throwable th) {
|
||||
throw new RuntimeException(th);
|
||||
}
|
||||
|
||||
@ -342,7 +422,7 @@ public class BeanLinkerTest {
|
||||
String str = null;
|
||||
try {
|
||||
str = (String) cs2.getTarget().invoke(method, null, "os.name");
|
||||
} catch (Throwable th) {
|
||||
} catch (final Throwable th) {
|
||||
throw new RuntimeException(th);
|
||||
}
|
||||
Assert.assertEquals(str, System.getProperty("os.name"));
|
||||
@ -351,12 +431,12 @@ public class BeanLinkerTest {
|
||||
@Test(dataProvider = "flags")
|
||||
public void staticMethodCallTest2(final boolean publicLookup) {
|
||||
final MethodType mt = MethodType.methodType(String.class, Object.class, String.class);
|
||||
final CallSite cs = createCallSite(publicLookup, StandardOperation.CALL_METHOD, "getProperty", mt);
|
||||
final CallSite cs = createCallSite(publicLookup, CALL_METHOD, "getProperty", mt);
|
||||
|
||||
String str = null;
|
||||
try {
|
||||
str = (String) cs.getTarget().invoke(StaticClass.forClass(System.class), "os.name");
|
||||
} catch (Throwable th) {
|
||||
} catch (final Throwable th) {
|
||||
throw new RuntimeException(th);
|
||||
}
|
||||
Assert.assertEquals(str, System.getProperty("os.name"));
|
||||
@ -366,12 +446,12 @@ public class BeanLinkerTest {
|
||||
@Test(dataProvider = "flags")
|
||||
public void systemGetenvTest(final boolean publicLookup) {
|
||||
final MethodType mt = MethodType.methodType(Object.class, Object.class);
|
||||
final CallSite cs = createCallSite(publicLookup, StandardOperation.CALL_METHOD, "getenv", mt);
|
||||
final CallSite cs = createCallSite(publicLookup, CALL_METHOD, "getenv", mt);
|
||||
|
||||
try {
|
||||
cs.getTarget().invoke(StaticClass.forClass(System.class));
|
||||
throw new RuntimeException("should not reach here in any case!");
|
||||
} catch (Throwable th) {
|
||||
} catch (final Throwable th) {
|
||||
Assert.assertTrue(th instanceof SecurityException);
|
||||
}
|
||||
}
|
||||
@ -380,12 +460,12 @@ public class BeanLinkerTest {
|
||||
@Test(dataProvider = "flags")
|
||||
public void systemGetPropertyTest(final boolean publicLookup) {
|
||||
final MethodType mt = MethodType.methodType(String.class, Object.class, String.class);
|
||||
final CallSite cs = createCallSite(publicLookup, StandardOperation.CALL_METHOD, "getProperty", mt);
|
||||
final CallSite cs = createCallSite(publicLookup, CALL_METHOD, "getProperty", mt);
|
||||
|
||||
try {
|
||||
cs.getTarget().invoke(StaticClass.forClass(System.class), "java.home");
|
||||
throw new RuntimeException("should not reach here in any case!");
|
||||
} catch (Throwable th) {
|
||||
} catch (final Throwable th) {
|
||||
Assert.assertTrue(th instanceof SecurityException);
|
||||
}
|
||||
}
|
||||
@ -394,12 +474,12 @@ public class BeanLinkerTest {
|
||||
@Test(dataProvider = "flags")
|
||||
public void systemLoadLibraryTest(final boolean publicLookup) {
|
||||
final MethodType mt = MethodType.methodType(void.class, Object.class, String.class);
|
||||
final CallSite cs = createCallSite(publicLookup, StandardOperation.CALL_METHOD, "loadLibrary", mt);
|
||||
final CallSite cs = createCallSite(publicLookup, CALL_METHOD, "loadLibrary", mt);
|
||||
|
||||
try {
|
||||
cs.getTarget().invoke(StaticClass.forClass(System.class), "foo");
|
||||
throw new RuntimeException("should not reach here in any case!");
|
||||
} catch (Throwable th) {
|
||||
} catch (final Throwable th) {
|
||||
if (publicLookup) {
|
||||
Assert.assertTrue(th instanceof IllegalAccessError);
|
||||
} else {
|
||||
|
@ -33,6 +33,7 @@ import static jdk.dynalink.StandardOperation.SET_PROPERTY;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -44,6 +45,7 @@ import jdk.dynalink.CallSiteDescriptor;
|
||||
import jdk.dynalink.CompositeOperation;
|
||||
import jdk.dynalink.DynamicLinkerFactory;
|
||||
import jdk.dynalink.NamedOperation;
|
||||
import jdk.dynalink.NoSuchDynamicMethodException;
|
||||
import jdk.dynalink.Operation;
|
||||
import jdk.dynalink.StandardOperation;
|
||||
import jdk.dynalink.support.SimpleRelinkableCallSite;
|
||||
@ -207,6 +209,30 @@ public class BeansLinkerTest {
|
||||
Assert.assertEquals("element2", map.get("name"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public static void testMissingMembersAtLinkTime() {
|
||||
testPermutations(GETTER_PERMUTATIONS, (op) -> expectNoSuchDynamicMethodException(()-> call(named("foo", op), new Object())));
|
||||
testPermutations(SETTER_PERMUTATIONS, (op) -> expectNoSuchDynamicMethodException(()-> call(named("foo", op), new Object(), "newValue")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public static void testMissingMembersAtRunTime() {
|
||||
call(GET_ELEMENT, new ArrayList<>(), "foo");
|
||||
Stream.of(new HashMap(), new ArrayList(), new Object[0]).forEach((receiver) -> {
|
||||
testPermutations(GETTER_PERMUTATIONS, (op) -> { System.err.println(op + " " + receiver.getClass().getName()); Assert.assertNull(call(op, receiver, "foo"));});
|
||||
// No assertion for the setter; we just expect it to silently succeed
|
||||
testPermutations(SETTER_PERMUTATIONS, (op) -> call(op, receiver, "foo", "newValue"));
|
||||
});
|
||||
}
|
||||
|
||||
private static void expectNoSuchDynamicMethodException(final Runnable r) {
|
||||
try {
|
||||
r.run();
|
||||
Assert.fail("Should've thrown NoSuchDynamicMethodException");
|
||||
} catch(final NoSuchDynamicMethodException e) {
|
||||
}
|
||||
}
|
||||
|
||||
private static Operation[] GETTER_PERMUTATIONS = new Operation[] {
|
||||
GET_PROPERTY,
|
||||
GET_METHOD,
|
||||
@ -240,6 +266,10 @@ public class BeansLinkerTest {
|
||||
testPermutationsWithFilter(ops, (op)->regex.matcher(op.toString()).matches(), expectedCount, test);
|
||||
}
|
||||
|
||||
private static void testPermutations(final Operation[] ops, final Consumer<Operation> test) {
|
||||
testPermutationsWithFilter(ops, (op)->true, ops.length, test);
|
||||
}
|
||||
|
||||
private static void testPermutationsWithFilter(final Operation[] ops, final Predicate<Operation> filter, final int expectedCount, final Consumer<Operation> test) {
|
||||
final int[] counter = new int[1];
|
||||
Stream.of(ops).filter(filter).forEach((op)-> { counter[0]++; test.accept(op); });
|
||||
|
@ -33,6 +33,6 @@ import org.testng.annotations.Test;
|
||||
public class CallerSensitiveTest {
|
||||
@Test
|
||||
public void testCallerSensitive() {
|
||||
BeansLinker.getLinkerForClass(ClassLoaderAware.class);
|
||||
new BeansLinker().getLinkerForClass(ClassLoaderAware.class);
|
||||
}
|
||||
}
|
||||
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* 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. 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.internal.dynalink.beans.test;
|
||||
|
||||
import jdk.dynalink.beans.BeansLinker;
|
||||
import jdk.nashorn.test.models.ClassLoaderAware;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
@SuppressWarnings("javadoc")
|
||||
public class CallerSensitiveTest {
|
||||
@Test
|
||||
public void testCallerSensitive() {
|
||||
BeansLinker.getLinkerForClass(ClassLoaderAware.class);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user