8023630: Implement Java.super() as the preferred way to call super methods
Reviewed-by: jlaskey, lagergren, sundar
This commit is contained in:
parent
8940235d91
commit
3a14dde3d2
@ -32,7 +32,6 @@ import java.lang.reflect.Array;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Deque;
|
import java.util.Deque;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import jdk.internal.dynalink.beans.StaticClass;
|
import jdk.internal.dynalink.beans.StaticClass;
|
||||||
import jdk.internal.dynalink.support.TypeUtilities;
|
import jdk.internal.dynalink.support.TypeUtilities;
|
||||||
import jdk.nashorn.internal.objects.annotations.Attribute;
|
import jdk.nashorn.internal.objects.annotations.Attribute;
|
||||||
@ -44,6 +43,7 @@ import jdk.nashorn.internal.runtime.JSType;
|
|||||||
import jdk.nashorn.internal.runtime.ListAdapter;
|
import jdk.nashorn.internal.runtime.ListAdapter;
|
||||||
import jdk.nashorn.internal.runtime.PropertyMap;
|
import jdk.nashorn.internal.runtime.PropertyMap;
|
||||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||||
|
import jdk.nashorn.internal.runtime.linker.Bootstrap;
|
||||||
import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory;
|
import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -539,4 +539,25 @@ public final class NativeJava {
|
|||||||
}
|
}
|
||||||
return JavaAdapterFactory.getAdapterClassFor(stypes, classOverrides);
|
return JavaAdapterFactory.getAdapterClassFor(stypes, classOverrides);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When given an object created using {@code Java.extend()} or equivalent mechanism (that is, any JavaScript-to-Java
|
||||||
|
* adapter), returns an object that can be used to invoke superclass methods on that object. E.g.:
|
||||||
|
* <pre>
|
||||||
|
* var cw = new FilterWriterAdapter(sw) {
|
||||||
|
* write: function(s, off, len) {
|
||||||
|
* s = capitalize(s, off, len)
|
||||||
|
* cw_super.write(s, 0, s.length())
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* var cw_super = Java.super(cw)
|
||||||
|
* </pre>
|
||||||
|
* @param self the {@code Java} object itself - not used.
|
||||||
|
* @param adapter the original Java adapter instance for which the super adapter is created.
|
||||||
|
* @return a super adapter for the original adapter
|
||||||
|
*/
|
||||||
|
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR, name="super")
|
||||||
|
public static Object _super(final Object self, final Object adapter) {
|
||||||
|
return Bootstrap.createSuperAdapter(adapter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,11 +30,10 @@ import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
|
|||||||
|
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import jdk.internal.dynalink.beans.BeansLinker;
|
|
||||||
import jdk.internal.dynalink.beans.StaticClass;
|
import jdk.internal.dynalink.beans.StaticClass;
|
||||||
import jdk.nashorn.api.scripting.ScriptObjectMirror;
|
|
||||||
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
|
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
|
||||||
import jdk.nashorn.internal.parser.Lexer;
|
import jdk.nashorn.internal.parser.Lexer;
|
||||||
|
import jdk.nashorn.internal.runtime.linker.Bootstrap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Representation for ECMAScript types - this maps directly to the ECMA script standard
|
* Representation for ECMAScript types - this maps directly to the ECMA script standard
|
||||||
@ -148,22 +147,10 @@ public enum JSType {
|
|||||||
return JSType.STRING;
|
return JSType.STRING;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj instanceof ScriptObject) {
|
if (Bootstrap.isCallable(obj)) {
|
||||||
return (obj instanceof ScriptFunction) ? JSType.FUNCTION : JSType.OBJECT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj instanceof StaticClass) {
|
|
||||||
return JSType.FUNCTION;
|
return JSType.FUNCTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BeansLinker.isDynamicMethod(obj)) {
|
|
||||||
return JSType.FUNCTION;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj instanceof ScriptObjectMirror) {
|
|
||||||
return ((ScriptObjectMirror)obj).isFunction()? JSType.FUNCTION : JSType.OBJECT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return JSType.OBJECT;
|
return JSType.OBJECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ import jdk.internal.dynalink.CallSiteDescriptor;
|
|||||||
import jdk.internal.dynalink.DynamicLinker;
|
import jdk.internal.dynalink.DynamicLinker;
|
||||||
import jdk.internal.dynalink.DynamicLinkerFactory;
|
import jdk.internal.dynalink.DynamicLinkerFactory;
|
||||||
import jdk.internal.dynalink.beans.BeansLinker;
|
import jdk.internal.dynalink.beans.BeansLinker;
|
||||||
|
import jdk.internal.dynalink.beans.StaticClass;
|
||||||
import jdk.internal.dynalink.linker.GuardedInvocation;
|
import jdk.internal.dynalink.linker.GuardedInvocation;
|
||||||
import jdk.internal.dynalink.linker.LinkerServices;
|
import jdk.internal.dynalink.linker.LinkerServices;
|
||||||
import jdk.nashorn.api.scripting.ScriptObjectMirror;
|
import jdk.nashorn.api.scripting.ScriptObjectMirror;
|
||||||
@ -61,7 +62,7 @@ public final class Bootstrap {
|
|||||||
static {
|
static {
|
||||||
final DynamicLinkerFactory factory = new DynamicLinkerFactory();
|
final DynamicLinkerFactory factory = new DynamicLinkerFactory();
|
||||||
factory.setPrioritizedLinkers(new NashornLinker(), new NashornPrimitiveLinker(), new NashornStaticClassLinker(),
|
factory.setPrioritizedLinkers(new NashornLinker(), new NashornPrimitiveLinker(), new NashornStaticClassLinker(),
|
||||||
new BoundDynamicMethodLinker(), new JSObjectLinker(), new ReflectionCheckLinker());
|
new BoundDynamicMethodLinker(), new JavaSuperAdapterLinker(), new JSObjectLinker(), new ReflectionCheckLinker());
|
||||||
factory.setFallbackLinkers(new BeansLinker(), new NashornBottomLinker());
|
factory.setFallbackLinkers(new BeansLinker(), new NashornBottomLinker());
|
||||||
factory.setSyncOnRelink(true);
|
factory.setSyncOnRelink(true);
|
||||||
final int relinkThreshold = Options.getIntProperty("nashorn.unstable.relink.threshold", -1);
|
final int relinkThreshold = Options.getIntProperty("nashorn.unstable.relink.threshold", -1);
|
||||||
@ -88,7 +89,8 @@ public final class Bootstrap {
|
|||||||
return obj instanceof ScriptFunction ||
|
return obj instanceof ScriptFunction ||
|
||||||
((obj instanceof ScriptObjectMirror) && ((ScriptObjectMirror)obj).isFunction()) ||
|
((obj instanceof ScriptObjectMirror) && ((ScriptObjectMirror)obj).isFunction()) ||
|
||||||
isDynamicMethod(obj) ||
|
isDynamicMethod(obj) ||
|
||||||
isFunctionalInterfaceObject(obj);
|
isFunctionalInterfaceObject(obj) ||
|
||||||
|
obj instanceof StaticClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -261,6 +263,16 @@ public final class Bootstrap {
|
|||||||
return new BoundDynamicMethod(dynamicMethod, boundThis);
|
return new BoundDynamicMethod(dynamicMethod, boundThis);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a super-adapter for an adapter, that is, an adapter to the adapter that allows invocation of superclass
|
||||||
|
* methods on it.
|
||||||
|
* @param adapter the original adapter
|
||||||
|
* @return a new adapter that can be used to invoke super methods on the original adapter.
|
||||||
|
*/
|
||||||
|
public static Object createSuperAdapter(final Object adapter) {
|
||||||
|
return new JavaSuperAdapter(adapter);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the given class is a reflection-specific class (anything in {@code java.lang.reflect} and
|
* If the given class is a reflection-specific class (anything in {@code java.lang.reflect} and
|
||||||
* {@code java.lang.invoke} package, as well a {@link Class} and any subclass of {@link ClassLoader}) and there is
|
* {@code java.lang.invoke} package, as well a {@link Class} and any subclass of {@link ClassLoader}) and there is
|
||||||
|
@ -67,11 +67,12 @@ final class BoundDynamicMethodLinker implements TypeBasedGuardingDynamicLinker {
|
|||||||
// BeansLinker.
|
// BeansLinker.
|
||||||
final CallSiteDescriptor descriptor = linkRequest.getCallSiteDescriptor();
|
final CallSiteDescriptor descriptor = linkRequest.getCallSiteDescriptor();
|
||||||
final MethodType type = descriptor.getMethodType();
|
final MethodType type = descriptor.getMethodType();
|
||||||
|
final Class<?> dynamicMethodClass = dynamicMethod.getClass();
|
||||||
final CallSiteDescriptor newDescriptor = descriptor.changeMethodType(
|
final CallSiteDescriptor newDescriptor = descriptor.changeMethodType(
|
||||||
type.changeParameterType(0, dynamicMethod.getClass()).changeParameterType(1, boundThis.getClass()));
|
type.changeParameterType(0, dynamicMethodClass).changeParameterType(1, boundThis.getClass()));
|
||||||
|
|
||||||
// Delegate to BeansLinker
|
// Delegate to BeansLinker
|
||||||
final GuardedInvocation inv = BeansLinker.getLinkerForClass(dynamicMethod.getClass()).getGuardedInvocation(
|
final GuardedInvocation inv = BeansLinker.getLinkerForClass(dynamicMethodClass).getGuardedInvocation(
|
||||||
linkRequest.replaceArguments(newDescriptor, args), linkerServices);
|
linkRequest.replaceArguments(newDescriptor, args), linkerServices);
|
||||||
if(inv == null) {
|
if(inv == null) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -174,7 +174,7 @@ final class JavaAdapterBytecodeGenerator {
|
|||||||
private static final String STATIC_GLOBAL_FIELD_NAME = "staticGlobal";
|
private static final String STATIC_GLOBAL_FIELD_NAME = "staticGlobal";
|
||||||
|
|
||||||
// Method name prefix for invoking super-methods
|
// Method name prefix for invoking super-methods
|
||||||
private static final String SUPER_PREFIX = "super$";
|
static final String SUPER_PREFIX = "super$";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collection of methods we never override: Object.clone(), Object.finalize().
|
* Collection of methods we never override: Object.clone(), Object.finalize().
|
||||||
|
@ -34,7 +34,6 @@ import java.security.Permissions;
|
|||||||
import java.security.PrivilegedAction;
|
import java.security.PrivilegedAction;
|
||||||
import java.security.ProtectionDomain;
|
import java.security.ProtectionDomain;
|
||||||
import java.security.SecureClassLoader;
|
import java.security.SecureClassLoader;
|
||||||
|
|
||||||
import jdk.internal.dynalink.beans.StaticClass;
|
import jdk.internal.dynalink.beans.StaticClass;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package jdk.nashorn.internal.runtime.linker;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a an adapter for invoking superclass methods on an adapter instance generated by
|
||||||
|
* {@link JavaAdapterBytecodeGenerator}. Note that objects of this class are just wrappers around the adapter instances,
|
||||||
|
* without any behavior. All the behavior is defined in the {@code JavaSuperAdapterLinker}.
|
||||||
|
*/
|
||||||
|
class JavaSuperAdapter {
|
||||||
|
private final Object adapter;
|
||||||
|
|
||||||
|
JavaSuperAdapter(final Object adapter) {
|
||||||
|
adapter.getClass(); // NPE check
|
||||||
|
this.adapter = adapter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getAdapter() {
|
||||||
|
return adapter;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,180 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.MethodType;
|
||||||
|
import jdk.internal.dynalink.CallSiteDescriptor;
|
||||||
|
import jdk.internal.dynalink.beans.BeansLinker;
|
||||||
|
import jdk.internal.dynalink.linker.GuardedInvocation;
|
||||||
|
import jdk.internal.dynalink.linker.LinkRequest;
|
||||||
|
import jdk.internal.dynalink.linker.LinkerServices;
|
||||||
|
import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
|
||||||
|
import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
|
||||||
|
import jdk.internal.dynalink.support.Lookup;
|
||||||
|
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A linker for instances of {@link JavaSuperAdapter}. Only links {@code getMethod} calls, by forwarding them to the
|
||||||
|
* bean linker for the adapter class and prepending {@code super$} to method names.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
final class JavaSuperAdapterLinker implements TypeBasedGuardingDynamicLinker {
|
||||||
|
private static final String GET_METHOD = "getMethod";
|
||||||
|
private static final String DYN_GET_METHOD = "dyn:" + GET_METHOD;
|
||||||
|
private static final String DYN_GET_METHOD_FIXED = DYN_GET_METHOD + ":" + SUPER_PREFIX;
|
||||||
|
|
||||||
|
private static final MethodHandle ADD_PREFIX_TO_METHOD_NAME;
|
||||||
|
private static final MethodHandle BIND_DYNAMIC_METHOD;
|
||||||
|
private static final MethodHandle GET_ADAPTER;
|
||||||
|
private static final MethodHandle IS_ADAPTER_OF_CLASS;
|
||||||
|
|
||||||
|
static {
|
||||||
|
final Lookup lookup = new Lookup(MethodHandles.lookup());
|
||||||
|
ADD_PREFIX_TO_METHOD_NAME = lookup.findOwnStatic("addPrefixToMethodName", Object.class, Object.class);
|
||||||
|
BIND_DYNAMIC_METHOD = lookup.findOwnStatic("bindDynamicMethod", Object.class, Object.class, Object.class);
|
||||||
|
GET_ADAPTER = lookup.findVirtual(JavaSuperAdapter.class, "getAdapter", MethodType.methodType(Object.class));
|
||||||
|
IS_ADAPTER_OF_CLASS = lookup.findOwnStatic("isAdapterOfClass", boolean.class, Class.class, Object.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canLinkType(final Class<?> type) {
|
||||||
|
return type == JavaSuperAdapter.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices)
|
||||||
|
throws Exception {
|
||||||
|
final Object objSuperAdapter = linkRequest.getReceiver();
|
||||||
|
if(!(objSuperAdapter instanceof JavaSuperAdapter)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final CallSiteDescriptor descriptor = linkRequest.getCallSiteDescriptor();
|
||||||
|
if(!CallSiteDescriptorFactory.tokenizeOperators(descriptor).contains(GET_METHOD)) {
|
||||||
|
// We only handle getMethod
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Object adapter = ((JavaSuperAdapter)objSuperAdapter).getAdapter();
|
||||||
|
|
||||||
|
// Replace argument (javaSuperAdapter, ...) => (adapter, ...) when delegating to BeansLinker
|
||||||
|
final Object[] args = linkRequest.getArguments();
|
||||||
|
args[0] = adapter;
|
||||||
|
|
||||||
|
// Use R(T0, ...) => R(adapter.class, ...) call site type when delegating to BeansLinker.
|
||||||
|
final MethodType type = descriptor.getMethodType();
|
||||||
|
final Class<?> adapterClass = adapter.getClass();
|
||||||
|
final boolean hasFixedName = descriptor.getNameTokenCount() > 2;
|
||||||
|
final String opName = hasFixedName ? (DYN_GET_METHOD_FIXED + descriptor.getNameToken(
|
||||||
|
CallSiteDescriptor.NAME_OPERAND)) : DYN_GET_METHOD;
|
||||||
|
|
||||||
|
final CallSiteDescriptor newDescriptor = NashornCallSiteDescriptor.get(descriptor.getLookup(), opName,
|
||||||
|
type.changeParameterType(0, adapterClass), 0);
|
||||||
|
|
||||||
|
// Delegate to BeansLinker
|
||||||
|
final GuardedInvocation guardedInv = BeansLinker.getLinkerForClass(adapterClass).getGuardedInvocation(
|
||||||
|
linkRequest.replaceArguments(newDescriptor, args), linkerServices);
|
||||||
|
|
||||||
|
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();
|
||||||
|
// For invocation typed R(T0, ...) create a dynamic method binder of type R(R, T0)
|
||||||
|
final MethodHandle typedBinder = BIND_DYNAMIC_METHOD.asType(MethodType.methodType(invType.returnType(),
|
||||||
|
invType.returnType(), invType.parameterType(0)));
|
||||||
|
// For invocation typed R(T0, T1, ...) create a dynamic method binder of type R(R, T0, T1, ...)
|
||||||
|
final MethodHandle droppingBinder = MethodHandles.dropArguments(typedBinder, 2,
|
||||||
|
invType.parameterList().subList(1, invType.parameterCount()));
|
||||||
|
// Finally, fold the invocation into the binder to produce a method handle that will bind every returned
|
||||||
|
// DynamicMethod object from dyn:getMethod calls to the actual receiver
|
||||||
|
// R(R(T0, T1, ...), T0, T1, ...)
|
||||||
|
final MethodHandle bindingInvocation = MethodHandles.foldArguments(droppingBinder, invocation);
|
||||||
|
|
||||||
|
final MethodHandle typedGetAdapter = asFilterType(GET_ADAPTER, 0, invType, type);
|
||||||
|
final MethodHandle adaptedInvocation;
|
||||||
|
if(hasFixedName) {
|
||||||
|
adaptedInvocation = MethodHandles.filterArguments(bindingInvocation, 0, typedGetAdapter);
|
||||||
|
} else {
|
||||||
|
// Add a filter that'll prepend "super$" to each name passed to the variable-name "dyn:getMethod".
|
||||||
|
final MethodHandle typedAddPrefix = asFilterType(ADD_PREFIX_TO_METHOD_NAME, 1, invType, type);
|
||||||
|
adaptedInvocation = MethodHandles.filterArguments(bindingInvocation, 0, typedGetAdapter, typedAddPrefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
return guardedInv.replaceMethods(adaptedInvocation, guard).asType(descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapts the type of a method handle used as a filter in a position from a source method type to a target method type.
|
||||||
|
* @param filter the filter method handle
|
||||||
|
* @param pos the position in the argument list that it's filtering
|
||||||
|
* @param targetType the target method type for filtering
|
||||||
|
* @param sourceType the source method type for filtering
|
||||||
|
* @return a type adapted filter
|
||||||
|
*/
|
||||||
|
private static MethodHandle asFilterType(final MethodHandle filter, int pos, MethodType targetType, MethodType sourceType) {
|
||||||
|
return filter.asType(MethodType.methodType(targetType.parameterType(pos), sourceType.parameterType(pos)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private static Object addPrefixToMethodName(final Object name) {
|
||||||
|
return SUPER_PREFIX.concat(String.valueOf(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to transform the return value of getMethod; transform a {@code DynamicMethod} into a
|
||||||
|
* {@code BoundDynamicMethod} while also accounting for the possibility of a non-existent method.
|
||||||
|
* @param dynamicMethod the dynamic method to bind
|
||||||
|
* @param boundThis the adapter underlying a super adapter, to which the dynamic method is bound.
|
||||||
|
* @return a dynamic method bound to the adapter instance.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private static Object bindDynamicMethod(final Object dynamicMethod, final Object boundThis) {
|
||||||
|
return dynamicMethod == null ? ScriptRuntime.UNDEFINED : Bootstrap.bindDynamicMethod(dynamicMethod, boundThis);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used as the guard of linkages, as the receiver is not guaranteed to be a JavaSuperAdapter.
|
||||||
|
* @param clazz the class the receiver's adapter is tested against.
|
||||||
|
* @param obj receiver
|
||||||
|
* @return true if the receiver is a super adapter, and its underlying adapter is of the specified class
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private static boolean isAdapterOfClass(Class<?> clazz, Object obj) {
|
||||||
|
return obj instanceof JavaSuperAdapter && clazz == (((JavaSuperAdapter)obj).getAdapter()).getClass();
|
||||||
|
}
|
||||||
|
}
|
94
nashorn/test/script/basic/JDK-8023630.js
Normal file
94
nashorn/test/script/basic/JDK-8023630.js
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JDK-8023630: Implement Java.super() as the preferred way to call super methods
|
||||||
|
*
|
||||||
|
* @test
|
||||||
|
* @run
|
||||||
|
*/
|
||||||
|
|
||||||
|
var CharArray = Java.type("char[]")
|
||||||
|
var jString = Java.type("java.lang.String")
|
||||||
|
var Character = Java.type("java.lang.Character")
|
||||||
|
|
||||||
|
function capitalize(s) {
|
||||||
|
if(s instanceof CharArray) {
|
||||||
|
return new jString(s).toUpperCase()
|
||||||
|
}
|
||||||
|
if(s instanceof jString) {
|
||||||
|
return s.toUpperCase()
|
||||||
|
}
|
||||||
|
return Character.toUpperCase(s) // must be int
|
||||||
|
}
|
||||||
|
|
||||||
|
var sw = new (Java.type("java.io.StringWriter"))
|
||||||
|
|
||||||
|
var FilterWriterAdapter = Java.extend(Java.type("java.io.FilterWriter"))
|
||||||
|
|
||||||
|
var cw = new FilterWriterAdapter(sw) {
|
||||||
|
write: function(s, off, len) {
|
||||||
|
s = capitalize(s)
|
||||||
|
// Must handle overloads by arity
|
||||||
|
if(off === undefined) {
|
||||||
|
cw_super.write(s, 0, s.length())
|
||||||
|
} else if (typeof s === "string") {
|
||||||
|
cw_super.write(s, off, len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var cw_super = Java.super(cw)
|
||||||
|
|
||||||
|
cw.write("abcd")
|
||||||
|
cw.write("e".charAt(0))
|
||||||
|
cw.write("fgh".toCharArray())
|
||||||
|
cw.write("**ijk**", 2, 3)
|
||||||
|
cw.write("***lmno**".toCharArray(), 3, 4)
|
||||||
|
cw.flush()
|
||||||
|
print(sw)
|
||||||
|
|
||||||
|
// Can invoke super for Object methods
|
||||||
|
print("cw_super has hashCode(): " + (typeof cw_super.hashCode === "function"))
|
||||||
|
print("cw_super has super equals(): " + (typeof cw_super.equals === "function"))
|
||||||
|
// Can't invoke super for final methods
|
||||||
|
print("cw_super has no getClass(): " + (typeof cw_super.getClass === "undefined"))
|
||||||
|
print("cw_super has no wait(): " + (typeof cw_super.wait === "undefined"))
|
||||||
|
|
||||||
|
var r = new (Java.type("java.lang.Runnable"))(function() {})
|
||||||
|
var r_super = Java.super(r)
|
||||||
|
|
||||||
|
// Can't invoke super for abstract methods
|
||||||
|
print("r_super has no run(): " + (typeof r_super.run === "undefined"))
|
||||||
|
// Interfaces can also invoke super Object methods
|
||||||
|
print("r_super has hashCode(): " + (typeof r_super.hashCode === "function"))
|
||||||
|
print("r_super has equals(): " + (typeof r_super.equals === "function"))
|
||||||
|
// But still can't invoke final methods
|
||||||
|
print("r_super has no getClass(): " + (typeof r_super.getClass === "undefined"))
|
||||||
|
print("r_super has no wait(): " + (typeof r_super.wait === "undefined"))
|
||||||
|
|
||||||
|
var name = "write"
|
||||||
|
print("cw_super can access write through [] getter: " + (typeof cw_super[name] === "function"))
|
||||||
|
var name = "hashCode"
|
||||||
|
print("cw_super can access hashCode through [] getter: " + (typeof cw_super[name] === "function"))
|
||||||
|
var name = "getClass"
|
||||||
|
print("cw_super can not access getClass through [] getter: " + (typeof cw_super[name] === "undefined"))
|
13
nashorn/test/script/basic/JDK-8023630.js.EXPECTED
Normal file
13
nashorn/test/script/basic/JDK-8023630.js.EXPECTED
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
ABCDEFGHIJKLMNO
|
||||||
|
cw_super has hashCode(): true
|
||||||
|
cw_super has super equals(): true
|
||||||
|
cw_super has no getClass(): true
|
||||||
|
cw_super has no wait(): true
|
||||||
|
r_super has no run(): true
|
||||||
|
r_super has hashCode(): true
|
||||||
|
r_super has equals(): true
|
||||||
|
r_super has no getClass(): true
|
||||||
|
r_super has no wait(): true
|
||||||
|
cw_super can access write through [] getter: true
|
||||||
|
cw_super can access hashCode through [] getter: true
|
||||||
|
cw_super can not access getClass through [] getter: true
|
@ -35,7 +35,10 @@ if (typeof (5).x !== 'number') {
|
|||||||
fail("typeof(5).x is not 'number'");
|
fail("typeof(5).x is not 'number'");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof (java.lang.System.out) != 'object') {
|
// It is function because PrintStream implements Closeable, which is
|
||||||
|
// marked with @FunctionalInterface. Yes, this means calling a stream
|
||||||
|
// like "stream()" closes it.
|
||||||
|
if (typeof (java.lang.System.out) != 'function') {
|
||||||
fail("typeof java.lang.System.out is not 'object'");
|
fail("typeof java.lang.System.out is not 'object'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user