mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-15 16:44:36 +02:00
Merge
This commit is contained in:
commit
06fb272637
21 changed files with 793 additions and 130 deletions
|
@ -504,7 +504,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
|
||||||
|
|
||||||
<testng outputdir="${build.test.results.dir}" classfilesetref="test.classes"
|
<testng outputdir="${build.test.results.dir}" classfilesetref="test.classes"
|
||||||
verbose="${testng.verbose}" haltonfailure="true" useDefaultListeners="false" listeners="${testng.listeners}" workingDir="${basedir}">
|
verbose="${testng.verbose}" haltonfailure="true" useDefaultListeners="false" listeners="${testng.listeners}" workingDir="${basedir}">
|
||||||
<jvmarg line="${ext.class.path}"/>
|
<jvmarg line="${boot.class.path}"/>
|
||||||
<jvmarg line="${run.test.jvmargs} -Xmx${run.test.xmx} -Dbuild.dir=${build.dir}"/>
|
<jvmarg line="${run.test.jvmargs} -Xmx${run.test.xmx} -Dbuild.dir=${build.dir}"/>
|
||||||
<propertyset>
|
<propertyset>
|
||||||
<propertyref prefix="testjfx-test-sys-prop."/>
|
<propertyref prefix="testjfx-test-sys-prop."/>
|
||||||
|
@ -524,7 +524,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
|
||||||
|
|
||||||
<testng outputdir="${build.test.results.dir}" classfilesetref="test.classes"
|
<testng outputdir="${build.test.results.dir}" classfilesetref="test.classes"
|
||||||
verbose="${testng.verbose}" haltonfailure="true" useDefaultListeners="false" listeners="${testng.listeners}" workingDir="${basedir}">
|
verbose="${testng.verbose}" haltonfailure="true" useDefaultListeners="false" listeners="${testng.listeners}" workingDir="${basedir}">
|
||||||
<jvmarg line="${ext.class.path}"/>
|
<jvmarg line="${boot.class.path}"/>
|
||||||
<jvmarg line="${run.test.jvmargs} -Xmx${run.test.xmx} ${run.test.jvmsecurityargs} -Dbuild.dir=${build.dir}"/>
|
<jvmarg line="${run.test.jvmargs} -Xmx${run.test.xmx} ${run.test.jvmsecurityargs} -Dbuild.dir=${build.dir}"/>
|
||||||
<propertyset>
|
<propertyset>
|
||||||
<propertyref prefix="testmarkdown-test-sys-prop."/>
|
<propertyref prefix="testmarkdown-test-sys-prop."/>
|
||||||
|
@ -543,7 +543,7 @@ grant codeBase "file:/${basedir}/test/script/markdown.js" {
|
||||||
|
|
||||||
<testng outputdir="${build.test.results.dir}" classfilesetref="test.classes"
|
<testng outputdir="${build.test.results.dir}" classfilesetref="test.classes"
|
||||||
verbose="${testng.verbose}" haltonfailure="true" useDefaultListeners="false" listeners="${testng.listeners}" workingDir="${basedir}">
|
verbose="${testng.verbose}" haltonfailure="true" useDefaultListeners="false" listeners="${testng.listeners}" workingDir="${basedir}">
|
||||||
<jvmarg line="${ext.class.path}"/>
|
<jvmarg line="${boot.class.path}"/>
|
||||||
<jvmarg line="${run.test.jvmargs} -Xmx${run.test.xmx} ${run.test.jvmsecurityargs} -Dbuild.dir=${build.dir}"/>
|
<jvmarg line="${run.test.jvmargs} -Xmx${run.test.xmx} ${run.test.jvmsecurityargs} -Dbuild.dir=${build.dir}"/>
|
||||||
<propertyset>
|
<propertyset>
|
||||||
<propertyref prefix="nashorn."/>
|
<propertyref prefix="nashorn."/>
|
||||||
|
|
122
nashorn/samples/getclassnpe.js
Normal file
122
nashorn/samples/getclassnpe.js
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
#// Usage: jjs getclassnpe.js -- <directory>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* - Neither the name of Oracle nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||||
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* java.lang.Object.getClass() is sometimes used to do null check. This
|
||||||
|
* obfuscating Object.getClass() check relies on non-related intrinsic
|
||||||
|
* performance, which is potentially not available everywhere.
|
||||||
|
* See also http://cr.openjdk.java.net/~shade/scratch/NullChecks.java
|
||||||
|
* This nashorn script checks for such uses in your .java files in the
|
||||||
|
* given directory (recursively).
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (arguments.length == 0) {
|
||||||
|
print("Usage: jjs getclassnpe.js -- <directory>");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Java types used
|
||||||
|
var File = Java.type("java.io.File");
|
||||||
|
var Files = Java.type("java.nio.file.Files");
|
||||||
|
var StringArray = Java.type("java.lang.String[]");
|
||||||
|
var ToolProvider = Java.type("javax.tools.ToolProvider");
|
||||||
|
var MethodInvocationTree = Java.type("com.sun.source.tree.MethodInvocationTree");
|
||||||
|
var TreeScanner = Java.type("com.sun.source.util.TreeScanner");
|
||||||
|
|
||||||
|
// parse a specific .java file to check if it uses
|
||||||
|
// Object.getClass() for null check.
|
||||||
|
function checkGetClassNPE() {
|
||||||
|
// get the system compiler tool
|
||||||
|
var compiler = ToolProvider.systemJavaCompiler;
|
||||||
|
// get standard file manager
|
||||||
|
var fileMgr = compiler.getStandardFileManager(null, null, null);
|
||||||
|
// Using Java.to convert script array (arguments) to a Java String[]
|
||||||
|
var compUnits = fileMgr.getJavaFileObjects(
|
||||||
|
Java.to(arguments, StringArray));
|
||||||
|
// create a new compilation task
|
||||||
|
var task = compiler.getTask(null, fileMgr, null, null, null, compUnits);
|
||||||
|
// subclass SimpleTreeVisitor - to check for obj.getClass(); statements
|
||||||
|
var GetClassNPEChecker = Java.extend(TreeScanner);
|
||||||
|
|
||||||
|
var visitor = new GetClassNPEChecker() {
|
||||||
|
lineMap: null,
|
||||||
|
sourceFile: null,
|
||||||
|
|
||||||
|
// save compilation unit details for reporting
|
||||||
|
visitCompilationUnit: function(node, p) {
|
||||||
|
this.sourceFile = node.sourceFile;
|
||||||
|
this.lineMap = node.lineMap;
|
||||||
|
return Java.super(visitor).visitCompilationUnit(node, p);
|
||||||
|
},
|
||||||
|
|
||||||
|
// look for "foo.getClass();" expression statements
|
||||||
|
visitExpressionStatement: function(node, p) {
|
||||||
|
var expr = node.expression;
|
||||||
|
if (expr instanceof MethodInvocationTree) {
|
||||||
|
var name = String(expr.methodSelect.identifier);
|
||||||
|
|
||||||
|
// will match any "getClass" call with zero arguments!
|
||||||
|
if (name == "getClass" && expr.arguments.size() == 0) {
|
||||||
|
print(this.sourceFile.getName()
|
||||||
|
+ " @ "
|
||||||
|
+ this.lineMap.getLineNumber(node.pos)
|
||||||
|
+ ":"
|
||||||
|
+ this.lineMap.getColumnNumber(node.pos));
|
||||||
|
|
||||||
|
print("\t", node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for each (var cu in task.parse()) {
|
||||||
|
cu.accept(visitor, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// for each ".java" file in the directory (recursively)
|
||||||
|
function main(dir) {
|
||||||
|
Files.walk(dir.toPath()).
|
||||||
|
forEach(function(p) {
|
||||||
|
var name = p.toFile().absolutePath;
|
||||||
|
if (name.endsWith(".java")) {
|
||||||
|
try {
|
||||||
|
checkGetClassNPE(p.toFile().getAbsolutePath());
|
||||||
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
main(new File(arguments[0]));
|
|
@ -40,7 +40,6 @@
|
||||||
var Arrays = Java.type("java.util.Arrays");
|
var Arrays = Java.type("java.util.Arrays");
|
||||||
var BufferedReader = Java.type("java.io.BufferedReader");
|
var BufferedReader = Java.type("java.io.BufferedReader");
|
||||||
var FileWriter = Java.type("java.io.FileWriter");
|
var FileWriter = Java.type("java.io.FileWriter");
|
||||||
var List = Java.type("java.util.List");
|
|
||||||
var LocalDateTime = Java.type("java.time.LocalDateTime");
|
var LocalDateTime = Java.type("java.time.LocalDateTime");
|
||||||
var InputStreamReader = Java.type("java.io.InputStreamReader");
|
var InputStreamReader = Java.type("java.io.InputStreamReader");
|
||||||
var PrintWriter = Java.type("java.io.PrintWriter");
|
var PrintWriter = Java.type("java.io.PrintWriter");
|
||||||
|
@ -122,7 +121,7 @@ EOF
|
||||||
// execute code command
|
// execute code command
|
||||||
function exec(args) {
|
function exec(args) {
|
||||||
// build child process and start it!
|
// build child process and start it!
|
||||||
new ProcessBuilder(Java.to(args.split(' '), List))
|
new ProcessBuilder(Arrays.asList(args.split(' ')))
|
||||||
.inheritIO()
|
.inheritIO()
|
||||||
.start()
|
.start()
|
||||||
.waitFor();
|
.waitFor();
|
||||||
|
|
|
@ -42,7 +42,6 @@
|
||||||
var Arrays = Java.type("java.util.Arrays");
|
var Arrays = Java.type("java.util.Arrays");
|
||||||
var BufferedReader = Java.type("java.io.BufferedReader");
|
var BufferedReader = Java.type("java.io.BufferedReader");
|
||||||
var InputStreamReader = Java.type("java.io.InputStreamReader");
|
var InputStreamReader = Java.type("java.io.InputStreamReader");
|
||||||
var List = Java.type("java.util.List");
|
|
||||||
var ProcessBuilder = Java.type("java.lang.ProcessBuilder");
|
var ProcessBuilder = Java.type("java.lang.ProcessBuilder");
|
||||||
var System = Java.type("java.lang.System");
|
var System = Java.type("java.lang.System");
|
||||||
|
|
||||||
|
@ -67,7 +66,7 @@
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// build child process and start it!
|
// build child process and start it!
|
||||||
new ProcessBuilder(Java.to(args, List))
|
new ProcessBuilder(Arrays.asList(args))
|
||||||
.inheritIO()
|
.inheritIO()
|
||||||
.start()
|
.start()
|
||||||
.waitFor();
|
.waitFor();
|
||||||
|
|
|
@ -97,6 +97,8 @@ import jdk.internal.dynalink.beans.BeansLinker;
|
||||||
import jdk.internal.dynalink.linker.GuardingDynamicLinker;
|
import jdk.internal.dynalink.linker.GuardingDynamicLinker;
|
||||||
import jdk.internal.dynalink.linker.GuardingTypeConverterFactory;
|
import jdk.internal.dynalink.linker.GuardingTypeConverterFactory;
|
||||||
import jdk.internal.dynalink.linker.LinkRequest;
|
import jdk.internal.dynalink.linker.LinkRequest;
|
||||||
|
import jdk.internal.dynalink.linker.LinkerServices;
|
||||||
|
import jdk.internal.dynalink.linker.MethodHandleTransformer;
|
||||||
import jdk.internal.dynalink.linker.MethodTypeConversionStrategy;
|
import jdk.internal.dynalink.linker.MethodTypeConversionStrategy;
|
||||||
import jdk.internal.dynalink.support.AutoDiscovery;
|
import jdk.internal.dynalink.support.AutoDiscovery;
|
||||||
import jdk.internal.dynalink.support.BottomGuardingDynamicLinker;
|
import jdk.internal.dynalink.support.BottomGuardingDynamicLinker;
|
||||||
|
@ -132,6 +134,7 @@ public class DynamicLinkerFactory {
|
||||||
private int unstableRelinkThreshold = DEFAULT_UNSTABLE_RELINK_THRESHOLD;
|
private int unstableRelinkThreshold = DEFAULT_UNSTABLE_RELINK_THRESHOLD;
|
||||||
private GuardedInvocationFilter prelinkFilter;
|
private GuardedInvocationFilter prelinkFilter;
|
||||||
private MethodTypeConversionStrategy autoConversionStrategy;
|
private MethodTypeConversionStrategy autoConversionStrategy;
|
||||||
|
private MethodHandleTransformer internalObjectsFilter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the class loader for automatic discovery of available linkers. If not set explicitly, then the thread
|
* Sets the class loader for automatic discovery of available linkers. If not set explicitly, then the thread
|
||||||
|
@ -283,6 +286,15 @@ public class DynamicLinkerFactory {
|
||||||
this.autoConversionStrategy = autoConversionStrategy;
|
this.autoConversionStrategy = autoConversionStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a method handle transformer that is supposed to act as the implementation of this linker factory's linkers'
|
||||||
|
* services {@link LinkerServices#filterInternalObjects(java.lang.invoke.MethodHandle)} method.
|
||||||
|
* @param internalObjectsFilter a method handle transformer filtering out internal objects, or null.
|
||||||
|
*/
|
||||||
|
public void setInternalObjectsFilter(final MethodHandleTransformer internalObjectsFilter) {
|
||||||
|
this.internalObjectsFilter = internalObjectsFilter;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new dynamic linker consisting of all the prioritized, autodiscovered, and fallback linkers as well as
|
* Creates a new dynamic linker consisting of all the prioritized, autodiscovered, and fallback linkers as well as
|
||||||
* the pre-link filter.
|
* the pre-link filter.
|
||||||
|
@ -350,8 +362,8 @@ public class DynamicLinkerFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
return new DynamicLinker(new LinkerServicesImpl(new TypeConverterFactory(typeConverters,
|
return new DynamicLinker(new LinkerServicesImpl(new TypeConverterFactory(typeConverters,
|
||||||
autoConversionStrategy), composite), prelinkFilter, runtimeContextArgCount, syncOnRelink,
|
autoConversionStrategy), composite, internalObjectsFilter), prelinkFilter, runtimeContextArgCount,
|
||||||
unstableRelinkThreshold);
|
syncOnRelink, unstableRelinkThreshold);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ClassLoader getThreadContextClassLoader() {
|
private static ClassLoader getThreadContextClassLoader() {
|
||||||
|
|
|
@ -570,7 +570,7 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||||
private static final MethodHandle CONSTANT_NULL_DROP_ANNOTATED_METHOD = MethodHandles.dropArguments(
|
private static final MethodHandle CONSTANT_NULL_DROP_ANNOTATED_METHOD = MethodHandles.dropArguments(
|
||||||
MethodHandles.constant(Object.class, null), 0, AnnotatedDynamicMethod.class);
|
MethodHandles.constant(Object.class, null), 0, AnnotatedDynamicMethod.class);
|
||||||
private static final MethodHandle GET_ANNOTATED_METHOD = privateLookup.findVirtual(AnnotatedDynamicMethod.class,
|
private static final MethodHandle GET_ANNOTATED_METHOD = privateLookup.findVirtual(AnnotatedDynamicMethod.class,
|
||||||
"getTarget", MethodType.methodType(MethodHandle.class, MethodHandles.Lookup.class));
|
"getTarget", MethodType.methodType(MethodHandle.class, MethodHandles.Lookup.class, LinkerServices.class));
|
||||||
private static final MethodHandle GETTER_INVOKER = MethodHandles.invoker(MethodType.methodType(Object.class, Object.class));
|
private static final MethodHandle GETTER_INVOKER = MethodHandles.invoker(MethodType.methodType(Object.class, Object.class));
|
||||||
|
|
||||||
private GuardedInvocationComponent getPropertyGetter(final CallSiteDescriptor callSiteDescriptor,
|
private GuardedInvocationComponent getPropertyGetter(final CallSiteDescriptor callSiteDescriptor,
|
||||||
|
@ -593,7 +593,7 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||||
final MethodHandle typedGetter = linkerServices.asType(getPropertyGetterHandle, type.changeReturnType(
|
final MethodHandle typedGetter = linkerServices.asType(getPropertyGetterHandle, type.changeReturnType(
|
||||||
AnnotatedDynamicMethod.class));
|
AnnotatedDynamicMethod.class));
|
||||||
final MethodHandle callSiteBoundMethodGetter = MethodHandles.insertArguments(
|
final MethodHandle callSiteBoundMethodGetter = MethodHandles.insertArguments(
|
||||||
GET_ANNOTATED_METHOD, 1, callSiteDescriptor.getLookup());
|
GET_ANNOTATED_METHOD, 1, callSiteDescriptor.getLookup(), linkerServices);
|
||||||
final MethodHandle callSiteBoundInvoker = MethodHandles.filterArguments(GETTER_INVOKER, 0,
|
final MethodHandle callSiteBoundInvoker = MethodHandles.filterArguments(GETTER_INVOKER, 0,
|
||||||
callSiteBoundMethodGetter);
|
callSiteBoundMethodGetter);
|
||||||
// Object(AnnotatedDynamicMethod, Object)->Object(AnnotatedDynamicMethod, T0)
|
// Object(AnnotatedDynamicMethod, Object)->Object(AnnotatedDynamicMethod, T0)
|
||||||
|
@ -873,8 +873,8 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
MethodHandle getTarget(final MethodHandles.Lookup lookup) {
|
MethodHandle getTarget(final MethodHandles.Lookup lookup, final LinkerServices linkerServices) {
|
||||||
final MethodHandle inv = method.getTarget(lookup);
|
final MethodHandle inv = linkerServices.filterInternalObjects(method.getTarget(lookup));
|
||||||
assert inv != null;
|
assert inv != null;
|
||||||
return inv;
|
return inv;
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,6 +165,10 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
|
||||||
private static MethodHandle LIST_GUARD = Guards.getInstanceOfGuard(List.class);
|
private static MethodHandle LIST_GUARD = Guards.getInstanceOfGuard(List.class);
|
||||||
private static MethodHandle MAP_GUARD = Guards.getInstanceOfGuard(Map.class);
|
private static MethodHandle MAP_GUARD = Guards.getInstanceOfGuard(Map.class);
|
||||||
|
|
||||||
|
private enum CollectionType {
|
||||||
|
ARRAY, LIST, MAP
|
||||||
|
};
|
||||||
|
|
||||||
private GuardedInvocationComponent getElementGetter(final CallSiteDescriptor callSiteDescriptor,
|
private GuardedInvocationComponent getElementGetter(final CallSiteDescriptor callSiteDescriptor,
|
||||||
final LinkerServices linkerServices, final List<String> operations) throws Exception {
|
final LinkerServices linkerServices, final List<String> operations) throws Exception {
|
||||||
final MethodType callSiteType = callSiteDescriptor.getMethodType();
|
final MethodType callSiteType = callSiteDescriptor.getMethodType();
|
||||||
|
@ -178,27 +182,27 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
|
||||||
// Note that for arrays and lists, using LinkerServices.asType() will ensure that any language specific linkers
|
// Note that for arrays and lists, using LinkerServices.asType() will ensure that any language specific linkers
|
||||||
// in use will get a chance to perform any (if there's any) implicit conversion to integer for the indices.
|
// in use will get a chance to perform any (if there's any) implicit conversion to integer for the indices.
|
||||||
final GuardedInvocationComponent gic;
|
final GuardedInvocationComponent gic;
|
||||||
final boolean isMap;
|
final CollectionType collectionType;
|
||||||
if(declaredType.isArray()) {
|
if(declaredType.isArray()) {
|
||||||
gic = new GuardedInvocationComponent(MethodHandles.arrayElementGetter(declaredType));
|
gic = createInternalFilteredGuardedInvocationComponent(MethodHandles.arrayElementGetter(declaredType), linkerServices);
|
||||||
isMap = false;
|
collectionType = CollectionType.ARRAY;
|
||||||
} else if(List.class.isAssignableFrom(declaredType)) {
|
} else if(List.class.isAssignableFrom(declaredType)) {
|
||||||
gic = new GuardedInvocationComponent(GET_LIST_ELEMENT);
|
gic = createInternalFilteredGuardedInvocationComponent(GET_LIST_ELEMENT, linkerServices);
|
||||||
isMap = false;
|
collectionType = CollectionType.LIST;
|
||||||
} else if(Map.class.isAssignableFrom(declaredType)) {
|
} else if(Map.class.isAssignableFrom(declaredType)) {
|
||||||
gic = new GuardedInvocationComponent(GET_MAP_ELEMENT);
|
gic = createInternalFilteredGuardedInvocationComponent(GET_MAP_ELEMENT, linkerServices);
|
||||||
isMap = true;
|
collectionType = CollectionType.MAP;
|
||||||
} else if(clazz.isArray()) {
|
} else if(clazz.isArray()) {
|
||||||
gic = getClassGuardedInvocationComponent(MethodHandles.arrayElementGetter(clazz), callSiteType);
|
gic = getClassGuardedInvocationComponent(linkerServices.filterInternalObjects(MethodHandles.arrayElementGetter(clazz)), callSiteType);
|
||||||
isMap = false;
|
collectionType = CollectionType.ARRAY;
|
||||||
} else if(List.class.isAssignableFrom(clazz)) {
|
} else if(List.class.isAssignableFrom(clazz)) {
|
||||||
gic = new GuardedInvocationComponent(GET_LIST_ELEMENT, Guards.asType(LIST_GUARD, callSiteType), List.class,
|
gic = createInternalFilteredGuardedInvocationComponent(GET_LIST_ELEMENT, Guards.asType(LIST_GUARD, callSiteType), List.class, ValidationType.INSTANCE_OF,
|
||||||
ValidationType.INSTANCE_OF);
|
linkerServices);
|
||||||
isMap = false;
|
collectionType = CollectionType.LIST;
|
||||||
} else if(Map.class.isAssignableFrom(clazz)) {
|
} else if(Map.class.isAssignableFrom(clazz)) {
|
||||||
gic = new GuardedInvocationComponent(GET_MAP_ELEMENT, Guards.asType(MAP_GUARD, callSiteType), Map.class,
|
gic = createInternalFilteredGuardedInvocationComponent(GET_MAP_ELEMENT, Guards.asType(MAP_GUARD, callSiteType), Map.class, ValidationType.INSTANCE_OF,
|
||||||
ValidationType.INSTANCE_OF);
|
linkerServices);
|
||||||
isMap = true;
|
collectionType = CollectionType.MAP;
|
||||||
} else {
|
} else {
|
||||||
// Can't retrieve elements for objects that are neither arrays, nor list, nor maps.
|
// Can't retrieve elements for objects that are neither arrays, nor list, nor maps.
|
||||||
return nextComponent;
|
return nextComponent;
|
||||||
|
@ -208,7 +212,7 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
|
||||||
final String fixedKey = getFixedKey(callSiteDescriptor);
|
final String fixedKey = getFixedKey(callSiteDescriptor);
|
||||||
// Convert the key to a number if we're working with a list or array
|
// Convert the key to a number if we're working with a list or array
|
||||||
final Object typedFixedKey;
|
final Object typedFixedKey;
|
||||||
if(!isMap && fixedKey != null) {
|
if(collectionType != CollectionType.MAP && fixedKey != null) {
|
||||||
typedFixedKey = convertKeyToInteger(fixedKey, linkerServices);
|
typedFixedKey = convertKeyToInteger(fixedKey, linkerServices);
|
||||||
if(typedFixedKey == null) {
|
if(typedFixedKey == null) {
|
||||||
// key is not numeric, it can never succeed
|
// key is not numeric, it can never succeed
|
||||||
|
@ -227,15 +231,21 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
|
||||||
}
|
}
|
||||||
|
|
||||||
final MethodHandle checkGuard;
|
final MethodHandle checkGuard;
|
||||||
if(invocation == GET_LIST_ELEMENT) {
|
switch(collectionType) {
|
||||||
|
case LIST:
|
||||||
checkGuard = convertArgToInt(RANGE_CHECK_LIST, linkerServices, callSiteDescriptor);
|
checkGuard = convertArgToInt(RANGE_CHECK_LIST, linkerServices, callSiteDescriptor);
|
||||||
} else if(invocation == GET_MAP_ELEMENT) {
|
break;
|
||||||
|
case MAP:
|
||||||
// TODO: A more complex solution could be devised for maps, one where we do a get() first, and fold it
|
// 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()
|
// 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)
|
// that returns constant null (on true), or falls back to next component (on false)
|
||||||
checkGuard = CONTAINS_MAP;
|
checkGuard = linkerServices.filterInternalObjects(CONTAINS_MAP);
|
||||||
} else {
|
break;
|
||||||
|
case ARRAY:
|
||||||
checkGuard = convertArgToInt(RANGE_CHECK_ARRAY, linkerServices, callSiteDescriptor);
|
checkGuard = convertArgToInt(RANGE_CHECK_ARRAY, linkerServices, callSiteDescriptor);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new AssertionError();
|
||||||
}
|
}
|
||||||
final MethodPair matchedInvocations = matchReturnTypes(binder.bind(invocation),
|
final MethodPair matchedInvocations = matchReturnTypes(binder.bind(invocation),
|
||||||
nextComponent.getGuardedInvocation().getInvocation());
|
nextComponent.getGuardedInvocation().getInvocation());
|
||||||
|
@ -243,6 +253,18 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
|
||||||
gic.getValidatorClass(), gic.getValidationType());
|
gic.getValidatorClass(), gic.getValidationType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static GuardedInvocationComponent createInternalFilteredGuardedInvocationComponent(
|
||||||
|
final MethodHandle invocation, final LinkerServices linkerServices) {
|
||||||
|
return new GuardedInvocationComponent(linkerServices.filterInternalObjects(invocation));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GuardedInvocationComponent createInternalFilteredGuardedInvocationComponent(
|
||||||
|
final MethodHandle invocation, final MethodHandle guard, final Class<?> validatorClass,
|
||||||
|
final ValidationType validationType, final LinkerServices linkerServices) {
|
||||||
|
return new GuardedInvocationComponent(linkerServices.filterInternalObjects(invocation), guard,
|
||||||
|
validatorClass, validationType);
|
||||||
|
}
|
||||||
|
|
||||||
private static String getFixedKey(final CallSiteDescriptor callSiteDescriptor) {
|
private static String getFixedKey(final CallSiteDescriptor callSiteDescriptor) {
|
||||||
return callSiteDescriptor.getNameTokenCount() == 2 ? null : callSiteDescriptor.getNameToken(
|
return callSiteDescriptor.getNameTokenCount() == 2 ? null : callSiteDescriptor.getNameToken(
|
||||||
CallSiteDescriptor.NAME_OPERAND);
|
CallSiteDescriptor.NAME_OPERAND);
|
||||||
|
@ -381,37 +403,38 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
|
||||||
// dealing with an array, or a list or map, but hey...
|
// dealing with an array, or a list or map, but hey...
|
||||||
// Note that for arrays and lists, using LinkerServices.asType() will ensure that any language specific linkers
|
// Note that for arrays and lists, using LinkerServices.asType() will ensure that any language specific linkers
|
||||||
// in use will get a chance to perform any (if there's any) implicit conversion to integer for the indices.
|
// in use will get a chance to perform any (if there's any) implicit conversion to integer for the indices.
|
||||||
final boolean isMap;
|
final CollectionType collectionType;
|
||||||
if(declaredType.isArray()) {
|
if(declaredType.isArray()) {
|
||||||
gic = new GuardedInvocationComponent(MethodHandles.arrayElementSetter(declaredType));
|
gic = createInternalFilteredGuardedInvocationComponent(MethodHandles.arrayElementSetter(declaredType), linkerServices);
|
||||||
isMap = false;
|
collectionType = CollectionType.ARRAY;
|
||||||
} else if(List.class.isAssignableFrom(declaredType)) {
|
} else if(List.class.isAssignableFrom(declaredType)) {
|
||||||
gic = new GuardedInvocationComponent(SET_LIST_ELEMENT);
|
gic = createInternalFilteredGuardedInvocationComponent(SET_LIST_ELEMENT, linkerServices);
|
||||||
isMap = false;
|
collectionType = CollectionType.LIST;
|
||||||
} else if(Map.class.isAssignableFrom(declaredType)) {
|
} else if(Map.class.isAssignableFrom(declaredType)) {
|
||||||
gic = new GuardedInvocationComponent(PUT_MAP_ELEMENT);
|
gic = createInternalFilteredGuardedInvocationComponent(PUT_MAP_ELEMENT, linkerServices);
|
||||||
isMap = true;
|
collectionType = CollectionType.MAP;
|
||||||
} else if(clazz.isArray()) {
|
} else if(clazz.isArray()) {
|
||||||
gic = getClassGuardedInvocationComponent(MethodHandles.arrayElementSetter(clazz), callSiteType);
|
gic = getClassGuardedInvocationComponent(linkerServices.filterInternalObjects(
|
||||||
isMap = false;
|
MethodHandles.arrayElementSetter(clazz)), callSiteType);
|
||||||
|
collectionType = CollectionType.ARRAY;
|
||||||
} else if(List.class.isAssignableFrom(clazz)) {
|
} else if(List.class.isAssignableFrom(clazz)) {
|
||||||
gic = new GuardedInvocationComponent(SET_LIST_ELEMENT, Guards.asType(LIST_GUARD, callSiteType), List.class,
|
gic = createInternalFilteredGuardedInvocationComponent(SET_LIST_ELEMENT, Guards.asType(LIST_GUARD, callSiteType), List.class, ValidationType.INSTANCE_OF,
|
||||||
ValidationType.INSTANCE_OF);
|
linkerServices);
|
||||||
isMap = false;
|
collectionType = CollectionType.LIST;
|
||||||
} else if(Map.class.isAssignableFrom(clazz)) {
|
} else if(Map.class.isAssignableFrom(clazz)) {
|
||||||
gic = new GuardedInvocationComponent(PUT_MAP_ELEMENT, Guards.asType(MAP_GUARD, callSiteType), Map.class,
|
gic = createInternalFilteredGuardedInvocationComponent(PUT_MAP_ELEMENT, Guards.asType(MAP_GUARD, callSiteType),
|
||||||
ValidationType.INSTANCE_OF);
|
Map.class, ValidationType.INSTANCE_OF, linkerServices);
|
||||||
isMap = true;
|
collectionType = CollectionType.MAP;
|
||||||
} else {
|
} else {
|
||||||
// Can't set elements for objects that are neither arrays, nor list, nor maps.
|
// Can't set elements for objects that are neither arrays, nor list, nor maps.
|
||||||
gic = null;
|
gic = null;
|
||||||
isMap = false;
|
collectionType = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// In contrast to, say, getElementGetter, we only compute the nextComponent if the target object is not a map,
|
// 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
|
// as maps will always succeed in setting the element and will never need to fall back to the next component
|
||||||
// operation.
|
// operation.
|
||||||
final GuardedInvocationComponent nextComponent = isMap ? null : getGuardedInvocationComponent(
|
final GuardedInvocationComponent nextComponent = collectionType == CollectionType.MAP ? null : getGuardedInvocationComponent(
|
||||||
callSiteDescriptor, linkerServices, operations);
|
callSiteDescriptor, linkerServices, operations);
|
||||||
if(gic == null) {
|
if(gic == null) {
|
||||||
return nextComponent;
|
return nextComponent;
|
||||||
|
@ -421,7 +444,7 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
|
||||||
final String fixedKey = getFixedKey(callSiteDescriptor);
|
final String fixedKey = getFixedKey(callSiteDescriptor);
|
||||||
// Convert the key to a number if we're working with a list or array
|
// Convert the key to a number if we're working with a list or array
|
||||||
final Object typedFixedKey;
|
final Object typedFixedKey;
|
||||||
if(!isMap && fixedKey != null) {
|
if(collectionType != CollectionType.MAP && fixedKey != null) {
|
||||||
typedFixedKey = convertKeyToInteger(fixedKey, linkerServices);
|
typedFixedKey = convertKeyToInteger(fixedKey, linkerServices);
|
||||||
if(typedFixedKey == null) {
|
if(typedFixedKey == null) {
|
||||||
// key is not numeric, it can never succeed
|
// key is not numeric, it can never succeed
|
||||||
|
@ -439,7 +462,8 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
|
||||||
return gic.replaceInvocation(binder.bind(invocation));
|
return gic.replaceInvocation(binder.bind(invocation));
|
||||||
}
|
}
|
||||||
|
|
||||||
final MethodHandle checkGuard = convertArgToInt(invocation == SET_LIST_ELEMENT ? RANGE_CHECK_LIST :
|
assert collectionType == CollectionType.LIST || collectionType == CollectionType.ARRAY;
|
||||||
|
final MethodHandle checkGuard = convertArgToInt(collectionType == CollectionType.LIST ? RANGE_CHECK_LIST :
|
||||||
RANGE_CHECK_ARRAY, linkerServices, callSiteDescriptor);
|
RANGE_CHECK_ARRAY, linkerServices, callSiteDescriptor);
|
||||||
final MethodPair matchedInvocations = matchReturnTypes(binder.bind(invocation),
|
final MethodPair matchedInvocations = matchReturnTypes(binder.bind(invocation),
|
||||||
nextComponent.getGuardedInvocation().getInvocation());
|
nextComponent.getGuardedInvocation().getInvocation());
|
||||||
|
|
|
@ -139,7 +139,8 @@ class OverloadedMethod {
|
||||||
final MethodHandle bound = SELECT_METHOD.bindTo(this);
|
final MethodHandle bound = SELECT_METHOD.bindTo(this);
|
||||||
final MethodHandle collecting = SingleDynamicMethod.collectArguments(bound, argNum).asType(
|
final MethodHandle collecting = SingleDynamicMethod.collectArguments(bound, argNum).asType(
|
||||||
callSiteType.changeReturnType(MethodHandle.class));
|
callSiteType.changeReturnType(MethodHandle.class));
|
||||||
invoker = MethodHandles.foldArguments(MethodHandles.exactInvoker(this.callSiteType), collecting);
|
invoker = linkerServices.asTypeLosslessReturn(MethodHandles.foldArguments(
|
||||||
|
MethodHandles.exactInvoker(this.callSiteType), collecting), callSiteType);
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodHandle getInvoker() {
|
MethodHandle getInvoker() {
|
||||||
|
|
|
@ -165,10 +165,11 @@ abstract class SingleDynamicMethod extends DynamicMethod {
|
||||||
* @return the adapted method handle.
|
* @return the adapted method handle.
|
||||||
*/
|
*/
|
||||||
static MethodHandle getInvocation(final MethodHandle target, final MethodType callSiteType, final LinkerServices linkerServices) {
|
static MethodHandle getInvocation(final MethodHandle target, final MethodType callSiteType, final LinkerServices linkerServices) {
|
||||||
final MethodType methodType = target.type();
|
final MethodHandle filteredTarget = linkerServices.filterInternalObjects(target);
|
||||||
|
final MethodType methodType = filteredTarget.type();
|
||||||
final int paramsLen = methodType.parameterCount();
|
final int paramsLen = methodType.parameterCount();
|
||||||
final boolean varArgs = target.isVarargsCollector();
|
final boolean varArgs = target.isVarargsCollector();
|
||||||
final MethodHandle fixTarget = varArgs ? target.asFixedArity() : target;
|
final MethodHandle fixTarget = varArgs ? filteredTarget.asFixedArity() : filteredTarget;
|
||||||
final int fixParamsLen = varArgs ? paramsLen - 1 : paramsLen;
|
final int fixParamsLen = varArgs ? paramsLen - 1 : paramsLen;
|
||||||
final int argsLen = callSiteType.parameterCount();
|
final int argsLen = callSiteType.parameterCount();
|
||||||
if(argsLen < fixParamsLen) {
|
if(argsLen < fixParamsLen) {
|
||||||
|
@ -204,7 +205,7 @@ abstract class SingleDynamicMethod extends DynamicMethod {
|
||||||
if(varArgType.isAssignableFrom(callSiteLastArgType)) {
|
if(varArgType.isAssignableFrom(callSiteLastArgType)) {
|
||||||
// Call site signature guarantees we'll always be passed a single compatible array; just link directly
|
// Call site signature guarantees we'll always be passed a single compatible array; just link directly
|
||||||
// to the method, introducing necessary conversions. Also, preserve it being a variable arity method.
|
// to the method, introducing necessary conversions. Also, preserve it being a variable arity method.
|
||||||
return createConvertingInvocation(target, linkerServices, callSiteType).asVarargsCollector(
|
return createConvertingInvocation(filteredTarget, linkerServices, callSiteType).asVarargsCollector(
|
||||||
callSiteLastArgType);
|
callSiteLastArgType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -180,6 +180,15 @@ public interface LinkerServices {
|
||||||
*/
|
*/
|
||||||
public Comparison compareConversion(Class<?> sourceType, Class<?> targetType1, Class<?> targetType2);
|
public Comparison compareConversion(Class<?> sourceType, Class<?> targetType1, Class<?> targetType2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifies the method handle so that any parameters that can receive potentially internal language runtime objects
|
||||||
|
* will have a filter added on them to prevent them from escaping, potentially by wrapping them.
|
||||||
|
* It can also potentially add an unwrapping filter to the return value.
|
||||||
|
* @param target the target method handle
|
||||||
|
* @return a method handle with parameters and/or return type potentially filtered for wrapping and unwrapping.
|
||||||
|
*/
|
||||||
|
public MethodHandle filterInternalObjects(final MethodHandle target);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If we could just use Java 8 constructs, then {@code asTypeSafeReturn} would be a method with default
|
* If we could just use Java 8 constructs, then {@code asTypeSafeReturn} would be a method with default
|
||||||
* implementation. Since we can't do that, we extract common default implementations into this static class.
|
* implementation. Since we can't do that, we extract common default implementations into this static class.
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is available under and governed by the GNU General Public
|
||||||
|
* License version 2 only, as published by the Free Software Foundation.
|
||||||
|
* However, the following notice accompanied the original version of this
|
||||||
|
* file, and Oracle licenses the original version of this file under the BSD
|
||||||
|
* license:
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
Copyright 2009-2015 Attila Szegedi
|
||||||
|
|
||||||
|
Licensed under both the Apache License, Version 2.0 (the "Apache License")
|
||||||
|
and the BSD License (the "BSD License"), with licensee being free to
|
||||||
|
choose either of the two at their discretion.
|
||||||
|
|
||||||
|
You may not use this file except in compliance with either the Apache
|
||||||
|
License or the BSD License.
|
||||||
|
|
||||||
|
If you choose to use this file in compliance with the Apache License, the
|
||||||
|
following notice applies to you:
|
||||||
|
|
||||||
|
You may obtain a copy of the Apache License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied. See the License for the specific language governing
|
||||||
|
permissions and limitations under the License.
|
||||||
|
|
||||||
|
If you choose to use this file in compliance with the BSD License, the
|
||||||
|
following notice applies to you:
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the copyright holder nor the names of
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||||
|
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
|
||||||
|
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||||
|
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package jdk.internal.dynalink.linker;
|
||||||
|
|
||||||
|
import java.lang.invoke.MethodHandle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A generic interface describing operations that transform method handles.
|
||||||
|
*/
|
||||||
|
public interface MethodHandleTransformer {
|
||||||
|
/**
|
||||||
|
* Transforms a method handle.
|
||||||
|
* @param target the method handle being transformed.
|
||||||
|
* @return transformed method handle.
|
||||||
|
*/
|
||||||
|
public MethodHandle transform(final MethodHandle target);
|
||||||
|
}
|
|
@ -0,0 +1,177 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is available under and governed by the GNU General Public
|
||||||
|
* License version 2 only, as published by the Free Software Foundation.
|
||||||
|
* However, the following notice accompanied the original version of this
|
||||||
|
* file, and Oracle licenses the original version of this file under the BSD
|
||||||
|
* license:
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
Copyright 2009-2015 Attila Szegedi
|
||||||
|
|
||||||
|
Licensed under both the Apache License, Version 2.0 (the "Apache License")
|
||||||
|
and the BSD License (the "BSD License"), with licensee being free to
|
||||||
|
choose either of the two at their discretion.
|
||||||
|
|
||||||
|
You may not use this file except in compliance with either the Apache
|
||||||
|
License or the BSD License.
|
||||||
|
|
||||||
|
If you choose to use this file in compliance with the Apache License, the
|
||||||
|
following notice applies to you:
|
||||||
|
|
||||||
|
You may obtain a copy of the Apache License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied. See the License for the specific language governing
|
||||||
|
permissions and limitations under the License.
|
||||||
|
|
||||||
|
If you choose to use this file in compliance with the BSD License, the
|
||||||
|
following notice applies to you:
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the copyright holder nor the names of
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||||
|
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||||
|
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
|
||||||
|
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||||
|
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package jdk.internal.dynalink.support;
|
||||||
|
|
||||||
|
import java.lang.invoke.MethodHandle;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.MethodType;
|
||||||
|
import jdk.internal.dynalink.DynamicLinkerFactory;
|
||||||
|
import jdk.internal.dynalink.linker.MethodHandleTransformer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default implementation for a {@link DynamicLinkerFactory#setInternalObjectsFilter(MethodHandleTransformer)}.
|
||||||
|
* Given a method handle of {@code Object(Object)} type for filtering parameter and another one of the same type for
|
||||||
|
* filtering return values, applies them to passed method handles where their parameter types and/or return value types
|
||||||
|
* are declared to be {@link Object}.
|
||||||
|
*/
|
||||||
|
public class DefaultInternalObjectFilter implements MethodHandleTransformer {
|
||||||
|
private static final MethodHandle FILTER_VARARGS = new Lookup(MethodHandles.lookup()).findStatic(
|
||||||
|
DefaultInternalObjectFilter.class, "filterVarArgs", MethodType.methodType(Object[].class, MethodHandle.class, Object[].class));
|
||||||
|
|
||||||
|
private final MethodHandle parameterFilter;
|
||||||
|
private final MethodHandle returnFilter;
|
||||||
|
private final MethodHandle varArgFilter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new filter.
|
||||||
|
* @param parameterFilter the filter for method parameters. Must be of type {@code Object(Object)}, or null.
|
||||||
|
* @param returnFilter the filter for return values. Must be of type {@code Object(Object)}, or null.
|
||||||
|
* @throws IllegalArgumentException if one or both filters are not of the expected type.
|
||||||
|
*/
|
||||||
|
public DefaultInternalObjectFilter(final MethodHandle parameterFilter, final MethodHandle returnFilter) {
|
||||||
|
this.parameterFilter = checkHandle(parameterFilter, "parameterFilter");
|
||||||
|
this.returnFilter = checkHandle(returnFilter, "returnFilter");
|
||||||
|
this.varArgFilter = parameterFilter == null ? null : FILTER_VARARGS.bindTo(parameterFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MethodHandle transform(final MethodHandle target) {
|
||||||
|
assert target != null;
|
||||||
|
MethodHandle[] filters = null;
|
||||||
|
final MethodType type = target.type();
|
||||||
|
final boolean isVarArg = target.isVarargsCollector();
|
||||||
|
final int paramCount = type.parameterCount();
|
||||||
|
final MethodHandle paramsFiltered;
|
||||||
|
// Filter parameters
|
||||||
|
if (parameterFilter != null) {
|
||||||
|
int firstFilter = -1;
|
||||||
|
// Ignore receiver, start from argument 1
|
||||||
|
for(int i = 1; i < paramCount; ++i) {
|
||||||
|
final Class<?> paramType = type.parameterType(i);
|
||||||
|
final boolean filterVarArg = isVarArg && i == paramCount - 1 && paramType == Object[].class;
|
||||||
|
if (filterVarArg || paramType == Object.class) {
|
||||||
|
if (filters == null) {
|
||||||
|
firstFilter = i;
|
||||||
|
filters = new MethodHandle[paramCount - firstFilter];
|
||||||
|
}
|
||||||
|
filters[i - firstFilter] = filterVarArg ? varArgFilter : parameterFilter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
paramsFiltered = filters != null ? MethodHandles.filterArguments(target, firstFilter, filters) : target;
|
||||||
|
} else {
|
||||||
|
paramsFiltered = target;
|
||||||
|
}
|
||||||
|
// Filter return value if needed
|
||||||
|
final MethodHandle returnFiltered = returnFilter != null && type.returnType() == Object.class ? MethodHandles.filterReturnValue(paramsFiltered, returnFilter) : paramsFiltered;
|
||||||
|
// Preserve varargs collector state
|
||||||
|
return isVarArg && !returnFiltered.isVarargsCollector() ? returnFiltered.asVarargsCollector(type.parameterType(paramCount - 1)) : returnFiltered;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MethodHandle checkHandle(final MethodHandle handle, final String handleKind) {
|
||||||
|
if (handle != null) {
|
||||||
|
final MethodType objectObjectType = MethodType.methodType(Object.class, Object.class);
|
||||||
|
if (!handle.type().equals(objectObjectType)) {
|
||||||
|
throw new IllegalArgumentException("Method type for " + handleKind + " must be " + objectObjectType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private static Object[] filterVarArgs(final MethodHandle parameterFilter, final Object[] args) throws Throwable {
|
||||||
|
Object[] newArgs = null;
|
||||||
|
for(int i = 0; i < args.length; ++i) {
|
||||||
|
final Object arg = args[i];
|
||||||
|
final Object newArg = parameterFilter.invokeExact(arg);
|
||||||
|
if (arg != newArg) {
|
||||||
|
if (newArgs == null) {
|
||||||
|
newArgs = args.clone();
|
||||||
|
}
|
||||||
|
newArgs[i] = newArg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newArgs == null ? args : newArgs;
|
||||||
|
}
|
||||||
|
}
|
|
@ -90,6 +90,7 @@ import jdk.internal.dynalink.linker.GuardedInvocation;
|
||||||
import jdk.internal.dynalink.linker.GuardingDynamicLinker;
|
import jdk.internal.dynalink.linker.GuardingDynamicLinker;
|
||||||
import jdk.internal.dynalink.linker.LinkRequest;
|
import jdk.internal.dynalink.linker.LinkRequest;
|
||||||
import jdk.internal.dynalink.linker.LinkerServices;
|
import jdk.internal.dynalink.linker.LinkerServices;
|
||||||
|
import jdk.internal.dynalink.linker.MethodHandleTransformer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default implementation of the {@link LinkerServices} interface.
|
* Default implementation of the {@link LinkerServices} interface.
|
||||||
|
@ -103,17 +104,21 @@ public class LinkerServicesImpl implements LinkerServices {
|
||||||
|
|
||||||
private final TypeConverterFactory typeConverterFactory;
|
private final TypeConverterFactory typeConverterFactory;
|
||||||
private final GuardingDynamicLinker topLevelLinker;
|
private final GuardingDynamicLinker topLevelLinker;
|
||||||
|
private final MethodHandleTransformer internalObjectsFilter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new linker services object.
|
* Creates a new linker services object.
|
||||||
*
|
*
|
||||||
* @param typeConverterFactory the type converter factory exposed by the services.
|
* @param typeConverterFactory the type converter factory exposed by the services.
|
||||||
* @param topLevelLinker the top level linker used by the services.
|
* @param topLevelLinker the top level linker used by the services.
|
||||||
|
* @param internalObjectsFilter a method handle transformer that is supposed to act as the implementation of this
|
||||||
|
* services' {@link #filterInternalObjects(java.lang.invoke.MethodHandle)} method.
|
||||||
*/
|
*/
|
||||||
public LinkerServicesImpl(final TypeConverterFactory typeConverterFactory,
|
public LinkerServicesImpl(final TypeConverterFactory typeConverterFactory,
|
||||||
final GuardingDynamicLinker topLevelLinker) {
|
final GuardingDynamicLinker topLevelLinker, final MethodHandleTransformer internalObjectsFilter) {
|
||||||
this.typeConverterFactory = typeConverterFactory;
|
this.typeConverterFactory = typeConverterFactory;
|
||||||
this.topLevelLinker = topLevelLinker;
|
this.topLevelLinker = topLevelLinker;
|
||||||
|
this.internalObjectsFilter = internalObjectsFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -152,6 +157,11 @@ public class LinkerServicesImpl implements LinkerServices {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MethodHandle filterInternalObjects(final MethodHandle target) {
|
||||||
|
return internalObjectsFilter != null ? internalObjectsFilter.transform(target) : target;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the currently processed link request, or null if the method is invoked outside of the linking process.
|
* Returns the currently processed link request, or null if the method is invoked outside of the linking process.
|
||||||
* @return the currently processed link request, or null.
|
* @return the currently processed link request, or null.
|
||||||
|
|
|
@ -448,7 +448,7 @@ public final class ScriptObjectMirror extends AbstractJSObject implements Bindin
|
||||||
checkKey(key);
|
checkKey(key);
|
||||||
return inGlobal(new Callable<Object>() {
|
return inGlobal(new Callable<Object>() {
|
||||||
@Override public Object call() {
|
@Override public Object call() {
|
||||||
return wrap(sobj.remove(key, strict), global);
|
return translateUndefined(wrap(sobj.remove(key, strict), global));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@ import java.util.IdentityHashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains utility methods for calculating the memory usage of objects. It
|
* Contains utility methods for calculating the memory usage of objects. It
|
||||||
|
@ -150,7 +151,7 @@ public final class ObjectSizeCalculator {
|
||||||
* @param memoryLayoutSpecification a description of the JVM memory layout.
|
* @param memoryLayoutSpecification a description of the JVM memory layout.
|
||||||
*/
|
*/
|
||||||
public ObjectSizeCalculator(final MemoryLayoutSpecification memoryLayoutSpecification) {
|
public ObjectSizeCalculator(final MemoryLayoutSpecification memoryLayoutSpecification) {
|
||||||
memoryLayoutSpecification.getClass();
|
Objects.requireNonNull(memoryLayoutSpecification);
|
||||||
arrayHeaderSize = memoryLayoutSpecification.getArrayHeaderSize();
|
arrayHeaderSize = memoryLayoutSpecification.getArrayHeaderSize();
|
||||||
objectHeaderSize = memoryLayoutSpecification.getObjectHeaderSize();
|
objectHeaderSize = memoryLayoutSpecification.getObjectHeaderSize();
|
||||||
objectPadding = memoryLayoutSpecification.getObjectPadding();
|
objectPadding = memoryLayoutSpecification.getObjectPadding();
|
||||||
|
|
|
@ -119,6 +119,7 @@ public final class Bootstrap {
|
||||||
return unboxReturnType(target, newType);
|
return unboxReturnType(target, newType);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
factory.setInternalObjectsFilter(NashornBeansLinker.createHiddenObjectFilter());
|
||||||
final int relinkThreshold = Options.getIntProperty("nashorn.unstable.relink.threshold", NASHORN_DEFAULT_UNSTABLE_RELINK_THRESHOLD);
|
final int relinkThreshold = Options.getIntProperty("nashorn.unstable.relink.threshold", NASHORN_DEFAULT_UNSTABLE_RELINK_THRESHOLD);
|
||||||
if (relinkThreshold > -1) {
|
if (relinkThreshold > -1) {
|
||||||
factory.setUnstableRelinkThreshold(relinkThreshold);
|
factory.setUnstableRelinkThreshold(relinkThreshold);
|
||||||
|
|
|
@ -40,10 +40,11 @@ import jdk.internal.dynalink.linker.GuardedInvocation;
|
||||||
import jdk.internal.dynalink.linker.GuardingDynamicLinker;
|
import jdk.internal.dynalink.linker.GuardingDynamicLinker;
|
||||||
import jdk.internal.dynalink.linker.LinkRequest;
|
import jdk.internal.dynalink.linker.LinkRequest;
|
||||||
import jdk.internal.dynalink.linker.LinkerServices;
|
import jdk.internal.dynalink.linker.LinkerServices;
|
||||||
|
import jdk.internal.dynalink.linker.MethodHandleTransformer;
|
||||||
|
import jdk.internal.dynalink.support.DefaultInternalObjectFilter;
|
||||||
import jdk.internal.dynalink.support.Guards;
|
import jdk.internal.dynalink.support.Guards;
|
||||||
import jdk.internal.dynalink.support.Lookup;
|
import jdk.internal.dynalink.support.Lookup;
|
||||||
import jdk.nashorn.api.scripting.ScriptUtils;
|
import jdk.nashorn.api.scripting.ScriptUtils;
|
||||||
import jdk.nashorn.internal.objects.NativeArray;
|
|
||||||
import jdk.nashorn.internal.runtime.ConsString;
|
import jdk.nashorn.internal.runtime.ConsString;
|
||||||
import jdk.nashorn.internal.runtime.Context;
|
import jdk.nashorn.internal.runtime.Context;
|
||||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||||
|
@ -52,10 +53,14 @@ import jdk.nashorn.internal.runtime.options.Options;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This linker delegates to a {@code BeansLinker} but passes it a special linker services object that has a modified
|
* This linker delegates to a {@code BeansLinker} but passes it a special linker services object that has a modified
|
||||||
* {@code asType} method that will ensure that we never pass internal engine objects that should not be externally
|
* {@code compareConversion} method that favors conversion of {@link ConsString} to either {@link String} or
|
||||||
* observable (currently ConsString and ScriptObject) to Java APIs, but rather that we flatten it into a String. We can't just add
|
* {@link CharSequence}. It also provides a {@link #createHiddenObjectFilter()} method for use with bootstrap that will
|
||||||
* this functionality as custom converters via {@code GuaardingTypeConverterFactory}, since they are not consulted when
|
* ensure that we never pass internal engine objects that should not be externally observable (currently ConsString and
|
||||||
* the target method handle parameter signature is {@code Object}.
|
* ScriptObject) to Java APIs, but rather that we flatten it into a String. We can't just add this functionality as
|
||||||
|
* custom converters via {@code GuaardingTypeConverterFactory}, since they are not consulted when
|
||||||
|
* the target method handle parameter signature is {@code Object}. This linker also makes sure that primitive
|
||||||
|
* {@link String} operations can be invoked on a {@link ConsString}, and allows invocation of objects implementing
|
||||||
|
* the {@link FunctionalInterface} attribute.
|
||||||
*/
|
*/
|
||||||
public class NashornBeansLinker implements GuardingDynamicLinker {
|
public class NashornBeansLinker implements GuardingDynamicLinker {
|
||||||
// System property to control whether to wrap ScriptObject->ScriptObjectMirror for
|
// System property to control whether to wrap ScriptObject->ScriptObjectMirror for
|
||||||
|
@ -63,16 +68,12 @@ public class NashornBeansLinker implements GuardingDynamicLinker {
|
||||||
private static final boolean MIRROR_ALWAYS = Options.getBooleanProperty("nashorn.mirror.always", true);
|
private static final boolean MIRROR_ALWAYS = Options.getBooleanProperty("nashorn.mirror.always", true);
|
||||||
|
|
||||||
private static final MethodHandle EXPORT_ARGUMENT;
|
private static final MethodHandle EXPORT_ARGUMENT;
|
||||||
private static final MethodHandle EXPORT_NATIVE_ARRAY;
|
|
||||||
private static final MethodHandle EXPORT_SCRIPT_OBJECT;
|
|
||||||
private static final MethodHandle IMPORT_RESULT;
|
private static final MethodHandle IMPORT_RESULT;
|
||||||
private static final MethodHandle FILTER_CONSSTRING;
|
private static final MethodHandle FILTER_CONSSTRING;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
final Lookup lookup = new Lookup(MethodHandles.lookup());
|
final Lookup lookup = new Lookup(MethodHandles.lookup());
|
||||||
EXPORT_ARGUMENT = lookup.findOwnStatic("exportArgument", Object.class, Object.class);
|
EXPORT_ARGUMENT = lookup.findOwnStatic("exportArgument", Object.class, Object.class);
|
||||||
EXPORT_NATIVE_ARRAY = lookup.findOwnStatic("exportNativeArray", Object.class, NativeArray.class);
|
|
||||||
EXPORT_SCRIPT_OBJECT = lookup.findOwnStatic("exportScriptObject", Object.class, ScriptObject.class);
|
|
||||||
IMPORT_RESULT = lookup.findOwnStatic("importResult", Object.class, Object.class);
|
IMPORT_RESULT = lookup.findOwnStatic("importResult", Object.class, Object.class);
|
||||||
FILTER_CONSSTRING = lookup.findOwnStatic("consStringFilter", Object.class, Object.class);
|
FILTER_CONSSTRING = lookup.findOwnStatic("consStringFilter", Object.class, Object.class);
|
||||||
}
|
}
|
||||||
|
@ -115,8 +116,9 @@ public class NashornBeansLinker implements GuardingDynamicLinker {
|
||||||
}
|
}
|
||||||
return new GuardedInvocation(
|
return new GuardedInvocation(
|
||||||
// drop 'thiz' passed from the script.
|
// drop 'thiz' passed from the script.
|
||||||
MH.dropArguments(desc.getLookup().unreflect(m), 1, callType.parameterType(1)),
|
MH.dropArguments(linkerServices.filterInternalObjects(desc.getLookup().unreflect(m)), 1,
|
||||||
Guards.getInstanceOfGuard(m.getDeclaringClass())).asTypeSafeReturn(
|
callType.parameterType(1)), Guards.getInstanceOfGuard(
|
||||||
|
m.getDeclaringClass())).asTypeSafeReturn(
|
||||||
new NashornBeansLinkerServices(linkerServices), callType);
|
new NashornBeansLinkerServices(linkerServices), callType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,21 +143,6 @@ public class NashornBeansLinker implements GuardingDynamicLinker {
|
||||||
return exportArgument(arg, MIRROR_ALWAYS);
|
return exportArgument(arg, MIRROR_ALWAYS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private static Object exportNativeArray(final NativeArray arg) {
|
|
||||||
return exportArgument(arg, MIRROR_ALWAYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private static Object exportScriptObject(final ScriptObject arg) {
|
|
||||||
return exportArgument(arg, MIRROR_ALWAYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private static Object exportScriptArray(final NativeArray arg) {
|
|
||||||
return exportArgument(arg, MIRROR_ALWAYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Object exportArgument(final Object arg, final boolean mirrorAlways) {
|
static Object exportArgument(final Object arg, final boolean mirrorAlways) {
|
||||||
if (arg instanceof ConsString) {
|
if (arg instanceof ConsString) {
|
||||||
return arg.toString();
|
return arg.toString();
|
||||||
|
@ -208,6 +195,10 @@ public class NashornBeansLinker implements GuardingDynamicLinker {
|
||||||
return FUNCTIONAL_IFACE_METHOD.get(clazz);
|
return FUNCTIONAL_IFACE_METHOD.get(clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static MethodHandleTransformer createHiddenObjectFilter() {
|
||||||
|
return new DefaultInternalObjectFilter(EXPORT_ARGUMENT, MIRROR_ALWAYS ? IMPORT_RESULT : null);
|
||||||
|
}
|
||||||
|
|
||||||
private static class NashornBeansLinkerServices implements LinkerServices {
|
private static class NashornBeansLinkerServices implements LinkerServices {
|
||||||
private final LinkerServices linkerServices;
|
private final LinkerServices linkerServices;
|
||||||
|
|
||||||
|
@ -217,50 +208,7 @@ public class NashornBeansLinker implements GuardingDynamicLinker {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MethodHandle asType(final MethodHandle handle, final MethodType fromType) {
|
public MethodHandle asType(final MethodHandle handle, final MethodType fromType) {
|
||||||
final MethodType handleType = handle.type();
|
return linkerServices.asType(handle, fromType);
|
||||||
final int paramCount = handleType.parameterCount();
|
|
||||||
assert fromType.parameterCount() == handleType.parameterCount();
|
|
||||||
|
|
||||||
MethodType newFromType = fromType;
|
|
||||||
MethodHandle[] filters = null;
|
|
||||||
for(int i = 0; i < paramCount; ++i) {
|
|
||||||
final MethodHandle filter = argConversionFilter(handleType.parameterType(i), fromType.parameterType(i));
|
|
||||||
if (filter != null) {
|
|
||||||
if (filters == null) {
|
|
||||||
filters = new MethodHandle[paramCount];
|
|
||||||
}
|
|
||||||
// "erase" specific type with Object type or else we'll get filter mismatch
|
|
||||||
newFromType = newFromType.changeParameterType(i, Object.class);
|
|
||||||
filters[i] = filter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final MethodHandle typed = linkerServices.asType(handle, newFromType);
|
|
||||||
MethodHandle result = filters != null ? MethodHandles.filterArguments(typed, 0, filters) : typed;
|
|
||||||
// Filter Object typed return value for possible ScriptObjectMirror. We convert
|
|
||||||
// ScriptObjectMirror as ScriptObject (if it is mirror from current global).
|
|
||||||
if (MIRROR_ALWAYS && areBothObjects(handleType.returnType(), fromType.returnType())) {
|
|
||||||
result = MethodHandles.filterReturnValue(result, IMPORT_RESULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static MethodHandle argConversionFilter(final Class<?> handleType, final Class<?> fromType) {
|
|
||||||
if (handleType == Object.class) {
|
|
||||||
if (fromType == Object.class) {
|
|
||||||
return EXPORT_ARGUMENT;
|
|
||||||
} else if (fromType == NativeArray.class) {
|
|
||||||
return EXPORT_NATIVE_ARRAY;
|
|
||||||
} else if (fromType == ScriptObject.class) {
|
|
||||||
return EXPORT_SCRIPT_OBJECT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean areBothObjects(final Class<?> handleType, final Class<?> fromType) {
|
|
||||||
return handleType == Object.class && fromType == Object.class;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -296,5 +244,10 @@ public class NashornBeansLinker implements GuardingDynamicLinker {
|
||||||
}
|
}
|
||||||
return linkerServices.compareConversion(sourceType, targetType1, targetType2);
|
return linkerServices.compareConversion(sourceType, targetType1, targetType2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MethodHandle filterInternalObjects(MethodHandle target) {
|
||||||
|
return linkerServices.filterInternalObjects(target);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
69
nashorn/test/script/basic/JDK-8072596.js
Normal file
69
nashorn/test/script/basic/JDK-8072596.js
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JDK-8072596: Arrays.asList results in ClassCastException with a JS array
|
||||||
|
*
|
||||||
|
* @test
|
||||||
|
* @run
|
||||||
|
*/
|
||||||
|
var arr = java.util.Arrays.asList("hello world".split(' '));
|
||||||
|
// We split it into a list of two elements: [hello, world]
|
||||||
|
Assert.assertTrue(arr instanceof java.util.List);
|
||||||
|
Assert.assertEquals(arr.length, 2);
|
||||||
|
Assert.assertEquals(arr[0], "hello");
|
||||||
|
Assert.assertEquals(arr[1], "world");
|
||||||
|
|
||||||
|
var Jdk8072596TestSubject = Java.type("jdk.nashorn.test.models.Jdk8072596TestSubject");
|
||||||
|
var testSubject = new Jdk8072596TestSubject({bar: 0});
|
||||||
|
testSubject.test1(true, {foo: 1}, {bar: 2});
|
||||||
|
testSubject.test2(true, {foo: 1}, {bar: 2}, {baz: 3}, {bing: 4});
|
||||||
|
var h = "h";
|
||||||
|
var ello = "ello";
|
||||||
|
testSubject.test3(true, {foo: 5}, /* ConsString, why not */ h + ello, [6, 7], 8);
|
||||||
|
Jdk8072596TestSubject.test4({foo: 9});
|
||||||
|
|
||||||
|
// Test wrapping setters arguments and unwrapping getters return values on list.
|
||||||
|
var list = new java.util.ArrayList();
|
||||||
|
list.add(null);
|
||||||
|
var obj0 = {valueOf: function() { return 0; }};
|
||||||
|
var obj1 = {foo: 10};
|
||||||
|
list[obj0] = obj1;
|
||||||
|
testSubject.testListHasWrappedObject(list);
|
||||||
|
// NOTE: can't use Assert.assertSame(obj1, list[obj0]), as the arguments would end up being wrapped...
|
||||||
|
Assert.assertTrue(obj1 === list[obj0]);
|
||||||
|
|
||||||
|
// Test wrapping setters arguments and unwrapping getters return values on array.
|
||||||
|
var arr2 = new (Java.type("java.lang.Object[]"))(1);
|
||||||
|
var obj2 = {bar: 11};
|
||||||
|
arr2[obj0] = obj2;
|
||||||
|
testSubject.testArrayHasWrappedObject(arr2);
|
||||||
|
Assert.assertTrue(obj2 === arr2[obj0]);
|
||||||
|
|
||||||
|
// Test wrapping setters index and arguments and getters index, and unwrapping getters return values on map.
|
||||||
|
// Since ScriptObjectMirror.equals() uses underlying ScriptObject identity, using them as map keys works.
|
||||||
|
var map = new java.util.HashMap();
|
||||||
|
var obj3 = {bar: 12};
|
||||||
|
map[obj0] = obj3;
|
||||||
|
testSubject.testMapHasWrappedObject(map, obj0);
|
||||||
|
Assert.assertTrue(obj3 === map[obj0]);
|
|
@ -706,4 +706,74 @@ public class ScopeTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @bug 8071678: NashornScriptEngine returns javax.script.ScriptContext instance
|
||||||
|
// with get/setAttribute methods insonsistent for GLOBAL_SCOPE
|
||||||
|
@Test
|
||||||
|
public void testGlobalScopeSearch() throws Exception {
|
||||||
|
final ScriptEngineManager m = new ScriptEngineManager();
|
||||||
|
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||||
|
final ScriptContext c = e.getContext();
|
||||||
|
c.setAttribute("name1234", "value", ScriptContext.GLOBAL_SCOPE);
|
||||||
|
assertEquals(c.getAttribute("name1234"), "value");
|
||||||
|
assertEquals(c.getAttributesScope("name1234"),
|
||||||
|
ScriptContext.GLOBAL_SCOPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @bug 8071594: NashornScriptEngine returns javax.script.ScriptContext instance
|
||||||
|
// which doesn't completely conform to the spec regarding exceptions throwing
|
||||||
|
@Test
|
||||||
|
public void testScriptContext_NPE_IAE() throws Exception {
|
||||||
|
final ScriptEngineManager m = new ScriptEngineManager();
|
||||||
|
final ScriptEngine e = m.getEngineByName("nashorn");
|
||||||
|
final ScriptContext c = e.getContext();
|
||||||
|
try {
|
||||||
|
c.getAttribute("");
|
||||||
|
throw new AssertionError("should have thrown IAE");
|
||||||
|
} catch (IllegalArgumentException iae1) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
c.getAttribute(null);
|
||||||
|
throw new AssertionError("should have thrown NPE");
|
||||||
|
} catch (NullPointerException npe1) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
c.getAttribute("", ScriptContext.ENGINE_SCOPE);
|
||||||
|
throw new AssertionError("should have thrown IAE");
|
||||||
|
} catch (IllegalArgumentException iae2) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
c.getAttribute(null, ScriptContext.ENGINE_SCOPE);
|
||||||
|
throw new AssertionError("should have thrown NPE");
|
||||||
|
} catch (NullPointerException npe2) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
c.removeAttribute("", ScriptContext.ENGINE_SCOPE);
|
||||||
|
throw new AssertionError("should have thrown IAE");
|
||||||
|
} catch (IllegalArgumentException iae3) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
c.removeAttribute(null, ScriptContext.ENGINE_SCOPE);
|
||||||
|
throw new AssertionError("should have thrown NPE");
|
||||||
|
} catch (NullPointerException npe3) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
c.setAttribute("", "value", ScriptContext.ENGINE_SCOPE);
|
||||||
|
throw new AssertionError("should have thrown IAE");
|
||||||
|
} catch (IllegalArgumentException iae4) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
c.setAttribute(null, "value", ScriptContext.ENGINE_SCOPE);
|
||||||
|
throw new AssertionError("should have thrown NPE");
|
||||||
|
} catch (NullPointerException npe4) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
c.getAttributesScope("");
|
||||||
|
throw new AssertionError("should have thrown IAE");
|
||||||
|
} catch (IllegalArgumentException iae5) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
c.getAttributesScope(null);
|
||||||
|
throw new AssertionError("should have thrown NPE");
|
||||||
|
} catch (NullPointerException npe5) {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -852,6 +852,17 @@ public class ScriptEngineTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @bug 8071989: NashornScriptEngine returns javax.script.ScriptContext instance
|
||||||
|
// with insonsistent get/remove methods behavior for undefined attributes
|
||||||
|
@Test
|
||||||
|
public void testScriptContextGetRemoveUndefined() throws Exception {
|
||||||
|
final ScriptEngineManager manager = new ScriptEngineManager();
|
||||||
|
final ScriptEngine e = manager.getEngineByName("nashorn");
|
||||||
|
final ScriptContext ctx = e.getContext();
|
||||||
|
assertNull(ctx.getAttribute("undefinedname", ScriptContext.ENGINE_SCOPE));
|
||||||
|
assertNull(ctx.removeAttribute("undefinedname", ScriptContext.ENGINE_SCOPE));
|
||||||
|
}
|
||||||
|
|
||||||
private static void checkProperty(final ScriptEngine e, final String name)
|
private static void checkProperty(final ScriptEngine e, final String name)
|
||||||
throws ScriptException {
|
throws ScriptException {
|
||||||
final String value = System.getProperty(name);
|
final String value = System.getProperty(name);
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package jdk.nashorn.test.models;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import jdk.nashorn.api.scripting.ScriptObjectMirror;
|
||||||
|
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||||
|
import org.testng.Assert;
|
||||||
|
|
||||||
|
public class Jdk8072596TestSubject {
|
||||||
|
|
||||||
|
public Jdk8072596TestSubject(final Object x) {
|
||||||
|
Assert.assertTrue(x instanceof ScriptObjectMirror);
|
||||||
|
Assert.assertEquals(((ScriptObjectMirror)x).get("bar"), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test having to wrap some arguments but not others
|
||||||
|
public void test1(final String x, final Object y, final ScriptObject w) {
|
||||||
|
Assert.assertEquals(x, "true");
|
||||||
|
|
||||||
|
Assert.assertTrue(y instanceof ScriptObjectMirror);
|
||||||
|
Assert.assertEquals(((ScriptObjectMirror)y).get("foo"), 1);
|
||||||
|
|
||||||
|
Assert.assertEquals(w.get("bar"), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test having to wrap some arguments but not others, and a vararg array
|
||||||
|
public void test2(String x, final Object y, final ScriptObject w, final Object... z) {
|
||||||
|
test1(x, y, w);
|
||||||
|
|
||||||
|
Assert.assertEquals(z.length, 2);
|
||||||
|
|
||||||
|
Assert.assertTrue(z[0] instanceof ScriptObjectMirror);
|
||||||
|
Assert.assertEquals(((ScriptObjectMirror)z[0]).get("baz"), 3);
|
||||||
|
|
||||||
|
Assert.assertTrue(z[1] instanceof ScriptObjectMirror);
|
||||||
|
Assert.assertEquals(((ScriptObjectMirror)z[1]).get("bing"), 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test mixed (wrappable and non-wrappable) elements in a vararg array
|
||||||
|
public void test3(final Object... z) {
|
||||||
|
Assert.assertEquals(z.length, 5);
|
||||||
|
|
||||||
|
Assert.assertEquals(z[0], true);
|
||||||
|
|
||||||
|
Assert.assertTrue(z[1] instanceof ScriptObjectMirror);
|
||||||
|
Assert.assertEquals(((ScriptObjectMirror)z[1]).get("foo"), 5);
|
||||||
|
|
||||||
|
Assert.assertEquals(z[2], "hello");
|
||||||
|
|
||||||
|
Assert.assertTrue(z[3] instanceof ScriptObjectMirror);
|
||||||
|
Assert.assertEquals(((ScriptObjectMirror)z[3]).getSlot(0), 6);
|
||||||
|
Assert.assertEquals(((ScriptObjectMirror)z[3]).getSlot(1), 7);
|
||||||
|
|
||||||
|
Assert.assertEquals(z[4], 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// test wrapping the first argument of a static method
|
||||||
|
public static void test4(final Object x) {
|
||||||
|
Assert.assertTrue(x instanceof ScriptObjectMirror);
|
||||||
|
Assert.assertEquals(((ScriptObjectMirror)x).get("foo"), 9);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testListHasWrappedObject(final List<?> l) {
|
||||||
|
Assert.assertEquals(l.size(), 1);
|
||||||
|
Assert.assertTrue(l.get(0) instanceof ScriptObjectMirror);
|
||||||
|
Assert.assertEquals(((ScriptObjectMirror)l.get(0)).get("foo"), 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testArrayHasWrappedObject(final Object[] a) {
|
||||||
|
Assert.assertEquals(a.length, 1);
|
||||||
|
Assert.assertTrue(a[0] instanceof ScriptObjectMirror);
|
||||||
|
Assert.assertEquals(((ScriptObjectMirror)a[0]).get("bar"), 11);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMapHasWrappedObject(final Map<?, ?> m, final Object key) {
|
||||||
|
Assert.assertEquals(m.size(), 1);
|
||||||
|
Assert.assertTrue(key instanceof ScriptObjectMirror);
|
||||||
|
Assert.assertTrue(m.get(key) instanceof ScriptObjectMirror);
|
||||||
|
Assert.assertEquals(((ScriptObjectMirror)m.get(key)).get("bar"), 12);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue