8043232: Index selection of overloaded java new constructors

Reviewed-by: attila, hannesw, jlaskey
This commit is contained in:
Athijegannathan Sundararajan 2014-07-02 18:10:31 +05:30
parent 113a7f0c05
commit 27ba0956b6
13 changed files with 222 additions and 6 deletions

@ -290,7 +290,7 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
return new CallerSensitiveDynamicMethod(m);
}
final Member member = (Member)m;
return new SimpleDynamicMethod(unreflectSafely(m), member.getDeclaringClass(), member.getName());
return new SimpleDynamicMethod(unreflectSafely(m), member.getDeclaringClass(), member.getName(), m instanceof Constructor);
}
/**

@ -168,6 +168,26 @@ public class BeansLinker implements GuardingDynamicLinker {
return obj instanceof DynamicMethod;
}
/**
* Returns true if the object is a Dynalink Java constructor.
*
* @param obj the object we want to test for being a constructor
* @return true if it is a constructor, false otherwise.
*/
public static boolean isDynamicConstructor(final Object obj) {
return obj instanceof DynamicMethod && ((DynamicMethod)obj).isConstructor();
}
/**
* Return the dynamic method of constructor of the given class and the given signature.
* @param clazz the class
* @param signature full signature of the constructor
* @return DynamicMethod for the constructor
*/
public static Object getConstructorMethod(final Class<?> clazz, final String signature) {
return StaticClassLinker.getConstructorMethod(clazz, signature);
}
/**
* Returns a collection of names of all readable instance properties of a class.
* @param clazz the class

@ -155,4 +155,9 @@ class CallerSensitiveDynamicMethod extends SingleDynamicMethod {
return StaticClassIntrospector.editConstructorMethodHandle(Lookup.unreflectConstructor(lookup,
(Constructor<?>)target));
}
@Override
boolean isConstructor() {
return target instanceof Constructor;
}
}

@ -147,4 +147,13 @@ abstract class DynamicMethod {
public String toString() {
return "[" + getClass().getName() + " " + getName() + "]";
}
/**
* True if this method happens to be a constructor method.
*
* @return true if this represents a constructor.
*/
boolean isConstructor() {
return false;
}
}

@ -114,15 +114,30 @@ class DynamicMethodLinker implements TypeBasedGuardingDynamicLinker {
return null;
}
final String operator = desc.getNameToken(CallSiteDescriptor.OPERATOR);
if(operator == "call") {
final MethodHandle invocation = ((DynamicMethod)receiver).getInvocation(
final DynamicMethod dynMethod = (DynamicMethod)receiver;
final boolean constructor = dynMethod.isConstructor();
final MethodHandle invocation;
if (operator == "call" && !constructor) {
invocation = dynMethod.getInvocation(
CallSiteDescriptorFactory.dropParameterTypes(desc, 0, 1), linkerServices);
if(invocation == null) {
} else if (operator == "new" && constructor) {
final MethodHandle ctorInvocation = dynMethod.getInvocation(desc, linkerServices);
if(ctorInvocation == null) {
return null;
}
return new GuardedInvocation(MethodHandles.dropArguments(invocation, 0,
desc.getMethodType().parameterType(0)), Guards.getIdentityGuard(receiver));
// Insert null for StaticClass parameter
invocation = MethodHandles.insertArguments(ctorInvocation, 0, (Object)null);
} else {
return null;
}
if (invocation != null) {
return new GuardedInvocation(MethodHandles.dropArguments(invocation, 0,
desc.getMethodType().parameterType(0)), Guards.getIdentityGuard(receiver));
}
return null;
}
}

@ -236,6 +236,12 @@ class OverloadedDynamicMethod extends DynamicMethod {
return false;
}
@Override
public boolean isConstructor() {
assert !methods.isEmpty();
return methods.getFirst().isConstructor();
}
ClassLoader getClassLoader() {
return classLoader;
}
@ -303,6 +309,11 @@ class OverloadedDynamicMethod extends DynamicMethod {
* @param method a method to add
*/
public void addMethod(final SingleDynamicMethod method) {
assert constructorFlagConsistent(method);
methods.add(method);
}
private boolean constructorFlagConsistent(final SingleDynamicMethod method) {
return methods.isEmpty()? true : (methods.getFirst().isConstructor() == method.isConstructor());
}
}

@ -98,6 +98,7 @@ import java.lang.invoke.MethodType;
*/
class SimpleDynamicMethod extends SingleDynamicMethod {
private final MethodHandle target;
private final boolean constructor;
/**
* Creates a new simple dynamic method, with a name constructed from the class name, method name, and handle
@ -108,8 +109,22 @@ class SimpleDynamicMethod extends SingleDynamicMethod {
* @param name the simple name of the method
*/
SimpleDynamicMethod(final MethodHandle target, final Class<?> clazz, final String name) {
this(target, clazz, name, false);
}
/**
* Creates a new simple dynamic method, with a name constructed from the class name, method name, and handle
* signature.
*
* @param target the target method handle
* @param clazz the class declaring the method
* @param name the simple name of the method
* @param constructor does this represent a constructor?
*/
SimpleDynamicMethod(final MethodHandle target, final Class<?> clazz, final String name, final boolean constructor) {
super(getName(target, clazz, name));
this.target = target;
this.constructor = constructor;
}
private static String getName(final MethodHandle target, final Class<?> clazz, final String name) {
@ -130,4 +145,9 @@ class SimpleDynamicMethod extends SingleDynamicMethod {
MethodHandle getTarget(final Lookup lookup) {
return target;
}
@Override
boolean isConstructor() {
return constructor;
}
}

@ -160,6 +160,14 @@ class StaticClassLinker implements TypeBasedGuardingDynamicLinker {
}
return null;
}
DynamicMethod getConstructorMethod(final String signature) {
return constructor.getMethodForExactParamTypes(signature);
}
}
static Object getConstructorMethod(final Class<?> clazz, final String signature) {
return linkers.get(clazz).getConstructorMethod(signature);
}
static Collection<String> getReadableStaticPropertyNames(final Class<?> clazz) {

@ -26,11 +26,13 @@
package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
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.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.beans.BeansLinker;
import jdk.internal.dynalink.beans.StaticClass;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
@ -232,6 +234,35 @@ public final class NativeJavaPackage extends ScriptObject {
//ignored
}
// Check for explicit constructor signature use
// Example: new (java.awt["Color(int, int,int)"])(2, 3, 4);
final int openBrace = propertyName.indexOf('(');
final int closeBrace = propertyName.lastIndexOf(')');
if (openBrace != -1 || closeBrace != -1) {
final int lastChar = propertyName.length() - 1;
if (openBrace == -1 || closeBrace != lastChar) {
throw typeError("improper.constructor.signature", propertyName);
}
// get the class name and try to load it
final String className = name + "." + propertyName.substring(0, openBrace);
try {
javaClass = context.findClass(className);
} catch (final NoClassDefFoundError | ClassNotFoundException e) {
throw typeError(e, "no.such.java.class", className);
}
// try to find a matching constructor
final Object constructor = BeansLinker.getConstructorMethod(
javaClass, propertyName.substring(openBrace + 1, lastChar));
if (constructor != null) {
set(propertyName, constructor, false);
return constructor;
}
// we didn't find a matching constructor!
throw typeError("no.such.java.constructor", propertyName);
}
final Object propertyValue;
if (javaClass == null) {
propertyValue = new NativeJavaPackage(fullName, getProto());

@ -111,6 +111,9 @@ final class NashornBottomLinker implements GuardingDynamicLinker, GuardingTypeCo
MH.dropArguments(desc.getLookup().unreflect(m), 1, callType.parameterType(1)),
Guards.getInstanceOfGuard(m.getDeclaringClass())), linkerServices, desc);
}
if(BeansLinker.isDynamicConstructor(self)) {
throw typeError("constructor.requires.new", ScriptRuntime.safeToString(self));
}
if(BeansLinker.isDynamicMethod(self)) {
throw typeError("no.method.matches.args", ScriptRuntime.safeToString(self));
}

@ -92,6 +92,9 @@ type.error.cant.delete.property.of.undefined=Cannot delete property "{0}" of und
type.error.property.has.no.setter=Cannot set property "{0}" of {1} that has only a getter
type.error.cant.set.proto.to.non.object=Cannot set Object {0}'s __proto__ to be a non-object like {1}
type.error.no.such.function={1} has no such function "{0}"
type.error.no.such.java.class=No such Java class: {0}
type.error.no.such.java.constructor=No such Java constructor: {0}
type.error.improper.constructor.signature=Java constructor signature invalid: {0}
type.error.cant.get.property=Cannot get property "{0}" of {1}
type.error.cant.set.property=Cannot set property "{0}" of {1}
type.error.cant.delete.property=Cannot delete property "{0}" of {1}

@ -0,0 +1,80 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* JDK-8043232: Index selection of overloaded java new constructors
*
* @test
* @run
*/
// call explicit constructor
print(new (java.awt["Color(int,int,int)"])(255,0,255));
// print the constructor itself
print(java.awt["Color(int,int,int)"]);
// store constructor to call later
var Color = java.awt["Color(int,int,int)"];
// call stored constructor
print(new Color(33, 233, 2))
// check if default constructor works
var obj = new (java.lang["Object()"])();
if (obj.class != java.lang.Object.class) {
fail("obj is a java.lang.Object");
}
// expected failure cases.
function checkIt(func) {
try {
func();
throw new Error("should have thrown TypeError");
} catch(e) {
if (! (e instanceof TypeError)) {
fail("Expected TypeError, got " + e);
}
print(e);
}
}
// constructor of a non-existent class
checkIt(function() new (java.lang["NonExistent(String)"])());
// non-existent constructor of an existing class
checkIt(function() new (java.lang["Object(String)"])());
// garbage signature string
checkIt(function() new (java.lang["Object()xxxxx"])());
checkIt(function() new (java.lang["Object("])());
checkIt(function() new (java.lang["Object)"])());
var System = Java.type("java.lang.System");
// try to do 'new' on static method
checkIt(function() new (System.getProperty)("java.version"));
// try to do 'new' on an instance method
var println = System.out.println;
checkIt(function() new println("hello"));
// call constructor as normal method (without 'new')
checkIt(function() Color());

@ -0,0 +1,11 @@
java.awt.Color[r=255,g=0,b=255]
[jdk.internal.dynalink.beans.SimpleDynamicMethod Color java.awt.Color.java.awt.Color(int,int,int)]
java.awt.Color[r=33,g=233,b=2]
TypeError: No such Java class: java.lang.NonExistent
TypeError: No such Java constructor: Object(String)
TypeError: Java constructor signature invalid: Object()xxxxx
TypeError: Java constructor signature invalid: Object(
TypeError: Java constructor signature invalid: Object)
TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod java.lang.System.getProperty] cant be used as a constructor.
TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod java.io.PrintStream.println] cant be used as a constructor.
TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod Color java.awt.Color.java.awt.Color(int,int,int)] requires new.