8023630: Implement Java.super() as the preferred way to call super methods
Reviewed-by: jlaskey, lagergren, sundar
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java Fri Aug 23 12:44:01 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJava.java Fri Aug 23 13:10:45 2013 +0200
@@ -32,7 +32,6 @@
import java.util.Collection;
import java.util.Deque;
import java.util.List;
-
import jdk.internal.dynalink.beans.StaticClass;
import jdk.internal.dynalink.support.TypeUtilities;
import jdk.nashorn.internal.objects.annotations.Attribute;
@@ -44,6 +43,7 @@
import jdk.nashorn.internal.runtime.ListAdapter;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory;
/**
@@ -539,4 +539,25 @@
}
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);
+ }
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/JSType.java Fri Aug 23 12:44:01 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/JSType.java Fri Aug 23 13:10:45 2013 +0200
@@ -30,11 +30,10 @@
import java.lang.invoke.MethodHandles;
import java.util.Locale;
-import jdk.internal.dynalink.beans.BeansLinker;
import jdk.internal.dynalink.beans.StaticClass;
-import jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
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
@@ -148,22 +147,10 @@
return JSType.STRING;
}
- if (obj instanceof ScriptObject) {
- return (obj instanceof ScriptFunction) ? JSType.FUNCTION : JSType.OBJECT;
- }
-
- if (obj instanceof StaticClass) {
+ if (Bootstrap.isCallable(obj)) {
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;
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Fri Aug 23 12:44:01 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Fri Aug 23 13:10:45 2013 +0200
@@ -36,6 +36,7 @@
import jdk.internal.dynalink.DynamicLinker;
import jdk.internal.dynalink.DynamicLinkerFactory;
import jdk.internal.dynalink.beans.BeansLinker;
+import jdk.internal.dynalink.beans.StaticClass;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
@@ -61,7 +62,7 @@
static {
final DynamicLinkerFactory factory = new DynamicLinkerFactory();
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.setSyncOnRelink(true);
final int relinkThreshold = Options.getIntProperty("nashorn.unstable.relink.threshold", -1);
@@ -88,7 +89,8 @@
return obj instanceof ScriptFunction ||
((obj instanceof ScriptObjectMirror) && ((ScriptObjectMirror)obj).isFunction()) ||
isDynamicMethod(obj) ||
- isFunctionalInterfaceObject(obj);
+ isFunctionalInterfaceObject(obj) ||
+ obj instanceof StaticClass;
}
/**
@@ -262,6 +264,16 @@
}
/**
+ * 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
* {@code java.lang.invoke} package, as well a {@link Class} and any subclass of {@link ClassLoader}) and there is
* a security manager in the system, then it checks the {@code nashorn.JavaReflection} {@code RuntimePermission}.
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java Fri Aug 23 12:44:01 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java Fri Aug 23 13:10:45 2013 +0200
@@ -67,11 +67,12 @@
// BeansLinker.
final CallSiteDescriptor descriptor = linkRequest.getCallSiteDescriptor();
final MethodType type = descriptor.getMethodType();
+ final Class<?> dynamicMethodClass = dynamicMethod.getClass();
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
- final GuardedInvocation inv = BeansLinker.getLinkerForClass(dynamicMethod.getClass()).getGuardedInvocation(
+ final GuardedInvocation inv = BeansLinker.getLinkerForClass(dynamicMethodClass).getGuardedInvocation(
linkRequest.replaceArguments(newDescriptor, args), linkerServices);
if(inv == null) {
return null;
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java Fri Aug 23 12:44:01 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java Fri Aug 23 13:10:45 2013 +0200
@@ -174,7 +174,7 @@
private static final String STATIC_GLOBAL_FIELD_NAME = "staticGlobal";
// 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().
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java Fri Aug 23 12:44:01 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java Fri Aug 23 13:10:45 2013 +0200
@@ -34,7 +34,6 @@
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.security.SecureClassLoader;
-
import jdk.internal.dynalink.beans.StaticClass;
/**
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapter.java Fri Aug 23 13:10:45 2013 +0200
@@ -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;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java Fri Aug 23 13:10:45 2013 +0200
@@ -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();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8023630.js Fri Aug 23 13:10:45 2013 +0200
@@ -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"))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8023630.js.EXPECTED Fri Aug 23 13:10:45 2013 +0200
@@ -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
--- a/nashorn/test/script/basic/NASHORN-397.js Fri Aug 23 12:44:01 2013 +0200
+++ b/nashorn/test/script/basic/NASHORN-397.js Fri Aug 23 13:10:45 2013 +0200
@@ -35,7 +35,10 @@
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'");
}